Created
July 3, 2025 20:45
-
-
Save LouisGameDev/61966ce089556a8bf5de2f87be37036a to your computer and use it in GitHub Desktop.
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 characters
--@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() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment