MusicTimer/addons/kanban_tasks/view/details/details.gd
2024-03-22 17:11:54 +01:00

228 lines
7.8 KiB
GDScript

@tool
extends AcceptDialog
const __BoardData := preload("../../data/board.gd")
const __StepData := preload("../../data/step.gd")
const __StepEntry := preload("../details/step_entry.gd")
const __Singletons := preload("../../plugin_singleton/singletons.gd")
const __EditContext := preload("../edit_context.gd")
var board_data: __BoardData
var data_uuid: String
var __step_data: __StepData
@onready var category_select: OptionButton = %Category
@onready var h_split_container: HSplitContainer = %HSplitContainer
@onready var description_edit: TextEdit = %Description
@onready var step_holder: VBoxContainer = %StepHolder
@onready var steps_panel_container: PanelContainer = %PanelContainer
@onready var create_step_edit: LineEdit = %CreateStepEdit
@onready var step_details: VBoxContainer = %StepDetails
@onready var close_step_details_button: Button = %CloseStepDetails
@onready var step_edit: TextEdit = %StepEdit
func _ready() -> void:
about_to_popup.connect(__on_about_to_popup)
create_step_edit.text_submitted.connect(__create_step)
close_step_details_button.pressed.connect(__close_step_details)
notification(NOTIFICATION_THEME_CHANGED)
step_holder.entry_action_triggered.connect(__on_step_action_triggered)
step_holder.entry_move_requesed.connect(__step_move_requesed)
visibility_changed.connect(__save_internal_state)
func _notification(what: int) -> void:
match(what):
NOTIFICATION_THEME_CHANGED:
if is_instance_valid(steps_panel_container):
steps_panel_container.add_theme_stylebox_override(&"panel", get_theme_stylebox(&"panel", &"Tree"))
if is_instance_valid(create_step_edit):
create_step_edit.right_icon = get_theme_icon(&"Add", &"EditorIcons")
if is_instance_valid(close_step_details_button):
close_step_details_button.icon = get_theme_icon(&"Close", &"EditorIcons")
func update() -> void:
if description_edit.text_changed.is_connected(__on_description_changed):
description_edit.text_changed.disconnect(__on_description_changed)
if description_edit.text != board_data.get_task(data_uuid).description:
description_edit.text = board_data.get_task(data_uuid).description
description_edit.text_changed.connect(__on_description_changed)
title = "Task Details: " + board_data.get_task(data_uuid).title
if category_select.item_selected.is_connected(__on_category_selected):
category_select.item_selected.disconnect(__on_category_selected)
category_select.clear()
for uuid in board_data.get_categories():
var i = Image.create(16, 16, false, Image.FORMAT_RGB8)
i.fill(board_data.get_category(uuid).color)
var t = ImageTexture.create_from_image(i)
category_select.add_icon_item(t, board_data.get_category(uuid).title)
category_select.set_item_metadata(-1, uuid)
if uuid == board_data.get_task(data_uuid).category:
category_select.select(category_select.item_count - 1)
category_select.item_selected.connect(__on_category_selected)
step_holder.clear_steps()
for step in board_data.get_task(data_uuid).steps:
step_holder.add_step(step)
for entry in step_holder.get_step_entries():
entry.being_edited = (entry.step_data == __step_data)
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
step_details.visible = is_instance_valid(__step_data)
description_edit.visible = not (ctx.settings.edit_step_details_exclusively and is_instance_valid(__step_data))
if is_instance_valid(__step_data):
if step_edit.text_changed.is_connected(__on_step_details_changed):
step_edit.text_changed.disconnect(__on_step_details_changed)
step_edit.text = __step_data.details
step_edit.text_changed.connect(__on_step_details_changed)
# 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 edit_step_details(step: __StepData) -> void:
if is_instance_valid(__step_data):
__step_data.changed.disconnect(update)
__step_data = step
__step_data.changed.connect(update)
update()
step_edit.set_caret_line(step_edit.get_line_count())
step_edit.set_caret_column(len(step_edit.get_line(step_edit.get_line_count() - 1)))
step_edit.grab_focus.call_deferred()
func move_step_up(step: __StepData) -> void:
var steps = board_data.get_task(data_uuid).steps
if step in steps and steps[0] != step:
var index = steps.find(step)
steps.erase(step)
steps.insert(index - 1, step)
board_data.get_task(data_uuid).steps = steps
update()
func move_step_down(step: __StepData) -> void:
var steps = board_data.get_task(data_uuid).steps
if step in steps and steps[-1] != step:
var index = steps.find(step)
steps.erase(step)
steps.insert(index + 1, step)
board_data.get_task(data_uuid).steps = steps
update()
func delete_step(step: __StepData) -> void:
close_step_details(step)
var steps = board_data.get_task(data_uuid).steps
if step in steps:
steps.erase(step)
board_data.get_task(data_uuid).steps = steps
update()
func close_step_details(step: __StepData) -> void:
if __step_data == step:
__close_step_details()
func __on_step_action_triggered(entry: __StepEntry, action: __StepEntry.Actions) -> void:
match action:
__StepEntry.Actions.EDIT_HARD:
edit_step_details(entry.step_data)
__StepEntry.Actions.EDIT_SOFT:
if is_instance_valid(__step_data):
edit_step_details(entry.step_data)
__StepEntry.Actions.CLOSE:
close_step_details(entry.step_data)
__StepEntry.Actions.DELETE:
delete_step(entry.step_data)
__StepEntry.Actions.MOVE_UP:
move_step_up(entry.step_data)
__StepEntry.Actions.MOVE_DOWN:
move_step_down(entry.step_data)
func __step_move_requesed(moved_entry: __StepEntry, target_entry: __StepEntry, move_after_target: bool) -> void:
var steps = board_data.get_task(data_uuid).steps
var moved_idx = steps.find(moved_entry.step_data)
var target_idx = steps.find(target_entry.step_data)
if moved_idx < 0 or target_idx < 0 or moved_idx == target_idx:
return
steps.erase(moved_entry.step_data)
if moved_idx < target_idx:
target_idx -= 1
if move_after_target:
steps.insert(target_idx + 1, moved_entry.step_data)
else:
steps.insert(target_idx, moved_entry.step_data)
board_data.get_task(data_uuid).steps = steps
update()
func __load_internal_state() -> void:
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
if ctx.settings.internal_states.has("details_editor_step_holder_width"):
h_split_container.split_offset = ctx.settings.internal_states["details_editor_step_holder_width"]
func __save_internal_state() -> void:
if not visible:
var ctx: __EditContext = __Singletons.instance_of(__EditContext, self)
ctx.settings.set_internal_state("details_editor_step_holder_width", h_split_container.split_offset)
func __close_step_details() -> void:
__step_data.changed.disconnect(update)
__step_data = null
update()
func __on_step_details_changed() -> void:
if __step_data.changed.is_connected(update):
__step_data.changed.disconnect(update)
__step_data.details = step_edit.text
__step_data.changed.connect(update)
func __on_about_to_popup() -> void:
if is_instance_valid(__step_data):
__close_step_details()
update()
__load_internal_state()
if board_data.get_task(data_uuid).description.is_empty():
description_edit.grab_focus.call_deferred()
func __on_description_changed() -> void:
board_data.get_task(data_uuid).description = description_edit.text
func __on_category_selected(index: int) -> void:
board_data.get_task(data_uuid).category = category_select.get_item_metadata(index)
func __create_step(text: String) -> void:
if text.is_empty():
return
var task = board_data.get_task(data_uuid)
var data = __StepData.new(text)
task.add_step(data)
create_step_edit.text = ""
update()
if is_instance_valid(__step_data):
for step in step_holder.get_step_entries():
if step.step_data == data:
step.grab_focus.call_deferred()