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 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 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 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 and then call the ``on_submit`` callback. Pressing the Escape key (or r-clicking
release keyboard focus, but first it will restore the text that was displayed with the mouse) will also release keyboard focus, but first it will restore the
before the ``EditField`` gained focus and then call the ``on_change`` callback. 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. 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 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
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) function Viewport:scrollByKey(key)
local dx, dy, dz = get_movement_delta(key, 10, 20) local dx, dy, dz = get_movement_delta(key, 10, 20)
if dx then if dx then
@ -339,13 +352,9 @@ function DwarfOverlay:selectBuilding(building,cursor,viewport,gap)
end end
function DwarfOverlay:propagateMoveKeys(keys) function DwarfOverlay:propagateMoveKeys(keys)
for code,_ in pairs(keys) do local map_key = getMapKey(keys)
if MOVEMENT_KEYS[code] or HOTKEY_KEYS[code] then if map_key then
if not HOTKEY_KEYS[code] or get_hotkey_target(code) then self:sendInputToParent(map_key)
self:sendInputToParent(code)
end
return code
end
end end
end end
@ -414,124 +423,45 @@ function DwarfOverlay:onAboutToShow(parent)
end end
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 -- 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 -- get_overlay_pen_fn takes a coordinate position and an is_cursor boolean and
-- returns the char to render at that position and, optionally, the foreground -- returns the pen (and optional char and tile) to render at that position. If
-- and background colors to use to draw the char. If nothing should be rendered -- nothing should be rendered at that position, the function should return nil.
-- 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.
-- --
-- bounds_rect has elements {x1, x2, y1, y2} in global map coordinates (not -- 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 -- 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 -- get the range over which get_overlay_char_fn is called. If bounds_rect is not
-- specified, the entire viewport is scanned. -- specified, the entire viewport is scanned.
-- --
-- example call from a subclass: -- example call:
-- function MyMenuOverlaySubclass:onRenderBody() -- function MyMapOverlay:onRenderFrame(dc, rect)
-- local function get_overlay_char(pos) -- local function get_overlay_pen(pos)
-- return safe_index(self.overlay_chars, pos.z, pos.y, pos.x), COLOR_RED -- 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 -- end
-- self:renderMapOverlay(get_overlay_char, self.overlay_bounds) -- guidm.renderMapOverlay(get_overlay_pen, self.overlay_bounds)
-- end -- end
function MenuOverlay:renderMapOverlay(get_overlay_char_fn, bounds_rect) function renderMapOverlay(get_overlay_pen_fn, bounds_rect)
local vp = self:getViewport() local vp = Viewport.get()
local rect = gui.ViewRect{rect=vp, local rect = gui.ViewRect{rect=vp,
clip_view=bounds_rect and gui.ViewRect{rect=bounds_rect} or nil} 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 if rect:isDefunct() then return end
local dc = gui.Painter.new(self.df_layout.map)
local z = df.global.window_z local z = df.global.window_z
local cursor = getCursorPos() local cursor = getCursorPos()
for y=rect.clip_y1,rect.clip_y2 do for y=rect.clip_y1,rect.clip_y2 do
for x=rect.clip_x1,rect.clip_x2 do for x=rect.clip_x1,rect.clip_x2 do
local pos = xyz2pos(x, y, z) local pos = xyz2pos(x, y, z)
local overlay_char, fg_color, bg_color = get_overlay_char_fn( local overlay_pen, char, tile = get_overlay_pen_fn(pos, same_xy(cursor, pos))
pos, same_xy(cursor, pos)) if overlay_pen then
if not overlay_char then goto continue end local stile = vp:tileToScreen(pos)
local stile = vp:tileToScreen(pos) dscreen.paintTile(overlay_pen, stile.x, stile.y, char, tile, true)
dc:map(true):seek(stile.x, stile.y): end
pen(fg_color or COLOR_GREEN, bg_color or COLOR_BLACK):
char(overlay_char):map(false)
::continue::
end end
end end
end end

@ -708,7 +708,7 @@ function EditField:onInput(keys)
end end
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 local old = self.text
self:setText(self.saved_text) self:setText(self.saved_text)
if self.on_change and old ~= self.saved_text then if self.on_change and old ~= self.saved_text then