pokemon-base/addons/imjp94.yafsm/scenes/transition_editors/TransitionEditor.gd
2025-01-26 20:23:56 +01:00

185 lines
6.3 KiB
GDScript

@tool
extends VBoxContainer
const Utils = preload("../../scripts/Utils.gd")
const ConditionEditor = preload("../condition_editors/ConditionEditor.tscn")
const BoolConditionEditor = preload("../condition_editors/BoolConditionEditor.tscn")
const IntegerConditionEditor = preload("../condition_editors/IntegerConditionEditor.tscn")
const FloatConditionEditor = preload("../condition_editors/FloatConditionEditor.tscn")
const StringConditionEditor = preload("../condition_editors/StringConditionEditor.tscn")
@onready var header = $HeaderContainer/Header
@onready var title = $HeaderContainer/Header/Title
@onready var title_icon = $HeaderContainer/Header/Title/Icon
@onready var from = $HeaderContainer/Header/Title/From
@onready var to = $HeaderContainer/Header/Title/To
@onready var condition_count_icon = $HeaderContainer/Header/ConditionCount/Icon
@onready var condition_count_label = $HeaderContainer/Header/ConditionCount/Label
@onready var priority_icon = $HeaderContainer/Header/Priority/Icon
@onready var priority_spinbox = $HeaderContainer/Header/Priority/SpinBox
@onready var add = $HeaderContainer/Header/HBoxContainer/Add
@onready var add_popup_menu = $HeaderContainer/Header/HBoxContainer/Add/PopupMenu
@onready var content_container = $MarginContainer
@onready var condition_list = $MarginContainer/Conditions
var undo_redo
var transition:
set = set_transition
var _to_free
func _init():
_to_free = []
func _ready():
header.gui_input.connect(_on_header_gui_input)
priority_spinbox.value_changed.connect(_on_priority_spinbox_value_changed)
add.pressed.connect(_on_add_pressed)
add_popup_menu.index_pressed.connect(_on_add_popup_menu_index_pressed)
condition_count_icon.texture = get_theme_icon("MirrorX", "EditorIcons")
priority_icon.texture = get_theme_icon("AnimationTrackGroup", "EditorIcons")
func _exit_tree():
free_node_from_undo_redo() # Managed by EditorInspector
func _on_header_gui_input(event):
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
toggle_conditions()
func _on_priority_spinbox_value_changed(val: int) -> void:
set_priority(val)
func _on_add_pressed():
Utils.popup_on_target(add_popup_menu, add)
func _on_add_popup_menu_index_pressed(index):
## Handle condition name duplication (4.x changed how duplicates are
## automatically handled and gave a random index instead of a progressive one)
var default_new_condition_name = "Param"
var condition_dup_index = 0
var new_name = default_new_condition_name
for condition_editor in condition_list.get_children():
var condition_name = condition_editor.condition.name
if (condition_name == new_name):
condition_dup_index += 1
new_name = "%s%s" % [default_new_condition_name, condition_dup_index]
var condition
match index:
0: # Trigger
condition = Condition.new(new_name)
1: # Boolean
condition = BooleanCondition.new(new_name)
2: # Integer
condition = IntegerCondition.new(new_name)
3: # Float
condition = FloatCondition.new(new_name)
4: # String
condition = StringCondition.new(new_name)
_:
push_error("Unexpected index(%d) from PopupMenu" % index)
var editor = create_condition_editor(condition)
add_condition_editor_action(editor, condition)
func _on_ConditionEditorRemove_pressed(editor):
remove_condition_editor_action(editor)
func _on_transition_changed(new_transition):
if not new_transition:
return
for condition in transition.conditions.values():
var editor = create_condition_editor(condition)
add_condition_editor(editor, condition)
update_title()
update_condition_count()
update_priority_spinbox_value()
func _on_condition_editor_added(editor):
editor.undo_redo = undo_redo
if not editor.remove.pressed.is_connected(_on_ConditionEditorRemove_pressed):
editor.remove.pressed.connect(_on_ConditionEditorRemove_pressed.bind(editor))
transition.add_condition(editor.condition)
update_condition_count()
func add_condition_editor(editor, condition):
condition_list.add_child(editor)
editor.condition = condition # Must be assigned after enter tree, as assignment would trigger ui code
_on_condition_editor_added(editor)
func remove_condition_editor(editor):
transition.remove_condition(editor.condition.name)
condition_list.remove_child(editor)
_to_free.append(editor) # Freeing immediately after removal will break undo/redo
update_condition_count()
func update_title():
from.text = transition.from
to.text = transition.to
func update_condition_count():
var count = transition.conditions.size()
condition_count_label.text = str(count)
if count == 0:
hide_conditions()
else:
show_conditions()
func update_priority_spinbox_value():
priority_spinbox.value = transition.priority
priority_spinbox.apply()
func set_priority(value):
transition.priority = value
func show_conditions():
content_container.visible = true
func hide_conditions():
content_container.visible = false
func toggle_conditions():
content_container.visible = !content_container.visible
func create_condition_editor(condition):
var editor
if condition is BooleanCondition:
editor = BoolConditionEditor.instantiate()
elif condition is IntegerCondition:
editor = IntegerConditionEditor.instantiate()
elif condition is FloatCondition:
editor = FloatConditionEditor.instantiate()
elif condition is StringCondition:
editor = StringConditionEditor.instantiate()
else:
editor = ConditionEditor.instantiate()
return editor
func add_condition_editor_action(editor, condition):
undo_redo.create_action("Add Transition Condition")
undo_redo.add_do_method(self, "add_condition_editor", editor, condition)
undo_redo.add_undo_method(self, "remove_condition_editor", editor)
undo_redo.commit_action()
func remove_condition_editor_action(editor):
undo_redo.create_action("Remove Transition Condition")
undo_redo.add_do_method(self, "remove_condition_editor", editor)
undo_redo.add_undo_method(self, "add_condition_editor", editor, editor.condition)
undo_redo.commit_action()
func set_transition(t):
if transition != t:
transition = t
_on_transition_changed(t)
# Free nodes cached in UndoRedo stack
func free_node_from_undo_redo():
for node in _to_free:
if is_instance_valid(node):
var history_id = undo_redo.get_object_history_id(node)
undo_redo.get_history_undo_redo(history_id).clear_history(false) # TODO: Should be handled by plugin.gd (Temporary solution as only TransitionEditor support undo/redo)
node.queue_free()
_to_free.clear()