z_mirror/TaskList

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

raiguardMostly hook up task details GUI (#7)fa77a7d

task-details-gui
9.2 KiB354 linesraw
1local gui = require("__flib__.gui")
2
3local constants = require("constants")
4
5local templates = require("scripts.gui.templates")
6local util = require("scripts.util")
7
8local actions = require("actions")
9
10-- GUI
11
12--- @class TasksGuiRefs
13--- @field window LuaGuiElement
14--- @field titlebar_flow LuaGuiElement
15--- @field pin_button LuaGuiElement
16--- @field visibility_switch LuaGuiElement
17--- @field scroll_pane LuaGuiElement
18--- @field force_flow LuaGuiElement
19--- @field private_flow LuaGuiElement
20
21--- @class TasksGui
22local TasksGui = {}
23
24TasksGui.actions = actions
25
26function TasksGui:destroy()
27  local window = self.refs.window
28  if window and window.valid then
29    self.refs.window.destroy()
30  end
31
32  self.player_table.guis.tasks = nil
33end
34
35function TasksGui:open()
36  self.refs.window.bring_to_front()
37  self.refs.window.visible = true
38  self.state.visible = true
39
40  if not self.state.pinned then
41    self.player.opened = self.refs.window
42  end
43
44  self.player.set_shortcut_toggled("tlst-toggle-gui", true)
45end
46
47function TasksGui:close()
48  if self.state.ignore_close then
49    self.state.ignore_close = false
50    return
51  end
52
53  self.refs.window.visible = false
54  self.state.visible = false
55
56  if self.player.opened == self.refs.window then
57    self.player.opened = nil
58  end
59
60  self.player.set_shortcut_toggled("tlst-toggle-gui", false)
61end
62
63function TasksGui:toggle()
64  if self.state.visible then
65    self:close()
66  else
67    self:open()
68  end
69end
70
71function TasksGui:dispatch(msg, e)
72  local transform = msg.transform
73  if transform then
74    if transform == "handle_titlebar_click" and e.button == defines.mouse_button_type.middle then
75      msg.action = "recenter"
76    elseif transform == "handle_expand_click" then
77      if e.button == defines.mouse_button_type.middle then
78        msg.action = "open_task_gui"
79      else
80        if e.shift then
81          msg.action = "move_task"
82          msg.delta = -1
83        elseif e.control then
84          msg.action = "move_task"
85          msg.delta = 1
86        else
87          msg.action = "expand_task"
88        end
89      end
90    end
91  end
92
93  if msg.action then
94    local handler = self.actions[msg.action]
95    if handler then
96      handler(self, msg, e)
97    end
98  end
99end
100
101--- Get the parent flow for the given task
102--- @param Task Task
103function TasksGui:get_parent_flow(Task)
104  local route = {}
105
106  local owner = Task.owner
107  while owner.object_name == "Task" do
108    table.insert(route, 1, owner)
109    owner = owner.owner
110  end
111
112  -- At this point, the owner will be a LuaForce or LuaPlayer
113  local flow = owner.object_name == "LuaForce" and self.refs.force_flow or self.refs.private_flow
114  for _, owner in pairs(route) do
115    local subflow = owner.completed and flow.completed or flow.incompleted
116    local row = subflow[tostring(owner.id)]
117    if row then
118      flow = row.details_flow.subtasks_flow
119    end
120  end
121
122  return flow
123end
124
125--- @param Task Task
126--- @param index number
127function TasksGui:add_task(Task, index, completed)
128  if completed == nil then
129    completed = Task.completed
130  end
131  local flow = self:get_parent_flow(Task)
132  --- @type LuaGuiElement
133  local flow = completed and flow.completed or flow.incompleted
134
135  gui.add(flow, templates.task_item(Task, "tasks", index, completed))
136
137  if #flow.children > 0 and (not completed or self.state.show_completed) then
138    flow.visible = true
139  else
140    flow.visible = false
141  end
142
143  -- Add subtasks
144  for _, subtasks in pairs({ Task.completed_tasks, Task.tasks }) do
145    for _, subtask_id in pairs(subtasks) do
146      local subtask = global.tasks[subtask_id]
147      if subtask then
148        self:add_task(subtask)
149      end
150    end
151  end
152end
153
154--- @param Task Task
155function TasksGui:update_task(Task)
156  local flow = self:get_parent_flow(Task)
157  --- @type LuaGuiElement
158  local flow = Task.completed and flow.completed or flow.incompleted
159
160  local row = flow[tostring(Task.id)]
161  if row then
162    local status_info = constants.task_status[Task.status]
163    local assignee_name = Task.assignee and Task.assignee.name or nil
164    gui.update(row, {
165      {
166        { elem_mods = { caption = Task.title } },
167        { elem_mods = { caption = assignee_name, visible = assignee_name and true or false } },
168        {
169          elem_mods = {
170            sprite = "flib_indicator_" .. status_info.color,
171            tooltip = status_info.label,
172          },
173        },
174      },
175      {
176        { elem_mods = { caption = Task.description, visible = #Task.description > 0 } },
177      },
178    })
179  end
180end
181
182--- @param Task Task
183function TasksGui:delete_task(Task, completed)
184  if completed == nil then
185    completed = Task.completed
186  end
187  local flow = self:get_parent_flow(Task)
188  --- @type LuaGuiElement
189  local flow = completed and flow.completed or flow.incompleted
190
191  local row = flow[tostring(Task.id)]
192  if row then
193    row.destroy()
194  end
195
196  if #flow.children > 0 and (not completed or self.state.show_completed) then
197    flow.visible = true
198  else
199    flow.visible = false
200  end
201end
202
203--- @param Task Task
204--- @param delta number
205function TasksGui:move_task(Task, delta)
206  local flow = self:get_parent_flow(Task)
207  --- @type LuaGuiElement
208  local flow = Task.completed and flow.completed or flow.incompleted
209  local row = flow[tostring(Task.id)]
210  if row then
211    flow.swap_children(row.get_index_in_parent(), row.get_index_in_parent() + delta)
212  end
213end
214
215function TasksGui:update_show_completed()
216  local show_completed = self.state.show_completed
217
218  util.recursive_show_completed(self.refs.force_flow, show_completed)
219  util.recursive_show_completed(self.refs.private_flow, show_completed)
220end
221
222-- BOOTSTRAP
223
224local index = {}
225
226--- @param player LuaPlayer
227--- @param player_table PlayerTable
228function index.new(player, player_table)
229  --- @type TasksGuiRefs
230  local refs = gui.build(player.gui.screen, {
231    {
232      type = "frame",
233      style_mods = { width = 500 },
234      direction = "vertical",
235      ref = { "window" },
236      visible = false,
237      actions = {
238        on_closed = { gui = "tasks", action = "close" },
239      },
240      {
241        type = "flow",
242        style = "flib_titlebar_flow",
243        ref = { "titlebar_flow" },
244        actions = {
245          on_click = { gui = "tasks", transform = "handle_titlebar_click" },
246        },
247        { type = "label", style = "frame_title", caption = { "gui.tlst-tasks" }, ignored_by_interaction = true },
248        { type = "empty-widget", style = "flib_titlebar_drag_handle", ignored_by_interaction = true },
249        templates.frame_action_button(
250          "flib_pin",
251          { "gui.flib-keep-open" },
252          { gui = "tasks", action = "pin" },
253          { "pin_button" }
254        ),
255        templates.frame_action_button("utility/close", { "gui.close-instruction" }, {
256          gui = "tasks",
257          action = "close",
258        }),
259      },
260      {
261        type = "frame",
262        style = "inside_shallow_frame",
263        direction = "vertical",
264        {
265          type = "frame",
266          style = "subheader_frame",
267          {
268            type = "checkbox",
269            style_mods = { left_margin = 8 },
270            caption = { "gui.tlst-show-completed" },
271            state = false,
272            actions = {
273              on_checked_state_changed = { gui = "tasks", action = "toggle_show_completed" },
274            },
275          },
276          { type = "empty-widget", style = "flib_horizontal_pusher" },
277          {
278            type = "switch",
279            left_label_caption = { "gui.tlst-force" },
280            left_label_tooltip = { "gui.tlst-force-switch-description" },
281            right_label_caption = { "gui.tlst-private" },
282            right_label_tooltip = { "gui.tlst-private-switch-description" },
283            switch_state = "left",
284            ref = { "visibility_switch" },
285            actions = {
286              on_switch_state_changed = { gui = "tasks", action = "toggle_tasks_mode" },
287            },
288          },
289          { type = "empty-widget", style_mods = { width = 20 } },
290          {
291            type = "sprite-button",
292            style = "flib_tool_button_light_green",
293            sprite = "utility/add",
294            tooltip = { "gui.tlst-new-task" },
295            actions = {
296              on_click = { gui = "tasks", action = "edit_task" },
297            },
298          },
299        },
300        {
301          type = "scroll-pane",
302          style = "flib_naked_scroll_pane",
303          ref = { "scroll_pane" },
304          templates.checkboxes_flow("force"),
305          templates.checkboxes_flow("private", false),
306        },
307      },
308    },
309  })
310
311  refs.window.force_auto_center()
312  refs.titlebar_flow.drag_target = refs.window
313
314  --- @type TasksGui
315  local self = {
316    player = player,
317    player_table = player_table,
318    refs = refs,
319    --- @class TasksGuiState
320    state = {
321      ignore_close = false,
322      pinned = false,
323      show_completed = false,
324      visible = false,
325    },
326  }
327
328  setmetatable(self, { __index = TasksGui })
329
330  player_table.guis.tasks = self
331
332  -- Add existing tasks
333  local force_table = global.forces[player.force.index]
334  for _, tasks in pairs({
335    force_table.completed_tasks,
336    force_table.tasks,
337    player_table.completed_tasks,
338    player_table.tasks,
339  }) do
340    for _, task_id in pairs(tasks) do
341      local Task = global.tasks[task_id]
342      if Task then
343        self:add_task(Task)
344      end
345    end
346  end
347end
348
349--- @param Gui TasksGui
350function index.load(Gui)
351  setmetatable(Gui, { __index = TasksGui })
352end
353
354return index