diff --git a/GoDo.gd b/GoDo.gd index 706690b..499fa15 100644 --- a/GoDo.gd +++ b/GoDo.gd @@ -1,9 +1,13 @@ extends Panel -@onready var input = preload("res://lib/input.tscn") - func _ready(): Globals.root_list = %List - Globals.new_input(%List) - Globals.load_tasks() + Globals.menu = %Menu + Globals.load_tasks(0) Globals.item_selected.emit(null) + +func _on_prev_workspace_pressed(): + Globals.change_workspace.emit(-1) + +func _on_next_workspace_pressed(): + Globals.change_workspace.emit(+1) diff --git a/GoDo.tscn b/GoDo.tscn index 2934ba7..04594c4 100644 --- a/GoDo.tscn +++ b/GoDo.tscn @@ -1,6 +1,7 @@ -[gd_scene load_steps=2 format=3 uid="uid://clpfvb50iavnk"] +[gd_scene load_steps=3 format=3 uid="uid://clpfvb50iavnk"] [ext_resource type="Script" path="res://GoDo.gd" id="1_cm71t"] +[ext_resource type="PackedScene" uid="uid://q08a5ojcfou7" path="res://lib/menu.tscn" id="2_ve6er"] [node name="GoDo" type="Panel"] anchors_preset = 15 @@ -10,23 +11,31 @@ grow_horizontal = 2 grow_vertical = 2 script = ExtResource("1_cm71t") -[node name="Border" type="MarginContainer" parent="."] +[node name="VBoxContainer" type="VBoxContainer" parent="."] layout_mode = 1 anchors_preset = 15 anchor_right = 1.0 anchor_bottom = 1.0 grow_horizontal = 2 grow_vertical = 2 + +[node name="Menu" parent="VBoxContainer" instance=ExtResource("2_ve6er")] +unique_name_in_owner = true +layout_mode = 2 + +[node name="Border" type="MarginContainer" parent="VBoxContainer"] +layout_mode = 2 +size_flags_vertical = 3 theme_override_constants/margin_left = 5 theme_override_constants/margin_top = 5 theme_override_constants/margin_right = 5 theme_override_constants/margin_bottom = 5 -[node name="ScrollContainer" type="ScrollContainer" parent="Border"] +[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer/Border"] clip_contents = false layout_mode = 2 -[node name="List" type="VBoxContainer" parent="Border/ScrollContainer"] +[node name="List" type="VBoxContainer" parent="VBoxContainer/Border/ScrollContainer"] unique_name_in_owner = true layout_mode = 2 size_flags_horizontal = 3 diff --git a/lib/entry.gd b/lib/entry.gd index 95601cf..b64e8b0 100644 --- a/lib/entry.gd +++ b/lib/entry.gd @@ -74,7 +74,7 @@ func _on_finish_pressed(save=true): queue_free() Globals.save_data.emit() -func save() -> Dictionary: +func to_dict() -> Dictionary: var save_data = { "name": text, "collapsed": %Toggle.text == "+" @@ -101,8 +101,6 @@ func _can_drop_data(_at_position, data): return true func _drop_data(at_position, data): - var old_parent = data["node"].get_parent() - # Cleanup the old stuff data["node"]._on_finish_pressed(false) diff --git a/lib/globals.gd b/lib/globals.gd index 2ca0c66..d165d59 100644 --- a/lib/globals.gd +++ b/lib/globals.gd @@ -3,19 +3,24 @@ extends Node signal item_selected(item) signal item_changed() # TODO, remove signal save_data() +signal change_workspace(direction : int) +signal rename_workspace(new_name) var root_list +var menu var active_item : Entry const INDENT = 20 -const SAVE_FILE = "user://godo.json" -var task_id = 0 +const SAVE_FILE = "user://godo_%d.json" +var global_task_id = 0 +var current_workspace_id = 0 @onready var entry = preload("res://lib/entry.tscn") @onready var input = preload("res://lib/input.tscn") func _ready(): item_selected.connect(func(item): active_item = item) - save_data.connect(func(): save_tasks()) + save_data.connect(func(): save_tasks(current_workspace_id)) + change_workspace.connect(func (dir : int): load_or_create_workspace(dir)) func _unhandled_input(event): if event.is_action_pressed("add_below"): @@ -32,9 +37,14 @@ func _unhandled_input(event): new_input(root_list) return - if event.is_action_pressed("rename") and active_item: - active_item.rename() - return + if event.is_action_pressed("rename"): + if active_item: + active_item.rename() + return + else: + print_debug("Rename workspace") + rename_workspace.emit(false) + return func _input(event): if event.is_action_pressed("deselect"): @@ -44,10 +54,10 @@ func _input(event): # Save/Load via buttons is only intended for debugging if OS.has_feature("editor"): if event.is_action_pressed("save"): - save_tasks() + save_tasks(0) if event.is_action_pressed("load"): - load_tasks() + load_tasks(0) func new_input(parent): var inp = input.instantiate() @@ -57,47 +67,68 @@ func new_input(parent): func add_task(ref, new_text) -> Entry: var item = entry.instantiate() - item.name = "task-%d" % next_task_id() + item.name = "task-%d" % next_global_task_id() item.text = new_text ref.add_child(item) return item -func next_task_id() -> int: - task_id += 1 - return task_id +func next_global_task_id() -> int: + global_task_id += 1 + return global_task_id -func save_tasks(): - var save_data = { +func save_tasks(file_id): + var data = { "exported_at": Time.get_datetime_string_from_system(), + "workspace": menu.workspace_name(), "tasks": _save_nested_tasks(root_list), } - var file = FileAccess.open(SAVE_FILE, FileAccess.WRITE) - file.store_line(JSON.stringify(save_data)) + if len(data["tasks"]) == 0: + return false + + var file = FileAccess.open(SAVE_FILE % file_id, FileAccess.WRITE) + file.store_line(JSON.stringify(data)) func _save_nested_tasks(list) -> Array: var tasks = [] for ele in list.get_children(): if ele is Entry and not ele.is_queued_for_deletion(): - tasks.push_back(ele.save()) + tasks.push_back(ele.to_dict()) return tasks -func load_tasks(): - if not FileAccess.file_exists(SAVE_FILE): - return +func load_tasks(file_id): + var save_file = SAVE_FILE % file_id + print_debug("Load file %s" % save_file) + + if not FileAccess.file_exists(save_file): + return false - var file = FileAccess.open(SAVE_FILE, FileAccess.READ) + var file = FileAccess.open(save_file, FileAccess.READ) var json = JSON.new() var parse_result = json.parse(file.get_line()) + file = null + if not parse_result == OK: print("JSON Parse Error: ", json.get_error_message()) - return + return false - var data = json.get_data().get("tasks") - if data is Array and len(data) > 0: - for ele in root_list.get_children(): - ele.queue_free() - _load_nested_tasks(root_list, data) + + var data = json.get_data() + var workspace_title = data.get("workspace") + if workspace_title == null: + workspace_title = "Workspace %d" % file_id + rename_workspace.emit(workspace_title) + + var tasks = data.get("tasks") + if tasks is Array and len(tasks) > 0: + clear_list() + _load_nested_tasks(root_list, tasks) + + return true +func clear_list(): + for ele in root_list.get_children(): + ele.queue_free() + func _load_nested_tasks(ref, list): for ele in list: var item = add_task(ref, ele["name"]) @@ -106,3 +137,19 @@ func _load_nested_tasks(ref, list): _load_nested_tasks(sub_list, ele["tasks"]) if ele.get("collapsed"): item.toggle_children_visibility() + +func load_or_create_workspace(dt_index): + if current_workspace_id == 0 and dt_index == -1: + return + + # Save before changing workspace + save_tasks(current_workspace_id) + + current_workspace_id += dt_index + print_debug("Change workspace to %d" % current_workspace_id) + if load_tasks(current_workspace_id): + return + else: # Workspace does not exist yet + clear_list() + %WorkspaceTitle.text = "Workspace %d" % current_workspace_id + new_input(root_list) diff --git a/lib/menu.gd b/lib/menu.gd new file mode 100644 index 0000000..2396a3a --- /dev/null +++ b/lib/menu.gd @@ -0,0 +1,32 @@ +extends MarginContainer + +func _ready(): + Globals.rename_workspace.connect(_rename_workspace) + %WorkspaceTitle.show() + %WorkspaceEdit.hide() + +func _rename_workspace(new_name): + print_debug("Renaming to %s", new_name) + if new_name: + %WorkspaceTitle.text = new_name + return + else: + %WorkspaceTitle.hide() + %WorkspaceEdit.text = %WorkspaceTitle.text + %WorkspaceEdit.show() + %WorkspaceEdit.grab_focus() + +func _on_prev_workspace_pressed(): + Globals.change_workspace.emit(-1) + +func _on_next_workspace_pressed(): + Globals.change_workspace.emit(+1) + +func _on_workspace_edit_text_submitted(new_text): + %WorkspaceEdit.hide() + %WorkspaceTitle.text = %WorkspaceEdit.text + %WorkspaceTitle.show() + Globals.save_data.emit() + +func workspace_name() -> String: + return %WorkspaceTitle.text diff --git a/lib/menu.tscn b/lib/menu.tscn new file mode 100644 index 0000000..f8de368 --- /dev/null +++ b/lib/menu.tscn @@ -0,0 +1,47 @@ +[gd_scene load_steps=4 format=3 uid="uid://q08a5ojcfou7"] + +[ext_resource type="Script" path="res://lib/menu.gd" id="1_45qa4"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_fcwat"] + +[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_h5oi5"] + +[node name="Menu" type="MarginContainer"] +theme_override_constants/margin_left = 5 +theme_override_constants/margin_top = 5 +theme_override_constants/margin_right = 5 +theme_override_constants/margin_bottom = 5 +script = ExtResource("1_45qa4") + +[node name="Container" type="HBoxContainer" parent="."] +custom_minimum_size = Vector2(0, 40) +layout_mode = 2 + +[node name="PrevWorkspace" type="Button" parent="Container"] +layout_mode = 2 +theme_override_styles/focus = SubResource("StyleBoxEmpty_fcwat") +text = "<" + +[node name="WorkspaceTitle" type="Label" parent="Container"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 +text = "Workspace 0" +horizontal_alignment = 1 +vertical_alignment = 1 + +[node name="WorkspaceEdit" type="LineEdit" parent="Container"] +unique_name_in_owner = true +layout_mode = 2 +size_flags_horizontal = 3 + +[node name="NextWorkspace" type="Button" parent="Container"] +layout_mode = 2 +theme_override_styles/focus = SubResource("StyleBoxEmpty_h5oi5") +shortcut_feedback = false +shortcut_in_tooltip = false +text = ">" + +[connection signal="pressed" from="Container/PrevWorkspace" to="." method="_on_prev_workspace_pressed"] +[connection signal="text_submitted" from="Container/WorkspaceEdit" to="." method="_on_workspace_edit_text_submitted"] +[connection signal="pressed" from="Container/NextWorkspace" to="." method="_on_next_workspace_pressed"]