├── .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 | ![Godot Project Management Plugin](/addons/NbPM/screenshots/screenshot1.gif "Godot Project Management") 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 | --------------------------------------------------------------------------------