Skip to content

Commit

Permalink
Add wesnoth.interface.add_floating_label as a replacement for wesnoth…
Browse files Browse the repository at this point in the history
….print

This returns a label handle which allows you to remove, reposition, or replace the label later.

In addition to all the features of wesnoth.print, you can now specify where the label appears onscreen,
as well as a fadeout time separate from the duration.
  • Loading branch information
CelticMinstrel committed Jun 7, 2021
1 parent f7e4379 commit cebb99b
Show file tree
Hide file tree
Showing 7 changed files with 190 additions and 37 deletions.
Expand Up @@ -1270,12 +1270,12 @@
[/filter_condition]

# Print a reminder of the time limit
[print]
[floating_label]
text= _ "$(16 - $turn_number) turns remain to free $number_merfolk_caged| merfolk"
size=24
duration=5000
color=200,200,255
[/print]
[/floating_label]
[/event]

[event]
Expand Down
10 changes: 5 additions & 5 deletions data/campaigns/tutorial/utils/utils.cfg
@@ -1,18 +1,18 @@
#textdomain wesnoth-tutorial

#define PRINT STRING
[print]
[floating_label]
text={STRING}
size=18
duration=10000
red,green,blue=255,255,255
[/print]
color=255,255,255
[/floating_label]
#enddef

#define CLEAR_PRINT
[print]
[floating_label]
text="" # wmllint: ignore
[/print]
[/floating_label]
#enddef

#define GENDER MALE_WML FEMALE_WML
Expand Down
12 changes: 6 additions & 6 deletions data/core/macros/ai_controller.cfg
Expand Up @@ -485,11 +485,11 @@
{VARIABLE ai_controller_{AFFIX}.defend_location.original_controller_invokation_y $y1}
{VARIABLE ai_controller_finished yes}

[print]
[floating_label]
text= _ "Right-click to select a location to defend"
duration=100
{COLOR_WHITE}
[/print]
[/floating_label]

[set_menu_item]
id=ai_controller_defend_location_picker
Expand Down Expand Up @@ -523,10 +523,10 @@
[/goal]
)}

[print]
[floating_label]
text=" " # wmllint: ignore
duration=1
[/print]
[/floating_label]

[fire_event]
name=menu item ai_controller
Expand All @@ -551,11 +551,11 @@
[then]
{VARIABLE ai_controller_{AFFIX}.defend_location.picker_active no}

[print]
[floating_label]
text= _ "Location selection canceled"
duration=100
{COLOR_WHITE}
[/print]
[/floating_label]
[/then]
[/if]
[/event]
Expand Down
4 changes: 4 additions & 0 deletions data/lua/core/interface.lua
Expand Up @@ -53,6 +53,10 @@ if wesnoth.kernel_type() == "Game Lua Kernel" then
wesnoth.zoom = wesnoth.deprecate_api('wesnoth.zoom', 'wesnoth.interface.zoom', 1, nil, wesnoth.interface.zoom)
wesnoth.gamestate_inspector = wesnoth.deprecate_api('wesnoth.gamestate_inspector', 'gui.show_inspector', 1, nil, gui.show_inspector)
wesnoth.color_adjust = wesnoth.deprecate_api('wesnoth.color_adjust', 'wesnoth.interface.color_adjust', 1, nil, function(cfg) wesnoth.interface.color_adjust(cfg.red, cfg.green, cfg.blue) end)
-- wesnoth.wml_actions.print doesn't exist yet at this point, so create a helper function instead.
wesnoth.print = wesnoth.deprecate_api('wesnoth.print', 'wesnoth.interface.add_floating_label', 1, nil, function(cfg)
wesnoth.wml_actions.print(cfg)
end)
-- No deprecation for these since since they're not actually public API yet
wesnoth.set_menu_item = wesnoth.interface.set_menu_item
wesnoth.clear_menu_item = wesnoth.interface.clear_menu_item
Expand Down
42 changes: 41 additions & 1 deletion data/lua/wml-tags.lua
Expand Up @@ -767,8 +767,48 @@ function wml_actions.redraw(cfg)
wesnoth.redraw(cfg, clear_shroud)
end

local wml_floating_label = {valid = false}
function wml_actions.print(cfg)
wesnoth.print(cfg)
wesnoth.deprecated_message('[print]', 1, nil, 'use [floating_label] instead')
if wml_floating_label.valid then
wml_floating_label:remove()
end
local label_text = {cfg.text}
if cfg.size then
table.insert(label_text, cfg.size)
end
if cfg.color then
table.insert(label_text, stringx.split(cfg.color))
elseif cfg.red or cfg.green or cfg.blue then
table.insert(label_text, {cfg.red or 0, cfg.green or 0, cfg.blue or 0})
end

wml_floating_label = wesnoth.interface.add_floating_label(label_text, cfg.duration or 50)
end

function wml_actions.floating_label(cfg)
local label_text, lifetime = {cfg.text}, {}
if wml_floating_label.valid then
wml_floating_label:remove()
end
if cfg.size then
table.insert(label_text, cfg.size)
end
if cfg.color then
table.insert(label_text, stringx.split(cfg.color))
end
local offset = nil
if cfg.x_offset or cfg.y_offset then
offset = {cfg.x_offset or 0, cfg.y_offset or 0}
end
if cfg.duration then
lifetime.duration = cfg.duration
end
if cfg.fade_time then
lifetime.fade_time = cfg.fade_time
end

wml_floating_label = wesnoth.interface.add_floating_label(label_text, lifetime, offset)
end

function wml_actions.unsynced(cfg)
Expand Down
151 changes: 129 additions & 22 deletions src/scripting/game_lua_kernel.cpp
Expand Up @@ -1974,42 +1974,149 @@ int game_lua_kernel::intf_find_cost_map(lua_State *L)
return 1;
}

int game_lua_kernel::intf_print(lua_State *L) {
vconfig cfg(luaW_checkvconfig(L, 1));
const char* labelKey = "floating label";

// Remove any old message.
static int floating_label = 0;
if (floating_label)
font::remove_floating_label(floating_label);
static int* luaW_check_floating_label(lua_State* L, int idx)
{
return reinterpret_cast<int*>(luaL_checkudata(L, idx, labelKey));
}

// Display a message on-screen
std::string text = cfg["text"];
if(text.empty() || !game_display_)
return 0;
static int impl_floating_label_getmethod(lua_State* L)
{
const char* m = luaL_checkstring(L, 2);
return_bool_attrib("valid", *luaW_check_floating_label(L, 1) != 0);
return luaW_getmetafield(L, 1, m);
}

int size = cfg["size"].to_int(font::SIZE_SMALL);
int lifetime = cfg["duration"].to_int(50);
int game_lua_kernel::intf_remove_floating_label(lua_State* L)
{
int* handle = luaW_check_floating_label(L, 1);
if(*handle != 0) {
font::remove_floating_label(*handle);
}
*handle = 0;
return 0;
}

int game_lua_kernel::intf_move_floating_label(lua_State* L)
{
int* handle = luaW_check_floating_label(L, 1);
if(*handle != 0) {
font::move_floating_label(*handle, luaL_checknumber(L, 2), luaL_checknumber(L, 3));
}
return 0;
}

int game_lua_kernel::intf_set_floating_label(lua_State* L, bool spawn)
{
int first_arg = spawn ? 1 : 2;
t_string text;
int size = font::SIZE_SMALL;
color_t color = font::LABEL_COLOR;
if(!luaW_totstring(L, first_arg, text)) {
if(lua_type(L, first_arg) != LUA_TTABLE) {
return luaW_type_error(L, 1, "string or table");
}
for(lua_Unsigned i = 1; i <= lua_rawlen(L, first_arg); i++) {
lua_geti(L, first_arg, i);
if(i == 1) {
text = luaW_checktstring(L, -1);
} else switch(lua_type(L, -1)) {
default:
return luaL_error(L, "unknown floating label text setting - should be either size (integer) or color (hex string or array of 3 integers)");
case LUA_TNUMBER:
size = lua_tointeger(L, -1);
break;
case LUA_TSTRING:
color = color_t::from_hex_string(lua_tostring(L, -1));
break;
case LUA_TTABLE:
auto vec = lua_check<std::vector<int>>(L, -1);
if(vec.size() != 3) {
return luaL_error(L, "floating label text color should be a hex string or an array of 3 integers");
}
color.r = vec[0];
color.g = vec[1];
color.b = vec[2];
break;
}
lua_pop(L, 1);
}
}

if(!cfg["color"].empty()) {
color = color_t::from_rgb_string(cfg["color"]);
} else if(cfg.has_attribute("red") || cfg.has_attribute("green") || cfg.has_attribute("blue")) {
color = color_t(cfg["red"], cfg["green"], cfg["blue"]);
int lifetime = 2'000, fadeout = 100;
map_location loc{0, 0, wml_loc()};
bool found_location = false;
switch(lua_type(L, first_arg + 1)) {
case LUA_TNIL: case LUA_TNONE:
break;
case LUA_TTABLE:
if(luaW_tolocation(L, first_arg + 1, loc)) {
found_location = true;
} else {
lifetime = luaW_table_get_def(L, first_arg + 1, "duration", 2000);
fadeout = luaW_table_get_def(L, first_arg + 1, "fade_time", 100);
}
break;
case LUA_TNUMBER:
lifetime = lua_tointeger(L, first_arg + 1);
break;
case LUA_TSTRING:
if(luaW_tostring(L, first_arg + 1) == "infinity") {
lifetime = -1;
break;
}
[[fallthrough]];
default:
return luaW_type_error(L, first_arg + 1, "integer or 'infinity'");
}

if(!found_location && !lua_isnoneornil(L, first_arg + 2)) {
loc = luaW_checklocation(L, first_arg + 2);
}

int* handle = nullptr;
if(spawn) {
// Creating a new label, allocate a new handle
handle = new(L)int();
} else {
// First argument is the label handle
handle = luaW_check_floating_label(L, 1);
}
int handle_idx = lua_gettop(L);

if(*handle != 0) {
font::remove_floating_label(*handle);
}

const SDL_Rect& rect = game_display_->map_outside_area();
int x = rect.x + rect.w / 2 + loc.wml_x();
int y = rect.y + rect.h / 2 + loc.wml_y();

font::floating_label flabel(text);
flabel.set_font_size(size);
flabel.set_color(color);
flabel.set_position(rect.x + rect.w/2, rect.y + rect.h/2);
flabel.set_lifetime(lifetime);
flabel.set_position(x, y);
flabel.set_lifetime(lifetime, fadeout);
flabel.set_clip_rect(rect);

floating_label = font::add_floating_label(flabel);

return 0;
*handle = font::add_floating_label(flabel);
lua_settop(L, handle_idx);
if(luaL_newmetatable(L, labelKey)) {
// Initialize the metatable
static const luaL_Reg methods[] = {
{"remove", &dispatch<&game_lua_kernel::intf_remove_floating_label>},
{"move", &dispatch<&game_lua_kernel::intf_move_floating_label>},
{"replace", &dispatch2<&game_lua_kernel::intf_set_floating_label, false>},
{"__index", &impl_floating_label_getmethod},
{ nullptr, nullptr }
};
luaL_setfuncs(L, methods, 0);
luaW_table_set(L, -1, "__metatable", std::string(labelKey));
}
lua_setmetatable(L, handle_idx);
lua_settop(L, handle_idx);
return 1;
}

void game_lua_kernel::put_unit_helper(const map_location& loc)
Expand Down Expand Up @@ -4033,7 +4140,6 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports
{ "log_replay", &dispatch<&game_lua_kernel::intf_log_replay > },
{ "log", &dispatch<&game_lua_kernel::intf_log > },
{ "message", &dispatch<&game_lua_kernel::intf_message > },
{ "print", &dispatch<&game_lua_kernel::intf_print > },
{ "redraw", &dispatch<&game_lua_kernel::intf_redraw > },
{ "remove_event_handler", &dispatch<&game_lua_kernel::intf_remove_event > },
{ "replace_schedule", &dispatch<&game_lua_kernel::intf_replace_schedule > },
Expand Down Expand Up @@ -4260,6 +4366,7 @@ game_lua_kernel::game_lua_kernel(game_state & gs, play_controller & pc, reports
{"zoom", &dispatch<&game_lua_kernel::intf_zoom>},
{"clear_menu_item", &dispatch<&game_lua_kernel::intf_clear_menu_item>},
{"set_menu_item", &dispatch<&game_lua_kernel::intf_set_menu_item>},
{"add_floating_label", &dispatch2<&game_lua_kernel::intf_set_floating_label, true>},
{ nullptr, nullptr }
};
lua_getglobal(L, "wesnoth");
Expand Down
4 changes: 3 additions & 1 deletion src/scripting/game_lua_kernel.hpp
Expand Up @@ -118,7 +118,9 @@ class game_lua_kernel : public lua_kernel_base
int intf_message(lua_State *L);
int intf_open_help(lua_State *L);
int intf_play_sound(lua_State *L);
int intf_print(lua_State *L);
int intf_set_floating_label(lua_State* L, bool spawn);
int intf_remove_floating_label(lua_State* L);
int intf_move_floating_label(lua_State* L);
void put_unit_helper(const map_location& loc);
int intf_put_unit(lua_State *L);
int intf_erase_unit(lua_State *L);
Expand Down

0 comments on commit cebb99b

Please sign in to comment.