z_mirror/BlueprintTools

git clone https://git.raiguard.me/z_mirror/BlueprintTools

Caleb HeuerGet control scripting working00b37f1

trunk
7.5 KiB316 linesraw
1-- FIXME: Use flib gui-lite
2
3--- @diagnostic disable
4
5local mod_name = script.mod_name
6local gui_event_defines = {}
7
8local event_id_to_string_mapping = {}
9for name, id in pairs(defines.events) do
10  if string.find(name, "^on_gui") then
11    gui_event_defines[name] = id
12    event_id_to_string_mapping[id] = string.gsub(name, "^on_gui", "on")
13  end
14end
15
16local flib_gui = {}
17
18function flib_gui.hook_events(callback)
19  local on_event = script.on_event
20  for _, id in pairs(gui_event_defines) do
21    on_event(id, callback)
22  end
23end
24
25function flib_gui.read_action(event_data)
26  local elem = event_data.element
27  if not elem or not elem.valid then
28    return
29  end
30
31  local mod_tags = elem.tags[mod_name]
32  if not mod_tags then
33    return
34  end
35
36  local elem_actions = mod_tags.flib
37  if not elem_actions then
38    return
39  end
40
41  local event_name = event_id_to_string_mapping[event_data.name]
42  local msg = elem_actions[event_name]
43
44  return msg
45end
46
47local function recursive_build(parent, structure, refs)
48  -- If the structure has no type, just ignore it
49  -- This is to make it possible to pass unit types `{}` to represent "no element" without breaking things
50  if not structure.type then
51    return
52  end
53
54  -- Prepare tags
55  local original_tags = structure.tags
56  local tags = original_tags or {}
57  local actions = structure.actions
58  local tags_flib = tags.flib
59  tags.flib = actions
60  structure.tags = { [mod_name] = tags }
61
62  -- Make the game not convert these into a property tree for no reason
63  structure.actions = nil
64  -- Substructures can be defined in special tables or as the array portion of this structure
65  local substructures
66  local substructures_len = #structure
67  if substructures_len > 0 then
68    if structure.children or structure.tabs then
69      error("Children or tab-and-content pairs must ALL be in the array portion, or a subtable. Not both at once!")
70    end
71    substructures = {}
72    for i = 1, substructures_len do
73      substructures[i] = structure[i]
74      structure[i] = nil
75    end
76  else
77    substructures = structure.children or structure.tabs
78    structure.children = nil
79    structure.tabs = nil
80  end
81
82  -- Create element
83  local elem = parent.add(structure)
84
85  -- Restore structure
86  structure.tags = original_tags
87  structure.actions = actions
88  tags.flib = tags_flib
89
90  local style_mods = structure.style_mods
91  if style_mods then
92    for k, v in pairs(style_mods) do
93      elem.style[k] = v
94    end
95  end
96
97  local elem_mods = structure.elem_mods
98  if elem_mods then
99    for k, v in pairs(elem_mods) do
100      elem[k] = v
101    end
102  end
103
104  local ref = structure.ref
105  if ref then
106    -- Recursively create tables as needed
107    local prev = refs
108    local ref_length = #ref
109    for i = 1, ref_length - 1 do
110      local current_key = ref[i]
111      local current = prev[current_key]
112      if not current then
113        current = {}
114        prev[current_key] = current
115      end
116      prev = current
117    end
118    prev[ref[ref_length]] = elem
119  end
120
121  -- Substructures
122  if substructures then
123    if structure.type == "tabbed-pane" then
124      local add_tab = elem.add_tab
125      for i = 1, #substructures do
126        local tab_and_content = substructures[i]
127        if not (tab_and_content.tab and tab_and_content.content) then
128          error("TabAndContent must have `tab` and `content` fields")
129        end
130        local tab = recursive_build(elem, tab_and_content.tab, refs)
131        local content = recursive_build(elem, tab_and_content.content, refs)
132        add_tab(tab, content)
133      end
134    else
135      for i = 1, #substructures do
136        recursive_build(elem, substructures[i], refs)
137      end
138    end
139  end
140
141  return elem
142end
143
144function flib_gui.build(parent, structures)
145  local refs = {}
146  for i = 1, #structures do
147    recursive_build(parent, structures[i], refs)
148  end
149  return refs
150end
151
152function flib_gui.add(parent, structure)
153  -- Just in case they had a ref in the structure already, extract it
154  local previous_ref = structure.ref
155  -- Put in a known ref that we can use later
156  structure.ref = { "FLIB_ADD_ROOT" }
157  -- Build the element
158  local refs = {}
159  recursive_build(parent, structure, refs)
160  -- Restore the previous ref
161  structure.ref = previous_ref
162  -- Return the element
163  return refs.FLIB_ADD_ROOT
164end
165
166local function recursive_update(elem, updates)
167  if updates.cb then
168    updates.cb(elem)
169  end
170
171  if updates.style then
172    elem.style = updates.style
173  end
174
175  if updates.style_mods then
176    for key, value in pairs(updates.style_mods) do
177      elem.style[key] = value
178    end
179  end
180
181  if updates.elem_mods then
182    for key, value in pairs(updates.elem_mods) do
183      elem[key] = value
184    end
185  end
186
187  if updates.tags then
188    flib_gui.update_tags(elem, updates.tags)
189  end
190
191  -- TODO: This could be a lot better
192  if updates.actions then
193    for event_name, payload in pairs(updates.actions) do
194      flib_gui.set_action(elem, event_name, payload)
195    end
196  end
197
198  local substructures
199  local substructures_len = #updates
200  if substructures_len > 0 then
201    if updates.children or updates.tabs then
202      error("Children or tab-and-content pairs must ALL be in the array portion, or a subtable. Not both at once!")
203    end
204    substructures = {}
205    for i = 1, substructures_len do
206      substructures[i] = updates[i]
207      updates[i] = nil
208    end
209  else
210    substructures = updates.children or updates.tabs
211    updates.children = nil
212    updates.tabs = nil
213  end
214  local subelements
215  if elem.type == "tabbed-pane" then
216    subelements = elem.tabs
217  else
218    subelements = elem.children
219  end
220
221  if substructures then
222    for i, substructure in pairs(substructures) do
223      if substructure.tab or substructure.content then
224        local elem_tab_and_content = subelements[i]
225        if elem_tab_and_content then
226          local tab = elem_tab_and_content.tab
227          local tab_updates = substructures.tab
228          if tab and tab_updates then
229            recursive_update(tab, tab_updates)
230          end
231          local content = elem_tab_and_content.content
232          local content_updates = substructures.content
233          if content and content_updates then
234            recursive_update(content, content_updates)
235          end
236        end
237      elseif subelements[i] then
238        recursive_update(subelements[i], substructure)
239      end
240    end
241  end
242end
243
244function flib_gui.update(elem, updates)
245  recursive_update(elem, updates)
246end
247
248function flib_gui.get_tags(elem)
249  return elem.tags[mod_name] or {}
250end
251
252function flib_gui.set_tags(elem, tags)
253  local elem_tags = elem.tags
254  elem_tags[mod_name] = tags
255  elem.tags = elem_tags
256end
257
258function flib_gui.delete_tags(elem)
259  local elem_tags = elem.tags
260  elem_tags[mod_name] = nil
261  elem.tags = elem_tags
262end
263
264function flib_gui.update_tags(elem, updates)
265  local elem_tags = elem.tags
266  local existing = elem_tags[mod_name]
267
268  if not existing then
269    existing = {}
270    elem_tags[mod_name] = existing
271  end
272
273  for k, v in pairs(updates) do
274    existing[k] = v
275  end
276
277  elem.tags = elem_tags
278end
279
280function flib_gui.set_action(elem, event_name, msg)
281  local elem_tags = elem.tags
282  local existing = elem_tags[mod_name]
283
284  if not existing then
285    existing = {}
286    elem_tags[mod_name] = existing
287  end
288
289  local actions = existing.flib
290  if not actions then
291    actions = {}
292    existing.flib = actions
293  end
294
295  actions[event_name] = msg or nil
296
297  elem.tags = elem_tags
298end
299
300function flib_gui.get_action(elem, event_name)
301  local elem_tags = elem.tags
302  local existing = elem_tags[mod_name]
303
304  if not existing then
305    return
306  end
307
308  local actions = existing.flib
309  if not actions then
310    return
311  end
312
313  return actions[event_name]
314end
315
316return flib_gui