4 var current_glossary: DialogicGlossary = null
5 var current_entry_name := ""
6 var current_entry := {}
8 ################################################################################
10 ################################################################################
12 func _get_title() -> String:
16 func _get_icon() -> Texture:
17 var base_directory: String = self.get_script().get_path().get_base_dir()
18 var icon_path := base_directory + "/icon.svg"
19 return load(icon_path)
22 func _register() -> void:
23 editors_manager.register_simple_editor(self)
24 alternative_text = "Create and edit glossaries."
27 func _ready() -> void:
28 var add_glossary_icon_path: String = self.get_script().get_path().get_base_dir() + "/add-glossary.svg"
29 var add_glossary_icon := load(add_glossary_icon_path)
30 %AddGlossaryFile.icon = add_glossary_icon
32 %LoadGlossaryFile.icon = get_theme_icon('Folder', 'EditorIcons')
33 %DeleteGlossaryFile.icon = get_theme_icon('Remove', 'EditorIcons')
34 %DeleteGlossaryEntry.icon = get_theme_icon('Remove', 'EditorIcons')
36 %DeleteGlossaryFile.pressed.connect(_on_delete_glossary_file_pressed)
38 %AddGlossaryEntry.icon = get_theme_icon('Add', 'EditorIcons')
39 %EntrySearch.right_icon = get_theme_icon('Search', 'EditorIcons')
41 %GlossaryList.item_selected.connect(_on_GlossaryList_item_selected)
42 %EntryList.item_selected.connect(_on_EntryList_item_selected)
44 %DefaultColor.color_changed.connect(set_setting.bind('dialogic/glossary/default_color'))
45 %DefaultCaseSensitive.toggled.connect(set_setting.bind('dialogic/glossary/default_case_sensitive'))
47 %EntryCaseSensitive.icon = get_theme_icon("MatchCase", "EditorIcons")
49 %EntryAlternatives.text_changed.connect(_on_entry_alternatives_text_changed)
52 func set_setting(value: Variant, setting: String) -> void:
53 ProjectSettings.set_setting(setting, value)
54 ProjectSettings.save()
57 func _open(_argument: Variant = null) -> void:
58 %DefaultColor.color = ProjectSettings.get_setting('dialogic/glossary/default_color', Color.POWDER_BLUE)
59 %DefaultCaseSensitive.button_pressed = ProjectSettings.get_setting('dialogic/glossary/default_case_sensitive', true)
63 for file: String in ProjectSettings.get_setting('dialogic/glossary/glossary_files', []):
65 if ResourceLoader.exists(file):
66 %GlossaryList.add_item(DialogicUtil.pretty_name(file), get_theme_icon('FileList', 'EditorIcons'))
68 %GlossaryList.add_item(DialogicUtil.pretty_name(file), get_theme_icon('FileDead', 'EditorIcons'))
70 %GlossaryList.set_item_tooltip(idx, file)
75 if %GlossaryList.item_count != 0:
76 %GlossaryList.select(0)
77 _on_GlossaryList_item_selected(0)
79 current_glossary = null
82 ################################################################################
84 ################################################################################
85 func _on_GlossaryList_item_selected(idx: int) -> void:
87 var tooltip_item: String = %GlossaryList.get_item_tooltip(idx)
89 if ResourceLoader.exists(tooltip_item):
90 var glossary_item := load(tooltip_item)
92 if not glossary_item is DialogicGlossary:
95 current_glossary = load(tooltip_item)
97 if not current_glossary is DialogicGlossary:
102 for entry_key: String in current_glossary.entries.keys():
103 var entry: Variant = current_glossary.entries.get(entry_key)
108 # Older glossary entries may not have the name property and the
109 # alternatives may not be set up as alias entries.
110 if not entry.has(DialogicGlossary.NAME_PROPERTY):
111 entry[DialogicGlossary.NAME_PROPERTY] = entry_key
112 var alternatives_array: Array = entry.get(DialogicGlossary.ALTERNATIVE_PROPERTY, [])
113 var alternatives := ",".join(alternatives_array)
114 _on_entry_alternatives_text_changed(alternatives)
115 ResourceSaver.save(current_glossary)
117 %EntryList.add_item(entry.get(DialogicGlossary.NAME_PROPERTY, str(DialogicGlossary.NAME_PROPERTY)), get_theme_icon("Breakpoint", "EditorIcons"))
118 var modulate_color: Color = entry.get('color', %DefaultColor.color)
119 %EntryList.set_item_metadata(entry_idx, entry)
120 %EntryList.set_item_icon_modulate(entry_idx, modulate_color)
124 if %EntryList.item_count != 0:
126 _on_EntryList_item_selected(0)
131 func _on_add_glossary_file_pressed() -> void:
132 find_parent('EditorView').godot_file_dialog(create_new_glossary_file, '*.tres', EditorFileDialog.FILE_MODE_SAVE_FILE, 'Create new glossary resource')
135 func create_new_glossary_file(path:String) -> void:
136 var glossary := DialogicGlossary.new()
137 glossary.resource_path = path
138 ResourceSaver.save(glossary, path)
139 load_glossary_file(path)
142 func _on_load_glossary_file_pressed() -> void:
143 find_parent('EditorView').godot_file_dialog(load_glossary_file, '*.tres', EditorFileDialog.FILE_MODE_OPEN_FILE, 'Select glossary resource')
146 func load_glossary_file(path:String) -> void:
147 var list: Array = ProjectSettings.get_setting('dialogic/glossary/glossary_files', [])
151 ProjectSettings.set_setting('dialogic/glossary/glossary_files', list)
152 ProjectSettings.save()
153 %GlossaryList.add_item(DialogicUtil.pretty_name(path), get_theme_icon('FileList', 'EditorIcons'))
155 var selected_item_index: int = %GlossaryList.item_count - 1
157 %GlossaryList.set_item_tooltip(selected_item_index, path)
158 %GlossaryList.select(selected_item_index)
159 _on_GlossaryList_item_selected(selected_item_index)
162 func _on_delete_glossary_file_pressed() -> void:
163 var selected_items: PackedInt32Array = %GlossaryList.get_selected_items()
165 if not selected_items.is_empty():
166 var list: Array = ProjectSettings.get_setting('dialogic/glossary/glossary_files', [])
167 var selected_item_index := selected_items[0]
168 list.remove_at(selected_item_index)
170 ProjectSettings.set_setting('dialogic/glossary/glossary_files', list)
171 ProjectSettings.save()
176 ################################################################################
178 ################################################################################
179 func _on_EntryList_item_selected(idx: int) -> void:
180 current_entry_name = %EntryList.get_item_text(idx)
182 var entry_info: Dictionary = current_glossary.get_entry(current_entry_name)
183 current_entry = entry_info
185 %EntrySettings.show()
186 %EntryName.text = current_entry_name
187 %EntryCaseSensitive.button_pressed = entry_info.get('case_sensitive', %DefaultCaseSensitive.button_pressed)
189 var alternative_property: Array = entry_info.get(DialogicGlossary.ALTERNATIVE_PROPERTY, [])
190 var alternatives := ", ".join(alternative_property)
191 %EntryAlternatives.text = alternatives
193 %EntryTitle.text = entry_info.get('title', '')
194 %EntryText.text = entry_info.get('text', '')
195 %EntryExtra.text = entry_info.get('extra', '')
196 %EntryEnabled.button_pressed = entry_info.get('enabled', true)
198 %EntryColor.color = entry_info.get('color', %DefaultColor.color)
199 %EntryCustomColor.button_pressed = entry_info.has('color')
200 %EntryColor.disabled = !entry_info.has('color')
202 _check_entry_alternatives(alternatives)
203 _check_entry_name(current_entry_name, current_entry)
205 func _on_add_glossary_entry_pressed() -> void:
206 if !current_glossary:
209 var entry_count := current_glossary.entries.size() + 1
210 var new_name := "New Entry " + str(entry_count)
212 if new_name in current_glossary.entries.keys():
213 var random_hex_number := str(randi() % 0xFFFFFF)
214 new_name = new_name + " " + str(random_hex_number)
216 var new_glossary := {}
217 new_glossary[DialogicGlossary.NAME_PROPERTY] = new_name
219 if not current_glossary.try_add_entry(new_glossary):
220 print_rich("[color=red]Failed adding '" + new_name + "', exists already.[/color]")
223 ResourceSaver.save(current_glossary)
225 %EntryList.add_item(new_name, get_theme_icon("Breakpoint", "EditorIcons"))
226 var item_count: int = %EntryList.item_count - 1
228 %EntryList.set_item_metadata(item_count, new_name)
229 %EntryList.set_item_icon_modulate(item_count, %DefaultColor.color)
230 %EntryList.select(item_count)
232 _on_EntryList_item_selected(item_count)
234 %EntryList.ensure_current_is_visible()
235 %EntryName.grab_focus()
238 func _on_delete_glossary_entry_pressed() -> void:
239 var selected_items: Array = %EntryList.get_selected_items()
241 if not selected_items.is_empty():
242 var selected_item_index: int = selected_items[0]
244 if not current_glossary == null:
245 current_glossary.remove_entry(current_entry_name)
246 ResourceSaver.save(current_glossary)
248 %EntryList.remove_item(selected_item_index)
249 var entries_count: int = %EntryList.item_count
251 if entries_count > 0:
252 var previous_item_index := selected_item_index - 1
253 %EntryList.select(previous_item_index)
257 func _on_entry_search_text_changed(new_text: String) -> void:
258 if new_text.is_empty() or new_text.to_lower() in %EntryList.get_item_text(%EntryList.get_selected_items()[0]).to_lower():
261 for i: int in %EntryList.item_count:
263 if new_text.is_empty() or new_text.to_lower() in %EntryList.get_item_text(i).to_lower():
265 _on_EntryList_item_selected(i)
266 %EntryList.ensure_current_is_visible()
269 ################################################################################
271 ################################################################################
272 func hide_entry_editor() -> void:
273 %EntrySettings.hide()
276 func _update_alias_entries(old_alias_value_key: String, new_alias_value_key: String) -> void:
277 for entry_key: String in current_glossary.entries.keys():
279 var entry_value: Variant = current_glossary.entries.get(entry_key)
281 if not entry_value is String:
284 if not entry_value == old_alias_value_key:
287 current_glossary.entries[entry_key] = new_alias_value_key
290 ## Checks if the [param entry_name] is already used as a key for another entry
291 ## and returns true if it doesn't.
292 ## The [param entry] will be used to check if found entry uses the same
293 ## reference in memory.
294 func _check_entry_name(entry_name: String, entry: Dictionary) -> bool:
295 var selected_item: int = %EntryList.get_selected_items()[0]
296 var raised_error: bool = false
298 var entry_assigned: Variant = current_glossary.entries.get(entry_name, {})
300 # Alternative entry uses the entry name already.
301 if entry_assigned is String:
304 if entry_assigned is Dictionary and not entry_assigned.is_empty():
305 var entry_name_assigned: String = entry_assigned.get(DialogicGlossary.NAME_PROPERTY, "")
307 # Another entry uses the entry name already.
308 if not entry_name_assigned == entry_name:
311 # Not the same memory reference.
312 if not entry == entry_assigned:
316 %EntryList.set_item_custom_bg_color(selected_item,
317 get_theme_color("warning_color", "Editor").darkened(0.8))
318 %EntryName.add_theme_color_override("font_color", get_theme_color("warning_color", "Editor"))
319 %EntryName.right_icon = get_theme_icon("StatusError", "EditorIcons")
324 %EntryName.add_theme_color_override("font_color", get_theme_color("font_color", "Editor"))
325 %EntryName.add_theme_color_override("caret_color", get_theme_color("font_color", "Editor"))
326 %EntryName.right_icon = null
327 %EntryList.set_item_custom_bg_color(
335 func _on_entry_name_text_changed(new_name: String) -> void:
336 new_name = new_name.strip_edges()
338 if current_entry_name != new_name:
339 var selected_item: int = %EntryList.get_selected_items()[0]
341 if not _check_entry_name(new_name, current_entry):
344 print_rich("[color=green]Renaming entry '" + current_entry_name + "'' to '" + new_name + "'[/color]")
346 _update_alias_entries(current_entry_name, new_name)
348 current_glossary.replace_entry_key(current_entry_name, new_name)
350 %EntryList.set_item_text(selected_item, new_name)
351 %EntryList.set_item_metadata(selected_item, new_name)
352 ResourceSaver.save(current_glossary)
353 current_entry_name = new_name
356 func _on_entry_case_sensitive_toggled(button_pressed: bool) -> void:
357 current_glossary.get_entry(current_entry_name)['case_sensitive'] = button_pressed
358 ResourceSaver.save(current_glossary)
361 ## Checks if the [param new_alternatives] has any alternatives that are already
362 ## used as a key for another entry and returns true if it doesn't.
363 func _can_change_alternative(new_alternatives: String) -> bool:
364 for alternative: String in new_alternatives.split(',', false):
365 var stripped_alternative := alternative.strip_edges()
367 var value: Variant = current_glossary.entries.get(stripped_alternative, null)
373 value = current_glossary.entries.get(value, null)
375 var value_name: String = value[DialogicGlossary.NAME_PROPERTY]
377 if not current_entry_name == value_name:
383 ## Checks if [entry_alternatives] has any alternatives that are already
384 ## used by any entry and returns true if it doesn't.
385 ## If false, it will set the alternatives text field to a warning color and
387 ## If true, the alternatives text field will be set to the default color and
388 ## the icon will be removed.
389 func _check_entry_alternatives(entry_alternatives: String) -> bool:
391 if not _can_change_alternative(entry_alternatives):
392 %EntryAlternatives.add_theme_color_override("font_color", get_theme_color("warning_color", "Editor"))
393 %EntryAlternatives.right_icon = get_theme_icon("StatusError", "EditorIcons")
397 %EntryAlternatives.add_theme_color_override("font_color", get_theme_color("font_color", "Editor"))
398 %EntryAlternatives.right_icon = null
403 ## The [param new_alternatives] is a passed as a string of comma separated
404 ## values form the Dialogic editor.
406 ## Saves the glossary resource file.
407 func _on_entry_alternatives_text_changed(new_alternatives: String) -> void:
408 var current_alternatives: Array = current_glossary.get_entry(current_entry_name).get(DialogicGlossary.ALTERNATIVE_PROPERTY, [])
410 if not _check_entry_alternatives(new_alternatives):
413 for current_alternative: String in current_alternatives:
414 current_glossary._remove_entry_alias(current_alternative)
416 var alternatives := []
418 for new_alternative: String in new_alternatives.split(',', false):
419 var stripped_alternative := new_alternative.strip_edges()
420 alternatives.append(stripped_alternative)
421 current_glossary._add_entry_key_alias(current_entry_name, stripped_alternative)
423 current_glossary.get_entry(current_entry_name)[DialogicGlossary.ALTERNATIVE_PROPERTY] = alternatives
424 ResourceSaver.save(current_glossary)
427 func _on_entry_title_text_changed(new_text:String) -> void:
428 current_glossary.get_entry(current_entry_name)['title'] = new_text
429 ResourceSaver.save(current_glossary)
432 func _on_entry_text_text_changed() -> void:
433 current_glossary.get_entry(current_entry_name)['text'] = %EntryText.text
434 ResourceSaver.save(current_glossary)
437 func _on_entry_extra_text_changed() -> void:
438 current_glossary.get_entry(current_entry_name)['extra'] = %EntryExtra.text
439 ResourceSaver.save(current_glossary)
442 func _on_entry_enabled_toggled(button_pressed:bool) -> void:
443 current_glossary.get_entry(current_entry_name)['enabled'] = button_pressed
444 ResourceSaver.save(current_glossary)
447 func _on_entry_custom_color_toggled(button_pressed:bool) -> void:
448 %EntryColor.disabled = !button_pressed
451 current_glossary.get_entry(current_entry_name).erase('color')
452 %EntryList.set_item_icon_modulate(%EntryList.get_selected_items()[0], %DefaultColor.color)
454 current_glossary.get_entry(current_entry_name)['color'] = %EntryColor.color
455 %EntryList.set_item_icon_modulate(%EntryList.get_selected_items()[0], %EntryColor.color)
458 func _on_entry_color_color_changed(color:Color) -> void:
459 current_glossary.get_entry(current_entry_name)['color'] = color
460 %EntryList.set_item_icon_modulate(%EntryList.get_selected_items()[0], color)
461 ResourceSaver.save(current_glossary)