make windows lockable (can ignore r-click and esc)

develop
Myk Taylor 2023-01-06 18:48:53 -08:00
parent 1f5ae4165f
commit 810430f1a2
No known key found for this signature in database
GPG Key ID: 8A39CA0FA0C16E78
3 changed files with 67 additions and 16 deletions

@ -4094,7 +4094,15 @@ Clicks that are not over any visible ZScreen element, of course, are passed
through to the underlying viewscreen. through to the underlying viewscreen.
If :kbd:`Esc` or the right mouse button is pressed, and the ZScreen widgets If :kbd:`Esc` or the right mouse button is pressed, and the ZScreen widgets
don't otherwise handle them, then the top ZScreen is dismissed. don't otherwise handle them, then the top ZScreen is dismissed. If the ZScreen
is "locked", then the screen is not dismissed and the input is passed on to the
underlying DF viewscreen. :kbd:`Alt`:kbd:`L` toggles the locked status if the
ZScreen widgets don't otherwise handle that key sequence. If you have a
``Panel`` with the ``lockable`` attribute set and a frame that has pens defined
for the lock icon (like ``Window`` widgets have by default), then a lock icon
will appear in the upper right corner of the frame. Clicking on this icon will
toggle the ZScreen ``locked`` status just as if :kbd:`Alt`:kbd:`L` had been
pressed.
Keyboard input goes to the top ZScreen, as usual. If the subviews of the top Keyboard input goes to the top ZScreen, as usual. If the subviews of the top
ZScreen don't handle the input (i.e. they all return something falsey), the ZScreen don't handle the input (i.e. they all return something falsey), the
@ -4122,14 +4130,16 @@ ZScreen provides the following functions:
when the tool command is run and raise the existing dialog if it exists or when the tool command is run and raise the existing dialog if it exists or
show a new dialog if it doesn't. See the sample code below for an example. show a new dialog if it doesn't. See the sample code below for an example.
* ``zscreen:toggleLocked()``
Toggles whether the window closes on :kbd:`ESC` or r-click (unlocked) or not
(locked).
* ``zscreen:isMouseOver()`` * ``zscreen:isMouseOver()``
If the ZScreen subclass has a subview with a ``view_id`` equal to "main", The default implementation iterates over the direct subviews of the ZScreen
then the mouse will be considered to be over the visible viewscreen elements subclass and sees if ``getMouseFramePos()`` returns a position for any of
when ``self.subviews.main:getMouseFramePos()`` returns a position. Subclasses them. Subclasses can override this function if that logic is not appropriate.
can override this function if that logic is not appropriate, for example if
there are multiple independent windows being shown and this function should
return true if the mouse is over any of them.
Here is an example skeleton for a ZScreen tool dialog:: Here is an example skeleton for a ZScreen tool dialog::
@ -4159,7 +4169,7 @@ Here is an example skeleton for a ZScreen tool dialog::
} }
function MyScreen:init() function MyScreen:init()
self:addviews{MyWindow{view_id='main'}} self:addviews{MyWindow{}}
end end
function MyScreen:onDismiss() function MyScreen:onDismiss()
@ -4315,6 +4325,11 @@ Has attributes:
hitting :kbd:`Esc` (while resizing with the mouse or keyboard), or by calling hitting :kbd:`Esc` (while resizing with the mouse or keyboard), or by calling
``Panel:setKeyboardResizeEnabled(false)`` (while resizing with the keyboard). ``Panel:setKeyboardResizeEnabled(false)`` (while resizing with the keyboard).
* ``lockable = bool`` (default: ``false``)
Determines whether the panel will draw a lock icon in its frame. See
`ZScreen class`_ for details.
* ``autoarrange_subviews = bool`` (default: ``false``) * ``autoarrange_subviews = bool`` (default: ``false``)
* ``autoarrange_gap = int`` (default: ``0``) * ``autoarrange_gap = int`` (default: ``0``)
@ -4376,7 +4391,7 @@ Window class
------------ ------------
Subclass of Panel; sets Panel attributes to useful defaults for a top-level Subclass of Panel; sets Panel attributes to useful defaults for a top-level
framed, draggable window. framed, lockable, draggable window.
ResizingPanel class ResizingPanel class
------------------- -------------------

@ -706,6 +706,10 @@ function ZScreen:isOnTop()
return dfhack.gui.getCurViewscreen(true) == self._native return dfhack.gui.getCurViewscreen(true) == self._native
end end
function ZScreen:toggleLocked()
self.locked = not self.locked
end
function ZScreen:onInput(keys) function ZScreen:onInput(keys)
if not self:isOnTop() then if not self:isOnTop() then
if keys._MOUSE_L_DOWN and self:isMouseOver() then if keys._MOUSE_L_DOWN and self:isMouseOver() then
@ -719,7 +723,13 @@ function ZScreen:onInput(keys)
if ZScreen.super.onInput(self, keys) then if ZScreen.super.onInput(self, keys) then
return return
end end
if keys.LEAVESCREEN or keys._MOUSE_R_DOWN then
if keys.CUSTOM_ALT_L then
self:toggleLocked()
return
end
if not self.locked and (keys.LEAVESCREEN or keys._MOUSE_R_DOWN) then
self:dismiss() self:dismiss()
-- ensure underlying DF screens don't also react to the click -- ensure underlying DF screens don't also react to the click
df.global.enabler.mouse_rbut_down = 0 df.global.enabler.mouse_rbut_down = 0
@ -732,7 +742,6 @@ function ZScreen:onInput(keys)
end end
end end
-- move this viewscreen to the top of the stack (if it's not there already)
function ZScreen:raise() function ZScreen:raise()
if self:isDismissed() or self:isOnTop() then if self:isDismissed() or self:isOnTop() then
return self return self
@ -741,10 +750,10 @@ function ZScreen:raise()
return self return self
end end
-- subclasses should either annotate their viewable panel with view_id='main'
-- or override this and return whether the mouse is over an owned screen element
function ZScreen:isMouseOver() function ZScreen:isMouseOver()
return self.subviews.main and self.subviews.main:getMouseFramePos() or false for _,sv in ipairs(self.subviews) do
if sv:getMouseFramePos() then return true end
end
end end
-------------------------- --------------------------
@ -777,9 +786,11 @@ GREY_LINE_FRAME = {
rb_frame_pen = to_pen{ tile=917, ch=188, fg=COLOR_GREY, bg=COLOR_BLACK }, rb_frame_pen = to_pen{ tile=917, ch=188, fg=COLOR_GREY, bg=COLOR_BLACK },
title_pen = to_pen{ fg=COLOR_BLACK, bg=COLOR_GREY }, title_pen = to_pen{ fg=COLOR_BLACK, bg=COLOR_GREY },
signature_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK }, signature_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK },
locked_pen = to_pen{tile=779, ch=216, fg=COLOR_GREY, bg=COLOR_GREEN},
unlocked_pen = to_pen{tile=782, ch=216, fg=COLOR_GREY, bg=COLOR_BLACK},
} }
function paint_frame(dc,rect,style,title) function paint_frame(dc,rect,style,title,show_lock,locked)
local pen = style.frame_pen local pen = style.frame_pen
local x1,y1,x2,y2 = dc.x1+rect.x1, dc.y1+rect.y1, dc.x1+rect.x2, dc.y1+rect.y2 local x1,y1,x2,y2 = dc.x1+rect.x1, dc.y1+rect.y1, dc.x1+rect.x2, dc.y1+rect.y2
dscreen.paintTile(style.lt_frame_pen or pen, x1, y1) dscreen.paintTile(style.lt_frame_pen or pen, x1, y1)
@ -802,6 +813,14 @@ function paint_frame(dc,rect,style,title)
end end
dscreen.paintString(style.title_pen or pen, x, y1, tstr) dscreen.paintString(style.title_pen or pen, x, y1, tstr)
end end
if show_lock then
if locked and style.locked_pen then
dscreen.paintTile(style.locked_pen, x2-1, y1)
elseif not locked and style.unlocked_pen then
dscreen.paintTile(style.unlocked_pen, x2-1, y1)
end
end
end end
FramedScreen = defclass(FramedScreen, Screen) FramedScreen = defclass(FramedScreen, Screen)

@ -81,6 +81,7 @@ Panel.ATTRS {
resize_min = DEFAULT_NIL, resize_min = DEFAULT_NIL,
on_resize_begin = DEFAULT_NIL, on_resize_begin = DEFAULT_NIL,
on_resize_end = DEFAULT_NIL, on_resize_end = DEFAULT_NIL,
lockable = false,
autoarrange_subviews = false, -- whether to automatically lay out subviews autoarrange_subviews = false, -- whether to automatically lay out subviews
autoarrange_gap = 0, -- how many blank lines to insert between widgets autoarrange_gap = 0, -- how many blank lines to insert between widgets
} }
@ -464,7 +465,11 @@ end
function Panel:onRenderFrame(dc, rect) function Panel:onRenderFrame(dc, rect)
Panel.super.onRenderFrame(self, dc, rect) Panel.super.onRenderFrame(self, dc, rect)
if not self.frame_style then return end if not self.frame_style then return end
gui.paint_frame(dc, rect, self.frame_style, self.frame_title) local locked = nil
if self.lockable then
locked = self.parent_view and self.parent_view.locked
end
gui.paint_frame(dc, rect, self.frame_style, self.frame_title, self.lockable, locked)
if self.kbd_get_pos then if self.kbd_get_pos then
local pos = self.kbd_get_pos() local pos = self.kbd_get_pos()
local pen = to_pen{fg=COLOR_GREEN, bg=COLOR_BLACK} local pen = to_pen{fg=COLOR_GREEN, bg=COLOR_BLACK}
@ -487,8 +492,20 @@ Window.ATTRS {
frame_background = gui.CLEAR_PEN, frame_background = gui.CLEAR_PEN,
frame_inset = 1, frame_inset = 1,
draggable = true, draggable = true,
lockable = true,
} }
function Window:onInput(keys)
if keys._MOUSE_L_DOWN and self.parent_view and self.parent_view.toggleLocked then
local x,y = dscreen.getMousePos()
local frame_rect = self.frame_rect
if x == frame_rect.x2-1 and y == frame_rect.y1 then
self.parent_view:toggleLocked()
end
end
return Window.super.onInput(self, keys)
end
------------------- -------------------
-- ResizingPanel -- -- ResizingPanel --
------------------- -------------------