@@ -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
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.
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
178176local function button_widths_to_toolbar (widths )
179177 local offsets = {}
180178 local buttons = {}
@@ -203,15 +201,15 @@ local function buttons_to_widths(buttons)
203201end
204202
205203--- @param buttons string[]
206- --- @return Toolbar
204+ --- @return Toolbar.Base
207205local function buttons_to_toolbar (buttons )
208206 return button_widths_to_toolbar (buttons_to_widths (buttons ))
209207end
210208
211209-- Fortress mode toolbar definitions
212210fort = {}
213211
214- --- @class LeftToolbar : Toolbar
212+ --- @class LeftToolbar : Toolbar
215213fort .left = buttons_to_toolbar {
216214 ' citizens' , ' tasks' , ' places' , ' labor' ,
217215 ' orders' , ' nobles' , ' objects' , ' justice' ,
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 }
316315end
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
382428fort .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