From 10f22ecc27ce72cc6116fd1ec41b19c0a47bc9f1 Mon Sep 17 00:00:00 2001 From: Myk Date: Mon, 11 Apr 2022 18:25:00 -0700 Subject: [PATCH] add ResizingPanel class and autolayout for Panels (#2086) * add autolayout for Panels and new ResizingPanel --- docs/Lua API.rst | 17 ++++++++++++++ docs/changelog.txt | 2 ++ library/lua/gui/widgets.lua | 46 +++++++++++++++++++++++++++++++++++++ 3 files changed, 65 insertions(+) diff --git a/docs/Lua API.rst b/docs/Lua API.rst index bc1e3b0ee..a333d9fa0 100644 --- a/docs/Lua API.rst +++ b/docs/Lua API.rst @@ -3705,6 +3705,23 @@ Has attributes: Called from ``onRenderBody``. +* ``autoarrange_subviews = bool`` (default: false) +* ``autoarrange_gap = int`` (default: 0) + + If ``autoarrange_subviews`` is set to ``true``, the Panel will + automatically handle subview layout. Subviews are laid out vertically + according to their current height, with ``autoarrange_gap`` empty lines + between subviews. This allows you to have widgets dynamically change + height or become visible/hidden and you don't have to worry about + recalculating subview positions. + +ResizingPanel class +------------------- + +Subclass of Panel; automatically adjusts its own frame height according to +the size, position, and visibility of its subviews. Pairs nicely with a +parent Panel that has ``autoarrange_subviews`` enabled. + Pages class ----------- diff --git a/docs/changelog.txt b/docs/changelog.txt index 631cef406..deb15d478 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -75,6 +75,8 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - Lua wrappers for functions reverse-engineered from ambushing unit code: ``isHidden(unit)``, ``isFortControlled(unit)``, ``getOuterContainerRef(unit)``, ``getOuterContainerRef(item)`` - ``dwarfmode.enterSidebarMode()``: passing ``df.ui_sidebar_mode.DesignateMine`` now always results in you entering ``DesignateMine`` mode and not ``DesignateChopTrees``, even when you looking at the surface where the default designation mode is ``DesignateChopTrees`` - New string class function: ``string:escape_pattern()`` escapes regex special characters within a string +- ``widgets.Panel``: if ``autoarrange_subviews`` is set, ``Panel``\s will now automatically lay out widgets vertically according to their current height. This allows you to have widgets dynamically change height or become visible/hidden and you don't have to worry about recalculating frame layouts +- ``widgets.ResizingPanel``: new ``Panel`` subclass that automatically recalculates it's own frame height based on the size, position, and visibility of its subviews - ``safe_index`` now properly handles lua sparse tables that are indexed by numbers # 0.47.05-r4 diff --git a/library/lua/gui/widgets.lua b/library/lua/gui/widgets.lua index 13df73425..140882a00 100644 --- a/library/lua/gui/widgets.lua +++ b/library/lua/gui/widgets.lua @@ -75,6 +75,8 @@ Panel = defclass(Panel, Widget) Panel.ATTRS { on_render = DEFAULT_NIL, on_layout = DEFAULT_NIL, + autoarrange_subviews = false, -- whether to automatically lay out subviews + autoarrange_gap = 0, -- how many blank lines to insert between widgets } function Panel:init(args) @@ -89,6 +91,50 @@ function Panel:postComputeFrame(body) if self.on_layout then self.on_layout(body) end end +-- if self.autoarrange_subviews is true, lay out visible subviews vertically, +-- adding gaps between widgets according to self.autoarrange_gap. +function Panel:postUpdateLayout() + if not self.autoarrange_subviews then return end + + local gap = self.autoarrange_gap + local y = 0 + for _,subview in ipairs(self.subviews) do + subview.frame.t = y + if subview.visible then + y = y + subview.frame.h + gap + end + end + self.frame_rect.height = y + + -- let widgets adjust to their new positions + self:updateSubviewLayout() +end + +------------------- +-- ResizingPanel -- +------------------- + +ResizingPanel = defclass(ResizingPanel, Panel) + +function ResizingPanel:init() + -- ensure we have a frame so a containing widget can read our dimensions + if not self.frame then self.frame = {} end +end + +-- adjust our frame dimensions according to positions and sizes of our subviews +function ResizingPanel:postUpdateLayout(frame_body) + local w, h = 0, 0 + for _,subview in ipairs(self.subviews) do + if subview.visible then + w = math.max(w, (subview.frame.l or 0) + + (subview.frame.w or frame_body.width)) + h = math.max(h, (subview.frame.t or 0) + + (subview.frame.h or frame_body.height)) + end + end + self.frame.w, self.frame.h = w, h +end + ----------- -- Pages -- -----------