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