Skip to content

Commit c2001bb

Browse files
committed
devel/dflayout: rework fort toolbar demos
Have the toolbar demos set their own frames via computeFrame. These overridden computeFrames also allow the button extent indicator strings to draw over the edges of the Panel's border. The left, right, and secondary toolbars don't have their own "borders" like the center toolbar, so the first and last buttons in those toolbars previously had their button indicators cut off by the Panel border. Certainly not a good look for general use, but for a devel inspection tool, it should be okay (and leaves the Panel borders showing the true extent of each toolbar). Only compute the button strings once for the static left, center, and right toolbars.
1 parent e83410e commit c2001bb

File tree

1 file changed

+132
-59
lines changed

1 file changed

+132
-59
lines changed

devel/dflayout.lua

Lines changed: 132 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -132,35 +132,140 @@ local function fort_toolbars_visible()
132132
return visible() and fort_toolbars_demo.active
133133
end
134134

135-
FortToolbarDemoPanel = defclass(FortToolbarDemoPanel, widgets.Panel)
136-
FortToolbarDemoPanel.ATTRS{
135+
local secondary_visible = false
136+
137+
local function primary_toolbar_dy()
138+
if secondary_visible then
139+
-- When a secondary toolbar is active, move the primary demos up to let
140+
-- the secondary demo be right above the actual secondary:
141+
-- {l demo} {c demo} {r demo}
142+
-- {s demo}
143+
-- [s tool]
144+
-- [l tool] [c tool] [r tool] (bottom of UI)
145+
return -(layout.TOOLBAR_HEIGHT + 2 * layout.SECONDARY_TOOLBAR_HEIGHT)
146+
else
147+
-- Otherwise, draw primary toolbar demos right above the primary
148+
-- toolbars:
149+
-- {l demo} {c demo} {r demo}
150+
-- [l tool] [c tool] [r tool] (bottom of UI)
151+
return -layout.TOOLBAR_HEIGHT
152+
end
153+
end
154+
155+
-- Generates a `view:computeFrame()` function that tracks the placement of the
156+
-- given `toolbar`.
157+
--
158+
-- Note: The returned function does not return a separate body rect; subviews
159+
-- will be able to overwrite the normal UI-drawn frame!
160+
---@param toolbar DFLayout.Toolbar
161+
---@param dy_fn fun(): integer
162+
---@return function
163+
local function get_computeFrame_fn(toolbar, dy_fn)
164+
return function(self, parent_rect)
165+
local ir = gui.get_interface_rect()
166+
local frame = toolbar.frame(ir)
167+
return gui.mkdims_wh(
168+
ir.x1 + frame.l,
169+
ir.y1 + frame.t + dy_fn(),
170+
frame.w,
171+
frame.h)
172+
end
173+
end
174+
175+
---@param buttons DFLayout.Toolbar.NamedButtons
176+
local function buttons_string(buttons)
177+
local sorted = {}
178+
for _, button in pairs(buttons) do
179+
utils.insert_sorted(sorted, button, 'offset')
180+
end
181+
-- For a one-column button, use | to indicate the button's position.
182+
-- For wider buttons, use shapes like /\ or /--\ to illustrate the
183+
-- button's position and width.
184+
local str = ''
185+
for i, o in ipairs(sorted) do
186+
if o.offset > #str then
187+
str = str .. (' '):rep(o.offset - #str)
188+
end
189+
if o.width == 1 then
190+
str = str .. '|'
191+
elseif o.width > 1 then
192+
str = str .. '/' .. ('-'):rep(o.width - 2) .. '\\'
193+
end
194+
end
195+
return str
196+
end
197+
198+
---@class ToolbarDemo.attrs: widgets.Panel.attrs
199+
---@class ToolbarDemo.attrs.partial: widgets.Panel.attrs.partial
200+
---@class ToolbarDemo.initTable: ToolbarDemo.attrs.partial, { toolbar?: DFLayout.Toolbar, toolbar_dy?: fun(): integer }
201+
---@class ToolbarDemo: widgets.Panel
202+
---@field super widgets.Panel
203+
---@field ATTRS ToolbarDemo.attrs|fun(attributes: ToolbarDemo.attrs.partial)
204+
---@overload fun(init_table: ToolbarDemo.initTable): self
205+
ToolbarDemo = defclass(ToolbarDemo, widgets.Panel)
206+
ToolbarDemo.ATTRS{
137207
frame_style = function(...)
138208
local style = gui.FRAME_THIN(...)
139209
style.signature_pen = false
140210
return style
141211
end,
142-
visible_override = true,
143212
visible = fort_toolbars_visible,
144213
frame_background = { ch = 32, bg = COLOR_BLACK },
145214
}
146215

147-
local left_toolbar_demo = FortToolbarDemoPanel{
216+
---@param args ToolbarDemo.initTable
217+
function ToolbarDemo:init(args)
218+
self.label = widgets.Label{ frame = { l = 0 } }
219+
if args.toolbar and args.toolbar_dy then
220+
self:update_to_toolbar(args.toolbar, args.toolbar_dy)
221+
end
222+
self:addviews{ self.label }
223+
end
224+
225+
---@param toolbar DFLayout.Toolbar
226+
---@param dy fun(): integer
227+
---@return unknown
228+
function ToolbarDemo:update_to_toolbar(toolbar, dy)
229+
-- set button representation string
230+
local text = buttons_string(toolbar.buttons)
231+
local l_inset = 0
232+
if text:sub(1, 1) == ' ' then
233+
-- don't overwrite the left border edge with a plain space
234+
l_inset = 1
235+
text = text:sub(2)
236+
end
237+
self.label.frame.l = l_inset
238+
self.label:setText(text)
239+
240+
-- track actual toolbar, but with a y offset
241+
self.computeFrame = get_computeFrame_fn(toolbar, dy)
242+
243+
return self
244+
end
245+
246+
local left_toolbar_demo = ToolbarDemo{
148247
frame_title = 'left toolbar',
149-
subviews = { widgets.Label{ view_id = 'buttons', frame = { l = 0, r = 0 } } },
248+
toolbar = layout.fort.toolbars.left,
249+
toolbar_dy = primary_toolbar_dy,
150250
}
151-
local center_toolbar_demo = FortToolbarDemoPanel{
251+
252+
local center_toolbar_demo = ToolbarDemo{
152253
frame_title = 'center toolbar',
153-
subviews = { widgets.Label{ view_id = 'buttons', frame = { l = 0, r = 0 } } },
254+
toolbar = layout.fort.toolbars.center,
255+
toolbar_dy = primary_toolbar_dy,
154256
}
155-
local right_toolbar_demo = FortToolbarDemoPanel{
257+
258+
local right_toolbar_demo = ToolbarDemo{
156259
frame_title = 'right toolbar',
157-
subviews = { widgets.Label{ view_id = 'buttons', frame = { l = 0, r = 0 } } },
260+
toolbar = layout.fort.toolbars.right,
261+
toolbar_dy = primary_toolbar_dy,
158262
}
159-
local secondary_visible = false
160-
local secondary_toolbar_demo = FortToolbarDemoPanel{
263+
264+
local secondary_toolbar_demo = ToolbarDemo{
161265
frame_title = 'secondary toolbar',
162-
subviews = { widgets.Label{ view_id = 'buttons', frame = { l = 0, r = 0 } } },
163-
visible = function() return fort_toolbars_visible() and secondary_visible end,
266+
visible = function()
267+
return fort_toolbars_visible() and secondary_visible
268+
end,
164269
}
165270

166271
fort_toolbars_demo.views = {
@@ -172,59 +277,26 @@ fort_toolbars_demo.views = {
172277

173278
---@param secondary? DFLayout.Fort.SecondaryToolbar.Names
174279
local function update_fort_toolbars(secondary)
175-
-- by default, draw primary toolbar demonstrations right above the primary toolbars:
176-
-- {l demo} {c demo} {r demo}
177-
-- [l tool] [c tool] [r tool] (bottom of UI)
178-
local toolbar_demo_dy = -layout.TOOLBAR_HEIGHT
179-
local ir = gui.get_interface_rect()
180-
---@param v widgets.Panel
181-
---@param frame widgets.Widget.frame
182-
---@param buttons DFLayout.Toolbar.NamedButtons
183-
local function update(v, frame, buttons)
184-
v.frame = {
185-
w = frame.w,
186-
h = frame.h,
187-
l = frame.l + ir.x1,
188-
t = frame.t + ir.y1 + toolbar_demo_dy,
189-
}
190-
local sorted = {}
191-
for _, button in pairs(buttons) do
192-
utils.insert_sorted(sorted, button, 'offset')
193-
end
194-
local buttons = ''
195-
for i, o in ipairs(sorted) do
196-
if o.offset > #buttons then
197-
buttons = buttons .. (' '):rep(o.offset - #buttons)
198-
end
199-
if o.width == 1 then
200-
buttons = buttons .. '|'
201-
elseif o.width > 1 then
202-
buttons = buttons .. '/' .. ('-'):rep(o.width - 2) .. '\\'
203-
end
280+
local function updateLayout(view)
281+
if view.frame_parent_rect then
282+
view:updateLayout()
204283
end
205-
v.subviews.buttons:setText(
206-
buttons:sub(2) -- the demo panel border is at offset 0, so trim first character to start at offset 1
207-
)
208-
v:updateLayout()
209284
end
210285
if secondary then
211-
-- a secondary toolbar is active, move the primary demonstration up to
212-
-- let the secondary be demonstrated right above the actual secondary:
213-
-- {l demo} {c demo} {r demo}
214-
-- {s demo}
215-
-- [s tool]
216-
-- [l tool] [c tool] [r tool] (bottom of UI)
217-
update(secondary_toolbar_demo, layout.fort.secondary_toolbars[secondary].frame(ir),
218-
layout.fort.secondary_toolbars[secondary].buttons)
286+
-- show secondary demo just above actual secondary
287+
local function dy()
288+
return -layout.SECONDARY_TOOLBAR_HEIGHT
289+
end
290+
secondary_toolbar_demo:update_to_toolbar(layout.fort.secondary_toolbars[secondary], dy)
291+
updateLayout(secondary_toolbar_demo)
219292
secondary_visible = true
220-
toolbar_demo_dy = toolbar_demo_dy - 2 * layout.SECONDARY_TOOLBAR_HEIGHT
221293
else
222294
secondary_visible = false
223295
end
224296

225-
update(left_toolbar_demo, layout.fort.toolbars.left.frame(ir), layout.fort.toolbars.left.buttons)
226-
update(right_toolbar_demo, layout.fort.toolbars.right.frame(ir), layout.fort.toolbars.right.buttons)
227-
update(center_toolbar_demo, layout.fort.toolbars.center.frame(ir), layout.fort.toolbars.center.buttons)
297+
updateLayout(left_toolbar_demo)
298+
updateLayout(right_toolbar_demo)
299+
updateLayout(center_toolbar_demo)
228300
end
229301

230302
local tool_from_designation = {
@@ -303,13 +375,14 @@ fort_toolbars_demo.update = function()
303375
end
304376

305377
local secondary
378+
local center_render = center_toolbar_demo.render
306379
function center_toolbar_demo:render(...)
307380
local new_secondary = active_secondary()
308381
if new_secondary ~= secondary then
309382
secondary = new_secondary
310383
update_fort_toolbars(secondary)
311384
end
312-
return FortToolbarDemoPanel.render(self, ...)
385+
return center_render(self, ...)
313386
end
314387

315388
--- start demo control window ---

0 commit comments

Comments
 (0)