@tool extends DialogicEditor ## Editor that handles the editing of styles and their layers. var styles: Array[DialogicStyle] = [] var current_style : DialogicStyle = null var default_style := "" var premade_style_parts := {} #region EDITOR MANAGEMENT ################################################################################ func _get_title() -> String: return "Styles" func _get_icon() -> Texture: return load(DialogicUtil.get_module_path('StyleEditor').path_join("styles_icon.svg")) func _register() -> void: editors_manager.register_simple_editor(self) alternative_text = "Change the look of the dialog in your game" func _open(extra_info:Variant = null) -> void: load_style_list() func _close() -> void: save_style_list() save_style() #endregion func _ready() -> void: collect_styles() setup_ui() #region STYLE MANAGEMENT ################################################################################ func collect_styles() -> void: for indexer in DialogicUtil.get_indexers(): for layout in indexer._get_layout_parts(): premade_style_parts[layout['path']] = layout var style_list: Array = ProjectSettings.get_setting('dialogic/layout/style_list', []) for style in style_list: if ResourceLoader.exists(style): var style_res := load(style) if style != null: styles.append(ResourceLoader.load(style, "DialogicStyle")) else: print("[Dialogic] Failed to open style '", style, "'. Some dependency might be broken.") else: print("[Dialogic] Failed to open style '", style, "'. Might have been moved or deleted.") default_style = ProjectSettings.get_setting('dialogic/layout/default_style', 'Default') func save_style_list() -> void: ProjectSettings.set_setting('dialogic/layout/style_list', styles.map(func(style:DialogicStyle): return style.resource_path)) ProjectSettings.set_setting('dialogic/layout/default_style', default_style) ProjectSettings.save() func save_style() -> void: if current_style == null: return ResourceSaver.save(current_style) func add_style(file_path:String, style:DialogicStyle, inherits:DialogicStyle= null) -> void: style.resource_path = file_path style.inherits = inherits if style.layers.is_empty() and style.inherits != null: for l in style.get_layer_list(): style.add_layer('', {}) ResourceSaver.save(style, file_path) styles.append(style) if len(styles) == 1: default_style = style.resource_path save_style_list() load_style_list() select_style(style) func delete_style(style:DialogicStyle) -> void: for other_style in styles: if other_style.inherits == style: other_style.realize_inheritance() push_warning('[Dialogic] Style "',other_style.name,'" had to be realized because it inherited "', style.name,'" which was deleted!') if style.resource_path == default_style: default_style = "" styles.erase(style) save_style_list() func delete_style_by_name(style_name:String) -> void: for style in styles: if style.name == style_name: delete_style(style) return func realize_style() -> void: current_style.realize_inheritance() select_style(current_style) #endregion #region USER INTERFACE ################################################################################ func setup_ui() -> void: %AddButton.icon = get_theme_icon("Add", "EditorIcons") %DuplicateButton.icon = get_theme_icon("Duplicate", "EditorIcons") %InheritanceButton.icon = get_theme_icon("GuiDropdown", "EditorIcons") %RemoveButton.icon = get_theme_icon("Remove", "EditorIcons") %EditNameButton.icon = get_theme_icon("Edit", "EditorIcons") %TestStyleButton.icon = get_theme_icon("PlayCustom", "EditorIcons") %MakeDefaultButton.icon = get_theme_icon("Favorites", "EditorIcons") %StyleList.item_selected.connect(_on_stylelist_selected) %AddButton.get_popup().index_pressed.connect(_on_AddStyleMenu_selected) %AddButton.about_to_popup.connect(_on_AddStyleMenu_about_to_popup) %InheritanceButton.get_popup().index_pressed.connect(_on_inheritance_index_pressed) %StyleList.set_drag_forwarding(_on_stylelist_drag, _on_stylelist_can_drop, _on_style_list_drop) %StyleView.hide() %NoStyleView.show() func load_style_list() -> void: var latest: String = DialogicUtil.get_editor_setting('latest_layout_style', 'Default') %StyleList.clear() var idx := 0 for style in styles: %StyleList.add_item(style.name, get_theme_icon("PopupMenu", "EditorIcons")) if style.resource_path == default_style: %StyleList.set_item_icon_modulate(idx, get_theme_color("warning_color", "Editor")) if style.name == latest: %StyleList.select(idx) load_style(style) %StyleList.set_item_tooltip(idx, style.resource_path) %StyleList.set_item_metadata(idx, style) idx += 1 if len(styles) == 0: %StyleView.hide() %NoStyleView.show() elif !%StyleList.is_anything_selected(): %StyleList.select(0) load_style(%StyleList.get_item_metadata(0)) func _on_stylelist_selected(index:int) -> void: load_style(%StyleList.get_item_metadata(index)) func select_style(style:DialogicStyle) -> void: DialogicUtil.set_editor_setting('latest_layout_style', style.name) for idx in range(%StyleList.item_count): if %StyleList.get_item_metadata(idx) == style: %StyleList.select(idx) return func load_style(style:DialogicStyle) -> void: if current_style != null: current_style.changed.disconnect(save_style) save_style() current_style = style if current_style == null: return current_style.changed.connect(save_style) %LayoutStyleName.text = style.name if style.resource_path == default_style: %MakeDefaultButton.tooltip_text = "Is Default" %MakeDefaultButton.disabled = true else: %MakeDefaultButton.tooltip_text = "Make Default" %MakeDefaultButton.disabled = false %StyleEditor.load_style(style) %InheritanceButton.visible = style.inherits_anything() if %InheritanceButton.visible: %InheritanceButton.text = "Inherits " + style.inherits.name DialogicUtil.set_editor_setting('latest_layout_style', style.name) %StyleView.show() %NoStyleView.hide() func _on_AddStyleMenu_about_to_popup() -> void: %AddButton.get_popup().set_item_disabled(3, not %StyleList.is_anything_selected()) func _on_AddStyleMenu_selected(index:int) -> void: # add preset style if index == 2: %StyleBrowserWindow.popup_centered_ratio(0.6) %StyleBrowser.current_type = 1 %StyleBrowser.load_parts() var picked_info: Dictionary = await %StyleBrowserWindow.get_picked_info() if not picked_info.has('style_path'): return if not ResourceLoader.exists(picked_info.style_path): return var new_style: DialogicStyle = load(picked_info.style_path).clone() find_parent('EditorView').godot_file_dialog( add_style_undoable.bind(new_style), '*.tres', EditorFileDialog.FILE_MODE_SAVE_FILE, "Select folder for new style") if index == 3: if %StyleList.get_selected_items().is_empty(): return find_parent('EditorView').godot_file_dialog( add_style_undoable.bind(DialogicStyle.new(), current_style), '*.tres', EditorFileDialog.FILE_MODE_SAVE_FILE, "Select folder for new style") if index == 4: find_parent('EditorView').godot_file_dialog( add_style_undoable.bind(DialogicStyle.new()), '*.tres', EditorFileDialog.FILE_MODE_SAVE_FILE, "Select folder for new style") func add_style_undoable(file_path:String, style:DialogicStyle, inherits:DialogicStyle = null) -> void: style.name = _get_new_name(file_path.get_file().trim_suffix('.'+file_path.get_extension())) var undo_redo: EditorUndoRedoManager = DialogicUtil.get_dialogic_plugin().get_undo_redo() undo_redo.create_action('Add Style', UndoRedo.MERGE_ALL) undo_redo.add_do_method(self, "add_style", file_path, style, inherits) undo_redo.add_do_method(self, "load_style_list") undo_redo.add_undo_method(self, "delete_style", style) undo_redo.add_undo_method(self, "load_style_list") undo_redo.commit_action() DialogicUtil.set_editor_setting('latest_layout_style', style.name) func _on_duplicate_button_pressed(): if !%StyleList.is_anything_selected(): return find_parent('EditorView').godot_file_dialog( add_style_undoable.bind(current_style.clone(), null), '*.tres', EditorFileDialog.FILE_MODE_SAVE_FILE, "Select folder for new style") func _on_remove_button_pressed(): if !%StyleList.is_anything_selected(): return if current_style.name == default_style: push_warning("[Dialogic] You cannot delete the default style!") return delete_style(current_style) load_style_list() func _on_edit_name_button_pressed(): %LayoutStyleName.grab_focus() %LayoutStyleName.select_all() func _on_layout_style_name_text_submitted(new_text:String) -> void: _on_layout_style_name_focus_exited() func _on_layout_style_name_focus_exited(): var new_name :String= %LayoutStyleName.text.strip_edges() if new_name == current_style.name: return for style in styles: if style.name == new_name: %LayoutStyleName.text = current_style.name return current_style.name = new_name DialogicUtil.set_editor_setting('latest_layout_style', new_name) load_style_list() func _on_make_default_button_pressed(): default_style = current_style.resource_path save_style_list() load_style_list() func _on_test_style_button_pressed(): var dialogic_plugin := DialogicUtil.get_dialogic_plugin() # Save the current opened timeline DialogicUtil.set_editor_setting('current_test_style', current_style.name) DialogicUtil.get_dialogic_plugin().get_editor_interface().play_custom_scene("res://addons/dialogic/Editor/TimelineEditor/test_timeline_scene.tscn") await get_tree().create_timer(3).timeout DialogicUtil.set_editor_setting('current_test_style', '') func _on_inheritance_index_pressed(index:int) -> void: if index == 0: realize_style() func _on_start_styling_button_pressed() -> void: var new_style := DialogicUtil.get_fallback_style().clone() find_parent('EditorView').godot_file_dialog( add_style_undoable.bind(new_style), '*.tres', EditorFileDialog.FILE_MODE_SAVE_FILE, "Select folder for new style") #endregion func _on_stylelist_drag(vector:Vector2) -> Variant: return null func _on_stylelist_can_drop(at_position: Vector2, data: Variant) -> bool: if not data is Dictionary: return false if not data.get('type', 's') == 'files': return false for f in data.files: var style := load(f) if style is DialogicStyle: if not style in styles: return true return false func _on_style_list_drop(at_position: Vector2, data: Variant) -> void: for file in data.files: var style := load(file) if style is DialogicStyle: if not style in styles: styles.append(style) save_style_list() load_style_list() #region Helpers func _get_new_name(base_name:String) -> String: var new_name_idx := 1 var found_unique_name := false var new_name := base_name while not found_unique_name: found_unique_name = true for style in styles: if style.name == new_name: new_name_idx += 1 new_name = base_name+" "+str(new_name_idx) found_unique_name = false return new_name #endregion