632 lines
23 KiB
GDScript
632 lines
23 KiB
GDScript
tool
|
|
class_name DialogicUtil
|
|
|
|
## This class is used by the DialogicEditor
|
|
## For example by the Editors (Timeline, Character, Theme), the MasterTree and the EventParts
|
|
|
|
static func list_to_dict(list):
|
|
var dict := {}
|
|
for val in list:
|
|
dict[val["file"]] = val
|
|
return dict
|
|
|
|
## *****************************************************************************
|
|
## CHARACTERS
|
|
## *****************************************************************************
|
|
|
|
static func get_character_list() -> Array:
|
|
var characters: Array = []
|
|
for file in DialogicResources.listdir(DialogicResources.get_path('CHAR_DIR')):
|
|
if '.json' in file:
|
|
var data: Dictionary = DialogicResources.get_character_json(file)
|
|
|
|
characters.append({
|
|
'name': data.get('name', data['id']),
|
|
'color': Color(data.get('color', "#ffffff")),
|
|
'file': file,
|
|
'portraits': data.get('portraits', []),
|
|
'display_name': data.get('display_name', ''),
|
|
'nickname': data.get('nickname', ''),
|
|
'data': data # This should be the only thing passed... not sure what I was thinking
|
|
})
|
|
return characters
|
|
|
|
|
|
|
|
static func get_characters_dict():
|
|
return list_to_dict(get_character_list())
|
|
|
|
|
|
static func get_sorted_character_list():
|
|
var array = get_character_list()
|
|
array.sort_custom(DialgicSorter, 'sort_resources')
|
|
return array
|
|
|
|
|
|
# helper that allows to get a character by file
|
|
static func get_character(character_id):
|
|
var characters = get_character_list()
|
|
for c in characters:
|
|
if c['file'] == character_id:
|
|
return c
|
|
return {}
|
|
|
|
## *****************************************************************************
|
|
## TIMELINES
|
|
## *****************************************************************************
|
|
|
|
|
|
static func get_timeline_list() -> Array:
|
|
var timelines: Array = []
|
|
for file in DialogicResources.listdir(DialogicResources.get_path('TIMELINE_DIR')):
|
|
if '.json' in file: # TODO check for real .json because if .json is in the middle of the sentence it still thinks it is a timeline
|
|
var data = DialogicResources.get_timeline_json(file)
|
|
if data.has('error') == false:
|
|
if data.has('metadata'):
|
|
var metadata = data['metadata']
|
|
var color = Color("#ffffff")
|
|
if metadata.has('name'):
|
|
timelines.append({'name':metadata['name'], 'color': color, 'file': file })
|
|
else:
|
|
timelines.append({'name':file.split('.')[0], 'color': color, 'file': file })
|
|
return timelines
|
|
|
|
# returns a dictionary with file_names as keys and metadata as values
|
|
static func get_timeline_dict() -> Dictionary:
|
|
return list_to_dict(get_timeline_list())
|
|
|
|
|
|
static func get_sorted_timeline_list():
|
|
var array = get_timeline_list()
|
|
array.sort_custom(DialgicSorter, 'sort_resources')
|
|
return array
|
|
|
|
|
|
## *****************************************************************************
|
|
## THEMES
|
|
## *****************************************************************************
|
|
|
|
static func get_theme_list() -> Array:
|
|
var themes: Array = []
|
|
for file in DialogicResources.listdir(DialogicResources.get_path('THEME_DIR')):
|
|
if '.cfg' in file:
|
|
var config = DialogicResources.get_theme_config(file)
|
|
themes.append({
|
|
'file': file,
|
|
'name': config.get_value('settings','name', file),
|
|
'config': config
|
|
})
|
|
return themes
|
|
|
|
# returns a dictionary with file_names as keys and metadata as values
|
|
static func get_theme_dict() -> Dictionary:
|
|
return list_to_dict(get_theme_list())
|
|
|
|
|
|
static func get_sorted_theme_list():
|
|
var array = get_theme_list()
|
|
array.sort_custom(DialgicSorter, 'sort_resources')
|
|
return array
|
|
|
|
|
|
## *****************************************************************************
|
|
## DEFINITIONS
|
|
## *****************************************************************************
|
|
|
|
static func get_default_definitions_list() -> Array:
|
|
return DialogicDefinitionsUtil.definitions_json_to_array(DialogicResources.get_default_definitions())
|
|
|
|
|
|
static func get_default_definitions_dict():
|
|
var dict = {}
|
|
for val in get_default_definitions_list():
|
|
dict[val['id']] = val
|
|
return dict
|
|
|
|
|
|
static func get_sorted_default_definitions_list():
|
|
var array = get_default_definitions_list()
|
|
array.sort_custom(DialgicSorter, 'sort_resources')
|
|
return array
|
|
|
|
# returns the result of the given dialogic comparison
|
|
static func compare_definitions(def_value: String, event_value: String, condition: String):
|
|
var definitions
|
|
if not Engine.is_editor_hint():
|
|
if Engine.get_main_loop().has_meta('definitions'):
|
|
definitions = Engine.get_main_loop().get_meta('definitions')
|
|
else:
|
|
definitions = DialogicResources.get_default_definitions()
|
|
Engine.get_main_loop().set_meta('definitions', definitions)
|
|
else:
|
|
definitions = DialogicResources.get_default_definitions()
|
|
var condition_met = false
|
|
if def_value != null and event_value != null:
|
|
# check if event_value equals a definition name and use that instead
|
|
for d in definitions['variables']:
|
|
if (d['name'] != '' and d['name'] == event_value):
|
|
event_value = d['value']
|
|
break;
|
|
var converted_def_value = def_value
|
|
var converted_event_value = event_value
|
|
if def_value.is_valid_float() and event_value.is_valid_float():
|
|
converted_def_value = float(def_value)
|
|
converted_event_value = float(event_value)
|
|
if condition == '':
|
|
condition = '==' # The default condition is Equal to
|
|
match condition:
|
|
"==":
|
|
condition_met = converted_def_value == converted_event_value
|
|
"!=":
|
|
condition_met = converted_def_value != converted_event_value
|
|
">":
|
|
condition_met = converted_def_value > converted_event_value
|
|
">=":
|
|
condition_met = converted_def_value >= converted_event_value
|
|
"<":
|
|
condition_met = converted_def_value < converted_event_value
|
|
"<=":
|
|
condition_met = converted_def_value <= converted_event_value
|
|
return condition_met
|
|
|
|
|
|
## *****************************************************************************
|
|
## RESOURCE FOLDER MANAGEMENT
|
|
## *****************************************************************************
|
|
# The MasterTree uses a "fake" folder structure
|
|
|
|
## PATH FUNCTIONS
|
|
# removes the last thing from a path
|
|
static func get_parent_path(path: String):
|
|
return path.replace("/"+path.split("/")[-1], "")
|
|
|
|
|
|
## GETTERS
|
|
# returns the full resource structure
|
|
static func get_full_resource_folder_structure():
|
|
return DialogicResources.get_resource_folder_structure()
|
|
|
|
static func get_timelines_folder_structure():
|
|
return get_folder_at_path("Timelines")
|
|
|
|
static func get_characters_folder_structure():
|
|
return get_folder_at_path("Characters")
|
|
|
|
static func get_definitions_folder_structure():
|
|
return get_folder_at_path("Definitions")
|
|
|
|
static func get_theme_folder_structure():
|
|
return get_folder_at_path("Themes")
|
|
|
|
# this gets the content of the folder at a path
|
|
# a path consists of the foldernames divided by '/'
|
|
static func get_folder_at_path(path):
|
|
var folder_data = get_full_resource_folder_structure()
|
|
|
|
for folder in path.split("/"):
|
|
if folder:
|
|
folder_data = folder_data['folders'][folder]
|
|
|
|
if folder_data == null:
|
|
folder_data = {"folders":{}, "files":[]}
|
|
return folder_data
|
|
|
|
|
|
## SETTERS
|
|
static func set_folder_content_recursive(path_array: Array, orig_data: Dictionary, new_data: Dictionary) -> Dictionary:
|
|
if len(path_array) == 1:
|
|
if path_array[0] in orig_data['folders'].keys():
|
|
if new_data.empty():
|
|
orig_data['folders'].erase(path_array[0])
|
|
else:
|
|
orig_data["folders"][path_array[0]] = new_data
|
|
else:
|
|
var current_folder = path_array.pop_front()
|
|
orig_data["folders"][current_folder] = set_folder_content_recursive(path_array, orig_data["folders"][current_folder], new_data)
|
|
return orig_data
|
|
|
|
static func set_folder_at_path(path: String, data:Dictionary):
|
|
var orig_structure = get_full_resource_folder_structure()
|
|
var new_data = set_folder_content_recursive(path.split("/"), orig_structure, data)
|
|
DialogicResources.save_resource_folder_structure(new_data)
|
|
return OK
|
|
|
|
## FOLDER METADATA
|
|
static func set_folder_meta(folder_path: String, key:String, value):
|
|
var data = get_folder_at_path(folder_path)
|
|
data['metadata'][key] = value
|
|
set_folder_at_path(folder_path, data)
|
|
|
|
static func get_folder_meta(folder_path: String, key:String):
|
|
return get_folder_at_path(folder_path)['metadata'][key]
|
|
|
|
|
|
## FOLDER FUNCTIONS
|
|
static func add_folder(path:String, folder_name:String):
|
|
# check if the name is allowed
|
|
if folder_name in get_folder_at_path(path)['folders'].keys():
|
|
print("[D] A folder with the name '"+folder_name+"' already exists in the target folder '"+path+"'.")
|
|
return ERR_ALREADY_EXISTS
|
|
|
|
var folder_data = get_folder_at_path(path)
|
|
folder_data['folders'][folder_name] = {"folders":{}, "files":[], 'metadata':{'color':null, 'folded':false}}
|
|
set_folder_at_path(path, folder_data)
|
|
|
|
return OK
|
|
|
|
static func remove_folder(folder_path:String, delete_files:bool = true):
|
|
#print("[D] Removing 'Folder' "+folder_path)
|
|
for folder in get_folder_at_path(folder_path)['folders']:
|
|
remove_folder(folder_path+"/"+folder, delete_files)
|
|
|
|
if delete_files:
|
|
for file in get_folder_at_path(folder_path)['files']:
|
|
#print("[D] Removing file ", file)
|
|
match folder_path.split("/")[0]:
|
|
'Timelines':
|
|
DialogicResources.delete_timeline(file)
|
|
'Characters':
|
|
DialogicResources.delete_character(file)
|
|
'Definitions':
|
|
DialogicResources.delete_default_definition(file)
|
|
'Themes':
|
|
DialogicResources.delete_theme(file)
|
|
set_folder_at_path(folder_path, {})
|
|
|
|
static func rename_folder(path:String, new_folder_name:String):
|
|
# check if the name is allowed
|
|
if new_folder_name in get_folder_at_path(get_parent_path(path))['folders'].keys():
|
|
print("[D] A folder with the name '"+new_folder_name+"' already exists in the target folder '"+get_parent_path(path)+"'.")
|
|
return ERR_ALREADY_EXISTS
|
|
elif new_folder_name.empty():
|
|
return ERR_PRINTER_ON_FIRE
|
|
|
|
|
|
# save the content
|
|
var folder_content = get_folder_at_path(path)
|
|
|
|
# remove the old folder BUT NOT THE FILES !!!!!
|
|
remove_folder(path, false)
|
|
|
|
# add the new folder
|
|
add_folder(get_parent_path(path), new_folder_name)
|
|
var new_path = get_parent_path(path)+ "/"+new_folder_name
|
|
set_folder_at_path(new_path, folder_content)
|
|
|
|
return OK
|
|
|
|
static func move_folder_to_folder(orig_path, target_folder):
|
|
# check if the name is allowed
|
|
if orig_path.split("/")[-1] in get_folder_at_path(target_folder)['folders'].keys():
|
|
print("[D] A folder with the name '"+orig_path.split("/")[-1]+"' already exists in the target folder '"+target_folder+"'.")
|
|
return ERR_ALREADY_EXISTS
|
|
|
|
# save the content
|
|
var folder_content = get_folder_at_path(orig_path)
|
|
|
|
# remove the old folder BUT DON'T DELETE THE FILES!!!!!!!!!!!
|
|
# took me ages to find this when I forgot it..
|
|
remove_folder(orig_path, false)
|
|
|
|
# add the new folder
|
|
var folder_name = orig_path.split("/")[-1]
|
|
add_folder(target_folder, folder_name)
|
|
var new_path = target_folder+ "/"+folder_name
|
|
set_folder_at_path(new_path, folder_content)
|
|
|
|
return OK
|
|
|
|
## FILE FUNCTIONS
|
|
static func move_file_to_folder(file_name, orig_folder, target_folder):
|
|
remove_file_from_folder(orig_folder, file_name)
|
|
add_file_to_folder(target_folder, file_name)
|
|
|
|
static func add_file_to_folder(folder_path, file_name):
|
|
var folder_data = get_folder_at_path(folder_path)
|
|
folder_data["files"].append(file_name)
|
|
set_folder_at_path(folder_path, folder_data)
|
|
|
|
static func remove_file_from_folder(folder_path, file_name):
|
|
var folder_data = get_folder_at_path(folder_path)
|
|
folder_data["files"].erase(file_name)
|
|
set_folder_at_path(folder_path, folder_data)
|
|
|
|
|
|
## STRUCTURE UPDATES
|
|
#should be called when files got deleted and on program start
|
|
static func update_resource_folder_structure():
|
|
var character_files = DialogicResources.listdir(DialogicResources.get_path('CHAR_DIR'))
|
|
var timeline_files = DialogicResources.listdir(DialogicResources.get_path('TIMELINE_DIR'))
|
|
var theme_files = DialogicResources.listdir(DialogicResources.get_path('THEME_DIR'))
|
|
var definition_files = get_default_definitions_dict().keys()
|
|
|
|
var folder_structure = DialogicResources.get_resource_folder_structure()
|
|
|
|
folder_structure['folders']['Timelines'] = check_folders_section(folder_structure['folders']['Timelines'], timeline_files)
|
|
folder_structure['folders']['Characters'] = check_folders_section(folder_structure['folders']['Characters'], character_files)
|
|
folder_structure['folders']['Themes'] = check_folders_section(folder_structure['folders']['Themes'], theme_files)
|
|
folder_structure['folders']['Definitions'] = check_folders_section(folder_structure['folders']['Definitions'], definition_files)
|
|
|
|
DialogicResources.save_resource_folder_structure(folder_structure)
|
|
|
|
# calls the check_folders_recursive
|
|
static func check_folders_section(section_structure: Dictionary, section_files:Array):
|
|
var result = check_folders_recursive(section_structure, section_files)
|
|
section_structure = result[0]
|
|
section_structure['files'] += result[1]
|
|
return section_structure
|
|
|
|
static func check_folders_recursive(folder_data: Dictionary, file_names:Array):
|
|
if not folder_data.has('metadata'):
|
|
folder_data['metadata'] = {'color':null, 'folded':false}
|
|
for folder in folder_data['folders'].keys():
|
|
var result = check_folders_recursive(folder_data["folders"][folder], file_names)
|
|
folder_data['folders'][folder] = result[0]
|
|
file_names = result[1]
|
|
for file in folder_data['files']:
|
|
if not file in file_names:
|
|
folder_data["files"].erase(file)
|
|
#print("[D] The file ", file, " was deleted!")
|
|
else:
|
|
file_names.erase(file)
|
|
return [folder_data, file_names]
|
|
|
|
|
|
static func beautify_filename(animation_name: String) -> String:
|
|
if animation_name == '[Default]' or animation_name == '[No Animation]':
|
|
return animation_name
|
|
var a_string = animation_name.get_file().trim_suffix('.gd')
|
|
if '-' in a_string:
|
|
a_string = a_string.split('-')[1].capitalize()
|
|
else:
|
|
a_string = a_string.capitalize()
|
|
return a_string
|
|
|
|
## *****************************************************************************
|
|
## USEFUL FUNCTIONS
|
|
## *****************************************************************************
|
|
|
|
static func generate_random_id() -> String:
|
|
return str(OS.get_unix_time()) + '-' + str(100 + randi()%899+1)
|
|
|
|
|
|
static func compare_dicts(dict_1: Dictionary, dict_2: Dictionary) -> bool:
|
|
# I tried using the .hash() function but it was returning different numbers
|
|
# even when the dictionary was exactly the same.
|
|
if str(dict_1) != "Null" and str(dict_2) != "Null":
|
|
if str(dict_1) == str(dict_2):
|
|
return true
|
|
return false
|
|
|
|
|
|
static func path_fixer_load(path):
|
|
# This function was added because some of the default assets shipped with
|
|
# Dialogic 1.0 were moved for version 1.1. If by any chance they still
|
|
# Use those resources, we redirect the paths from the old place to the new
|
|
# ones. This can be safely removed and replace all instances of
|
|
# DialogicUtil.path_fixer_load(x) with just load(x) on version 2.0
|
|
# since we will break compatibility.
|
|
|
|
match path:
|
|
'res://addons/dialogic/Fonts/DefaultFont.tres':
|
|
return load("res://addons/dialogic/Example Assets/Fonts/DefaultFont.tres")
|
|
'res://addons/dialogic/Fonts/GlossaryFont.tres':
|
|
return load('res://addons/dialogic/Example Assets/Fonts/GlossaryFont.tres')
|
|
'res://addons/dialogic/Images/background/background-1.png':
|
|
return load('res://addons/dialogic/Example Assets/backgrounds/background-1.png')
|
|
'res://addons/dialogic/Images/background/background-2.png':
|
|
return load('res://addons/dialogic/Example Assets/backgrounds/background-2.png')
|
|
'res://addons/dialogic/Images/next-indicator.png':
|
|
return load('res://addons/dialogic/Example Assets/next-indicator/next-indicator.png')
|
|
|
|
return load(path)
|
|
|
|
# This function contains necessary updates.
|
|
# This should be deleted in 2.0
|
|
static func resource_fixer():
|
|
var update_index = DialogicResources.get_settings_config().get_value("updates", "updatenumber", 0)
|
|
|
|
if update_index < 1:
|
|
print("[D] Update NR. "+str(update_index)+" | Adds event ids. Don't worry about this.")
|
|
for timeline_info in get_timeline_list():
|
|
var timeline = DialogicResources.get_timeline_json(timeline_info['file'])
|
|
|
|
var events = timeline["events"]
|
|
for i in events:
|
|
if not i.has("event_id"):
|
|
match i:
|
|
# MAIN EVENTS
|
|
# Text event
|
|
{'text', 'character', 'portrait'}:
|
|
i['event_id'] = 'dialogic_001'
|
|
# Join event
|
|
{'character', 'action', 'position', 'portrait',..}:
|
|
i['event_id'] = 'dialogic_002'
|
|
# Character Leave event
|
|
{'character', 'action'}:
|
|
i['event_id'] = 'dialogic_003'
|
|
|
|
# LOGIC EVENTS
|
|
# Question event
|
|
{'question', 'options', ..}:
|
|
i['event_id'] = 'dialogic_010'
|
|
# Choice event
|
|
{'choice', ..}:
|
|
i['event_id'] = 'dialogic_011'
|
|
# Condition event
|
|
{'condition', 'definition', 'value'}:
|
|
i['event_id'] = 'dialogic_012'
|
|
# End Branch event
|
|
{'endbranch'}:
|
|
i['event_id'] = 'dialogic_013'
|
|
# Set Value event
|
|
{'set_value', 'definition', ..}:
|
|
i['event_id'] = 'dialogic_014'
|
|
|
|
# TIMELINE EVENTS
|
|
# Change Timeline event
|
|
{'change_timeline'}:
|
|
i['event_id'] = 'dialogic_020'
|
|
# Change Backround event
|
|
{'background'}:
|
|
i['event_id'] = 'dialogic_021'
|
|
# Close Dialog event
|
|
{'close_dialog', ..}:
|
|
i['event_id'] = 'dialogic_022'
|
|
# Wait seconds event
|
|
{'wait_seconds'}:
|
|
i['event_id'] = 'dialogic_023'
|
|
# Set Theme event
|
|
{'set_theme'}:
|
|
i['event_id'] = 'dialogic_024'
|
|
|
|
# AUDIO EVENTS
|
|
# Audio event
|
|
{'audio', 'file', ..}:
|
|
i['event_id'] = 'dialogic_030'
|
|
# Background Music event
|
|
{'background-music', 'file', ..}:
|
|
i['event_id'] = 'dialogic_031'
|
|
|
|
# GODOT EVENTS
|
|
# Emit signal event
|
|
{'emit_signal'}:
|
|
i['event_id'] = 'dialogic_040'
|
|
# Change Scene event
|
|
{'change_scene'}:
|
|
i['event_id'] = 'dialogic_041'
|
|
# Call Node event
|
|
{'call_node'}:
|
|
i['event_id'] = 'dialogic_042'
|
|
# No Skip event
|
|
{'block_input'}:
|
|
i['event_id'] = 'dialogic_050'
|
|
timeline['events'] = events
|
|
DialogicResources.set_timeline(timeline)
|
|
if update_index < 2:
|
|
# Updates the text alignment to be saved as int like all anchors
|
|
print("[D] Update NR. "+str(update_index)+" | Changes how some theme values are saved. No need to worry about this.")
|
|
for theme_info in get_theme_list():
|
|
var theme = DialogicResources.get_theme_config(theme_info['file'])
|
|
|
|
match theme.get_value('text', 'alignment', 'Left'):
|
|
'Left':
|
|
DialogicResources.set_theme_value(theme_info['file'], 'text', 'alignment', 0)
|
|
'Center':
|
|
DialogicResources.set_theme_value(theme_info['file'], 'text', 'alignment', 1)
|
|
'Right':
|
|
DialogicResources.set_theme_value(theme_info['file'], 'text', 'alignment', 2)
|
|
|
|
if update_index < 3:
|
|
# Character Join and Character Leave have been unified to a new Character event
|
|
print("[D] Update NR. "+str(update_index)+" | Removes Character Join and Character Leave events in favor of the new 'Character' event. No need to worry about this.")
|
|
for timeline_info in get_timeline_list():
|
|
var timeline = DialogicResources.get_timeline_json(timeline_info['file'])
|
|
var events = timeline["events"]
|
|
for i in range(len(events)):
|
|
if events[i]['event_id'] == 'dialogic_002':
|
|
var new_event = {
|
|
'event_id':'dialogic_002',
|
|
'type':0,
|
|
'character':events[i].get('character', ''),
|
|
'portrait':events[i].get('portrait','Default'),
|
|
'position':events[i].get('position'),
|
|
'animation':'[Default]',
|
|
'animation_length':0.5,
|
|
'mirror_portrait':events[i].get('mirror', false),
|
|
'z_index': events[i].get('z_index', 0),
|
|
}
|
|
if new_event['portrait'].empty(): new_event['portrait'] = 'Default'
|
|
events[i] = new_event
|
|
elif events[i]['event_id'] == 'dialogic_003':
|
|
var new_event = {
|
|
'event_id':'dialogic_002',
|
|
'type':1,
|
|
'character':events[i].get('character', ''),
|
|
'animation':'[Default]',
|
|
'animation_length':0.5,
|
|
'mirror_portrait':events[i].get('mirror', false),
|
|
'z_index':events[i].get('z_index', 0),
|
|
}
|
|
events[i] = new_event
|
|
timeline['events'] = events
|
|
DialogicResources.set_timeline(timeline)
|
|
|
|
DialogicResources.set_settings_value("updates", "updatenumber", 3)
|
|
|
|
if !ProjectSettings.has_setting('input/dialogic_default_action'):
|
|
print("[D] Added the 'dialogic_default_action' to the InputMap. This is the default if you didn't select a different one in the dialogic settings. You will have to force the InputMap editor to update before you can see the action (reload project or add a new input action).")
|
|
var input_enter = InputEventKey.new()
|
|
input_enter.scancode = KEY_ENTER
|
|
var input_left_click = InputEventMouseButton.new()
|
|
input_left_click.button_index = BUTTON_LEFT
|
|
input_left_click.pressed = true
|
|
var input_space = InputEventKey.new()
|
|
input_space.scancode = KEY_SPACE
|
|
var input_x = InputEventKey.new()
|
|
input_x.scancode = KEY_X
|
|
var input_controller = InputEventJoypadButton.new()
|
|
input_controller.button_index = JOY_BUTTON_0
|
|
|
|
ProjectSettings.set_setting('input/dialogic_default_action', {'deadzone':0.5, 'events':[input_enter, input_left_click, input_space, input_x, input_controller]})
|
|
ProjectSettings.save()
|
|
if DialogicResources.get_settings_value('input', 'default_action_key', '[Default]') == '[Default]':
|
|
DialogicResources.set_settings_value('input', 'default_action_key', 'dialogic_default_action')
|
|
|
|
static func get_editor_scale(ref) -> float:
|
|
# There hasn't been a proper way of reliably getting the editor scale
|
|
# so this function aims at fixing that by identifying what the scale is and
|
|
# returning a value to use as a multiplier for manual UI tweaks
|
|
|
|
# The way of getting the scale could change, but this is the most reliable
|
|
# solution I could find that works in many different computer/monitors.
|
|
var _scale = ref.get_constant("inspector_margin", "Editor")
|
|
_scale = _scale * 0.125
|
|
|
|
return _scale
|
|
|
|
|
|
static func list_dir(path: String) -> Array:
|
|
var files = []
|
|
var dir = Directory.new()
|
|
dir.open(path)
|
|
dir.list_dir_begin(true)
|
|
|
|
var file = dir.get_next()
|
|
while file != '':
|
|
files += [file]
|
|
file = dir.get_next()
|
|
return files
|
|
|
|
|
|
## *****************************************************************************
|
|
## DIALOGIC_SORTER CLASS
|
|
## *****************************************************************************
|
|
|
|
# This class is only used by this script to sort the resource lists
|
|
class DialgicSorter:
|
|
|
|
static func key_available(key, a: Dictionary) -> bool:
|
|
return key in a.keys() and not a[key].empty()
|
|
|
|
static func get_compare_value(a: Dictionary) -> String:
|
|
if key_available('display_name', a):
|
|
return a['display_name']
|
|
|
|
if key_available('name', a):
|
|
return a['name']
|
|
|
|
if key_available('id', a):
|
|
return a['id']
|
|
|
|
if 'metadata' in a.keys():
|
|
var a_metadata = a['metadata']
|
|
if key_available('name', a_metadata):
|
|
return a_metadata['name']
|
|
if key_available('file', a_metadata):
|
|
return a_metadata['file']
|
|
return ''
|
|
|
|
static func sort_resources(a: Dictionary, b: Dictionary):
|
|
return get_compare_value(a).to_lower() < get_compare_value(b).to_lower()
|