Skip to content

Commit 698c98a

Browse files
committed
toolbars: make secondary toolbar API the same as for primaries
This irregularity became blindingly obvious when writing the documentation.
1 parent 1e1be64 commit 698c98a

File tree

1 file changed

+126
-80
lines changed

1 file changed

+126
-80
lines changed

internal/df-bottom-toolbars.lua

Lines changed: 126 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -114,22 +114,17 @@ The module provides the following fields:
114114
``mass_designation``. See the complete list of secondary toolbar buttons in
115115
the module's code.
116116
117-
The definition of a secondary toolbar uses the same ``width`` & ``buttons``
118-
fields as the primary toolbars.
117+
The definition of a secondary toolbar provides the same ``width``
118+
and``buttons`` fields and ``frame`` method as the primary toolbars.
119119
120-
* ``fort.center:secondary_toolbar_frame(interface_rect, secondary_name)``
121-
122-
Provides the frame (like ``toolbar:frame()``) for the specified secondary
123-
toolbar when displayed in the specified interface size.
124-
125-
Again, a button's ``offset`` can be combined with its secondary toolbar's
126-
frame's ``l`` to find the location of a specific button::
120+
The ``offset`` of a secondary toolbar's button can be combined with the
121+
toolbar's frame's ``l`` to find the location of a specific button::
127122
128123
local tb = reqscript('internal/df-bottom-toolbars')
129124
...
130-
local center = tb.fort.center
131-
local dig_advanced_offset = center:secondary_toolbar_frame(interface_size, 'dig')
132-
+ center.secondary_toolbars.dig.advanced_toggle.offset
125+
local dig = tb.fort.center.secondary_toolbars.dig
126+
local dig_advanced_offset = dig:frame(interface_size)
127+
+ dig.buttons.advanced_toggle.offset
133128
134129
]]
135130

@@ -160,11 +155,6 @@ end
160155
---@alias Button { offset: integer, width: integer }
161156
---@alias NamedButtons table<string,Button> -- multiple entries
162157

163-
---@class Toolbar
164-
---@field button_offsets NamedOffsets deprecated, use buttons[name].offset
165-
---@field buttons NamedButtons
166-
---@field width integer
167-
168158
---@class Toolbar.Widget.frame: widgets.Widget.frame
169159
---@field l integer Gap between the left edge of the frame and the parent.
170160
---@field t integer Gap between the top edge of the frame and the parent.
@@ -173,8 +163,16 @@ end
173163
---@field w integer Width
174164
---@field h integer Height
175165

166+
---@class Toolbar.Base
167+
---@field button_offsets NamedOffsets deprecated, use buttons[name].offset
168+
---@field buttons NamedButtons
169+
---@field width integer
170+
171+
---@class Toolbar: Toolbar.Base
172+
---@field frame fun(self: Toolbar, interface_size: Toolbar.Rectangle.Size): Toolbar.Widget.frame
173+
176174
---@param widths NamedWidth[] single-name entries only!
177-
---@return Toolbar
175+
---@return Toolbar.Base
178176
local function button_widths_to_toolbar(widths)
179177
local offsets = {}
180178
local buttons = {}
@@ -203,15 +201,15 @@ local function buttons_to_widths(buttons)
203201
end
204202

205203
---@param buttons string[]
206-
---@return Toolbar
204+
---@return Toolbar.Base
207205
local function buttons_to_toolbar(buttons)
208206
return button_widths_to_toolbar(buttons_to_widths(buttons))
209207
end
210208

211209
-- Fortress mode toolbar definitions
212210
fort = {}
213211

214-
---@class LeftToolbar : Toolbar
212+
---@class LeftToolbar: Toolbar
215213
fort.left = buttons_to_toolbar{
216214
'citizens', 'tasks', 'places', 'labor',
217215
'orders', 'nobles', 'objects', 'justice',
@@ -270,6 +268,7 @@ end
270268
---@alias CenterToolbarToolNames 'dig' | 'chop' | 'gather' | 'smooth' | 'erase' | 'build' | 'stockpile' | 'zone' | 'burrow' | 'cart' | 'traffic' | 'mass_designation'
271269
---@alias CenterToolbarSecondaryToolbarNames 'dig' | 'chop' | 'gather' | 'smooth' | 'erase' | 'stockpile' | 'stockpile_paint' | 'burrow_paint' | 'traffic' | 'mass_designation'
272270

271+
---@deprecated Use center.secondary_toolbars[toolbar_name]:frame().
273272
---@param interface_size Toolbar.Rectangle.Size
274273
---@param toolbar_name CenterToolbarSecondaryToolbarNames
275274
---@return Toolbar.Widget.frame
@@ -315,68 +314,115 @@ function fort.center:secondary_toolbar_frame(interface_size, toolbar_name)
315314
}
316315
end
317316

317+
---@param interface_size Toolbar.Rectangle.Size
318+
---@param tool_name CenterToolbarToolNames
319+
---@param secondary_toolbar Toolbar.Base
320+
---@return Toolbar.Widget.frame
321+
local function center_secondary_frame(interface_size, tool_name, secondary_toolbar)
322+
local toolbar_offset = fort.center:frame(interface_size).l
323+
local toolbar_button = fort.center.buttons[tool_name] or dfhack.error('invalid tool name: ' .. tool_name)
324+
325+
-- Ideally, the secondary toolbar is positioned directly above the (main) toolbar button
326+
local ideal_offset = toolbar_offset + toolbar_button.offset
327+
328+
-- In "narrow" interfaces conditions, a wide secondary toolbar (pretty much
329+
-- any tool that has "advanced" options) that was ideally positioned above
330+
-- its tool's button would extend past the right edge of the interface area.
331+
-- Such wide secondary toolbars are instead right justified with a bit of
332+
-- padding.
333+
334+
-- padding necessary to line up width-constrained secondaries
335+
local secondary_padding = 5
336+
local width_constrained_offset = math.max(0, interface_size.width - (secondary_toolbar.width + secondary_padding))
337+
338+
-- Use whichever position is left-most.
339+
local l = math.min(ideal_offset, width_constrained_offset)
340+
return {
341+
l = l,
342+
w = secondary_toolbar.width,
343+
r = interface_size.width - l - secondary_toolbar.width,
344+
345+
t = interface_size.height - TOOLBAR_HEIGHT - SECONDARY_TOOLBAR_HEIGHT,
346+
h = SECONDARY_TOOLBAR_HEIGHT,
347+
b = TOOLBAR_HEIGHT,
348+
}
349+
end
350+
318351
---@type table<CenterToolbarSecondaryToolbarNames,Toolbar>
319-
fort.center.secondary_toolbars = {
320-
dig = buttons_to_toolbar{
321-
'dig', 'stairs', 'ramp', 'channel', 'remove_construction', '_gap',
322-
'rectangle', 'draw', '_gap',
323-
'advanced_toggle', '_gap',
324-
'all', 'auto', 'ore_gem', 'gem', '_gap',
325-
'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', '_gap',
326-
'blueprint', 'blueprint_to_standard', 'standard_to_blueprint',
327-
},
328-
chop = buttons_to_toolbar{
329-
'chop', '_gap',
330-
'rectangle', 'draw', '_gap',
331-
'advanced_toggle', '_gap',
332-
'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', '_gap',
333-
'blueprint', 'blueprint_to_standard', 'standard_to_blueprint',
334-
},
335-
gather = buttons_to_toolbar{
336-
'gather', '_gap',
337-
'rectangle', 'draw', '_gap',
338-
'advanced_toggle', '_gap',
339-
'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', '_gap',
340-
'blueprint', 'blueprint_to_standard', 'standard_to_blueprint',
341-
},
342-
smooth = buttons_to_toolbar{
343-
'smooth', 'engrave', 'carve_track', 'carve_fortification', '_gap',
352+
fort.center.secondary_toolbars = {}
353+
354+
---@param tool_name CenterToolbarToolNames
355+
---@param secondary_name CenterToolbarSecondaryToolbarNames
356+
---@param toolbar Toolbar.Base
357+
---@return Toolbar
358+
local function center_secondary(tool_name, secondary_name, toolbar)
359+
local ntb = toolbar --[[@as Toolbar]]
360+
function ntb:frame(interface_size)
361+
return center_secondary_frame(interface_size, tool_name, self)
362+
end
363+
fort.center.secondary_toolbars[secondary_name] = ntb
364+
return ntb
365+
end
366+
367+
center_secondary('dig', 'dig', buttons_to_toolbar{
368+
'dig', 'stairs', 'ramp', 'channel', 'remove_construction', '_gap',
369+
'rectangle', 'draw', '_gap',
370+
'advanced_toggle', '_gap',
371+
'all', 'auto', 'ore_gem', 'gem', '_gap',
372+
'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', '_gap',
373+
'blueprint', 'blueprint_to_standard', 'standard_to_blueprint',
374+
})
375+
center_secondary('chop', 'chop', buttons_to_toolbar{
376+
'chop', '_gap',
377+
'rectangle', 'draw', '_gap',
378+
'advanced_toggle', '_gap',
379+
'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', '_gap',
380+
'blueprint', 'blueprint_to_standard', 'standard_to_blueprint',
381+
})
382+
center_secondary('gather', 'gather', buttons_to_toolbar{
383+
'gather', '_gap',
384+
'rectangle', 'draw', '_gap',
385+
'advanced_toggle', '_gap',
386+
'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', '_gap',
387+
'blueprint', 'blueprint_to_standard', 'standard_to_blueprint',
388+
})
389+
center_secondary('smooth', 'smooth', buttons_to_toolbar{
390+
'smooth', 'engrave', 'carve_track', 'carve_fortification', '_gap',
391+
'rectangle', 'draw', '_gap',
392+
'advanced_toggle', '_gap',
393+
'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', '_gap',
394+
'blueprint', 'blueprint_to_standard', 'standard_to_blueprint',
395+
})
396+
center_secondary( 'erase', 'erase', buttons_to_toolbar{
397+
'rectangle',
398+
'draw',
399+
})
400+
-- build -- completely different and quite variable
401+
center_secondary('stockpile', 'stockpile', buttons_to_toolbar{ 'add_stockpile' })
402+
center_secondary('stockpile', 'stockpile_paint', buttons_to_toolbar{
403+
'rectangle', 'draw', 'erase_toggle', 'remove',
404+
})
405+
-- zone -- no secondary toolbar
406+
-- burrow -- no direct secondary toolbar
407+
center_secondary('burrow', 'burrow_paint', buttons_to_toolbar{
408+
'rectangle', 'draw', 'erase_toggle', 'remove',
409+
})
410+
-- cart -- no secondary toolbar
411+
center_secondary('traffic', 'traffic', button_widths_to_toolbar(
412+
concat_sequences{ buttons_to_widths{
413+
'high', 'normal', 'low', 'restricted', '_gap',
344414
'rectangle', 'draw', '_gap',
345415
'advanced_toggle', '_gap',
346-
'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', '_gap',
347-
'blueprint', 'blueprint_to_standard', 'standard_to_blueprint',
348-
},
349-
erase = buttons_to_toolbar{
350-
'rectangle',
351-
'draw',
352-
},
353-
-- build -- completely different and quite variable
354-
stockpile = buttons_to_toolbar{ 'add_stockpile' },
355-
stockpile_paint = buttons_to_toolbar{
356-
'rectangle', 'draw', 'erase_toggle', 'remove',
357-
},
358-
-- zone -- no secondary toolbar
359-
-- burrow -- no direct secondary toolbar
360-
burrow_paint = buttons_to_toolbar{
361-
'rectangle', 'draw', 'erase_toggle', 'remove',
362-
},
363-
-- cart -- no secondary toolbar
364-
traffic = button_widths_to_toolbar(
365-
concat_sequences{ buttons_to_widths{
366-
'high', 'normal', 'low', 'restricted', '_gap',
367-
'rectangle', 'draw', '_gap',
368-
'advanced_toggle', '_gap',
369-
}, {
370-
{ weight_which = 4 },
371-
{ weight_slider = 26 },
372-
{ weight_input = 6 },
373-
} }
374-
),
375-
mass_designation = buttons_to_toolbar{
376-
'claim', 'forbid', 'dump', 'no_dump', 'melt', 'no_melt', 'hidden', 'visible', '_gap',
377-
'rectangle', 'draw',
378-
},
379-
}
416+
}, {
417+
{ weight_which = 4 },
418+
{ weight_slider = 26 },
419+
{ weight_input = 6 },
420+
} }
421+
))
422+
center_secondary('mass_designation', 'mass_designation', buttons_to_toolbar{
423+
'claim', 'forbid', 'dump', 'no_dump', 'melt', 'no_melt', 'hidden', 'visible', '_gap',
424+
'rectangle', 'draw',
425+
})
380426

381427
---@class RightToolbar: Toolbar
382428
fort.right = buttons_to_toolbar{
@@ -502,7 +548,7 @@ local function update_demonstrations(secondary)
502548
-- {s demo}
503549
-- [s tool]
504550
-- [l tool] [c tool] [r tool] (bottom of UI)
505-
update(secondary_toolbar_demo, fort.center:secondary_toolbar_frame(ir, secondary),
551+
update(secondary_toolbar_demo, fort.center.secondary_toolbars[secondary]:frame(ir),
506552
fort.center.secondary_toolbars[secondary].buttons)
507553
secondary_visible = true
508554
toolbar_demo_dy = toolbar_demo_dy - 2 * SECONDARY_TOOLBAR_HEIGHT

0 commit comments

Comments
 (0)