Merge pull request #2601 from myk002/myk_dwarfmode

pull the useful bits out of guidm.MenuOverlay and make them available
develop
Myk 2023-01-14 01:09:57 -08:00 committed by GitHub
commit fc6a8fb00b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 40 additions and 109 deletions

@ -4472,9 +4472,10 @@ calling ``setFocus(true)`` on the field object.
If an activation ``key`` is specified, the ``EditField`` will manage its own
focus. It will start in the unfocused state, and pressing the activation key
will acquire keyboard focus. Pressing the Enter key will release keyboard focus
and then call the ``on_submit`` callback. Pressing the Escape key will also
release keyboard focus, but first it will restore the text that was displayed
before the ``EditField`` gained focus and then call the ``on_change`` callback.
and then call the ``on_submit`` callback. Pressing the Escape key (or r-clicking
with the mouse) will also release keyboard focus, but first it will restore the
text that was displayed before the ``EditField`` gained focus and then call the
``on_change`` callback.
The ``EditField`` cursor can be moved to where you want to insert/remove text.
You can click where you want the cursor to move or you can use any of the

@ -286,6 +286,19 @@ function get_hotkey_target(key)
end
end
function getMapKey(keys)
for code in pairs(keys) do
if MOVEMENT_KEYS[code] or HOTKEY_KEYS[code]
or code == '_MOUSE_M_DOWN' or code == '_MOUSE_M'
or code == 'ZOOM_OUT' or code == 'ZOOM_IN' then
if not HOTKEY_KEYS[code] or get_hotkey_target(code) then
return true
end
return code
end
end
end
function Viewport:scrollByKey(key)
local dx, dy, dz = get_movement_delta(key, 10, 20)
if dx then
@ -339,13 +352,9 @@ function DwarfOverlay:selectBuilding(building,cursor,viewport,gap)
end
function DwarfOverlay:propagateMoveKeys(keys)
for code,_ in pairs(keys) do
if MOVEMENT_KEYS[code] or HOTKEY_KEYS[code] then
if not HOTKEY_KEYS[code] or get_hotkey_target(code) then
self:sendInputToParent(code)
end
return code
end
local map_key = getMapKey(keys)
if map_key then
self:sendInputToParent(map_key)
end
end
@ -414,124 +423,45 @@ function DwarfOverlay:onAboutToShow(parent)
end
end
MenuOverlay = defclass(MenuOverlay, DwarfOverlay)
MenuOverlay.ATTRS {
frame_inset = 0,
frame_background = gui.CLEAR_PEN,
-- if sidebar_mode is set, we will enter the specified sidebar mode on show
-- and restore the previous sidebar mode on dismiss. otherwise it is up to
-- the caller to ensure we are in a sidebar mode where the menu is visible.
sidebar_mode = DEFAULT_NIL,
}
function MenuOverlay:init()
if not dfhack.isMapLoaded() then
-- sidebar menus are only valid when a fort map is loaded
error('A fortress map must be loaded.')
end
if self.sidebar_mode then
self.saved_sidebar_mode = df.global.plotinfo.main.mode
-- what mode should we restore when this window is dismissed? ideally, we'd
-- restore the mode that the user has set, but we should fall back to
-- restoring the default mode if either of the following conditions are
-- true:
-- 1) enterSidebarMode doesn't support getting back into the current mode
-- 2) a dfhack viewscreen is currently visible. in this case, we can't trust
-- that the current sidebar mode was set by the user. it could just be a
-- MenuOverlay subclass that is currently being shown that has set the
-- sidebar mode for its own purposes.
if not SIDEBAR_MODE_KEYS[self.saved_sidebar_mode]
or dfhack.gui.getCurFocus(true):find('^dfhack/') then
self.saved_sidebar_mode = df.ui_sidebar_mode.Default
end
enterSidebarMode(self.sidebar_mode)
end
end
function MenuOverlay:computeFrame(parent_rect)
return self.df_layout.menu, gui.inset_frame(self.df_layout.menu, self.frame_inset)
end
function MenuOverlay:onAboutToShow(parent)
self:updateLayout()
if not self.df_layout.menu then
error("The menu panel of dwarfmode is not visible")
end
end
function MenuOverlay:onDismiss()
if self.saved_sidebar_mode then
enterSidebarMode(self.saved_sidebar_mode)
end
end
function MenuOverlay:render(dc)
self:renderParent()
local menu = self.df_layout.menu
if menu then
-- Paint signature on the frame.
dscreen.paintString(
{fg=COLOR_BLACK,bg=COLOR_DARKGREY},
menu.x1+1, menu.y2+1, "DFHack"
)
if self.frame_background then
dc:fill(menu, self.frame_background)
end
MenuOverlay.super.render(self, dc)
end
end
-- Framework for managing rendering over the map area. This function is intended
-- to be called from a subclass's onRenderBody() function.
-- to be called from a window's onRenderFrame() function.
--
-- get_overlay_char_fn takes a coordinate position and an is_cursor boolean and
-- returns the char to render at that position and, optionally, the foreground
-- and background colors to use to draw the char. If nothing should be rendered
-- at that position, the function should return nil. If no foreground color is
-- specified, it defaults to COLOR_GREEN. If no background color is specified,
-- it defaults to COLOR_BLACK.
-- get_overlay_pen_fn takes a coordinate position and an is_cursor boolean and
-- returns the pen (and optional char and tile) to render at that position. If
-- nothing should be rendered at that position, the function should return nil.
--
-- bounds_rect has elements {x1, x2, y1, y2} in global map coordinates (not
-- screen coordinates). The rect is intersected with the visible map viewport to
-- get the range over which get_overlay_char_fn is called. If bounds_rect is not
-- specified, the entire viewport is scanned.
--
-- example call from a subclass:
-- function MyMenuOverlaySubclass:onRenderBody()
-- local function get_overlay_char(pos)
-- return safe_index(self.overlay_chars, pos.z, pos.y, pos.x), COLOR_RED
-- example call:
-- function MyMapOverlay:onRenderFrame(dc, rect)
-- local function get_overlay_pen(pos)
-- if safe_index(self.overlay_map, pos.z, pos.y, pos.x) then
-- return COLOR_GREEN, 'X', dfhack.screen.findGraphicsTile('CURSORS', 4, 3)
-- end
-- end
-- self:renderMapOverlay(get_overlay_char, self.overlay_bounds)
-- guidm.renderMapOverlay(get_overlay_pen, self.overlay_bounds)
-- end
function MenuOverlay:renderMapOverlay(get_overlay_char_fn, bounds_rect)
local vp = self:getViewport()
function renderMapOverlay(get_overlay_pen_fn, bounds_rect)
local vp = Viewport.get()
local rect = gui.ViewRect{rect=vp,
clip_view=bounds_rect and gui.ViewRect{rect=bounds_rect} or nil}
-- nothing to do if the viewport is completely separate from the bounds_rect
-- nothing to do if the viewport is completely disjoint from the bounds_rect
if rect:isDefunct() then return end
local dc = gui.Painter.new(self.df_layout.map)
local z = df.global.window_z
local cursor = getCursorPos()
for y=rect.clip_y1,rect.clip_y2 do
for x=rect.clip_x1,rect.clip_x2 do
local pos = xyz2pos(x, y, z)
local overlay_char, fg_color, bg_color = get_overlay_char_fn(
pos, same_xy(cursor, pos))
if not overlay_char then goto continue end
local stile = vp:tileToScreen(pos)
dc:map(true):seek(stile.x, stile.y):
pen(fg_color or COLOR_GREEN, bg_color or COLOR_BLACK):
char(overlay_char):map(false)
::continue::
local overlay_pen, char, tile = get_overlay_pen_fn(pos, same_xy(cursor, pos))
if overlay_pen then
local stile = vp:tileToScreen(pos)
dscreen.paintTile(overlay_pen, stile.x, stile.y, char, tile, true)
end
end
end
end

@ -708,7 +708,7 @@ function EditField:onInput(keys)
end
end
if self.key and keys.LEAVESCREEN then
if self.key and (keys.LEAVESCREEN or keys._MOUSE_R_DOWN) then
local old = self.text
self:setText(self.saved_text)
if self.on_change and old ~= self.saved_text then