442 lines
12 KiB
GDScript
442 lines
12 KiB
GDScript
@tool
|
|
extends "standalone_plugin.gd"
|
|
|
|
|
|
const __Singletons := preload("./plugin_singleton/singletons.gd")
|
|
const __Shortcuts := preload("./view/shortcuts.gd")
|
|
const __EditContext := preload("./view/edit_context.gd")
|
|
const __Settings := preload("./data/settings.gd")
|
|
const __BoardData := preload("./data/board.gd")
|
|
const __LayoutData := preload("./data/layout.gd")
|
|
const __TaskData := preload("./data/task.gd")
|
|
const __CategoryData := preload("./data/category.gd")
|
|
const __StageData := preload("./data/stage.gd")
|
|
const __BoardView := preload("./view/board/board.tscn")
|
|
const __BoardViewType := preload("./view/board/board.gd")
|
|
const __StartView := preload("./view/start/start.tscn")
|
|
const __StartViewType := preload("./view/start/start.gd")
|
|
const __DocumentationView := preload("./view/documentation/documentation.tscn")
|
|
|
|
const SETTINGS_KEY: String = "kanban_tasks/general/settings"
|
|
|
|
enum {
|
|
ACTION_SAVE,
|
|
ACTION_SAVE_AS,
|
|
ACTION_OPEN,
|
|
ACTION_CREATE,
|
|
ACTION_CLOSE,
|
|
ACTION_DOCUMENTATION,
|
|
ACTION_QUIT,
|
|
}
|
|
|
|
var main_panel_frame: MarginContainer
|
|
var start_view: __StartViewType
|
|
var file_dialog_save: FileDialog
|
|
var file_dialog_open: FileDialog
|
|
var discard_changes_dialog: ConfirmationDialog
|
|
var documentation_dialog: AcceptDialog
|
|
|
|
var file_menu: PopupMenu
|
|
var help_menu: PopupMenu
|
|
|
|
var board_view: __BoardViewType
|
|
var board_label: Label
|
|
var board_path: String = "":
|
|
set(value):
|
|
board_path = value
|
|
__update_board_label()
|
|
__update_menus()
|
|
var board_changed: bool = false:
|
|
set(value):
|
|
board_changed = value
|
|
__update_board_label()
|
|
|
|
|
|
func _enter_tree() -> void:
|
|
board_label = Label.new()
|
|
if not Engine.is_editor_hint():
|
|
add_control_to_container(CONTAINER_TOOLBAR, board_label)
|
|
|
|
file_menu = PopupMenu.new()
|
|
file_menu.name = "File"
|
|
file_menu.add_item("Save board", ACTION_SAVE)
|
|
file_menu.add_item("Save board as...", ACTION_SAVE_AS)
|
|
file_menu.add_item("Close board", ACTION_CLOSE)
|
|
file_menu.add_item("Open board...", ACTION_OPEN)
|
|
file_menu.add_item("Create board", ACTION_CREATE)
|
|
file_menu.add_separator()
|
|
file_menu.add_item("Quit", ACTION_QUIT)
|
|
file_menu.id_pressed.connect(__action)
|
|
add_menu(file_menu)
|
|
|
|
help_menu = PopupMenu.new()
|
|
help_menu.name = "Help"
|
|
help_menu.add_item("Documentation", ACTION_DOCUMENTATION)
|
|
help_menu.id_pressed.connect(__action)
|
|
add_menu(help_menu)
|
|
|
|
file_dialog_save = FileDialog.new()
|
|
file_dialog_save.access = FileDialog.ACCESS_FILESYSTEM
|
|
file_dialog_save.file_mode = FileDialog.FILE_MODE_SAVE_FILE
|
|
file_dialog_save.add_filter("*.kanban, *.json", "Kanban Board")
|
|
file_dialog_save.min_size = Vector2(800, 500)
|
|
file_dialog_save.file_selected.connect(__save_board)
|
|
get_editor_interface().get_base_control().add_child(file_dialog_save)
|
|
|
|
file_dialog_open = FileDialog.new()
|
|
file_dialog_open.access = FileDialog.ACCESS_FILESYSTEM
|
|
file_dialog_open.file_mode = FileDialog.FILE_MODE_OPEN_FILE
|
|
file_dialog_open.add_filter("*.kanban, *.json", "Kanban Board")
|
|
file_dialog_open.min_size = Vector2(800, 500)
|
|
file_dialog_open.file_selected.connect(__open_board)
|
|
get_editor_interface().get_base_control().add_child(file_dialog_open)
|
|
|
|
discard_changes_dialog = ConfirmationDialog.new()
|
|
discard_changes_dialog.dialog_text = "All unsaved changes will be discarded."
|
|
discard_changes_dialog.unresizable = true
|
|
get_editor_interface().get_base_control().add_child(discard_changes_dialog)
|
|
|
|
documentation_dialog = __DocumentationView.instantiate()
|
|
get_editor_interface().get_base_control().add_child(documentation_dialog)
|
|
|
|
main_panel_frame = MarginContainer.new()
|
|
main_panel_frame.add_theme_constant_override(&"margin_top", 5)
|
|
main_panel_frame.add_theme_constant_override(&"margin_left", 5)
|
|
main_panel_frame.add_theme_constant_override(&"margin_bottom", 5)
|
|
main_panel_frame.add_theme_constant_override(&"margin_right", 5)
|
|
main_panel_frame.size_flags_vertical = Control.SIZE_EXPAND_FILL
|
|
get_editor_interface().get_editor_main_screen().add_child(main_panel_frame)
|
|
|
|
start_view = __StartView.instantiate()
|
|
start_view.create_board.connect(__action.bind(ACTION_CREATE))
|
|
start_view.open_board.connect(__on_start_view_open_board)
|
|
main_panel_frame.add_child(start_view)
|
|
|
|
_make_visible(false)
|
|
|
|
await get_tree().create_timer(0.0).timeout
|
|
|
|
__load_settings()
|
|
|
|
if Engine.is_editor_hint():
|
|
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
|
|
var editor_data_file_path = ctx.settings.editor_data_file_path
|
|
if FileAccess.file_exists(editor_data_file_path):
|
|
__open_board(editor_data_file_path)
|
|
elif FileAccess.file_exists("res://addons/kanban_tasks/data.json"):
|
|
# TODO: Remove sometime in the future.
|
|
# Migrate from old version.
|
|
__open_board("res://addons/kanban_tasks/data.json")
|
|
__save_board(editor_data_file_path)
|
|
else:
|
|
__create_board()
|
|
__save_board(editor_data_file_path)
|
|
|
|
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
|
|
ctx.save_board.connect(__editor_save_board)
|
|
ctx.reload_board.connect(__editor_reload_board)
|
|
ctx.create_board.connect(__editor_create_board)
|
|
|
|
__update_menus()
|
|
|
|
|
|
func _exit_tree() -> void:
|
|
if not Engine.is_editor_hint():
|
|
remove_control_from_container(CONTAINER_TOOLBAR, board_label)
|
|
board_label.queue_free()
|
|
|
|
remove_menu(file_menu)
|
|
file_menu.queue_free()
|
|
|
|
remove_menu(help_menu)
|
|
file_menu.queue_free()
|
|
|
|
file_dialog_save.queue_free()
|
|
file_dialog_open.queue_free()
|
|
discard_changes_dialog.queue_free()
|
|
documentation_dialog.queue_free()
|
|
|
|
main_panel_frame.queue_free()
|
|
start_view.queue_free()
|
|
|
|
if is_instance_valid(board_view):
|
|
board_view.queue_free()
|
|
|
|
|
|
func _shortcut_input(event: InputEvent) -> void:
|
|
var shortcuts: __Shortcuts = __Singletons.instance_of(__Shortcuts, self)
|
|
if not Engine.is_editor_hint() and shortcuts.save.matches_event(event):
|
|
get_viewport().set_input_as_handled()
|
|
__action(ACTION_SAVE)
|
|
|
|
if not Engine.is_editor_hint() and shortcuts.save_as.matches_event(event):
|
|
get_viewport().set_input_as_handled()
|
|
__action(ACTION_SAVE_AS)
|
|
|
|
|
|
func _has_main_screen() -> bool:
|
|
return true
|
|
|
|
|
|
func _make_visible(visible) -> void:
|
|
if main_panel_frame:
|
|
main_panel_frame.visible = visible
|
|
|
|
|
|
func _get_plugin_name() -> String:
|
|
return "Tasks"
|
|
|
|
|
|
func _get_plugin_icon() -> Texture2D:
|
|
return preload("./icon.svg")
|
|
|
|
|
|
func _notification(what: int) -> void:
|
|
match what:
|
|
NOTIFICATION_WM_CLOSE_REQUEST:
|
|
if not Engine.is_editor_hint():
|
|
if not board_changed:
|
|
get_tree().quit()
|
|
else:
|
|
__request_discard_changes(get_tree().quit)
|
|
|
|
|
|
func __update_menus() -> void:
|
|
if not is_instance_valid(file_menu):
|
|
return
|
|
|
|
var shortcuts: __Shortcuts = __Singletons.instance_of(__Shortcuts, self)
|
|
|
|
file_menu.set_item_disabled(
|
|
file_menu.get_item_index(ACTION_SAVE),
|
|
not is_instance_valid(board_view),
|
|
)
|
|
file_menu.set_item_shortcut(
|
|
file_menu.get_item_index(ACTION_SAVE),
|
|
shortcuts.save,
|
|
)
|
|
file_menu.set_item_disabled(
|
|
file_menu.get_item_index(ACTION_SAVE_AS),
|
|
not is_instance_valid(board_view),
|
|
)
|
|
file_menu.set_item_shortcut(
|
|
file_menu.get_item_index(ACTION_SAVE_AS),
|
|
shortcuts.save_as,
|
|
)
|
|
file_menu.set_item_disabled(
|
|
file_menu.get_item_index(ACTION_CLOSE),
|
|
not is_instance_valid(board_view),
|
|
)
|
|
|
|
|
|
func __update_board_label() -> void:
|
|
if not is_instance_valid(board_label):
|
|
return
|
|
if is_instance_valid(board_view):
|
|
if board_path.is_empty():
|
|
board_label.text = "unsaved"
|
|
else:
|
|
board_label.text = board_path
|
|
if board_changed:
|
|
board_label.text += "*"
|
|
else:
|
|
board_label.text = ""
|
|
|
|
|
|
func __action(id: int) -> void:
|
|
match id:
|
|
ACTION_SAVE:
|
|
__request_save()
|
|
ACTION_SAVE_AS:
|
|
__request_save(true)
|
|
ACTION_CREATE:
|
|
if not board_changed:
|
|
__create_board()
|
|
else:
|
|
__request_discard_changes(__create_board)
|
|
ACTION_OPEN:
|
|
if not board_changed:
|
|
file_dialog_open.popup_centered()
|
|
else:
|
|
__request_discard_changes(file_dialog_open.popup_centered)
|
|
ACTION_CLOSE:
|
|
if not board_changed:
|
|
__close_board()
|
|
else:
|
|
__request_discard_changes(__close_board)
|
|
ACTION_DOCUMENTATION:
|
|
documentation_dialog.popup_centered()
|
|
ACTION_QUIT:
|
|
get_tree().get_root().propagate_notification(NOTIFICATION_WM_CLOSE_REQUEST)
|
|
|
|
|
|
func __editor_save_board() -> void:
|
|
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
|
|
__save_board(ctx.settings.editor_data_file_path)
|
|
|
|
|
|
func __editor_reload_board() -> void:
|
|
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
|
|
__action(ACTION_SAVE)
|
|
__open_board(ctx.settings.editor_data_file_path)
|
|
|
|
|
|
func __editor_create_board() -> void:
|
|
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
|
|
__action(ACTION_SAVE)
|
|
__create_board()
|
|
__save_board(ctx.settings.editor_data_file_path)
|
|
|
|
|
|
func __request_discard_changes(callback: Callable) -> void:
|
|
for connection in discard_changes_dialog.confirmed.get_connections():
|
|
discard_changes_dialog.confirmed.disconnect(connection["callable"])
|
|
discard_changes_dialog.confirmed.connect(callback)
|
|
discard_changes_dialog.popup_centered()
|
|
|
|
|
|
func __request_save(force_new_location: bool = false) -> void:
|
|
if not is_instance_valid(board_view):
|
|
return
|
|
if not force_new_location and not board_path.is_empty():
|
|
__save_board(board_path)
|
|
else:
|
|
file_dialog_save.popup_centered()
|
|
|
|
|
|
func __create_board() -> void:
|
|
var data := __BoardData.new()
|
|
|
|
data.layout = __LayoutData.new([
|
|
PackedStringArray([data.add_stage(__StageData.new("Todo"))]),
|
|
PackedStringArray([data.add_stage(__StageData.new("Doing"))]),
|
|
PackedStringArray([data.add_stage(__StageData.new("Done"))]),
|
|
])
|
|
data.add_category(
|
|
__CategoryData.new(
|
|
"Task",
|
|
get_editor_interface().get_base_control().
|
|
get_theme_color(&"accent_color", &"Editor")
|
|
)
|
|
)
|
|
|
|
data.changed.connect(__on_board_changed)
|
|
|
|
__make_board_view_visible(data)
|
|
|
|
board_path = ""
|
|
board_changed = false
|
|
|
|
|
|
func __save_board(path: String) -> void:
|
|
if is_instance_valid(board_view):
|
|
__add_to_recent_files(path)
|
|
board_path = path
|
|
board_view.board_data.save(path)
|
|
board_changed = false
|
|
|
|
|
|
func __open_board(path: String) -> void:
|
|
var data := __BoardData.new()
|
|
data.load(path)
|
|
data.changed.connect(__on_board_changed)
|
|
|
|
__make_board_view_visible(data)
|
|
__add_to_recent_files(path)
|
|
|
|
board_path = path
|
|
board_changed = false
|
|
|
|
|
|
func __close_board() -> void:
|
|
board_view.queue_free()
|
|
board_view = null
|
|
board_path = ""
|
|
board_changed = false
|
|
start_view.show()
|
|
|
|
|
|
func __add_to_recent_files(path: String) -> void:
|
|
if Engine.is_editor_hint():
|
|
return
|
|
|
|
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
|
|
var files = ctx.settings.recent_files
|
|
|
|
if path in files:
|
|
files.remove_at(files.find(path))
|
|
files.insert(0, path)
|
|
else:
|
|
files.insert(0, path)
|
|
files.resize(ctx.settings.recent_file_count)
|
|
|
|
ctx.settings.recent_files = files
|
|
|
|
|
|
func __on_board_changed() -> void:
|
|
board_changed = true
|
|
if Engine.is_editor_hint():
|
|
__request_save()
|
|
|
|
|
|
func __on_start_view_open_board(path: String) -> void:
|
|
if path.is_empty():
|
|
__action(ACTION_OPEN)
|
|
else:
|
|
__open_board(path)
|
|
|
|
|
|
func __make_board_view_visible(data: __BoardData) -> void:
|
|
if is_instance_valid(board_view):
|
|
board_view.queue_free()
|
|
board_view = __BoardView.instantiate()
|
|
board_view.show_documentation.connect(__action.bind(ACTION_DOCUMENTATION))
|
|
board_view.board_data = data
|
|
|
|
main_panel_frame.add_child(board_view)
|
|
start_view.hide()
|
|
|
|
|
|
func __save_settings() -> void:
|
|
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
|
|
var data := JSON.stringify(ctx.settings.to_json())
|
|
if Engine.is_editor_hint():
|
|
get_editor_interface().get_editor_settings().set_setting(
|
|
SETTINGS_KEY,
|
|
data,
|
|
)
|
|
else:
|
|
ProjectSettings.set_setting(
|
|
SETTINGS_KEY,
|
|
data,
|
|
)
|
|
save_project_settings()
|
|
|
|
|
|
func __load_settings() -> void:
|
|
var data: String = "{}"
|
|
if Engine.is_editor_hint():
|
|
var editor_settings = get_editor_interface().get_editor_settings()
|
|
if editor_settings.has_setting(SETTINGS_KEY):
|
|
data = editor_settings.get_setting(SETTINGS_KEY)
|
|
else:
|
|
if ProjectSettings.has_setting(SETTINGS_KEY):
|
|
data = ProjectSettings.get_setting(SETTINGS_KEY)
|
|
|
|
var json = JSON.new()
|
|
var err = json.parse(data)
|
|
if err != OK:
|
|
push_error(
|
|
"Error "
|
|
+ str(err)
|
|
+ " while parsing settings. At line "
|
|
+ str(json.get_error_line())
|
|
+ " the following problem occured:\n"
|
|
+ json.get_error_message()
|
|
)
|
|
return
|
|
|
|
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
|
|
ctx.settings.from_json(json.data)
|
|
ctx.settings.changed.connect(__save_settings)
|