This commit is contained in:
kobewi 2022-02-01 00:56:02 +01:00
commit fa7c9a5e65
15 changed files with 468 additions and 0 deletions

4
.gitattributes vendored Normal file
View File

@ -0,0 +1,4 @@
.gitattributes export-ignore
LICENSE.txt export-ignore
README.md export-ignore
Media export-ignore

21
LICENSE.txt Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Tomek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

BIN
Media/Icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
Media/ReadmeShowcase.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
Media/ReadmeUndo.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

BIN
Media/Screenshot1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

15
README.md Normal file
View File

@ -0,0 +1,15 @@
# <img src="https://github.com/KoBeWi/Godot-Simple-TODO/blob/master/Media/Icon.png" width="64" height="64"> Godot Simple TODO
This simple plugin that lets you take random notes and organize them in named columns (which also count number of items). If you like putting your TODO lists in a text file, but they are hundreds of lines long and you start thinking that it's maybe too big, this plugin is for you. It's like kanban board, but without unnecessary features.
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)
The plugin has full undo support.
![](https://github.com/KoBeWi/Godot-Simple-TODO/blob/master/Media/ReadmeUndo.gif)
## Data
Data of your columns is stored in a simple .cfg file. You can edit it by hand (the item names don't matter btw), but do so only when the plugin is not active. The plugin automatically saves all your changes. You can change the file where data is stored by modifying `DATA_FILE` constant in `SimpleTODO.gd`.

View File

@ -0,0 +1,84 @@
tool
extends EditorPlugin
const DATA_FILE = "res://TODO.cfg"
var todo_screen: Control
var is_loading: bool
func get_plugin_name():
return "TODO"
func get_plugin_icon():
return get_editor_interface().get_base_control().get_icon("Node", "EditorIcons")
func has_main_screen() -> bool:
return true
func _enter_tree():
todo_screen = preload("res://addons/SimpleTODO/TODO.tscn").instance()
todo_screen.hide()
add_to_group("__todo_plugin__")
get_editor_interface().get_editor_viewport().add_child(todo_screen)
load_data()
func _ready() -> void:
set_process_input(false)
func _exit_tree():
todo_screen.queue_free()
func make_visible(visible: bool) -> void:
todo_screen.visible = visible
set_process_input(visible)
func _input(event: InputEvent) -> void:
if event is InputEventKey:
if event.pressed:
if event.control:
if event.scancode == KEY_Z:
todo_screen.undo_redo.undo()
get_viewport().set_input_as_handled()
elif event.scancode == KEY_Y:
todo_screen.undo_redo.redo()
get_viewport().set_input_as_handled()
func save_data():
if is_loading:
return
var data = ConfigFile.new()
for column in todo_screen.column_container.get_children():
var section = column.name_edit.text
if column.item_container.get_child_count() > 0:
for item in column.item_container.get_children():
data.set_value(section, str("item", item.get_index()), item.text_field.text)
else:
data.set_value(section, "__none__", "null")
data.save(DATA_FILE)
func load_data():
var data = ConfigFile.new()
data.load(DATA_FILE)
is_loading = true
for section in data.get_sections():
var column = todo_screen.add_column()
column.name_edit.text = section
for item in data.get_section_keys(section):
if item == "__none__":
continue
var column_item = column.add_item()
column_item.text_field.text = data.get_value(section, item)
todo_screen.undo_redo.clear_history()
is_loading = false
print("TODO loaded")

40
addons/SimpleTODO/TODO.gd Normal file
View File

@ -0,0 +1,40 @@
tool
extends VBoxContainer
onready var column_container = $ScrollContainer/Columns
var undo_redo: UndoRedo
func _ready() -> void:
undo_redo = UndoRedo.new()
func add_column(from_button := false) -> Control:
var column = preload("res://addons/SimpleTODO/TODOColumn.tscn").instance()
column.undo_redo = undo_redo
column.connect("delete", self, "delete_column", [column])
undo_redo.create_action("Add Column")
undo_redo.add_do_method(column_container, "add_child", column)
undo_redo.add_do_reference(column)
undo_redo.add_do_method(self, "request_save")
undo_redo.add_undo_method(column_container, "remove_child", column)
undo_redo.add_undo_method(self, "request_save")
undo_redo.commit_action()
if from_button:
column.get_node("VBoxContainer/HBoxContainer2/Name").call_deferred("grab_focus")
column.get_node("VBoxContainer/HBoxContainer2/Name").call_deferred("select_all")
return column
func delete_column(column):
undo_redo.create_action("Delete Column")
undo_redo.add_do_method(column_container, "remove_child", column)
undo_redo.add_do_method(self, "request_save")
undo_redo.add_undo_method(column_container, "add_child", column)
undo_redo.add_undo_reference(column)
undo_redo.add_undo_method(self, "request_save")
undo_redo.commit_action()
func request_save() -> void:
get_tree().get_nodes_in_group("__todo_plugin__").front().save_data()

View File

@ -0,0 +1,39 @@
[gd_scene load_steps=2 format=2]
[ext_resource path="res://addons/SimpleTODO/TODO.gd" type="Script" id=1]
[node name="TODO" type="VBoxContainer"]
anchor_right = 1.0
anchor_bottom = 1.0
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="PanelContainer" type="PanelContainer" parent="."]
margin_right = 1024.0
margin_bottom = 34.0
[node name="Button" type="Button" parent="PanelContainer"]
margin_left = 467.0
margin_top = 7.0
margin_right = 556.0
margin_bottom = 27.0
size_flags_horizontal = 4
text = "Add column"
[node name="ScrollContainer" type="ScrollContainer" parent="."]
margin_top = 38.0
margin_right = 1024.0
margin_bottom = 600.0
size_flags_vertical = 3
[node name="Columns" type="HBoxContainer" parent="ScrollContainer"]
margin_right = 1024.0
margin_bottom = 562.0
size_flags_horizontal = 3
size_flags_vertical = 3
[connection signal="pressed" from="PanelContainer/Button" to="." method="add_column" binds= [ true ]]

View File

@ -0,0 +1,54 @@
tool
extends PanelContainer
onready var name_edit = $VBoxContainer/HBoxContainer2/Name
onready var item_container = $VBoxContainer/ScrollContainer/Items
onready var counter = $VBoxContainer/HBoxContainer2/Counter
onready var delete_button = $VBoxContainer/HBoxContainer/DeleteColumn
onready var timer = $Timer
var undo_redo: UndoRedo
signal delete
func _ready() -> void:
delete_button.icon = get_icon("Remove", "EditorIcons")
counter.rect_min_size.x = delete_button.get_minimum_size().x
func add_item(from_button := false) -> Control:
var item = preload("res://addons/SimpleTODO/TODOItem.tscn").instance()
item.connect("delete", self, "delete_item", [item])
undo_redo.create_action("Add Item")
undo_redo.add_do_method(item_container, "add_child", item)
undo_redo.add_do_method(item, "add_child", item)
undo_redo.add_do_reference(item)
undo_redo.add_do_method(self, "request_save")
undo_redo.add_undo_method(item_container, "remove_child", item)
undo_redo.add_undo_method(self, "request_save")
undo_redo.commit_action()
if from_button:
item.get_node("Text").call_deferred("grab_focus")
item.get_node("Text").call_deferred("select_all")
return item
func delete_item(item):
undo_redo.create_action("Delete Item")
undo_redo.add_do_method(item_container, "remove_child", item)
undo_redo.add_do_method(self, "request_save")
undo_redo.add_undo_method(item_container, "add_child", item)
undo_redo.add_undo_reference(item)
undo_redo.add_undo_method(self, "request_save")
undo_redo.commit_action()
func delete_column() -> void:
emit_signal("delete")
func request_save() -> void:
counter.text = str(item_container.get_child_count())
get_tree().get_nodes_in_group("__todo_plugin__").front().save_data()
func name_changed(new_text: String) -> void:
timer.start()

View File

@ -0,0 +1,118 @@
[gd_scene load_steps=5 format=2]
[ext_resource path="res://addons/SimpleTODO/TODOColumn.gd" type="Script" id=1]
[sub_resource type="StyleBoxFlat" id=3]
content_margin_left = 4.0
content_margin_right = 4.0
content_margin_top = 4.0
content_margin_bottom = 4.0
bg_color = Color( 0, 0, 0, 0.501961 )
corner_radius_top_left = 4
corner_radius_top_right = 4
corner_radius_bottom_right = 4
corner_radius_bottom_left = 4
[sub_resource type="Image" id=4]
data = {
"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ),
"format": "LumAlpha8",
"height": 16,
"mipmaps": false,
"width": 16
}
[sub_resource type="ImageTexture" id=2]
flags = 4
flags = 4
image = SubResource( 4 )
size = Vector2( 16, 16 )
[node name="TODOColumn" type="PanelContainer"]
margin_right = 400.0
margin_bottom = 480.0
rect_min_size = Vector2( 400, 0 )
size_flags_vertical = 0
custom_styles/panel = SubResource( 3 )
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="VBoxContainer" type="VBoxContainer" parent="."]
margin_left = 4.0
margin_top = 4.0
margin_right = 396.0
margin_bottom = 476.0
rect_min_size = Vector2( 200, 0 )
[node name="HBoxContainer2" type="HBoxContainer" parent="VBoxContainer"]
margin_right = 392.0
margin_bottom = 24.0
[node name="Name" type="LineEdit" parent="VBoxContainer/HBoxContainer2"]
margin_right = 360.0
margin_bottom = 24.0
size_flags_horizontal = 3
text = "Column name"
[node name="Counter" type="Label" parent="VBoxContainer/HBoxContainer2"]
margin_left = 364.0
margin_top = 5.0
margin_right = 392.0
margin_bottom = 19.0
rect_min_size = Vector2( 28, 0 )
text = "0"
align = 1
[node name="HSeparator" type="HSeparator" parent="VBoxContainer"]
margin_top = 28.0
margin_right = 392.0
margin_bottom = 32.0
[node name="ScrollContainer" type="ScrollContainer" parent="VBoxContainer"]
margin_top = 36.0
margin_right = 392.0
margin_bottom = 438.0
size_flags_vertical = 3
scroll_horizontal_enabled = false
scroll_vertical_enabled = false
[node name="Items" type="VBoxContainer" parent="VBoxContainer/ScrollContainer"]
margin_right = 392.0
margin_bottom = 402.0
size_flags_horizontal = 3
size_flags_vertical = 3
[node name="HSeparator2" type="HSeparator" parent="VBoxContainer"]
margin_top = 442.0
margin_right = 392.0
margin_bottom = 446.0
[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer"]
margin_top = 450.0
margin_right = 392.0
margin_bottom = 472.0
[node name="AddItem" type="Button" parent="VBoxContainer/HBoxContainer"]
margin_right = 360.0
margin_bottom = 22.0
hint_tooltip = "Add item"
size_flags_horizontal = 3
text = "+"
[node name="DeleteColumn" type="Button" parent="VBoxContainer/HBoxContainer"]
margin_left = 364.0
margin_right = 392.0
margin_bottom = 22.0
hint_tooltip = "Delete column"
icon = SubResource( 2 )
[node name="Timer" type="Timer" parent="."]
wait_time = 0.5
one_shot = true
[connection signal="text_changed" from="VBoxContainer/HBoxContainer2/Name" to="." method="name_changed"]
[connection signal="pressed" from="VBoxContainer/HBoxContainer/AddItem" to="." method="add_item" binds= [ true ]]
[connection signal="pressed" from="VBoxContainer/HBoxContainer/DeleteColumn" to="." method="delete_column"]
[connection signal="timeout" from="Timer" to="." method="request_save"]

View File

@ -0,0 +1,21 @@
tool
extends HBoxContainer
onready var text_field = $Text
onready var label_hack = $Text/HackLabel
signal delete
func _ready() -> void:
get_node("Button").icon = get_icon("Remove", "EditorIcons")
call_deferred("text_changed")
func delete_pressed() -> void:
emit_signal("delete")
func request_save() -> void:
get_tree().get_nodes_in_group("__todo_plugin__").front().save_data()
func text_changed() -> void:
label_hack.text = text_field.text
text_field.rect_min_size.y = label_hack.get_minimum_size().y + 8

View File

@ -0,0 +1,65 @@
[gd_scene load_steps=4 format=2]
[ext_resource path="res://addons/SimpleTODO/TODOItem.gd" type="Script" id=1]
[sub_resource type="Image" id=3]
data = {
"data": PoolByteArray( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ),
"format": "LumAlpha8",
"height": 16,
"mipmaps": false,
"width": 16
}
[sub_resource type="ImageTexture" id=2]
flags = 4
flags = 4
image = SubResource( 3 )
size = Vector2( 16, 16 )
[node name="TODOItem" type="HBoxContainer"]
margin_right = 480.0
margin_bottom = 36.0
script = ExtResource( 1 )
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Text" type="TextEdit" parent="."]
margin_right = 448.0
margin_bottom = 36.0
rect_min_size = Vector2( 0, 22 )
size_flags_horizontal = 3
text = "TODO"
wrap_enabled = true
[node name="HackLabel" type="Label" parent="Text"]
anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
margin_left = -224.0
margin_top = 80.0
margin_right = 122.0
margin_bottom = 160.0
text = "TODO"
autowrap = true
__meta__ = {
"_edit_use_anchors_": false
}
[node name="Button" type="Button" parent="."]
margin_left = 452.0
margin_right = 480.0
margin_bottom = 36.0
hint_tooltip = "Delete item"
icon = SubResource( 2 )
[node name="Timer" type="Timer" parent="."]
wait_time = 0.5
one_shot = true
[connection signal="text_changed" from="Text" to="." method="text_changed"]
[connection signal="text_changed" from="Text" to="Timer" method="start"]
[connection signal="pressed" from="Button" to="." method="delete_pressed"]
[connection signal="timeout" from="Timer" to="." method="request_save"]

View File

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