From 6f26650255c2f8ecc887e20a79f46d3a966e6401 Mon Sep 17 00:00:00 2001 From: shevernitskiy Date: Fri, 1 Sep 2023 18:12:59 +0300 Subject: [PATCH] reserved texpos range --- docs/dev/Lua API.rst | 12 ++- library/LuaApi.cpp | 9 +- library/include/modules/Textures.h | 10 +- library/lua/gui/textures.lua | 22 ++-- library/modules/Textures.cpp | 118 +++++++++++++++++--- plugins/lua/hotkeys.lua | 168 +++++++++++++++-------------- plugins/pathable.cpp | 2 +- 7 files changed, 222 insertions(+), 119 deletions(-) diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 4f182d132..9199130fe 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2595,10 +2595,12 @@ The ``textures`` module solves this problem by providing a stable handle instead raw ``texpos``. When we need to draw a particular tile, we can look up the current ``texpos`` value via the handle. -* ``loadTileset(file, tile_px_w, tile_px_h)`` +* ``loadTileset(file, tile_px_w, tile_px_h, reserved?)`` Loads a tileset from the image ``file`` with give tile dimensions in pixels. The image will be sliced in row major order. Returns an array of ``TexposHandle``. + ``reserved`` is optional boolean argument, which indicates texpos range. + ``true`` - reserved, ``false`` - dynamic (default). Example usage:: @@ -2611,18 +2613,22 @@ raw ``texpos``. When we need to draw a particular tile, we can look up the curre get the ``texpos`` for your texture. ``texpos`` can change when game textures are reset, but the handle will be the same. -* ``createTile(pixels, tile_px_w, tile_px_h)`` +* ``createTile(pixels, tile_px_w, tile_px_h, reserved?)`` Create and register a new texture with the given tile dimensions and an array of ``pixels`` in row major order. Each pixel is an integer representing color in packed RBGA format (for example, #0022FF11). Returns a ``TexposHandle``. + ``reserved`` is optional boolean argument, which indicates texpos range. + ``true`` - reserved, ``false`` - dynamic (default). -* ``createTileset(pixels, texture_px_w, texture_px_h, tile_px_w, tile_px_h)`` +* ``createTileset(pixels, texture_px_w, texture_px_h, tile_px_w, tile_px_h, reserved?)`` Create and register a new texture with the given texture dimensions and an array of ``pixels`` in row major order. Then slice it into tiles with the given tile dimensions. Each pixel is an integer representing color in packed RBGA format (for example #0022FF11). Returns an array of ``TexposHandle``. + ``reserved`` is optional boolean argument, which indicates texpos range. + ``true`` - reserved, ``false`` - dynamic (default). * ``deleteHandle(handle)`` diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index f792cff90..5faec6d88 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -1760,7 +1760,8 @@ static int textures_loadTileset(lua_State *state) std::string file = luaL_checkstring(state, 1); auto tile_w = luaL_checkint(state, 2); auto tile_h = luaL_checkint(state, 3); - auto handles = Textures::loadTileset(file, tile_w, tile_h); + bool reserved = lua_isboolean(state, 4) ? lua_toboolean(state, 4) : false; + auto handles = Textures::loadTileset(file, tile_w, tile_h, reserved); Lua::PushVector(state, handles); return 1; } @@ -1798,7 +1799,8 @@ static int textures_createTile(lua_State *state) Lua::GetVector(state, pixels); auto tile_w = luaL_checkint(state, 2); auto tile_h = luaL_checkint(state, 3); - auto handle = Textures::createTile(pixels, tile_w, tile_h); + bool reserved = lua_isboolean(state, 4) ? lua_toboolean(state, 4) : false; + auto handle = Textures::createTile(pixels, tile_w, tile_h, reserved); Lua::Push(state, handle); return 1; } @@ -1811,7 +1813,8 @@ static int textures_createTileset(lua_State *state) auto texture_h = luaL_checkint(state, 3); auto tile_w = luaL_checkint(state, 4); auto tile_h = luaL_checkint(state, 5); - auto handles = Textures::createTileset(pixels, texture_w, texture_h, tile_w, tile_h); + bool reserved = lua_isboolean(state, 6) ? lua_toboolean(state, 6) : false; + auto handles = Textures::createTileset(pixels, texture_w, texture_h, tile_w, tile_h, reserved); Lua::PushVector(state, handles); return 1; } diff --git a/library/include/modules/Textures.h b/library/include/modules/Textures.h index 5b238a4fd..b820c3332 100644 --- a/library/include/modules/Textures.h +++ b/library/include/modules/Textures.h @@ -26,7 +26,7 @@ const uint32_t TILE_HEIGHT_PX = 12; * Load texture and get handle. * Keep it to obtain valid texpos. */ -DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface); +DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface, bool reserved = false); /** * Load tileset from image file. @@ -34,7 +34,8 @@ DFHACK_EXPORT TexposHandle loadTexture(SDL_Surface* surface); */ DFHACK_EXPORT std::vector loadTileset(const std::string& file, int tile_px_w = TILE_WIDTH_PX, - int tile_px_h = TILE_HEIGHT_PX); + int tile_px_h = TILE_HEIGHT_PX, + bool reserved = false); /** * Get texpos by handle. @@ -53,7 +54,7 @@ DFHACK_EXPORT void deleteHandle(TexposHandle handle); * Register this texture and return TexposHandle. */ DFHACK_EXPORT TexposHandle createTile(std::vector& pixels, int tile_px_w = TILE_WIDTH_PX, - int tile_px_h = TILE_HEIGHT_PX); + int tile_px_h = TILE_HEIGHT_PX, bool reserved = false); /** * Create new textures as tileset with RGBA32 format and pixels as data in row major order. @@ -62,7 +63,8 @@ DFHACK_EXPORT TexposHandle createTile(std::vector& pixels, int tile_px DFHACK_EXPORT std::vector createTileset(std::vector& pixels, int texture_px_w, int texture_px_h, int tile_px_w = TILE_WIDTH_PX, - int tile_px_h = TILE_HEIGHT_PX); + int tile_px_h = TILE_HEIGHT_PX, + bool reserved = false); /** * Call this on DFHack init just once to setup interposed handlers and diff --git a/library/lua/gui/textures.lua b/library/lua/gui/textures.lua index 6557b6e02..6dac234e0 100644 --- a/library/lua/gui/textures.lua +++ b/library/lua/gui/textures.lua @@ -6,18 +6,18 @@ local _ENV = mkmodule('gui.textures') -- Preloaded DFHack Assets. -- Use this handles if you need to get dfhack standard textures. ----@type table +---@type table local texpos_handles = { - green_pin = dfhack.textures.loadTileset('hack/data/art/green-pin.png', 8, 12), - red_pin = dfhack.textures.loadTileset('hack/data/art/red-pin.png', 8, 12), - icons = dfhack.textures.loadTileset('hack/data/art/icons.png', 8, 12), - on_off = dfhack.textures.loadTileset('hack/data/art/on-off.png', 8, 12), - control_panel = dfhack.textures.loadTileset('hack/data/art/control-panel.png', 8, 12), - border_thin = dfhack.textures.loadTileset('hack/data/art/border-thin.png', 8, 12), - border_medium = dfhack.textures.loadTileset('hack/data/art/border-medium.png', 8, 12), - border_bold = dfhack.textures.loadTileset('hack/data/art/border-bold.png', 8, 12), - border_panel = dfhack.textures.loadTileset('hack/data/art/border-panel.png', 8, 12), - border_window = dfhack.textures.loadTileset('hack/data/art/border-window.png', 8, 12), + green_pin = dfhack.textures.loadTileset('hack/data/art/green-pin.png', 8, 12, true), + red_pin = dfhack.textures.loadTileset('hack/data/art/red-pin.png', 8, 12, true), + icons = dfhack.textures.loadTileset('hack/data/art/icons.png', 8, 12, true), + on_off = dfhack.textures.loadTileset('hack/data/art/on-off.png', 8, 12, true), + control_panel = dfhack.textures.loadTileset('hack/data/art/control-panel.png', 8, 12, true), + border_thin = dfhack.textures.loadTileset('hack/data/art/border-thin.png', 8, 12, true), + border_medium = dfhack.textures.loadTileset('hack/data/art/border-medium.png', 8, 12, true), + border_bold = dfhack.textures.loadTileset('hack/data/art/border-bold.png', 8, 12, true), + border_panel = dfhack.textures.loadTileset('hack/data/art/border-panel.png', 8, 12, true), + border_window = dfhack.textures.loadTileset('hack/data/art/border-window.png', 8, 12, true), } -- Get valid texpos for preloaded texture in tileset diff --git a/library/modules/Textures.cpp b/library/modules/Textures.cpp index c957bd878..e52445f18 100644 --- a/library/modules/Textures.cpp +++ b/library/modules/Textures.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -29,8 +30,30 @@ DBG_DECLARE(core, textures, DebugCategory::LINFO); } static std::unordered_map g_handle_to_texpos; +static std::unordered_map g_handle_to_reserved_texpos; static std::unordered_map g_handle_to_surface; +static std::unordered_map> g_tileset_to_handles; static std::mutex g_adding_mutex; +static std::atomic loading_state = false; + +struct Reserved { + static void init(int32_t start) { + reserved_range.start = start; + reserved_range.end = start + Reserved::size; + reserved_range.current = start; + } + static long get_new_texpos() { + if (reserved_range.current == reserved_range.end) + return -1; + current = reserved_range.current; + reserved_range.current++; + return current; + } + static const int32_t size = 10000; // size of reserved texpos buffer + inline static int32_t start = -1; + inline static int32_t end = -1; + inline static long current = -1; +} reserved_range; // Converts an arbitrary Surface to something like the display format // (32-bit RGBA), and converts magenta to transparency if convert_magenta is set @@ -71,6 +94,12 @@ static long add_texture(SDL_Surface* surface) { return texpos; } +// register surface in texture raws to specific texpos, returns a texpos +static void insert_texture(SDL_Surface* surface, long texpos) { + std::lock_guard lg_add_texture(g_adding_mutex); + enabler->textures.raws[texpos] = surface; +} + // delete surface from texture raws static void delete_texture(long texpos) { std::lock_guard lg_add_texture(g_adding_mutex); @@ -94,7 +123,8 @@ SDL_Surface* create_texture(std::vector& pixels, int texture_px_w, int // convert single surface into tiles according w/h // register tiles in texture raws and return handles -std::vector slice_tileset(SDL_Surface* surface, int tile_px_w, int tile_px_h) { +std::vector slice_tileset(SDL_Surface* surface, int tile_px_w, int tile_px_h, + bool reserved) { std::vector handles{}; if (!surface) return handles; @@ -109,7 +139,7 @@ std::vector slice_tileset(SDL_Surface* surface, int tile_px_w, int surface->format->Bmask, surface->format->Amask); SDL_Rect vp{tile_px_w * x, tile_px_h * y, tile_px_w, tile_px_h}; DFSDL_UpperBlit(surface, &vp, tile, NULL); - auto handle = Textures::loadTexture(tile); + auto handle = Textures::loadTexture(tile, reserved); handles.push_back(handle); } } @@ -118,22 +148,38 @@ std::vector slice_tileset(SDL_Surface* surface, int tile_px_w, int return handles; } -TexposHandle Textures::loadTexture(SDL_Surface* surface) { +TexposHandle Textures::loadTexture(SDL_Surface* surface, bool reserved) { if (!surface || !enabler) return 0; // should be some error, i guess + if (loading_state) { + ERR(textures).printerr("unable to load texture during game loading\n"); + return 0; + } auto handle = reinterpret_cast(surface); g_handle_to_surface.emplace(handle, surface); surface->refcount++; // prevent destruct on next FreeSurface by game - auto texpos = add_texture(surface); - g_handle_to_texpos.emplace(handle, texpos); + if (reserved) { + auto texpos = reserved_range.get_new_texpos(); + if (texpos == -1) { + ERR(textures).printerr("reserved range limit has been reached, use dynamic range\n"); + return 0; + } + insert_texture(surface, texpos); + g_handle_to_reserved_texpos.emplace(handle, texpos); + } else { + auto texpos = add_texture(surface); + g_handle_to_texpos.emplace(handle, texpos); + } return handle; } std::vector Textures::loadTileset(const std::string& file, int tile_px_w, - int tile_px_h) { + int tile_px_h, bool reserved) { if (!enabler) return std::vector{}; + if (g_tileset_to_handles.contains(file)) + return g_tileset_to_handles[file]; SDL_Surface* surface = DFIMG_Load(file.c_str()); if (!surface) { @@ -142,10 +188,12 @@ std::vector Textures::loadTileset(const std::string& file, int til } surface = canonicalize_format(surface); - auto handles = slice_tileset(surface, tile_px_w, tile_px_h); + auto handles = slice_tileset(surface, tile_px_w, tile_px_h, reserved); - DEBUG(textures).print("loaded %zd textures from '%s'\n", handles.size(), file.c_str()); + DEBUG(textures).print("loaded %zd textures from '%s' to %s range\n", handles.size(), + file.c_str(), reserved ? "reserved" : "dynamic"); + g_tileset_to_handles[file] = handles; return handles; } @@ -153,10 +201,15 @@ long Textures::getTexposByHandle(TexposHandle handle) { if (!handle || !enabler) return -1; + if (g_handle_to_reserved_texpos.contains(handle)) + return g_handle_to_reserved_texpos[handle]; if (g_handle_to_texpos.contains(handle)) return g_handle_to_texpos[handle]; - if (g_handle_to_surface.contains(handle)) { + if (loading_state) { + ERR(textures).printerr("unable reinit texture from dynamic range during loading\n"); + return -1; + } g_handle_to_surface[handle]->refcount++; // prevent destruct on next FreeSurface by game auto texpos = add_texture(g_handle_to_surface[handle]); g_handle_to_texpos.emplace(handle, texpos); @@ -166,22 +219,24 @@ long Textures::getTexposByHandle(TexposHandle handle) { return -1; } -TexposHandle Textures::createTile(std::vector& pixels, int tile_px_w, int tile_px_h) { +TexposHandle Textures::createTile(std::vector& pixels, int tile_px_w, int tile_px_h, + bool reserved) { if (!enabler) return 0; auto texture = create_texture(pixels, tile_px_w, tile_px_h); - auto handle = Textures::loadTexture(texture); + auto handle = Textures::loadTexture(texture, reserved); return handle; } std::vector Textures::createTileset(std::vector& pixels, int texture_px_w, - int texture_px_h, int tile_px_w, int tile_px_h) { + int texture_px_h, int tile_px_w, int tile_px_h, + bool reserved) { if (!enabler) return std::vector{}; auto texture = create_texture(pixels, texture_px_w, texture_px_h); - auto handles = slice_tileset(texture, tile_px_w, tile_px_h); + auto handles = slice_tileset(texture, tile_px_w, tile_px_h, reserved); return handles; } @@ -192,6 +247,8 @@ void Textures::deleteHandle(TexposHandle handle) { auto texpos = Textures::getTexposByHandle(handle); if (texpos > 0) delete_texture(texpos); + if (g_handle_to_reserved_texpos.contains(handle)) + g_handle_to_reserved_texpos.erase(handle); if (g_handle_to_texpos.contains(handle)) g_handle_to_texpos.erase(handle); if (g_handle_to_surface.contains(handle)) { @@ -207,7 +264,18 @@ static void reset_texpos() { g_handle_to_texpos.clear(); } +static void reset_reserved_texpos() { + DEBUG(textures).print("resetting reserved texture mappings\n"); + g_handle_to_reserved_texpos.clear(); +} + +static void reset_tilesets() { + DEBUG(textures).print("resetting tileset to handle mappings\n"); + g_tileset_to_handles.clear(); +} + static void reset_surface() { + DEBUG(textures).print("deleting cached surfaces\n"); for (auto& entry : g_handle_to_surface) { DFSDL_FreeSurface(entry.second); } @@ -220,7 +288,9 @@ struct tracking_stage_new_region : df::viewscreen_new_regionst { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_raw_load_stage != this->raw_load_stage) { - TRACE(textures).print("raw_load_stage %d -> %d\n", this->m_raw_load_stage, this->raw_load_stage); + TRACE(textures).print("raw_load_stage %d -> %d\n", this->m_raw_load_stage, + this->raw_load_stage); + loading_state = this->raw_load_stage >= 0 && this->raw_load_stage < 3 ? true : false; this->m_raw_load_stage = this->raw_load_stage; if (this->m_raw_load_stage == 1) reset_texpos(); @@ -240,6 +310,7 @@ struct tracking_stage_adopt_region : df::viewscreen_adopt_regionst { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { TRACE(textures).print("step %d -> %d\n", this->m_cur_step, this->cur_step); + loading_state = this->cur_step >= 0 && this->cur_step < 3 ? true : false; this->m_cur_step = this->cur_step; if (this->m_cur_step == 1) reset_texpos(); @@ -259,6 +330,7 @@ struct tracking_stage_load_region : df::viewscreen_loadgamest { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { TRACE(textures).print("step %d -> %d\n", this->m_cur_step, this->cur_step); + loading_state = this->cur_step >= 0 && this->cur_step < 3 ? true : false; this->m_cur_step = this->cur_step; if (this->m_cur_step == 1) reset_texpos(); @@ -278,6 +350,7 @@ struct tracking_stage_new_arena : df::viewscreen_new_arenast { DEFINE_VMETHOD_INTERPOSE(void, logic, ()) { if (this->m_cur_step != this->cur_step) { TRACE(textures).print("step %d -> %d\n", this->m_cur_step, this->cur_step); + loading_state = this->cur_step >= 0 && this->cur_step < 3 ? true : false; this->m_cur_step = this->cur_step; if (this->m_cur_step == 0) reset_texpos(); @@ -304,12 +377,25 @@ static void uninstall_reset_point() { INTERPOSE_HOOK(tracking_stage_new_arena, logic).remove(); } +static void reserve_static_range() { + reserved_range.init(enabler->textures.init_texture_size); + auto dummy_surface = + DFSDL_CreateRGBSurfaceWithFormat(0, 0, 0, 32, SDL_PixelFormatEnum::SDL_PIXELFORMAT_RGBA32); + for (int32_t i = 0; i < Reserved::size; i++) { + add_texture(dummy_surface); + } + enabler->textures.init_texture_size += Reserved::size; +} + void Textures::init(color_ostream& out) { if (!enabler) return; + reserve_static_range(); install_reset_point(); - DEBUG(textures, out).print("dynamic texture loading ready"); + DEBUG(textures, out) + .print("dynamic texture loading ready, reserved range %d-%d\n", reserved_range.start, + reserved_range.end); } void Textures::cleanup() { @@ -317,6 +403,8 @@ void Textures::cleanup() { return; reset_texpos(); + reset_reserved_texpos(); + reset_tilesets(); reset_surface(); uninstall_reset_point(); } diff --git a/plugins/lua/hotkeys.lua b/plugins/lua/hotkeys.lua index fae138353..4169d439a 100644 --- a/plugins/lua/hotkeys.lua +++ b/plugins/lua/hotkeys.lua @@ -5,8 +5,8 @@ local helpdb = require('helpdb') local overlay = require('plugins.overlay') local widgets = require('gui.widgets') -local logo_textures = dfhack.textures.loadTileset('hack/data/art/logo.png', 8, 12) -local logo_hovered_textures = dfhack.textures.loadTileset('hack/data/art/logo_hovered.png', 8, 12) +local logo_textures = dfhack.textures.loadTileset('hack/data/art/logo.png', 8, 12, true) +local logo_hovered_textures = dfhack.textures.loadTileset('hack/data/art/logo_hovered.png', 8, 12, true) local function get_command(cmdline) local first_word = cmdline:trim():split(' +')[1] @@ -17,8 +17,8 @@ end function should_hide_armok(cmdline) local command = get_command(cmdline) return dfhack.getHideArmokTools() and - helpdb.is_entry(command) and - helpdb.get_entry_tags(command).armok + helpdb.is_entry(command) and + helpdb.get_entry_tags(command).armok end -- ----------------- -- @@ -26,11 +26,11 @@ end -- ----------------- -- HotspotMenuWidget = defclass(HotspotMenuWidget, overlay.OverlayWidget) -HotspotMenuWidget.ATTRS{ - default_pos={x=5,y=1}, - default_enabled=true, - version=2, - viewscreens={ +HotspotMenuWidget.ATTRS { + default_pos = { x = 5, y = 1 }, + default_enabled = true, + version = 2, + viewscreens = { 'adopt_region', 'choose_game_type', -- 'choose_start_site', -- conflicts with vanilla panel layouts @@ -48,51 +48,51 @@ HotspotMenuWidget.ATTRS{ 'update_region', 'world' }, - frame={w=4, h=3} + frame = { w = 4, h = 3 } } function HotspotMenuWidget:init() local to_pen = dfhack.pen.parse local function tp(idx, ch) - return to_pen{ - tile=function() return dfhack.textures.getTexposByHandle(logo_textures[idx]) end, - ch=ch, - fg=COLOR_GREY, + return to_pen { + tile = function() return dfhack.textures.getTexposByHandle(logo_textures[idx]) end, + ch = ch, + fg = COLOR_GREY, } end local function tph(idx, ch) - return to_pen{ - tile=function() return dfhack.textures.getTexposByHandle(logo_hovered_textures[idx]) end, - ch=ch, - fg=COLOR_WHITE, + return to_pen { + tile = function() return dfhack.textures.getTexposByHandle(logo_hovered_textures[idx]) end, + ch = ch, + fg = COLOR_WHITE, } end local function get_tile_token(idx, ch) return { - tile=tp(idx, ch), - htile=tph(idx, ch), - width=1, + tile = tp(idx, ch), + htile = tph(idx, ch), + width = 1, } end - self:addviews{ - widgets.Label{ - text={ + self:addviews { + widgets.Label { + text = { get_tile_token(1, '!'), get_tile_token(2, 'D'), get_tile_token(3, 'F'), get_tile_token(4, '!'), NEWLINE, get_tile_token(5, '!'), get_tile_token(6, 'H'), get_tile_token(7, 'a'), get_tile_token(8, '!'), NEWLINE, get_tile_token(9, '!'), get_tile_token(10, 'c'), get_tile_token(11, 'k'), get_tile_token(12, '!'), }, - on_click=function() dfhack.run_command('hotkeys') end, + on_click = function() dfhack.run_command('hotkeys') end, }, } end function HotspotMenuWidget:overlay_trigger() - return MenuScreen{hotspot=self}:show() + return MenuScreen { hotspot = self }:show() end -- register the menu hotspot with the overlay -OVERLAY_WIDGETS = {menu=HotspotMenuWidget} +OVERLAY_WIDGETS = { menu = HotspotMenuWidget } -- ---- -- -- Menu -- @@ -103,15 +103,15 @@ local MAX_LIST_WIDTH = 45 local MAX_LIST_HEIGHT = 15 Menu = defclass(Menu, widgets.Panel) -Menu.ATTRS{ - hotspot=DEFAULT_NIL, +Menu.ATTRS { + hotspot = DEFAULT_NIL, } -- get a map from the binding string to a list of hotkey strings that all -- point to that binding local function get_bindings_to_hotkeys(hotkeys, bindings) local bindings_to_hotkeys = {} - for _,hotkey in ipairs(hotkeys) do + for _, hotkey in ipairs(hotkeys) do local binding = bindings[hotkey] table.insert(ensure_key(bindings_to_hotkeys, binding), hotkey) end @@ -126,17 +126,17 @@ local function get_choices(hotkeys, bindings, is_inverted) local bindings_to_hotkeys = get_bindings_to_hotkeys(hotkeys, bindings) -- build list choices - for _,hotkey in ipairs(hotkeys) do + for _, hotkey in ipairs(hotkeys) do local command = bindings[hotkey] if seen[command] then goto continue end seen[command] = true local hk_width, tokens = 0, {} - for _,hk in ipairs(bindings_to_hotkeys[command]) do + for _, hk in ipairs(bindings_to_hotkeys[command]) do if hk_width ~= 0 then table.insert(tokens, ', ') hk_width = hk_width + 2 end - table.insert(tokens, {text=hk, pen=COLOR_LIGHTGREEN}) + table.insert(tokens, { text = hk, pen = COLOR_LIGHTGREEN }) hk_width = hk_width + #hk end local command_str = command @@ -144,16 +144,20 @@ local function get_choices(hotkeys, bindings, is_inverted) local max_command_len = MAX_LIST_WIDTH - hk_width - LIST_BUFFER command_str = command:sub(1, max_command_len - 3) .. '...' end - table.insert(tokens, 1, {text=command_str}) - local choice = {icon=ARROW, command=command, text=tokens, - hk_width=hk_width} + table.insert(tokens, 1, { text = command_str }) + local choice = { + icon = ARROW, + command = command, + text = tokens, + hk_width = hk_width + } max_width = math.max(max_width, hk_width + #command_str + LIST_BUFFER) table.insert(choices, is_inverted and 1 or #choices + 1, choice) ::continue:: end -- adjust width of command fields so the hotkey tokens are right justified - for _,choice in ipairs(choices) do + for _, choice in ipairs(choices) do local command_token = choice.text[1] command_token.width = max_width - choice.hk_width - (LIST_BUFFER - 1) end @@ -164,17 +168,17 @@ end function Menu:init() local hotkeys, bindings = getHotkeys() if #hotkeys == 0 then - hotkeys = {''} - bindings = {['']='gui/launcher'} + hotkeys = { '' } + bindings = { [''] = 'gui/launcher' } end local is_inverted = not not self.hotspot.frame.b - local choices,list_width = get_choices(hotkeys, bindings, is_inverted) + local choices, list_width = get_choices(hotkeys, bindings, is_inverted) list_width = math.max(35, list_width) local list_frame = copyall(self.hotspot.frame) - local list_widget_frame = {h=math.min(#choices, MAX_LIST_HEIGHT)} + local list_widget_frame = { h = math.min(#choices, MAX_LIST_HEIGHT) } local quickstart_frame = {} list_frame.w = list_width + 2 list_frame.h = list_widget_frame.h + 4 @@ -193,51 +197,51 @@ function Menu:init() list_frame.r = math.max(0, list_frame.r + 5) end - local help_frame = {w=list_frame.w, l=list_frame.l, r=list_frame.r} + local help_frame = { w = list_frame.w, l = list_frame.l, r = list_frame.r } if list_frame.t then help_frame.t = list_frame.t + list_frame.h else help_frame.b = list_frame.b + list_frame.h end - self:addviews{ - widgets.Panel{ - view_id='list_panel', - frame=list_frame, - frame_style=gui.PANEL_FRAME, - frame_background=gui.CLEAR_PEN, - subviews={ - widgets.List{ - view_id='list', - frame=list_widget_frame, - choices=choices, - icon_width=2, - on_select=self:callback('onSelect'), - on_submit=self:callback('onSubmit'), - on_submit2=self:callback('onSubmit2'), + self:addviews { + widgets.Panel { + view_id = 'list_panel', + frame = list_frame, + frame_style = gui.PANEL_FRAME, + frame_background = gui.CLEAR_PEN, + subviews = { + widgets.List { + view_id = 'list', + frame = list_widget_frame, + choices = choices, + icon_width = 2, + on_select = self:callback('onSelect'), + on_submit = self:callback('onSubmit'), + on_submit2 = self:callback('onSubmit2'), }, - widgets.Panel{frame={h=1}}, - widgets.HotkeyLabel{ - frame=quickstart_frame, - label='Quickstart guide', - key='STRING_A063', - on_activate=function() - self:onSubmit(nil, {command='quickstart-guide'}) + widgets.Panel { frame = { h = 1 } }, + widgets.HotkeyLabel { + frame = quickstart_frame, + label = 'Quickstart guide', + key = 'STRING_A063', + on_activate = function() + self:onSubmit(nil, { command = 'quickstart-guide' }) end, }, }, }, - widgets.ResizingPanel{ - view_id='help_panel', - autoarrange_subviews=true, - frame=help_frame, - frame_style=gui.PANEL_FRAME, - frame_background=gui.CLEAR_PEN, - subviews={ - widgets.WrappedLabel{ - view_id='help', - text_to_wrap='', - scroll_keys={}, + widgets.ResizingPanel { + view_id = 'help_panel', + autoarrange_subviews = true, + frame = help_frame, + frame_style = gui.PANEL_FRAME, + frame_background = gui.CLEAR_PEN, + subviews = { + widgets.WrappedLabel { + view_id = 'help', + text_to_wrap = '', + scroll_keys = {}, }, }, }, @@ -252,7 +256,7 @@ function Menu:onSelect(_, choice) if not choice or #self.subviews == 0 then return end local command = get_command(choice.command) self.subviews.help.text_to_wrap = helpdb.is_entry(command) and - helpdb.get_entry_short_help(command) or 'Command not found' + helpdb.get_entry_short_help(command) or 'Command not found' self.subviews.help_panel:updateLayout() end @@ -302,7 +306,7 @@ end function Menu:getMouseFramePos() return self.subviews.list_panel:getMouseFramePos() or - self.subviews.help_panel:getMouseFramePos() + self.subviews.help_panel:getMouseFramePos() end function Menu:onRenderBody(dc) @@ -324,14 +328,14 @@ end MenuScreen = defclass(MenuScreen, gui.ZScreen) MenuScreen.ATTRS { - focus_path='hotkeys/menu', - initial_pause=false, - hotspot=DEFAULT_NIL, + focus_path = 'hotkeys/menu', + initial_pause = false, + hotspot = DEFAULT_NIL, } function MenuScreen:init() - self:addviews{ - Menu{hotspot=self.hotspot}, + self:addviews { + Menu { hotspot = self.hotspot }, } end diff --git a/plugins/pathable.cpp b/plugins/pathable.cpp index 12852a894..be6537d32 100644 --- a/plugins/pathable.cpp +++ b/plugins/pathable.cpp @@ -36,7 +36,7 @@ namespace DFHack { static std::vector textures; DFhackCExport command_result plugin_init(color_ostream &out, std::vector &commands) { - textures = Textures::loadTileset("hack/data/art/pathable.png", 32, 32); + textures = Textures::loadTileset("hack/data/art/pathable.png", 32, 32, true); return CR_OK; }