You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
284 lines
9.4 KiB
284 lines
9.4 KiB
6 months ago
|
@tool
|
||
|
extends Control
|
||
|
|
||
|
## Node that manages editors, the toolbar and the sidebar.
|
||
|
|
||
|
signal resource_opened(resource)
|
||
|
signal editor_changed(previous, current)
|
||
|
|
||
|
### References
|
||
|
@onready var hsplit = $HSplit
|
||
|
@onready var sidebar = $HSplit/Sidebar
|
||
|
@onready var editors_holder = $HSplit/VBox/Editors
|
||
|
@onready var toolbar = $HSplit/VBox/Toolbar
|
||
|
@onready var tabbar = $HSplit/VBox/Toolbar/EditorTabBar
|
||
|
|
||
|
var reference_manager: Node:
|
||
|
get:
|
||
|
return get_node("../../ReferenceManager")
|
||
|
|
||
|
## Information on supported resource extensions and registered editors
|
||
|
var current_editor: DialogicEditor = null
|
||
|
var previous_editor: DialogicEditor = null
|
||
|
var editors := {}
|
||
|
var supported_file_extensions := []
|
||
|
var used_resources_cache : Array = []
|
||
|
|
||
|
|
||
|
################################################################################
|
||
|
## REGISTERING EDITORS
|
||
|
################################################################################
|
||
|
|
||
|
## Asks all childs of the editor holder to register
|
||
|
func _ready() -> void:
|
||
|
if owner.get_parent() is SubViewport:
|
||
|
return
|
||
|
|
||
|
tabbar.clear_tabs()
|
||
|
|
||
|
# Load base editors
|
||
|
_add_editor("res://addons/dialogic/Editor/HomePage/home_page.tscn")
|
||
|
_add_editor("res://addons/dialogic/Editor/TimelineEditor/timeline_editor.tscn")
|
||
|
_add_editor("res://addons/dialogic/Editor/CharacterEditor/character_editor.tscn")
|
||
|
|
||
|
# Load custom editors
|
||
|
for indexer in DialogicUtil.get_indexers():
|
||
|
for editor_path in indexer._get_editors():
|
||
|
_add_editor(editor_path)
|
||
|
_add_editor("res://addons/dialogic/Editor/Settings/settings_editor.tscn")
|
||
|
|
||
|
tabbar.tab_clicked.connect(_on_editors_tab_changed)
|
||
|
|
||
|
# Needs to be done here to make sure this node is ready when doing the register calls
|
||
|
for editor in editors_holder.get_children():
|
||
|
editor.editors_manager = self
|
||
|
editor._register()
|
||
|
|
||
|
DialogicResourceUtil.update()
|
||
|
|
||
|
await get_parent().get_parent().ready
|
||
|
await get_tree().process_frame
|
||
|
|
||
|
load_saved_state()
|
||
|
used_resources_cache = DialogicUtil.get_editor_setting('last_resources', [])
|
||
|
sidebar.update_resource_list(used_resources_cache)
|
||
|
|
||
|
find_parent('EditorView').plugin_reference.get_editor_interface().get_file_system_dock().files_moved.connect(_on_file_moved)
|
||
|
find_parent('EditorView').plugin_reference.get_editor_interface().get_file_system_dock().file_removed.connect(_on_file_removed)
|
||
|
|
||
|
hsplit.set("theme_override_constants/separation", get_theme_constant("base_margin", "Editor") * DialogicUtil.get_editor_scale())
|
||
|
|
||
|
|
||
|
func _add_editor(path:String) -> void:
|
||
|
var editor: DialogicEditor = load(path).instantiate()
|
||
|
editors_holder.add_child(editor)
|
||
|
editor.hide()
|
||
|
tabbar.add_tab(editor._get_title(), editor._get_icon())
|
||
|
|
||
|
|
||
|
## Call to register an editor/tab that edits a resource with a custom ending.
|
||
|
func register_resource_editor(resource_extension:String, editor:DialogicEditor) -> void:
|
||
|
editors[editor.name] = {'node':editor, 'buttons':[], 'extension': resource_extension}
|
||
|
supported_file_extensions.append(resource_extension)
|
||
|
editor.resource_saved.connect(_on_resource_saved.bind(editor))
|
||
|
editor.resource_unsaved.connect(_on_resource_unsaved.bind(editor))
|
||
|
|
||
|
|
||
|
## Call to register an editor/tab that doesn't edit a resource
|
||
|
func register_simple_editor(editor:DialogicEditor) -> void:
|
||
|
editors[editor.name] = {'node': editor, 'buttons':[]}
|
||
|
|
||
|
|
||
|
## Call to add an icon button. These buttons are always visible.
|
||
|
func add_icon_button(icon:Texture, tooltip:String, editor:DialogicEditor=null) -> Node:
|
||
|
var button: Button = toolbar.add_icon_button(icon, tooltip)
|
||
|
if editor != null:
|
||
|
editors[editor.name]['buttons'].append(button)
|
||
|
return button
|
||
|
|
||
|
|
||
|
## Call to add a custom action button. Only visible if editor is visible.
|
||
|
func add_custom_button(label:String, icon:Texture, editor:DialogicEditor) -> Node:
|
||
|
var button: Button = toolbar.add_custom_button(label, icon)
|
||
|
editors[editor.name]['buttons'].append(button)
|
||
|
return button
|
||
|
|
||
|
|
||
|
func can_edit_resource(resource:Resource) -> bool:
|
||
|
return resource.resource_path.get_extension() in supported_file_extensions
|
||
|
|
||
|
|
||
|
################################################################################
|
||
|
## OPENING/CLOSING
|
||
|
################################################################################
|
||
|
|
||
|
|
||
|
func _on_editors_tab_changed(tab:int) -> void:
|
||
|
open_editor(editors_holder.get_child(tab))
|
||
|
|
||
|
|
||
|
func edit_resource(resource:Resource, save_previous:bool = true, silent:= false) -> void:
|
||
|
if not resource:
|
||
|
# The resource doesn't exists, show an error
|
||
|
print('[Dialogic] The resource you are trying to edit doesn\'t exists any more.')
|
||
|
return
|
||
|
|
||
|
if current_editor and save_previous:
|
||
|
current_editor._save()
|
||
|
|
||
|
if !resource.resource_path in used_resources_cache:
|
||
|
used_resources_cache.append(resource.resource_path)
|
||
|
sidebar.update_resource_list(used_resources_cache)
|
||
|
|
||
|
## Open the correct editor
|
||
|
var extension: String = resource.resource_path.get_extension()
|
||
|
for editor in editors.values():
|
||
|
if editor.get('extension', '') == extension:
|
||
|
editor['node']._open_resource(resource)
|
||
|
if !silent:
|
||
|
open_editor(editor['node'], false)
|
||
|
if !silent:
|
||
|
resource_opened.emit(resource)
|
||
|
|
||
|
|
||
|
|
||
|
## Only works if there was a different editor opened previously
|
||
|
func toggle_editor(editor) -> void:
|
||
|
if editor.visible:
|
||
|
open_editor(previous_editor, true)
|
||
|
else:
|
||
|
open_editor(editor, true)
|
||
|
|
||
|
|
||
|
## Shows the given editor
|
||
|
func open_editor(editor:DialogicEditor, save_previous: bool = true, extra_info:Variant = null) -> void:
|
||
|
if current_editor and save_previous:
|
||
|
current_editor._save()
|
||
|
|
||
|
if current_editor:
|
||
|
current_editor._close()
|
||
|
current_editor.hide()
|
||
|
|
||
|
if current_editor != previous_editor:
|
||
|
previous_editor = current_editor
|
||
|
|
||
|
editor._open(extra_info)
|
||
|
editor.opened.emit()
|
||
|
current_editor = editor
|
||
|
editor.show()
|
||
|
tabbar.current_tab = editor.get_index()
|
||
|
|
||
|
if editor.current_resource:
|
||
|
var text:String = editor.current_resource.resource_path.get_file()
|
||
|
if editor.current_resource_state == DialogicEditor.ResourceStates.UNSAVED:
|
||
|
text += "(*)"
|
||
|
|
||
|
## This makes custom button editor-specific
|
||
|
## I think it's better without.
|
||
|
|
||
|
save_current_state()
|
||
|
editor_changed.emit(previous_editor, current_editor)
|
||
|
|
||
|
|
||
|
## Rarely used to completely clear an editor.
|
||
|
func clear_editor(editor:DialogicEditor, save:bool = false) -> void:
|
||
|
if save:
|
||
|
editor._save()
|
||
|
|
||
|
editor._clear()
|
||
|
|
||
|
## Shows a file selector. Calls [accept_callable] once accepted
|
||
|
func show_add_resource_dialog(accept_callable:Callable, filter:String = "*", title = "New resource", default_name = "new_character", mode = EditorFileDialog.FILE_MODE_SAVE_FILE) -> void:
|
||
|
find_parent('EditorView').godot_file_dialog(
|
||
|
_on_add_resource_dialog_accepted.bind(accept_callable),
|
||
|
filter,
|
||
|
mode,
|
||
|
title,
|
||
|
default_name,
|
||
|
true,
|
||
|
"Do not use \"'()!;:/\\*# in character or timeline names!"
|
||
|
)
|
||
|
|
||
|
|
||
|
func _on_add_resource_dialog_accepted(path:String, callable:Callable) -> void:
|
||
|
var file_name :String= path.get_file().trim_suffix('.'+path.get_extension())
|
||
|
for i in ['#','&','+',';','(',')','!','*','*','"',"'",'%', '$', ':','.',',']:
|
||
|
file_name = file_name.replace(i, '')
|
||
|
callable.call(path.trim_suffix(path.get_file()).path_join(file_name)+'.'+path.get_extension())
|
||
|
|
||
|
|
||
|
## Called by the plugin.gd script on CTRL+S or Debug Game start
|
||
|
func save_current_resource() -> void:
|
||
|
current_editor._save()
|
||
|
|
||
|
|
||
|
## Change the resource state
|
||
|
func _on_resource_saved(editor:DialogicEditor):
|
||
|
sidebar.set_unsaved_indicator(true)
|
||
|
|
||
|
|
||
|
## Change the resource state
|
||
|
func _on_resource_unsaved(editor:DialogicEditor):
|
||
|
sidebar.set_unsaved_indicator(false)
|
||
|
|
||
|
|
||
|
## Tries opening the last resource
|
||
|
func load_saved_state() -> void:
|
||
|
var current_resources: Dictionary = DialogicUtil.get_editor_setting('current_resources', {})
|
||
|
for editor in current_resources.keys():
|
||
|
editors[editor]['node']._open_resource(load(current_resources[editor]))
|
||
|
|
||
|
var current_editor: String = DialogicUtil.get_editor_setting('current_editor', 'HomePage')
|
||
|
open_editor(editors[current_editor]['node'])
|
||
|
|
||
|
|
||
|
func save_current_state() -> void:
|
||
|
DialogicUtil.set_editor_setting('current_editor', current_editor.name)
|
||
|
var current_resources: Dictionary = {}
|
||
|
for editor in editors.values():
|
||
|
if editor['node'].current_resource != null:
|
||
|
current_resources[editor['node'].name] = editor['node'].current_resource.resource_path
|
||
|
DialogicUtil.set_editor_setting('current_resources', current_resources)
|
||
|
|
||
|
|
||
|
func _on_file_moved(old_name:String, new_name:String) -> void:
|
||
|
if !old_name.get_extension() in supported_file_extensions:
|
||
|
return
|
||
|
|
||
|
used_resources_cache = DialogicUtil.get_editor_setting('last_resources', [])
|
||
|
if old_name in used_resources_cache:
|
||
|
used_resources_cache.insert(used_resources_cache.find(old_name), new_name)
|
||
|
used_resources_cache.erase(old_name)
|
||
|
|
||
|
sidebar.update_resource_list(used_resources_cache)
|
||
|
|
||
|
for editor in editors:
|
||
|
if editors[editor].node.current_resource != null and editors[editor].node.current_resource.resource_path == old_name:
|
||
|
editors[editor].node.current_resource.take_over_path(new_name)
|
||
|
edit_resource(load(new_name), true, true)
|
||
|
|
||
|
save_current_state()
|
||
|
|
||
|
|
||
|
func _on_file_removed(file_name:String) -> void:
|
||
|
var current_resources: Dictionary = DialogicUtil.get_editor_setting('current_resources', {})
|
||
|
for editor_name in current_resources:
|
||
|
if current_resources[editor_name] == file_name:
|
||
|
clear_editor(editors[editor_name].node, false)
|
||
|
sidebar.update_resource_list()
|
||
|
save_current_state()
|
||
|
|
||
|
|
||
|
|
||
|
################################################################################
|
||
|
## HELPERS
|
||
|
################################################################################
|
||
|
|
||
|
|
||
|
func get_current_editor() -> DialogicEditor:
|
||
|
return current_editor
|
||
|
|
||
|
|
||
|
func _exit_tree():
|
||
|
DialogicUtil.set_editor_setting('last_resources', used_resources_cache)
|