Improvements

- Added column filter
- Added "marker" functionality (right-click item's drag panel to toggle mark)
- Column loading is deferred for better performance
This commit is contained in:
kobewi 2023-05-26 08:30:13 +02:00
parent 8f0f90c7b7
commit b35e5d9b8b
11 changed files with 125 additions and 35 deletions

BIN
Media/ReadmeFilter.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

BIN
Media/ReadmeMarker.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

View File

@ -4,15 +4,23 @@ This simple plugin that lets you take random notes and organize them in named co
Just enable it to get a new editor screen called "TODO" where you can create columns, where you can create random labels where you can put any text. Simple as that. Just enable it to get a new editor screen called "TODO" where you can create columns, where you can create random labels where you can put any text. Simple as that.
![](https://github.com/KoBeWi/Godot-Simple-TODO/blob/master/Media/ReadmeShowcase.gif) ![](Media/ReadmeShowcase.gif)
The plugin has full undo support. The plugin has full undo support.
![](https://github.com/KoBeWi/Godot-Simple-TODO/blob/master/Media/ReadmeUndo.gif) ![](Media/ReadmeUndo.gif)
And drag and drop support (contributed by [@Nukiloco](https://github.com/Nukiloco)). And drag and drop support (contributed by [@Nukiloco](https://github.com/Nukiloco)).
![](https://github.com/KoBeWi/Godot-Simple-TODO/blob/master/Media/ReadmeDragAndDrop.gif) ![](Media/ReadmeDragAndDrop.gif)
You can filter items.
![](Media/ReadmeFilter.gif)
There is also a simple "marker" function. You can right-click the item's drag field to leave a temporary visual marker. The marker is not saved, it's only meant to easier keep track of the item you are currently working on.
![](Media/ReadmeMarker.gif)
## Data ## Data

View File

@ -2,9 +2,9 @@
extends EditorPlugin extends EditorPlugin
const DATA_FILE = "res://TODO.cfg" const DATA_FILE = "res://TODO.cfg"
var pending_columns: Array[Control]
var todo_screen: Control var todo_screen: Control
var is_loading: bool
func _get_plugin_name(): func _get_plugin_name():
return "TODO" return "TODO"
@ -22,11 +22,19 @@ func _enter_tree():
get_editor_interface().get_editor_main_screen().add_child(todo_screen) get_editor_interface().get_editor_main_screen().add_child(todo_screen)
load_data() load_data()
print("TODO loaded")
func _ready() -> void: func _ready() -> void:
set_process_input(false) set_process_input(false)
func _process(delta: float) -> void:
if pending_columns.is_empty():
set_process(false)
print("TODO loaded")
return
var column = pending_columns.pop_front()
todo_screen.column_container.add_child(column)
func _set_window_layout(configuration: ConfigFile): func _set_window_layout(configuration: ConfigFile):
if configuration.has_section("SimpleTODO"): if configuration.has_section("SimpleTODO"):
var minimized_tabs = configuration.get_value("SimpleTODO", "minimized_tabs") var minimized_tabs = configuration.get_value("SimpleTODO", "minimized_tabs")
@ -68,9 +76,6 @@ func _input(event: InputEvent) -> void:
get_viewport().set_input_as_handled() get_viewport().set_input_as_handled()
func save_data(): func save_data():
if is_loading:
return
var data := ConfigFile.new() var data := ConfigFile.new()
for column in todo_screen.column_container.get_children(): for column in todo_screen.column_container.get_children():
var section = column.header.name_edit.text var section = column.header.name_edit.text
@ -87,19 +92,15 @@ func load_data():
var data := ConfigFile.new() var data := ConfigFile.new()
data.load(DATA_FILE) data.load(DATA_FILE)
is_loading = true
for section in data.get_sections(): for section in data.get_sections():
var column = todo_screen.add_column() var column = todo_screen.create_column()
column.set_name(section) column.ready.connect(column.set_title.bind(section))
pending_columns.append(column)
for item in data.get_section_keys(section): for item in data.get_section_keys(section):
if item == "__none__": if item == "__none__":
continue continue
var column_item = column.add_item() var column_item = column.create_item()
column_item.text_field.text = data.get_value(section, item) column_item.ready.connect(column_item.initialize.bind(data.get_value(section, item), item.to_int()), CONNECT_DEFERRED)
column_item.id = item.to_int() column.ready.connect(column_item.add_to_column.bind(column))
todo_screen.undo_redo.clear_history()
is_loading = false

View File

@ -9,11 +9,13 @@ var plugin: EditorPlugin
var undo_redo: UndoRedo var undo_redo: UndoRedo
var item_placement_holder: Panel var item_placement_holder: Panel
var counter_queued: bool
func _ready() -> void: func _ready() -> void:
undo_redo = UndoRedo.new() undo_redo = UndoRedo.new()
item_placement_holder = create_drag_placement_holder() item_placement_holder = create_drag_placement_holder()
scroll_container.get_v_scroll_bar().value_changed.connect(update_mirror) scroll_container.get_v_scroll_bar().value_changed.connect(update_mirror)
update_full_counter()
func update_mirror(v: float): func update_mirror(v: float):
column_mirror.visible = v > column_mirror.get_child(0).size.y column_mirror.visible = v > column_mirror.get_child(0).size.y
@ -29,13 +31,18 @@ func create_drag_placement_holder() -> Panel:
return new_holder return new_holder
func add_column(from_button := false) -> Control: func create_column() -> Control:
var column = preload("res://addons/SimpleTODO/TODOColumn.tscn").instantiate() var column = preload("res://addons/SimpleTODO/TODOColumn.tscn").instantiate()
column.main = self column.main = self
column.plugin = plugin column.plugin = plugin
column.undo_redo = undo_redo column.undo_redo = undo_redo
column.delete.connect(delete_column.bind(column)) column.delete.connect(delete_column.bind(column))
column.counter_updated.connect(update_full_counter)
return column
func add_column(from_button := false) -> Control:
var column := create_column()
undo_redo.create_action("Add Column") undo_redo.create_action("Add Column")
undo_redo.add_do_method(column_container.add_child.bind(column)) undo_redo.add_do_method(column_container.add_child.bind(column))
@ -67,3 +74,19 @@ func request_save() -> void:
func refresh_mirrors(): func refresh_mirrors():
for column in column_container.get_children(): for column in column_container.get_children():
column.update_mirror.call_deferred(0) column.update_mirror.call_deferred(0)
func filter_elements(new_text: String) -> void:
for column in column_container.get_children():
for item in column.item_container.get_children():
item.filter(new_text)
func update_full_counter():
if counter_queued:
return
counter_queued = true
_update_full_counter.call_deferred()
func _update_full_counter():
%Total.text = str("Total: %d" % column_container.get_children().reduce(func(accum: int, column: Node) -> int: return accum + column.item_container.get_child_count(), 0))
counter_queued = false

View File

@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://yf8y5e74vv4o"] [gd_scene load_steps=2 format=3 uid="uid://yf8y5e74vv4o"]
[ext_resource type="Script" path="res://addons/SimpleTODO/TODO.gd" id="1"] [ext_resource type="Script" path="res://addons/SimpleTODO/TODO.gd" id="1_wo5wb"]
[node name="TODO" type="Control"] [node name="TODO" type="Control"]
clip_contents = true clip_contents = true
@ -12,7 +12,7 @@ grow_horizontal = 2
grow_vertical = 2 grow_vertical = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
script = ExtResource("1") script = ExtResource("1_wo5wb")
[node name="VBoxContainer" type="VBoxContainer" parent="."] [node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 1 layout_mode = 1
@ -30,11 +30,40 @@ layout_mode = 2
[node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/PanelContainer"] [node name="VBoxContainer" type="VBoxContainer" parent="VBoxContainer/PanelContainer"]
layout_mode = 2 layout_mode = 2
[node name="Button" type="Button" parent="VBoxContainer/PanelContainer/VBoxContainer"] [node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/PanelContainer/VBoxContainer"]
layout_mode = 2
theme_override_constants/separation = 100
[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/PanelContainer/VBoxContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Total" type="Label" parent="VBoxContainer/PanelContainer/VBoxContainer/HBoxContainer/MarginContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 8
text = "Total: %d"
[node name="MarginContainer2" type="MarginContainer" parent="VBoxContainer/PanelContainer/VBoxContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="Button" type="Button" parent="VBoxContainer/PanelContainer/VBoxContainer/HBoxContainer/MarginContainer2"]
layout_mode = 2 layout_mode = 2
size_flags_horizontal = 4 size_flags_horizontal = 4
text = "Add column" text = "Add column"
[node name="MarginContainer3" type="MarginContainer" parent="VBoxContainer/PanelContainer/VBoxContainer/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
[node name="LineEdit" type="LineEdit" parent="VBoxContainer/PanelContainer/VBoxContainer/HBoxContainer/MarginContainer3"]
custom_minimum_size = Vector2(400, 0)
layout_mode = 2
size_flags_horizontal = 0
placeholder_text = "Search Items"
clear_button_enabled = true
[node name="ColumnMirror" type="Control" parent="VBoxContainer/PanelContainer/VBoxContainer"] [node name="ColumnMirror" type="Control" parent="VBoxContainer/PanelContainer/VBoxContainer"]
unique_name_in_owner = true unique_name_in_owner = true
visible = false visible = false
@ -52,4 +81,5 @@ layout_mode = 2
size_flags_horizontal = 3 size_flags_horizontal = 3
size_flags_vertical = 3 size_flags_vertical = 3
[connection signal="pressed" from="VBoxContainer/PanelContainer/VBoxContainer/Button" to="." method="add_column" binds= [true]] [connection signal="pressed" from="VBoxContainer/PanelContainer/VBoxContainer/HBoxContainer/MarginContainer2/Button" to="." method="add_column" binds= [true]]
[connection signal="text_changed" from="VBoxContainer/PanelContainer/VBoxContainer/HBoxContainer/MarginContainer3/LineEdit" to="." method="filter_elements"]

View File

@ -23,6 +23,7 @@ var current_drag_item_index := 0
var item_margin := 20 var item_margin := 20
signal delete signal delete
signal counter_updated
func set_minimized(val: bool): func set_minimized(val: bool):
minimized = val minimized = val
@ -67,7 +68,7 @@ func _ready() -> void:
item_container.child_entered_tree.connect(update_counter.unbind(1), CONNECT_DEFERRED) item_container.child_entered_tree.connect(update_counter.unbind(1), CONNECT_DEFERRED)
item_container.child_exiting_tree.connect(update_counter.unbind(1), CONNECT_DEFERRED) item_container.child_exiting_tree.connect(update_counter.unbind(1), CONNECT_DEFERRED)
func set_name(column_name): func set_title(column_name):
header.name_edit.text = column_name header.name_edit.text = column_name
mirror_header.name_edit.text = column_name mirror_header.name_edit.text = column_name
@ -98,12 +99,16 @@ func _process(delta):
position = mouse_position position = mouse_position
func add_item(from_button := false) -> Control: func create_item() -> Control:
var item = preload("res://addons/SimpleTODO/TODOItem.tscn").instantiate() var item = preload("res://addons/SimpleTODO/TODOItem.tscn").instantiate()
item.parent_column = self item.parent_column = self
item.plugin = plugin item.plugin = plugin
item.main = main item.main = main
return item
func add_item(from_button := false) -> Control:
var item := create_item()
undo_redo.create_action("Add Item") undo_redo.create_action("Add Item")
undo_redo.add_do_method(item_container.add_child.bind(item)) undo_redo.add_do_method(item_container.add_child.bind(item))
undo_redo.add_do_reference(item) undo_redo.add_do_reference(item)
@ -124,6 +129,7 @@ func delete_column() -> void:
func update_counter() -> void: func update_counter() -> void:
header.counter.text = str(item_container.get_child_count()) header.counter.text = str(item_container.get_child_count())
mirror_header.counter.text = str(item_container.get_child_count()) mirror_header.counter.text = str(item_container.get_child_count())
counter_updated.emit()
func request_save() -> void: func request_save() -> void:
plugin.save_data() plugin.save_data()

View File

@ -1,7 +1,7 @@
[gd_scene load_steps=4 format=3 uid="uid://bga0tfe37uva2"] [gd_scene load_steps=4 format=3 uid="uid://bga0tfe37uva2"]
[ext_resource type="Script" path="res://addons/SimpleTODO/TODOColumn.gd" id="1"] [ext_resource type="Script" path="res://addons/SimpleTODO/TODOColumn.gd" id="1_6bfuv"]
[ext_resource type="PackedScene" uid="uid://cwcwdmxxpf65e" path="res://addons/SimpleTODO/ColumnHeader.tscn" id="2"] [ext_resource type="PackedScene" uid="uid://cwcwdmxxpf65e" path="res://addons/SimpleTODO/ColumnHeader.tscn" id="2_0fkhl"]
[sub_resource type="StyleBoxFlat" id="3"] [sub_resource type="StyleBoxFlat" id="3"]
content_margin_left = 4.0 content_margin_left = 4.0
@ -18,12 +18,12 @@ corner_radius_bottom_left = 4
custom_minimum_size = Vector2(400, 0) custom_minimum_size = Vector2(400, 0)
size_flags_vertical = 2 size_flags_vertical = 2
theme_override_styles/panel = SubResource("3") theme_override_styles/panel = SubResource("3")
script = ExtResource("1") script = ExtResource("1_6bfuv")
[node name="VBoxContainer" type="VBoxContainer" parent="."] [node name="VBoxContainer" type="VBoxContainer" parent="."]
layout_mode = 2 layout_mode = 2
[node name="Header" parent="VBoxContainer" instance=ExtResource("2")] [node name="Header" parent="VBoxContainer" instance=ExtResource("2_0fkhl")]
unique_name_in_owner = true unique_name_in_owner = true
layout_mode = 2 layout_mode = 2

View File

@ -1,7 +1,7 @@
@tool @tool
extends HBoxContainer extends HBoxContainer
@onready var text_field = $Text @onready var text_field: TextEdit = $Text
@onready var button: Button = $Button @onready var button: Button = $Button
var main: Control var main: Control
@ -19,6 +19,7 @@ var is_dragging := false
var item_margin := 20 var item_margin := 20
var id: int var id: int
var is_marked: bool
func _ready() -> void: func _ready() -> void:
undo_redo = main.undo_redo undo_redo = main.undo_redo
@ -99,7 +100,7 @@ func get_column_item_from_mouse_position() -> Dictionary:
# Handles left click being pressed on the drag panel. # Handles left click being pressed on the drag panel.
func drag_panel_input(event: InputEvent): func drag_panel_input(event: InputEvent):
if event is InputEventMouseButton: if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed and !is_dragging: if event.button_index == MOUSE_BUTTON_LEFT and event.pressed and not is_dragging:
initial_item_index = get_index() initial_item_index = get_index()
get_parent().remove_child(self) get_parent().remove_child(self)
main.add_child(self) main.add_child(self)
@ -119,6 +120,13 @@ func drag_panel_input(event: InputEvent):
item_placement_holder.visible = true item_placement_holder.visible = true
item_placement_holder.custom_minimum_size = custom_minimum_size item_placement_holder.custom_minimum_size = custom_minimum_size
item_placement_holder.size = size item_placement_holder.size = size
elif event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
if is_marked:
$DragPanel.modulate = Color.WHITE
is_marked = false
else:
$DragPanel.modulate = Color.RED
is_marked = true
# Handles left click being released. # Handles left click being released.
func _input(event: InputEvent): func _input(event: InputEvent):
@ -175,3 +183,16 @@ func delete_item():
undo_redo.add_undo_method(parent_column.item_container.move_child.bind(self, get_index())) undo_redo.add_undo_method(parent_column.item_container.move_child.bind(self, get_index()))
undo_redo.add_undo_method(parent_column.request_save) undo_redo.add_undo_method(parent_column.request_save)
undo_redo.commit_action() undo_redo.commit_action()
func filter(text: String):
if text.is_empty() or text_field.text.contains(text):
show()
else:
hide()
func initialize(text: String, p_id: int):
text_field.text = text
id = p_id
func add_to_column(column: Control):
column.item_container.add_child(self)

View File

@ -1,14 +1,15 @@
[gd_scene load_steps=2 format=3 uid="uid://bdesiystlxdb2"] [gd_scene load_steps=2 format=3 uid="uid://bdesiystlxdb2"]
[ext_resource type="Script" path="res://addons/SimpleTODO/TODOItem.gd" id="1"] [ext_resource type="Script" path="res://addons/SimpleTODO/TODOItem.gd" id="1_ecqce"]
[node name="TODOItem" type="HBoxContainer"] [node name="TODOItem" type="HBoxContainer"]
mouse_filter = 2 mouse_filter = 2
script = ExtResource("1") script = ExtResource("1_ecqce")
[node name="DragPanel" type="Panel" parent="."] [node name="DragPanel" type="Panel" parent="."]
custom_minimum_size = Vector2(20, 0) custom_minimum_size = Vector2(20, 0)
layout_mode = 2 layout_mode = 2
tooltip_text = "Right-click to mark/unmark"
mouse_default_cursor_shape = 13 mouse_default_cursor_shape = 13
[node name="Text" type="TextEdit" parent="."] [node name="Text" type="TextEdit" parent="."]

View File

@ -1,7 +1,7 @@
[plugin] [plugin]
name="Simple TODO" name="Simple TODO"
description="Organize random notes in tabs." description="Organize random notes in columns."
author="KoBeWi" author="KoBeWi"
version="1.4" version="1.5"
script="SimpleTODO.gd" script="SimpleTODO.gd"