Merge pull request #2705 from myk002/myk_zscreen_redux

Implement new ZScreen semantics
develop
Myk 2023-01-24 11:14:43 -08:00 committed by GitHub
commit 83c89cfaa9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 183 additions and 142 deletions

@ -99,37 +99,33 @@ How do DFHack in-game windows work?
Many DFHack tools have graphical interfaces that appear in-game. You can tell Many DFHack tools have graphical interfaces that appear in-game. You can tell
which windows belong to DFHack tools because they will have the word "DFHack" which windows belong to DFHack tools because they will have the word "DFHack"
printed across their bottom frame edge. DFHack provides a custom windowing system printed across their bottom frame edge. DFHack provides an advanced windowing
that gives the player a lot of control over where the windows appear and whether system that gives the player a lot of control over where the windows appear and
they capture keyboard and mouse input. whether they capture keyboard and mouse input.
The DFHack windowing system allows you to use DFHack tools without interrupting The DFHack windowing system allows multiple overlapping windows to be active at
the game. That is, if the game is unpaused, it will continue to run while a once. The one with the highlighted title bar has focus and will receive anything
DFHack window is open. You can also interact with the map, scrolling it with the you type at the keyboard. Hit Esc or right click to close the window or cancel
keyboard or mouse and selecting units, buildings, and items. Some tools will the current operation. You can click anywhere on the screen that is not a
capture all keyboard input, such as tools with editable text fields, and some will DFHack window to unfocus the window and let it just sit in the background. It won't
force-pause the game if it makes sense to, like `gui/quickfort`, since you cannot respond to key presses or mouse clicks until you click on it again to give it
interact with the map normally while trying to apply a blueprint. focus. You can right click directly on an unfocused window to close it without
left clicking to activate it first.
DFHack windows are draggable from the title bar or from anywhere on the window DFHack windows are draggable from the title bar or from anywhere on the window
that doesn't have a mouse-clickable widget on it. Many are resizable as well that doesn't have a mouse-clickable widget on it. Many are resizable as well
(if the tool window has components that can reasonably be resized). (if the tool window has components that can reasonably be resized).
DFHack windows close with a right mouse click or keyboard Esc, but if you You can generally use DFHack tools without interrupting the game. That is, if the
want to keep a DFHack tool open while you interact with the game, you can click the game is unpaused, it can continue to run while a DFHack window is open. Many tools
pin in the upper right corner of the DFHack window or hit Alt-L so will initially pause the game to let you focus on the task at hand, but you can
that the pin turns green. The DFHack window will then ignore right clicks and unpause like normal if you want. You can also interact with the map, scrolling it
Esc key presses that would otherwise close the window. This is especially with the keyboard or mouse and selecting units, buildings, and items. Some tools
useful for the configuration tool windows for the automation tools. For example, will capture all keyboard input, such as tools with editable text fields, and some
you can pin the `gui/autochop` window, set it to minimal mode, and let it sit will force-pause the game if it makes sense to, like `gui/quickfort`, since you
there monitoring your logging industry as you play, using it as a live status cannot interact with the map normally while trying to apply a blueprint. Windows
window. Note that you can still right click *on* the DFHack tool window to close for tools that force-pause the game will have a pause icon in their upper right
it, even when it is pinned. corner to indicate which tool is responsible for the pausing.
You can have multiple DFHack tool windows on the screen at the same time. The
one that is receiving keyboard input has a highlighted title bar and will appear
over other windows if dragged across them. Clicking on a DFHack window that is not
currently active will bring it to the foreground and make it the active window.
Where do I go next? Where do I go next?
------------------- -------------------
@ -161,10 +157,11 @@ You can enable it from the GUI, so you don't need to run `enable autochop <enabl
directly. You can set a target number of logs, and autochop will manage directly. You can set a target number of logs, and autochop will manage
your logging industry for you. You can control where your woodsdwarves go to your logging industry for you. You can control where your woodsdwarves go to
cut down trees by setting up burrows and configuring autochop to only cut in cut down trees by setting up burrows and configuring autochop to only cut in
those burrows. If you have the extra screen space, go ahead and click the pin so those burrows. If you have the extra screen space, go ahead and set the
it turns green and set the `gui/autochop` window to minimal mode (click on the `gui/autochop` window to minimal mode (click on the hint near the upper right
hint near the upper right corner of the window or hit Alt-M). As you play the game, corner of the window or hit Alt-M) and click on the map so the window loses
you can glance at it to check on your stocks of wood. keyboard focus. As you play the game, you can glance at the status panel to
check on your stocks of wood.
Finally, let's do some fort design copy-pasting. Go to some bedrooms that you have Finally, let's do some fort design copy-pasting. Go to some bedrooms that you have
set up in your fort. Run `gui/blueprint`, set a name for your blueprint by set up in your fort. Run `gui/blueprint`, set a name for your blueprint by

@ -42,6 +42,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences:
- `hotkeys`: clicking on the DFHack logo no longer closes the popup menu - `hotkeys`: clicking on the DFHack logo no longer closes the popup menu
- `gui/launcher`: sped up initialization time for faster load of the UI - `gui/launcher`: sped up initialization time for faster load of the UI
- `orders`: orders plugin functionality is now offered via an overlay widget when the manager orders screen is open - `orders`: orders plugin functionality is now offered via an overlay widget when the manager orders screen is open
- Many DFHack windows can now be unfocused by clicking somewhere not over the tool window. This has the same effect as pinning previously did, but without the extra clicking.
## Documentation ## Documentation

@ -4117,32 +4117,28 @@ It adds the following methods:
ZScreen class ZScreen class
------------- -------------
A screen subclass that allows the underlying viewscreens to be interacted with. A screen subclass that allows multi-layer interactivity. For example, a DFHack
For example, a DFHack GUI tool implemented as a ZScreen can allow the player to GUI tool implemented as a ZScreen can allow the player to interact with the
interact with the underlying map. That is, even when the DFHack tool window is underlying map, or even other DFHack ZScreen windows! That is, even when the
visible, players will be able to use vanilla designation tools, select units, or DFHack tool window is visible, players will be able to use vanilla designation
scan/drag the map around. tools, select units, and scan/drag the map around.
If multiple ZScreens are on the stack and the player clicks on a visible element At most one ZScreen can have keyboard focus at a time. That ZScreen's widgets
of a non-top ZScreen, that ZScreen will be raised to the top of the viewscreen will have a chance to handle the input before anything else. If unhandled, the
stack. This allows multiple DFHack gui tools to be usable at the same time. input skips all unfocused ZScreens under that ZScreen and is passed directly to
Clicks that are not over any visible ZScreen element, of course, are passed the first non-ZScreen viewscreen. There are class attributes that can be set to
through to the underlying viewscreen. control what kind of unhandled input is passed to the lower layers.
If :kbd:`Esc` or the right mouse button is pressed, and the ZScreen widgets If multiple ZScreens are visible and the player left or right clicks on a
don't otherwise handle them, then the top ZScreen is dismissed. If the ZScreen visible element of a non-focused ZScreen, that ZScreen will be given focus. This
is "pinned", then the screen is not dismissed and the input is passed on to the allows multiple DFHack GUI tools to be usable at the same time. If the mouse is
underlying DF viewscreen. :kbd:`Alt`:kbd:`L` toggles the pinned status if the clicked away from the ZScreen widgets, that ZScreen loses focus. If no ZScreen
ZScreen widgets don't otherwise handle that key sequence. If you have a has focus, all input is passed directly through to the first underlying
``Panel`` with the ``pinnable`` attribute set and a frame that has pens defined non-ZScreen viewscreen.
for the pin icon (like ``Window`` widgets have by default), then a pin icon
will appear in the upper right corner of the frame. Clicking on this icon will For a ZScreen with keyboard focus, if :kbd:`Esc` or the right mouse button is
toggle the ZScreen ``pinned`` status just as if :kbd:`Alt`:kbd:`L` had been pressed, and the ZScreen widgets don't otherwise handle them, then the ZScreen
pressed. is dismissed.
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
input is passed directly to the first underlying non-ZScreen.
All this behavior is implemented in ``ZScreen:onInput()``, which subclasses All this behavior is implemented in ``ZScreen:onInput()``, which subclasses
**must not override**. Instead, ZScreen subclasses should delegate all input **must not override**. Instead, ZScreen subclasses should delegate all input
@ -4152,24 +4148,23 @@ level input processor.
When rendering, the parent viewscreen is automatically rendered first, so When rendering, the parent viewscreen is automatically rendered first, so
subclasses do not have to call ``self:renderParent()``. Calls to ``logic()`` subclasses do not have to call ``self:renderParent()``. Calls to ``logic()``
(a world "tick" when playing the game) are also passed through, so the game (a world "tick" when playing the game) are also passed through, so the game
progresses normally and can be paused/unpaused as normal by the player. progresses normally and can be paused/unpaused as normal by the player. Note
ZScreens that handle the :kbd:`Space` key may want to provide an alternate way that passing ``logic()`` calls through to the underlying map is required for
to pause. Note that passing ``logic()`` calls through to the underlying map is allowing the player to drag the map with the mouse. ZScreen subclasses can set
required for allowing the player to drag the map with the mouse. attributes that control whether the game is paused when the ZScreen is shown and
whether the game is forced to continue being paused while the ZScreen is shown.
If pausing is forced, child ``Window`` widgets will show a force-pause icon to
indicate which tool is forcing the pausing.
ZScreen provides the following functions: ZScreen provides the following functions:
* ``zscreen:raise()`` * ``zscreen:raise()``
Raises the ZScreen to the top of the viewscreen stack and returns a reference Raises the ZScreen to the top of the viewscreen stack, gives it keyboard
to ``self``. A common pattern is to check if a tool dialog is already active focus, and returns a reference to ``self``. A common pattern is to check if a
when the tool command is run and raise the existing dialog if it exists or tool dialog is already active when the tool command is run and raise the
show a new dialog if it doesn't. See the sample code below for an example. existing dialog if it exists or show a new dialog if it doesn't. See the
sample code below for an example.
* ``zscreen:togglePinned()``
Toggles whether the window closes on :kbd:`ESC` or r-click (unpinned) or not
(pinned).
* ``zscreen:isMouseOver()`` * ``zscreen:isMouseOver()``
@ -4177,6 +4172,37 @@ ZScreen provides the following functions:
subclass and sees if ``getMouseFramePos()`` returns a position for any of subclass and sees if ``getMouseFramePos()`` returns a position for any of
them. Subclasses can override this function if that logic is not appropriate. them. Subclasses can override this function if that logic is not appropriate.
* ``zscreen:hasFocus()``
Whether the ZScreen has keyboard focus. Subclasses will generally not need to
check this because they can assume if they are getting input, then they have
focus.
ZScreen subclasses can set the following attributes:
* ``initial_pause`` (default: ``true``)
Whether to pause the game when the ZScreen is shown.
* ``force_pause`` (default: ``false``)
Whether to ensure the game *stays* paused while the ZScreen is shown.
* ``pass_pause`` (default: ``true``)
Whether to pass the pause key to the lower viewscreens if it is not handled
by this ZScreen.
* ``pass_movement_keys`` (default: ``false``)
Whether to pass the map movement keys to the lower viewscreens if they ar not
handled by this ZScreen.
* ``pass_mouse_clicks`` (default: ``true``)
Whether to pass mouse clicks to the lower viewscreens if they are not handled
by this ZScreen.
Here is an example skeleton for a ZScreen tool dialog:: Here is an example skeleton for a ZScreen tool dialog::
local gui = require('gui') local gui = require('gui')
@ -4187,11 +4213,12 @@ Here is an example skeleton for a ZScreen tool dialog::
frame_title='My Window', frame_title='My Window',
frame={w=50, h=45}, frame={w=50, h=45},
resizable=true, -- if resizing makes sense for your dialog resizable=true, -- if resizing makes sense for your dialog
resize_min={w=50, h=20}, -- try to allow users to shrink your windows
} }
function MyWindow:init() function MyWindow:init()
self:addviews{ self:addviews{
-- add subviews here -- add subview widgets here
} }
end end
@ -4202,6 +4229,7 @@ Here is an example skeleton for a ZScreen tool dialog::
MyScreen = defclass(MyScreen, gui.ZScreen) MyScreen = defclass(MyScreen, gui.ZScreen)
MyScreen.ATTRS { MyScreen.ATTRS {
focus_path='myscreen', focus_path='myscreen',
-- set pause and passthrough attributes as appropriate
} }
function MyScreen:init() function MyScreen:init()
@ -4364,11 +4392,6 @@ 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).
* ``pinnable = bool`` (default: ``false``)
Determines whether the panel will draw a pin 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``)
@ -4430,7 +4453,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, pinnable, draggable window. framed, draggable window.
ResizingPanel class ResizingPanel class
------------------- -------------------

@ -13,16 +13,18 @@ CLEAR_PEN = to_pen{tile=909, ch=32, fg=0, bg=0, write_to_lower=true}
TRANSPARENT_PEN = to_pen{tile=0, ch=0} TRANSPARENT_PEN = to_pen{tile=0, ch=0}
KEEP_LOWER_PEN = to_pen{ch=32, fg=0, bg=0, keep_lower=true} KEEP_LOWER_PEN = to_pen{ch=32, fg=0, bg=0, keep_lower=true}
local FAKE_INPUT_KEYS = { local MOUSE_KEYS = {
_MOUSE_L = true, _MOUSE_L = true,
_MOUSE_R = true, _MOUSE_R = true,
_MOUSE_M = true, _MOUSE_M = true,
_MOUSE_L_DOWN = true, _MOUSE_L_DOWN = true,
_MOUSE_R_DOWN = true, _MOUSE_R_DOWN = true,
_MOUSE_M_DOWN = true, _MOUSE_M_DOWN = true,
_STRING = true,
} }
local FAKE_INPUT_KEYS = copyall(MOUSE_KEYS)
FAKE_INPUT_KEYS._STRING = true
function simulateInput(screen,...) function simulateInput(screen,...)
local keys = {} local keys = {}
local function push_key(arg) local function push_key(arg)
@ -692,8 +694,35 @@ end
----------------------------- -----------------------------
ZScreen = defclass(ZScreen, Screen) ZScreen = defclass(ZScreen, Screen)
ZScreen.ATTRS{
initial_pause=true,
force_pause=false,
pass_pause=true,
pass_movement_keys=false,
pass_mouse_clicks=true,
}
function ZScreen:init()
self.saved_pause_state = df.global.pause_state
if self.initial_pause then
df.global.pause_state = true
end
self.defocused = false
end
function ZScreen:dismiss()
ZScreen.super.dismiss(self)
if self.force_pause or self.initial_pause then
-- never go from unpaused to paused, just from paused to unpaused
df.global.pause_state = df.global.pause_state and self.saved_pause_state
end
end
-- this is necessary for middle-click map scrolling to function
function ZScreen:onIdle() function ZScreen:onIdle()
if self.force_pause then
df.global.pause_state = true
end
if self._native and self._native.parent then if self._native and self._native.parent then
self._native.parent:logic() self._native.parent:logic()
end end
@ -704,17 +733,15 @@ function ZScreen:render(dc)
ZScreen.super.render(self, dc) ZScreen.super.render(self, dc)
end end
function ZScreen:isOnTop() function ZScreen:hasFocus()
return dfhack.gui.getCurViewscreen(true) == self._native return not self.defocused
end and dfhack.gui.getCurViewscreen(true) == self._native
function ZScreen:togglePinned()
self.pinned = not self.pinned
end end
function ZScreen:onInput(keys) function ZScreen:onInput(keys)
if not self:isOnTop() then local has_mouse = self:isMouseOver()
if keys._MOUSE_L_DOWN and self:isMouseOver() then if not self:hasFocus() then
if (keys._MOUSE_L_DOWN or keys._MOUSE_R_DOWN) and has_mouse then
self:raise() self:raise()
else else
self:sendInputToParent(keys) self:sendInputToParent(keys)
@ -734,30 +761,42 @@ function ZScreen:onInput(keys)
return return
end end
if keys.CUSTOM_ALT_L then if self.pass_mouse_clicks and keys._MOUSE_L_DOWN and not has_mouse then
self:togglePinned() self.defocused = true
self:sendInputToParent(keys)
return return
end elseif keys.LEAVESCREEN or keys._MOUSE_R_DOWN then
if (self:isMouseOver() or not self.pinned)
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 rclick
df.global.enabler.mouse_rbut_down = 0 df.global.enabler.mouse_rbut_down = 0
df.global.enabler.mouse_rbut = 0 df.global.enabler.mouse_rbut = 0
return return
end else
local passit = self.pass_pause and keys.D_PAUSE
if not keys._MOUSE_L or not self:isMouseOver() then if not passit and self.pass_mouse_clicks then
self:sendInputToParent(keys) for key in pairs(MOUSE_KEYS) do
if keys[key] then
passit = true
break
end
end
end
if not passit and self.pass_movement_keys then
passit = require('gui.dwarfmode').getMapKey(keys)
end
if passit then
self:sendInputToParent(keys)
end
return
end end
end end
function ZScreen:raise() function ZScreen:raise()
if self:isDismissed() or self:isOnTop() then if self:isDismissed() or self:hasFocus() then
return self return self
end end
dscreen.raise(self) dscreen.raise(self)
self.defocused = false
return self return self
end end
@ -809,8 +848,7 @@ local BASE_FRAME = {
title_pen = to_pen{ fg=COLOR_BLACK, bg=COLOR_GREY }, title_pen = to_pen{ fg=COLOR_BLACK, bg=COLOR_GREY },
inactive_title_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK }, inactive_title_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK },
signature_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK }, signature_pen = to_pen{ fg=COLOR_GREY, bg=COLOR_BLACK },
pinned_pen = to_pen{tile=779, ch=216, fg=COLOR_GREY, bg=COLOR_GREEN}, paused_pen = to_pen{tile=782, ch=216, fg=COLOR_GREY, bg=COLOR_BLACK},
unpinned_pen = to_pen{tile=782, ch=216, fg=COLOR_GREY, bg=COLOR_BLACK},
} }
local function make_frame(name, double_line) local function make_frame(name, double_line)
@ -840,7 +878,7 @@ THIN_FRAME = make_frame('Thin', false)
-- for compatibility with pre-steam code -- for compatibility with pre-steam code
GREY_LINE_FRAME = WINDOW_FRAME GREY_LINE_FRAME = WINDOW_FRAME
function paint_frame(dc,rect,style,title,show_pin,pinned,inactive) function paint_frame(dc,rect,style,title,inactive, pause_forced)
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)
@ -865,27 +903,19 @@ function paint_frame(dc,rect,style,title,show_pin,pinned,inactive)
x, y1, tstr) x, y1, tstr)
end end
if show_pin then if pause_forced then
if pinned and style.pinned_pen then -- get the tiles for the activated pause symbol
local pin_texpos = dfhack.textures.getGreenPinTexposStart() local pause_texpos_ul = dfhack.screen.findGraphicsTile('INTERFACE_BITS', 18, 28)
if pin_texpos == -1 then local pause_texpos_ur = dfhack.screen.findGraphicsTile('INTERFACE_BITS', 19, 28)
dscreen.paintTile(style.pinned_pen, x2-1, y1) local pause_texpos_ll = dfhack.screen.findGraphicsTile('INTERFACE_BITS', 18, 29)
else local pause_texpos_lr = dfhack.screen.findGraphicsTile('INTERFACE_BITS', 19, 29)
dscreen.paintTile(style.pinned_pen, x2-2, y1-1, nil, pin_texpos+0) if not pause_texpos_ul then
dscreen.paintTile(style.pinned_pen, x2-1, y1-1, nil, pin_texpos+1) dscreen.paintTile(style.paused_pen, x2-1, y1)
dscreen.paintTile(style.pinned_pen, x2-2, y1, nil, pin_texpos+2) else
dscreen.paintTile(style.pinned_pen, x2-1, y1, nil, pin_texpos+3) dscreen.paintTile(style.paused_pen, x2-2, y1-1, nil, pause_texpos_ul)
end dscreen.paintTile(style.paused_pen, x2-1, y1-1, nil, pause_texpos_ur)
elseif not pinned and style.unpinned_pen then dscreen.paintTile(style.paused_pen, x2-2, y1, nil, pause_texpos_ll)
local pin_texpos = dfhack.textures.getRedPinTexposStart() dscreen.paintTile(style.paused_pen, x2-1, y1, nil, pause_texpos_lr)
if pin_texpos == -1 then
dscreen.paintTile(style.unpinned_pen, x2-1, y1)
else
dscreen.paintTile(style.unpinned_pen, x2-2, y1-1, nil, pin_texpos+0)
dscreen.paintTile(style.unpinned_pen, x2-1, y1-1, nil, pin_texpos+1)
dscreen.paintTile(style.unpinned_pen, x2-2, y1, nil, pin_texpos+2)
dscreen.paintTile(style.unpinned_pen, x2-1, y1, nil, pin_texpos+3)
end
end end
end end
end end

@ -81,7 +81,6 @@ 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,
pinnable = 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
} }
@ -272,21 +271,21 @@ local function Panel_on_double_click(self)
Panel_update_frame(self, frame, true) Panel_update_frame(self, frame, true)
end end
local function panel_is_on_pin(self) local function panel_mouse_is_on_pause_icon(self)
local frame_rect = self.frame_rect local frame_rect = self.frame_rect
local x,y = dscreen.getMousePos() local x,y = dscreen.getMousePos()
return (x == frame_rect.x2-2 or x == frame_rect.x2-1) return (x == frame_rect.x2-2 or x == frame_rect.x2-1)
and (y == frame_rect.y1-1 or y == frame_rect.y1) and (y == frame_rect.y1-1 or y == frame_rect.y1)
end end
local function panel_is_pinnable(self) local function panel_has_pause_icon(self)
return self.pinnable and self.parent_view and self.parent_view.togglePinned return self.parent_view and self.parent_view.force_pause
end end
function Panel:getMouseFramePos() function Panel:getMouseFramePos()
local x,y = Panel.super.getMouseFramePos(self) local x,y = Panel.super.getMouseFramePos(self)
if x then return x, y end if x then return x, y end
if panel_is_pinnable(self) and panel_is_on_pin(self) then if panel_has_pause_icon(self) and panel_mouse_is_on_pause_icon(self) then
local frame_rect = self.frame_rect local frame_rect = self.frame_rect
return frame_rect.width - 3, 0 return frame_rect.width - 3, 0
end end
@ -320,12 +319,6 @@ function Panel:onInput(keys)
end end
return true return true
end end
if panel_is_pinnable(self) and keys._MOUSE_L_DOWN then
if panel_is_on_pin(self) then
self.parent_view:togglePinned()
return true
end
end
if Panel.super.onInput(self, keys) then if Panel.super.onInput(self, keys) then
return true return true
end end
@ -505,14 +498,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
local pinned = nil local inactive = self.parent_view and self.parent_view.hasFocus
if self.pinnable then and not self.parent_view:hasFocus()
pinned = self.parent_view and self.parent_view.pinned local pause_forced = self.parent_view and self.parent_view.force_pause
end gui.paint_frame(dc, rect, self.frame_style, self.frame_title, inactive,
local inactive = self.parent_view and self.parent_view.isOnTop pause_forced)
and not self.parent_view:isOnTop()
gui.paint_frame(dc, rect, self.frame_style, self.frame_title,
self.pinnable, pinned, inactive)
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}
@ -535,7 +525,6 @@ Window.ATTRS {
frame_background = gui.CLEAR_PEN, frame_background = gui.CLEAR_PEN,
frame_inset = 1, frame_inset = 1,
draggable = true, draggable = true,
pinnable = true,
} }
------------------- -------------------

@ -297,6 +297,7 @@ end
MenuScreen = defclass(MenuScreen, gui.ZScreen) MenuScreen = defclass(MenuScreen, gui.ZScreen)
MenuScreen.ATTRS { MenuScreen.ATTRS {
focus_path='hotkeys/menu', focus_path='hotkeys/menu',
initial_pause=false,
hotspot=DEFAULT_NIL, hotspot=DEFAULT_NIL,
} }