Created
July 3, 2025 20:45
-
-
Save LouisGameDev/61966ce089556a8bf5de2f87be37036a to your computer and use it in GitHub Desktop.
Revisions
-
LouisGameDev created this gist
Jul 3, 2025 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,242 @@ --@module = true local gui = require('gui') local widgets = require('gui.widgets') local INVISIBLE_FRAME = { frame_pen=gui.CLEAR_PEN, signature_pen=false, } -- MAIN BUG TRIGGERED HERE ----------------------------------------- BugDemoPanel = defclass(BugDemoPanel, widgets.Panel) BugDemoPanel.ATTRS { --frame_style = INVISIBLE_FRAME -- ^ This is the key part that triggers the bug. -- if style is nil, it will be nil and panel.lua::Panel_end_drag will never be called -- https://github.com/DFHack/dfhack/blob/e3165854e80411eec584c74949c73000f2aa0dcb/library/lua/gui/widgets/containers/panel.lua#L497C1-L498C1 -- even if user intends to finish drag } ----------------------------------------- function BugDemoPanel:onInput(keys) local key_info = {} for key, value in pairs(keys) do table.insert(key_info, string.format("%s=%s", tostring(key), tostring(value))) end table.sort(key_info) return BugDemoPanel.super.onInput(self, keys) end BugDemoWindow = defclass(BugDemoWindow, widgets.Window) BugDemoWindow.ATTRS { view_id = 'bugdemo_window', frame_title = 'Frame Style Bug Demo', resizable = true, resize_min = {w = 54, h = 20}, frame_inset = {l = 0, r = 0, t = 0, b = 0} } BugDemoScreen = defclass(BugDemoScreen, gui.ZScreen) BugDemoScreen.ATTRS { view_id = 'bugdemo_screen', focus_path = 'bugdemo', pass_movement_keys = true, defocusable = true } function BugDemoWindow:init() self.resizing_panels = false self:addviews{ BugDemoPanel { view_id = 'category_panel', frame = {l = 0, w = 22, t = 0, b = 1}, frame_inset = {l = 1, t = 0, b = 1, r = 1}, resizable = true, resize_anchors = {l = false, t = false, r = true, b = true}, resize_min = {w = 24}, on_resize_begin = self:callback('onPanelResizeBegin'), on_resize_end = self:callback('onPanelResizeEnd'), subviews = { widgets.Label { frame = {t = 0, l = 0}, text = 'category_panel', text_pen = COLOR_YELLOW } } }, widgets.Divider { view_id = 'divider1', frame = {l = 30, t = 0, b = 2, w = 1}, interior_b = true, frame_style_t = false }, widgets.Panel { view_id = 'item_panel', frame = {t = 1, b = 3, l = 25, r = 0}, resize_min = {w = 30, h = 10}, frame_inset = {l = 1, r = 0}, subviews = { widgets.Label { view_id = 'item_header', frame = {t = 0, l = 0, r = 0, h = 1}, text = 'item_panel', text_pen = COLOR_YELLOW } } }, widgets.HelpButton { command = "gui/stockmonitor", frame = {r = 0, t = 1} }, widgets.Divider { frame = {l = 0, r = 0, b = 2, h = 1}, frame_style_l = false, frame_style_r = false, interior_l = true }, widgets.Panel { frame = {l = 0, r = 0, b = 1, h = 1}, frame_inset = {l = 1, r = 1, t = 0, w = 100}, subviews = { widgets.HotkeyLabel { frame = {l = 0}, key = 'CUSTOM_CTRL_R', label = 'Button A', auto_width = true, on_activate = function() self:testResize() end }, widgets.HotkeyLabel { frame = {l = 25}, key = 'CUSTOM_CTRL_O', label = 'Button B', auto_width = true, on_activate = function() end } } } } end function BugDemoWindow:testResize() local category_panel = self.subviews.category_panel if category_panel then category_panel.frame.w = (category_panel.frame.w == 22) and 32 or 22 self:ensurePanelsRelSize() self:updateLayout() end end function BugDemoWindow:onPanelResizeBegin() self.resizing_panels = true end function BugDemoWindow:onPanelResizeEnd() self.resizing_panels = false self:ensurePanelsRelSize() self:updateLayout() end function BugDemoWindow:ensurePanelsRelSize() local category_panel = self.subviews.category_panel local item_panel = self.subviews.item_panel local divider1 = self.subviews.divider1 if not category_panel or not item_panel or not divider1 then return end local main_width = self.frame.w or 100 local min_item_width = 30 category_panel.frame.w = math.min(math.max(category_panel.frame.w, 24), main_width - min_item_width) local cat_width = category_panel.frame.w item_panel.frame.l = category_panel.visible and cat_width or 1 divider1.frame.l = item_panel.frame.l - 1 end function BugDemoWindow:onRenderBody(dc) if self.resizing_panels then self:ensurePanelsRelSize() self:updateLayout() end return BugDemoWindow.super.onRenderBody(self, dc) end function BugDemoWindow:preUpdateLayout() self:ensurePanelsRelSize() end function BugDemoWindow:onInput(keys) local key_info = {} for key, value in pairs(keys) do table.insert(key_info, string.format("%s=%s", tostring(key), tostring(value))) end table.sort(key_info) return BugDemoWindow.super.onInput(self, keys) end function BugDemoScreen:init() local optimal_size = self:calculateOptimalFrameSize() self:addviews{BugDemoWindow {frame = optimal_size}} end function BugDemoScreen:calculateOptimalFrameSize() local base_width = 100 local base_height = 35 local optimal_width = math.max(base_width, 90) local optimal_height = math.max(base_height, 25) return {w = optimal_width, h = optimal_height} end function BugDemoScreen:onDismiss() bug_demo_screen = nil end bug_demo_screen = bug_demo_screen or nil if dfhack_flags.module then return end -- Main entry point -- if not dfhack.isWorldLoaded() then -- qerror("This script requires a loaded world") -- end -- Check for existing instance if bug_demo_screen and not bug_demo_screen._native then bug_demo_screen = nil end if bug_demo_screen then local success, is_dismissed = pcall(function() return bug_demo_screen:isDismissed() end) if not success or is_dismissed then bug_demo_screen = nil else return end end -- Create and show new instance bug_demo_screen = BugDemoScreen{}:show()