add kanban
This commit is contained in:
@@ -0,0 +1,55 @@
|
||||
@tool
|
||||
extends VBoxContainer
|
||||
|
||||
|
||||
const __BoardData := preload("../../../data/board.gd")
|
||||
const __CategoryEntry := preload("../../settings/categories/category_entry.gd")
|
||||
const __CategoryData := preload("../../../data/category.gd")
|
||||
const __EditLabel := preload("../../../edit_label/edit_label.gd")
|
||||
|
||||
var board_data: __BoardData
|
||||
|
||||
var randomizer := RandomNumberGenerator.new()
|
||||
|
||||
@onready var category_holder: VBoxContainer = %CategoryHolder
|
||||
@onready var scroll_container: ScrollContainer = %ScrollContainer
|
||||
@onready var add_category_button: Button = %Add
|
||||
@onready var panel_container: PanelContainer = %PanelContainer
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
notification(NOTIFICATION_THEME_CHANGED)
|
||||
randomizer.randomize()
|
||||
add_category_button.pressed.connect(__add_category)
|
||||
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_THEME_CHANGED and not is_part_of_edited_scene():
|
||||
if is_instance_valid(add_category_button):
|
||||
add_category_button.icon = get_theme_icon(&"Add", &"EditorIcons")
|
||||
if is_instance_valid(panel_container):
|
||||
panel_container.add_theme_stylebox_override(&"panel", get_theme_stylebox(&"panel", &"Panel"))
|
||||
|
||||
|
||||
func update() -> void:
|
||||
for category in category_holder.get_children():
|
||||
category.queue_free()
|
||||
|
||||
for uuid in board_data.get_categories():
|
||||
var entry := __CategoryEntry.new()
|
||||
entry.board_data = board_data
|
||||
entry.data_uuid = uuid
|
||||
|
||||
category_holder.add_child(entry)
|
||||
|
||||
|
||||
func __add_category() -> void:
|
||||
var color = Color.from_hsv(randomizer.randf(), randomizer.randf_range(0.8, 1.0), randomizer.randf_range(0.7, 1.0))
|
||||
var data = __CategoryData.new("New category", color)
|
||||
var uuid = board_data.add_category(data)
|
||||
update()
|
||||
for i in category_holder.get_children():
|
||||
if i.data_uuid == uuid:
|
||||
await get_tree().create_timer(0.0).timeout
|
||||
i.grab_focus()
|
||||
i.show_edit(__EditLabel.INTENTION.REPLACE)
|
||||
@@ -0,0 +1 @@
|
||||
uid://brn3wr8cbs41k
|
||||
@@ -0,0 +1,40 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://b2likgss81t0s"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://brn3wr8cbs41k" path="res://addons/kanban_tasks/view/settings/categories/categories.gd" id="1_n36ev"]
|
||||
|
||||
[node name="Categories" type="VBoxContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 3
|
||||
script = ExtResource("1_n36ev")
|
||||
|
||||
[node name="Header" type="HBoxContainer" parent="."]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="\'Available Categories\'" type="Label" parent="Header"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Available Categories:"
|
||||
|
||||
[node name="Add" type="Button" parent="Header"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="PanelContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
follow_focus = true
|
||||
|
||||
[node name="CategoryHolder" type="VBoxContainer" parent="PanelContainer/ScrollContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
@@ -0,0 +1,94 @@
|
||||
@tool
|
||||
extends HBoxContainer
|
||||
|
||||
## Visual representation of a category.
|
||||
|
||||
|
||||
const __EditLabel := preload("../../../edit_label/edit_label.gd")
|
||||
const __BoardData := preload("../../../data/board.gd")
|
||||
const __Singletons := preload("../../../plugin_singleton/singletons.gd")
|
||||
const __Shortcuts := preload("../../shortcuts.gd")
|
||||
|
||||
var title: __EditLabel
|
||||
var delete: Button
|
||||
var color_picker: ColorPickerButton
|
||||
var focus_box: StyleBoxFlat
|
||||
|
||||
var board_data: __BoardData
|
||||
var data_uuid: String
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
set_h_size_flags(SIZE_EXPAND_FILL)
|
||||
focus_mode = FOCUS_ALL
|
||||
title = __EditLabel.new()
|
||||
title.set_h_size_flags(SIZE_EXPAND_FILL)
|
||||
title.text = board_data.get_category(data_uuid).title
|
||||
title.text_changed.connect(__on_title_changed)
|
||||
add_child(title)
|
||||
|
||||
color_picker = ColorPickerButton.new()
|
||||
color_picker.custom_minimum_size.x = 100
|
||||
color_picker.edit_alpha = false
|
||||
color_picker.color = board_data.get_category(data_uuid).color
|
||||
color_picker.focus_mode = Control.FOCUS_NONE
|
||||
color_picker.flat = true
|
||||
color_picker.popup_closed.connect(__on_color_changed)
|
||||
add_child(color_picker)
|
||||
|
||||
delete = Button.new()
|
||||
delete.focus_mode = FOCUS_NONE
|
||||
delete.flat = true
|
||||
delete.disabled = board_data.get_category_count() <= 1
|
||||
delete.pressed.connect(__on_delete)
|
||||
add_child(delete)
|
||||
|
||||
focus_box = StyleBoxFlat.new()
|
||||
focus_box.bg_color = Color(1, 1, 1, 0.1)
|
||||
|
||||
notification(NOTIFICATION_THEME_CHANGED)
|
||||
|
||||
|
||||
func _shortcut_input(event: InputEvent) -> void:
|
||||
if not __Shortcuts.should_handle_shortcut(self):
|
||||
return
|
||||
var shortcuts: __Shortcuts = __Singletons.instance_of(__Shortcuts, self)
|
||||
if not event.is_echo() and event.is_pressed():
|
||||
if shortcuts.rename.matches_event(event):
|
||||
get_viewport().set_input_as_handled()
|
||||
title.show_edit()
|
||||
|
||||
|
||||
func _notification(what) -> void:
|
||||
match(what):
|
||||
NOTIFICATION_THEME_CHANGED when not is_part_of_edited_scene():
|
||||
if is_instance_valid(delete):
|
||||
delete.icon = get_theme_icon(&"Remove", &"EditorIcons")
|
||||
NOTIFICATION_DRAW:
|
||||
if has_focus():
|
||||
focus_box.draw(get_canvas_item(), Rect2(Vector2.ZERO, get_rect().size))
|
||||
|
||||
|
||||
func show_edit(intention: int = title.default_intention) -> void:
|
||||
title.show_edit(intention)
|
||||
|
||||
|
||||
func __on_title_changed(new: String) -> void:
|
||||
board_data.get_category(data_uuid).title = new
|
||||
|
||||
|
||||
func __on_color_changed() -> void:
|
||||
board_data.get_category(data_uuid).color = color_picker.color
|
||||
# Hack to get the tasks to update their color.
|
||||
board_data.layout.changed.emit()
|
||||
|
||||
|
||||
func __on_delete() -> void:
|
||||
board_data.remove_category(data_uuid)
|
||||
|
||||
var fallback_to = board_data.get_categories()[0]
|
||||
for uuid in board_data.get_tasks():
|
||||
if board_data.get_task(uuid).category == data_uuid:
|
||||
board_data.get_task(uuid).category = fallback_to
|
||||
|
||||
get_parent().get_owner().update()
|
||||
@@ -0,0 +1 @@
|
||||
uid://dlf6mdc2al4qm
|
||||
@@ -0,0 +1,150 @@
|
||||
@tool
|
||||
extends VBoxContainer
|
||||
|
||||
|
||||
const __Singletons := preload("../../../plugin_singleton/singletons.gd")
|
||||
const __EditContext := preload("../../edit_context.gd")
|
||||
const __SettingData := preload("../../../data/settings.gd")
|
||||
|
||||
var data: __SettingData = null
|
||||
|
||||
var file_dialog_open_option: CheckBox
|
||||
var file_dialog_save_option: CheckBox
|
||||
var file_dialog_create_option: CheckBox
|
||||
var file_dialog_option_button_group: ButtonGroup
|
||||
|
||||
@onready var show_description_preview: CheckBox = %ShowDescriptionPreview
|
||||
@onready var show_steps_preview: CheckBox = %ShowStepsPreview
|
||||
@onready var show_category_on_board: CheckBox = %ShowCategoriesOnBoard
|
||||
@onready var edit_step_details_exclusively: CheckBox = %EditStepDetailsExclusively
|
||||
@onready var max_displayed_lines_in_description: SpinBox = %MaxDisplayedLinesInDescription
|
||||
@onready var description_on_board: OptionButton = %DescriptionOnBoard
|
||||
# Keep IDs of the items of StepsOnBoard in sync with the values of setting.gd/StepsOnBoard
|
||||
@onready var steps_on_board: OptionButton = %StepsOnBoard
|
||||
@onready var max_steps_on_board: SpinBox = %MaxStepsOnBoard
|
||||
@onready var data_file_path_label: Control = %DataFilePathLabel
|
||||
@onready var data_file_path_container: Control = %DataFilePathContainer
|
||||
@onready var data_file_path: LineEdit = %DataFilePath
|
||||
@onready var data_file_path_button: Button = %DataFilePathButton
|
||||
@onready var file_dialog: FileDialog = %FileDialog
|
||||
@onready var panel_container: PanelContainer = %PanelContainer
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
await get_tree().create_timer(0.0).timeout
|
||||
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
|
||||
data = ctx.settings
|
||||
data.changed.connect(update)
|
||||
update()
|
||||
|
||||
show_description_preview.toggled.connect(func(x): __apply_changes())
|
||||
show_steps_preview.toggled.connect(func(x): __apply_changes())
|
||||
show_category_on_board.toggled.connect(func(x): __apply_changes())
|
||||
edit_step_details_exclusively.toggled.connect(func(x): __apply_changes())
|
||||
max_displayed_lines_in_description.value_changed.connect(func(x): __apply_changes())
|
||||
description_on_board.item_selected.connect(func(x): __apply_changes())
|
||||
steps_on_board.item_selected.connect(func(x): __apply_changes())
|
||||
max_steps_on_board.value_changed.connect(func(x): __apply_changes())
|
||||
if not Engine.is_editor_hint():
|
||||
data_file_path_label.visible = false
|
||||
data_file_path_container.visible = false
|
||||
data_file_path_button.pressed.connect(__open_data_file_path_dialog)
|
||||
|
||||
file_dialog_open_option = CheckBox.new()
|
||||
file_dialog_open_option.text = "Open board from existing file"
|
||||
file_dialog.get_vbox().add_child(file_dialog_open_option)
|
||||
file_dialog_save_option = CheckBox.new()
|
||||
file_dialog_save_option.text = "Save current board to file"
|
||||
file_dialog.get_vbox().add_child(file_dialog_save_option)
|
||||
file_dialog_create_option = CheckBox.new()
|
||||
file_dialog_create_option.text = "Create new board in file"
|
||||
file_dialog.get_vbox().add_child(file_dialog_create_option)
|
||||
file_dialog_option_button_group = ButtonGroup.new()
|
||||
file_dialog_open_option.button_group = file_dialog_option_button_group
|
||||
file_dialog_save_option.button_group = file_dialog_option_button_group
|
||||
file_dialog_create_option.button_group = file_dialog_option_button_group
|
||||
file_dialog_option_button_group.pressed.connect(func (button): __update_file_dialog())
|
||||
file_dialog.get_line_edit().text_changed.connect(func (new_text): __update_file_dialog())
|
||||
file_dialog_open_option.button_pressed = true
|
||||
|
||||
file_dialog.file_selected.connect(__update_editor_data_file)
|
||||
|
||||
notification(NOTIFICATION_THEME_CHANGED)
|
||||
|
||||
|
||||
func _notification(what: int) -> void:
|
||||
if what == NOTIFICATION_THEME_CHANGED and not is_part_of_edited_scene():
|
||||
if is_instance_valid(panel_container):
|
||||
panel_container.add_theme_stylebox_override(&"panel", get_theme_stylebox(&"panel", &"Panel"))
|
||||
|
||||
|
||||
func update() -> void:
|
||||
show_description_preview.button_pressed = data.show_description_preview
|
||||
show_steps_preview.button_pressed = data.show_steps_preview
|
||||
show_category_on_board.button_pressed = data.show_category_on_board
|
||||
edit_step_details_exclusively.button_pressed = data.edit_step_details_exclusively
|
||||
max_displayed_lines_in_description.value = data.max_displayed_lines_in_description
|
||||
max_steps_on_board.value = data.max_steps_on_board
|
||||
|
||||
description_on_board.select(description_on_board.get_item_index(data.description_on_board))
|
||||
steps_on_board.select(steps_on_board.get_item_index(data.steps_on_board))
|
||||
|
||||
data_file_path.text = data.editor_data_file_path
|
||||
|
||||
|
||||
func __open_data_file_path_dialog() -> void:
|
||||
file_dialog_open_option.set_pressed_no_signal(true)
|
||||
file_dialog_save_option.set_pressed_no_signal(false)
|
||||
file_dialog_create_option.set_pressed_no_signal(false)
|
||||
file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE
|
||||
file_dialog.clear_filters()
|
||||
file_dialog.add_filter("*.kanban, *.json", "Kanban Board")
|
||||
file_dialog.popup_centered(file_dialog.size)
|
||||
|
||||
|
||||
func __update_file_dialog() -> void:
|
||||
if file_dialog_save_option.button_pressed:
|
||||
file_dialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE
|
||||
file_dialog.title = file_dialog_save_option.text
|
||||
file_dialog.ok_button_text = "Save"
|
||||
elif file_dialog_create_option.button_pressed:
|
||||
file_dialog.file_mode = FileDialog.FILE_MODE_SAVE_FILE
|
||||
file_dialog.title = file_dialog_create_option.text
|
||||
file_dialog.ok_button_text = "Create"
|
||||
else:
|
||||
file_dialog.file_mode = FileDialog.FILE_MODE_OPEN_FILE
|
||||
file_dialog.title = file_dialog_open_option.text
|
||||
file_dialog.ok_button_text = "Open"
|
||||
|
||||
|
||||
func __update_editor_data_file(path: String) -> void:
|
||||
data_file_path.text = path
|
||||
__apply_changes()
|
||||
|
||||
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
|
||||
if file_dialog_save_option.button_pressed:
|
||||
ctx.save_board.emit()
|
||||
elif file_dialog_create_option.button_pressed:
|
||||
ctx.create_board.emit()
|
||||
else:
|
||||
ctx.reload_board.emit(false)
|
||||
|
||||
|
||||
func __apply_changes() -> void:
|
||||
if data.changed.is_connected(update):
|
||||
data.changed.disconnect(update)
|
||||
|
||||
data.__emit_changed = false
|
||||
data.show_description_preview = show_description_preview.button_pressed
|
||||
data.show_steps_preview = show_steps_preview.button_pressed
|
||||
data.show_category_on_board = show_category_on_board.button_pressed
|
||||
data.edit_step_details_exclusively = edit_step_details_exclusively.button_pressed
|
||||
data.max_displayed_lines_in_description = max_displayed_lines_in_description.value
|
||||
data.description_on_board = description_on_board.get_selected_id()
|
||||
data.steps_on_board = steps_on_board.get_selected_id()
|
||||
data.max_steps_on_board = max_steps_on_board.value
|
||||
data.editor_data_file_path = data_file_path.text
|
||||
data.__emit_changed = true
|
||||
data.__notify_changed()
|
||||
|
||||
data.changed.connect(update)
|
||||
@@ -0,0 +1 @@
|
||||
uid://nnqalkr7jnvx
|
||||
@@ -0,0 +1,157 @@
|
||||
[gd_scene load_steps=2 format=3 uid="uid://due07vdflx4o"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://nnqalkr7jnvx" path="res://addons/kanban_tasks/view/settings/general/general.gd" id="1_8tblh"]
|
||||
|
||||
[node name="General" type="VBoxContainer"]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
script = ExtResource("1_8tblh")
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="."]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="PanelContainer"]
|
||||
layout_mode = 2
|
||||
|
||||
[node name="GridContainer" type="GridContainer" parent="PanelContainer/ScrollContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
columns = 2
|
||||
|
||||
[node name="ShowDescriptionPreviewLabel" type="Label" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Show description preview"
|
||||
|
||||
[node name="ShowDescriptionPreview" type="CheckBox" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
focus_mode = 0
|
||||
text = "On"
|
||||
|
||||
[node name="ShowStepsPreviewLabel" type="Label" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Show steps preview"
|
||||
|
||||
[node name="ShowStepsPreview" type="CheckBox" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
focus_mode = 0
|
||||
text = "On"
|
||||
|
||||
[node name="ShowCategoriesOnBoardLabel" type="Label" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Show categories on board"
|
||||
|
||||
[node name="ShowCategoriesOnBoard" type="CheckBox" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
focus_mode = 0
|
||||
text = "On"
|
||||
|
||||
[node name="EditStepDetailsExclusivelyLabel" type="Label" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Edit step details in fullscreen"
|
||||
|
||||
[node name="EditStepDetailsExclusively" type="CheckBox" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
focus_mode = 0
|
||||
text = "On"
|
||||
|
||||
[node name="DescriptionOnBoardLabel" type="Label" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Description on board"
|
||||
|
||||
[node name="DescriptionOnBoard" type="OptionButton" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
selected = 1
|
||||
item_count = 3
|
||||
popup/item_0/text = "Full description"
|
||||
popup/item_0/id = 0
|
||||
popup/item_1/text = "First line of description"
|
||||
popup/item_1/id = 1
|
||||
popup/item_2/text = "Until first blank line of description"
|
||||
popup/item_2/id = 2
|
||||
|
||||
[node name="MaxDisplayedLinesInDescriptionLabel" type="Label" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Maximum displayed lines in description"
|
||||
|
||||
[node name="MaxDisplayedLinesInDescription" type="SpinBox" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
allow_greater = true
|
||||
|
||||
[node name="StepsOnBoardLabel" type="Label" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
layout_mode = 2
|
||||
text = "Steps on board"
|
||||
|
||||
[node name="StepsOnBoard" type="OptionButton" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
selected = 0
|
||||
item_count = 3
|
||||
popup/item_0/text = "Only open steps"
|
||||
popup/item_0/id = 0
|
||||
popup/item_1/text = "All, but open first"
|
||||
popup/item_1/id = 1
|
||||
popup/item_2/text = "All in original order"
|
||||
popup/item_2/id = 2
|
||||
|
||||
[node name="MaxStepsOnBoardLabel" type="Label" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Maximum steps on board"
|
||||
|
||||
[node name="MaxStepsOnBoard" type="SpinBox" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
value = 2.0
|
||||
allow_greater = true
|
||||
|
||||
[node name="DataFilePathLabel" type="Label" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = "Data file path"
|
||||
|
||||
[node name="DataFilePathContainer" type="HBoxContainer" parent="PanelContainer/ScrollContainer/GridContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
|
||||
[node name="DataFilePath" type="LineEdit" parent="PanelContainer/ScrollContainer/GridContainer/DataFilePathContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "res://kanban_tasks_data.kanban"
|
||||
editable = false
|
||||
|
||||
[node name="DataFilePathButton" type="Button" parent="PanelContainer/ScrollContainer/GridContainer/DataFilePathContainer"]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
text = " ... "
|
||||
|
||||
[node name="FileDialog" type="FileDialog" parent="."]
|
||||
unique_name_in_owner = true
|
||||
title = "Open board from existing file"
|
||||
size = Vector2i(800, 600)
|
||||
ok_button_text = "Open"
|
||||
mode_overrides_title = false
|
||||
file_mode = 0
|
||||
@@ -0,0 +1,34 @@
|
||||
@tool
|
||||
extends AcceptDialog
|
||||
|
||||
|
||||
const __BoardData := preload("../../data/board.gd")
|
||||
const __CategoriesScene := preload("../settings/categories/categories.tscn")
|
||||
const __CategoriesScript := preload("../settings/categories/categories.gd")
|
||||
|
||||
@onready var category_settings: __CategoriesScript = %Categories
|
||||
@onready var stage_settings = %Stages
|
||||
@onready var tab_container: TabContainer = %Settings
|
||||
|
||||
var board_data: __BoardData
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
# Wait for board to set board_data.
|
||||
await get_tree().create_timer(0.0).timeout
|
||||
|
||||
category_settings.board_data = board_data
|
||||
stage_settings.board_data = board_data
|
||||
about_to_popup.connect(stage_settings.update)
|
||||
about_to_popup.connect(category_settings.update)
|
||||
|
||||
|
||||
# Workaround for godotengine/godot#70451
|
||||
func popup_centered_ratio_no_fullscreen(ratio: float = 0.8) -> void:
|
||||
var viewport: Viewport = get_parent().get_viewport()
|
||||
popup(Rect2i(Vector2(viewport.position) + viewport.size / 2.0 - viewport.size * ratio / 2.0, viewport.size * ratio))
|
||||
|
||||
|
||||
func on_theme_changed():
|
||||
# Called from parent since changing this during this nodes theme change notification will create infinite recursion.
|
||||
add_theme_stylebox_override(&"panel", get_theme_stylebox(&"panel", &"EditorSettingsDialog"))
|
||||
@@ -0,0 +1 @@
|
||||
uid://7jskmn63x3pt
|
||||
@@ -0,0 +1,46 @@
|
||||
[gd_scene format=3 uid="uid://dh1yunmhipirg"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://7jskmn63x3pt" path="res://addons/kanban_tasks/view/settings/settings.gd" id="1_4eaw3"]
|
||||
[ext_resource type="PackedScene" uid="uid://due07vdflx4o" path="res://addons/kanban_tasks/view/settings/general/general.tscn" id="1_dk7pg"]
|
||||
[ext_resource type="PackedScene" uid="uid://b2likgss81t0s" path="res://addons/kanban_tasks/view/settings/categories/categories.tscn" id="3_iycb0"]
|
||||
[ext_resource type="PackedScene" uid="uid://dapkpnkm8sow8" path="res://addons/kanban_tasks/view/settings/stages/stages.tscn" id="4_okolg"]
|
||||
|
||||
[node name="Settings" type="AcceptDialog" unique_id=650180224]
|
||||
oversampling_override = 1.0
|
||||
title = "Settings"
|
||||
position = Vector2i(0, 36)
|
||||
size = Vector2i(800, 400)
|
||||
visible = true
|
||||
script = ExtResource("1_4eaw3")
|
||||
|
||||
[node name="Settings" type="TabContainer" parent="." unique_id=690004289]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(600, 300)
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 8.0
|
||||
offset_top = 8.0
|
||||
offset_right = -8.0
|
||||
offset_bottom = -49.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
theme_type_variation = &"TabContainerOdd"
|
||||
current_tab = 0
|
||||
|
||||
[node name="General" parent="Settings" unique_id=2109241999 instance=ExtResource("1_dk7pg")]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
metadata/_tab_index = 0
|
||||
|
||||
[node name="Categories" parent="Settings" unique_id=1569239372 instance=ExtResource("3_iycb0")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
metadata/_tab_index = 1
|
||||
|
||||
[node name="Stages" parent="Settings" unique_id=152864210 instance=ExtResource("4_okolg")]
|
||||
unique_name_in_owner = true
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
metadata/_tab_index = 2
|
||||
@@ -0,0 +1,205 @@
|
||||
@tool
|
||||
extends VBoxContainer
|
||||
|
||||
|
||||
const __Singletons := preload("../../../plugin_singleton/singletons.gd")
|
||||
const __EditContext := preload("../../edit_context.gd")
|
||||
const __BoardData = preload("../../../data/board.gd")
|
||||
const __StageData = preload("../../../data/stage.gd")
|
||||
|
||||
var board_data: __BoardData
|
||||
|
||||
var stylebox_n: StyleBoxFlat
|
||||
var stylebox_hp: StyleBoxFlat
|
||||
|
||||
@onready var column_holder: HBoxContainer = %ColumnHolder
|
||||
@onready var column_add: Button = %AddColumn
|
||||
@onready var warning_sign: Button = %WarningSign
|
||||
@onready var warn_about_empty_deletion: CheckBox = %WarnAboutEmptyDeletion
|
||||
@onready var width_spin_box: SpinBox = %WidthSpinBox
|
||||
@onready var confirm_not_empty: ConfirmationDialog = %ConfirmNotEmpty
|
||||
@onready var confirm_empty: ConfirmationDialog = %ConfirmEmpty
|
||||
@onready var task_destination: OptionButton = %TaskDestination
|
||||
@onready var panel_container: PanelContainer = %PanelContainer
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
column_add.focus_mode = Control.FOCUS_NONE
|
||||
column_add.pressed.connect(__on_add_stage.bind(-1))
|
||||
|
||||
var center_container := CenterContainer.new()
|
||||
center_container.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
center_container.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
column_add.add_child(center_container)
|
||||
|
||||
var plus := TextureRect.new()
|
||||
plus.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
center_container.add_child(plus)
|
||||
|
||||
notification(NOTIFICATION_THEME_CHANGED)
|
||||
|
||||
await get_tree().create_timer(0.0).timeout
|
||||
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
|
||||
ctx.settings.changed.connect(__settings_changed)
|
||||
|
||||
warn_about_empty_deletion.toggled.connect(__apply_settings_changes)
|
||||
width_spin_box.value_changed.connect(__apply_settings_changes)
|
||||
|
||||
|
||||
func _notification(what) -> void:
|
||||
if what == NOTIFICATION_THEME_CHANGED and not is_part_of_edited_scene():
|
||||
stylebox_n = get_theme_stylebox(&"normal", &"Button").duplicate()
|
||||
stylebox_n.set_border_width_all(1)
|
||||
stylebox_n.border_color = Color8(32, 32, 32, 255)
|
||||
|
||||
stylebox_hp = get_theme_stylebox(&"read_only", &"LineEdit").duplicate()
|
||||
stylebox_hp.set_border_width_all(1)
|
||||
stylebox_hp.border_color = Color8(32, 32, 32, 128)
|
||||
|
||||
if is_instance_valid(column_add):
|
||||
column_add.get_child(0).get_child(0).texture = get_theme_icon(&"Add", &"EditorIcons")
|
||||
column_add.add_theme_stylebox_override(&"normal", stylebox_n)
|
||||
column_add.add_theme_stylebox_override(&"hover", stylebox_hp)
|
||||
column_add.add_theme_stylebox_override(&"pressed", stylebox_hp)
|
||||
if is_instance_valid(warning_sign):
|
||||
warning_sign.icon = get_theme_icon(&"NodeWarning", &"EditorIcons")
|
||||
if is_instance_valid(panel_container):
|
||||
panel_container.add_theme_stylebox_override(&"panel", get_theme_stylebox(&"panel", &"Panel"))
|
||||
|
||||
|
||||
func update() -> void:
|
||||
if not board_data.layout.changed.is_connected(update):
|
||||
board_data.layout.changed.connect(update)
|
||||
|
||||
var too_high = false
|
||||
for column in board_data.layout.columns:
|
||||
if len(column) > 3:
|
||||
too_high = true
|
||||
warning_sign.visible = too_high or len(board_data.layout.columns) > 4
|
||||
|
||||
for child in column_holder.get_children():
|
||||
child.queue_free()
|
||||
|
||||
var index = 0
|
||||
for column in board_data.layout.columns:
|
||||
var column_entry := VBoxContainer.new()
|
||||
column_entry.add_theme_constant_override(&"separation", 5)
|
||||
column_holder.add_child(column_entry)
|
||||
|
||||
for stage in column:
|
||||
var stage_entry := Button.new()
|
||||
stage_entry.tooltip_text = board_data.get_stage(stage).title
|
||||
stage_entry.focus_mode = Control.FOCUS_NONE
|
||||
stage_entry.set_v_size_flags(SIZE_EXPAND_FILL)
|
||||
stage_entry.custom_minimum_size = Vector2i(70, 50)
|
||||
stage_entry.add_theme_stylebox_override(&"normal", stylebox_n)
|
||||
stage_entry.add_theme_stylebox_override(&"hover", stylebox_hp)
|
||||
stage_entry.add_theme_stylebox_override(&"pressed", stylebox_hp)
|
||||
stage_entry.add_theme_stylebox_override(&"disabled", stylebox_hp)
|
||||
stage_entry.pressed.connect(__on_remove_stage.bind(stage))
|
||||
stage_entry.disabled = len(board_data.layout.columns) <= 1 and len(board_data.layout.columns[0]) <= 1
|
||||
column_entry.add_child(stage_entry)
|
||||
|
||||
var center_container := CenterContainer.new()
|
||||
center_container.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
center_container.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
stage_entry.add_child(center_container)
|
||||
|
||||
var remove := TextureRect.new()
|
||||
remove.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
remove.texture = get_theme_icon(&"Remove", &"EditorIcons")
|
||||
center_container.add_child(remove)
|
||||
|
||||
var add = Button.new()
|
||||
add.custom_minimum_size = Vector2i(70, 40)
|
||||
add.focus_mode = Control.FOCUS_NONE
|
||||
add.pressed.connect(__on_add_stage.bind(index))
|
||||
add.add_theme_stylebox_override(&"normal", stylebox_n)
|
||||
add.add_theme_stylebox_override(&"hover", stylebox_hp)
|
||||
add.add_theme_stylebox_override(&"pressed", stylebox_hp)
|
||||
column_entry.add_child(add)
|
||||
|
||||
var center_container = CenterContainer.new()
|
||||
center_container.set_anchors_preset(Control.PRESET_FULL_RECT)
|
||||
center_container.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
add.add_child(center_container)
|
||||
|
||||
var plus := TextureRect.new()
|
||||
plus.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
center_container.add_child(plus)
|
||||
plus.texture = get_theme_icon(&"Add", &"EditorIcons")
|
||||
|
||||
index += 1
|
||||
|
||||
|
||||
func __on_add_stage(column: int) -> void:
|
||||
var data = __StageData.new("New Stage")
|
||||
var uuid = board_data.add_stage(data, true)
|
||||
|
||||
var columns = board_data.layout.columns
|
||||
if column < len(board_data.layout.columns) and column >= 0:
|
||||
columns[column].append(uuid)
|
||||
else:
|
||||
columns.append(PackedStringArray([uuid]))
|
||||
board_data.layout.columns = columns
|
||||
|
||||
|
||||
func __on_remove_stage(uuid: String) -> void:
|
||||
if len(board_data.get_stage(uuid).tasks) == 0:
|
||||
if warn_about_empty_deletion.button_pressed:
|
||||
if confirm_empty.confirmed.is_connected(__remove_stage):
|
||||
confirm_empty.confirmed.disconnect(__remove_stage)
|
||||
confirm_empty.confirmed.connect(__remove_stage.bind(uuid))
|
||||
confirm_empty.popup_centered()
|
||||
else:
|
||||
__remove_stage(uuid)
|
||||
else:
|
||||
__update_task_destination(uuid)
|
||||
if confirm_not_empty.confirmed.is_connected(__remove_stage):
|
||||
confirm_not_empty.confirmed.disconnect(__remove_stage)
|
||||
confirm_not_empty.confirmed.connect(__remove_stage.bind(uuid))
|
||||
confirm_not_empty.popup_centered()
|
||||
|
||||
|
||||
func __update_task_destination(uuid: String) -> void:
|
||||
task_destination.clear()
|
||||
for stage in board_data.get_stages():
|
||||
if stage != uuid:
|
||||
task_destination.add_item(board_data.get_stage(stage).title)
|
||||
task_destination.set_item_metadata(-1, stage)
|
||||
|
||||
|
||||
func __remove_stage(uuid: String) -> void:
|
||||
if len(board_data.get_stage(uuid).tasks) > 0:
|
||||
var old_tasks = board_data.get_stage(uuid).tasks
|
||||
var new_tasks = board_data.get_stage(task_destination.get_selected_metadata()).tasks
|
||||
for task in old_tasks.duplicate():
|
||||
old_tasks.erase(task)
|
||||
new_tasks.append(task)
|
||||
board_data.get_stage(uuid).tasks = old_tasks
|
||||
board_data.get_stage(task_destination.get_selected_metadata()).tasks = new_tasks
|
||||
|
||||
board_data.remove_stage(uuid, true)
|
||||
|
||||
var columns = board_data.layout.columns
|
||||
for column in columns.duplicate():
|
||||
if uuid in column:
|
||||
column.remove_at(column.find(uuid))
|
||||
if len(column) == 0:
|
||||
columns.erase(column)
|
||||
|
||||
board_data.layout.columns = columns
|
||||
|
||||
|
||||
func __settings_changed() -> void:
|
||||
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
|
||||
warn_about_empty_deletion.button_pressed = ctx.settings.warn_about_empty_deletion
|
||||
width_spin_box.value = ctx.settings.stages_width
|
||||
|
||||
|
||||
func __apply_settings_changes(warn: bool) -> void:
|
||||
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
|
||||
ctx.settings.changed.disconnect(__settings_changed)
|
||||
ctx.settings.warn_about_empty_deletion = warn
|
||||
ctx.settings.stages_width = int(width_spin_box.value)
|
||||
ctx.settings.changed.connect(__settings_changed)
|
||||
@@ -0,0 +1 @@
|
||||
uid://kwwmdo325o42
|
||||
@@ -0,0 +1,138 @@
|
||||
[gd_scene format=3 uid="uid://dapkpnkm8sow8"]
|
||||
|
||||
[ext_resource type="Script" uid="uid://kwwmdo325o42" path="res://addons/kanban_tasks/view/settings/stages/stages.gd" id="1_1yycq"]
|
||||
|
||||
[node name="Stages" type="VBoxContainer" unique_id=730317252]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
script = ExtResource("1_1yycq")
|
||||
|
||||
[node name="Header" type="HBoxContainer" parent="." unique_id=560617268]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 10
|
||||
|
||||
[node name="\'EditStageLayout\'" type="Label" parent="Header" unique_id=348522360]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
text = "Edit Stage Layout:"
|
||||
|
||||
[node name="\'StageWidth\'" type="Label" parent="Header" unique_id=827952690]
|
||||
layout_mode = 2
|
||||
text = "Stage Width"
|
||||
|
||||
[node name="WidthSpinBox" type="SpinBox" parent="Header" unique_id=2023771662]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 2
|
||||
accessibility_labeled_by_nodes = Array[NodePath]([NodePath("../\'StageWidth\'")])
|
||||
min_value = 200.0
|
||||
max_value = 800.0
|
||||
value = 200.0
|
||||
rounded = true
|
||||
allow_greater = true
|
||||
alignment = 1
|
||||
suffix = "px"
|
||||
select_all_on_focus = true
|
||||
|
||||
[node name="WarnAboutEmptyDeletion" type="CheckBox" parent="Header" unique_id=1017071750]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
focus_mode = 0
|
||||
text = "Warn about empty deletion."
|
||||
|
||||
[node name="PanelContainer" type="PanelContainer" parent="." unique_id=1613118127]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="ScrollContainer" type="ScrollContainer" parent="PanelContainer" unique_id=2013896487]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="CenterContainer" type="CenterContainer" parent="PanelContainer/ScrollContainer" unique_id=1647933709]
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
size_flags_vertical = 3
|
||||
|
||||
[node name="Grid" type="HBoxContainer" parent="PanelContainer/ScrollContainer/CenterContainer" unique_id=1695163191]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 5
|
||||
|
||||
[node name="ColumnHolder" type="HBoxContainer" parent="PanelContainer/ScrollContainer/CenterContainer/Grid" unique_id=1263007802]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 5
|
||||
|
||||
[node name="AddColumn" type="VBoxContainer" parent="PanelContainer/ScrollContainer/CenterContainer/Grid" unique_id=2093623661]
|
||||
layout_mode = 2
|
||||
theme_override_constants/separation = 5
|
||||
|
||||
[node name="AddColumn" type="Button" parent="PanelContainer/ScrollContainer/CenterContainer/Grid/AddColumn" unique_id=1445148106]
|
||||
unique_name_in_owner = true
|
||||
custom_minimum_size = Vector2(40, 105)
|
||||
layout_mode = 2
|
||||
size_flags_vertical = 3
|
||||
focus_mode = 0
|
||||
|
||||
[node name="Empty" type="Button" parent="PanelContainer/ScrollContainer/CenterContainer/Grid/AddColumn" unique_id=1868106499]
|
||||
self_modulate = Color(1, 1, 1, 0)
|
||||
custom_minimum_size = Vector2(40, 40)
|
||||
layout_mode = 2
|
||||
text = "+"
|
||||
|
||||
[node name="Warning" type="Control" parent="PanelContainer" unique_id=1339112746]
|
||||
visible = false
|
||||
layout_mode = 2
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="WarningSign" type="Button" parent="PanelContainer/Warning" unique_id=1578402273]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 0
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
grow_horizontal = 0
|
||||
tooltip_text = "Adding to much stages can overflow the editor.
|
||||
|
||||
Recommended maximum: 4*3"
|
||||
focus_mode = 0
|
||||
flat = true
|
||||
|
||||
[node name="ConfirmNotEmpty" type="ConfirmationDialog" parent="." unique_id=1240101809]
|
||||
unique_name_in_owner = true
|
||||
title = "Delete Stage"
|
||||
size = Vector2i(403, 159)
|
||||
|
||||
[node name="VBoxContainer" type="VBoxContainer" parent="ConfirmNotEmpty" unique_id=1173550062]
|
||||
anchors_preset = 15
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
offset_left = 8.0
|
||||
offset_top = 8.0
|
||||
offset_right = -8.0
|
||||
offset_bottom = -49.0
|
||||
grow_horizontal = 2
|
||||
grow_vertical = 2
|
||||
|
||||
[node name="Label" type="Label" parent="ConfirmNotEmpty/VBoxContainer" unique_id=1210268278]
|
||||
layout_mode = 2
|
||||
text = "You are deleting a stage which has tasks assigned.
|
||||
|
||||
The tasks will be assigned to the following stage:"
|
||||
|
||||
[node name="TaskDestination" type="OptionButton" parent="ConfirmNotEmpty/VBoxContainer" unique_id=1622670225]
|
||||
unique_name_in_owner = true
|
||||
layout_mode = 2
|
||||
size_flags_horizontal = 3
|
||||
|
||||
[node name="ConfirmEmpty" type="ConfirmationDialog" parent="." unique_id=1107424921]
|
||||
unique_name_in_owner = true
|
||||
title = "Delete Stage"
|
||||
size = Vector2i(316, 100)
|
||||
dialog_text = "Do you really want to delete this stage?
|
||||
You can not undo this."
|
||||
Reference in New Issue
Block a user