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.
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
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
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()``
If the ZScreen subclass has a subview with a ``view_id`` equal to "main",
then the mouse will be considered to be over the visible viewscreen elements
when ``self.subviews.main:getMouseFramePos()`` returns a position. Subclasses
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.
The default implementation iterates over the direct subviews of the ZScreen
subclass and sees if ``getMouseFramePos()`` returns a position for any of
them. Subclasses can override this function if that logic is not appropriate.
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()
self:addviews{MyWindow{view_id='main'}}
self:addviews{MyWindow{}}
end
function MyScreen:onDismiss()
@ -4315,6 +4325,11 @@ Has attributes:
hitting :kbd:`Esc` (while resizing with the mouse or keyboard), or by calling
``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_gap = int`` (default: ``0``)
@ -4376,7 +4391,7 @@ Window class
------------
Subclass of Panel; sets Panel attributes to useful defaults for a top-level
framed, draggable window.
framed, lockable, draggable window.
ResizingPanel class
-------------------

@ -706,6 +706,10 @@ function ZScreen:isOnTop()
return dfhack.gui.getCurViewscreen(true) == self._native
end
function ZScreen:toggleLocked()
self.locked = not self.locked
end
function ZScreen:onInput(keys)
if not self:isOnTop() 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
return
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()
-- ensure underlying DF screens don't also react to the click
df.global.enabler.mouse_rbut_down = 0
@ -732,7 +742,6 @@ function ZScreen:onInput(keys)
end
end
-- move this viewscreen to the top of the stack (if it's not there already)
function ZScreen:raise()
if self:isDismissed() or self:isOnTop() then
return self
@ -741,10 +750,10 @@ function ZScreen:raise()
return self
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()
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
--------------------------
@ -777,9 +786,11 @@ GREY_LINE_FRAME = {
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 },
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 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)
@ -802,6 +813,14 @@ function paint_frame(dc,rect,style,title)
end
dscreen.paintString(style.title_pen or pen, x, y1, tstr)
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
FramedScreen = defclass(FramedScreen, Screen)

@ -81,6 +81,7 @@ Panel.ATTRS {
resize_min = DEFAULT_NIL,
on_resize_begin = DEFAULT_NIL,
on_resize_end = DEFAULT_NIL,
lockable = false,
autoarrange_subviews = false, -- whether to automatically lay out subviews
autoarrange_gap = 0, -- how many blank lines to insert between widgets
}
@ -464,7 +465,11 @@ end
function Panel:onRenderFrame(dc, rect)
Panel.super.onRenderFrame(self, dc, rect)
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
local pos = self.kbd_get_pos()
local pen = to_pen{fg=COLOR_GREEN, bg=COLOR_BLACK}
@ -487,8 +492,20 @@ Window.ATTRS {
frame_background = gui.CLEAR_PEN,
frame_inset = 1,
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 --
-------------------