4 ## Editor for editing character resources.
6 signal character_loaded(resource_path:String)
7 signal portrait_selected()
12 var current_previewed_scene: Variant = null
13 var current_scene_path: String = ""
16 var selected_item: TreeItem
17 var def_portrait_path: String = DialogicUtil.get_module_path('Character').path_join('default_portrait.tscn')
20 ######### EDITOR STUFF and LOADING/SAVING ######################################
22 #region Resource Logic
23 ## Method is called once editors manager is ready to accept registers.
24 func _register() -> void:
25 ## Makes the editor open this when a .dch file is selected.
26 ## Then _open_resource() is called.
27 editors_manager.register_resource_editor("dch", self)
29 ## Add an "add character" button
30 var add_character_button: Button = editors_manager.add_icon_button(
31 load("res://addons/dialogic/Editor/Images/Toolbar/add-character.svg"),
34 add_character_button.pressed.connect(_on_create_character_button_pressed)
35 add_character_button.shortcut = Shortcut.new()
36 add_character_button.shortcut.events.append(InputEventKey.new())
37 add_character_button.shortcut.events[0].keycode = KEY_2
38 add_character_button.shortcut.events[0].ctrl_pressed = true
40 ## By default show the no character screen
41 $NoCharacterScreen.show()
44 func _get_title() -> String:
48 func _get_icon() -> Texture:
49 return load("res://addons/dialogic/Editor/Images/Resources/character.svg")
52 ## Called when a character is opened somehow
53 func _open_resource(resource:Resource) -> void:
55 $NoCharacterScreen.show()
59 current_resource = (resource as DialogicCharacter)
61 ## Make sure changes in the ui won't trigger saving
64 ## Load other main tabs
65 for child in %MainSettingsSections.get_children():
66 if child is DialogicCharacterEditorMainSection:
67 child._load_character(current_resource)
69 ## Clear and then load Portrait section
70 %PortraitSearch.text = ""
74 character_loaded.emit(resource.resource_path)
76 %CharacterName.text = DialogicResourceUtil.get_unique_identifier(resource.resource_path)
78 $NoCharacterScreen.hide()
79 %PortraitChangeInfo.hide()
82 ## Called when the character is opened.
83 func _open(extra_info:Variant="") -> void:
84 if !ProjectSettings.get_setting('dialogic/portraits/default_portrait', '').is_empty():
85 def_portrait_path = ProjectSettings.get_setting('dialogic/portraits/default_portrait', '')
87 def_portrait_path = DialogicUtil.get_module_path('Character').path_join('default_portrait.tscn')
89 if current_resource == null:
90 $NoCharacterScreen.show()
94 %PortraitChangeInfo.hide()
97 func _clear() -> void:
98 current_resource = null
99 current_resource_state = ResourceStates.SAVED
100 $NoCharacterScreen.show()
103 func _save() -> void:
104 if ! visible or not current_resource:
108 current_resource.portraits = get_updated_portrait_dict()
111 for child in %MainSettingsSections.get_children():
112 if child is DialogicCharacterEditorMainSection:
113 current_resource = child._save_changes(current_resource)
115 ResourceSaver.save(current_resource, current_resource.resource_path)
116 current_resource_state = ResourceStates.SAVED
117 DialogicResourceUtil.update_directory('dch')
120 ## Saves a new empty character to the given path
121 func new_character(path: String) -> void:
122 var resource := DialogicCharacter.new()
123 resource.resource_path = path
124 resource.display_name = path.get_file().trim_suffix("."+path.get_extension())
125 resource.color = Color(1,1,1,1)
126 resource.default_portrait = ""
127 resource.custom_info = {}
128 ResourceSaver.save(resource, path)
129 EditorInterface.get_resource_filesystem().update_file(path)
130 DialogicResourceUtil.update_directory('dch')
131 editors_manager.edit_resource(resource)
136 ######### INTERFACE ############################################################
139 func _ready() -> void:
140 if get_parent() is SubViewport:
143 DialogicUtil.get_dialogic_plugin().resource_saved.connect(_on_some_resource_saved)
144 # NOTE: This check is required because up to 4.2 this signal is not exposed.
145 if DialogicUtil.get_dialogic_plugin().has_signal("scene_saved"):
146 DialogicUtil.get_dialogic_plugin().scene_saved.connect(_on_some_resource_saved)
148 $NoCharacterScreen.color = get_theme_color("dark_color_2", "Editor")
149 $NoCharacterScreen.show()
150 setup_portrait_list_tab()
152 _on_fit_preview_toggle_toggled(DialogicUtil.get_editor_setting('character_preview_fit', true))
153 %PreviewLabel.add_theme_color_override("font_color", get_theme_color("readonly_color", "Editor"))
155 %PortraitChangeWarning.add_theme_color_override("font_color", get_theme_color("warning_color", "Editor"))
157 %RealPreviewPivot.texture = get_theme_icon("EditorPivot", "EditorIcons")
159 %MainSettingsCollapse.icon = get_theme_icon("GuiVisibilityVisible", "EditorIcons")
161 set_portrait_settings_position(DialogicUtil.get_editor_setting('portrait_settings_position', true))
163 await find_parent('EditorView').ready
166 add_settings_section(load("res://addons/dialogic/Editor/CharacterEditor/char_edit_section_general.tscn").instantiate(), %MainSettingsSections)
167 add_settings_section(load("res://addons/dialogic/Editor/CharacterEditor/char_edit_section_portraits.tscn").instantiate(), %MainSettingsSections)
168 add_settings_section(load("res://addons/dialogic/Editor/CharacterEditor/character_prefix_suffix.tscn").instantiate(), %MainSettingsSections)
171 add_settings_section(load("res://addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main_exports.tscn").instantiate(), %PortraitSettingsSection)
172 add_settings_section(load("res://addons/dialogic/Editor/CharacterEditor/char_edit_p_section_exports.tscn").instantiate(), %PortraitSettingsSection)
173 add_settings_section(load("res://addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main.tscn").instantiate(), %PortraitSettingsSection)
174 add_settings_section(load("res://addons/dialogic/Editor/CharacterEditor/char_edit_p_section_layout.tscn").instantiate(), %PortraitSettingsSection)
176 ## Load custom sections from modules
177 for indexer in DialogicUtil.get_indexers():
178 for path in indexer._get_character_editor_sections():
179 var scene: Control = load(path).instantiate()
180 if scene is DialogicCharacterEditorMainSection:
181 add_settings_section(scene, %MainSettingsSections)
182 elif scene is DialogicCharacterEditorPortraitSection:
183 add_settings_section(scene, %PortraitSettingsSection)
186 ## Add a section (a control) either to the given settings section (Main or Portraits)
187 ## - sets up the title of the section
188 ## - connects to various signals
189 func add_settings_section(edit:Control, parent:Node) -> void:
190 edit.changed.connect(something_changed)
191 edit.character_editor = self
193 if edit.has_signal('update_preview'):
194 edit.update_preview.connect(update_preview)
198 if edit._show_title():
199 var hbox := HBoxContainer.new()
200 hbox.name = edit._get_title()+"BOX"
201 button = Button.new()
203 button.theme_type_variation = "DialogicSection"
204 button.alignment = HORIZONTAL_ALIGNMENT_LEFT
205 button.size_flags_horizontal = Control.SIZE_SHRINK_BEGIN
206 button.text = edit._get_title()
207 button.icon_alignment = HORIZONTAL_ALIGNMENT_RIGHT
208 button.pressed.connect(_on_section_button_pressed.bind(button))
209 button.focus_mode = Control.FOCUS_NONE
210 button.icon = get_theme_icon("CodeFoldDownArrow", "EditorIcons")
211 button.add_theme_color_override('icon_normal_color', get_theme_color("font_color", "DialogicSection"))
213 hbox.size_flags_horizontal = Control.SIZE_EXPAND_FILL
214 hbox.add_child(button)
216 if !edit.hint_text.is_empty():
217 var hint: Node = load("res://addons/dialogic/Editor/Common/hint_tooltip_icon.tscn").instantiate()
218 hint.hint_text = edit.hint_text
221 parent.add_child(hbox)
222 parent.add_child(edit)
223 parent.add_child(HSeparator.new())
224 if button and !edit._start_opened():
225 _on_section_button_pressed(button)
228 func get_settings_section_by_name(name:String, main:=true) -> Node:
229 var parent := %MainSettingsSections
231 parent = %PortraitSettingsSection
233 if parent.has_node(name):
234 return parent.get_node(name)
235 elif parent.has_node(name+"BOX/"+name):
236 return parent.get_node(name+"BOX/"+name)
241 func _on_section_button_pressed(button:Button) -> void:
242 var section_header := button.get_parent()
243 var section := section_header.get_parent().get_child(section_header.get_index()+1)
245 button.icon = get_theme_icon("CodeFoldedRightArrow", "EditorIcons")
246 section.visible = false
248 button.icon = get_theme_icon("CodeFoldDownArrow", "EditorIcons")
249 section.visible = true
251 if section_header.get_parent().get_child_count() > section_header.get_index()+2 and section_header.get_parent().get_child(section_header.get_index()+2) is Separator:
252 section_header.get_parent().get_child(section_header.get_index()+2).visible = section_header.get_parent().get_child(section_header.get_index()+1).visible
255 func something_changed(fake_argument = "", fake_arg2 = null) -> void:
257 current_resource_state = ResourceStates.UNSAVED
260 func _on_main_settings_collapse_toggled(button_pressed:bool) -> void:
261 %MainSettingsTitle.visible = !button_pressed
262 %MainSettingsScroll.visible = !button_pressed
265 %MainSettingsCollapse.icon = get_theme_icon("GuiVisibilityHidden", "EditorIcons")
268 %MainSettingsCollapse.icon = get_theme_icon("GuiVisibilityVisible", "EditorIcons")
271 func _on_switch_portrait_settings_position_pressed() -> void:
272 set_portrait_settings_position(!%RightSection.vertical)
275 func set_portrait_settings_position(is_below:bool) -> void:
276 %RightSection.vertical = is_below
277 DialogicUtil.set_editor_setting('portrait_settings_position', is_below)
279 %SwitchPortraitSettingsPosition.icon = get_theme_icon("ControlAlignRightWide", "EditorIcons")
281 %SwitchPortraitSettingsPosition.icon = get_theme_icon("ControlAlignBottomWide", "EditorIcons")
286 ########## PORTRAIT SECTION ####################################################
288 #region Portrait Section
289 func setup_portrait_list_tab() -> void:
290 %PortraitTree.editor = self
292 ## Portrait section styling/connections
293 %AddPortraitButton.icon = get_theme_icon("Add", "EditorIcons")
294 %AddPortraitButton.pressed.connect(add_portrait)
295 %AddPortraitGroupButton.icon = load("res://addons/dialogic/Editor/Images/Pieces/add-folder.svg")
296 %AddPortraitGroupButton.pressed.connect(add_portrait_group)
297 %ImportPortraitsButton.icon = get_theme_icon("Load", "EditorIcons")
298 %ImportPortraitsButton.pressed.connect(open_portrait_folder_select)
299 %PortraitSearch.right_icon = get_theme_icon("Search", "EditorIcons")
300 %PortraitSearch.text_changed.connect(filter_portrait_list)
302 %PortraitTree.item_selected.connect(load_selected_portrait)
303 %PortraitTree.item_edited.connect(_on_item_edited)
304 %PortraitTree.item_activated.connect(_on_item_activated)
307 func open_portrait_folder_select() -> void:
308 find_parent("EditorView").godot_file_dialog(
309 import_portraits_from_folder, "*.svg, *.png",
310 EditorFileDialog.FILE_MODE_OPEN_DIR)
313 func import_portraits_from_folder(path:String) -> void:
314 var parent: TreeItem = %PortraitTree.get_root()
316 if %PortraitTree.get_selected() and %PortraitTree.get_selected() != parent and %PortraitTree.get_selected().get_metadata(0).has('group'):
317 parent = %PortraitTree.get_selected()
319 var dir := DirAccess.open(path)
321 var file_name: String = dir.get_next()
323 while file_name != "":
324 if not dir.current_is_dir():
325 var file_lower := file_name.to_lower()
326 if '.svg' in file_lower or '.png' in file_lower:
327 if not '.import' in file_lower:
328 files.append(file_name)
329 file_name = dir.get_next()
331 var prefix: String = files[0]
334 if file.begins_with(prefix):
336 if prefix.is_empty():
338 prefix = prefix.substr(0, len(prefix)-1)
341 %PortraitTree.add_portrait_item(file.trim_prefix(prefix).trim_suffix('.'+file.get_extension()),
342 {'scene':"",'export_overrides':{'image':var_to_str(path.path_join(file))}, 'scale':1, 'offset':Vector2(), 'mirror':false}, parent)
345 if parent.get_child_count():
346 parent.get_first_child().select(0)
348 # Call anyways to clear preview and hide portrait settings section
349 load_selected_portrait()
354 func add_portrait(portrait_name:String='New portrait', portrait_data:Dictionary={'scene':"", 'export_overrides':{'image':''}, 'scale':1, 'offset':Vector2(), 'mirror':false}) -> void:
355 var parent: TreeItem = %PortraitTree.get_root()
356 if %PortraitTree.get_selected():
357 if %PortraitTree.get_selected().get_metadata(0) and %PortraitTree.get_selected().get_metadata(0).has('group'):
358 parent = %PortraitTree.get_selected()
360 parent = %PortraitTree.get_selected().get_parent()
361 var item: TreeItem = %PortraitTree.add_portrait_item(portrait_name, portrait_data, parent)
362 item.set_meta('new', true)
363 item.set_editable(0, true)
365 %PortraitTree.call_deferred('edit_selected')
369 func add_portrait_group() -> void:
370 var parent_item: TreeItem = %PortraitTree.get_root()
371 if %PortraitTree.get_selected() and %PortraitTree.get_selected().get_metadata(0).has('group'):
372 parent_item = %PortraitTree.get_selected()
373 var item: TreeItem = %PortraitTree.add_portrait_group("Group", parent_item)
374 item.set_meta('new', true)
375 item.set_editable(0, true)
377 %PortraitTree.call_deferred('edit_selected')
380 func load_portrait_tree() -> void:
381 %PortraitTree.clear_tree()
382 var root: TreeItem = %PortraitTree.create_item()
384 for portrait in current_resource.portraits.keys():
385 var portrait_label: String = portrait
386 var parent: TreeItem = %PortraitTree.get_root()
388 parent = %PortraitTree.create_necessary_group_items(portrait)
389 portrait_label = portrait.split('/')[-1]
391 %PortraitTree.add_portrait_item(portrait_label, current_resource.portraits[portrait], parent)
393 update_default_portrait_star(current_resource.default_portrait)
395 if root.get_child_count():
396 root.get_first_child().select(0)
397 while %PortraitTree.get_selected().get_child_count():
398 %PortraitTree.get_selected().get_child(0).select(0)
400 # Call anyways to clear preview and hide portrait settings section
401 load_selected_portrait()
404 func filter_portrait_list(filter_term := "") -> void:
405 filter_branch(%PortraitTree.get_root(), filter_term)
408 func filter_branch(parent: TreeItem, filter_term: String) -> bool:
409 var anything_visible := false
410 for item in parent.get_children():
411 if item.get_metadata(0).has('group'):
412 item.visible = filter_branch(item, filter_term)
413 anything_visible = item.visible
414 elif filter_term.is_empty() or filter_term.to_lower() in item.get_text(0).to_lower():
416 anything_visible = true
419 return anything_visible
422 ## This is used to save the portrait data
423 func get_updated_portrait_dict() -> Dictionary:
424 return list_portraits(%PortraitTree.get_root().get_children())
427 func list_portraits(tree_items: Array[TreeItem], dict := {}, path_prefix := "") -> Dictionary:
428 for item in tree_items:
429 if item.get_metadata(0).has('group'):
430 dict = list_portraits(item.get_children(), dict, path_prefix+item.get_text(0)+"/")
432 dict[path_prefix +item.get_text(0)] = item.get_metadata(0)
436 func load_selected_portrait() -> void:
437 if selected_item and is_instance_valid(selected_item):
438 selected_item.set_editable(0, false)
440 selected_item = %PortraitTree.get_selected()
442 if selected_item and selected_item.get_metadata(0) != null and !selected_item.get_metadata(0).has('group'):
443 %PortraitSettingsSection.show()
444 var current_portrait_data: Dictionary = selected_item.get_metadata(0)
445 portrait_selected.emit(%PortraitTree.get_full_item_name(selected_item), current_portrait_data)
449 for child in %PortraitSettingsSection.get_children():
450 if child is DialogicCharacterEditorPortraitSection:
451 child.selected_item = selected_item
452 child._load_portrait_data(current_portrait_data)
455 %PortraitSettingsSection.hide()
459 func delete_portrait_item(item: TreeItem) -> void:
460 if item.get_next_visible(true) and item.get_next_visible(true) != item:
461 item.get_next_visible(true).select(0)
464 load_selected_portrait()
469 func duplicate_item(item: TreeItem) -> void:
470 var new_item: TreeItem = %PortraitTree.add_portrait_item(item.get_text(0)+'_duplicated', item.get_metadata(0).duplicate(true), item.get_parent())
471 new_item.set_meta('new', true)
475 func _input(event: InputEvent) -> void:
476 if !is_visible_in_tree() or (get_viewport().gui_get_focus_owner()!= null and !name+'/' in str(get_viewport().gui_get_focus_owner().get_path())):
478 if event is InputEventKey and event.pressed:
479 if event.keycode == KEY_F2 and %PortraitTree.get_selected():
480 %PortraitTree.get_selected().set_editable(0, true)
481 %PortraitTree.edit_selected()
482 get_viewport().set_input_as_handled()
483 elif event.keycode == KEY_DELETE and get_viewport().gui_get_focus_owner() is Tree and %PortraitTree.get_selected():
484 delete_portrait_item(%PortraitTree.get_selected())
485 get_viewport().set_input_as_handled()
488 func _on_portrait_right_click_menu_index_pressed(id: int) -> void:
494 delete_portrait_item(%PortraitTree.get_selected())
497 duplicate_item(%PortraitTree.get_selected())
499 get_settings_section_by_name("Portraits").set_default_portrait(%PortraitTree.get_full_item_name(%PortraitTree.get_selected()))
502 ## This removes/and adds the DEFAULT star on the portrait list
503 func update_default_portrait_star(default_portrait_name: String) -> void:
504 var item_list: Array = %PortraitTree.get_root().get_children()
505 if item_list.is_empty() == false:
507 var item: TreeItem = item_list.pop_back()
508 if item.get_button_by_id(0, 2) != -1:
509 item.erase_button(0, item.get_button_by_id(0, 2))
510 if %PortraitTree.get_full_item_name(item) == default_portrait_name:
511 item.add_button(0, get_theme_icon("Favorites", "EditorIcons"), 2, true, "Default")
512 item_list.append_array(item.get_children())
513 if item_list.is_empty():
517 func _on_item_edited() -> void:
518 selected_item = %PortraitTree.get_selected()
521 if %PreviewLabel.text.trim_prefix('Preview of "').trim_suffix('"') == current_resource.default_portrait:
522 current_resource.default_portrait = %PortraitTree.get_full_item_name(selected_item)
523 selected_item.set_editable(0, false)
525 if !selected_item.has_meta('new') and %PortraitTree.get_full_item_name(selected_item) != selected_item.get_meta('previous_name'):
526 report_name_change(selected_item)
527 %PortraitChangeInfo.show()
531 func _on_item_activated() -> void:
532 if %PortraitTree.get_selected() == null:
534 %PortraitTree.get_selected().set_editable(0, true)
535 %PortraitTree.edit_selected()
538 func report_name_change(item: TreeItem) -> void:
539 if item.get_metadata(0).has('group'):
540 for s_item in item.get_children():
541 if s_item.get_metadata(0).has('group') or !s_item.has_meta('new'):
542 report_name_change(s_item)
544 if item.get_meta('previous_name') == %PortraitTree.get_full_item_name(item):
546 editors_manager.reference_manager.add_portrait_ref_change(
547 item.get_meta('previous_name'),
548 %PortraitTree.get_full_item_name(item),
549 [DialogicResourceUtil.get_unique_identifier(current_resource.resource_path)])
550 item.set_meta('previous_name', %PortraitTree.get_full_item_name(item))
551 %PortraitChangeInfo.show()
555 ########### PREVIEW ############################################################
558 func update_preview(force := false, ignore_settings_reload := false) -> void:
559 %ScenePreviewWarning.hide()
561 if selected_item and is_instance_valid(selected_item) and selected_item.get_metadata(0) != null and !selected_item.get_metadata(0).has('group'):
562 %PreviewLabel.text = 'Preview of "'+%PortraitTree.get_full_item_name(selected_item)+'"'
564 var current_portrait_data: Dictionary = selected_item.get_metadata(0)
566 if not force and current_previewed_scene != null \
567 and scene_file_path == current_portrait_data.get('scene') \
568 and current_previewed_scene.has_method('_should_do_portrait_update') \
569 and is_instance_valid(current_previewed_scene.get_script()) \
570 and current_previewed_scene._should_do_portrait_update(current_resource, selected_item.get_text(0)):
571 # We keep the same scene.
575 for node in %RealPreviewPivot.get_children():
578 current_previewed_scene = null
579 current_scene_path = ""
581 var scene_path := def_portrait_path
582 if not current_portrait_data.get('scene', '').is_empty():
583 scene_path = current_portrait_data.get('scene')
585 if ResourceLoader.exists(scene_path):
586 current_previewed_scene = load(scene_path).instantiate()
587 current_scene_path = scene_path
589 if not current_previewed_scene == null:
590 %RealPreviewPivot.add_child(current_previewed_scene)
592 if not current_previewed_scene == null:
593 var scene: Node = current_previewed_scene
595 scene.show_behind_parent = true
596 DialogicUtil.apply_scene_export_overrides(scene, current_portrait_data.get('export_overrides', {}))
598 var mirror: bool = current_portrait_data.get('mirror', false) != current_resource.mirror
599 var scale: float = current_portrait_data.get('scale', 1) * current_resource.scale
601 if current_portrait_data.get('ignore_char_scale', false):
602 scale = current_portrait_data.get('scale', 1)
604 var offset: Vector2 = current_portrait_data.get('offset', Vector2()) + current_resource.offset
606 if is_instance_valid(scene.get_script()) and scene.script.is_tool():
608 if scene.has_method('_update_portrait'):
609 ## Create a fake duplicate resource that has all the portrait changes applied already
610 var preview_character := current_resource.duplicate()
611 preview_character.portraits = get_updated_portrait_dict()
612 scene._update_portrait(preview_character, %PortraitTree.get_full_item_name(selected_item))
614 if scene.has_method('_set_mirror'):
615 scene._set_mirror(mirror)
617 if !%FitPreview_Toggle.button_pressed:
618 scene.position = Vector2() + offset
619 scene.scale = Vector2(1,1)*scale
622 if not scene.get_script() == null and scene.script.is_tool() and scene.has_method('_get_covered_rect'):
623 var rect: Rect2 = scene._get_covered_rect()
624 var available_rect: Rect2 = %FullPreviewAvailableRect.get_rect()
625 scene.scale = Vector2(1,1) * min(available_rect.size.x/rect.size.x, available_rect.size.y/rect.size.y)
626 %RealPreviewPivot.position = (rect.position)*-1*scene.scale
627 %RealPreviewPivot.position.x = %FullPreviewAvailableRect.size.x/2
628 scene.position = Vector2()
631 %ScenePreviewWarning.show()
633 %PreviewLabel.text = 'Nothing to preview'
635 if not ignore_settings_reload:
636 for child in %PortraitSettingsSection.get_children():
637 if child is DialogicCharacterEditorPortraitSection:
638 child._recheck(current_portrait_data)
641 %PreviewLabel.text = 'No portrait to preview.'
643 for node in %RealPreviewPivot.get_children():
646 current_previewed_scene = null
647 current_scene_path = ""
650 func _on_some_resource_saved(file:Variant) -> void:
651 if current_previewed_scene == null:
654 if file is Resource and file == current_previewed_scene.script:
657 if typeof(file) == TYPE_STRING and file == current_previewed_scene.get_meta("path", ""):
661 func _on_full_preview_available_rect_resized() -> void:
662 if %FitPreview_Toggle.button_pressed:
663 update_preview(false, true)
666 func _on_create_character_button_pressed() -> void:
667 editors_manager.show_add_resource_dialog(
669 '*.dch; DialogicCharacter',
670 'Create new character',
675 func _on_fit_preview_toggle_toggled(button_pressed):
676 %FitPreview_Toggle.set_pressed_no_signal(button_pressed)
678 %FitPreview_Toggle.icon = get_theme_icon("ScrollContainer", "EditorIcons")
679 %FitPreview_Toggle.tooltip_text = "Real scale"
681 %FitPreview_Toggle.tooltip_text = "Fit into preview"
682 %FitPreview_Toggle.icon = get_theme_icon("CenterContainer", "EditorIcons")
683 DialogicUtil.set_editor_setting('character_preview_fit', button_pressed)
684 update_preview(false, true)
688 ## Open the reference manager
689 func _on_reference_manger_button_pressed() -> void:
690 editors_manager.reference_manager.open()
691 %PortraitChangeInfo.hide()