OK, so after writing not one but four bug reports related to this little endeavor i might as well also write down how i ended up implementing it manually as best as currently possible. (Unless i'm really missing something blatantly obvious here.)
As stated above each switch is created as "table" type gui element that contains three children: two labels and one switch.
Code: Select all
function ScreenshotGui:add_aligned_switch(opts, args, ...)
if not opts.width then error('aligned switch needs width') end
--
local switch_table = opts.parent.add{
name = args.name, -- element name
type = 'table',
column_count = 3,
style = 'er:screenshot-gui-aligned-switch-table',
}
switch_table.style.width = opts.width
--
self:add_element({
parent = switch_table,
update = 'on_player_clicked_aligned_switch',
},{
type = 'label',
style = 'er:screenshot-gui-aligned-switch-inactive-label',
caption = args.left_label_caption,
},{
})
self:add_element({
name = opts.name, -- storage name
parent = switch_table,
update = 'on_player_clicked_aligned_switch',
},{
type = 'switch',
name = 'aligned-switch',
switch_state = CONST.GUI.DUMMY_SWITCH_STATE,
allow_none_state = args.allow_none_state,
})
self:add_element({
parent = switch_table,
update = 'on_player_clicked_aligned_switch',
},{
type = 'label',
style = 'er:screenshot-gui-aligned-switch-inactive-label',
caption = args.right_label_caption,
},{
})
if opts.update then
set_gui_element_update_handler(switch_table, opts.update)
end
return switch_table
end
I tried using a horizontal flow first, but that didn't work out due to
this bug. I could've written even more workarounds for that but just using a table seemed easier. The table alignments and size here do the main problem-solving magic. They force each label to an exact width so that different content width doesn't disalign the switch button.
Code: Select all
styles['er:screenshot-gui-aligned-switch-table'] = {
type = 'table_style',
parent = nil,
column_widths = {
{column = 1, width = 54},
-- {column = 2, width = 20}, -- width of the switch itself is untouched
{column = 3, width = 54},
},
column_alignments = {
{column = 1, alignment = 'middle-right' },
{column = 2, alignment = 'middle-center'},
{column = 3, alignment = 'middle-left' },
}
}
Because a normal switch style also contains the label styles i had to copy those too to make them accessible during runtime.
Code: Select all
-- Create stand-alone names for vanilla switch labels.
styles['er:screenshot-gui-aligned-switch-inactive-label'] =
util.table.deepcopy(styles['switch'].inactive_label)
styles['er:screenshot-gui-aligned-switch-active-label'] =
util.table.deepcopy(styles['switch'].active_label)
When the player clicks any of the tree components i call a proxy update function. It checks which component the player clicked, and if that click results in a change to the switches state, and then updates the label styles and plays a sound. And then passes the click on to the real click handler - the one that would have been called if i had used a native switch gui element.
Code: Select all
function ScreenshotGui:on_player_clicked_aligned_switch(elm, e)
-- triggers for clicks on any of the three components!
local switch_table = e.element.parent
if switch_table == e.element then return end
local left_label = switch_table.children[1]
local switch = switch_table.children[2]
local right_label = switch_table.children[3]
--
local function switch_if_changed(side)
if switch.switch_state ~= side then
-- "gui_click" is not the correct sound for switches, but playing
-- custom sounds does not currently work at high zoom-out @factorio 1.1
self.player.play_sound {path = 'utility/gui_click'}
-- self.player.play_sound {path = 'er:gui-switch-click'}
switch.switch_state = side
end
end
if e.element == left_label then
switch_if_changed 'left'
elseif e.element == right_label then
switch_if_changed 'right'
else
-- switch.switch_state = 'none'
end
--
self:update_aligned_switch_labels()
--
local update_handler_name = get_gui_element_update_handler(switch_table)
if update_handler_name then
e.element = switch_table
self:on_player_clicked_something(e)
end
end
function ScreenshotGui:update_aligned_switch_labels()
local _styles = {
[true ] = 'er:screenshot-gui-aligned-switch-active-label' ,
[false] = 'er:screenshot-gui-aligned-switch-inactive-label',
}
for _, elm in pairs(self.elements) do
if elm.name == 'aligned-switch' then
-- 1,2,3 -> left-label, switch, right-label
local switch_table = elm.parent
local switch_state = switch_table.children[2].switch_state
switch_table.children[1].style = _styles['left' == switch_state]
switch_table.children[3].style = _styles['right' == switch_state]
end
end
end
So for something as simple as changing the width of a label... this is way too much code. Hopefully any future readers now better understand why i really didn't want to go this route. And may it help other modders if they encounter similar problems.