diff --git a/docs/changelog.txt b/docs/changelog.txt index d0c7b1abb..08aa39951 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -49,6 +49,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: ## API - ``Gui::getDwarfmodeDims``: now only returns map viewport dimensions; menu dimensions are obsolete - ``Gui::getDFViewscreen``: returns the topmost underlying DF viewscreen +- ``Screen::Pen``: now accepts ``keep_lower`` and ``write_to_lower`` properties to support foreground and background textures in graphics mode ## Lua - Removed ``os.execute()`` and ``io.popen()`` built-in functions @@ -58,10 +59,13 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - ``widgets.CycleHotkeyLabel``: now supports rendering option labels in the color of your choice - ``widgets.CycleHotkeyLabel``: new functions ``setOption()`` and ``getOptionPen()`` - ``widgets.ToggleHotkeyLabel``: now renders the ``On`` option in green text +- ``widgets.Label``: tiles can now have an associated width - `overlay`: ``OverlayWidget`` now inherits from ``Panel`` instead of ``Widget`` to get all the frame and mouse integration goodies - ``dfhack.gui.getDFViewscreen()``: returns the topmost underlying DF viewscreen - ``gui.ZScreen``: Screen subclass that implements window raising, multi-viewscreen input handling, and viewscreen event pass-through so the underlying map can be interacted with and dragged around while DFHack screens are visible - ``gui.View``: new function ``view:getMouseFramePos()`` for detecting whether the mouse is within (or over) the exterior frame of a view +- ``gui.CLEAR_PEN``: now clears the background and foreground and writes to the background (before it would always write to the foreground) +- ``gui.KEEP_LOWER_PEN``: a general use pen that writes associated tiles to the foreground while keeping the existing background ## Internals diff --git a/docs/dev/Lua API.rst b/docs/dev/Lua API.rst index 90ccdb851..f73af1472 100644 --- a/docs/dev/Lua API.rst +++ b/docs/dev/Lua API.rst @@ -2266,6 +2266,12 @@ a table with the following possible fields: Specifies that the tile should be shaded with *fg/bg*. ``tile_fg, tile_bg`` If specified, overrides *tile_color* and supplies shading colors directly. + ``keep_lower`` + If set to true, will not overwrite the background tile when filling in + the foreground tile. + ``write_to_lower`` + If set to true, the specified ``tile`` will be written to the background + instead of the foreground. Alternatively, it may be a pre-parsed native object with the following API: @@ -3654,7 +3660,13 @@ Misc * ``CLEAR_PEN`` - The black pen used to clear the screen. + The black pen used to clear the screen. In graphics mode, it will clear the + foreground and set the background to the standard black tile. + +* ``KEEP_LOWER_PEN`` + + A pen that will write tiles over existing background tiles instead of clearing + them. * ``simulateInput(screen, keys...)`` @@ -4582,8 +4594,8 @@ containing newlines, or a table with the following possible fields: * ``token.width = ...`` - If specified either as a value or a callback, the text field is padded - or truncated to the specified number. + If specified either as a value or a callback, the text (or tile) field is + padded or truncated to the specified number. * ``token.pad_char = '?'`` diff --git a/library/LuaApi.cpp b/library/LuaApi.cpp index c327efe1b..90815708d 100644 --- a/library/LuaApi.cpp +++ b/library/LuaApi.cpp @@ -177,6 +177,17 @@ static bool get_char_field(lua_State *L, char *pf, int idx, const char *name, ch } } +static bool get_bool_field(lua_State *L, bool *pf, int idx, const char *name, bool defval) { + lua_getfield(L, idx, name); + bool nil = lua_isnil(L, -1); + if (nil) + *pf = defval; + else + *pf = lua_toboolean(L, -1); + lua_pop(L, 1); + return !nil; +} + static void decode_pen(lua_State *L, Pen &pen, int idx) { idx = lua_absindex(L, idx); @@ -208,6 +219,9 @@ static void decode_pen(lua_State *L, Pen &pen, int idx) pen.tile_mode = (lua_toboolean(L, -1) ? Pen::CharColor : Pen::AsIs); lua_pop(L, 1); } + + get_bool_field(L, &pen.keep_lower, idx, "keep_lower", false); + get_bool_field(L, &pen.write_to_lower, idx, "write_to_lower", false); } /************************************************** diff --git a/library/include/modules/Screen.h b/library/include/modules/Screen.h index bc8a406a0..9417d60e9 100644 --- a/library/include/modules/Screen.h +++ b/library/include/modules/Screen.h @@ -84,6 +84,9 @@ namespace DFHack } tile_mode; int8_t tile_fg, tile_bg; + bool write_to_lower = false; + bool keep_lower = false; + bool valid() const { return tile >= 0; } bool empty() const { return ch == 0 && tile == 0; } diff --git a/library/lua/gui.lua b/library/lua/gui.lua index ade8d0ceb..50b5fed3a 100644 --- a/library/lua/gui.lua +++ b/library/lua/gui.lua @@ -9,7 +9,8 @@ local getval = utils.getval local to_pen = dfhack.pen.parse -CLEAR_PEN = to_pen{tile=909, ch=32, fg=0, bg=0} +CLEAR_PEN = to_pen{tile=909, ch=32, fg=0, bg=0, write_to_lower=true} +KEEP_LOWER_PEN = to_pen{ch=32, fg=0, bg=0, keep_lower=true} local FAKE_INPUT_KEYS = { _MOUSE_L = true, diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 4a39efa8e..52c89b63b 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -688,7 +688,6 @@ function EditField:onRenderBody(dc) end_pos == #txt and '' or string.char(26)) end dc:advance(self.text_offset):string(txt) - dc:string((' '):rep(dc.clip_x2 - dc.x)) end function EditField:insert(text) @@ -1102,6 +1101,9 @@ function render_text(obj,dc,x0,y0,pen,dpen,disabled) x = x + 1 if dc then dc:tile(nil, token.tile) + if token.width then + dc:advance(token.width-1) + end end end diff --git a/library/modules/Screen.cpp b/library/modules/Screen.cpp index ae0a15b5e..a05db1da1 100644 --- a/library/modules/Screen.cpp +++ b/library/modules/Screen.cpp @@ -157,7 +157,8 @@ static bool doSetTile_default(const Pen &pen, int x, int y, bool map) *screen = 0; *texpos = 0; - *texpos_lower = 0; + if (!pen.keep_lower) + *texpos_lower = 0; gps->screentexpos_anchored[index] = 0; // keep SCREENTEXPOS_FLAG_ANCHOR_SUBORDINATE so occluded anchored textures // don't appear corrupted @@ -171,7 +172,8 @@ static bool doSetTile_default(const Pen &pen, int x, int y, bool map) *screen = 0; *texpos = 0; - *texpos_lower = 0; + if (!pen.keep_lower) + *texpos_lower = 0; gps->screentexpos_top_anchored[index] = 0; *flag &= 4; // keep SCREENTEXPOS_FLAG_ANCHOR_SUBORDINATE } @@ -190,10 +192,13 @@ static bool doSetTile_default(const Pen &pen, int x, int y, bool map) } if (pen.tile && use_graphics) { - *texpos = pen.tile; + if (pen.write_to_lower) + *texpos_lower = pen.tile; + else + *texpos = pen.tile; } else { screen[0] = uint8_t(pen.ch); - *texpos_lower = 909; + *texpos_lower = 909; // basic black background } auto rgb_fg = &gps->uccolor[fg][0];