├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── addons
└── NbPM
│ ├── ProjectScreen.gd
│ ├── ProjectScreen.tscn
│ ├── TodoDock.gd
│ ├── TodoDock.tscn
│ ├── card
│ ├── Card.gd
│ ├── Card.tscn
│ └── DragPreview.tscn
│ ├── font
│ ├── NotoSans-Regular.ttf
│ ├── OFL.txt
│ └── font12.tres
│ ├── icons
│ ├── add_task.png
│ ├── add_task.png.import
│ ├── caret-down-solid.svg
│ ├── caret-down-solid.svg.import
│ ├── chalkboard-teacher-solid.svg
│ ├── chalkboard-teacher-solid.svg.import
│ ├── ellipsis-h-solid.svg
│ ├── ellipsis-h-solid.svg.import
│ ├── external-link-alt-solid.svg
│ ├── external-link-alt-solid.svg.import
│ ├── plus-square-regular.svg
│ ├── plus-square-regular.svg.import
│ ├── pm_icon.png
│ ├── pm_icon.png.import
│ ├── save-solid.svg
│ ├── save-solid.svg.import
│ ├── sync-alt-solid.svg
│ ├── sync-alt-solid.svg.import
│ ├── tasks-solid.svg
│ ├── tasks-solid.svg.import
│ ├── times-solid.svg
│ ├── times-solid.svg.import
│ ├── trash-solid.svg
│ ├── trash-solid.svg.import
│ ├── view_src.png
│ └── view_src.png.import
│ ├── lane
│ ├── DropZone.gd
│ ├── DropZone.tscn
│ ├── Lane.gd
│ └── Lane.tscn
│ ├── ninepatch.png
│ ├── ninepatch.png.import
│ ├── plugin.cfg
│ ├── plugin_loader.gd
│ ├── screenshots
│ ├── .gdignore
│ ├── screenshot1.gif
│ ├── screenshot2.png
│ └── screenshot3.png
│ └── settings
│ ├── InputField.gd
│ └── InputField.tscn
├── default_env.tres
├── icon.png
├── icon.png.import
└── project.godot
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Normalize EOL for all files that Git considers text files.
2 | * text=auto eol=lf
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Godot 4+ specific ignores
2 | .godot/
3 |
4 | # Godot-specific ignores
5 | .import/
6 | export.cfg
7 | export_presets.cfg
8 |
9 | # Imported translations (automatically generated from CSV files)
10 | *.translation
11 |
12 | # Mono-specific ignores
13 | .mono/
14 | data_*/
15 | mono_crash.*.json
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 NimbleBeasts
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 | Icons from Fontawesome licensed under Creative Commons Attribution 4.0 International:
24 | https://fontawesome.com/license
25 |
26 |
27 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
28 | This license is copied below, and is also available with a FAQ at:
29 | http://scripts.sil.org/OFL
30 |
31 | Copyright 2012 Google Inc. All Rights Reserved.
32 |
33 | -----------------------------------------------------------
34 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
35 | -----------------------------------------------------------
36 |
37 | PREAMBLE
38 | The goals of the Open Font License (OFL) are to stimulate worldwide
39 | development of collaborative font projects, to support the font creation
40 | efforts of academic and linguistic communities, and to provide a free and
41 | open framework in which fonts may be shared and improved in partnership
42 | with others.
43 |
44 | The OFL allows the licensed fonts to be used, studied, modified and
45 | redistributed freely as long as they are not sold by themselves. The
46 | fonts, including any derivative works, can be bundled, embedded,
47 | redistributed and/or sold with any software provided that any reserved
48 | names are not used by derivative works. The fonts and derivatives,
49 | however, cannot be released under any other type of license. The
50 | requirement for fonts to remain under this license does not apply
51 | to any document created using the fonts or their derivatives.
52 |
53 | DEFINITIONS
54 | "Font Software" refers to the set of files released by the Copyright
55 | Holder(s) under this license and clearly marked as such. This may
56 | include source files, build scripts and documentation.
57 |
58 | "Reserved Font Name" refers to any names specified as such after the
59 | copyright statement(s).
60 |
61 | "Original Version" refers to the collection of Font Software components as
62 | distributed by the Copyright Holder(s).
63 |
64 | "Modified Version" refers to any derivative made by adding to, deleting,
65 | or substituting -- in part or in whole -- any of the components of the
66 | Original Version, by changing formats or by porting the Font Software to a
67 | new environment.
68 |
69 | "Author" refers to any designer, engineer, programmer, technical
70 | writer or other person who contributed to the Font Software.
71 |
72 | PERMISSION & CONDITIONS
73 | Permission is hereby granted, free of charge, to any person obtaining
74 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
75 | redistribute, and sell modified and unmodified copies of the Font
76 | Software, subject to the following conditions:
77 |
78 | 1) Neither the Font Software nor any of its individual components,
79 | in Original or Modified Versions, may be sold by itself.
80 |
81 | 2) Original or Modified Versions of the Font Software may be bundled,
82 | redistributed and/or sold with any software, provided that each copy
83 | contains the above copyright notice and this license. These can be
84 | included either as stand-alone text files, human-readable headers or
85 | in the appropriate machine-readable metadata fields within text or
86 | binary files as long as those fields can be easily viewed by the user.
87 |
88 | 3) No Modified Version of the Font Software may use the Reserved Font
89 | Name(s) unless explicit written permission is granted by the corresponding
90 | Copyright Holder. This restriction only applies to the primary font name as
91 | presented to the users.
92 |
93 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
94 | Software shall not be used to promote, endorse or advertise any
95 | Modified Version, except to acknowledge the contribution(s) of the
96 | Copyright Holder(s) and the Author(s) or with their explicit written
97 | permission.
98 |
99 | 5) The Font Software, modified or unmodified, in part or in whole,
100 | must be distributed entirely under this license, and must not be
101 | distributed under any other license. The requirement for fonts to
102 | remain under this license does not apply to any document created
103 | using the Font Software.
104 |
105 | TERMINATION
106 | This license becomes null and void if any of the above conditions are
107 | not met.
108 |
109 | DISCLAIMER
110 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
111 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
112 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
113 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
114 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
115 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
116 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
117 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
118 | OTHER DEALINGS IN THE FONT SOFTWARE.
119 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Project Management for Godot
2 |
3 | > A Multi-Party Kanban Project Management Plugin for Godot
4 |
5 | 
6 |
7 | - For all those annoyed by lazy developers who don't feel like updating the project board
8 | - For all those who want their developers to have no distraction by using a web browser
9 | - For all those solo devs, jammers, and all other
10 |
11 | ## Features
12 | - Create tasks and track the progress
13 | - Add members and assign tasks
14 | - Filter your tasks
15 | - Configure the amount and name of your swimlanes
16 | - TODO Dock Window to list your TODOs
17 | - Jump to source from the TODO Dock
18 | - Create new tasks from TODOs
19 | - All tasks are JSON files
20 |
21 | ## Usage
22 | 1. Get the zip
23 | 2. Create a 'addons' folder within your project, if needed
24 | 3. Put the 'NbPM' folder in the addons folder
25 | 4. Project -> Project Settings -> Plugins -> Enable
26 | 5. Open the 'ProjectManagement' screen
27 | 6. Opening the PM for the first time will let you set up the project config
28 | 7. After saving, you will have to select the user
29 | 8. Commit everything to Git if needed
30 |
31 | > Soon to be available on the Godot asset store.
32 |
33 | ## Support this project
34 | This project can be supported via [Itch.io](https://nimblebeastscollective.itch.io/godot-project-manager).
35 |
--------------------------------------------------------------------------------
/addons/NbPM/ProjectScreen.gd:
--------------------------------------------------------------------------------
1 | tool
2 | extends Control
3 |
4 | ###############################################################################
5 | # Scenes
6 | ###############################################################################
7 | const Scene_Lane = preload("res://addons/NbPM/lane/Lane.tscn")
8 | const Scene_InputField = preload("res://addons/NbPM/settings/InputField.tscn")
9 |
10 | ###############################################################################
11 | # References
12 | ###############################################################################
13 | var Settings_Category = null
14 | var Settings_User = null
15 | var Settings_Tag = null
16 | var Settings_Folder = null
17 | # Loader Reference
18 | var ref = null
19 |
20 | ###############################################################################
21 | # State variables
22 | ###############################################################################
23 | var _project_cfg_provided = false
24 | var _user_cfg_provided = false
25 | var drag = false
26 |
27 | var tasks = []
28 | var base_color: Color
29 |
30 | var task_timestamp = 0
31 | var task_context = {}
32 |
33 | var needs_update = false
34 |
35 | var filter = false
36 |
37 | func hide_all():
38 | $ProjectSettingsWindow.hide()
39 | $UserSettingsWindow.hide()
40 | $TaskView.hide()
41 | $Scroll.hide()
42 |
43 |
44 | # Update the project settings window; Called by loader each time the cfg has changed.
45 | func update_project_config():
46 | Settings_Category = get_node("ProjectSettingsWindow/Category/scroll/v")
47 | Settings_User = get_node("ProjectSettingsWindow/Users/scroll/v")
48 | Settings_Tag = get_node("ProjectSettingsWindow/Tags/scroll/v")
49 | Settings_Folder = get_node("ProjectSettingsWindow/ExcludeFolders/scroll/v")
50 |
51 | # Update Settings
52 | # Categories
53 | _clear_setting_items(Settings_Category)
54 | _add_setting_items(Settings_Category, ref.config_project.categories)
55 | # Users
56 | _clear_setting_items(Settings_User)
57 | _add_setting_items(Settings_User, ref.config_project.user_names)
58 | # Tags
59 | _clear_setting_items(Settings_Tag)
60 | _add_setting_items(Settings_Tag, ref.config_project.tags)
61 | # Folders
62 | _clear_setting_items(Settings_Folder)
63 | _add_setting_items(Settings_Folder, ref.config_project.exclude_folders)
64 |
65 | # Clear olds
66 | $TaskView/Input/Stage.clear()
67 | $TaskView/Input/Assigned.clear()
68 | $UserSettingsWindow/UserSelect.clear()
69 | for lane in $Scroll/h.get_children():
70 | lane.queue_free()
71 |
72 | var id = 0
73 |
74 | for cat in ref.config_project.categories:
75 | # Update Options
76 | $TaskView/Input/Stage.add_item(cat, id)
77 |
78 | # Update Lanes
79 | var lane = Scene_Lane.instance()
80 | lane.setup(self, cat, id, base_color)
81 | $Scroll/h.add_child(lane)
82 | id += 1
83 |
84 | id = 0
85 | for user in ref.config_project.user_names:
86 | # Update Options
87 | $TaskView/Input/Assigned.add_item(user, id)
88 | $UserSettingsWindow/UserSelect.add_item(user, id)
89 | id += 1
90 |
91 | if _project_cfg_provided and _user_cfg_provided:
92 | needs_update = true
93 |
94 |
95 | # Update the user settings window; Called by loader each time the cfg has changed.
96 | func update_user_config():
97 | print("update_user_config")
98 | # Update Settings
99 |
100 | # Update Options
101 | pass
102 |
103 |
104 | # Save project settings to config
105 | func _on_ProjectSettingsSaveButton_button_up():
106 | ref.config_project.categories = _get_setting_items(Settings_Category)
107 | ref.config_project.user_names = _get_setting_items(Settings_User)
108 | ref.config_project.tags = _get_setting_items(Settings_Tag)
109 | ref.config_project.exclude_folders = _get_setting_items(Settings_Folder)
110 | ref.save_project_config()
111 |
112 | $ProjectSettingsWindow.hide()
113 |
114 | if _project_cfg_provided == false:
115 | _project_cfg_provided = true
116 | setup_steps()
117 |
118 | func _on_UserSettingsSaveButton_button_up():
119 | ref.config_user.user_id = $UserSettingsWindow/UserSelect.selected
120 |
121 | $UserSettingsWindow.hide()
122 |
123 | ref.save_user_config()
124 | if _user_cfg_provided == false:
125 | _user_cfg_provided = true
126 | setup_steps()
127 |
128 |
129 | # Get value of underlying item input fields
130 | func _get_setting_items(ref):
131 | var array = []
132 | for item in ref.get_children():
133 | array.append(item.get_value())
134 | return array
135 |
136 |
137 | # Remove all item input fields
138 | func _clear_setting_items(ref):
139 | if ref:
140 | for child in ref.get_children():
141 | child.queue_free()
142 | else:
143 | printerr("_clear_setting_items ref not found")
144 |
145 | # Add item input fields for each array element
146 | func _add_setting_items(ref, array):
147 | var remove = ""
148 | match ref:
149 | Settings_Category:
150 | remove = "_remove_category_item"
151 | Settings_User:
152 | remove = "_remove_user_item"
153 | Settings_Tag:
154 | remove = "_remove_tag_item"
155 | _: #Settings_Folder
156 | remove = "_remove_folder_item"
157 |
158 | for item in array:
159 | _add_setting_item(ref, remove, item)
160 |
161 |
162 |
163 | # If provided null, indicates, project was not set up.
164 | func setup(loader_ref, project_cfg_provided, user_cfg_provided):
165 | assert(loader_ref)
166 | ref = loader_ref
167 | _project_cfg_provided = project_cfg_provided
168 | _user_cfg_provided = user_cfg_provided
169 | base_color = loader_ref.get_editor_interface().get_editor_settings().get_setting("interface/theme/base_color")
170 |
171 | # Setup project config window
172 | update_project_config()
173 | # Setup user config window
174 | update_user_config()
175 |
176 | # Project config was not set-up, lets do this first
177 | setup_steps()
178 |
179 |
180 |
181 |
182 | func setup_steps():
183 | hide_all()
184 | # No project config provided
185 | if _project_cfg_provided == false:
186 | $ProjectSettingsWindow.show()
187 | return
188 | # No user config provided
189 | elif _user_cfg_provided == false:
190 | $UserSettingsWindow.show()
191 | return
192 | else:
193 | $Scroll.show()
194 | # Update Tasks
195 | _update_tasks()
196 |
197 |
198 | ## Create a new task
199 | func new_task(category = 0, context = {}):
200 | task_timestamp = 0
201 |
202 | if context.empty():
203 | $TaskView/Input/Title.text = "Title"
204 | $TaskView/Description.text = ""
205 | else:
206 | task_context = context
207 | $TaskView/Input/Title.text = str(task_context.todo.type) + ": " + str(task_context.todo.description)
208 | $TaskView/Description.text = "\n\n" + "(File: " + str(task_context.path_file) + " - Last known line: " + str(task_context.todo.line) + ")"
209 |
210 | $TaskView/Input/Stage.select(category)
211 | $TaskView/Input/Assigned.select(0)
212 |
213 | $TaskView/Input/TimestampLabel.set_text(_get_datetime_string(_get_local_unix_time()))
214 | $TaskView.show()
215 |
216 |
217 | ## Create a new task from todo
218 | func jump_to_main_screen(metadata):
219 | #{"type": "VIEW_TASK", "task": task}
220 | if metadata.type == "VIEW_TASK":
221 | view_task(metadata.task)
222 | else:
223 | new_task(0, metadata)
224 |
225 |
226 | ## View existing task
227 | func view_task(task_hash):
228 | for task in tasks:
229 | if task.hash == task_hash:
230 | $TaskView/Input/Title.text = task.title
231 | $TaskView/Input/Stage.select(task.category)
232 | $TaskView/Input/Assigned.select(task.assigned)
233 | task_timestamp = task.timestamp
234 | $TaskView/Input/TimestampLabel.set_text(_get_datetime_string(task_timestamp))
235 | $TaskView/Description.text = task.description
236 | break
237 | $TaskView.show()
238 |
239 |
240 | ## Save Task
241 | func save_task():
242 | if task_timestamp == 0:
243 | task_timestamp = _get_local_unix_time()
244 |
245 | var time_hash = str(task_timestamp).sha256_text()
246 |
247 | var save_task = {
248 | "title": $TaskView/Input/Title.text,
249 | "category": $TaskView/Input/Stage.selected,
250 | "assigned": $TaskView/Input/Assigned.selected,
251 | "timestamp": task_timestamp,
252 | "hash": time_hash,
253 | "description": $TaskView/Description.text,
254 | "todos": []
255 | }
256 |
257 | var file = File.new()
258 | file.open(ref.PM_TASK_DIRECTORY + "/" + time_hash + ".task", File.WRITE)
259 | file.store_line(JSON.print(save_task, "\t"))
260 | file.close()
261 |
262 | # Reset
263 | task_timestamp = 0
264 | $TaskView.hide()
265 |
266 | if not task_context.empty():
267 | ref.config_project.linkage.append(
268 | {
269 | "task": time_hash,
270 | "file": task_context.path_file,
271 | "description": task_context.todo.description
272 | }
273 | )
274 | task_context = {}
275 | # Saving will trigger update_project_config()
276 | ref.save_project_config()
277 |
278 | _update_tasks()
279 |
280 |
281 | ## Delete task
282 | func delete_task(task_hash):
283 | var dir = Directory.new()
284 | dir.remove(ref.PM_TASK_DIRECTORY + "/" + task_hash + ".task")
285 |
286 | var id = 0
287 | for link in ref.config_project.linkage:
288 | if link.task == task_hash:
289 | ref.config_project.linkage.remove(id)
290 | ref.save_project_config()
291 | break
292 | id += 1
293 |
294 | _update_tasks()
295 |
296 |
297 |
298 |
299 | func _update_tasks():
300 | _scan_tasks()
301 | _update_gui()
302 |
303 |
304 | func _scan_tasks():
305 | var dir = Directory.new()
306 | # Clean tasks
307 | tasks = []
308 |
309 | # Scan task directory
310 | if dir.open(ref.PM_TASK_DIRECTORY) == OK:
311 | dir.list_dir_begin(true, true)
312 | var file_name = dir.get_next()
313 |
314 | while file_name != "":
315 | if not dir.current_is_dir():
316 | if file_name.get_extension() == "task":
317 | #print(file_name)
318 | _scan_file(file_name)
319 | file_name = dir.get_next()
320 | dir.list_dir_end()
321 |
322 | func _scan_file(file_name):
323 | var file = File.new()
324 | file.open(ref.PM_TASK_DIRECTORY + "/" + file_name, File.READ)
325 | tasks.append(parse_json(file.get_as_text()))
326 | file.close()
327 |
328 |
329 | func _update_gui():
330 | #TODO: only re-render, if file has changed
331 | var id = 0
332 |
333 | # Loop over categories
334 | for lane in $Scroll/h.get_children():
335 | lane.clear()
336 |
337 | # Check if task matches category
338 | for task in tasks:
339 | if task.category == id:
340 | var assigned_string = ref.config_project.user_names[task.assigned]
341 | if not filter or (filter and task.assigned == ref.config_user.user_id):
342 | lane.add(task, assigned_string)
343 | id += 1
344 |
345 |
346 | func _process(delta):
347 | if drag:
348 | if not Input.is_mouse_button_pressed(BUTTON_LEFT):
349 | stop_card_drag()
350 | if needs_update:
351 | needs_update = false
352 | _update_tasks()
353 |
354 |
355 | func start_card_drag():
356 | for child in $Scroll/h.get_children():
357 | child.drag_start()
358 | drag = true
359 |
360 | func stop_card_drag():
361 | for child in $Scroll/h.get_children():
362 | child.drag_stop()
363 |
364 |
365 |
366 |
367 | func _on_SettingsButton_button_up():
368 | if $SettingsWindow.visible:
369 | $SettingsWindow.hide()
370 | else:
371 | $SettingsWindow.show()
372 |
373 |
374 |
375 | func move_task(id, task_hash):
376 | for task in tasks:
377 | if task.hash == task_hash:
378 | var data = task.duplicate()
379 | data.category = id
380 | var file = File.new()
381 | file.open(ref.PM_TASK_DIRECTORY + "/" + task_hash + ".task", File.WRITE)
382 | file.store_line(JSON.print(data, "\t"))
383 | file.close()
384 | _update_tasks()
385 | break
386 |
387 | func _get_datetime_string(unixTime):
388 | var dict = OS.get_datetime_from_unix_time(unixTime)
389 | return "%0*d" % [2, dict.day] + "/" + "%0*d" % [2, dict.month] + "/" + str(dict.year) + " - " + "%0*d" % [2, dict.hour] + ":" + "%0*d" % [2, dict.minute]
390 |
391 | func _get_local_unix_time():
392 | var date = OS.get_datetime_from_unix_time(OS.get_unix_time())
393 | var time = OS.get_time()
394 | date.hour = time.hour
395 | date.minute = time.minute
396 | return OS.get_unix_time_from_datetime(date)
397 |
398 |
399 | func _on_TaskViewSaveButton_button_up():
400 | save_task()
401 |
402 |
403 | func _remove_category_item(reference, id):
404 | reference.queue_free()
405 | func _remove_user_item(reference, id):
406 | reference.queue_free()
407 | func _remove_tag_item(reference, id):
408 | reference.queue_free()
409 | func _remove_folder_item(reference, id):
410 | reference.queue_free()
411 |
412 | func _add_setting_item(reference, remove_function, value = ""):
413 | var item = Scene_InputField.instance()
414 | var id = reference.get_child_count()
415 | item.setup(id, value)
416 | item.connect("remove_input", self, remove_function)
417 | reference.add_child(item)
418 |
419 |
420 | func _on_AddCategory_button_up():
421 | _add_setting_item(Settings_Category, "_remove_category_item")
422 |
423 |
424 | func _on_AddUser_button_up():
425 | _add_setting_item(Settings_User, "_remove_user_item")
426 |
427 |
428 | func _on_AddTag_button_up():
429 | _add_setting_item(Settings_Tag, "_remove_tag_item")
430 |
431 |
432 | func _on_AddFolder_button_up():
433 | _add_setting_item(Settings_Folder, "_remove_folder_item")
434 |
435 |
436 | func _on_UserButton_button_up():
437 | if $UserSettingsWindow.visible:
438 | $UserSettingsWindow.hide()
439 | else:
440 | $UserSettingsWindow.show()
441 |
442 |
443 | func _on_ProjectButton_button_up():
444 | if $ProjectSettingsWindow.visible:
445 | $ProjectSettingsWindow.hide()
446 | else:
447 | $ProjectSettingsWindow.show()
448 |
449 |
450 | func _on_ProjectSettingsCloseButton_button_up():
451 | _on_ProjectButton_button_up()
452 |
453 |
454 | func _on_UserSettingsCloseButton_button_up():
455 | _on_UserButton_button_up()
456 |
457 | func _on_TaskViewCloseButton_button_up():
458 | $TaskView.hide()
459 |
460 |
461 | func _on_UpdateButton_button_up():
462 | _update_tasks()
463 |
464 |
465 | func _on_FilterButton_toggled(button_pressed):
466 | filter = button_pressed
467 | _update_gui()
468 |
469 |
470 | func _on_HelpButton_button_up():
471 | OS.shell_open("https://github.com/NimbleBeasts/NbGodotProjectManagement/wiki")
472 |
--------------------------------------------------------------------------------
/addons/NbPM/ProjectScreen.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=6 format=2]
2 |
3 | [ext_resource path="res://addons/NbPM/ProjectScreen.gd" type="Script" id=1]
4 | [ext_resource path="res://addons/NbPM/icons/save-solid.svg" type="Texture" id=2]
5 | [ext_resource path="res://addons/NbPM/icons/plus-square-regular.svg" type="Texture" id=3]
6 | [ext_resource path="res://addons/NbPM/icons/times-solid.svg" type="Texture" id=4]
7 | [ext_resource path="res://addons/NbPM/icons/sync-alt-solid.svg" type="Texture" id=5]
8 |
9 | [node name="PM" type="VBoxContainer"]
10 | anchor_right = 1.0
11 | anchor_bottom = 1.0
12 | rect_min_size = Vector2( 200, 200 )
13 | size_flags_horizontal = 3
14 | size_flags_vertical = 3
15 | custom_constants/separation = 4
16 | script = ExtResource( 1 )
17 | __meta__ = {
18 | "_edit_use_anchors_": false
19 | }
20 |
21 | [node name="Toolbar" type="HBoxContainer" parent="."]
22 | margin_right = 1024.0
23 | margin_bottom = 40.0
24 | rect_min_size = Vector2( 0, 24 )
25 | size_flags_horizontal = 3
26 |
27 | [node name="UpdateLabel" type="Label" parent="Toolbar"]
28 | margin_top = 8.0
29 | margin_right = 85.0
30 | margin_bottom = 32.0
31 | rect_min_size = Vector2( 64, 24 )
32 | text = "Force Update"
33 | valign = 1
34 |
35 | [node name="UpdateButton" type="Button" parent="Toolbar"]
36 | margin_left = 89.0
37 | margin_right = 113.0
38 | margin_bottom = 40.0
39 | rect_min_size = Vector2( 24, 24 )
40 | hint_tooltip = "Forcefully Update"
41 | icon = ExtResource( 5 )
42 | flat = true
43 | expand_icon = true
44 |
45 | [node name="Spacer2" type="Control" parent="Toolbar"]
46 | margin_left = 117.0
47 | margin_right = 133.0
48 | margin_bottom = 40.0
49 | rect_min_size = Vector2( 16, 24 )
50 |
51 | [node name="TasksLabel" type="Label" parent="Toolbar"]
52 | margin_left = 137.0
53 | margin_top = 8.0
54 | margin_right = 173.0
55 | margin_bottom = 32.0
56 | rect_min_size = Vector2( 36, 24 )
57 | text = "Filter"
58 | valign = 1
59 |
60 | [node name="FilterButton" type="CheckButton" parent="Toolbar"]
61 | margin_left = 177.0
62 | margin_right = 253.0
63 | margin_bottom = 40.0
64 | hint_tooltip = "Show only tasks for which you are responsible"
65 | __meta__ = {
66 | "_edit_use_anchors_": false
67 | }
68 |
69 | [node name="Spacer" type="Control" parent="Toolbar"]
70 | margin_left = 257.0
71 | margin_right = 807.0
72 | margin_bottom = 40.0
73 | rect_min_size = Vector2( 0, 24 )
74 | size_flags_horizontal = 3
75 |
76 | [node name="SettingsLabel" type="Label" parent="Toolbar"]
77 | margin_left = 811.0
78 | margin_top = 8.0
79 | margin_right = 875.0
80 | margin_bottom = 32.0
81 | rect_min_size = Vector2( 64, 24 )
82 | text = "Settings"
83 | valign = 1
84 |
85 | [node name="UserButton" type="Button" parent="Toolbar"]
86 | margin_left = 879.0
87 | margin_right = 921.0
88 | margin_bottom = 40.0
89 | hint_tooltip = "User settings"
90 | text = "User"
91 |
92 | [node name="ProjectButton" type="Button" parent="Toolbar"]
93 | margin_left = 925.0
94 | margin_right = 982.0
95 | margin_bottom = 40.0
96 | hint_tooltip = "Project settings"
97 | text = "Project"
98 |
99 | [node name="Spacer3" type="Control" parent="Toolbar"]
100 | margin_left = 986.0
101 | margin_right = 1002.0
102 | margin_bottom = 40.0
103 | rect_min_size = Vector2( 16, 24 )
104 |
105 | [node name="HelpButton" type="Button" parent="Toolbar"]
106 | margin_left = 1006.0
107 | margin_right = 1024.0
108 | margin_bottom = 40.0
109 | hint_tooltip = "Project settings"
110 | text = "?"
111 |
112 | [node name="ProjectSettingsWindow" type="Control" parent="."]
113 | visible = false
114 | margin_top = 44.0
115 | margin_right = 1024.0
116 | margin_bottom = 248.0
117 | rect_min_size = Vector2( 0, 204 )
118 | __meta__ = {
119 | "_edit_use_anchors_": false
120 | }
121 |
122 | [node name="Panel" type="Panel" parent="ProjectSettingsWindow"]
123 | anchor_right = 1.0
124 | anchor_bottom = 1.0
125 |
126 | [node name="Toolbar" type="ColorRect" parent="ProjectSettingsWindow"]
127 | anchor_right = 1.0
128 | margin_left = 2.0
129 | margin_top = 2.0
130 | margin_right = -2.0
131 | margin_bottom = 24.0
132 | rect_min_size = Vector2( 0, 24 )
133 | color = Color( 1, 1, 1, 0.109804 )
134 | __meta__ = {
135 | "_edit_use_anchors_": false
136 | }
137 |
138 | [node name="h" type="HBoxContainer" parent="ProjectSettingsWindow/Toolbar"]
139 | anchor_right = 1.0
140 | margin_bottom = 24.0
141 | rect_min_size = Vector2( 0, 24 )
142 | size_flags_horizontal = 3
143 | __meta__ = {
144 | "_edit_use_anchors_": false
145 | }
146 |
147 | [node name="Label" type="Label" parent="ProjectSettingsWindow/Toolbar/h"]
148 | margin_right = 104.0
149 | margin_bottom = 24.0
150 | rect_min_size = Vector2( 64, 24 )
151 | text = "Project Settings "
152 | valign = 1
153 |
154 | [node name="Spacer" type="Control" parent="ProjectSettingsWindow/Toolbar/h"]
155 | margin_left = 108.0
156 | margin_right = 964.0
157 | margin_bottom = 24.0
158 | rect_min_size = Vector2( 40, 24 )
159 | size_flags_horizontal = 3
160 |
161 | [node name="SaveButton" type="Button" parent="ProjectSettingsWindow/Toolbar/h"]
162 | margin_left = 968.0
163 | margin_right = 992.0
164 | margin_bottom = 24.0
165 | rect_min_size = Vector2( 24, 24 )
166 | hint_tooltip = "Save project settings"
167 | icon = ExtResource( 2 )
168 | flat = true
169 | expand_icon = true
170 | __meta__ = {
171 | "_edit_use_anchors_": false
172 | }
173 |
174 | [node name="CloseButton" type="Button" parent="ProjectSettingsWindow/Toolbar/h"]
175 | margin_left = 996.0
176 | margin_right = 1020.0
177 | margin_bottom = 24.0
178 | rect_min_size = Vector2( 24, 24 )
179 | hint_tooltip = "Close settings, discard changes."
180 | icon = ExtResource( 4 )
181 | flat = true
182 | expand_icon = true
183 | __meta__ = {
184 | "_edit_use_anchors_": false
185 | }
186 |
187 | [node name="Category" type="Control" parent="ProjectSettingsWindow"]
188 | margin_left = 8.0
189 | margin_top = 28.0
190 | margin_right = 152.0
191 | margin_bottom = 196.0
192 | __meta__ = {
193 | "_edit_use_anchors_": false
194 | }
195 |
196 | [node name="scroll" type="ScrollContainer" parent="ProjectSettingsWindow/Category"]
197 | anchor_right = 1.0
198 | anchor_bottom = 1.0
199 | margin_top = 24.0
200 | __meta__ = {
201 | "_edit_use_anchors_": false
202 | }
203 |
204 | [node name="v" type="VBoxContainer" parent="ProjectSettingsWindow/Category/scroll"]
205 | custom_constants/separation = 0
206 |
207 | [node name="Label" type="Label" parent="ProjectSettingsWindow/Category"]
208 | margin_left = 6.0
209 | margin_right = 88.0
210 | margin_bottom = 24.0
211 | text = "Categories"
212 | valign = 1
213 |
214 | [node name="AddCategory" type="Button" parent="ProjectSettingsWindow/Category"]
215 | anchor_left = 1.0
216 | anchor_right = 1.0
217 | margin_left = -32.0
218 | margin_right = -8.0
219 | margin_bottom = 24.0
220 | hint_tooltip = "Add a new category"
221 | icon = ExtResource( 3 )
222 | flat = true
223 | expand_icon = true
224 | __meta__ = {
225 | "_edit_use_anchors_": false
226 | }
227 |
228 | [node name="Users" type="Control" parent="ProjectSettingsWindow"]
229 | margin_left = 160.0
230 | margin_top = 28.0
231 | margin_right = 304.0
232 | margin_bottom = 196.0
233 | __meta__ = {
234 | "_edit_use_anchors_": false
235 | }
236 |
237 | [node name="scroll" type="ScrollContainer" parent="ProjectSettingsWindow/Users"]
238 | anchor_right = 1.0
239 | anchor_bottom = 1.0
240 | margin_top = 24.0
241 | __meta__ = {
242 | "_edit_use_anchors_": false
243 | }
244 |
245 | [node name="v" type="VBoxContainer" parent="ProjectSettingsWindow/Users/scroll"]
246 | custom_constants/separation = 0
247 |
248 | [node name="Label" type="Label" parent="ProjectSettingsWindow/Users"]
249 | margin_left = 6.0
250 | margin_right = 88.0
251 | margin_bottom = 24.0
252 | text = "Users"
253 | valign = 1
254 |
255 | [node name="AddUser" type="Button" parent="ProjectSettingsWindow/Users"]
256 | anchor_left = 1.0
257 | anchor_right = 1.0
258 | margin_left = -32.0
259 | margin_right = -8.0
260 | margin_bottom = 24.0
261 | hint_tooltip = "Add a new user"
262 | icon = ExtResource( 3 )
263 | flat = true
264 | expand_icon = true
265 |
266 | [node name="Tags" type="Control" parent="ProjectSettingsWindow"]
267 | margin_left = 312.0
268 | margin_top = 28.0
269 | margin_right = 456.0
270 | margin_bottom = 196.0
271 | __meta__ = {
272 | "_edit_use_anchors_": false
273 | }
274 |
275 | [node name="scroll" type="ScrollContainer" parent="ProjectSettingsWindow/Tags"]
276 | anchor_right = 1.0
277 | anchor_bottom = 1.0
278 | margin_top = 24.0
279 | __meta__ = {
280 | "_edit_use_anchors_": false
281 | }
282 |
283 | [node name="v" type="VBoxContainer" parent="ProjectSettingsWindow/Tags/scroll"]
284 | custom_constants/separation = 0
285 |
286 | [node name="Label" type="Label" parent="ProjectSettingsWindow/Tags"]
287 | margin_left = 6.0
288 | margin_right = 88.0
289 | margin_bottom = 24.0
290 | text = "Tags"
291 | valign = 1
292 |
293 | [node name="AddTag" type="Button" parent="ProjectSettingsWindow/Tags"]
294 | anchor_left = 1.0
295 | anchor_right = 1.0
296 | margin_left = -32.0
297 | margin_right = -8.0
298 | margin_bottom = 24.0
299 | hint_tooltip = "Add a new tag"
300 | icon = ExtResource( 3 )
301 | flat = true
302 | expand_icon = true
303 |
304 | [node name="ExcludeFolders" type="Control" parent="ProjectSettingsWindow"]
305 | margin_left = 464.0
306 | margin_top = 28.0
307 | margin_right = 608.0
308 | margin_bottom = 196.0
309 | __meta__ = {
310 | "_edit_use_anchors_": false
311 | }
312 |
313 | [node name="scroll" type="ScrollContainer" parent="ProjectSettingsWindow/ExcludeFolders"]
314 | anchor_right = 1.0
315 | anchor_bottom = 1.0
316 | margin_top = 24.0
317 | __meta__ = {
318 | "_edit_use_anchors_": false
319 | }
320 |
321 | [node name="v" type="VBoxContainer" parent="ProjectSettingsWindow/ExcludeFolders/scroll"]
322 | custom_constants/separation = 0
323 |
324 | [node name="Label" type="Label" parent="ProjectSettingsWindow/ExcludeFolders"]
325 | margin_left = 6.0
326 | margin_right = 88.0
327 | margin_bottom = 24.0
328 | text = "Exclude Folders"
329 | valign = 1
330 |
331 | [node name="AddFolder" type="Button" parent="ProjectSettingsWindow/ExcludeFolders"]
332 | anchor_left = 1.0
333 | anchor_right = 1.0
334 | margin_left = -32.0
335 | margin_right = -8.0
336 | margin_bottom = 24.0
337 | hint_tooltip = "Add a new folder"
338 | icon = ExtResource( 3 )
339 | flat = true
340 | expand_icon = true
341 |
342 | [node name="UserSettingsWindow" type="Control" parent="."]
343 | visible = false
344 | margin_top = 44.0
345 | margin_right = 1024.0
346 | margin_bottom = 124.0
347 | rect_min_size = Vector2( 0, 80 )
348 | __meta__ = {
349 | "_edit_use_anchors_": false
350 | }
351 |
352 | [node name="Panel" type="Panel" parent="UserSettingsWindow"]
353 | anchor_right = 1.0
354 | anchor_bottom = 1.0
355 |
356 | [node name="Toolbar" type="ColorRect" parent="UserSettingsWindow"]
357 | anchor_right = 1.0
358 | margin_left = 3.0
359 | margin_top = 3.0
360 | margin_right = -3.0
361 | margin_bottom = 24.0
362 | rect_min_size = Vector2( 0, 24 )
363 | color = Color( 1, 1, 1, 0.109804 )
364 | __meta__ = {
365 | "_edit_use_anchors_": false
366 | }
367 |
368 | [node name="h" type="HBoxContainer" parent="UserSettingsWindow/Toolbar"]
369 | anchor_right = 1.0
370 | margin_bottom = 24.0
371 | rect_min_size = Vector2( 0, 24 )
372 | size_flags_horizontal = 3
373 | __meta__ = {
374 | "_edit_use_anchors_": false
375 | }
376 |
377 | [node name="Label" type="Label" parent="UserSettingsWindow/Toolbar/h"]
378 | margin_right = 93.0
379 | margin_bottom = 24.0
380 | rect_min_size = Vector2( 64, 24 )
381 | text = "User Selection"
382 | valign = 1
383 |
384 | [node name="Spacer" type="Control" parent="UserSettingsWindow/Toolbar/h"]
385 | margin_left = 97.0
386 | margin_right = 962.0
387 | margin_bottom = 24.0
388 | rect_min_size = Vector2( 40, 24 )
389 | size_flags_horizontal = 3
390 |
391 | [node name="SaveButton" type="Button" parent="UserSettingsWindow/Toolbar/h"]
392 | margin_left = 966.0
393 | margin_right = 990.0
394 | margin_bottom = 24.0
395 | rect_min_size = Vector2( 24, 24 )
396 | hint_tooltip = "Save user settings"
397 | icon = ExtResource( 2 )
398 | flat = true
399 | expand_icon = true
400 | __meta__ = {
401 | "_edit_use_anchors_": false
402 | }
403 |
404 | [node name="CloseButton" type="Button" parent="UserSettingsWindow/Toolbar/h"]
405 | margin_left = 994.0
406 | margin_right = 1018.0
407 | margin_bottom = 24.0
408 | rect_min_size = Vector2( 24, 24 )
409 | hint_tooltip = "Discard changes"
410 | icon = ExtResource( 4 )
411 | flat = true
412 | expand_icon = true
413 | __meta__ = {
414 | "_edit_use_anchors_": false
415 | }
416 |
417 | [node name="UserSelect" type="OptionButton" parent="UserSettingsWindow"]
418 | margin_left = 160.0
419 | margin_top = 36.0
420 | margin_right = 280.0
421 | margin_bottom = 60.0
422 | __meta__ = {
423 | "_edit_use_anchors_": false
424 | }
425 |
426 | [node name="Label" type="Label" parent="UserSettingsWindow/UserSelect"]
427 | margin_left = -152.0
428 | margin_right = -7.0
429 | margin_bottom = 24.0
430 | text = "Select current user"
431 | valign = 1
432 |
433 | [node name="TaskView" type="Control" parent="."]
434 | visible = false
435 | margin_top = 44.0
436 | margin_right = 1024.0
437 | margin_bottom = 284.0
438 | rect_min_size = Vector2( 0, 240 )
439 | __meta__ = {
440 | "_edit_use_anchors_": false
441 | }
442 |
443 | [node name="Panel" type="Panel" parent="TaskView"]
444 | anchor_right = 1.0
445 | anchor_bottom = 1.0
446 | size_flags_horizontal = 3
447 | size_flags_vertical = 3
448 | __meta__ = {
449 | "_edit_use_anchors_": false
450 | }
451 |
452 | [node name="Toolbar" type="ColorRect" parent="TaskView"]
453 | anchor_right = 1.0
454 | margin_left = 4.0
455 | margin_top = 4.0
456 | margin_right = -4.0
457 | margin_bottom = 24.0
458 | rect_min_size = Vector2( 0, 24 )
459 | color = Color( 1, 1, 1, 0.109804 )
460 | __meta__ = {
461 | "_edit_use_anchors_": false
462 | }
463 |
464 | [node name="h" type="HBoxContainer" parent="TaskView/Toolbar"]
465 | anchor_right = 1.0
466 | margin_bottom = 24.0
467 | rect_min_size = Vector2( 0, 24 )
468 | size_flags_horizontal = 3
469 | __meta__ = {
470 | "_edit_use_anchors_": false
471 | }
472 |
473 | [node name="Label" type="Label" parent="TaskView/Toolbar/h"]
474 | margin_right = 64.0
475 | margin_bottom = 24.0
476 | rect_min_size = Vector2( 64, 24 )
477 | text = "Task"
478 | valign = 1
479 |
480 | [node name="Spacer" type="Control" parent="TaskView/Toolbar/h"]
481 | margin_left = 68.0
482 | margin_right = 960.0
483 | margin_bottom = 24.0
484 | rect_min_size = Vector2( 40, 24 )
485 | size_flags_horizontal = 3
486 |
487 | [node name="SaveButton" type="Button" parent="TaskView/Toolbar/h"]
488 | margin_left = 964.0
489 | margin_right = 988.0
490 | margin_bottom = 24.0
491 | rect_min_size = Vector2( 24, 24 )
492 | hint_tooltip = "Save task"
493 | icon = ExtResource( 2 )
494 | flat = true
495 | expand_icon = true
496 | __meta__ = {
497 | "_edit_use_anchors_": false
498 | }
499 |
500 | [node name="CloseButton" type="Button" parent="TaskView/Toolbar/h"]
501 | margin_left = 992.0
502 | margin_right = 1016.0
503 | margin_bottom = 24.0
504 | rect_min_size = Vector2( 24, 24 )
505 | hint_tooltip = "Close / discard changes"
506 | icon = ExtResource( 4 )
507 | flat = true
508 | expand_icon = true
509 | __meta__ = {
510 | "_edit_use_anchors_": false
511 | }
512 |
513 | [node name="Input" type="HBoxContainer" parent="TaskView"]
514 | anchor_right = 1.0
515 | margin_left = 8.0
516 | margin_top = 36.0
517 | margin_right = -8.0
518 | margin_bottom = 60.0
519 | rect_min_size = Vector2( 0, 24 )
520 | __meta__ = {
521 | "_edit_use_anchors_": false
522 | }
523 |
524 | [node name="TitleLabel" type="Label" parent="TaskView/Input"]
525 | margin_right = 28.0
526 | margin_bottom = 24.0
527 | rect_min_size = Vector2( 0, 24 )
528 | text = "Title"
529 | valign = 1
530 | __meta__ = {
531 | "_edit_use_anchors_": false
532 | }
533 |
534 | [node name="Title" type="LineEdit" parent="TaskView/Input"]
535 | margin_left = 32.0
536 | margin_right = 288.0
537 | margin_bottom = 24.0
538 | rect_min_size = Vector2( 256, 24 )
539 | hint_tooltip = "Task title"
540 | text = "Task Title"
541 | __meta__ = {
542 | "_edit_use_anchors_": false
543 | }
544 |
545 | [node name="Spacer2" type="Control" parent="TaskView/Input"]
546 | margin_left = 292.0
547 | margin_right = 308.0
548 | margin_bottom = 24.0
549 | rect_min_size = Vector2( 16, 24 )
550 |
551 | [node name="TitleStage" type="Label" parent="TaskView/Input"]
552 | margin_left = 312.0
553 | margin_right = 367.0
554 | margin_bottom = 24.0
555 | rect_min_size = Vector2( 0, 24 )
556 | text = "Category"
557 | valign = 1
558 | __meta__ = {
559 | "_edit_use_anchors_": false
560 | }
561 |
562 | [node name="Stage" type="OptionButton" parent="TaskView/Input"]
563 | margin_left = 371.0
564 | margin_right = 467.0
565 | margin_bottom = 24.0
566 | rect_min_size = Vector2( 96, 24 )
567 | hint_tooltip = "Task category"
568 | text = "Backlog"
569 | items = [ "Backlog", null, false, 0, null, "To do", null, false, 1, null, "In progress", null, false, 2, null, "Done", null, false, 3, null ]
570 | selected = 0
571 | __meta__ = {
572 | "_edit_use_anchors_": false
573 | }
574 |
575 | [node name="Spacer3" type="Control" parent="TaskView/Input"]
576 | margin_left = 471.0
577 | margin_right = 487.0
578 | margin_bottom = 24.0
579 | rect_min_size = Vector2( 16, 24 )
580 |
581 | [node name="TitleAssigned" type="Label" parent="TaskView/Input"]
582 | margin_left = 491.0
583 | margin_right = 549.0
584 | margin_bottom = 24.0
585 | rect_min_size = Vector2( 0, 24 )
586 | text = "Assigned"
587 | valign = 1
588 | __meta__ = {
589 | "_edit_use_anchors_": false
590 | }
591 |
592 | [node name="Assigned" type="OptionButton" parent="TaskView/Input"]
593 | margin_left = 553.0
594 | margin_right = 649.0
595 | margin_bottom = 24.0
596 | rect_min_size = Vector2( 96, 24 )
597 | hint_tooltip = "Task responsible"
598 | __meta__ = {
599 | "_edit_use_anchors_": false
600 | }
601 |
602 | [node name="Spacer" type="Control" parent="TaskView/Input"]
603 | margin_left = 653.0
604 | margin_right = 932.0
605 | margin_bottom = 24.0
606 | rect_min_size = Vector2( 0, 24 )
607 | size_flags_horizontal = 3
608 |
609 | [node name="TimestampLabel" type="Label" parent="TaskView/Input"]
610 | margin_left = 936.0
611 | margin_right = 1008.0
612 | margin_bottom = 24.0
613 | rect_min_size = Vector2( 0, 24 )
614 | text = "Timestamp"
615 | valign = 1
616 | __meta__ = {
617 | "_edit_use_anchors_": false
618 | }
619 |
620 | [node name="Description" type="TextEdit" parent="TaskView"]
621 | anchor_right = 1.0
622 | margin_left = 8.0
623 | margin_top = 68.0
624 | margin_right = -8.0
625 | margin_bottom = 236.0
626 | __meta__ = {
627 | "_edit_use_anchors_": false
628 | }
629 |
630 | [node name="Scroll" type="ScrollContainer" parent="."]
631 | margin_top = 44.0
632 | margin_right = 1024.0
633 | margin_bottom = 600.0
634 | size_flags_horizontal = 3
635 | size_flags_vertical = 3
636 | scroll_vertical_enabled = false
637 |
638 | [node name="h" type="HBoxContainer" parent="Scroll"]
639 | margin_right = 1024.0
640 | margin_bottom = 556.0
641 | size_flags_horizontal = 3
642 | size_flags_vertical = 3
643 | custom_constants/separation = 24
644 | __meta__ = {
645 | "_edit_use_anchors_": false
646 | }
647 |
648 | [connection signal="button_up" from="Toolbar/UpdateButton" to="." method="_on_UpdateButton_button_up"]
649 | [connection signal="toggled" from="Toolbar/FilterButton" to="." method="_on_FilterButton_toggled"]
650 | [connection signal="button_up" from="Toolbar/UserButton" to="." method="_on_UserButton_button_up"]
651 | [connection signal="button_up" from="Toolbar/ProjectButton" to="." method="_on_ProjectButton_button_up"]
652 | [connection signal="button_up" from="Toolbar/HelpButton" to="." method="_on_HelpButton_button_up"]
653 | [connection signal="button_up" from="ProjectSettingsWindow/Toolbar/h/SaveButton" to="." method="_on_ProjectSettingsSaveButton_button_up"]
654 | [connection signal="button_up" from="ProjectSettingsWindow/Toolbar/h/CloseButton" to="." method="_on_ProjectSettingsCloseButton_button_up"]
655 | [connection signal="button_up" from="ProjectSettingsWindow/Category/AddCategory" to="." method="_on_AddCategory_button_up"]
656 | [connection signal="button_up" from="ProjectSettingsWindow/Users/AddUser" to="." method="_on_AddUser_button_up"]
657 | [connection signal="button_up" from="ProjectSettingsWindow/Tags/AddTag" to="." method="_on_AddTag_button_up"]
658 | [connection signal="button_up" from="ProjectSettingsWindow/ExcludeFolders/AddFolder" to="." method="_on_AddFolder_button_up"]
659 | [connection signal="button_up" from="UserSettingsWindow/Toolbar/h/SaveButton" to="." method="_on_UserSettingsSaveButton_button_up"]
660 | [connection signal="button_up" from="UserSettingsWindow/Toolbar/h/CloseButton" to="." method="_on_UserSettingsCloseButton_button_up"]
661 | [connection signal="button_up" from="TaskView/Toolbar/h/SaveButton" to="." method="_on_TaskViewSaveButton_button_up"]
662 | [connection signal="button_up" from="TaskView/Toolbar/h/CloseButton" to="." method="_on_TaskViewCloseButton_button_up"]
663 |
--------------------------------------------------------------------------------
/addons/NbPM/TodoDock.gd:
--------------------------------------------------------------------------------
1 | tool
2 | extends Control
3 |
4 | const Icon_AddTask = preload("res://addons/NbPM/icons/add_task.png")
5 | const Icon_ViewSrc = preload("res://addons/NbPM/icons/view_src.png")
6 | const Icon_ViewTask = preload("res://addons/NbPM/icons/pm_icon.png")
7 |
8 | var ref = null
9 |
10 |
11 | #TODO: clean up
12 | var exclude_dir_list = ["addons"]
13 | var tags = []
14 | var regex = RegEx.new()
15 |
16 | var filter = []
17 |
18 | var _file_list = []
19 |
20 | ## Updates everytime the config was changed
21 | func update_project_config():
22 | var config = ref.config_project
23 |
24 | # Parse exclude list
25 | exclude_dir_list = []
26 | for folder in config.exclude_folders:
27 | exclude_dir_list.append(folder)
28 |
29 | var string = ""
30 | # Parse tags
31 | tags = config.tags.duplicate()
32 | for tag in tags:
33 | string += tag + "|"
34 | string = string.trim_suffix("|")
35 |
36 | # Search regex
37 | var regex_string = "(?:#|//)\\s*(%s)\\s*(\\:)?\\s*([^\\n]+)" % string
38 | regex.compile(regex_string)
39 | #print("scanning with: " + regex_string)
40 | assert(regex.is_valid())
41 |
42 | # Setup Todo Dock
43 | setup_dropdown()
44 |
45 | # Update
46 | _update_todos()
47 |
48 |
49 | func setup(loader_ref):
50 | assert(loader_ref)
51 | ref = loader_ref
52 |
53 | # Parse the project settings
54 | update_project_config()
55 |
56 | # Signals
57 | ref.get_editor_interface().get_resource_filesystem().connect("filesystem_changed", self, "_update_todos")
58 |
59 | # Display results initialy
60 | _update_gui()
61 |
62 |
63 | func setup_dropdown():
64 | $ToolbarBox/DropdownMenu.icon = ref.get_editor_interface().get_base_control().get_icon("GuiDropdown", "EditorIcons")
65 | var popup_menu = $ToolbarBox/DropdownMenu.get_popup()
66 | popup_menu.clear()
67 | var id = 0
68 | for tag in tags:
69 | popup_menu.add_check_item("Show " + str(tag), id)
70 | popup_menu.set_item_checked(id, not tag in filter)
71 | id += 1
72 |
73 | if not popup_menu.is_connected("id_pressed", self, "_popup_menu_id_pressed"):
74 | popup_menu.connect("id_pressed", self, "_popup_menu_id_pressed")
75 |
76 | func _popup_menu_id_pressed(id):
77 | var popup_menu = $ToolbarBox/DropdownMenu.get_popup()
78 |
79 | if popup_menu.is_item_checked(id):
80 | popup_menu.set_item_checked(id, false)
81 | filter.append(tags[id])
82 | else:
83 | popup_menu.set_item_checked(id, true)
84 | filter.erase(tags[id])
85 |
86 | print(filter)
87 | _update_gui()
88 |
89 |
90 |
91 | func _update_todos(force = false):
92 | # Detect changes
93 | if _scan_directory() != 0 or force:
94 | # Remove old db relicts
95 | _clean_deleted_files()
96 | # Save the new db
97 | ref.save_user_config()
98 | # Re-built todo tree
99 | _update_gui()
100 |
101 |
102 | ## Delete non-existing files from db
103 | func _clean_deleted_files():
104 | var ids = []
105 |
106 | # Check if file in db still exists in scanned list
107 | for i in range(ref.config_user.todo_database.size()):
108 | if not ref.config_user.todo_database[i].file_path in _file_list:
109 | #print("delete:" + str(_todo_database[i].file_path))
110 | ids.append(i)
111 |
112 | # Invert array to delete backwards
113 | ids.invert()
114 | for id in ids:
115 | ref.config_user.todo_database.remove(id)
116 |
117 | _file_list = []
118 |
119 | func _update_gui():
120 | var tree = $Tree
121 |
122 | tree.clear()
123 | var root = tree.create_item()
124 | tree.set_hide_root(true)
125 | tree.set_columns(3)
126 | tree.set_column_expand(0, true)
127 | tree.set_column_expand(1, false)
128 | tree.set_column_expand(2, false)
129 | tree.set_column_min_width(0, 100)
130 | tree.set_column_min_width(1, 24)
131 | tree.set_column_min_width(2, 24)
132 |
133 | var icon_ref = ref.get_editor_interface().get_base_control()
134 | for file in ref.config_user.todo_database:
135 | #{"file_path": file_path, "hash": file_hash, "todos": []
136 | var child_file = tree.create_item(root)
137 | child_file.set_icon(0, icon_ref.get_icon("Script", "EditorIcons"))
138 | child_file.set_text(0, file.file_path.substr(6))
139 | child_file.set_metadata(0, {"type": "SHOW_SOURCE", "line": 1, "path_file": file.file_path})
140 |
141 | for todo in file.todos:
142 | if not todo.type in filter:
143 | #{"type": type, "line": line_count, "description": description}
144 | var child_todo = tree.create_item(child_file)
145 | child_todo.set_text(0, str(todo.line) + ": " + str(todo.description))
146 | child_todo.set_metadata(0, {"type": "SHOW_SOURCE", "line": todo.line, "path_file": file.file_path})
147 | #child_todo.add_button(1, icon_ref.get_icon("PathFollow", "EditorIcons"))
148 | child_todo.add_button(1, Icon_ViewSrc, -1, false, "Jump to source")
149 | child_todo.set_metadata(1, {"type": "SHOW_SOURCE", "line": todo.line, "path_file": file.file_path})
150 |
151 |
152 | # TODO REMOVE
153 |
154 | var task = _has_task(file.file_path, todo.description)
155 | if task == "":
156 | #child_todo.add_button(2, icon_ref.get_icon("Add", "EditorIcons"))
157 | child_todo.add_button(2, Icon_AddTask, -1, false, "Add new task")
158 | child_todo.set_metadata(2, {"type": "CREATE_TASK", "todo": todo, "path_file": file.file_path})
159 | else:
160 | #child_todo.add_button(2, icon_ref.get_icon("TabContainer", "EditorIcons"))
161 | child_todo.add_button(2, Icon_ViewTask, -1, false, "Jump to task")
162 | child_todo.set_metadata(2, {"type": "VIEW_TASK", "task": task})
163 |
164 | # Returns task id if linked, else -1
165 | func _has_task(path_file, description):
166 | for links in ref.config_project.linkage:
167 | if path_file == links.file and description == links.description:
168 | return links.task
169 | return ""
170 |
171 | func _scan_directory(path = "res://"):
172 | var changes = 0
173 | var dir = Directory.new()
174 |
175 | if dir.open(path) == OK:
176 | dir.list_dir_begin(true, true)
177 | var file_name = dir.get_next()
178 |
179 | # Scan directories
180 | while file_name != "":
181 | # Build path tree
182 | var file_path = path
183 | if path == "res://":
184 | file_path += file_name
185 | else:
186 | file_path += "/" + file_name
187 |
188 | if dir.current_is_dir():
189 | # Recursive call to scan directory
190 | if not file_name in exclude_dir_list:
191 | # Scan directory
192 | changes += _scan_directory(file_path)
193 | else:
194 | if file_name.get_extension() == "gd":
195 | _file_list.append(file_path)
196 | # Scan file
197 | changes += _scan_file(path, file_name)
198 | #print("-----------------------------------")
199 |
200 | file_name = dir.get_next()
201 |
202 | dir.list_dir_end()
203 |
204 | return changes
205 |
206 |
207 | func _scan_file(path, file_name):
208 | var changes = 0
209 | var file = File.new()
210 |
211 | # Build file path
212 | var file_path = path
213 | if path == "res://":
214 | file_path += file_name
215 | else:
216 | file_path += "/" + file_name
217 |
218 | # Get file hash
219 | var file_hash = file.get_sha256(file_path)
220 | # Look up file in database, check for modification
221 | var db_index = _db_find_index_by_file_path(file_path)
222 |
223 | #print("file: " + file_name)
224 |
225 | # Check if we have an existing library
226 | if db_index != -1:
227 | if ref.config_user.todo_database[db_index].hash == file_hash:
228 | # File has not been changed since last parsing
229 | #print("no changes")
230 | return 0
231 |
232 | # Clear old entries
233 | ref.config_user.todo_database[db_index].todos = []
234 |
235 |
236 | # Load source and parse the source code
237 | var source = load(file_path).source_code
238 | var regex_findings = regex.search_all(source)
239 |
240 | # Create db file entry if needed
241 | if db_index == -1:
242 | ref.config_user.todo_database.append({"file_path": file_path, "hash": file_hash, "todos": []})
243 | db_index = ref.config_user.todo_database.size() - 1
244 |
245 | # Parse regex findings
246 | for finding in regex_findings:
247 | # TYPE: text
248 | # 0 = complete line, 1 = type, 3 = description
249 | var type = finding.get_string(1)
250 | var description = finding.get_string(3)
251 |
252 | var line_count = 1
253 | for line in source.split("\n"):
254 | if line == finding.get_string(0): break
255 | line_count += 1
256 |
257 | ref.config_user.todo_database[db_index].todos.append({"type": type, "line": line_count, "description": description})
258 | changes += 1
259 |
260 | #print("todos found: " + str(changes))
261 | # print(file_path)
262 | # print(file_hash)
263 | # print(todos)
264 | # print("--------------------------------")
265 | # print(changes)
266 | return changes
267 |
268 | func _db_find_index_by_file_path(path):
269 | var index = 0
270 | for entry in ref.config_user.todo_database:
271 | if path == entry.file_path:
272 | return index
273 | index += 1
274 |
275 | return -1
276 |
277 |
278 | func _on_Tree_item_activated():
279 | _process_click($Tree.get_selected().get_metadata(0))
280 |
281 |
282 | func _on_Tree_button_pressed(item, column, id):
283 | _process_click(item.get_metadata(column))
284 |
285 |
286 | func _process_click(metadata):
287 | if metadata.type == "SHOW_SOURCE":
288 | # Jump to source
289 | #{"type": "SHOW_SOURCE", "line": todo.line, "path_file": file.file_path}
290 | var source = load(metadata.path_file)
291 | var editor = ref.get_editor_interface().get_script_editor()
292 | if editor.has_method("_goto_script_line"):
293 | editor._goto_script_line(source, metadata.line - 1)
294 | else:
295 | printerr("Method '_goto_script_line' not found on script_editor_plugin.")
296 | else: #VIEW_TASK or CREATE_TASK
297 | ref.jump_to_main_screen(metadata)
298 |
299 |
300 | func _on_UpdateButton_button_up():
301 | _update_todos(true)
302 |
--------------------------------------------------------------------------------
/addons/NbPM/TodoDock.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=2]
2 |
3 | [ext_resource path="res://addons/NbPM/TodoDock.gd" type="Script" id=1]
4 | [ext_resource path="res://addons/NbPM/icons/sync-alt-solid.svg" type="Texture" id=2]
5 |
6 | [node name="NbTodo" type="Control"]
7 | anchor_right = 1.0
8 | anchor_bottom = 1.0
9 | script = ExtResource( 1 )
10 | __meta__ = {
11 | "_edit_use_anchors_": false
12 | }
13 |
14 | [node name="ToolbarBox" type="HBoxContainer" parent="."]
15 | anchor_right = 1.0
16 | margin_bottom = 24.0
17 | __meta__ = {
18 | "_edit_use_anchors_": false
19 | }
20 |
21 | [node name="UpdateButton" type="Button" parent="ToolbarBox"]
22 | margin_right = 24.0
23 | margin_bottom = 24.0
24 | rect_min_size = Vector2( 24, 24 )
25 | hint_tooltip = "Forcefully Update"
26 | icon = ExtResource( 2 )
27 | flat = true
28 | expand_icon = true
29 |
30 | [node name="Spacer" type="Control" parent="ToolbarBox"]
31 | margin_left = 28.0
32 | margin_right = 1008.0
33 | margin_bottom = 24.0
34 | rect_min_size = Vector2( 0, 24 )
35 | size_flags_horizontal = 3
36 |
37 | [node name="DropdownMenu" type="MenuButton" parent="ToolbarBox"]
38 | margin_left = 1012.0
39 | margin_right = 1024.0
40 | margin_bottom = 24.0
41 |
42 | [node name="Tree" type="Tree" parent="."]
43 | anchor_right = 1.0
44 | anchor_bottom = 1.0
45 | margin_top = 26.0
46 | __meta__ = {
47 | "_edit_use_anchors_": false
48 | }
49 |
50 | [connection signal="button_up" from="ToolbarBox/UpdateButton" to="." method="_on_UpdateButton_button_up"]
51 | [connection signal="button_pressed" from="Tree" to="." method="_on_Tree_button_pressed"]
52 | [connection signal="item_activated" from="Tree" to="." method="_on_Tree_item_activated"]
53 |
--------------------------------------------------------------------------------
/addons/NbPM/card/Card.gd:
--------------------------------------------------------------------------------
1 | tool
2 | extends Control
3 |
4 | const Scene_Preview = preload("res://addons/NbPM/card/DragPreview.tscn")
5 |
6 | var pm_ref = null
7 |
8 | var _context = {}
9 |
10 | func setup(ref, context, assigned_string, color):
11 | pm_ref = ref
12 | _context = context
13 |
14 | $Bg/v/toolbar/Title.set_text(str(context.title))
15 | $Bg/v/Description.bbcode_text = str(context.description)
16 | $Bg.color = color
17 | $Bg/v/Content/Assigned.set_text(str(assigned_string))
18 |
19 | var popup_menu = $Bg/v/toolbar/Menu.get_popup()
20 | popup_menu.clear()
21 | popup_menu.add_item("View", 0)
22 | popup_menu.add_item("Delete", 1)
23 | popup_menu.connect("id_pressed", self, "_on_item_pressed")
24 |
25 |
26 | func get_drag_data(_pos):
27 | var preview = Scene_Preview.instance()
28 | set_drag_preview(preview)
29 |
30 | if pm_ref:
31 | pm_ref.start_card_drag()
32 | return _context.hash
33 |
34 |
35 | func _on_item_pressed(id):
36 | if id == 0:
37 | pm_ref.view_task(_context.hash)
38 | elif id == 1:
39 | pm_ref.delete_task(_context.hash)
40 |
41 |
42 | func _on_View_button_up():
43 | pm_ref.view_task(_context.hash)
44 |
45 |
--------------------------------------------------------------------------------
/addons/NbPM/card/Card.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=8 format=2]
2 |
3 | [ext_resource path="res://addons/NbPM/icons/caret-down-solid.svg" type="Texture" id=1]
4 | [ext_resource path="res://addons/NbPM/card/Card.gd" type="Script" id=2]
5 | [ext_resource path="res://addons/NbPM/icons/pm_icon.png" type="Texture" id=3]
6 | [ext_resource path="res://addons/NbPM/font/font12.tres" type="DynamicFont" id=4]
7 | [ext_resource path="res://addons/NbPM/icons/external-link-alt-solid.svg" type="Texture" id=5]
8 |
9 | [sub_resource type="StyleBoxEmpty" id=1]
10 |
11 | [sub_resource type="StyleBoxEmpty" id=2]
12 |
13 | [node name="Card" type="Control"]
14 | margin_right = 308.0
15 | margin_bottom = 152.0
16 | rect_min_size = Vector2( 0, 160 )
17 | size_flags_horizontal = 3
18 | script = ExtResource( 2 )
19 | __meta__ = {
20 | "_edit_use_anchors_": false
21 | }
22 |
23 | [node name="Bg" type="ColorRect" parent="."]
24 | anchor_right = 1.0
25 | anchor_bottom = 1.0
26 | margin_left = 8.0
27 | margin_top = 8.0
28 | margin_right = -8.0
29 | margin_bottom = -8.0
30 | mouse_filter = 1
31 | color = Color( 0.2, 0.231373, 0.309804, 1 )
32 | __meta__ = {
33 | "_edit_use_anchors_": false
34 | }
35 |
36 | [node name="v" type="VBoxContainer" parent="Bg"]
37 | anchor_right = 1.0
38 | anchor_bottom = 1.0
39 | margin_left = 4.0
40 | margin_top = 4.0
41 | margin_right = -4.0
42 | margin_bottom = -4.0
43 | size_flags_horizontal = 3
44 | size_flags_vertical = 3
45 | __meta__ = {
46 | "_edit_use_anchors_": false
47 | }
48 |
49 | [node name="toolbar" type="HBoxContainer" parent="Bg/v"]
50 | margin_right = 284.0
51 | margin_bottom = 24.0
52 | rect_min_size = Vector2( 0, 24 )
53 | size_flags_horizontal = 3
54 | custom_constants/separation = 8
55 |
56 | [node name="IconHolder" type="Control" parent="Bg/v/toolbar"]
57 | margin_right = 24.0
58 | margin_bottom = 24.0
59 | rect_min_size = Vector2( 24, 24 )
60 |
61 | [node name="Icon" type="TextureRect" parent="Bg/v/toolbar/IconHolder"]
62 | anchor_right = 1.0
63 | anchor_bottom = 1.0
64 | margin_left = 4.0
65 | margin_top = 4.0
66 | margin_right = -4.0
67 | margin_bottom = -4.0
68 | size_flags_horizontal = 0
69 | size_flags_vertical = 0
70 | texture = ExtResource( 3 )
71 | expand = true
72 | __meta__ = {
73 | "_edit_use_anchors_": false
74 | }
75 |
76 | [node name="Title" type="Label" parent="Bg/v/toolbar"]
77 | margin_left = 32.0
78 | margin_right = 220.0
79 | margin_bottom = 24.0
80 | rect_min_size = Vector2( 0, 24 )
81 | size_flags_horizontal = 3
82 | text = "Todotitle"
83 | valign = 1
84 | clip_text = true
85 |
86 | [node name="View" type="Button" parent="Bg/v/toolbar"]
87 | margin_left = 228.0
88 | margin_right = 252.0
89 | margin_bottom = 24.0
90 | rect_min_size = Vector2( 24, 24 )
91 | hint_tooltip = "View task"
92 | size_flags_horizontal = 0
93 | size_flags_vertical = 0
94 | icon = ExtResource( 5 )
95 | flat = true
96 | expand_icon = true
97 |
98 | [node name="Menu" type="MenuButton" parent="Bg/v/toolbar"]
99 | margin_left = 260.0
100 | margin_right = 284.0
101 | margin_bottom = 24.0
102 | rect_min_size = Vector2( 24, 24 )
103 | hint_tooltip = "Task menu"
104 | focus_mode = 2
105 | size_flags_horizontal = 0
106 | size_flags_vertical = 0
107 | icon = ExtResource( 1 )
108 | expand_icon = true
109 |
110 | [node name="Description" type="RichTextLabel" parent="Bg/v"]
111 | margin_top = 28.0
112 | margin_right = 284.0
113 | margin_bottom = 114.0
114 | rect_min_size = Vector2( 0, 64 )
115 | mouse_filter = 1
116 | size_flags_vertical = 3
117 | custom_styles/focus = SubResource( 1 )
118 | custom_styles/normal = SubResource( 2 )
119 | bbcode_enabled = true
120 | bbcode_text = "text
121 | text
122 | text
123 | text
124 | text
125 | text
126 | text
127 | text"
128 | text = "text
129 | text
130 | text
131 | text
132 | text
133 | text
134 | text
135 | text"
136 | __meta__ = {
137 | "_edit_use_anchors_": false
138 | }
139 |
140 | [node name="Content" type="Control" parent="Bg/v"]
141 | margin_top = 118.0
142 | margin_right = 284.0
143 | margin_bottom = 136.0
144 | rect_min_size = Vector2( 0, 18 )
145 | mouse_filter = 1
146 | size_flags_horizontal = 3
147 |
148 | [node name="Assigned" type="Label" parent="Bg/v/Content"]
149 | anchor_right = 1.0
150 | margin_bottom = 16.0
151 | rect_min_size = Vector2( 0, 16 )
152 | size_flags_horizontal = 3
153 | custom_fonts/font = ExtResource( 4 )
154 | text = "Assigned"
155 | clip_text = true
156 | __meta__ = {
157 | "_edit_use_anchors_": false
158 | }
159 |
160 | [connection signal="button_up" from="Bg/v/toolbar/View" to="." method="_on_View_button_up"]
161 |
--------------------------------------------------------------------------------
/addons/NbPM/card/DragPreview.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=2 format=2]
2 |
3 | [ext_resource path="res://addons/NbPM/icons/tasks-solid.svg" type="Texture" id=1]
4 |
5 | [node name="DragPreview" type="ColorRect"]
6 | margin_right = 32.0
7 | margin_bottom = 32.0
8 | color = Color( 0.2, 0.231373, 0.309804, 1 )
9 | __meta__ = {
10 | "_edit_use_anchors_": false
11 | }
12 |
13 | [node name="Shadow" type="ColorRect" parent="."]
14 | show_behind_parent = true
15 | margin_left = 4.0
16 | margin_top = 4.0
17 | margin_right = 36.0
18 | margin_bottom = 36.0
19 | color = Color( 0, 0, 0, 0.25098 )
20 | __meta__ = {
21 | "_edit_use_anchors_": false
22 | }
23 |
24 | [node name="TextureRect" type="TextureRect" parent="."]
25 | anchor_right = 1.0
26 | anchor_bottom = 1.0
27 | margin_left = 4.0
28 | margin_top = 4.0
29 | margin_right = -4.0
30 | margin_bottom = -4.0
31 | texture = ExtResource( 1 )
32 | expand = true
33 |
--------------------------------------------------------------------------------
/addons/NbPM/font/NotoSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NimbleBeasts/NbGodotProjectManagement/db8f3cb407b397af3860a0ceb7becbfab97feb65/addons/NbPM/font/NotoSans-Regular.ttf
--------------------------------------------------------------------------------
/addons/NbPM/font/OFL.txt:
--------------------------------------------------------------------------------
1 | Copyright 2012 Google Inc. All Rights Reserved.
2 |
3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
4 | This license is copied below, and is also available with a FAQ at:
5 | http://scripts.sil.org/OFL
6 |
7 |
8 | -----------------------------------------------------------
9 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
10 | -----------------------------------------------------------
11 |
12 | PREAMBLE
13 | The goals of the Open Font License (OFL) are to stimulate worldwide
14 | development of collaborative font projects, to support the font creation
15 | efforts of academic and linguistic communities, and to provide a free and
16 | open framework in which fonts may be shared and improved in partnership
17 | with others.
18 |
19 | The OFL allows the licensed fonts to be used, studied, modified and
20 | redistributed freely as long as they are not sold by themselves. The
21 | fonts, including any derivative works, can be bundled, embedded,
22 | redistributed and/or sold with any software provided that any reserved
23 | names are not used by derivative works. The fonts and derivatives,
24 | however, cannot be released under any other type of license. The
25 | requirement for fonts to remain under this license does not apply
26 | to any document created using the fonts or their derivatives.
27 |
28 | DEFINITIONS
29 | "Font Software" refers to the set of files released by the Copyright
30 | Holder(s) under this license and clearly marked as such. This may
31 | include source files, build scripts and documentation.
32 |
33 | "Reserved Font Name" refers to any names specified as such after the
34 | copyright statement(s).
35 |
36 | "Original Version" refers to the collection of Font Software components as
37 | distributed by the Copyright Holder(s).
38 |
39 | "Modified Version" refers to any derivative made by adding to, deleting,
40 | or substituting -- in part or in whole -- any of the components of the
41 | Original Version, by changing formats or by porting the Font Software to a
42 | new environment.
43 |
44 | "Author" refers to any designer, engineer, programmer, technical
45 | writer or other person who contributed to the Font Software.
46 |
47 | PERMISSION & CONDITIONS
48 | Permission is hereby granted, free of charge, to any person obtaining
49 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
50 | redistribute, and sell modified and unmodified copies of the Font
51 | Software, subject to the following conditions:
52 |
53 | 1) Neither the Font Software nor any of its individual components,
54 | in Original or Modified Versions, may be sold by itself.
55 |
56 | 2) Original or Modified Versions of the Font Software may be bundled,
57 | redistributed and/or sold with any software, provided that each copy
58 | contains the above copyright notice and this license. These can be
59 | included either as stand-alone text files, human-readable headers or
60 | in the appropriate machine-readable metadata fields within text or
61 | binary files as long as those fields can be easily viewed by the user.
62 |
63 | 3) No Modified Version of the Font Software may use the Reserved Font
64 | Name(s) unless explicit written permission is granted by the corresponding
65 | Copyright Holder. This restriction only applies to the primary font name as
66 | presented to the users.
67 |
68 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
69 | Software shall not be used to promote, endorse or advertise any
70 | Modified Version, except to acknowledge the contribution(s) of the
71 | Copyright Holder(s) and the Author(s) or with their explicit written
72 | permission.
73 |
74 | 5) The Font Software, modified or unmodified, in part or in whole,
75 | must be distributed entirely under this license, and must not be
76 | distributed under any other license. The requirement for fonts to
77 | remain under this license does not apply to any document created
78 | using the Font Software.
79 |
80 | TERMINATION
81 | This license becomes null and void if any of the above conditions are
82 | not met.
83 |
84 | DISCLAIMER
85 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
86 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
87 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
88 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
89 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
90 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
91 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
92 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
93 | OTHER DEALINGS IN THE FONT SOFTWARE.
94 |
--------------------------------------------------------------------------------
/addons/NbPM/font/font12.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="DynamicFont" load_steps=2 format=2]
2 |
3 | [ext_resource path="res://addons/NbPM/font/NotoSans-Regular.ttf" type="DynamicFontData" id=1]
4 |
5 | [resource]
6 | size = 12
7 | font_data = ExtResource( 1 )
8 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/add_task.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NimbleBeasts/NbGodotProjectManagement/db8f3cb407b397af3860a0ceb7becbfab97feb65/addons/NbPM/icons/add_task.png
--------------------------------------------------------------------------------
/addons/NbPM/icons/add_task.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/add_task.png-a168a7c1229da47838c45ce75b7952cc.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/NbPM/icons/add_task.png"
13 | dest_files=[ "res://.import/add_task.png-a168a7c1229da47838c45ce75b7952cc.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/caret-down-solid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/caret-down-solid.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/caret-down-solid.svg-2014f74804f5717d4ddb1844bebad2bf.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/NbPM/icons/caret-down-solid.svg"
13 | dest_files=[ "res://.import/caret-down-solid.svg-2014f74804f5717d4ddb1844bebad2bf.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/chalkboard-teacher-solid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/chalkboard-teacher-solid.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/chalkboard-teacher-solid.svg-95e824d4f88ac580238aad754c71f4a9.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/NbPM/icons/chalkboard-teacher-solid.svg"
13 | dest_files=[ "res://.import/chalkboard-teacher-solid.svg-95e824d4f88ac580238aad754c71f4a9.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/ellipsis-h-solid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/ellipsis-h-solid.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/ellipsis-h-solid.svg-6232a4c4e9310f6aa0fbf3abb5f0bcad.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/NbPM/icons/ellipsis-h-solid.svg"
13 | dest_files=[ "res://.import/ellipsis-h-solid.svg-6232a4c4e9310f6aa0fbf3abb5f0bcad.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/external-link-alt-solid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/external-link-alt-solid.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/external-link-alt-solid.svg-2cc2c28f997e5cfdaf7a8fd7c7e2ea95.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/NbPM/icons/external-link-alt-solid.svg"
13 | dest_files=[ "res://.import/external-link-alt-solid.svg-2cc2c28f997e5cfdaf7a8fd7c7e2ea95.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/plus-square-regular.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/plus-square-regular.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/plus-square-regular.svg-b580088822f4c689d71a7a78750dfeba.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/NbPM/icons/plus-square-regular.svg"
13 | dest_files=[ "res://.import/plus-square-regular.svg-b580088822f4c689d71a7a78750dfeba.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/pm_icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NimbleBeasts/NbGodotProjectManagement/db8f3cb407b397af3860a0ceb7becbfab97feb65/addons/NbPM/icons/pm_icon.png
--------------------------------------------------------------------------------
/addons/NbPM/icons/pm_icon.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/pm_icon.png-9af85928493d52850320e2552ff7886b.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/NbPM/icons/pm_icon.png"
13 | dest_files=[ "res://.import/pm_icon.png-9af85928493d52850320e2552ff7886b.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/save-solid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/save-solid.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/save-solid.svg-92d05521dc2981b6b6f5b34db4681a6a.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/NbPM/icons/save-solid.svg"
13 | dest_files=[ "res://.import/save-solid.svg-92d05521dc2981b6b6f5b34db4681a6a.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/sync-alt-solid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/sync-alt-solid.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/sync-alt-solid.svg-e3f6368c61b86a0d16d80f70d9e0ff6a.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/NbPM/icons/sync-alt-solid.svg"
13 | dest_files=[ "res://.import/sync-alt-solid.svg-e3f6368c61b86a0d16d80f70d9e0ff6a.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/tasks-solid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/tasks-solid.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/tasks-solid.svg-a9ed75ca61cdbf00901ab75ac38792ba.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/NbPM/icons/tasks-solid.svg"
13 | dest_files=[ "res://.import/tasks-solid.svg-a9ed75ca61cdbf00901ab75ac38792ba.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/times-solid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/times-solid.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/times-solid.svg-b42e99ff9a47f35dbe013641bd09a6a9.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/NbPM/icons/times-solid.svg"
13 | dest_files=[ "res://.import/times-solid.svg-b42e99ff9a47f35dbe013641bd09a6a9.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/trash-solid.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/trash-solid.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/trash-solid.svg-d7d610e7f9ecd162411b3534ba195f20.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/NbPM/icons/trash-solid.svg"
13 | dest_files=[ "res://.import/trash-solid.svg-d7d610e7f9ecd162411b3534ba195f20.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/NbPM/icons/view_src.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NimbleBeasts/NbGodotProjectManagement/db8f3cb407b397af3860a0ceb7becbfab97feb65/addons/NbPM/icons/view_src.png
--------------------------------------------------------------------------------
/addons/NbPM/icons/view_src.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/view_src.png-8749c336c6204141154430b45484d6e2.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/NbPM/icons/view_src.png"
13 | dest_files=[ "res://.import/view_src.png-8749c336c6204141154430b45484d6e2.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/NbPM/lane/DropZone.gd:
--------------------------------------------------------------------------------
1 | tool
2 | extends NinePatchRect
3 |
4 |
5 | func can_drop_data(position, data):
6 | return true
7 |
8 |
9 | func drop_data(position, data):
10 | get_parent().drop(data)
11 |
12 |
--------------------------------------------------------------------------------
/addons/NbPM/lane/DropZone.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=2]
2 |
3 | [ext_resource path="res://addons/NbPM/lane/DropZone.gd" type="Script" id=1]
4 | [ext_resource path="res://addons/NbPM/ninepatch.png" type="Texture" id=2]
5 |
6 | [node name="DropZone" type="NinePatchRect"]
7 | anchor_right = 1.0
8 | anchor_bottom = 1.0
9 | margin_left = 4.0
10 | margin_top = 32.0
11 | margin_right = -4.0
12 | margin_bottom = -4.0
13 | mouse_filter = 0
14 | size_flags_horizontal = 3
15 | size_flags_vertical = 3
16 | texture = ExtResource( 2 )
17 | patch_margin_left = 2
18 | patch_margin_top = 2
19 | patch_margin_right = 2
20 | patch_margin_bottom = 2
21 | axis_stretch_horizontal = 1
22 | axis_stretch_vertical = 1
23 | script = ExtResource( 1 )
24 | __meta__ = {
25 | "_edit_use_anchors_": false
26 | }
27 |
--------------------------------------------------------------------------------
/addons/NbPM/lane/Lane.gd:
--------------------------------------------------------------------------------
1 | tool
2 | extends Panel
3 |
4 | signal item_drag_start()
5 |
6 | var pm_ref = null
7 |
8 | const Scene_Card = preload("res://addons/NbPM/card/Card.tscn")
9 |
10 | var _id = 0
11 | var _count = 0
12 |
13 | var base_color: Color
14 |
15 | func setup(ref, title, id, color):
16 | $v/Toolbar/Title.set_text(title)
17 | pm_ref = ref
18 | _id = id
19 |
20 | base_color = color
21 | $v/Toolbar/ItemCount/Bg.color = base_color
22 |
23 | func drop(data):
24 | pm_ref.move_task(_id, data)
25 | pm_ref.stop_card_drag()
26 |
27 | func clear():
28 | for card in $v/Items/v.get_children():
29 | card.queue_free()
30 | _count = 0
31 | $v/Toolbar/ItemCount.set_text(str(_count))
32 |
33 |
34 | func add(context, assigned_string):
35 | var card = Scene_Card.instance()
36 | card.setup(pm_ref, context, assigned_string, base_color)
37 | $v/Items/v.add_child(card)
38 | _count += 1
39 | $v/Toolbar/ItemCount.set_text(str(_count))
40 |
41 |
42 | func drag_start():
43 | $DropZone.show()
44 | self.modulate = Color(1.0, 1.0, 1.0, 0.6)
45 |
46 | func drag_stop():
47 | $DropZone.hide()
48 | self.modulate = Color(1.0, 1.0, 1.0, 1.0)
49 |
50 |
51 | func _on_AddTaskButton_button_up():
52 | pm_ref.new_task(_id)
53 |
--------------------------------------------------------------------------------
/addons/NbPM/lane/Lane.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=2]
2 |
3 | [ext_resource path="res://addons/NbPM/lane/Lane.gd" type="Script" id=1]
4 | [ext_resource path="res://addons/NbPM/lane/DropZone.tscn" type="PackedScene" id=2]
5 |
6 | [node name="Lane" type="Panel"]
7 | margin_right = 320.0
8 | margin_bottom = 568.0
9 | rect_min_size = Vector2( 320, 0 )
10 | script = ExtResource( 1 )
11 | __meta__ = {
12 | "_edit_use_anchors_": false
13 | }
14 |
15 | [node name="v" type="VBoxContainer" parent="."]
16 | anchor_right = 1.0
17 | anchor_bottom = 1.0
18 | __meta__ = {
19 | "_edit_use_anchors_": false
20 | }
21 |
22 | [node name="Toolbar" type="HBoxContainer" parent="v"]
23 | margin_right = 320.0
24 | margin_bottom = 28.0
25 | rect_min_size = Vector2( 0, 28 )
26 |
27 | [node name="ItemCount" type="Label" parent="v/Toolbar"]
28 | margin_right = 28.0
29 | margin_bottom = 28.0
30 | rect_min_size = Vector2( 28, 28 )
31 | hint_tooltip = "Task count"
32 | mouse_filter = 1
33 | text = "0"
34 | align = 1
35 | valign = 1
36 |
37 | [node name="Bg" type="ColorRect" parent="v/Toolbar/ItemCount"]
38 | show_behind_parent = true
39 | anchor_right = 1.0
40 | anchor_bottom = 1.0
41 | margin_left = 2.0
42 | margin_top = 2.0
43 | margin_right = -2.0
44 | margin_bottom = -2.0
45 | color = Color( 0.2, 0.309804, 0.254902, 1 )
46 | __meta__ = {
47 | "_edit_use_anchors_": false
48 | }
49 |
50 | [node name="Title" type="Label" parent="v/Toolbar"]
51 | margin_left = 32.0
52 | margin_top = 7.0
53 | margin_right = 69.0
54 | margin_bottom = 21.0
55 | text = "To Do"
56 |
57 | [node name="Spacer" type="Control" parent="v/Toolbar"]
58 | margin_left = 73.0
59 | margin_right = 296.0
60 | margin_bottom = 28.0
61 | size_flags_horizontal = 3
62 |
63 | [node name="AddTaskButton" type="Button" parent="v/Toolbar"]
64 | margin_left = 300.0
65 | margin_right = 320.0
66 | margin_bottom = 28.0
67 | hint_tooltip = "Add a new task to this category"
68 | text = "+"
69 |
70 | [node name="Items" type="ScrollContainer" parent="v"]
71 | margin_top = 32.0
72 | margin_right = 320.0
73 | margin_bottom = 568.0
74 | size_flags_horizontal = 3
75 | size_flags_vertical = 3
76 | scroll_horizontal_enabled = false
77 |
78 | [node name="v" type="VBoxContainer" parent="v/Items"]
79 | margin_right = 320.0
80 | size_flags_horizontal = 3
81 | custom_constants/separation = 0
82 |
83 | [node name="DropZone" parent="." instance=ExtResource( 2 )]
84 | visible = false
85 |
86 | [connection signal="button_up" from="v/Toolbar/AddTaskButton" to="." method="_on_AddTaskButton_button_up"]
87 |
--------------------------------------------------------------------------------
/addons/NbPM/ninepatch.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NimbleBeasts/NbGodotProjectManagement/db8f3cb407b397af3860a0ceb7becbfab97feb65/addons/NbPM/ninepatch.png
--------------------------------------------------------------------------------
/addons/NbPM/ninepatch.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/ninepatch.png-0083682c3eef3801f556da0a3511b048.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/NbPM/ninepatch.png"
13 | dest_files=[ "res://.import/ninepatch.png-0083682c3eef3801f556da0a3511b048.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/addons/NbPM/plugin.cfg:
--------------------------------------------------------------------------------
1 | [plugin]
2 |
3 | name="NbProjectManager"
4 | description="NimbleBeasts Project Manager.
5 | Create Kanban like tasks from TODOs to keep track of the remaining tasks in group projects."
6 | author="NimbleBeasts"
7 | version="1.0"
8 | script="plugin_loader.gd"
9 |
--------------------------------------------------------------------------------
/addons/NbPM/plugin_loader.gd:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Copyright (c) 2021 NimbleBeasts
3 | #
4 | # Permission is hereby granted, free of charge, to any person obtaining a copy
5 | # of this software and associated documentation files (the "Software"), to deal
6 | # in the Software without restriction, including without limitation the rights
7 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 | # copies of the Software, and to permit persons to whom the Software is
9 | # furnished to do so, subject to the following conditions:
10 | #
11 | # The above copyright notice and this permission notice shall be included in all
12 | # copies or substantial portions of the Software.
13 | #
14 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20 | # SOFTWARE.
21 | ###############################################################################
22 | tool
23 | extends EditorPlugin
24 |
25 | ###############################################################################
26 | # Plugin Consts
27 | ###############################################################################
28 | const PM_DIRECTORY = "res://_PM/"
29 | const PM_TASK_DIRECTORY = "res://_PM/tasks"
30 | const PM_PROJECT_CONFIG = "project.cfg"
31 | const PM_USER_CONFIG = "user.cfg"
32 | const TODO_CACHE = "cache.dat"
33 |
34 |
35 | ###############################################################################
36 | # Scenes
37 | ###############################################################################
38 | const Scene_TodoDock = preload("res://addons/NbPM/TodoDock.tscn")
39 | const Scene_ProjectScreen = preload("res://addons/NbPM/ProjectScreen.tscn")
40 |
41 | var todo_dock_instance = null
42 | var project_screen_instance = null
43 |
44 |
45 | ###############################################################################
46 | # Configs
47 | ###############################################################################
48 | var config_project = {
49 | "user_names": ["admin"],
50 | "categories": ["Backlog", "To do", "In progress", "Done"],
51 | "exclude_folders": ["addons"],
52 | "tags": ["TODO", "FIXME", "NOTE"],
53 | "linkage": [],
54 | }
55 |
56 | var config_user = {
57 | "user_id": 0,
58 | "todo_database": []
59 | }
60 |
61 | ###############################################################################
62 | # State variables
63 | ###############################################################################
64 | var todo_cache = {}
65 |
66 | var project_cfg_provided = true
67 | var user_cfg_provided = true
68 |
69 |
70 | func _enter_tree():
71 | _load_configs()
72 |
73 | # Setup main screen
74 | project_screen_instance = Scene_ProjectScreen.instance()
75 | project_screen_instance.setup(self, project_cfg_provided, user_cfg_provided)
76 | get_editor_interface().get_editor_viewport().add_child(project_screen_instance, true)
77 | make_visible(false)
78 |
79 | # Setup todo dock
80 | todo_dock_instance = Scene_TodoDock.instance()
81 | todo_dock_instance.setup(self)
82 | add_control_to_dock(EditorPlugin.DOCK_SLOT_LEFT_BR, todo_dock_instance)
83 |
84 | if todo_dock_instance and project_screen_instance:
85 | print(get_plugin_name() + ": Succesfully loaded")
86 | else:
87 | printerr(get_plugin_name() + ": Failed to load")
88 |
89 |
90 | func _exit_tree():
91 | remove_control_from_docks(todo_dock_instance)
92 | if project_screen_instance:
93 | project_screen_instance.queue_free()
94 |
95 |
96 | func has_main_screen():
97 | return true
98 |
99 |
100 | func make_visible(visible):
101 | if project_screen_instance:
102 | project_screen_instance.visible = visible
103 |
104 |
105 | func get_plugin_name():
106 | return "ProjectManagement"
107 |
108 |
109 | func get_plugin_icon():
110 | # Must return some kind of Texture for the icon.
111 | #return get_editor_interface().get_base_control().get_icon("SpriteSheet", "EditorIcons")
112 | return preload("res://addons/NbPM/icons/pm_icon.png")
113 |
114 |
115 | func save_user_config():
116 | _save_file(PM_USER_CONFIG, config_user)
117 |
118 | func save_project_config():
119 | _update_project_config()
120 | _save_file(PM_PROJECT_CONFIG, config_project)
121 |
122 | func _update_project_config():
123 | todo_dock_instance.update_project_config()
124 | project_screen_instance.update_project_config()
125 |
126 |
127 |
128 | ## Open main screen
129 | func jump_to_main_screen(metadata):
130 | if project_screen_instance:
131 | project_screen_instance.jump_to_main_screen(metadata)
132 | make_visible(true)
133 | get_editor_interface().set_main_screen_editor(get_plugin_name())
134 |
135 |
136 | ## Load config files, create files if needed
137 | func _load_configs():
138 | var dir = Directory.new()
139 | var cfg = File.new()
140 |
141 | # Create directories, if not exists
142 | if not dir.dir_exists(PM_DIRECTORY):
143 | dir.make_dir(PM_DIRECTORY)
144 | if not dir.dir_exists(PM_TASK_DIRECTORY):
145 | dir.make_dir(PM_TASK_DIRECTORY)
146 |
147 | # Project config
148 | if not cfg.file_exists(PM_DIRECTORY + PM_PROJECT_CONFIG):
149 | # Create project config
150 | _save_file(PM_PROJECT_CONFIG, config_project)
151 | project_cfg_provided = false
152 | else:
153 | # Load project config
154 | config_project = _load_file(PM_PROJECT_CONFIG)
155 |
156 | # User config
157 | if not cfg.file_exists(PM_DIRECTORY + PM_USER_CONFIG):
158 | # Create project config
159 | _save_file(PM_USER_CONFIG, config_user)
160 | user_cfg_provided = false
161 | else:
162 | # Load project config
163 | config_user = _load_file(PM_USER_CONFIG)
164 |
165 | # Add user.cfg to Git Ignore
166 | if not cfg.file_exists(PM_DIRECTORY + ".gitignore"):
167 | cfg.open(PM_DIRECTORY + ".gitignore", File.WRITE)
168 | cfg.store_line("/user.cfg")
169 | cfg.close()
170 |
171 |
172 | ## file saving
173 | func _save_file(file: String, settings: Dictionary):
174 | var cfg = File.new()
175 | cfg.open(PM_DIRECTORY + file, File.WRITE)
176 | cfg.store_line(JSON.print(settings, "\t"))
177 | cfg.close()
178 |
179 |
180 | ## file loading
181 | func _load_file(file: String):
182 | var cfg = File.new()
183 | cfg.open(PM_DIRECTORY + file, File.READ)
184 | var return_val = parse_json(cfg.get_as_text())
185 | cfg.close()
186 | return return_val
187 |
188 |
--------------------------------------------------------------------------------
/addons/NbPM/screenshots/.gdignore:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/addons/NbPM/screenshots/screenshot1.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NimbleBeasts/NbGodotProjectManagement/db8f3cb407b397af3860a0ceb7becbfab97feb65/addons/NbPM/screenshots/screenshot1.gif
--------------------------------------------------------------------------------
/addons/NbPM/screenshots/screenshot2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NimbleBeasts/NbGodotProjectManagement/db8f3cb407b397af3860a0ceb7becbfab97feb65/addons/NbPM/screenshots/screenshot2.png
--------------------------------------------------------------------------------
/addons/NbPM/screenshots/screenshot3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NimbleBeasts/NbGodotProjectManagement/db8f3cb407b397af3860a0ceb7becbfab97feb65/addons/NbPM/screenshots/screenshot3.png
--------------------------------------------------------------------------------
/addons/NbPM/settings/InputField.gd:
--------------------------------------------------------------------------------
1 | tool
2 | extends Control
3 |
4 | var id = 0
5 |
6 | signal remove_input(reference, id)
7 |
8 | func setup(my_id, value = ""):
9 | id = my_id
10 | $LineEdit.text = value
11 |
12 | func _on_Button_button_up():
13 | emit_signal("remove_input", self, id)
14 |
15 | func get_value():
16 | return $LineEdit.text
17 |
--------------------------------------------------------------------------------
/addons/NbPM/settings/InputField.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=2]
2 |
3 | [ext_resource path="res://addons/NbPM/icons/trash-solid.svg" type="Texture" id=1]
4 | [ext_resource path="res://addons/NbPM/settings/InputField.gd" type="Script" id=2]
5 |
6 | [node name="InputField" type="Control"]
7 | anchor_right = 1.0
8 | anchor_bottom = 1.0
9 | margin_right = -880.0
10 | margin_bottom = -568.0
11 | rect_min_size = Vector2( 144, 32 )
12 | script = ExtResource( 2 )
13 | __meta__ = {
14 | "_edit_use_anchors_": false
15 | }
16 |
17 | [node name="LineEdit" type="LineEdit" parent="."]
18 | margin_left = 8.0
19 | margin_top = 4.0
20 | margin_right = 112.0
21 | margin_bottom = 28.0
22 |
23 | [node name="Button" type="Button" parent="."]
24 | margin_left = 112.0
25 | margin_top = 4.0
26 | margin_right = 136.0
27 | margin_bottom = 28.0
28 | icon = ExtResource( 1 )
29 | flat = true
30 | expand_icon = true
31 | __meta__ = {
32 | "_edit_use_anchors_": false
33 | }
34 |
35 | [connection signal="button_up" from="Button" to="." method="_on_Button_button_up"]
36 |
--------------------------------------------------------------------------------
/default_env.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Environment" load_steps=2 format=2]
2 |
3 | [sub_resource type="ProceduralSky" id=1]
4 |
5 | [resource]
6 | background_mode = 2
7 | background_sky = SubResource( 1 )
8 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NimbleBeasts/NbGodotProjectManagement/db8f3cb407b397af3860a0ceb7becbfab97feb65/icon.png
--------------------------------------------------------------------------------
/icon.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://icon.png"
13 | dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=4
10 |
11 | [application]
12 |
13 | config/name="Nb Project Management"
14 | run/main_scene="res://addons/NbPM/ProjectScreen.tscn"
15 | config/icon="res://icon.png"
16 |
17 | [editor_plugins]
18 |
19 | enabled=PoolStringArray( "res://addons/NbPM/plugin.cfg" )
20 |
21 | [physics]
22 |
23 | common/enable_pause_aware_picking=true
24 |
25 | [rendering]
26 |
27 | environment/default_environment="res://default_env.tres"
28 |
29 | [statistics]
30 |
31 | force_include=PoolStringArray( )
32 |
--------------------------------------------------------------------------------