diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index b35d4ce3d..80c251814 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,9 +1,9 @@
# These are supported funding model platforms
-github: coppolaemilio
-patreon: coppolaemilio
+github: jowan-spooner
+patreon: jowanspooner
open_collective: # Replace with a single Open Collective username
-ko_fi: coppolaemilio
+ko_fi: jowan_spooner
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 50df48e53..d098e3f09 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -27,8 +27,8 @@ If applicable, add screenshots to help explain your problem.
**System (please complete the following information):**
- OS: [e.g. Windows, Linux]
- - Godot Version: [e.g. 3.2.3]
- - Dialogic Version: [e.g. 1.0]
+ - Godot Version: [e.g. 4.2.2]
+ - Dialogic Version: [e.g. 2.0 Alpha 14, please be specific!]
## Solutions
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 000000000..ac4012363
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,6 @@
+blank_issues_enabled: true
+contact_links:
+ - name: Dialogic 1 Repository
+ url: https://github.com/dialogic-godot/dialogic-1/issues
+ about: Please post anything related to Dialogc 1.x (Godot 3.x) on the Dialogic 1 Repository!
+
diff --git a/LICENSE b/LICENSE
index ad41466f6..f001429b7 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2020 - 2023 Emilio Coppola
+Copyright (c) 2020 - present Emilio Coppola
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/README.md b/README.md
index f54bc2dde..7d84d182d 100644
--- a/README.md
+++ b/README.md
@@ -2,7 +2,7 @@
-Dialogic
+Dialogic 2
Create Dialogs, Visual Novels, RPGs, and manage Characters with Godot to create your Game!
@@ -28,9 +28,7 @@
Dialogic 2 **requires at least Godot 4.2**.
-It's a major rewrite compared to the previous Dialogic 1.
-
-[If you are looking for the Godot 3.5 version you can find it here.](https://github.com/dialogic-godot/dialogic/tree/dialogic-1)
+[If you are looking for the Godot 3.x version (Dialogic 1.x) you can find it here.](https://github.com/dialogic-godot/dialogic-1)
## Installation
Follow the installation instructions on our [Getting Started](https://docs.dialogic.pro/getting-started.html#1-installation--activation) documentation.
@@ -68,9 +66,9 @@ Changelogs will accommodate for these changes and inform you on how to update yo
## Credits
-Made by [Emilio Coppola](https://github.com/coppolaemilio) and [Jowan-Spooner](https://github.com/Jowan-Spooner).
+Made by [Jowan-Spooner](https://github.com/Jowan-Spooner) and [Emilio Coppola](https://github.com/coppolaemilio).
-Contributors: [zaknafean](https://github.com/zaknafean), [thebardsrc](https://github.com/thebardsrc), [and more!](https://github.com/dialogic-godot/dialogic/graphs/contributors).
+Contributors: [CakeVR](https://github.com/CakeVR), [Exelia](https://github.com/exelia-antonov), [zaknafean](https://github.com/zaknafean), [and more!](https://github.com/dialogic-godot/dialogic/graphs/contributors).
Special thanks: [Arnaud](https://github.com/arnaudvergnet), [AnidemDex](https://github.com/AnidemDex), [ellogwen](https://github.com/ellogwen), [Tim Krief](https://github.com/timkrief), [Toen](https://twitter.com/ToenAndreMC), Òscar, [Francisco Presencia](https://francisco.io/), [M7mdKady14](https://github.com/M7mdKady14).
diff --git a/Tests/Unit/guess_special_resource_test.gd b/Tests/Unit/guess_special_resource_test.gd
new file mode 100644
index 000000000..41749c7d0
--- /dev/null
+++ b/Tests/Unit/guess_special_resource_test.gd
@@ -0,0 +1,40 @@
+extends GdUnitTestSuite
+
+## Check if transition animations can be accessed with "in", "out, "in out"
+## as space-delimited prefix.
+func test_fade_in_animation_paths() -> void:
+ const TYPE := "PortraitAnimation"
+ var fade_in_1: String = DialogicResourceUtil.guess_special_resource(TYPE, "fade in").get('path', "")
+ var fade_in_2: String = DialogicResourceUtil.guess_special_resource(TYPE, "fade cross").get('path', "")
+ var fade_in_3: String = DialogicResourceUtil.guess_special_resource(TYPE, "fade out").get('path', "")
+
+ var is_any_fade_in_empty := fade_in_1.is_empty() or fade_in_2.is_empty() or fade_in_3.is_empty()
+ assert(is_any_fade_in_empty == false, "Fade In/Out animations are empty.")
+
+ var are_all_fade_in_equal := fade_in_1 == fade_in_2 and fade_in_2 == fade_in_3
+ assert(are_all_fade_in_equal == true, "Fade In/Out animations returned different paths.")
+
+
+## Test if invalid animation paths will return empty strings.
+func test_invalid_animation_path() -> void:
+ const TYPE := "PortraitAnimation"
+ var invalid_animation_1: String = DialogicResourceUtil.guess_special_resource(TYPE, "fade i").get('path', "")
+ assert(invalid_animation_1.is_empty() == true, "Invalid animation 1's path is not empty.")
+
+
+ var invalid_animation_2: String = DialogicResourceUtil.guess_special_resource(TYPE, "fade").get('path', "")
+ assert(invalid_animation_2.is_empty() == true, "Invalid animation 2's path is not empty.")
+
+
+## Test if invalid types will return empty strings.
+func test_invalid_type_path() -> void:
+ const INVALID_TYPE := "Portait Animation"
+ var invalid_animation: String = DialogicResourceUtil.guess_special_resource(INVALID_TYPE, "fade in").get('path', "")
+ assert(invalid_animation.is_empty() == true, "Invalid animation 1's path is not empty.")
+
+ const VALID_TYPE := "PortraitAnimation"
+ var valid_animation_path: String = DialogicResourceUtil.guess_special_resource(VALID_TYPE, "fade in").get('path', "")
+ assert(valid_animation_path.is_empty() == false, "Valids animation's path is empty.")
+
+ assert(not invalid_animation == valid_animation_path, "Valid and invalid animation paths are equal.")
+
diff --git a/addons/dialogic/Core/DialogicGameHandler.gd b/addons/dialogic/Core/DialogicGameHandler.gd
index b9e582c80..43c255744 100644
--- a/addons/dialogic/Core/DialogicGameHandler.gd
+++ b/addons/dialogic/Core/DialogicGameHandler.gd
@@ -104,6 +104,9 @@ var Backgrounds := preload("res://addons/dialogic/Modules/Background/subsystem_b
var Portraits := preload("res://addons/dialogic/Modules/Character/subsystem_portraits.gd").new():
get: return get_subsystem("Portraits")
+var PortraitContainers := preload("res://addons/dialogic/Modules/Character/subsystem_containers.gd").new():
+ get: return get_subsystem("PortraitContainers")
+
var Choices := preload("res://addons/dialogic/Modules/Choice/subsystem_choices.gd").new():
get: return get_subsystem("Choices")
@@ -151,8 +154,6 @@ var Voice := preload("res://addons/dialogic/Modules/Voice/subsystem_voice.gd").n
## Autoloads are added first, so this happens REALLY early on game startup.
func _ready() -> void:
- DialogicResourceUtil.update()
-
_collect_subsystems()
clear()
@@ -166,7 +167,7 @@ func _ready() -> void:
## -> returns the layout node
func start(timeline:Variant, label:Variant="") -> Node:
# If we don't have a style subsystem, default to just start_timeline()
- if !has_subsystem('Styles'):
+ if not has_subsystem('Styles'):
printerr("[Dialogic] You called Dialogic.start() but the Styles subsystem is missing!")
clear(ClearFlags.KEEP_VARIABLES)
start_timeline(timeline, label)
@@ -178,12 +179,12 @@ func start(timeline:Variant, label:Variant="") -> Node:
scene = self.Styles.load_style()
else:
scene = self.Styles.get_layout_node()
+ scene.show()
if not scene.is_node_ready():
scene.ready.connect(clear.bind(ClearFlags.KEEP_VARIABLES))
scene.ready.connect(start_timeline.bind(timeline, label))
else:
- clear(ClearFlags.KEEP_VARIABLES)
start_timeline(timeline, label)
return scene
@@ -205,10 +206,12 @@ func start_timeline(timeline:Variant, label_or_idx:Variant = "") -> void:
printerr("[Dialogic] There was an error loading this timeline. Check the filename, and the timeline for errors")
return
- await (timeline as DialogicTimeline).process()
+ (timeline as DialogicTimeline).process()
current_timeline = timeline
current_timeline_events = current_timeline.events
+ for event in current_timeline_events:
+ event.dialogic = self
current_event_idx = -1
if typeof(label_or_idx) == TYPE_STRING:
@@ -232,15 +235,15 @@ func preload_timeline(timeline_resource:Variant) -> Variant:
if timeline_resource == null:
printerr("[Dialogic] There was an error preloading this timeline. Check the filename, and the timeline for errors")
return null
- else:
- await (timeline_resource as DialogicTimeline).process()
- return timeline_resource
+
+ (timeline_resource as DialogicTimeline).process()
+
return timeline_resource
## Clears and stops the current timeline.
func end_timeline() -> void:
- clear(ClearFlags.TIMELINE_INFO_ONLY)
+ await clear(ClearFlags.TIMELINE_INFO_ONLY)
_on_timeline_ended()
timeline_ended.emit()
@@ -256,8 +259,7 @@ func handle_event(event_index:int) -> void:
if not current_timeline:
return
- if has_meta('previous_event') and get_meta('previous_event') is DialogicEvent and (get_meta('previous_event') as DialogicEvent).event_finished.is_connected(handle_next_event):
- (get_meta('previous_event') as DialogicEvent).event_finished.disconnect(handle_next_event)
+ _cleanup_previous_event()
if paused:
await dialogic_resumed
@@ -286,22 +288,34 @@ func handle_event(event_index:int) -> void:
## By using the clear flags from the [member ClearFlags] enum you can specify
## what info should be kept.
## For example, at timeline end usually it doesn't clear node or subsystem info.
-func clear(clear_flags := ClearFlags.FULL_CLEAR) -> bool:
+func clear(clear_flags := ClearFlags.FULL_CLEAR) -> void:
+ _cleanup_previous_event()
if !clear_flags & ClearFlags.TIMELINE_INFO_ONLY:
for subsystem in get_children():
if subsystem is DialogicSubsystem:
(subsystem as DialogicSubsystem).clear_game_state(clear_flags)
- # Resetting variables
- if current_timeline:
- current_timeline.clean()
+ var timeline := current_timeline
current_timeline = null
current_event_idx = -1
current_timeline_events = []
current_state = States.IDLE
- return true
+
+ # Resetting variables
+ if timeline:
+ await timeline.clean()
+
+
+## Cleanup after previous event (if any).
+func _cleanup_previous_event():
+ if has_meta('previous_event') and get_meta('previous_event') is DialogicEvent:
+ var event := get_meta('previous_event') as DialogicEvent
+ if event.event_finished.is_connected(handle_next_event):
+ event.event_finished.disconnect(handle_next_event)
+ event._clear_state()
+ remove_meta("previous_event")
#endregion
@@ -320,6 +334,9 @@ func get_full_state() -> Dictionary:
current_state_info['current_event_idx'] = -1
current_state_info['current_timeline'] = null
+ for subsystem in get_children():
+ (subsystem as DialogicSubsystem).save_game_state()
+
return current_state_info.duplicate(true)
@@ -406,4 +423,11 @@ func _on_timeline_ended() -> void:
@warning_ignore("unsafe_method_access")
self.Styles.get_layout_node().hide()
+
+func print_debug_moment() -> void:
+ if not current_timeline:
+ return
+
+ printerr("\tAt event ", current_event_idx+1, " (",current_timeline_events[current_event_idx].event_name, ' Event) in timeline "', DialogicResourceUtil.get_unique_identifier(current_timeline.resource_path), '" (',current_timeline.resource_path,').')
+ print("\n")
#endregion
diff --git a/addons/dialogic/Core/DialogicResourceUtil.gd b/addons/dialogic/Core/DialogicResourceUtil.gd
index c020b8a60..a86356cbf 100644
--- a/addons/dialogic/Core/DialogicResourceUtil.gd
+++ b/addons/dialogic/Core/DialogicResourceUtil.gd
@@ -4,7 +4,7 @@ class_name DialogicResourceUtil
static var label_cache := {}
static var event_cache: Array[DialogicEvent] = []
-static var special_resources : Array[Dictionary] = []
+static var special_resources := {}
static func update() -> void:
@@ -156,7 +156,7 @@ static func update_event_cache() -> Array:
for indexer in DialogicUtil.get_indexers():
# build event cache
for event in indexer._get_events():
- if not FileAccess.file_exists(event):
+ if not ResourceLoader.exists(event):
continue
if not 'event_end_branch.gd' in event and not 'event_text.gd' in event:
event_cache.append(load(event).new())
@@ -173,25 +173,78 @@ static func update_event_cache() -> Array:
################################################################################
static func update_special_resources() -> void:
- special_resources = []
+ special_resources.clear()
for indexer in DialogicUtil.get_indexers():
- special_resources.append_array(indexer._get_special_resources())
+ var additions := indexer._get_special_resources()
+ for resource_type in additions:
+ if not resource_type in special_resources:
+ special_resources[resource_type] = {}
+ special_resources[resource_type].merge(additions[resource_type])
-static func list_special_resources_of_type(type:String) -> Array:
+static func list_special_resources(type:String, filter := {}) -> Dictionary:
if special_resources.is_empty():
update_special_resources()
- return special_resources.filter(func(x:Dictionary): return type == x.get('type','')).map(func(x:Dictionary): return x.get('path', ''))
+ if type in special_resources:
+ if filter.is_empty():
+ return special_resources[type]
+ else:
+ var results := {}
+ for i in special_resources[type]:
+ if match_resource_filter(special_resources[type][i], filter):
+ results[i] = special_resources[type][i]
+ return results
+ return {}
+
+
+static func match_resource_filter(dict:Dictionary, filter:Dictionary) -> bool:
+ for i in filter:
+ if not i in dict:
+ return false
+ if typeof(filter[i]) == TYPE_ARRAY:
+ if not dict[i] in filter[i]:
+ return false
+ else:
+ if not dict[i] == filter[i]:
+ return false
+ return true
+
+
+static func guess_special_resource(type: String, string: String, default := {}, filter := {}, ignores:PackedStringArray=[]) -> Dictionary:
+ if string.is_empty():
+ return default
-
-static func guess_special_resource(type:String, name:String, default:="") -> String:
if special_resources.is_empty():
update_special_resources()
- if name.begins_with('res://'):
- return name
- for path in list_special_resources_of_type(type):
- if DialogicUtil.pretty_name(path).to_lower() == name.to_lower():
- return path
+ var resources := list_special_resources(type, filter)
+ if resources.is_empty():
+ printerr("[Dialogic] No ", type, "s found, but attempted to use one.")
+ return default
+
+ if string.begins_with('res://'):
+ for i in resources.values():
+ if i.path == string:
+ return i
+ printerr("[Dialogic] Unable to find ", type, " at path '", string, "'.")
+ return default
+
+ string = string.to_lower()
+
+ if string in resources:
+ return resources[string]
+
+ if not ignores.is_empty():
+ var regex := RegEx.create_from_string(r" ?\b(" + "|".join(ignores) + r")\b")
+ for name in resources:
+ if regex.sub(name, "") == regex.sub(string, ""):
+ return resources[name]
+
+ ## As a last effort check against the unfiltered list
+ if string in special_resources[type]:
+ push_warning("[Dialogic] Using ", type, " '", string,"' when not supposed to.")
+ return special_resources[type][string]
+
+ printerr("[Dialogic] Unable to identify ", type, " based on string '", string, "'.")
return default
#endregion
diff --git a/addons/dialogic/Core/DialogicUtil.gd b/addons/dialogic/Core/DialogicUtil.gd
index 7dcbe3650..3924f48d4 100644
--- a/addons/dialogic/Core/DialogicUtil.gd
+++ b/addons/dialogic/Core/DialogicUtil.gd
@@ -5,7 +5,9 @@ class_name DialogicUtil
## Used whenever the same thing is needed in different parts of the plugin.
#region EDITOR
-################################################################################
+
+## This method should be used instead of EditorInterface.get_editor_scale(), because if you use that
+## it will run perfectly fine from the editor, but crash when the game is exported.
static func get_editor_scale() -> float:
return get_dialogic_plugin().get_editor_interface().get_editor_scale()
@@ -32,7 +34,7 @@ static func autoload() -> DialogicGameHandler:
#region FILE SYSTEM
################################################################################
-static func listdir(path: String, files_only:= true, throw_error:= true, full_file_path:= false, include_imports := false) -> Array:
+static func listdir(path: String, files_only:= true, _throw_error:= true, full_file_path:= false, include_imports := false) -> Array:
var files: Array = []
if path.is_empty(): path = "res://"
if DirAccess.dir_exists_absolute(path):
@@ -82,7 +84,7 @@ static func _update_autoload_subsystem_access() -> void:
new_subsystem_access_list += '\nvar {name} := preload("{script}").new():\n\tget: return get_subsystem("{name}")\n'.format(subsystem)
new_subsystem_access_list += "\n#endregion"
- script.source_code = RegEx.create_from_string("#region SUBSYSTEMS\\n#*\\n((?!#endregion)(.*\\n))*#endregion").sub(script.source_code, new_subsystem_access_list)
+ script.source_code = RegEx.create_from_string(r"#region SUBSYSTEMS\n#*\n((?!#endregion)(.*\n))*#endregion").sub(script.source_code, new_subsystem_access_list)
ResourceSaver.save(script)
Engine.get_singleton("EditorInterface").get_resource_filesystem().reimport_files(["res://addons/dialogic/Core/DialogicGameHandler.gd"])
@@ -95,38 +97,28 @@ static func get_indexers(include_custom := true, force_reload := false) -> Array
for file in listdir(DialogicUtil.get_module_path(''), false):
var possible_script: String = DialogicUtil.get_module_path(file).path_join("index.gd")
- if FileAccess.file_exists(possible_script):
+ if ResourceLoader.exists(possible_script):
indexers.append(load(possible_script).new())
if include_custom:
var extensions_folder: String = ProjectSettings.get_setting('dialogic/extensions_folder', "res://addons/dialogic_additions/")
for file in listdir(extensions_folder, false, false):
var possible_script: String = extensions_folder.path_join(file + "/index.gd")
- if FileAccess.file_exists(possible_script):
+ if ResourceLoader.exists(possible_script):
indexers.append(load(possible_script).new())
Engine.get_main_loop().set_meta('dialogic_indexers', indexers)
return indexers
-enum AnimationType {ALL, IN, OUT, ACTION}
-static func get_portrait_animation_scripts(type:=AnimationType.ALL, include_custom:=true) -> Array:
- var animations := DialogicResourceUtil.list_special_resources_of_type("PortraitAnimation")
-
- return animations.filter(
- func(script):
- if type == AnimationType.ALL: return true;
- if type == AnimationType.IN: return '_in' in script;
- if type == AnimationType.OUT: return '_out' in script;
- if type == AnimationType.ACTION: return not ('_in' in script or '_out' in script))
-
-static func pretty_name(script:String) -> String:
- var _name := script.get_file().trim_suffix("."+script.get_extension())
+## Turns a [param file_path] from `some_file.png` to `Some File`.
+static func pretty_name(file_path: String) -> String:
+ var _name := file_path.get_file().trim_suffix("." + file_path.get_extension())
_name = _name.replace('_', ' ')
_name = _name.capitalize()
- return _name
+ return _name
#endregion
@@ -193,6 +185,29 @@ static func update_timer_process_callback(timer:Timer) -> void:
#endregion
+#region MULTITWEEN
+################################################################################
+static func multitween(tweened_value:Variant, item:Node, property:String, part:String) -> void:
+ var parts: Dictionary = item.get_meta(property+'_parts', {})
+ parts[part] = tweened_value
+
+ if not item.has_meta(property+'_base_value') and not 'base' in parts:
+ item.set_meta(property+'_base_value', item.get(property))
+
+ var final_value: Variant = parts.get('base', item.get_meta(property+'_base_value', item.get(property)))
+
+ for key in parts:
+ if key == 'base':
+ continue
+ else:
+ final_value += parts[key]
+
+ item.set(property, final_value)
+ item.set_meta(property+'_parts', parts)
+
+#endregion
+
+
#region TRANSLATIONS
################################################################################
@@ -225,7 +240,7 @@ static func list_variables(dict:Dictionary, path := "", type:=VarTypes.ANY) -> A
return array
-static func get_variable_value_type(value:Variant) -> int:
+static func get_variable_value_type(value:Variant) -> VarTypes:
match typeof(value):
TYPE_STRING:
return VarTypes.STRING
@@ -339,7 +354,7 @@ static func get_scene_export_defaults(node:Node) -> Dictionary:
if !Engine.get_main_loop().has_meta('dialogic_scene_export_defaults'):
Engine.get_main_loop().set_meta('dialogic_scene_export_defaults', {})
var defaults := {}
- var property_info :Array[Dictionary] = node.script.get_script_property_list()
+ var property_info: Array[Dictionary] = node.script.get_script_property_list()
for i in property_info:
if i['usage'] & PROPERTY_USAGE_EDITOR:
defaults[i['name']] = node.get(i['name'])
@@ -348,6 +363,74 @@ static func get_scene_export_defaults(node:Node) -> Dictionary:
#endregion
+#region MAKE CUSTOM
+
+static func make_file_custom(original_file:String, target_folder:String, new_file_name := "", new_folder_name := "") -> String:
+ if not ResourceLoader.exists(original_file):
+ push_error("[Dialogic] Unable to make file with invalid path custom!")
+ return ""
+
+ if new_folder_name:
+ target_folder = target_folder.path_join(new_folder_name)
+ DirAccess.make_dir_absolute(target_folder)
+
+ if new_file_name.is_empty():
+ new_file_name = "custom_" + original_file.get_file()
+
+ if not new_file_name.ends_with(original_file.get_extension()):
+ new_file_name += "." + original_file.get_extension()
+
+ var target_file := target_folder.path_join(new_file_name)
+
+ customize_file(original_file, target_file)
+
+ get_dialogic_plugin().get_editor_interface().get_resource_filesystem().scan_sources()
+
+ return target_file
+
+
+static func customize_file(original_file:String, target_file:String) -> String:
+ #print("\nCUSTOMIZE FILE")
+ #printt(original_file, "->", target_file)
+
+ DirAccess.copy_absolute(original_file, target_file)
+
+ var file := FileAccess.open(target_file, FileAccess.READ)
+ var file_text := file.get_as_text()
+ file.close()
+
+ # If we are customizing a scene, we check for any resources used in that scene that are in the same folder.
+ # Those will be copied as well and the scene will be modified to point to them.
+ if file_text.begins_with('[gd_'):
+ var base_path: String = original_file.get_base_dir()
+
+ var remove_uuid_regex := r'\[gd_.* (?uid="uid:[^"]*")'
+ var result := RegEx.create_from_string(remove_uuid_regex).search(file_text)
+ if result:
+ file_text = file_text.replace(result.get_string("uid"), "")
+
+ # This regex also removes the UID referencing the original resource
+ var file_regex := r'(uid="[^"]*" )?\Qpath="'+base_path+r'\E(?[^"]*)"'
+ result = RegEx.create_from_string(file_regex).search(file_text)
+ while result:
+ var found_file_name := result.get_string('file')
+ var found_file_path := base_path.path_join(found_file_name)
+ var target_file_path := target_file.get_base_dir().path_join(found_file_name)
+
+ # Files found in this file will ALSO be customized.
+ customize_file(found_file_path, target_file_path)
+
+ file_text = file_text.replace(found_file_path, target_file_path)
+
+ result = RegEx.create_from_string(file_regex).search(file_text)
+
+ file = FileAccess.open(target_file, FileAccess.WRITE)
+ file.store_string(file_text)
+ file.close()
+
+ return target_file
+
+#endregion
#region INSPECTOR FIELDS
################################################################################
@@ -365,7 +448,7 @@ static func setup_script_property_edit_node(property_info: Dictionary, value:Var
if value != null:
input.color = value
input.color_changed.connect(DialogicUtil._on_export_color_submitted.bind(property_info.name, property_changed))
- input.custom_minimum_size.x = get_editor_scale()*50
+ input.custom_minimum_size.x = get_editor_scale() * 50
TYPE_INT:
if property_info['hint'] & PROPERTY_HINT_ENUM:
input = OptionButton.new()
@@ -432,9 +515,14 @@ static func setup_script_property_edit_node(property_info: Dictionary, value:Var
if value != null:
input.text = value
input.text_submitted.connect(DialogicUtil._on_export_input_text_submitted.bind(property_info.name, property_changed))
+ TYPE_DICTIONARY:
+ input = load("res://addons/dialogic/Editor/Events/Fields/field_dictionary.tscn").instantiate()
+ input.property_name = property_info["name"]
+ input.value_changed.connect(_on_export_dict_submitted.bind(property_changed))
TYPE_OBJECT:
input = load("res://addons/dialogic/Editor/Common/hint_tooltip_icon.tscn").instantiate()
input.hint_text = "Objects/Resources as settings are currently not supported. \nUse @export_file('*.extension') instead and load the resource once needed."
+
_:
input = LineEdit.new()
if value != null:
@@ -467,6 +555,9 @@ static func _on_export_string_enum_submitted(value:int, property_name:String, li
static func _on_export_vector_submitted(property_name:String, value:Variant, callable: Callable) -> void:
callable.call(property_name, var_to_str(value))
+static func _on_export_dict_submitted(property_name:String, value:Variant, callable: Callable) -> void:
+ callable.call(property_name, var_to_str(value))
+
#endregion
@@ -539,3 +630,71 @@ static func str_to_hash_set(source: String) -> Dictionary:
return dictionary
#endregion
+
+
+static func get_character_suggestions(_search_text:String, current_value:DialogicCharacter = null, allow_none := true, allow_all:= false, editor_node:Node = null) -> Dictionary:
+ var suggestions := {}
+
+ var icon := load("res://addons/dialogic/Editor/Images/Resources/character.svg")
+
+ if allow_none and current_value:
+ suggestions['(No one)'] = {'value':'', 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
+
+ if allow_all:
+ suggestions['ALL'] = {'value':'--All--', 'tooltip':'All currently joined characters leave', 'editor_icon':["GuiEllipsis", "EditorIcons"]}
+
+ # Get characters in the current timeline and place them at the top of suggestions.
+ if editor_node:
+ var recent_characters := []
+ var timeline_node := editor_node.get_parent().find_parent("Timeline") as DialogicEditor
+ for event_node in timeline_node.find_child("Timeline").get_children():
+ if event_node == editor_node:
+ break
+ if event_node.resource is DialogicCharacterEvent or event_node.resource is DialogicTextEvent:
+ recent_characters.append(event_node.resource.character)
+
+ recent_characters.reverse()
+ for character in recent_characters:
+ if character and not character.get_character_name() in suggestions:
+ suggestions[character.get_character_name()] = {'value': character.get_character_name(), 'tooltip': character.resource_path, 'icon': icon.duplicate()}
+
+ var character_directory := DialogicResourceUtil.get_character_directory()
+ for resource in character_directory.keys():
+ suggestions[resource] = {'value': resource, 'tooltip': character_directory[resource], 'icon': icon}
+
+ return suggestions
+
+
+static func get_portrait_suggestions(search_text:String, character:DialogicCharacter, allow_empty := false, empty_text := "Don't Change") -> Dictionary:
+ var icon := load("res://addons/dialogic/Editor/Images/Resources/portrait.svg")
+ var suggestions := {}
+
+ if allow_empty:
+ suggestions[empty_text] = {'value':'', 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
+
+ if "{" in search_text:
+ suggestions[search_text] = {'value':search_text, 'editor_icon':["Variant", "EditorIcons"]}
+
+ if character != null:
+ for portrait in character.portraits:
+ suggestions[portrait] = {'value':portrait, 'icon':icon}
+
+ return suggestions
+
+
+static func get_portrait_position_suggestions(search_text := "") -> Dictionary:
+ var icon := load(DialogicUtil.get_module_path("Character").path_join('portrait_position.svg'))
+
+ var setting: String = ProjectSettings.get_setting('dialogic/portraits/position_suggestion_names', 'leftmost, left, center, right, rightmost')
+
+ var suggestions := {}
+
+ if not search_text.is_empty():
+ suggestions[search_text] = {'value':search_text.strip_edges(), 'editor_icon':["GuiScrollArrowRight", "EditorIcons"]}
+
+ for position_id in setting.split(','):
+ suggestions[position_id.strip_edges()] = {'value':position_id.strip_edges(), 'icon':icon}
+ if not search_text.is_empty() and position_id.strip_edges().begins_with(search_text):
+ suggestions.erase(search_text)
+
+ return suggestions
diff --git a/addons/dialogic/Core/Dialogic_Subsystem.gd b/addons/dialogic/Core/Dialogic_Subsystem.gd
index 4b742a788..3ff55e60d 100644
--- a/addons/dialogic/Core/Dialogic_Subsystem.gd
+++ b/addons/dialogic/Core/Dialogic_Subsystem.gd
@@ -13,14 +13,21 @@ func post_install() -> void:
# To be overriden by sub-classes
# Fill in everything that should be cleared (for example before loading a different state)
-func clear_game_state(clear_flag:=DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
+func clear_game_state(_clear_flag:=DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
pass
# To be overriden by sub-classes
# Fill in everything that should be loaded using the dialogic_game_handler.current_state_info
# This is called when a save is loaded
-func load_game_state(load_flag:=LoadFlags.FULL_LOAD) -> void:
+func load_game_state(_load_flag:=LoadFlags.FULL_LOAD) -> void:
+ pass
+
+
+# To be overriden by sub-classes
+# Fill in everything that should be saved into the dialogic_game_handler.current_state_info
+# This is called when a save is saved
+func save_game_state() -> void:
pass
diff --git a/addons/dialogic/Core/index_class.gd b/addons/dialogic/Core/index_class.gd
index efc8adc89..30c8fa088 100644
--- a/addons/dialogic/Core/index_class.gd
+++ b/addons/dialogic/Core/index_class.gd
@@ -7,13 +7,13 @@ extends RefCounted
## Overwrite the methods to return the contents of that folder.
-var this_folder : String = get_script().resource_path.get_base_dir()
+var this_folder: String = get_script().resource_path.get_base_dir()
## Overwrite if this module contains any events. [br]
## Return an array with all the paths to the event scripts.[br]
## You can use the [property this_folder].path_join('my_event.gd')
func _get_events() -> Array:
- if FileAccess.file_exists(this_folder.path_join('event.gd')):
+ if ResourceLoader.exists(this_folder.path_join('event.gd')):
return [this_folder.path_join('event.gd')]
return []
@@ -59,7 +59,12 @@ func _get_text_modifiers() -> Array[Dictionary]:
## These can later be retrieved with DialogicResourceUtil.
## Each dictionary should contain (at least "type" and "path").
## E.g. {"type":"Animation", "path": "res://..."}
-func _get_special_resources() -> Array[Dictionary]:
+func _get_special_resources() -> Dictionary:
+ return {}
+
+
+## Return a list of dictionaries, each
+func _get_portrait_scene_presets() -> Array[Dictionary]:
return []
@@ -70,12 +75,26 @@ func list_dir(subdir:='') -> Array:
return Array(DirAccess.get_files_at(this_folder.path_join(subdir))).map(func(file):return this_folder.path_join(subdir).path_join(file))
-func list_special_resources(subdir:='', type:='', extension:="") -> Array[Dictionary]:
- var array := []
+func list_special_resources(subdir:='', extension:="") -> Dictionary:
+ var dict := {}
for i in list_dir(subdir):
if extension.is_empty() or i.ends_with(extension):
- array.append({'type':type, 'path':i})
- return Array(array, TYPE_DICTIONARY, "", null)
+ dict[DialogicUtil.pretty_name(i).to_lower()] = {"path":i}
+ return dict
+
+
+func list_animations(subdir := "") -> Dictionary:
+ var full_animation_list := {}
+ for path in list_dir(subdir):
+ if not path.ends_with(".gd") and not path.ends_with(".gdc"):
+ continue
+ var anim_object: DialogicAnimation = load(path).new()
+ var versions := anim_object._get_named_variations()
+ for version_name in versions:
+ full_animation_list[version_name] = versions[version_name]
+ full_animation_list[version_name]["path"] = path
+ anim_object.queue_free()
+ return full_animation_list
#endregion
@@ -99,7 +118,7 @@ func _get_layout_parts() -> Array[Dictionary]:
## Helper that allows scanning sub directories that might be layout parts or styles
func scan_for_layout_parts() -> Array[Dictionary]:
var dir := DirAccess.open(this_folder)
- var style_list :Array[Dictionary] = []
+ var style_list: Array[Dictionary] = []
if !dir:
return style_list
dir.list_dir_begin()
diff --git a/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_exports.gd b/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_exports.gd
index 3d5b226e7..9ad94cbbb 100644
--- a/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_exports.gd
+++ b/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_exports.gd
@@ -5,80 +5,82 @@ extends DialogicCharacterEditorPortraitSection
## for custom portrait scenes
var current_portrait_data := {}
-
+var last_scene := ""
func _get_title() -> String:
return "Settings"
-func _init():
- hint_text = "The settings here are @export variables from the used scene."
-
-
func _load_portrait_data(data:Dictionary) -> void:
- _recheck(data)
+ _recheck(data, true)
## Recheck section visibility and reload export fields.
## This allows reacting to changes of the portrait_scene setting.
-func _recheck(data:Dictionary):
- if data.get('scene', '').is_empty() and ProjectSettings.get_setting('dialogic/portraits/default_portrait', '').is_empty():
- hide()
- get_parent().get_child(get_index()-1).hide()
- get_parent().get_child(get_index()+1).hide()
- else:
- get_parent().get_child(get_index()-1).show()
-
+func _recheck(data: Dictionary, force:=false):
+ if last_scene == data.get("scene", "") and not force:
current_portrait_data = data
- load_portrait_scene_export_variables()
+ last_scene = data.get("scene", "")
+ return
+ last_scene = data.get("scene", "")
+ current_portrait_data = data
-func load_portrait_scene_export_variables():
- var scene = null
- if !current_portrait_data.get('scene', '').is_empty():
- scene = load(current_portrait_data.get('scene'))
- elif !ProjectSettings.get_setting('dialogic/portraits/default_portrait', '').is_empty():
- scene = load(ProjectSettings.get_setting('dialogic/portraits/default_portrait', ''))
+ for child in $Grid.get_children():
+ child.get_parent().remove_child(child)
+ child.queue_free()
+
+ var scene: Variant = null
+
+ if current_portrait_data.get('scene', '').is_empty():
+ if ProjectSettings.get_setting('dialogic/portraits/default_portrait', '').is_empty():
+ scene = load(character_editor.def_portrait_path)
+ else:
+ scene = load(ProjectSettings.get_setting('dialogic/portraits/default_portrait', ''))
else:
- scene = load(character_editor.def_portrait_path)
+ scene = load(current_portrait_data.get('scene'))
- if !scene:
+ if not scene:
return
- for child in $Grid.get_children():
- child.queue_free()
-
scene = scene.instantiate()
+
var skip := false
for i in scene.script.get_script_property_list():
if i['usage'] & PROPERTY_USAGE_EDITOR and !skip:
- var label = Label.new()
+ var label := Label.new()
label.text = i['name'].capitalize()
$Grid.add_child(label)
- var current_value :Variant = scene.get(i['name'])
+ var current_value: Variant = scene.get(i['name'])
if current_portrait_data.has('export_overrides') and current_portrait_data['export_overrides'].has(i['name']):
current_value = str_to_var(current_portrait_data.export_overrides[i['name']])
if current_value == null and typeof(scene.get(i['name'])) == TYPE_STRING:
current_value = current_portrait_data['export_overrides'][i['name']]
- var input :Node = DialogicUtil.setup_script_property_edit_node(i, current_value, set_export_override)
+ var input: Node = DialogicUtil.setup_script_property_edit_node(i, current_value, set_export_override)
input.size_flags_horizontal = SIZE_EXPAND_FILL
$Grid.add_child(input)
if i['usage'] & PROPERTY_USAGE_GROUP:
- if i['name'] == 'Main':
+ if i['name'] == 'Main' or i["name"] == "Private":
skip = true
continue
else:
skip = false
- $Label.visible = $Grid.get_child_count() == 0
+ if $Grid.get_child_count():
+ get_parent().get_child(get_index()-1).show()
+ show()
+ else:
+ hide()
+ get_parent().get_child(get_index()-1).hide()
+ get_parent().get_child(get_index()+1).hide()
## On any change, save the export override to the portrait items metadata.
func set_export_override(property_name:String, value:String = "") -> void:
- var data:Dictionary = selected_item.get_metadata(0)
+ var data: Dictionary = selected_item.get_metadata(0)
if !data.has('export_overrides'):
data['export_overrides'] = {}
if !value.is_empty():
diff --git a/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_exports.tscn b/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_exports.tscn
index 41dc75c2b..1392a1817 100644
--- a/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_exports.tscn
+++ b/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_exports.tscn
@@ -8,13 +8,6 @@ offset_right = 367.0
offset_bottom = 82.0
script = ExtResource("1_isys8")
-[node name="Label" type="Label" parent="."]
-layout_mode = 2
-theme_type_variation = &"DialogicHintText"
-theme_override_colors/font_color = Color(0, 0, 0, 1)
-text = "There are no exported variables to override. Add @export properties to the root script of your scene and make sure it's in @tool mode."
-autowrap_mode = 3
-
[node name="Grid" type="GridContainer" parent="."]
layout_mode = 2
size_flags_horizontal = 3
diff --git a/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_layout.gd b/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_layout.gd
index 6dec0bf47..03f4346e9 100644
--- a/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_layout.gd
+++ b/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_layout.gd
@@ -17,28 +17,28 @@ func _load_portrait_data(data:Dictionary) -> void:
func _on_portrait_scale_value_changed(value:float) -> void:
- var data:Dictionary = selected_item.get_metadata(0)
+ var data: Dictionary = selected_item.get_metadata(0)
data['scale'] = value/100.0
update_preview.emit()
changed.emit()
func _on_portrait_mirror_toggled(button_pressed:bool)-> void:
- var data:Dictionary = selected_item.get_metadata(0)
+ var data: Dictionary = selected_item.get_metadata(0)
data['mirror'] = button_pressed
update_preview.emit()
changed.emit()
func _on_ignore_scale_toggled(button_pressed:bool) -> void:
- var data:Dictionary = selected_item.get_metadata(0)
+ var data: Dictionary = selected_item.get_metadata(0)
data['ignore_char_scale'] = button_pressed
update_preview.emit()
changed.emit()
func _on_portrait_offset_value_changed(property:String, value:Vector2) -> void:
- var data:Dictionary = selected_item.get_metadata(0)
+ var data: Dictionary = selected_item.get_metadata(0)
data['offset'] = value
update_preview.emit()
changed.emit()
diff --git a/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main.gd b/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main.gd
index 9a1c1867b..80a96c8e1 100644
--- a/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main.gd
+++ b/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main.gd
@@ -6,10 +6,14 @@ extends DialogicCharacterEditorPortraitSection
func _get_title() -> String:
return "Scene"
-func _init():
+func _init() -> void:
hint_text = "You can use a custom scene for this portrait."
+func _start_opened() -> bool:
+ return true
+
func _ready() -> void:
+ %ChangeSceneButton.icon = get_theme_icon("Loop", "EditorIcons")
%ScenePicker.file_filter = "*.tscn, *.scn; Scenes"
%ScenePicker.resource_icon = get_theme_icon('PackedScene', 'EditorIcons')
%ScenePicker.placeholder = 'Default scene'
@@ -18,19 +22,80 @@ func _ready() -> void:
func _load_portrait_data(data:Dictionary) -> void:
- %ScenePicker.set_value(data.get('scene', ''))
- %OpenSceneButton.visible = !data.get('scene', '').is_empty()
+ reload_ui(data)
+
+
+func _on_open_scene_button_pressed() -> void:
+ var data: Dictionary = selected_item.get_metadata(0)
+ if ResourceLoader.exists(data.get("scene", "")):
+ DialogicUtil.get_dialogic_plugin().get_editor_interface().open_scene_from_path(data.get("scene", ""))
+ await get_tree().process_frame
+ EditorInterface.set_main_screen_editor("2D")
+
+
+func _on_change_scene_button_pressed() -> void:
+ %PortraitSceneBrowserWindow.popup_centered_ratio(0.6)
+
+
+func _on_portrait_scene_browser_activate_part(part_info: Dictionary) -> void:
+ %PortraitSceneBrowserWindow.hide()
+ match part_info.type:
+ "General":
+ set_scene_path(part_info.path)
+ "Preset":
+ find_parent("EditorView").godot_file_dialog(
+ create_new_portrait_scene.bind(part_info),
+ '*.tscn,*.scn',
+ EditorFileDialog.FILE_MODE_SAVE_FILE,
+ "Select where to save the new scene",
+ part_info.path.get_file().trim_suffix("."+part_info.path.get_extension())+"_"+character_editor.current_resource.get_character_name().to_lower())
+ "Custom":
+ find_parent("EditorView").godot_file_dialog(
+ set_scene_path,
+ '*.tscn, *.scn',
+ EditorFileDialog.FILE_MODE_OPEN_FILE,
+ "Select custom portrait scene",)
+ "Default":
+ set_scene_path("")
-func _on_scene_picker_value_changed(prop_name:String, value:String) -> void:
- var data:Dictionary = selected_item.get_metadata(0)
- data['scene'] = value
+func create_new_portrait_scene(target_file: String, info: Dictionary) -> void:
+ var path := make_portrait_preset_custom(target_file, info)
+ set_scene_path(path)
+
+
+func make_portrait_preset_custom(target_file:String, info: Dictionary) -> String:
+ var previous_file: String = info.path
+
+ var result_path := DialogicUtil.make_file_custom(previous_file, target_file.get_base_dir(), target_file.get_file())
+
+ return result_path
+
+
+func set_scene_path(path:String) -> void:
+ var data: Dictionary = selected_item.get_metadata(0)
+ data['scene'] = path
update_preview.emit()
changed.emit()
- %OpenSceneButton.visible = !data.get('scene', '').is_empty()
+ reload_ui(data)
-func _on_open_scene_button_pressed():
- if !%ScenePicker.current_value.is_empty() and FileAccess.file_exists(%ScenePicker.current_value):
- DialogicUtil.get_dialogic_plugin().get_editor_interface().open_scene_from_path(%ScenePicker.current_value)
- EditorInterface.set_main_screen_editor("2D")
+func reload_ui(data: Dictionary) -> void:
+ var path: String = data.get('scene', '')
+ %OpenSceneButton.hide()
+
+ if path.is_empty():
+ %SceneLabel.text = "Default Portrait Scene"
+ %SceneLabel.tooltip_text = "Can be changed in the settings."
+ %SceneLabel.add_theme_color_override("font_color", get_theme_color("readonly_color", "Editor"))
+
+ elif %PortraitSceneBrowser.is_premade_portrait_scene(path):
+ %SceneLabel.text = %PortraitSceneBrowser.portrait_scenes_info[path].name
+ %SceneLabel.tooltip_text = path
+ %SceneLabel.add_theme_color_override("font_color", get_theme_color("accent_color", "Editor"))
+
+ else:
+ %SceneLabel.text = path.get_file()
+ %SceneLabel.tooltip_text = path
+ %SceneLabel.add_theme_color_override("font_color", get_theme_color("property_color_x", "Editor"))
+ %OpenSceneButton.show()
diff --git a/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main.tscn b/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main.tscn
index db355bd9f..41a38dd9f 100644
--- a/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main.tscn
+++ b/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main.tscn
@@ -1,9 +1,10 @@
-[gd_scene load_steps=5 format=3 uid="uid://djq4aasoihexj"]
+[gd_scene load_steps=6 format=3 uid="uid://djq4aasoihexj"]
[ext_resource type="Script" path="res://addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main.gd" id="1_ht8lu"]
[ext_resource type="PackedScene" uid="uid://7mvxuaulctcq" path="res://addons/dialogic/Editor/Events/Fields/field_file.tscn" id="2_k8xs0"]
+[ext_resource type="PackedScene" uid="uid://b1wn8r84uh11b" path="res://addons/dialogic/Editor/CharacterEditor/portrait_scene_browser.tscn" id="3_ngvgq"]
-[sub_resource type="Image" id="Image_sbh6e"]
+[sub_resource type="Image" id="Image_tg5pd"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -12,8 +13,8 @@ data = {
"width": 16
}
-[sub_resource type="ImageTexture" id="ImageTexture_mbv6v"]
-image = SubResource("Image_sbh6e")
+[sub_resource type="ImageTexture" id="ImageTexture_f5xt2"]
+image = SubResource("Image_tg5pd")
[node name="Scene" type="GridContainer"]
offset_right = 298.0
@@ -25,18 +26,47 @@ script = ExtResource("1_ht8lu")
layout_mode = 2
size_flags_horizontal = 3
+[node name="ChangeSceneButton" type="Button" parent="HBox"]
+unique_name_in_owner = true
+layout_mode = 2
+tooltip_text = "Change Scene"
+icon = SubResource("ImageTexture_f5xt2")
+
+[node name="SceneLabel" type="Label" parent="HBox"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 3
+mouse_filter = 0
+theme_override_colors/font_color = Color(0, 0, 0, 1)
+text = "asdsdasdasd"
+clip_text = true
+
[node name="ScenePicker" parent="HBox" instance=ExtResource("2_k8xs0")]
unique_name_in_owner = true
+visible = false
layout_mode = 2
size_flags_horizontal = 3
file_filter = "*.tscn, *.scn; Scenes"
placeholder = "Default scene"
-resource_icon = SubResource("ImageTexture_mbv6v")
[node name="OpenSceneButton" type="Button" parent="HBox"]
unique_name_in_owner = true
layout_mode = 2
-icon = SubResource("ImageTexture_mbv6v")
+tooltip_text = "Open/Edit Scene"
+icon = SubResource("ImageTexture_f5xt2")
+
+[node name="PortraitSceneBrowserWindow" type="Window" parent="."]
+unique_name_in_owner = true
+title = "Portrait Scene Browser"
+position = Vector2i(0, 36)
+visible = false
+wrap_controls = true
+transient = true
+popup_window = true
+
+[node name="PortraitSceneBrowser" parent="PortraitSceneBrowserWindow" instance=ExtResource("3_ngvgq")]
+unique_name_in_owner = true
-[connection signal="value_changed" from="HBox/ScenePicker" to="." method="_on_scene_picker_value_changed"]
+[connection signal="pressed" from="HBox/ChangeSceneButton" to="." method="_on_change_scene_button_pressed"]
[connection signal="pressed" from="HBox/OpenSceneButton" to="." method="_on_open_scene_button_pressed"]
+[connection signal="activate_part" from="PortraitSceneBrowserWindow/PortraitSceneBrowser" to="." method="_on_portrait_scene_browser_activate_part"]
diff --git a/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main_exports.gd b/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main_exports.gd
index 30da4d370..d9ff6e5a9 100644
--- a/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main_exports.gd
+++ b/addons/dialogic/Editor/CharacterEditor/char_edit_p_section_main_exports.gd
@@ -3,46 +3,61 @@ extends DialogicCharacterEditorPortraitSection
## Portrait Settings Section that only shows the MAIN settings of a portrait scene.
+var current_portrait_data := {}
+var last_scene := ""
+
func _show_title() -> bool:
return false
-var current_portrait_data := {}
func _load_portrait_data(data:Dictionary) -> void:
+ _recheck(data, true)
+
+
+func _recheck(data:Dictionary, force := false) -> void:
get_parent().get_child(get_index()+1).hide()
+ if last_scene == data.get("scene", "") and not force:
+ current_portrait_data = data
+ last_scene = data.get("scene", "")
+ return
+
+ last_scene = data.get("scene", "")
current_portrait_data = data
+
load_portrait_scene_export_variables()
-func load_portrait_scene_export_variables():
+
+func load_portrait_scene_export_variables() -> void:
for child in $Grid.get_children():
child.queue_free()
- var scene = null
- if !current_portrait_data.get('scene', '').is_empty():
- scene = load(current_portrait_data.get('scene'))
- elif !ProjectSettings.get_setting('dialogic/portraits/default_portrait', '').is_empty():
- scene = load(ProjectSettings.get_setting('dialogic/portraits/default_portrait', ''))
+ var scene: Variant = null
+ if current_portrait_data.get('scene', '').is_empty():
+ if ProjectSettings.get_setting('dialogic/portraits/default_portrait', '').is_empty():
+ scene = load(character_editor.def_portrait_path)
+ else:
+ scene = load(ProjectSettings.get_setting('dialogic/portraits/default_portrait', ''))
else:
- scene = load(character_editor.def_portrait_path)
+ scene = load(current_portrait_data.get('scene'))
- if !scene:
+ if not scene:
return
scene = scene.instantiate()
var skip := true
for i in scene.script.get_script_property_list():
if i['usage'] & PROPERTY_USAGE_EDITOR and !skip:
- var label = Label.new()
+ var label := Label.new()
label.text = i['name'].capitalize()
$Grid.add_child(label)
- var current_value :Variant = scene.get(i['name'])
+ var current_value: Variant = scene.get(i['name'])
if current_portrait_data.has('export_overrides') and current_portrait_data['export_overrides'].has(i['name']):
current_value = str_to_var(current_portrait_data['export_overrides'][i['name']])
if current_value == null and typeof(scene.get(i['name'])) == TYPE_STRING:
current_value = current_portrait_data['export_overrides'][i['name']]
- var input :Node = DialogicUtil.setup_script_property_edit_node(i, current_value, set_export_override)
+ var input: Node = DialogicUtil.setup_script_property_edit_node(i, current_value, set_export_override)
input.size_flags_horizontal = SIZE_EXPAND_FILL
$Grid.add_child(input)
@@ -54,7 +69,7 @@ func load_portrait_scene_export_variables():
continue
func set_export_override(property_name:String, value:String = "") -> void:
- var data:Dictionary = selected_item.get_metadata(0)
+ var data: Dictionary = selected_item.get_metadata(0)
if !data.has('export_overrides'):
data['export_overrides'] = {}
if !value.is_empty():
diff --git a/addons/dialogic/Editor/CharacterEditor/char_edit_section_general.gd b/addons/dialogic/Editor/CharacterEditor/char_edit_section_general.gd
index 6fcd21dff..a5fe5140e 100644
--- a/addons/dialogic/Editor/CharacterEditor/char_edit_section_general.gd
+++ b/addons/dialogic/Editor/CharacterEditor/char_edit_section_general.gd
@@ -14,7 +14,7 @@ func _start_opened() -> bool:
func _ready() -> void:
# Connecting all necessary signals
- %ColorPickerButton.custom_minimum_size.x = DialogicUtil.get_editor_scale()*30
+ %ColorPickerButton.custom_minimum_size.x = DialogicUtil.get_editor_scale() * 30
%ColorPickerButton.color_changed.connect(character_editor.something_changed)
%DisplayNameLineEdit.text_changed.connect(character_editor.something_changed)
%NicknameLineEdit.text_changed.connect(character_editor.something_changed)
diff --git a/addons/dialogic/Editor/CharacterEditor/character_editor.gd b/addons/dialogic/Editor/CharacterEditor/character_editor.gd
index 9d6f4e10e..cc635cf52 100644
--- a/addons/dialogic/Editor/CharacterEditor/character_editor.gd
+++ b/addons/dialogic/Editor/CharacterEditor/character_editor.gd
@@ -9,11 +9,12 @@ signal portrait_selected()
# Current state
var loading := false
-var current_previewed_scene = null
+var current_previewed_scene: Variant = null
+var current_scene_path: String = ""
# References
var selected_item: TreeItem
-var def_portrait_path :String= DialogicUtil.get_module_path('Character').path_join('default_portrait.tscn')
+var def_portrait_path: String = DialogicUtil.get_module_path('Character').path_join('default_portrait.tscn')
######### EDITOR STUFF and LOADING/SAVING ######################################
@@ -26,7 +27,7 @@ func _register() -> void:
editors_manager.register_resource_editor("dch", self)
## Add an "add character" button
- var add_character_button = editors_manager.add_icon_button(
+ var add_character_button: Button = editors_manager.add_icon_button(
load("res://addons/dialogic/Editor/Images/Toolbar/add-character.svg"),
'Add Character',
self)
@@ -189,7 +190,7 @@ func add_settings_section(edit:Control, parent:Node) -> void:
if edit.has_signal('update_preview'):
edit.update_preview.connect(update_preview)
- var button :Button
+ var button: Button
if edit._show_title():
var hbox := HBoxContainer.new()
hbox.name = edit._get_title()+"BOX"
@@ -209,7 +210,7 @@ func add_settings_section(edit:Control, parent:Node) -> void:
hbox.add_child(button)
if !edit.hint_text.is_empty():
- var hint :Node = load("res://addons/dialogic/Editor/Common/hint_tooltip_icon.tscn").instantiate()
+ var hint: Node = load("res://addons/dialogic/Editor/Common/hint_tooltip_icon.tscn").instantiate()
hint.hint_text = edit.hint_text
hbox.add_child(hint)
@@ -313,16 +314,28 @@ func import_portraits_from_folder(path:String) -> void:
var dir := DirAccess.open(path)
dir.list_dir_begin()
- var file_name :String = dir.get_next()
+ var file_name: String = dir.get_next()
+ var files := []
while file_name != "":
if not dir.current_is_dir():
- var file_lower = file_name.to_lower()
+ var file_lower := file_name.to_lower()
if '.svg' in file_lower or '.png' in file_lower:
if not '.import' in file_lower:
- var final_name: String = path.path_join(file_name)
- %PortraitTree.add_portrait_item(file_name.trim_suffix('.'+file_name.get_extension()),
- {'scene':"",'export_overrides':{'image':var_to_str(final_name)}, 'scale':1, 'offset':Vector2(), 'mirror':false}, parent)
+ files.append(file_name)
file_name = dir.get_next()
+
+ var prefix: String = files[0]
+ for file in files:
+ while true:
+ if file.begins_with(prefix):
+ break
+ if prefix.is_empty():
+ break
+ prefix = prefix.substr(0, len(prefix)-1)
+
+ for file in files:
+ %PortraitTree.add_portrait_item(file.trim_prefix(prefix).trim_suffix('.'+file.get_extension()),
+ {'scene':"",'export_overrides':{'image':var_to_str(path.path_join(file))}, 'scale':1, 'offset':Vector2(), 'mirror':false}, parent)
## Handle selection
if parent.get_child_count():
@@ -341,7 +354,7 @@ func add_portrait(portrait_name:String='New portrait', portrait_data:Dictionary=
parent = %PortraitTree.get_selected()
else:
parent = %PortraitTree.get_selected().get_parent()
- var item :TreeItem = %PortraitTree.add_portrait_item(portrait_name, portrait_data, parent)
+ var item: TreeItem = %PortraitTree.add_portrait_item(portrait_name, portrait_data, parent)
item.set_meta('new', true)
item.set_editable(0, true)
item.select(0)
@@ -350,10 +363,10 @@ func add_portrait(portrait_name:String='New portrait', portrait_data:Dictionary=
func add_portrait_group() -> void:
- var parent_item :TreeItem = %PortraitTree.get_root()
+ var parent_item: TreeItem = %PortraitTree.get_root()
if %PortraitTree.get_selected() and %PortraitTree.get_selected().get_metadata(0).has('group'):
parent_item = %PortraitTree.get_selected()
- var item :TreeItem = %PortraitTree.add_portrait_group("Group", parent_item)
+ var item: TreeItem = %PortraitTree.add_portrait_group("Group", parent_item)
item.set_meta('new', true)
item.set_editable(0, true)
item.select(0)
@@ -362,11 +375,11 @@ func add_portrait_group() -> void:
func load_portrait_tree() -> void:
%PortraitTree.clear_tree()
- var root:TreeItem = %PortraitTree.create_item()
+ var root: TreeItem = %PortraitTree.create_item()
for portrait in current_resource.portraits.keys():
- var portrait_label = portrait
- var parent = %PortraitTree.get_root()
+ var portrait_label: String = portrait
+ var parent: TreeItem = %PortraitTree.get_root()
if '/' in portrait:
parent = %PortraitTree.create_necessary_group_items(portrait)
portrait_label = portrait.split('/')[-1]
@@ -384,11 +397,11 @@ func load_portrait_tree() -> void:
load_selected_portrait()
-func filter_portrait_list(filter_term:String = '') -> void:
+func filter_portrait_list(filter_term := "") -> void:
filter_branch(%PortraitTree.get_root(), filter_term)
-func filter_branch(parent:TreeItem, filter_term:String) -> bool:
+func filter_branch(parent: TreeItem, filter_term: String) -> bool:
var anything_visible := false
for item in parent.get_children():
if item.get_metadata(0).has('group'):
@@ -402,12 +415,12 @@ func filter_branch(parent:TreeItem, filter_term:String) -> bool:
return anything_visible
-# this is used to save the portrait data
+## This is used to save the portrait data
func get_updated_portrait_dict() -> Dictionary:
return list_portraits(%PortraitTree.get_root().get_children())
-func list_portraits(tree_items:Array[TreeItem], dict:Dictionary = {}, path_prefix = "") -> Dictionary:
+func list_portraits(tree_items: Array[TreeItem], dict := {}, path_prefix := "") -> Dictionary:
for item in tree_items:
if item.get_metadata(0).has('group'):
dict = list_portraits(item.get_children(), dict, path_prefix+item.get_text(0)+"/")
@@ -416,7 +429,7 @@ func list_portraits(tree_items:Array[TreeItem], dict:Dictionary = {}, path_prefi
return dict
-func load_selected_portrait():
+func load_selected_portrait() -> void:
if selected_item and is_instance_valid(selected_item):
selected_item.set_editable(0, false)
@@ -439,7 +452,7 @@ func load_selected_portrait():
update_preview()
-func delete_portrait_item(item:TreeItem) -> void:
+func delete_portrait_item(item: TreeItem) -> void:
if item.get_next_visible(true) and item.get_next_visible(true) != item:
item.get_next_visible(true).select(0)
else:
@@ -449,11 +462,13 @@ func delete_portrait_item(item:TreeItem) -> void:
something_changed()
-func duplicate_item(item:TreeItem) -> void:
- %PortraitTree.add_portrait_item(item.get_text(0)+'_duplicated', item.get_metadata(0).duplicate(true), item.get_parent()).select(0)
+func duplicate_item(item: TreeItem) -> void:
+ var new_item: TreeItem = %PortraitTree.add_portrait_item(item.get_text(0)+'_duplicated', item.get_metadata(0).duplicate(true), item.get_parent())
+ new_item.set_meta('new', true)
+ new_item.select(0)
-func _input(event:InputEvent) -> void:
+func _input(event: InputEvent) -> void:
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())):
return
if event is InputEventKey and event.pressed:
@@ -466,7 +481,7 @@ func _input(event:InputEvent) -> void:
get_viewport().set_input_as_handled()
-func _on_portrait_right_click_menu_index_pressed(id:int) -> void:
+func _on_portrait_right_click_menu_index_pressed(id: int) -> void:
# RENAME BUTTON
if id == 0:
_on_item_activated()
@@ -480,22 +495,22 @@ func _on_portrait_right_click_menu_index_pressed(id:int) -> void:
get_settings_section_by_name("Portraits").set_default_portrait(%PortraitTree.get_full_item_name(%PortraitTree.get_selected()))
-# this removes/and adds the DEFAULT star on the portrait list
-func update_default_portrait_star(default_portrait_name:String) -> void:
- var item_list : Array = %PortraitTree.get_root().get_children()
+## This removes/and adds the DEFAULT star on the portrait list
+func update_default_portrait_star(default_portrait_name: String) -> void:
+ var item_list: Array = %PortraitTree.get_root().get_children()
if item_list.is_empty() == false:
while true:
- var item = item_list.pop_back()
+ var item: TreeItem = item_list.pop_back()
if item.get_button_by_id(0, 2) != -1:
item.erase_button(0, item.get_button_by_id(0, 2))
if %PortraitTree.get_full_item_name(item) == default_portrait_name:
- item.add_button(0, get_theme_icon('Favorites', 'EditorIcons'), 2, true, 'Default')
+ item.add_button(0, get_theme_icon("Favorites", "EditorIcons"), 2, true, "Default")
item_list.append_array(item.get_children())
if item_list.is_empty():
break
-func _on_item_edited():
+func _on_item_edited() -> void:
selected_item = %PortraitTree.get_selected()
something_changed()
if selected_item:
@@ -509,14 +524,14 @@ func _on_item_edited():
update_preview()
-func _on_item_activated():
+func _on_item_activated() -> void:
if %PortraitTree.get_selected() == null:
return
%PortraitTree.get_selected().set_editable(0, true)
%PortraitTree.edit_selected()
-func report_name_change(item:TreeItem) -> void:
+func report_name_change(item: TreeItem) -> void:
if item.get_metadata(0).has('group'):
for s_item in item.get_children():
if s_item.get_metadata(0).has('group') or !s_item.has_meta('new'):
@@ -536,36 +551,41 @@ func report_name_change(item:TreeItem) -> void:
########### PREVIEW ############################################################
#region Preview
-func update_preview(force:=false) -> void:
+func update_preview(force := false, ignore_settings_reload := false) -> void:
%ScenePreviewWarning.hide()
+
if selected_item and is_instance_valid(selected_item) and selected_item.get_metadata(0) != null and !selected_item.get_metadata(0).has('group'):
%PreviewLabel.text = 'Preview of "'+%PortraitTree.get_full_item_name(selected_item)+'"'
var current_portrait_data: Dictionary = selected_item.get_metadata(0)
if not force and current_previewed_scene != null \
- and current_previewed_scene.get_meta('path', '') == current_portrait_data.get('scene') \
+ and scene_file_path == current_portrait_data.get('scene') \
and current_previewed_scene.has_method('_should_do_portrait_update') \
and is_instance_valid(current_previewed_scene.get_script()) \
and current_previewed_scene._should_do_portrait_update(current_resource, selected_item.get_text(0)):
- pass # we keep the same scene
+ # We keep the same scene.
+ pass
else:
+
for node in %RealPreviewPivot.get_children():
node.queue_free()
current_previewed_scene = null
+ current_scene_path = ""
var scene_path := def_portrait_path
if not current_portrait_data.get('scene', '').is_empty():
scene_path = current_portrait_data.get('scene')
- if FileAccess.file_exists(scene_path):
+ if ResourceLoader.exists(scene_path):
current_previewed_scene = load(scene_path).instantiate()
+ current_scene_path = scene_path
- if current_previewed_scene:
+ if not current_previewed_scene == null:
%RealPreviewPivot.add_child(current_previewed_scene)
- if current_previewed_scene != null:
+ if not current_previewed_scene == null:
var scene: Node = current_previewed_scene
scene.show_behind_parent = true
@@ -573,16 +593,20 @@ func update_preview(force:=false) -> void:
var mirror: bool = current_portrait_data.get('mirror', false) != current_resource.mirror
var scale: float = current_portrait_data.get('scale', 1) * current_resource.scale
+
if current_portrait_data.get('ignore_char_scale', false):
scale = current_portrait_data.get('scale', 1)
+
var offset: Vector2 = current_portrait_data.get('offset', Vector2()) + current_resource.offset
if is_instance_valid(scene.get_script()) and scene.script.is_tool():
+
if scene.has_method('_update_portrait'):
## Create a fake duplicate resource that has all the portrait changes applied already
var preview_character := current_resource.duplicate()
preview_character.portraits = get_updated_portrait_dict()
scene._update_portrait(preview_character, %PortraitTree.get_full_item_name(selected_item))
+
if scene.has_method('_set_mirror'):
scene._set_mirror(mirror)
@@ -590,25 +614,33 @@ func update_preview(force:=false) -> void:
scene.position = Vector2() + offset
scene.scale = Vector2(1,1)*scale
else:
- if is_instance_valid(scene.get_script()) and scene.script.is_tool() and scene.has_method('_get_covered_rect'):
- var rect: Rect2= scene._get_covered_rect()
+
+ if not scene.get_script() == null and scene.script.is_tool() and scene.has_method('_get_covered_rect'):
+ var rect: Rect2 = scene._get_covered_rect()
var available_rect: Rect2 = %FullPreviewAvailableRect.get_rect()
scene.scale = Vector2(1,1) * min(available_rect.size.x/rect.size.x, available_rect.size.y/rect.size.y)
%RealPreviewPivot.position = (rect.position)*-1*scene.scale
%RealPreviewPivot.position.x = %FullPreviewAvailableRect.size.x/2
scene.position = Vector2()
+
else:
%ScenePreviewWarning.show()
else:
%PreviewLabel.text = 'Nothing to preview'
- for child in %PortraitSettingsSection.get_children():
- if child is DialogicCharacterEditorPortraitSection:
- child._recheck(current_portrait_data)
+
+ if not ignore_settings_reload:
+ for child in %PortraitSettingsSection.get_children():
+ if child is DialogicCharacterEditorPortraitSection:
+ child._recheck(current_portrait_data)
+
else:
%PreviewLabel.text = 'No portrait to preview.'
+
for node in %RealPreviewPivot.get_children():
node.queue_free()
+
current_previewed_scene = null
+ current_scene_path = ""
func _on_some_resource_saved(file:Variant) -> void:
@@ -622,12 +654,12 @@ func _on_some_resource_saved(file:Variant) -> void:
update_preview(true)
-func _on_full_preview_available_rect_resized():
+func _on_full_preview_available_rect_resized() -> void:
if %FitPreview_Toggle.button_pressed:
- update_preview()
+ update_preview(false, true)
-func _on_create_character_button_pressed():
+func _on_create_character_button_pressed() -> void:
editors_manager.show_add_resource_dialog(
new_character,
'*.dch; DialogicCharacter',
@@ -645,11 +677,11 @@ func _on_fit_preview_toggle_toggled(button_pressed):
%FitPreview_Toggle.tooltip_text = "Fit into preview"
%FitPreview_Toggle.icon = get_theme_icon("CenterContainer", "EditorIcons")
DialogicUtil.set_editor_setting('character_preview_fit', button_pressed)
- update_preview()
+ update_preview(false, true)
#endregion
## Open the reference manager
-func _on_reference_manger_button_pressed():
+func _on_reference_manger_button_pressed() -> void:
editors_manager.reference_manager.open()
-
+ %PortraitChangeInfo.hide()
diff --git a/addons/dialogic/Editor/CharacterEditor/character_editor.tscn b/addons/dialogic/Editor/CharacterEditor/character_editor.tscn
index f77d11233..cef90fd17 100644
--- a/addons/dialogic/Editor/CharacterEditor/character_editor.tscn
+++ b/addons/dialogic/Editor/CharacterEditor/character_editor.tscn
@@ -5,7 +5,7 @@
[ext_resource type="Script" path="res://addons/dialogic/Editor/CharacterEditor/character_editor_portrait_tree.gd" id="2_vad0i"]
[ext_resource type="Texture2D" uid="uid://babwe22dqjta" path="res://addons/dialogic/Editor/Images/Pieces/add-folder.svg" id="3_v1qnr"]
-[sub_resource type="Image" id="Image_yiygw"]
+[sub_resource type="Image" id="Image_s4mcg"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -14,10 +14,10 @@ data = {
"width": 16
}
-[sub_resource type="ImageTexture" id="ImageTexture_hx3oq"]
-image = SubResource("Image_yiygw")
+[sub_resource type="ImageTexture" id="ImageTexture_oab13"]
+image = SubResource("Image_s4mcg")
-[sub_resource type="Image" id="Image_1n61j"]
+[sub_resource type="Image" id="Image_fnxud"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -27,7 +27,7 @@ data = {
}
[sub_resource type="ImageTexture" id="ImageTexture_u1a6g"]
-image = SubResource("Image_1n61j")
+image = SubResource("Image_fnxud")
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_es2rd"]
@@ -43,38 +43,42 @@ grow_horizontal = 2
grow_vertical = 2
script = ExtResource("2")
-[node name="VBoxContainer" type="VBoxContainer" parent="."]
+[node name="Scroll" type="ScrollContainer" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
+
+[node name="VBox" type="VBoxContainer" parent="Scroll"]
+layout_mode = 2
size_flags_horizontal = 3
+size_flags_vertical = 3
size_flags_stretch_ratio = 0.3
theme_override_constants/separation = 0
-[node name="TopSection" type="HBoxContainer" parent="VBoxContainer"]
+[node name="TopSection" type="HBoxContainer" parent="Scroll/VBox"]
layout_mode = 2
-[node name="NameContainer" type="HBoxContainer" parent="VBoxContainer/TopSection"]
+[node name="NameContainer" type="HBoxContainer" parent="Scroll/VBox/TopSection"]
layout_mode = 2
-[node name="CharacterName" type="Label" parent="VBoxContainer/TopSection/NameContainer"]
+[node name="CharacterName" type="Label" parent="Scroll/VBox/TopSection/NameContainer"]
unique_name_in_owner = true
layout_mode = 2
theme_type_variation = &"DialogicTitle"
text = "My Character"
-[node name="NameTooltip" parent="VBoxContainer/TopSection/NameContainer" instance=ExtResource("2_uhhqs")]
+[node name="NameTooltip" parent="Scroll/VBox/TopSection/NameContainer" instance=ExtResource("2_uhhqs")]
layout_mode = 2
tooltip_text = "This unique identifier is based on the file name. You can change it in the Reference Manager.
Use this name in timelines to reference this character."
-texture = SubResource("ImageTexture_hx3oq")
+texture = SubResource("ImageTexture_oab13")
hint_text = "This unique identifier is based on the file name. You can change it in the Reference Manager.
Use this name in timelines to reference this character."
-[node name="MainSettingsCollapse" type="Button" parent="VBoxContainer/TopSection"]
+[node name="MainSettingsCollapse" type="Button" parent="Scroll/VBox/TopSection"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 10
@@ -83,92 +87,91 @@ toggle_mode = true
text = "Main Settings"
icon = SubResource("ImageTexture_u1a6g")
-[node name="MainHSplit" type="HSplitContainer" parent="VBoxContainer"]
+[node name="MainHSplit" type="HSplitContainer" parent="Scroll/VBox"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
-[node name="MainSettings" type="VBoxContainer" parent="VBoxContainer/MainHSplit"]
+[node name="MainSettings" type="VBoxContainer" parent="Scroll/VBox/MainHSplit"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_stretch_ratio = 0.2
-[node name="MainSettingsTitle" type="Label" parent="VBoxContainer/MainHSplit/MainSettings"]
+[node name="MainSettingsTitle" type="Label" parent="Scroll/VBox/MainHSplit/MainSettings"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
theme_type_variation = &"DialogicSubTitle"
text = "Main Settings"
-[node name="MainSettingsScroll" type="ScrollContainer" parent="VBoxContainer/MainHSplit/MainSettings"]
+[node name="MainSettingsScroll" type="ScrollContainer" parent="Scroll/VBox/MainHSplit/MainSettings"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
theme_override_styles/panel = SubResource("StyleBoxEmpty_es2rd")
horizontal_scroll_mode = 0
-[node name="MainSettingsSections" type="VBoxContainer" parent="VBoxContainer/MainHSplit/MainSettings/MainSettingsScroll"]
+[node name="MainSettingsSections" type="VBoxContainer" parent="Scroll/VBox/MainHSplit/MainSettings/MainSettingsScroll"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
-[node name="Split" type="HSplitContainer" parent="VBoxContainer/MainHSplit"]
+[node name="Split" type="HSplitContainer" parent="Scroll/VBox/MainHSplit"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
-theme_override_constants/separation = 0
-[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/MainHSplit/Split"]
+[node name="HBoxContainer" type="HBoxContainer" parent="Scroll/VBox/MainHSplit/Split"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_stretch_ratio = 0.2
theme_override_constants/separation = 0
-[node name="MarginContainer" type="MarginContainer" parent="VBoxContainer/MainHSplit/Split/HBoxContainer"]
+[node name="MarginContainer" type="MarginContainer" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_stretch_ratio = 0.2
theme_override_constants/margin_bottom = 10
-[node name="PortraitListSection" type="PanelContainer" parent="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer"]
+[node name="PortraitListSection" type="PanelContainer" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
theme_type_variation = &"DialogicPanelA"
-[node name="Portraits" type="VBoxContainer" parent="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection"]
+[node name="Portraits" type="VBoxContainer" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection"]
layout_mode = 2
-[node name="PortraitsTitle" type="Label" parent="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits"]
+[node name="PortraitsTitle" type="Label" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits"]
layout_mode = 2
theme_type_variation = &"DialogicSubTitle"
text = "Portraits"
-[node name="PortraitListTools" type="HBoxContainer" parent="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits"]
+[node name="PortraitListTools" type="HBoxContainer" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits"]
layout_mode = 2
-[node name="AddPortraitButton" type="Button" parent="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitListTools"]
+[node name="AddPortraitButton" type="Button" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitListTools"]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Add portrait"
icon = SubResource("ImageTexture_u1a6g")
-[node name="AddPortraitGroupButton" type="Button" parent="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitListTools"]
+[node name="AddPortraitGroupButton" type="Button" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitListTools"]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Add Group"
icon = ExtResource("3_v1qnr")
-[node name="ImportPortraitsButton" type="Button" parent="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitListTools"]
+[node name="ImportPortraitsButton" type="Button" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitListTools"]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Import images from folder"
icon = SubResource("ImageTexture_u1a6g")
-[node name="PortraitSearch" type="LineEdit" parent="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitListTools"]
+[node name="PortraitSearch" type="LineEdit" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitListTools"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
@@ -180,12 +183,12 @@ right_icon = SubResource("ImageTexture_u1a6g")
caret_blink = true
caret_blink_interval = 0.5
-[node name="PortraitTreePanel" type="PanelContainer" parent="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits"]
+[node name="PortraitTreePanel" type="PanelContainer" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits"]
layout_mode = 2
size_flags_vertical = 3
theme_override_styles/panel = SubResource("StyleBoxEmpty_4xgdx")
-[node name="PortraitTree" type="Tree" parent="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitTreePanel"]
+[node name="PortraitTree" type="Tree" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitTreePanel"]
unique_name_in_owner = true
layout_mode = 2
allow_rmb_select = true
@@ -193,29 +196,30 @@ hide_root = true
drop_mode_flags = 3
script = ExtResource("2_vad0i")
-[node name="PortraitRightClickMenu" type="PopupMenu" parent="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitTreePanel/PortraitTree"]
+[node name="PortraitRightClickMenu" type="PopupMenu" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitTreePanel/PortraitTree"]
size = Vector2i(118, 100)
item_count = 5
item_0/text = "Rename"
-item_0/icon = SubResource("ImageTexture_hx3oq")
+item_0/icon = SubResource("ImageTexture_oab13")
item_0/id = 2
item_1/text = "Duplicate"
-item_1/icon = SubResource("ImageTexture_hx3oq")
+item_1/icon = SubResource("ImageTexture_oab13")
item_1/id = 0
item_2/text = "Delete"
-item_2/icon = SubResource("ImageTexture_hx3oq")
+item_2/icon = SubResource("ImageTexture_oab13")
item_2/id = 1
item_3/text = ""
item_3/id = 3
item_3/separator = true
item_4/text = "Make Default"
+item_4/icon = SubResource("ImageTexture_oab13")
item_4/id = 4
-[node name="PortraitChangeInfo" type="HBoxContainer" parent="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits"]
+[node name="PortraitChangeInfo" type="HBoxContainer" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits"]
unique_name_in_owner = true
layout_mode = 2
-[node name="PortraitChangeWarning" type="Label" parent="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitChangeInfo"]
+[node name="PortraitChangeWarning" type="Label" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitChangeInfo"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
@@ -223,24 +227,24 @@ theme_override_colors/font_color = Color(0, 0, 0, 1)
text = "Some portraits were renamed. Make sure no references broke!"
autowrap_mode = 3
-[node name="ReferenceMangerButton" type="Button" parent="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitChangeInfo"]
+[node name="ReferenceMangerButton" type="Button" parent="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitChangeInfo"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 4
text = "Reference
Manager"
-[node name="RightSection2" type="VBoxContainer" parent="VBoxContainer/MainHSplit/Split"]
+[node name="RightSection2" type="VBoxContainer" parent="Scroll/VBox/MainHSplit/Split"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
size_flags_stretch_ratio = 0.5
-[node name="Spacer" type="Control" parent="VBoxContainer/MainHSplit/Split/RightSection2"]
+[node name="Spacer" type="Control" parent="Scroll/VBox/MainHSplit/Split/RightSection2"]
custom_minimum_size = Vector2(0, 10)
layout_mode = 2
-[node name="RightSection" type="SplitContainer" parent="VBoxContainer/MainHSplit/Split/RightSection2"]
+[node name="RightSection" type="SplitContainer" parent="Scroll/VBox/MainHSplit/Split/RightSection2"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
@@ -248,7 +252,7 @@ size_flags_vertical = 3
size_flags_stretch_ratio = 0.5
vertical = true
-[node name="PortraitPreviewSection" type="Panel" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection"]
+[node name="PortraitPreviewSection" type="Panel" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection"]
unique_name_in_owner = true
show_behind_parent = true
custom_minimum_size = Vector2(100, 0)
@@ -257,7 +261,7 @@ size_flags_horizontal = 3
size_flags_vertical = 3
theme_type_variation = &"DialogicPanelB"
-[node name="ClipRect" type="Control" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection"]
+[node name="ClipRect" type="Control" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection"]
clip_contents = true
layout_mode = 1
anchors_preset = 15
@@ -266,15 +270,15 @@ anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
-[node name="Node2D" type="Node2D" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/ClipRect"]
+[node name="Node2D" type="Node2D" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/ClipRect"]
position = Vector2(13, 17)
-[node name="RealPreviewPivot" type="Sprite2D" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/ClipRect/Node2D"]
+[node name="RealPreviewPivot" type="Sprite2D" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/ClipRect/Node2D"]
unique_name_in_owner = true
position = Vector2(326.5, 267)
texture = SubResource("ImageTexture_u1a6g")
-[node name="ScenePreviewWarning" type="Label" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection"]
+[node name="ScenePreviewWarning" type="Label" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection"]
unique_name_in_owner = true
visible = false
layout_mode = 1
@@ -295,7 +299,7 @@ vertical_alignment = 1
autowrap_mode = 3
metadata/_edit_layout_mode = 1
-[node name="PreviewReal" type="CenterContainer" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection"]
+[node name="PreviewReal" type="CenterContainer" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection"]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 7
@@ -311,16 +315,16 @@ grow_vertical = 0
mouse_filter = 2
metadata/_edit_layout_mode = 1
-[node name="Control" type="Control" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/PreviewReal"]
+[node name="Control" type="Control" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/PreviewReal"]
layout_mode = 2
-[node name="RealSizeRemotePivotTransform" type="RemoteTransform2D" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/PreviewReal/Control"]
+[node name="RealSizeRemotePivotTransform" type="RemoteTransform2D" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/PreviewReal/Control"]
unique_name_in_owner = true
remote_path = NodePath("../../../ClipRect/Node2D/RealPreviewPivot")
update_rotation = false
update_scale = false
-[node name="FullPreviewAvailableRect" type="Control" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection"]
+[node name="FullPreviewAvailableRect" type="Control" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection"]
unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
@@ -335,7 +339,7 @@ grow_vertical = 2
mouse_filter = 2
metadata/_edit_layout_mode = 1
-[node name="HBoxContainer" type="HBoxContainer" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection"]
+[node name="HBoxContainer" type="HBoxContainer" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection"]
layout_mode = 1
anchors_preset = 10
anchor_right = 1.0
@@ -346,7 +350,7 @@ offset_bottom = 43.0
grow_horizontal = 2
mouse_filter = 2
-[node name="PreviewLabel" type="Label" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/HBoxContainer"]
+[node name="PreviewLabel" type="Label" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/HBoxContainer"]
unique_name_in_owner = true
show_behind_parent = true
layout_mode = 2
@@ -356,7 +360,7 @@ theme_override_colors/font_color = Color(0, 0, 0, 1)
text = "No portrait to preview."
text_overrun_behavior = 1
-[node name="FitPreview_Toggle" type="Button" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/HBoxContainer"]
+[node name="FitPreview_Toggle" type="Button" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/HBoxContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 0
@@ -368,22 +372,22 @@ icon = SubResource("ImageTexture_u1a6g")
flat = true
metadata/_edit_layout_mode = 1
-[node name="VBox" type="VBoxContainer" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection"]
+[node name="VBox" type="VBoxContainer" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
size_flags_stretch_ratio = 0.75
-[node name="Hbox" type="HBoxContainer" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/VBox"]
+[node name="Hbox" type="HBoxContainer" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/VBox"]
layout_mode = 2
-[node name="PortraitSettingsTitle" type="Label" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/VBox/Hbox"]
+[node name="PortraitSettingsTitle" type="Label" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/VBox/Hbox"]
unique_name_in_owner = true
layout_mode = 2
theme_type_variation = &"DialogicSubTitle"
text = "Portrait Settings"
-[node name="SwitchPortraitSettingsPosition" type="Button" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/VBox/Hbox"]
+[node name="SwitchPortraitSettingsPosition" type="Button" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/VBox/Hbox"]
unique_name_in_owner = true
modulate = Color(1, 1, 1, 0.647059)
layout_mode = 2
@@ -392,19 +396,19 @@ focus_mode = 0
icon = SubResource("ImageTexture_u1a6g")
flat = true
-[node name="Scroll" type="ScrollContainer" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/VBox"]
+[node name="Scroll" type="ScrollContainer" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/VBox"]
layout_mode = 2
size_flags_vertical = 3
size_flags_stretch_ratio = 0.4
-[node name="PortraitSettingsSection" type="VBoxContainer" parent="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/VBox/Scroll"]
+[node name="PortraitSettingsSection" type="VBoxContainer" parent="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/VBox/Scroll"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 3
size_flags_stretch_ratio = 0.3
-[node name="Spacer2" type="Control" parent="VBoxContainer/MainHSplit/Split/RightSection2"]
+[node name="Spacer2" type="Control" parent="Scroll/VBox/MainHSplit/Split/RightSection2"]
custom_minimum_size = Vector2(0, 20)
layout_mode = 2
@@ -442,11 +446,11 @@ autowrap_mode = 3
layout_mode = 2
text = "Create New Character"
-[connection signal="toggled" from="VBoxContainer/TopSection/MainSettingsCollapse" to="." method="_on_main_settings_collapse_toggled"]
-[connection signal="item_mouse_selected" from="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitTreePanel/PortraitTree" to="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitTreePanel/PortraitTree" method="_on_item_mouse_selected"]
-[connection signal="index_pressed" from="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitTreePanel/PortraitTree/PortraitRightClickMenu" to="." method="_on_portrait_right_click_menu_index_pressed"]
-[connection signal="pressed" from="VBoxContainer/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitChangeInfo/ReferenceMangerButton" to="." method="_on_reference_manger_button_pressed"]
-[connection signal="resized" from="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/FullPreviewAvailableRect" to="." method="_on_full_preview_available_rect_resized"]
-[connection signal="toggled" from="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/HBoxContainer/FitPreview_Toggle" to="." method="_on_fit_preview_toggle_toggled"]
-[connection signal="pressed" from="VBoxContainer/MainHSplit/Split/RightSection2/RightSection/VBox/Hbox/SwitchPortraitSettingsPosition" to="." method="_on_switch_portrait_settings_position_pressed"]
+[connection signal="toggled" from="Scroll/VBox/TopSection/MainSettingsCollapse" to="." method="_on_main_settings_collapse_toggled"]
+[connection signal="item_mouse_selected" from="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitTreePanel/PortraitTree" to="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitTreePanel/PortraitTree" method="_on_item_mouse_selected"]
+[connection signal="index_pressed" from="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitTreePanel/PortraitTree/PortraitRightClickMenu" to="." method="_on_portrait_right_click_menu_index_pressed"]
+[connection signal="pressed" from="Scroll/VBox/MainHSplit/Split/HBoxContainer/MarginContainer/PortraitListSection/Portraits/PortraitChangeInfo/ReferenceMangerButton" to="." method="_on_reference_manger_button_pressed"]
+[connection signal="resized" from="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/FullPreviewAvailableRect" to="." method="_on_full_preview_available_rect_resized"]
+[connection signal="toggled" from="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/PortraitPreviewSection/HBoxContainer/FitPreview_Toggle" to="." method="_on_fit_preview_toggle_toggled"]
+[connection signal="pressed" from="Scroll/VBox/MainHSplit/Split/RightSection2/RightSection/VBox/Hbox/SwitchPortraitSettingsPosition" to="." method="_on_switch_portrait_settings_position_pressed"]
[connection signal="pressed" from="NoCharacterScreen/CenterContainer/VBoxContainer/CreateCharacterButton" to="." method="_on_create_character_button_pressed"]
diff --git a/addons/dialogic/Editor/CharacterEditor/character_editor_main_settings_section.gd b/addons/dialogic/Editor/CharacterEditor/character_editor_main_settings_section.gd
index dc787ed9f..d329d0659 100644
--- a/addons/dialogic/Editor/CharacterEditor/character_editor_main_settings_section.gd
+++ b/addons/dialogic/Editor/CharacterEditor/character_editor_main_settings_section.gd
@@ -8,7 +8,7 @@ extends Control
signal changed
## Reference to the character editor, set when instantiated
-var character_editor:Control
+var character_editor: Control
## If not empty, a hint icon is added to the section title.
var hint_text := ""
diff --git a/addons/dialogic/Editor/CharacterEditor/character_editor_portrait_settings_section.gd b/addons/dialogic/Editor/CharacterEditor/character_editor_portrait_settings_section.gd
index 864e3bc60..920f8a576 100644
--- a/addons/dialogic/Editor/CharacterEditor/character_editor_portrait_settings_section.gd
+++ b/addons/dialogic/Editor/CharacterEditor/character_editor_portrait_settings_section.gd
@@ -12,10 +12,10 @@ signal changed
signal update_preview
## Reference to the character editor, set when instantiated
-var character_editor:Control
+var character_editor: Control
## Reference to the selected portrait item.
## `selected_item.get_metadata(0)` can access the portraits data
-var selected_item :TreeItem = null
+var selected_item: TreeItem = null
## If not empty a hint icon is added to the section title
var hint_text := ""
diff --git a/addons/dialogic/Editor/CharacterEditor/character_editor_portrait_tree.gd b/addons/dialogic/Editor/CharacterEditor/character_editor_portrait_tree.gd
index 573358922..c6fcf4666 100644
--- a/addons/dialogic/Editor/CharacterEditor/character_editor_portrait_tree.gd
+++ b/addons/dialogic/Editor/CharacterEditor/character_editor_portrait_tree.gd
@@ -3,7 +3,7 @@ extends Tree
## Tree that displays the portrait list as a hirarchy
-var editor = find_parent('Character Editor')
+var editor := find_parent('Character Editor')
var current_group_nodes := {}
@@ -19,8 +19,8 @@ func clear_tree() -> void:
current_group_nodes = {}
-func add_portrait_item(portrait_name:String, portrait_data:Dictionary, parent_item:TreeItem, previous_name:String = "") -> TreeItem:
- var item :TreeItem = %PortraitTree.create_item(parent_item)
+func add_portrait_item(portrait_name: String, portrait_data: Dictionary, parent_item: TreeItem, previous_name := "") -> TreeItem:
+ var item: TreeItem = %PortraitTree.create_item(parent_item)
item.set_text(0, portrait_name)
item.set_metadata(0, portrait_data)
if previous_name.is_empty():
@@ -32,8 +32,8 @@ func add_portrait_item(portrait_name:String, portrait_data:Dictionary, parent_it
return item
-func add_portrait_group(goup_name:String = "Group", parent_item:TreeItem = get_root(), previous_name:String = "") -> TreeItem:
- var item :TreeItem = %PortraitTree.create_item(parent_item)
+func add_portrait_group(goup_name := "Group", parent_item: TreeItem = get_root(), previous_name := "") -> TreeItem:
+ var item: TreeItem = %PortraitTree.create_item(parent_item)
item.set_icon(0, get_theme_icon("Folder", "EditorIcons"))
item.set_text(0, goup_name)
item.set_metadata(0, {'group':true})
@@ -44,7 +44,7 @@ func add_portrait_group(goup_name:String = "Group", parent_item:TreeItem = get_r
return item
-func get_full_item_name(item:TreeItem) -> String:
+func get_full_item_name(item: TreeItem) -> String:
var item_name := item.get_text(0)
while item.get_parent() != get_root() and item != get_root():
item_name = item.get_parent().get_text(0)+"/"+item_name
@@ -52,9 +52,9 @@ func get_full_item_name(item:TreeItem) -> String:
return item_name
-# Will create all not yet existing folders in the given path.
-# Returns the last folder (the parent of the portrait item of this path).
-func create_necessary_group_items(path:String) -> TreeItem:
+## Will create all not yet existing folders in the given path.
+## Returns the last folder (the parent of the portrait item of this path).
+func create_necessary_group_items(path: String) -> TreeItem:
var last_item := get_root()
var item_path := ""
@@ -64,13 +64,13 @@ func create_necessary_group_items(path:String) -> TreeItem:
if current_group_nodes.has(item_path+"/"+i):
last_item = current_group_nodes[item_path+"/"+i]
else:
- var new_item:TreeItem = add_portrait_group(i, last_item)
+ var new_item: TreeItem = add_portrait_group(i, last_item)
current_group_nodes[item_path+"/"+i] = new_item
last_item = new_item
return last_item
-func _on_item_mouse_selected(pos:Vector2, mouse_button_index:int) -> void:
+func _on_item_mouse_selected(pos: Vector2, mouse_button_index: int) -> void:
if mouse_button_index == MOUSE_BUTTON_RIGHT:
$PortraitRightClickMenu.set_item_disabled(1, get_selected().get_metadata(0).has('group'))
$PortraitRightClickMenu.popup_on_parent(Rect2(get_global_mouse_position(),Vector2()))
@@ -80,7 +80,7 @@ func _on_item_mouse_selected(pos:Vector2, mouse_button_index:int) -> void:
## DRAG AND DROP
################################################################################
-func _get_drag_data(position:Vector2) -> Variant:
+func _get_drag_data(position: Vector2) -> Variant:
drop_mode_flags = DROP_MODE_INBETWEEN
var preview := Label.new()
preview.text = " "+get_selected().get_text(0)
@@ -90,14 +90,14 @@ func _get_drag_data(position:Vector2) -> Variant:
return get_selected()
-func _can_drop_data(position:Vector2, data:Variant) -> bool:
+func _can_drop_data(position: Vector2, data: Variant) -> bool:
return data is TreeItem
-func _drop_data(position:Vector2, item:Variant) -> void:
+func _drop_data(position: Vector2, item: Variant) -> void:
var to_item := get_item_at_position(position)
if to_item:
- var test_item:= to_item
+ var test_item := to_item
while true:
if test_item == item:
return
@@ -126,8 +126,8 @@ func _drop_data(position:Vector2, item:Variant) -> void:
item.free()
-func copy_branch_or_item(item:TreeItem, new_parent:TreeItem) -> TreeItem:
- var new_item :TreeItem = null
+func copy_branch_or_item(item: TreeItem, new_parent: TreeItem) -> TreeItem:
+ var new_item: TreeItem = null
if item.get_metadata(0).has('group'):
new_item = add_portrait_group(item.get_text(0), new_parent, item.get_meta('previous_name'))
else:
@@ -136,4 +136,3 @@ func copy_branch_or_item(item:TreeItem, new_parent:TreeItem) -> TreeItem:
for child in item.get_children():
copy_branch_or_item(child, new_item)
return new_item
-
diff --git a/addons/dialogic/Editor/CharacterEditor/portrait_scene_browser.gd b/addons/dialogic/Editor/CharacterEditor/portrait_scene_browser.gd
new file mode 100644
index 000000000..119f813d2
--- /dev/null
+++ b/addons/dialogic/Editor/CharacterEditor/portrait_scene_browser.gd
@@ -0,0 +1,126 @@
+@tool
+extends Control
+
+var ListItem := load("res://addons/dialogic/Editor/Common/BrowserItem.tscn")
+
+enum Types {ALL, GENERAL, PRESET}
+var current_type := Types.ALL
+var current_info := {}
+
+var portrait_scenes_info := {}
+
+signal activate_part(part_info:Dictionary)
+
+
+func _ready() -> void:
+ collect_portrait_scenes()
+
+ %Search.right_icon = get_theme_icon("Search", "EditorIcons")
+ %CloseButton.icon = get_theme_icon("Close", "EditorIcons")
+
+ get_parent().close_requested.connect(_on_close_button_pressed)
+ get_parent().visibility_changed.connect(func():if get_parent().visible: open())
+
+
+func collect_portrait_scenes() -> void:
+ for indexer in DialogicUtil.get_indexers():
+ for element in indexer._get_portrait_scene_presets():
+ portrait_scenes_info[element.get('path', '')] = element
+
+
+func open() -> void:
+ collect_portrait_scenes()
+ load_parts()
+
+
+func is_premade_portrait_scene(scene_path:String) -> bool:
+ return scene_path in portrait_scenes_info
+
+
+func load_parts() -> void:
+ for i in %PartGrid.get_children():
+ i.queue_free()
+
+ %Search.placeholder_text = "Search for "
+ %Search.text = ""
+ match current_type:
+ Types.GENERAL: %Search.placeholder_text += "general portrait scenes"
+ Types.PRESET: %Search.placeholder_text += "portrait scene presets"
+ Types.ALL: %Search.placeholder_text += "general portrait scenes and presets"
+
+ for info in portrait_scenes_info.values():
+ var type: String = info.get('type', '_')
+ if (current_type == Types.GENERAL and type != "General") or (current_type == Types.PRESET and type != "Preset"):
+ continue
+
+ var item: Node = ListItem.instantiate()
+ item.load_info(info)
+ %PartGrid.add_child(item)
+ item.set_meta('info', info)
+ item.clicked.connect(_on_item_clicked.bind(item, info))
+ item.focused.connect(_on_item_clicked.bind(item, info))
+ item.double_clicked.connect(emit_signal.bind('activate_part', info))
+
+ await get_tree().process_frame
+
+ if %PartGrid.get_child_count() > 0:
+ %PartGrid.get_child(0).clicked.emit()
+ %PartGrid.get_child(0).grab_focus()
+
+
+func _on_item_clicked(item: Node, info:Dictionary) -> void:
+ load_part_info(info)
+
+
+func load_part_info(info:Dictionary) -> void:
+ current_info = info
+ %PartTitle.text = info.get('name', 'Unknown Part')
+ %PartAuthor.text = "by "+info.get('author', 'Anonymus')
+ %PartDescription.text = info.get('description', '')
+
+ if info.get('preview_image', null) and ResourceLoader.exists(info.preview_image[0]):
+ %PreviewImage.texture = load(info.preview_image[0])
+ %PreviewImage.show()
+ else:
+ %PreviewImage.hide()
+
+ match info.type:
+ "General":
+ %ActivateButton.text = "Use this scene"
+ %TypeDescription.text = "This is a general use scene, it can be used directly."
+ "Preset":
+ %ActivateButton.text = "Customize this scene"
+ %TypeDescription.text = "This is a preset you can use for a custom portrait scene. Dialogic will promt you to save a copy of this scene that you can then use and customize."
+ "Default":
+ %ActivateButton.text = "Use default scene"
+ %TypeDescription.text = ""
+ "Custom":
+ %ActivateButton.text = "Select a custom scene"
+ %TypeDescription.text = ""
+
+ if info.get("documentation", ""):
+ %DocumentationButton.show()
+ %DocumentationButton.uri = info.documentation
+ else:
+ %DocumentationButton.hide()
+
+
+func _on_activate_button_pressed() -> void:
+ activate_part.emit(current_info)
+
+
+func _on_close_button_pressed() -> void:
+ get_parent().hide()
+
+
+func _on_search_text_changed(new_text: String) -> void:
+ for item in %PartGrid.get_children():
+ if new_text.is_empty():
+ item.show()
+ continue
+
+ if new_text.to_lower() in item.get_meta('info').name.to_lower():
+ item.show()
+ continue
+
+ item.hide()
diff --git a/addons/dialogic/Editor/CharacterEditor/portrait_scene_browser.tscn b/addons/dialogic/Editor/CharacterEditor/portrait_scene_browser.tscn
new file mode 100644
index 000000000..3e4ecc186
--- /dev/null
+++ b/addons/dialogic/Editor/CharacterEditor/portrait_scene_browser.tscn
@@ -0,0 +1,260 @@
+[gd_scene load_steps=11 format=3 uid="uid://b1wn8r84uh11b"]
+
+[ext_resource type="Script" path="res://addons/dialogic/Editor/CharacterEditor/portrait_scene_browser.gd" id="1_an6nc"]
+
+[sub_resource type="Gradient" id="Gradient_0o1u0"]
+colors = PackedColorArray(0.100572, 0.303996, 0.476999, 1, 0.296448, 0.231485, 0.52887, 1)
+
+[sub_resource type="GradientTexture2D" id="GradientTexture2D_gxpvv"]
+gradient = SubResource("Gradient_0o1u0")
+fill = 2
+fill_from = Vector2(0.478632, 1)
+fill_to = Vector2(0, 0)
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_we8bq"]
+content_margin_left = 6.0
+content_margin_top = 3.0
+content_margin_right = 6.0
+content_margin_bottom = 3.0
+draw_center = false
+border_width_left = 2
+border_width_top = 2
+border_width_right = 2
+border_width_bottom = 2
+border_color = Color(1, 1, 1, 0.615686)
+corner_radius_top_left = 5
+corner_radius_top_right = 5
+corner_radius_bottom_right = 5
+corner_radius_bottom_left = 5
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3x0xw"]
+content_margin_left = 6.0
+content_margin_top = 3.0
+content_margin_right = 6.0
+content_margin_bottom = 3.0
+draw_center = false
+border_width_left = 3
+border_width_top = 3
+border_width_right = 3
+border_width_bottom = 3
+border_color = Color(1, 1, 1, 1)
+corner_radius_top_left = 5
+corner_radius_top_right = 5
+corner_radius_bottom_right = 5
+corner_radius_bottom_left = 5
+expand_margin_left = 2.0
+expand_margin_top = 2.0
+expand_margin_right = 2.0
+expand_margin_bottom = 2.0
+
+[sub_resource type="Image" id="Image_lwe0k"]
+data = {
+"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
+"format": "RGBA8",
+"height": 16,
+"mipmaps": false,
+"width": 16
+}
+
+[sub_resource type="ImageTexture" id="ImageTexture_d2gam"]
+image = SubResource("Image_lwe0k")
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_lf1ht"]
+bg_color = Color(0.0588235, 0.0313726, 0.0980392, 1)
+border_width_left = 5
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_a5iyu"]
+bg_color = Color(1, 1, 1, 1)
+draw_center = false
+corner_radius_top_left = 10
+corner_radius_top_right = 10
+corner_radius_bottom_right = 10
+corner_radius_bottom_left = 10
+shadow_color = Color(0.992157, 0.992157, 0.992157, 0.101961)
+shadow_size = 10
+
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_htwsp"]
+bg_color = Color(1, 1, 1, 1)
+corner_radius_top_left = 10
+corner_radius_top_right = 10
+corner_radius_bottom_right = 10
+corner_radius_bottom_left = 10
+
+[node name="PortraitSceneBrowser" type="Control"]
+layout_mode = 3
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+script = ExtResource("1_an6nc")
+
+[node name="BGColor" type="TextureRect" parent="."]
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+texture = SubResource("GradientTexture2D_gxpvv")
+
+[node name="HSplitContainer" type="HSplitContainer" parent="."]
+clip_contents = true
+layout_mode = 1
+anchors_preset = 15
+anchor_right = 1.0
+anchor_bottom = 1.0
+grow_horizontal = 2
+grow_vertical = 2
+size_flags_vertical = 3
+
+[node name="Margin" type="MarginContainer" parent="HSplitContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_stretch_ratio = 1.5
+theme_override_constants/margin_left = 10
+theme_override_constants/margin_top = 10
+theme_override_constants/margin_right = 10
+theme_override_constants/margin_bottom = 10
+
+[node name="VBox" type="VBoxContainer" parent="HSplitContainer/Margin"]
+layout_mode = 2
+size_flags_horizontal = 3
+
+[node name="BrowserTitle" type="Label" parent="HSplitContainer/Margin/VBox"]
+layout_mode = 2
+theme_type_variation = &"DialogicSubTitle"
+theme_override_font_sizes/font_size = 25
+text = "Dialogic Portrait Scene Browser"
+
+[node name="HBox" type="HBoxContainer" parent="HSplitContainer/Margin/VBox"]
+layout_mode = 2
+
+[node name="Search" type="LineEdit" parent="HSplitContainer/Margin/VBox/HBox"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_styles/normal = SubResource("StyleBoxFlat_we8bq")
+theme_override_styles/focus = SubResource("StyleBoxFlat_3x0xw")
+placeholder_text = "Search"
+right_icon = SubResource("ImageTexture_d2gam")
+
+[node name="ScrollContainer" type="ScrollContainer" parent="HSplitContainer/Margin/VBox"]
+layout_mode = 2
+size_flags_vertical = 3
+
+[node name="PartGrid" type="HFlowContainer" parent="HSplitContainer/Margin/VBox/ScrollContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 3
+
+[node name="Buttons" type="HBoxContainer" parent="HSplitContainer/Margin/VBox"]
+layout_mode = 2
+alignment = 1
+
+[node name="CloseButton" type="Button" parent="HSplitContainer/Margin/VBox/Buttons"]
+unique_name_in_owner = true
+layout_mode = 2
+text = "Close"
+icon = SubResource("ImageTexture_d2gam")
+
+[node name="PanelContainer" type="PanelContainer" parent="HSplitContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+theme_override_styles/panel = SubResource("StyleBoxFlat_lf1ht")
+
+[node name="Control" type="Control" parent="HSplitContainer/PanelContainer"]
+layout_mode = 2
+
+[node name="Panel" type="Panel" parent="HSplitContainer/PanelContainer/Control"]
+layout_mode = 1
+anchors_preset = 9
+anchor_bottom = 1.0
+offset_left = -4.0
+offset_right = 40.0
+offset_bottom = 71.0
+grow_vertical = 2
+rotation = 0.0349066
+theme_override_styles/panel = SubResource("StyleBoxFlat_lf1ht")
+
+[node name="MarginContainer" type="MarginContainer" parent="HSplitContainer/PanelContainer"]
+layout_mode = 2
+theme_override_constants/margin_left = 5
+theme_override_constants/margin_top = 10
+theme_override_constants/margin_right = 10
+theme_override_constants/margin_bottom = 10
+
+[node name="VBox" type="VBoxContainer" parent="HSplitContainer/PanelContainer/MarginContainer"]
+layout_mode = 2
+alignment = 1
+
+[node name="Panel" type="PanelContainer" parent="HSplitContainer/PanelContainer/MarginContainer/VBox"]
+layout_mode = 2
+theme_override_styles/panel = SubResource("StyleBoxFlat_a5iyu")
+
+[node name="Panel" type="PanelContainer" parent="HSplitContainer/PanelContainer/MarginContainer/VBox/Panel"]
+clip_children = 1
+layout_mode = 2
+theme_override_styles/panel = SubResource("StyleBoxFlat_htwsp")
+
+[node name="PreviewImage" type="TextureRect" parent="HSplitContainer/PanelContainer/MarginContainer/VBox/Panel/Panel"]
+unique_name_in_owner = true
+layout_mode = 2
+expand_mode = 5
+stretch_mode = 6
+
+[node name="HFlowContainer" type="HFlowContainer" parent="HSplitContainer/PanelContainer/MarginContainer/VBox"]
+layout_mode = 2
+
+[node name="PartTitle" type="Label" parent="HSplitContainer/PanelContainer/MarginContainer/VBox/HFlowContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_vertical = 8
+theme_type_variation = &"DialogicTitle"
+text = "Cool Style Part"
+
+[node name="PartAuthor" type="Label" parent="HSplitContainer/PanelContainer/MarginContainer/VBox/HFlowContainer"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_vertical = 8
+theme_type_variation = &"DialogicHintText"
+text = "by Jowan"
+
+[node name="PartType" type="Label" parent="HSplitContainer/PanelContainer/MarginContainer/VBox/HFlowContainer"]
+visible = false
+layout_mode = 2
+size_flags_vertical = 8
+theme_type_variation = &"DialogicHintText"
+text = "a style"
+
+[node name="PartDescription" type="Label" parent="HSplitContainer/PanelContainer/MarginContainer/VBox"]
+unique_name_in_owner = true
+layout_mode = 2
+theme_type_variation = &"DialogicHintText2"
+text = "A cool textbox layer"
+autowrap_mode = 3
+
+[node name="DocumentationButton" type="LinkButton" parent="HSplitContainer/PanelContainer/MarginContainer/VBox"]
+unique_name_in_owner = true
+layout_mode = 2
+text = "Learn more"
+
+[node name="HSeparator" type="HSeparator" parent="HSplitContainer/PanelContainer/MarginContainer/VBox"]
+layout_mode = 2
+
+[node name="ActivateButton" type="Button" parent="HSplitContainer/PanelContainer/MarginContainer/VBox"]
+unique_name_in_owner = true
+layout_mode = 2
+text = "Use"
+
+[node name="TypeDescription" type="Label" parent="HSplitContainer/PanelContainer/MarginContainer/VBox"]
+unique_name_in_owner = true
+layout_mode = 2
+theme_type_variation = &"DialogicHintText"
+text = "A cool textbox layer"
+autowrap_mode = 3
+
+[connection signal="text_changed" from="HSplitContainer/Margin/VBox/HBox/Search" to="." method="_on_search_text_changed"]
+[connection signal="pressed" from="HSplitContainer/Margin/VBox/Buttons/CloseButton" to="." method="_on_close_button_pressed"]
+[connection signal="pressed" from="HSplitContainer/PanelContainer/MarginContainer/VBox/ActivateButton" to="." method="_on_activate_button_pressed"]
diff --git a/addons/dialogic/Modules/StyleEditor/Components/StyleItem.gd b/addons/dialogic/Editor/Common/BrowserItem.gd
similarity index 82%
rename from addons/dialogic/Modules/StyleEditor/Components/StyleItem.gd
rename to addons/dialogic/Editor/Common/BrowserItem.gd
index 08bc8325f..7bfb3cfc4 100644
--- a/addons/dialogic/Modules/StyleEditor/Components/StyleItem.gd
+++ b/addons/dialogic/Editor/Common/BrowserItem.gd
@@ -6,7 +6,7 @@ signal middle_clicked
signal double_clicked
signal focused
-var base_size = 1
+var base_size := 1
func _ready() -> void:
@@ -14,7 +14,7 @@ func _ready() -> void:
return
%Name.add_theme_font_override("font", get_theme_font("bold", "EditorFonts"))
- custom_minimum_size = base_size*Vector2(200, 150)*DialogicUtil.get_editor_scale()
+ custom_minimum_size = base_size * Vector2(200, 150) * DialogicUtil.get_editor_scale()
%CurrentIcon.texture = get_theme_icon("Favorites", "EditorIcons")
if %Image.texture == null:
%Image.texture = get_theme_icon("ImportFail", "EditorIcons")
@@ -23,7 +23,9 @@ func _ready() -> void:
func load_info(info:Dictionary) -> void:
%Name.text = info.name
- if info.preview_image[0] == 'custom':
+ if not info.has("preview_image"):
+ pass
+ elif info.preview_image[0] == 'custom':
await ready
%Image.texture = get_theme_icon("CreateNewSceneFrom", "EditorIcons")
%Image.stretch_mode = TextureRect.STRETCH_KEEP_CENTERED
@@ -32,6 +34,9 @@ func load_info(info:Dictionary) -> void:
DialogicUtil.get_dialogic_plugin().get_editor_interface().get_resource_previewer().queue_resource_preview(info.preview_image[0], self, 'set_scene_preview', null)
elif ResourceLoader.exists(info.preview_image[0]):
%Image.texture = load(info.preview_image[0])
+ elif info.preview_image[0].is_valid_html_color():
+ %Image.texture = null
+ %Panel.self_modulate = Color(info.preview_image[0])
if ResourceLoader.exists(info.get('icon', '')):
%Icon.get_parent().show()
@@ -54,11 +59,11 @@ func set_current(current:bool):
%CurrentIcon.visible = current
-func _on_mouse_entered():
+func _on_mouse_entered() -> void:
%HoverBG.show()
-func _on_mouse_exited():
+func _on_mouse_exited() -> void:
%HoverBG.hide()
@@ -72,10 +77,10 @@ func _on_gui_input(event):
middle_clicked.emit()
-func _on_focus_entered():
+func _on_focus_entered() -> void:
$FocusFG.show()
focused.emit()
-func _on_focus_exited():
+func _on_focus_exited() -> void:
$FocusFG.hide()
diff --git a/addons/dialogic/Modules/StyleEditor/Components/StyleItem.tscn b/addons/dialogic/Editor/Common/BrowserItem.tscn
similarity index 95%
rename from addons/dialogic/Modules/StyleEditor/Components/StyleItem.tscn
rename to addons/dialogic/Editor/Common/BrowserItem.tscn
index 7478ddd50..4abc87bdd 100644
--- a/addons/dialogic/Modules/StyleEditor/Components/StyleItem.tscn
+++ b/addons/dialogic/Editor/Common/BrowserItem.tscn
@@ -1,6 +1,6 @@
[gd_scene load_steps=6 format=3 uid="uid://ddlxjde1cx035"]
-[ext_resource type="Script" path="res://addons/dialogic/Modules/StyleEditor/Components/StyleItem.gd" id="1_is0qu"]
+[ext_resource type="Script" path="res://addons/dialogic/Editor/Common/BrowserItem.gd" id="1_s3kf0"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_pfw08"]
bg_color = Color(1, 1, 1, 0.32549)
@@ -45,7 +45,7 @@ expand_margin_top = 4.0
expand_margin_right = 4.0
expand_margin_bottom = 4.0
-[node name="Margin" type="MarginContainer"]
+[node name="BrowserItem" type="MarginContainer"]
custom_minimum_size = Vector2(200, 150)
offset_left = 1.0
offset_top = 1.0
@@ -57,7 +57,7 @@ theme_override_constants/margin_left = 4
theme_override_constants/margin_top = 4
theme_override_constants/margin_right = 4
theme_override_constants/margin_bottom = 4
-script = ExtResource("1_is0qu")
+script = ExtResource("1_s3kf0")
[node name="HoverBG" type="Panel" parent="."]
unique_name_in_owner = true
@@ -87,7 +87,7 @@ layout_mode = 2
size_flags_vertical = 3
mouse_filter = 2
expand_mode = 1
-stretch_mode = 5
+stretch_mode = 6
[node name="CurrentIcon" type="TextureRect" parent="VBox/Panel/Image"]
unique_name_in_owner = true
diff --git a/addons/dialogic/Editor/Common/DCSS.gd b/addons/dialogic/Editor/Common/DCSS.gd
index 93e60f3c9..2a1f95a2f 100644
--- a/addons/dialogic/Editor/Common/DCSS.gd
+++ b/addons/dialogic/Editor/Common/DCSS.gd
@@ -1,26 +1,26 @@
@tool
class_name DCSS
-static func get_editor_scale() -> float:
- return DialogicUtil.get_editor_scale()
-
-static func inline(style:Dictionary) -> StyleBoxFlat:
- var scale:float = get_editor_scale()
+static func inline(style: Dictionary) -> StyleBoxFlat:
+ var scale: float = DialogicUtil.get_editor_scale()
var s := StyleBoxFlat.new()
for property in style.keys():
match property:
'border-left':
s.set('border_width_left', style[property] * scale)
'border-radius':
- var radius:float = style[property] * scale
+ var radius: float = style[property] * scale
s.set('corner_radius_top_left', radius)
s.set('corner_radius_top_right', radius)
s.set('corner_radius_bottom_left', radius)
s.set('corner_radius_bottom_right', radius)
'background':
- s.set('bg_color', style[property])
+ if typeof(style[property]) == TYPE_STRING and style[property] == "none":
+ s.set('draw_center', false)
+ else:
+ s.set('bg_color', style[property])
'border':
- var width:float = style[property] * scale
+ var width: float = style[property] * scale
s.set('border_width_left', width)
s.set('border_width_right', width)
s.set('border_width_top', width)
@@ -45,16 +45,3 @@ static func inline(style:Dictionary) -> StyleBoxFlat:
'padding-left':
s.set('content_margin_left', style[property] * scale)
return s
-
-static func style(node, style:Dictionary) -> StyleBoxFlat:
- var scale:float = get_editor_scale()
- var s:StyleBoxFlat = inline(style)
-
- node.set('theme_override_styles/normal', s)
- node.set('theme_override_styles/focus', s)
- node.set('theme_override_styles/read_only', s)
- node.set('theme_override_styles/hover', s)
- node.set('theme_override_styles/pressed', s)
- node.set('theme_override_styles/disabled', s)
- node.set('theme_override_styles/panel', s)
- return s
diff --git a/addons/dialogic/Editor/Common/ReferenceManager_AddReplacementPanel.gd b/addons/dialogic/Editor/Common/ReferenceManager_AddReplacementPanel.gd
index 685bb2e72..22626199c 100644
--- a/addons/dialogic/Editor/Common/ReferenceManager_AddReplacementPanel.gd
+++ b/addons/dialogic/Editor/Common/ReferenceManager_AddReplacementPanel.gd
@@ -5,7 +5,7 @@ extends PanelContainer
enum Modes {EDIT, ADD}
var mode := Modes.EDIT
-var item :TreeItem = null
+var item: TreeItem = null
func _ready() -> void:
@@ -86,7 +86,7 @@ func get_character_suggestions(search_text:String) -> Dictionary:
var suggestions := {}
#override the previous _character_directory with the meta, specifically for searching otherwise new nodes wont work
- var _character_directory = DialogicResourceUtil.get_character_directory()
+ var _character_directory := DialogicResourceUtil.get_character_directory()
var icon := load("res://addons/dialogic/Editor/Images/Resources/character.svg")
suggestions['(No one)'] = {'value':null, 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
@@ -99,7 +99,7 @@ func get_character_suggestions(search_text:String) -> Dictionary:
return suggestions
-func save():
+func save() -> void:
if %Old.text.is_empty() or %New.text.is_empty():
return
if %Where.selected == 1 and %Character.current_value == null:
diff --git a/addons/dialogic/Editor/Common/broken_reference_manager.gd b/addons/dialogic/Editor/Common/broken_reference_manager.gd
index 36627d0c2..b0d11cc3d 100644
--- a/addons/dialogic/Editor/Common/broken_reference_manager.gd
+++ b/addons/dialogic/Editor/Common/broken_reference_manager.gd
@@ -3,7 +3,7 @@ extends VSplitContainer
## This manager shows a list of changed references and allows searching for them and replacing them.
-var reference_changes :Array[Dictionary] = []:
+var reference_changes: Array[Dictionary] = []:
set(changes):
reference_changes = changes
update_indicator()
@@ -55,7 +55,7 @@ func open() -> void:
%ChangeTree.set_column_custom_minimum_width(2, 50)
var categories := {null:%ChangeTree.get_root()}
for i in reference_changes:
- var parent : TreeItem = null
+ var parent: TreeItem = null
if !i.get('category', null) in categories:
parent = %ChangeTree.create_item()
parent.set_text(1, i.category)
@@ -64,7 +64,7 @@ func open() -> void:
else:
parent = categories[i.get('category')]
- var item :TreeItem = %ChangeTree.create_item(parent)
+ var item: TreeItem = %ChangeTree.create_item(parent)
item.set_text(1, i.what+" -> "+i.forwhat)
item.add_button(1, get_theme_icon("Edit", "EditorIcons"), 1, false, 'Edit')
item.add_button(1, get_theme_icon("Remove", "EditorIcons"), 0, false, 'Remove Change from List')
@@ -98,8 +98,8 @@ func _on_change_tree_item_edited() -> void:
func _on_check_button_pressed() -> void:
- var to_be_checked :Array[Dictionary]= []
- var item :TreeItem = %ChangeTree.get_root()
+ var to_be_checked: Array[Dictionary]= []
+ var item: TreeItem = %ChangeTree.get_root()
while item.get_next_visible():
item = item.get_next_visible()
@@ -142,7 +142,7 @@ func _process(delta: float) -> void:
%Progress.value = progress_percent
progress_mutex.unlock()
else:
- var finds := finder_thread.wait_to_finish()
+ var finds: Variant = finder_thread.wait_to_finish()
display_search_results(finds)
@@ -236,7 +236,7 @@ func search_timelines(regexes:Array[Array]) -> Array[Dictionary]:
func _exit_tree() -> void:
# Shutting of
- if finder_thread.is_alive():
+ if finder_thread and finder_thread.is_alive():
finder_thread.wait_to_finish()
@@ -245,7 +245,7 @@ func get_line(string:String, at_index:int) -> String:
func update_count_coloring() -> void:
- var item :TreeItem = %ChangeTree.get_root()
+ var item: TreeItem = %ChangeTree.get_root()
while item.get_next_visible():
item = item.get_next_visible()
@@ -264,9 +264,9 @@ func update_count_coloring() -> void:
func _on_replace_pressed() -> void:
- var to_be_replaced :Array[Dictionary]= []
- var item :TreeItem = %ReferenceTree.get_root()
- var affected_timelines :Array[String]= []
+ var to_be_replaced: Array[Dictionary]= []
+ var item: TreeItem = %ReferenceTree.get_root()
+ var affected_timelines: Array[String]= []
while item.get_next_visible():
item = item.get_next_visible()
@@ -284,7 +284,7 @@ func _on_replace_pressed() -> void:
func replace(timelines:Array[String], replacement_info:Array[Dictionary]) -> void:
var reopen_timeline := ""
- var timeline_editor :DialogicEditor = find_parent('EditorView').editors_manager.editors['Timeline'].node
+ var timeline_editor: DialogicEditor = find_parent('EditorView').editors_manager.editors['Timeline'].node
if timeline_editor.current_resource != null and timeline_editor.current_resource.resource_path in timelines:
reopen_timeline = timeline_editor.current_resource.resource_path
find_parent('EditorView').editors_manager.clear_editor(timeline_editor)
@@ -295,7 +295,7 @@ func replace(timelines:Array[String], replacement_info:Array[Dictionary]) -> voi
%State.text = "Loading '"+timeline_path+"'"
var timeline_file := FileAccess.open(timeline_path, FileAccess.READ_WRITE)
- var timeline_text :String = timeline_file.get_as_text()
+ var timeline_text: String = timeline_file.get_as_text()
var timeline_events := timeline_text.split('\n')
timeline_file.close()
@@ -343,7 +343,7 @@ func update_indicator() -> void:
func close() -> void:
- var item :TreeItem = %ChangeTree.get_root()
+ var item: TreeItem = %ChangeTree.get_root()
if item:
while item.get_next_visible():
item = item.get_next_visible()
diff --git a/addons/dialogic/Editor/Common/hint_tooltip_icon.gd b/addons/dialogic/Editor/Common/hint_tooltip_icon.gd
index 940d2bd43..702fe9835 100644
--- a/addons/dialogic/Editor/Common/hint_tooltip_icon.gd
+++ b/addons/dialogic/Editor/Common/hint_tooltip_icon.gd
@@ -1,9 +1,12 @@
@tool
extends TextureRect
-@export_multiline var hint_text = ""
+@export_multiline var hint_text := ""
-func _ready():
+func _ready() -> void:
+ if owner and owner.get_parent() is SubViewport:
+ texture = null
+ return
texture = get_theme_icon("NodeInfo", "EditorIcons")
- modulate = get_theme_color("readonly_color", "Editor")
+ modulate = get_theme_color("contrast_color_1", "Editor")
tooltip_text = hint_text
diff --git a/addons/dialogic/Editor/Common/reference_manager.gd b/addons/dialogic/Editor/Common/reference_manager.gd
index c33ca282e..915e594e6 100644
--- a/addons/dialogic/Editor/Common/reference_manager.gd
+++ b/addons/dialogic/Editor/Common/reference_manager.gd
@@ -7,16 +7,17 @@ func _ready() -> void:
return
add_theme_stylebox_override("panel", get_theme_stylebox("Background", "EditorStyles"))
+ $Tabs/Close.icon = get_theme_icon("Close", "EditorIcons")
for tab in $Tabs/Tabs.get_children():
tab.add_theme_color_override("font_selected_color", get_theme_color("accent_color", "Editor"))
- tab.add_theme_font_override("font", get_theme_font("main_button_font", "EditorFonts"))
+ tab.add_theme_font_override("font", get_theme_font("main", "EditorFonts"))
tab.toggled.connect(tab_changed.bind(tab.get_index()+1))
func tab_changed(enabled:bool, index:int) -> void:
for child in $Tabs.get_children():
- if child.get_index() == 0 or child.get_index() == index:
+ if child.get_index() == 0 or child.get_index() == index or child is Button:
child.show()
if child.get_index() == index:
child.open()
@@ -28,6 +29,10 @@ func tab_changed(enabled:bool, index:int) -> void:
child.set_pressed_no_signal(index-1 == child.get_index())
-func open():
+func open() -> void:
show()
$Tabs/BrokenReferences.update_indicator()
+
+
+func _on_close_pressed() -> void:
+ get_parent()._on_close_requested()
diff --git a/addons/dialogic/Editor/Common/reference_manager.tscn b/addons/dialogic/Editor/Common/reference_manager.tscn
index 1774073c1..0bd60734b 100644
--- a/addons/dialogic/Editor/Common/reference_manager.tscn
+++ b/addons/dialogic/Editor/Common/reference_manager.tscn
@@ -8,7 +8,7 @@
[sub_resource type="ButtonGroup" id="ButtonGroup_l6uiy"]
-[sub_resource type="Image" id="Image_ii0d5"]
+[sub_resource type="Image" id="Image_36731"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 224, 224, 224, 255, 224, 224, 224, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -18,9 +18,9 @@ data = {
}
[sub_resource type="ImageTexture" id="ImageTexture_a0gfq"]
-image = SubResource("Image_ii0d5")
+image = SubResource("Image_36731")
-[sub_resource type="Image" id="Image_k5gyt"]
+[sub_resource type="Image" id="Image_0rvkq"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -29,10 +29,10 @@ data = {
"width": 16
}
-[sub_resource type="ImageTexture" id="ImageTexture_8oycd"]
-image = SubResource("Image_k5gyt")
+[sub_resource type="ImageTexture" id="ImageTexture_mr0fw"]
+image = SubResource("Image_0rvkq")
-[sub_resource type="Image" id="Image_qpnp8"]
+[sub_resource type="Image" id="Image_5fmdt"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -42,7 +42,7 @@ data = {
}
[sub_resource type="ImageTexture" id="ImageTexture_lce2m"]
-image = SubResource("Image_qpnp8")
+image = SubResource("Image_5fmdt")
[node name="Manager" type="PanelContainer"]
anchors_preset = 15
@@ -163,14 +163,14 @@ unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Match Case"
toggle_mode = true
-icon = SubResource("ImageTexture_8oycd")
+icon = SubResource("ImageTexture_mr0fw")
[node name="WholeWords" type="Button" parent="Tabs/BrokenReferences/ChangesList/VBox/ReplacementEditPanel/VBox/PureTextFlags"]
unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Whole World"
toggle_mode = true
-icon = SubResource("ImageTexture_8oycd")
+icon = SubResource("ImageTexture_mr0fw")
[node name="HBoxContainer4" type="HBoxContainer" parent="Tabs/BrokenReferences/ChangesList/VBox/ReplacementEditPanel/VBox"]
layout_mode = 2
@@ -298,12 +298,16 @@ layout_mode = 2
text = "You've renamed some identifier(s)! Use the \"Broken References\" tab to check if you have used this identifier (and fix it if so)."
autowrap_mode = 3
+[node name="Close" type="Button" parent="Tabs"]
+layout_mode = 2
+size_flags_horizontal = 4
+text = "Close"
+
[node name="HelpButton" type="LinkButton" parent="."]
-custom_minimum_size = Vector2(0, 30)
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 0
-text = "What is this about?"
+text = "Documentation"
uri = "https://docs.dialogic.pro/reference-manager.html"
[connection signal="pressed" from="Tabs/BrokenReferences/ChangesList/VBox/HBoxContainer/AddButton" to="Tabs/BrokenReferences" method="_on_add_button_pressed"]
@@ -317,3 +321,4 @@ uri = "https://docs.dialogic.pro/reference-manager.html"
[connection signal="text_changed" from="Tabs/UniqueIdentifiers/VBox/Tools/Search" to="Tabs/UniqueIdentifiers" method="_on_search_text_changed"]
[connection signal="button_clicked" from="Tabs/UniqueIdentifiers/VBox/IdentifierTable" to="Tabs/UniqueIdentifiers" method="_on_identifier_table_button_clicked"]
[connection signal="item_edited" from="Tabs/UniqueIdentifiers/VBox/IdentifierTable" to="Tabs/UniqueIdentifiers" method="_on_identifier_table_item_edited"]
+[connection signal="pressed" from="Tabs/Close" to="." method="_on_close_pressed"]
diff --git a/addons/dialogic/Editor/Common/reference_manager_window.gd b/addons/dialogic/Editor/Common/reference_manager_window.gd
index fae954c12..7bb42ec72 100644
--- a/addons/dialogic/Editor/Common/reference_manager_window.gd
+++ b/addons/dialogic/Editor/Common/reference_manager_window.gd
@@ -5,12 +5,12 @@ extends Window
## Other scripts can call the add_ref_change() method to register changes directly
## or use the helpers add_variable_ref_change() and add_portrait_ref_change()
-@onready var editors_manager := get_node("../Margin/EditorsManager")
+@onready var editors_manager := get_node("../EditorsManager")
@onready var broken_manager := get_node("Manager/Tabs/BrokenReferences")
enum Where {EVERYWHERE, BY_CHARACTER, TEXTS_ONLY}
enum Types {TEXT, VARIABLE, PORTRAIT, CHARACTER_NAME, TIMELINE_NAME}
-var icon_button :Button = null
+var icon_button: Button = null
func _ready() -> void:
@@ -31,7 +31,7 @@ func _ready() -> void:
icon_button.add_child(dot)
- var old_changes :Array = DialogicUtil.get_editor_setting('reference_changes', [])
+ var old_changes: Array = DialogicUtil.get_editor_setting('reference_changes', [])
if !old_changes.is_empty():
broken_manager.reference_changes = old_changes
diff --git a/addons/dialogic/Editor/Common/side_bar.tscn b/addons/dialogic/Editor/Common/side_bar.tscn
index a9dc0d0d0..72f82cd45 100644
--- a/addons/dialogic/Editor/Common/side_bar.tscn
+++ b/addons/dialogic/Editor/Common/side_bar.tscn
@@ -1,6 +1,8 @@
-[gd_scene load_steps=5 format=3 uid="uid://cwe3r2tbh2og1"]
+[gd_scene load_steps=7 format=3 uid="uid://cwe3r2tbh2og1"]
[ext_resource type="Script" path="res://addons/dialogic/Editor/Common/sidebar.gd" id="1_jnq65"]
+[ext_resource type="Texture2D" uid="uid://bff65e82555qr" path="res://addons/dialogic/Editor/Images/Pieces/close-icon.svg" id="2_54pks"]
+[ext_resource type="Texture2D" uid="uid://dx3o2ild56i76" path="res://addons/dialogic/Editor/Images/Pieces/closed-icon.svg" id="2_ilyps"]
[sub_resource type="Theme" id="Theme_pn0f4"]
VBoxContainer/constants/separation = 4
@@ -20,24 +22,41 @@ theme = SubResource("Theme_pn0f4")
split_offset = 100
script = ExtResource("1_jnq65")
-[node name="VBox" type="VBoxContainer" parent="."]
+[node name="VBoxHidden" type="VBoxContainer" parent="."]
+unique_name_in_owner = true
+visible = false
+layout_mode = 2
+
+[node name="OpenButton" type="Button" parent="VBoxHidden"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 0
+size_flags_vertical = 3
+tooltip_text = "Show Sidebar"
+theme_override_constants/icon_max_width = 20
+icon = ExtResource("2_ilyps")
+flat = true
+icon_alignment = 1
+
+[node name="VBoxPrimary" type="VBoxContainer" parent="."]
+unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
-[node name="Margin" type="MarginContainer" parent="VBox"]
+[node name="Margin" type="MarginContainer" parent="VBoxPrimary"]
layout_mode = 2
size_flags_vertical = 3
theme_override_constants/margin_left = 5
theme_override_constants/margin_bottom = 5
-[node name="VSplitContainer" type="VSplitContainer" parent="VBox/Margin"]
+[node name="VSplitContainer" type="VSplitContainer" parent="VBoxPrimary/Margin"]
layout_mode = 2
-[node name="VBox" type="VBoxContainer" parent="VBox/Margin/VSplitContainer"]
+[node name="VBox" type="VBoxContainer" parent="VBoxPrimary/Margin/VSplitContainer"]
layout_mode = 2
size_flags_vertical = 3
-[node name="Logo" type="TextureRect" parent="VBox/Margin/VSplitContainer/VBox"]
+[node name="Logo" type="TextureRect" parent="VBoxPrimary/Margin/VSplitContainer/VBox"]
unique_name_in_owner = true
modulate = Color(1, 1, 1, 0.623529)
texture_filter = 6
@@ -46,49 +65,111 @@ layout_mode = 2
expand_mode = 3
stretch_mode = 4
-[node name="CurrentResource" type="Label" parent="VBox/Margin/VSplitContainer/VBox"]
+[node name="HBox" type="HBoxContainer" parent="VBoxPrimary/Margin/VSplitContainer/VBox"]
+layout_mode = 2
+
+[node name="CurrentResource" type="LineEdit" parent="VBoxPrimary/Margin/VSplitContainer/VBox/HBox"]
unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
text = "No resource"
-horizontal_alignment = 1
-vertical_alignment = 1
-text_overrun_behavior = 1
+alignment = 1
+editable = false
-[node name="Search" type="LineEdit" parent="VBox/Margin/VSplitContainer/VBox"]
+[node name="CloseButton" type="Button" parent="VBoxPrimary/Margin/VSplitContainer/VBox/HBox"]
unique_name_in_owner = true
layout_mode = 2
+tooltip_text = "Hide Sidebar"
+text = " "
+icon = ExtResource("2_54pks")
+flat = true
+icon_alignment = 1
+expand_icon = true
+
+[node name="HBoxSearchSort" type="HBoxContainer" parent="VBoxPrimary/Margin/VSplitContainer/VBox"]
+layout_mode = 2
+
+[node name="Search" type="LineEdit" parent="VBoxPrimary/Margin/VSplitContainer/VBox/HBoxSearchSort"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 3
+tooltip_text = "Filter Resources"
placeholder_text = "Filter Resources"
caret_blink = true
caret_blink_interval = 0.5
-[node name="ResourcesList" type="ItemList" parent="VBox/Margin/VSplitContainer/VBox"]
+[node name="SortOption" type="OptionButton" parent="VBoxPrimary/Margin/VSplitContainer/VBox/HBoxSearchSort"]
+unique_name_in_owner = true
+layout_mode = 2
+tooltip_text = "Sort
+- Default: Sort alphabetically split into Characters & Timeilnes.
+- Folder: Sort alphabetically by parent directory.
+- Path: Display full path relative to res://.
+- None: Sort alphabetically with no categories."
+text_overrun_behavior = 1
+clip_text = true
+selected = 0
+item_count = 4
+popup/item_0/text = "Type"
+popup/item_1/text = "Folder"
+popup/item_1/id = 1
+popup/item_2/text = "Path"
+popup/item_2/id = 2
+popup/item_3/text = "None"
+popup/item_3/id = 3
+
+[node name="ResourceTree" type="Tree" parent="VBoxPrimary/Margin/VSplitContainer/VBox"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
-same_column_width = true
+allow_rmb_select = true
+hide_root = true
+scroll_horizontal_enabled = false
+
+[node name="HBoxContainer" type="HBoxContainer" parent="VBoxPrimary/Margin/VSplitContainer/VBox"]
+visible = false
+layout_mode = 2
-[node name="ContentListSection" type="VBoxContainer" parent="VBox/Margin/VSplitContainer"]
+[node name="Label" type="Label" parent="VBoxPrimary/Margin/VSplitContainer/VBox/HBoxContainer"]
+layout_mode = 2
+size_flags_vertical = 1
+text = "Sort Order"
+vertical_alignment = 1
+
+[node name="SortOption" type="OptionButton" parent="VBoxPrimary/Margin/VSplitContainer/VBox/HBoxContainer"]
+layout_mode = 2
+size_flags_horizontal = 3
+item_count = 1
+popup/item_0/text = "Alphabetical (All)"
+
+[node name="ContentListSection" type="VBoxContainer" parent="VBoxPrimary/Margin/VSplitContainer"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
-[node name="ContentList" type="ItemList" parent="VBox/Margin/VSplitContainer/ContentListSection"]
+[node name="ContentList" type="ItemList" parent="VBoxPrimary/Margin/VSplitContainer/ContentListSection"]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
+tooltip_text = "Label events in your timeline will appear here, allowing you to jump to them."
theme_override_styles/selected = SubResource("StyleBoxEmpty_gxwm6")
theme_override_styles/selected_focus = SubResource("StyleBoxEmpty_n8rql")
allow_reselect = true
same_column_width = true
-[node name="CurrentVersion" type="Button" parent="VBox"]
+[node name="CurrentVersion" type="Button" parent="VBoxPrimary"]
unique_name_in_owner = true
layout_mode = 2
text = "Some Version"
flat = true
clip_text = true
-[connection signal="gui_input" from="VBox/Margin/VSplitContainer/VBox/Logo" to="." method="_on_logo_gui_input"]
-[connection signal="text_changed" from="VBox/Margin/VSplitContainer/VBox/Search" to="." method="_on_search_text_changed"]
-[connection signal="pressed" from="VBox/CurrentVersion" to="." method="_on_current_version_pressed"]
+[node name="RightClickMenu" type="PopupMenu" parent="."]
+unique_name_in_owner = true
+size = Vector2i(164, 100)
+
+[connection signal="gui_input" from="VBoxPrimary/Margin/VSplitContainer/VBox/Logo" to="." method="_on_logo_gui_input"]
+[connection signal="text_changed" from="VBoxPrimary/Margin/VSplitContainer/VBox/HBoxSearchSort/Search" to="." method="_on_search_text_changed"]
+[connection signal="text_submitted" from="VBoxPrimary/Margin/VSplitContainer/VBox/HBoxSearchSort/Search" to="." method="_on_search_text_submitted"]
+[connection signal="pressed" from="VBoxPrimary/CurrentVersion" to="." method="_on_current_version_pressed"]
+[connection signal="id_pressed" from="RightClickMenu" to="." method="_on_right_click_menu_id_pressed"]
diff --git a/addons/dialogic/Editor/Common/sidebar.gd b/addons/dialogic/Editor/Common/sidebar.gd
index 74fb1318e..339b6181d 100644
--- a/addons/dialogic/Editor/Common/sidebar.gd
+++ b/addons/dialogic/Editor/Common/sidebar.gd
@@ -1,5 +1,5 @@
@tool
-extends Control
+class_name DialogicSidebar extends Control
## Script that handles the editor sidebar.
@@ -7,56 +7,136 @@ signal file_activated(file_path)
signal content_item_activated(item_name)
+signal show_sidebar(show: bool)
+
@onready var editors_manager = get_parent().get_parent()
+@onready var resource_tree: Tree = %ResourceTree
+var current_resource_list: Array = []
+enum SortMode {
+ TYPE,
+ FOLDER,
+ PATH,
+ NONE,
+}
+
+
+var sort_mode: SortMode = SortMode.TYPE
-func _ready():
- if owner.get_parent() is SubViewport:
+func _ready() -> void:
+ if owner != null and owner.get_parent() is SubViewport:
+ return
+ if editors_manager is SubViewportContainer:
return
## CONNECTIONS
- %ResourcesList.item_selected.connect(_on_resources_list_item_selected)
- %ResourcesList.item_clicked.connect(_on_resources_list_item_clicked)
editors_manager.resource_opened.connect(_on_editors_resource_opened)
editors_manager.editor_changed.connect(_on_editors_editor_changed)
- %ContentList.item_selected.connect(func (idx:int): content_item_activated.emit(%ContentList.get_item_text(idx)))
+ resource_tree.item_activated.connect(_on_resources_tree_item_activated)
+ resource_tree.item_mouse_selected.connect(_on_resources_tree_item_clicked)
+
+
+
+ %ContentList.item_selected.connect(
+ func(idx: int): content_item_activated.emit(%ContentList.get_item_text(idx))
+ )
+
+ (%OpenButton as Button).pressed.connect(_show_sidebar)
+ (%CloseButton as Button).pressed.connect(_hide_sidebar)
var editor_scale := DialogicUtil.get_editor_scale()
## ICONS
%Logo.texture = load("res://addons/dialogic/Editor/Images/dialogic-logo.svg")
- %Logo.custom_minimum_size.y = 30*editor_scale
+ %Logo.custom_minimum_size.y = 30 * editor_scale
%Search.right_icon = get_theme_icon("Search", "EditorIcons")
- %CurrentResource.add_theme_stylebox_override('normal', get_theme_stylebox('normal', 'LineEdit'))
-
- %ContentList.add_theme_color_override("font_hovered_color", get_theme_color("warning_color", "Editor"))
- %ContentList.add_theme_color_override("font_selected_color", get_theme_color("property_color_z", "Editor"))
+ %ContentList.add_theme_color_override(
+ "font_hovered_color", get_theme_color("warning_color", "Editor")
+ )
+ %ContentList.add_theme_color_override(
+ "font_selected_color", get_theme_color("property_color_z", "Editor")
+ )
## MARGINS
- $VBox/Margin.set("theme_override_constants/margin_left", 4 * editor_scale)
- $VBox/Margin.set("theme_override_constants/margin_bottom", 4 * editor_scale)
+ %VBoxPrimary/Margin.set(
+ "theme_override_constants/margin_left",
+ get_theme_constant("base_margin", "Editor") * editor_scale
+ )
+ %VBoxPrimary/Margin.set(
+ "theme_override_constants/margin_bottom",
+ get_theme_constant("base_margin", "Editor") * editor_scale
+ )
+
+ ## RIGHT CLICK MENU
+ %RightClickMenu.clear()
+ %RightClickMenu.add_icon_item(get_theme_icon("Remove", "EditorIcons"), "Remove From List", 1)
+ %RightClickMenu.add_separator()
+ %RightClickMenu.add_icon_item(get_theme_icon("ActionCopy", "EditorIcons"), "Copy Identifier", 4)
+ %RightClickMenu.add_separator()
+ %RightClickMenu.add_icon_item(
+ get_theme_icon("Filesystem", "EditorIcons"), "Show in FileSystem", 2
+ )
+ %RightClickMenu.add_icon_item(
+ get_theme_icon("ExternalLink", "EditorIcons"), "Open in External Program", 3
+ )
+
+ ## SORT MENU
+ %SortOption.set_item_icon(0, get_theme_icon("AnimationTrackGroup", "EditorIcons"))
+ %SortOption.set_item_icon(1, get_theme_icon("Folder", "EditorIcons"))
+ %SortOption.set_item_icon(2, get_theme_icon("FolderBrowse", "EditorIcons"))
+ %SortOption.set_item_icon(3, get_theme_icon("AnimationTrackList", "EditorIcons"))
+ %SortOption.item_selected.connect(_on_sort_changed)
+
+ await get_tree().process_frame
+ if DialogicUtil.get_editor_setting("sidebar_collapsed", false):
+ _hide_sidebar()
+
+ %SortOption.select(DialogicUtil.get_editor_setting("sidebar_sort_mode", 0))
+ sort_mode = DialogicUtil.get_editor_setting("sidebar_sort_mode", 0)
+ update_resource_list()
+
+
+################################################################################
+## SHOW/HIDE SIDEBAR
+################################################################################
+
+
+func _show_sidebar() -> void:
+ %VBoxPrimary.show()
+ %VBoxHidden.hide()
+ DialogicUtil.set_editor_setting("sidebar_collapsed", false)
+ show_sidebar.emit(true)
+
+
+func _hide_sidebar() -> void:
+ %VBoxPrimary.hide()
+ %VBoxHidden.show()
+ DialogicUtil.set_editor_setting("sidebar_collapsed", true)
+ show_sidebar.emit(false)
################################################################################
## RESOURCE LIST
################################################################################
-func _on_editors_resource_opened(resource:Resource) -> void:
+
+func _on_editors_resource_opened(resource: Resource) -> void:
update_resource_list()
+ pass
-func _on_editors_editor_changed(previous:DialogicEditor, current:DialogicEditor) -> void:
+func _on_editors_editor_changed(previous: DialogicEditor, current: DialogicEditor) -> void:
%ContentListSection.visible = current.current_resource is DialogicTimeline
update_resource_list()
-func clean_resource_list(resources_list:Array = []) -> PackedStringArray:
- return PackedStringArray(resources_list.filter(func(x): return FileAccess.file_exists(x)))
+func clean_resource_list(resources_list: Array = []) -> PackedStringArray:
+ return PackedStringArray(resources_list.filter(func(x): return ResourceLoader.exists(x)))
-func update_resource_list(resources_list:PackedStringArray = []) -> void:
- var filter :String = %Search.text
+func update_resource_list(resources_list: PackedStringArray = []) -> void:
+ var filter: String = %Search.text
var current_file := ""
if editors_manager.current_editor and editors_manager.current_editor.current_resource:
current_file = editors_manager.current_editor.current_resource.resource_path
@@ -64,90 +144,230 @@ func update_resource_list(resources_list:PackedStringArray = []) -> void:
var character_directory: Dictionary = DialogicResourceUtil.get_character_directory()
var timeline_directory: Dictionary = DialogicResourceUtil.get_timeline_directory()
if resources_list.is_empty():
- resources_list = DialogicUtil.get_editor_setting('last_resources', [])
+ resources_list = DialogicUtil.get_editor_setting("last_resources", [])
if !current_file in resources_list:
resources_list.append(current_file)
resources_list = clean_resource_list(resources_list)
%CurrentResource.text = "No Resource"
- %CurrentResource.add_theme_color_override("font_color", get_theme_color("disabled_font_color", "Editor"))
-
- %ResourcesList.clear()
- var idx := 0
- for character_name in character_directory:
- if character_directory[character_name] in resources_list:
- if filter.is_empty() or filter.to_lower() in character_name.to_lower():
- %ResourcesList.add_item(
- character_name,
- load("res://addons/dialogic/Editor/Images/Resources/character.svg"))
- %ResourcesList.set_item_metadata(idx, character_directory[character_name])
- %ResourcesList.set_item_tooltip(idx, character_directory[character_name])
- if character_directory[character_name] == current_file:
- %ResourcesList.select(idx)
- %ResourcesList.set_item_custom_fg_color(idx, get_theme_color("accent_color", "Editor"))
- %CurrentResource.text = character_directory[character_name].get_file()
- idx += 1
- for timeline_name in timeline_directory:
- if timeline_directory[timeline_name] in resources_list:
- if filter.is_empty() or filter.to_lower() in timeline_name.to_lower():
- %ResourcesList.add_item(timeline_name, get_theme_icon("TripleBar", "EditorIcons"))
- %ResourcesList.set_item_metadata(idx, timeline_directory[timeline_name])
- if timeline_directory[timeline_name] == current_file:
- %ResourcesList.select(idx)
- %ResourcesList.set_item_custom_fg_color(idx, get_theme_color("accent_color", "Editor"))
- %CurrentResource.text = timeline_name+'.dtl'
- idx += 1
+ %CurrentResource.add_theme_color_override(
+ "font_uneditable_color", get_theme_color("disabled_font_color", "Editor")
+ )
+
+ resource_tree.clear()
+ var resource_list_items := []
+
+ var get_directory_items := func(directory:Dictionary, filter:String, icon:Texture2D) -> Array:
+ var items := []
+ for item_name in directory:
+ if (directory[item_name] in resources_list) and (filter.is_empty() or filter.to_lower() in item_name.to_lower()):
+ var item := ResourceListItem.new()
+ item.text = item_name
+ item.icon = icon
+ item.metadata = directory[item_name]
+ item.tooltip = directory[item_name]
+ items.append(item)
+ return items
+
+ var character_items: Array = get_directory_items.call(character_directory, filter, load("res://addons/dialogic/Editor/Images/Resources/character.svg"))
+ var timeline_items: Array = get_directory_items.call(timeline_directory, filter, get_theme_icon("TripleBar", "EditorIcons"))
+
+
+ # BUILD TREE
+ var root: TreeItem = resource_tree.create_item()
+
+ if sort_mode == SortMode.TYPE:
+ character_items.sort_custom(_sort_by_item_text)
+ timeline_items.sort_custom(_sort_by_item_text)
+ if character_items.size() > 0:
+ var character_tree := add_folder_item("Characters", root)
+ for item in character_items:
+ add_item(item, character_tree, current_file)
+
+ if timeline_items.size() > 0:
+ var timeline_tree := add_folder_item("Timelines", root)
+ for item in timeline_items:
+ add_item(item, timeline_tree, current_file)
+
+ if sort_mode == SortMode.NONE:
+ var all_items := character_items + timeline_items
+ all_items.sort_custom(_sort_by_item_text)
+ for item in all_items:
+ var tree_item = resource_tree.create_item(root)
+ tree_item.set_text(0, item.text)
+ tree_item.set_icon(0, item.icon)
+ tree_item.set_metadata(0, item.metadata)
+ tree_item.set_tooltip_text(0, item.tooltip)
+ if item.metadata == current_file:
+ %CurrentResource.text = item.metadata.get_file()
+ resource_tree.set_selected(tree_item, 0)
+
+ if sort_mode == SortMode.FOLDER:
+ var all_items := character_items + timeline_items
+ var dirs := {}
+ for item in all_items:
+ var dir := item.get_parent_directory() as String
+ if !dirs.has(dir):
+ dirs[dir] = []
+ dirs[dir].append(item)
+ for dir in dirs:
+ var dir_item = resource_tree.create_item(root)
+ dir_item.set_text(0, dir)
+ dir_item.set_icon(0, get_theme_icon("Folder", "EditorIcons"))
+ dir_item.set_custom_bg_color(0, get_theme_color("base_color", "Editor"))
+ for item in dirs[dir]:
+ var tree_item = resource_tree.create_item(dir_item)
+ tree_item.set_text(0, item.text)
+ tree_item.set_icon(0, item.icon)
+ tree_item.set_metadata(0, item.metadata)
+ tree_item.set_tooltip_text(0, item.tooltip)
+ if item.metadata == current_file:
+ %CurrentResource.text = item.metadata.get_file()
+ resource_tree.set_selected(tree_item, 0)
+
+ if sort_mode == SortMode.PATH:
+ var all_items := character_items + timeline_items
+ var dirs := {}
+ var regex := RegEx.new()
+ for item in all_items:
+ var path := (item.metadata.get_base_dir() as String).replace("res://", "")
+ regex.compile("(\\w+\\/)?\\w+$")
+ if !dirs.has(path):
+ dirs[path] = []
+ dirs[path].append(item)
+
+ for dir in dirs:
+ var dir_display := regex.search(dir).get_string(0)
+ var dir_item = resource_tree.create_item(root)
+ var dir_color = ProjectSettings.get_setting("file_customization/folder_colors").get("res://" + dir + "/", get_theme_color("base_color", "Editor"))
+ var default_color_used = true;
+ if dir_color as Color != null and Color(dir_color) != get_theme_color("base_color", "Editor"):
+ dir_color = Color(dir_color)
+ dir_color.a = 0.2
+ dir_color = (dir_color as Color).to_html(true)
+ default_color_used = false
+ dir_item.set_text(0, dir_display)
+ dir_item.set_icon(0, get_theme_icon("Folder", "EditorIcons"))
+ dir_item.set_custom_bg_color(0, dir_color)
+ for item in dirs[dir]:
+ var tree_item = resource_tree.create_item(dir_item)
+ tree_item.set_text(0, item.text)
+ tree_item.set_icon(0, item.icon)
+ tree_item.set_metadata(0, item.metadata)
+ if !default_color_used:
+ dir_color = Color(dir_color)
+ dir_color.a = 0.1
+ dir_color = (dir_color as Color).to_html(true)
+ tree_item.set_custom_bg_color(0, dir_color)
+ tree_item.set_tooltip_text(0, item.tooltip)
+ if item.metadata == current_file:
+ %CurrentResource.text = item.metadata.get_file()
+ resource_tree.set_selected(tree_item, 0)
+
if %CurrentResource.text != "No Resource":
- %CurrentResource.add_theme_color_override("font_color", get_theme_color("font_color", "Editor"))
- %ResourcesList.sort_items_by_text()
- DialogicUtil.set_editor_setting('last_resources', resources_list)
+ %CurrentResource.add_theme_color_override(
+ "font_uneditable_color", get_theme_color("font_color", "Editor")
+ )
+ DialogicUtil.set_editor_setting("last_resources", resources_list)
-func _on_resources_list_item_selected(index:int) -> void:
- if %ResourcesList.get_item_metadata(index) == null:
- return
- editors_manager.edit_resource(load(%ResourcesList.get_item_metadata(index)))
+
+func add_item(item:ResourceListItem, parent:TreeItem, current_file := "") -> TreeItem:
+ var tree_item := resource_tree.create_item(parent)
+ tree_item.set_text(0, item.text)
+ tree_item.set_icon(0, item.icon)
+ tree_item.set_metadata(0, item.metadata)
+ tree_item.set_tooltip_text(0, item.tooltip)
+ if item.metadata == current_file:
+ %CurrentResource.text = item.metadata.get_file()
+ resource_tree.set_selected(tree_item, 0)
+ return tree_item
-func _on_resources_list_item_clicked(index: int, at_position: Vector2, mouse_button_index: int) -> void:
- # If clicked with the middle mouse button, remove the item from the list
- if mouse_button_index == 3:
- var new_list := []
- for entry in DialogicUtil.get_editor_setting('last_resources', []):
- if entry != %ResourcesList.get_item_metadata(index):
- new_list.append(entry)
- DialogicUtil.set_editor_setting('last_resources', new_list)
- %ResourcesList.remove_item(index)
+func add_folder_item(label: String, parent:TreeItem) -> TreeItem:
+ var folder_item := resource_tree.create_item(parent)
+ folder_item.set_text(0, label)
+ folder_item.set_icon(0, get_theme_icon("Folder", "EditorIcons"))
+ folder_item.set_custom_bg_color(0, get_theme_color("base_color", "Editor"))
+ return folder_item
-func _on_search_text_changed(new_text:String) -> void:
+func _on_resources_tree_item_activated() -> void:
+ if resource_tree.get_selected() == null:
+ return
+ var item := resource_tree.get_selected()
+ if item.get_metadata(0) == null:
+ return
+ edit_resource(item.get_metadata(0))
+
+
+func _on_resources_tree_item_clicked(_pos: Vector2, mouse_button_index: int) -> void:
+ if mouse_button_index == MOUSE_BUTTON_LEFT:
+ var selected_item := resource_tree.get_selected()
+ if selected_item == null:
+ return
+ if selected_item.get_metadata(0) == null:
+ return
+ var resource_item := load(selected_item.get_metadata(0))
+ call_deferred("edit_resource", resource_item)
+ return
+ if mouse_button_index == MOUSE_BUTTON_MIDDLE:
+ remove_item_from_list(resource_tree.get_selected())
+ return
+ if mouse_button_index == MOUSE_BUTTON_RIGHT:
+ if resource_tree.get_selected().get_metadata(0):
+ %RightClickMenu.popup_on_parent(Rect2(get_global_mouse_position(), Vector2()))
+ (%RightClickMenu as PopupMenu).set_meta("item_clicked", resource_tree.get_selected())
+ return
+
+
+func _on_search_text_changed(new_text: String) -> void:
update_resource_list()
+ var tree_root := resource_tree.get_root()
+ var tree_items := tree_root.get_children()
+ if tree_items.size() == 0:
+ return
+ for item in tree_items:
+ if item.get_children().size() > 0:
+ resource_tree.set_selected(item.get_child(0), 0)
+ break
+
+func _on_search_text_submitted(new_text: String) -> void:
+ if resource_tree.get_selected() == null:
+ return
+ var item := resource_tree.get_selected()
+ if item.get_metadata(0) == null:
+ return
+ edit_resource(item.get_metadata(0))
+ %Search.clear()
-func set_unsaved_indicator(saved:bool = true) -> void:
- if saved and %CurrentResource.text.ends_with('(*)'):
- %CurrentResource.text = %CurrentResource.text.trim_suffix('(*)')
- if not saved and not %CurrentResource.text.ends_with('(*)'):
- %CurrentResource.text = %CurrentResource.text+"(*)"
+func set_unsaved_indicator(saved: bool = true) -> void:
+ if saved and %CurrentResource.text.ends_with("(*)"):
+ %CurrentResource.text = %CurrentResource.text.trim_suffix("(*)")
+ if not saved and not %CurrentResource.text.ends_with("(*)"):
+ %CurrentResource.text = %CurrentResource.text + "(*)"
-func _on_logo_gui_input(event:InputEvent) -> void:
+
+func _on_logo_gui_input(event: InputEvent) -> void:
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed:
- editors_manager.open_editor(editors_manager.editors['HomePage'].node)
+ editors_manager.open_editor(editors_manager.editors["HomePage"].node)
-func update_content_list(list:PackedStringArray) -> void:
+func update_content_list(list: PackedStringArray) -> void:
var prev_selected := ""
if %ContentList.is_anything_selected():
prev_selected = %ContentList.get_item_text(%ContentList.get_selected_items()[0])
%ContentList.clear()
- %ContentList.add_item('~ Top')
+ %ContentList.add_item("~ Top")
for i in list:
- if i.is_empty(): continue
+ if i.is_empty():
+ continue
%ContentList.add_item(i)
if i == prev_selected:
- %ContentList.select(%ContentList.item_count-1)
+ %ContentList.select(%ContentList.item_count - 1)
if list.is_empty():
return
@@ -165,3 +385,96 @@ func update_content_list(list:PackedStringArray) -> void:
DialogicResourceUtil.set_label_cache(label_directory)
+
+func remove_item_from_list(item: TreeItem) -> void:
+ var new_list := []
+ for entry in DialogicUtil.get_editor_setting("last_resources", []):
+ if entry != item.get_metadata(0):
+ new_list.append(entry)
+ DialogicUtil.set_editor_setting("last_resources", new_list)
+ update_resource_list(new_list)
+
+
+func _on_right_click_menu_id_pressed(id: int) -> void:
+ match id:
+ 1: # REMOVE ITEM FROM LIST
+ remove_item_from_list(%RightClickMenu.get_meta("item_clicked"))
+ 2: # OPEN IN FILESYSTEM
+ EditorInterface.get_file_system_dock().navigate_to_path(
+ %RightClickMenu.get_meta("item_clicked").get_metadata(0)
+ )
+ 3: # OPEN IN EXTERNAL EDITOR
+ OS.shell_open(
+ ProjectSettings.globalize_path(
+ %RightClickMenu.get_meta("item_clicked").get_metadata(0)
+ )
+ )
+ 4: # COPY IDENTIFIER
+ DisplayServer.clipboard_set(
+ DialogicResourceUtil.get_unique_identifier(
+ %RightClickMenu.get_meta("item_clicked").get_metadata(0)
+ )
+ )
+
+
+func _on_sort_changed(idx: int) -> void:
+ if (SortMode as Dictionary).values().has(idx):
+ sort_mode = idx
+ DialogicUtil.set_editor_setting("sidebar_sort_mode", idx)
+ update_resource_list()
+ else:
+ sort_mode = SortMode.TYPE
+ print("Invalid sort mode: ", idx)
+
+
+func _sort_by_item_text(a: ResourceListItem, b: ResourceListItem) -> bool:
+ return a.text < b.text
+
+
+func edit_resource(resource_item: Variant) -> void:
+ if resource_item is Resource:
+ editors_manager.edit_resource(resource_item)
+ else:
+ editors_manager.edit_resource(load(resource_item))
+
+
+
+
+class ResourceListItem:
+ extends Object
+
+ var text: String
+ var index: int = -1
+ var icon: Texture
+ var metadata: String
+ var tooltip: String
+
+ func _to_string() -> String:
+ return JSON.stringify(
+ {
+ "text": text,
+ "index": index,
+ "icon": icon.resource_path,
+ "metadata": metadata,
+ "tooltip": tooltip,
+ "parent_dir": get_parent_directory()
+ },
+ "\t",
+ false
+ )
+
+ func add_to_item_list(item_list: ItemList, current_file: String) -> void:
+ item_list.add_item(text, icon)
+ item_list.set_item_metadata(item_list.item_count - 1, metadata)
+ item_list.set_item_tooltip(item_list.item_count - 1, tooltip)
+
+ func get_parent_directory() -> String:
+ return (metadata.get_base_dir() as String).split("/")[-1]
+
+ func current_file(sidebar: Control, resource_list: ItemList, current_file: String) -> void:
+ if metadata == current_file:
+ resource_list.select(index)
+ resource_list.set_item_custom_fg_color(
+ index, resource_list.get_theme_color("accent_color", "Editor")
+ )
+ sidebar.find_child("CurrentResource").text = metadata.get_file()
diff --git a/addons/dialogic/Editor/Common/toolbar.gd b/addons/dialogic/Editor/Common/toolbar.gd
index 1921802b7..e49c1ea04 100644
--- a/addons/dialogic/Editor/Common/toolbar.gd
+++ b/addons/dialogic/Editor/Common/toolbar.gd
@@ -6,12 +6,11 @@ extends HBoxContainer
################################################################################
## EDITOR BUTTONS/LABELS
################################################################################
-func _ready():
+func _ready() -> void:
if owner.get_parent() is SubViewport:
return
- var editor_scale := DialogicUtil.get_editor_scale()
- %CustomButtons.custom_minimum_size.y = 33*editor_scale
-
+ %CustomButtons.custom_minimum_size.y = 33 * DialogicUtil.get_editor_scale()
+
for child in get_children():
if child is Button:
child.queue_free()
@@ -35,7 +34,7 @@ func add_custom_button(label:String, icon:Texture) -> Button:
button.text = label
button.icon = icon
# button.flat = true
-
+
button.size_flags_vertical = Control.SIZE_SHRINK_BEGIN
%CustomButtons.add_child(button)
# custom_minimum_size.y = button.size.y
diff --git a/addons/dialogic/Editor/Common/unique_identifiers_manager.gd b/addons/dialogic/Editor/Common/unique_identifiers_manager.gd
index 28a47354e..fc7c993e0 100644
--- a/addons/dialogic/Editor/Common/unique_identifiers_manager.gd
+++ b/addons/dialogic/Editor/Common/unique_identifiers_manager.gd
@@ -48,7 +48,7 @@ func fill_table() -> void:
func _on_identifier_table_item_edited() -> void:
var item: TreeItem = %IdentifierTable.get_edited()
- var new_identifier : String = item.get_text(1)
+ var new_identifier: String = item.get_text(1)
if new_identifier == item.get_metadata(1):
diff --git a/addons/dialogic/Editor/Common/update_install_window.gd b/addons/dialogic/Editor/Common/update_install_window.gd
index 7cdda8b16..0d5a49809 100644
--- a/addons/dialogic/Editor/Common/update_install_window.gd
+++ b/addons/dialogic/Editor/Common/update_install_window.gd
@@ -1,22 +1,22 @@
@tool
extends Control
-var current_info : Dictionary = {}
+var current_info := {}
@onready var editor_view := find_parent('EditorView')
-func _ready():
+func _ready() -> void:
await editor_view.ready
theme = editor_view.theme
%Install.icon = editor_view.get_theme_icon("AssetLib", "EditorIcons")
%LoadingIcon.texture = editor_view.get_theme_icon("KeyTrackScale", "EditorIcons")
%InstallWarning.modulate = editor_view.get_theme_color("warning_color", "Editor")
-
+ %CloseButton.icon = editor_view.get_theme_icon("Close", "EditorIcons")
DialogicUtil.get_dialogic_plugin().get_editor_interface().get_resource_filesystem().resources_reimported.connect(_on_resources_reimported)
-func open():
+func open() -> void:
get_parent().popup_centered_ratio(0.5)
get_parent().mode = Window.MODE_WINDOWED
get_parent().move_to_foreground()
@@ -55,7 +55,7 @@ func load_info(info:Dictionary, update_type:int) -> void:
%Install.disabled = true
%UpdateName.text = info.name
- %Content.text = markdown_to_bbcode('#'+info.body.get_slice('#', 1)).strip_edges()
+ %Content.text = markdown_to_bbcode(info.body).get_slice("\n[font_size", 0).strip_edges()
%ShortInfo.text = "Published on "+info.published_at.substr(0, info.published_at.find('T'))+" by "+info.author.login
if info.has("html_url"):
%ReadFull.uri = info.html_url
@@ -76,11 +76,11 @@ func load_info(info:Dictionary, update_type:int) -> void:
else:
%Reactions.hide()
-func _on_window_close_requested():
+func _on_window_close_requested() -> void:
get_parent().visible = false
-func _on_install_pressed():
+func _on_install_pressed() -> void:
find_parent('UpdateManager').request_update_download()
%InfoLabel.text = "Downloading. This can take a moment."
@@ -88,7 +88,7 @@ func _on_install_pressed():
%LoadingIcon.create_tween().set_loops().tween_property(%LoadingIcon, 'rotation', 2*PI, 1).from(0)
-func _on_refresh_pressed():
+func _on_refresh_pressed() -> void:
find_parent('UpdateManager').request_update_check()
@@ -154,7 +154,7 @@ func markdown_to_bbcode(text:String) -> String:
while res:
text = text.replace(res.get_string(), '[code][bgcolor='+get_theme_color("box_selection_fill_color", "Editor").to_html()+']'+res.get_string('text').strip_edges()+'[/bgcolor][/code]')
res = big_code_regex.search(text)
-
+
return text
@@ -163,14 +163,18 @@ func _on_content_meta_clicked(meta:Variant) -> void:
OS.shell_open(str(meta))
-func _on_install_mouse_entered():
+func _on_install_mouse_entered() -> void:
if not %Install.disabled:
%InstallWarning.show()
-func _on_install_mouse_exited():
+func _on_install_mouse_exited() -> void:
%InstallWarning.hide()
-func _on_restart_pressed():
+func _on_restart_pressed() -> void:
DialogicUtil.get_dialogic_plugin().get_editor_interface().restart_editor(true)
+
+
+func _on_close_button_pressed() -> void:
+ get_parent().hide()
diff --git a/addons/dialogic/Editor/Common/update_install_window.tscn b/addons/dialogic/Editor/Common/update_install_window.tscn
index d4c2d2e51..9c7788f4d 100644
--- a/addons/dialogic/Editor/Common/update_install_window.tscn
+++ b/addons/dialogic/Editor/Common/update_install_window.tscn
@@ -290,9 +290,19 @@ layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 7
+[node name="Close" type="HBoxContainer" parent="VBoxContainer"]
+layout_mode = 2
+alignment = 1
+
+[node name="CloseButton" type="Button" parent="VBoxContainer/Close"]
+unique_name_in_owner = true
+layout_mode = 2
+text = "Close"
+
[connection signal="pressed" from="VBoxContainer/HBoxContainer2/VBox/ScrollContainer/VBoxContainer/Panel/Refresh" to="." method="_on_refresh_pressed"]
[connection signal="meta_clicked" from="VBoxContainer/HBoxContainer2/VBox/ScrollContainer/VBoxContainer/Content" to="." method="_on_content_meta_clicked"]
[connection signal="pressed" from="VBoxContainer/HBoxContainer2/VBox/ScrollContainer/VBoxContainer/HBoxContainer/PanelContainer/HBox/Restart" to="." method="_on_restart_pressed"]
[connection signal="mouse_entered" from="VBoxContainer/HBoxContainer2/VBox/ScrollContainer/VBoxContainer/HBoxContainer/PanelContainer/HBox/Install" to="." method="_on_install_mouse_entered"]
[connection signal="mouse_exited" from="VBoxContainer/HBoxContainer2/VBox/ScrollContainer/VBoxContainer/HBoxContainer/PanelContainer/HBox/Install" to="." method="_on_install_mouse_exited"]
[connection signal="pressed" from="VBoxContainer/HBoxContainer2/VBox/ScrollContainer/VBoxContainer/HBoxContainer/PanelContainer/HBox/Install" to="." method="_on_install_pressed"]
+[connection signal="pressed" from="VBoxContainer/Close/CloseButton" to="." method="_on_close_button_pressed"]
diff --git a/addons/dialogic/Editor/Common/update_manager.gd b/addons/dialogic/Editor/Common/update_manager.gd
index d1296a33d..36a116ec5 100644
--- a/addons/dialogic/Editor/Common/update_manager.gd
+++ b/addons/dialogic/Editor/Common/update_manager.gd
@@ -11,13 +11,13 @@ enum DownloadResult {SUCCESS, FAILURE}
enum ReleaseState {ALPHA, BETA, STABLE}
const REMOTE_RELEASES_URL := "https://api.github.com/repos/dialogic-godot/dialogic/releases"
-const TEMP_FILE_NAME = "user://temp.zip"
+const TEMP_FILE_NAME := "user://temp.zip"
-var current_version : String = ""
+var current_version := ""
var update_info: Dictionary
var current_info: Dictionary
-var version_indicator :Button
+var version_indicator: Button
func _ready() -> void:
request_update_check()
@@ -43,14 +43,14 @@ func _on_UpdateCheck_request_completed(result:int, response_code:int, headers:Pa
return
# Work out the next version from the releases information on GitHub
- var response :Variant= JSON.parse_string(body.get_string_from_utf8())
+ var response: Variant = JSON.parse_string(body.get_string_from_utf8())
if typeof(response) != TYPE_ARRAY: return
var current_release_info := get_release_tag_info(get_current_version())
# GitHub releases are in order of creation, not order of version
- var versions :Array = (response as Array).filter(compare_versions.bind(current_release_info))
+ var versions: Array = (response as Array).filter(compare_versions.bind(current_release_info))
if versions.size() > 0:
update_info = versions[0]
update_check_completed.emit(UpdateCheckResult.UPDATE_AVAILABLE)
@@ -92,13 +92,13 @@ func get_release_tag_info(release_tag:String) -> Dictionary:
release_tag = release_tag.substr(0, release_tag.find('('))
release_tag = release_tag.to_lower()
- var regex := RegEx.create_from_string('(?\\d+\\.\\d+)(-(?alpha|beta)-)?(?(2)(?\\d*)|\\.(?\\d*))?')
+ var regex := RegEx.create_from_string(r"(?\d+\.\d+)(-(?alpha|beta)-)?(?(2)(?\d*)|\.(?\d*))?")
var result: RegExMatch = regex.search(release_tag)
if !result:
return {}
- var info:Dictionary = {'tag':release_tag}
+ var info: Dictionary = {'tag':release_tag}
info['major'] = float(result.get_string('major'))
info['minor'] = int(result.get_string('minor'))
@@ -141,7 +141,7 @@ func _on_DownloadRequest_completed(result:int, response_code:int, headers:Packed
zip_reader.open(TEMP_FILE_NAME)
var files: PackedStringArray = zip_reader.get_files()
- var base_path = files[0].path_join('addons/')
+ var base_path: String = files[0].path_join('addons/')
for path in files:
if not "dialogic/" in path:
continue
@@ -162,14 +162,14 @@ func _on_DownloadRequest_completed(result:int, response_code:int, headers:Packed
###################### SOME UI MANAGEMENT #####################################
################################################################################
-func setup_version_indicator():
+func setup_version_indicator() -> void:
version_indicator = %Sidebar.get_node('%CurrentVersion')
version_indicator.pressed.connect($Window/UpdateInstallWindow.open)
version_indicator.text = get_current_version()
func _on_update_check_completed(result:int):
- var result_color : Color
+ var result_color: Color
match result:
UpdateCheckResult.UPDATE_AVAILABLE:
result_color = version_indicator.get_theme_color("warning_color", "Editor")
diff --git a/addons/dialogic/Editor/Events/BranchEnd.gd b/addons/dialogic/Editor/Events/BranchEnd.gd
index 0500cf639..d43ebe345 100644
--- a/addons/dialogic/Editor/Events/BranchEnd.gd
+++ b/addons/dialogic/Editor/Events/BranchEnd.gd
@@ -16,7 +16,7 @@ var selected := false
func _ready() -> void:
$Icon.icon = get_theme_icon("GuiSpinboxUpdown", "EditorIcons")
- $Spacer.custom_minimum_size.x = 90*DialogicUtil.get_editor_scale()
+ $Spacer.custom_minimum_size.x = 90 * DialogicUtil.get_editor_scale()
visual_deselect()
parent_node_changed()
@@ -59,7 +59,7 @@ func update_hidden_events_indicator(hidden_events_count:int = 0) -> void:
## Called by the visual timeline editor
func set_indent(indent: int) -> void:
- $Indent.custom_minimum_size = Vector2(indent_size * indent*DialogicUtil.get_editor_scale(), 0)
+ $Indent.custom_minimum_size = Vector2(indent_size * indent * DialogicUtil.get_editor_scale(), 0)
$Indent.visible = indent != 0
current_indent_level = indent
queue_redraw()
diff --git a/addons/dialogic/Editor/Events/EventBlock/event_block.gd b/addons/dialogic/Editor/Events/EventBlock/event_block.gd
index bce4a1463..f5c39d365 100644
--- a/addons/dialogic/Editor/Events/EventBlock/event_block.gd
+++ b/addons/dialogic/Editor/Events/EventBlock/event_block.gd
@@ -6,7 +6,7 @@ extends MarginContainer
signal content_changed()
## REFERENCES
-var resource : DialogicEvent
+var resource: DialogicEvent
var editor_reference
# for choice and condition
var end_node: Node = null:
@@ -14,7 +14,7 @@ var end_node: Node = null:
return end_node
set(node):
end_node = node
- %CollapseButton.visible = true if end_node else false
+ %ToggleChildrenVisibilityButton.visible = true if end_node else false
## FLAGS
@@ -40,7 +40,7 @@ var current_indent_level := 1
#region UI AND LOGIC INITIALIZATION
################################################################################
-func _ready():
+func _ready() -> void:
if get_parent() is SubViewport:
return
@@ -63,8 +63,12 @@ func initialize_ui() -> void:
%Warning.position = Vector2(-5 * _scale, -10 * _scale)
# Expand Button
- %ExpandButton.icon = get_theme_icon("CodeFoldedRightArrow", "EditorIcons")
- %ExpandButton.modulate = get_theme_color("readonly_color", "Editor")
+ %ToggleBodyVisibilityButton.icon = get_theme_icon("CodeFoldedRightArrow", "EditorIcons")
+ %ToggleBodyVisibilityButton.set("theme_override_colors/icon_normal_color", get_theme_color("contrast_color_2", "Editor"))
+ %ToggleBodyVisibilityButton.set("theme_override_colors/icon_hover_color", get_theme_color("accent_color", "Editor"))
+ %ToggleBodyVisibilityButton.set("theme_override_colors/icon_pressed_color", get_theme_color("contrast_color_2", "Editor"))
+ %ToggleBodyVisibilityButton.set("theme_override_colors/icon_hover_pressed_color", get_theme_color("accent_color", "Editor"))
+ %ToggleBodyVisibilityButton.add_theme_stylebox_override('hover_pressed', StyleBoxEmpty.new())
# Icon Panel
%IconPanel.tooltip_text = resource.event_name
@@ -86,9 +90,9 @@ func initialize_ui() -> void:
%Header.add_theme_constant_override("custom_constants/separation", 5 * _scale)
# Collapse Button
- %CollapseButton.toggled.connect(_on_collapse_toggled)
- %CollapseButton.icon = get_theme_icon("Collapse", "EditorIcons")
- %CollapseButton.hide()
+ %ToggleChildrenVisibilityButton.toggled.connect(_on_collapse_toggled)
+ %ToggleChildrenVisibilityButton.icon = get_theme_icon("Collapse", "EditorIcons")
+ %ToggleChildrenVisibilityButton.hide()
%Body.add_theme_constant_override("margin_left", icon_size * _scale)
@@ -103,7 +107,7 @@ func initialize_logic() -> void:
content_changed.connect(recalculate_field_visibility)
- _on_ExpandButton_toggled(resource.expand_by_default or resource.created_by_button)
+ _on_ToggleBodyVisibility_toggled(resource.expand_by_default or resource.created_by_button)
#endregion
@@ -138,7 +142,7 @@ func set_warning(text:String= "") -> void:
func set_indent(indent: int) -> void:
- add_theme_constant_override("margin_left", indent_size*indent*DialogicUtil.get_editor_scale())
+ add_theme_constant_override("margin_left", indent_size * indent * DialogicUtil.get_editor_scale())
current_indent_level = indent
#endregion
@@ -161,7 +165,8 @@ var FIELD_SCENES := {
DialogicEvent.ValueType.NUMBER: "res://addons/dialogic/Editor/Events/Fields/field_number.tscn",
DialogicEvent.ValueType.VECTOR2: "res://addons/dialogic/Editor/Events/Fields/field_vector2.tscn",
DialogicEvent.ValueType.VECTOR3: "res://addons/dialogic/Editor/Events/Fields/field_vector3.tscn",
- DialogicEvent.ValueType.VECTOR4: "res://addons/dialogic/Editor/Events/Fields/field_vector4.tscn"
+ DialogicEvent.ValueType.VECTOR4: "res://addons/dialogic/Editor/Events/Fields/field_vector4.tscn",
+ DialogicEvent.ValueType.COLOR: "res://addons/dialogic/Editor/Events/Fields/field_color.tscn"
}
func build_editor(build_header:bool = true, build_body:bool = false) -> void:
@@ -189,7 +194,7 @@ func build_editor(build_header:bool = true, build_body:bool = false) -> void:
### --------------------------------------------------------------------
### 1. CREATE A NODE OF THE CORRECT TYPE FOR THE PROPERTY
- var editor_node : Control
+ var editor_node: Control
### LINEBREAK
if p.name == "linebreak":
@@ -213,12 +218,13 @@ func build_editor(build_header:bool = true, build_body:bool = false) -> void:
elif p.field_type == resource.ValueType.BUTTON:
editor_node = Button.new()
editor_node.text = p.display_info.text
+ editor_node.tooltip_text = p.display_info.get('tooltip', '')
if typeof(p.display_info.icon) == TYPE_ARRAY:
editor_node.icon = callv('get_theme_icon', p.display_info.icon)
else:
editor_node.icon = p.display_info.icon
editor_node.flat = true
- editor_node.custom_minimum_size.x = 30*DialogicUtil.get_editor_scale()
+ editor_node.custom_minimum_size.x = 30 * DialogicUtil.get_editor_scale()
editor_node.pressed.connect(p.display_info.callable)
## CUSTOM
@@ -318,13 +324,15 @@ func recalculate_field_visibility() -> void:
else:
if _evaluate_visibility_condition(p):
if p.node != null:
+ if p.node.visible == false and p.has("property"):
+ p.node._set_value(resource.get(p.property))
p.node.show()
if p.location == 1:
has_any_enabled_body_content = true
else:
if p.node != null:
p.node.hide()
- %ExpandButton.visible = has_any_enabled_body_content
+ %ToggleBodyVisibilityButton.visible = has_any_enabled_body_content
func set_property(property_name:String, value:Variant) -> void:
@@ -368,7 +376,7 @@ func _on_resource_ui_update_needed() -> void:
func _on_collapse_toggled(toggled:bool) -> void:
collapsed = toggled
- var timeline_editor = find_parent('VisualEditor')
+ var timeline_editor: Node = find_parent('VisualEditor')
if (timeline_editor != null):
# @todo select item and clear selection is marked as "private" in TimelineEditor.gd
# consider to make it "public" or add a public helper function
@@ -376,15 +384,15 @@ func _on_collapse_toggled(toggled:bool) -> void:
-func _on_ExpandButton_toggled(button_pressed:bool) -> void:
+func _on_ToggleBodyVisibility_toggled(button_pressed:bool) -> void:
if button_pressed and !body_was_build:
build_editor(false, true)
- %ExpandButton.set_pressed_no_signal(button_pressed)
+ %ToggleBodyVisibilityButton.set_pressed_no_signal(button_pressed)
if button_pressed:
- %ExpandButton.icon = get_theme_icon("CodeFoldDownArrow", "EditorIcons")
+ %ToggleBodyVisibilityButton.icon = get_theme_icon("CodeFoldDownArrow", "EditorIcons")
else:
- %ExpandButton.icon = get_theme_icon("CodeFoldedRightArrow", "EditorIcons")
+ %ToggleBodyVisibilityButton.icon = get_theme_icon("CodeFoldedRightArrow", "EditorIcons")
expanded = button_pressed
%Body.visible = button_pressed
@@ -398,11 +406,11 @@ func _on_EventNode_gui_input(event:InputEvent) -> void:
grab_focus() # Grab focus to avoid copy pasting text or events
if event.double_click:
if has_any_enabled_body_content:
- _on_ExpandButton_toggled(!expanded)
+ _on_ToggleBodyVisibility_toggled(!expanded)
# For opening the context menu
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_RIGHT and event.pressed:
- var popup :PopupMenu = get_parent().get_parent().get_node('EventPopupMenu')
+ var popup: PopupMenu = get_parent().get_parent().get_node('EventPopupMenu')
popup.current_event = self
popup.popup_on_parent(Rect2(get_global_mouse_position(),Vector2()))
if resource.help_page_path == "":
diff --git a/addons/dialogic/Editor/Events/EventBlock/event_block.tscn b/addons/dialogic/Editor/Events/EventBlock/event_block.tscn
index f0b363c0c..5bd715bd9 100644
--- a/addons/dialogic/Editor/Events/EventBlock/event_block.tscn
+++ b/addons/dialogic/Editor/Events/EventBlock/event_block.tscn
@@ -11,7 +11,7 @@ corner_radius_top_right = 5
corner_radius_bottom_right = 5
corner_radius_bottom_left = 5
-[sub_resource type="Image" id="Image_ng2y4"]
+[sub_resource type="Image" id="Image_mem38"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -21,7 +21,7 @@ data = {
}
[sub_resource type="ImageTexture" id="ImageTexture_rc1wh"]
-image = SubResource("Image_ng2y4")
+image = SubResource("Image_mem38")
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_ee4ub"]
@@ -91,18 +91,22 @@ stretch_mode = 5
unique_name_in_owner = true
layout_mode = 2
-[node name="ExpandButton" type="Button" parent="PanelContainer/VBoxContainer/Header"]
+[node name="ToggleBodyVisibilityButton" type="Button" parent="PanelContainer/VBoxContainer/Header"]
unique_name_in_owner = true
-modulate = Color(0, 0, 0, 1)
+custom_minimum_size = Vector2(20, 0)
layout_mode = 2
size_flags_horizontal = 0
tooltip_text = "Fold/Unfold Settings"
+theme_override_styles/normal = SubResource("StyleBoxEmpty_ee4ub")
+theme_override_styles/hover = SubResource("StyleBoxEmpty_ee4ub")
+theme_override_styles/pressed = SubResource("StyleBoxEmpty_ee4ub")
+theme_override_styles/disabled = SubResource("StyleBoxEmpty_ee4ub")
theme_override_styles/focus = SubResource("StyleBoxEmpty_ee4ub")
toggle_mode = true
icon = SubResource("ImageTexture_rc1wh")
flat = true
-[node name="CollapseButton" type="Button" parent="PanelContainer/VBoxContainer/Header"]
+[node name="ToggleChildrenVisibilityButton" type="Button" parent="PanelContainer/VBoxContainer/Header"]
unique_name_in_owner = true
visible = false
layout_mode = 2
@@ -126,4 +130,4 @@ size_flags_vertical = 3
mouse_filter = 2
[connection signal="gui_input" from="." to="." method="_on_EventNode_gui_input"]
-[connection signal="toggled" from="PanelContainer/VBoxContainer/Header/ExpandButton" to="." method="_on_ExpandButton_toggled"]
+[connection signal="toggled" from="PanelContainer/VBoxContainer/Header/ToggleBodyVisibilityButton" to="." method="_on_ToggleBodyVisibility_toggled"]
diff --git a/addons/dialogic/Editor/Events/EventBlock/event_right_click_menu.gd b/addons/dialogic/Editor/Events/EventBlock/event_right_click_menu.gd
index a2b42b9ec..0b765f633 100644
--- a/addons/dialogic/Editor/Events/EventBlock/event_right_click_menu.gd
+++ b/addons/dialogic/Editor/Events/EventBlock/event_right_click_menu.gd
@@ -1,9 +1,9 @@
@tool
extends PopupMenu
-var current_event : Node = null
+var current_event: Node = null
-func _ready():
+func _ready() -> void:
clear()
add_icon_item(get_theme_icon("Duplicate", "EditorIcons"), "Duplicate")
add_separator()
diff --git a/addons/dialogic/Editor/Events/Fields/array_part.gd b/addons/dialogic/Editor/Events/Fields/array_part.gd
index 97352d8ad..20c7c72c8 100644
--- a/addons/dialogic/Editor/Events/Fields/array_part.gd
+++ b/addons/dialogic/Editor/Events/Fields/array_part.gd
@@ -11,138 +11,18 @@ var value_type: int = -1
var current_value: Variant
func _ready() -> void:
- %ValueType.options = [{
- 'label': 'String',
- 'icon': ["String", "EditorIcons"],
- 'value': TYPE_STRING
- },{
- 'label': 'Number (int)',
- 'icon': ["int", "EditorIcons"],
- 'value': TYPE_INT
- },{
- 'label': 'Number (float)',
- 'icon': ["float", "EditorIcons"],
- 'value': TYPE_FLOAT
- },{
- 'label': 'Boolean',
- 'icon': ["bool", "EditorIcons"],
- 'value': TYPE_BOOL
- },{
- 'label': 'Expression',
- 'icon': ["Variant", "EditorIcons"],
- 'value': TYPE_MAX
- }
- ]
- %ValueType.symbol_only = true
- %ValueType.value_changed.connect(_on_type_changed.bind())
- %ValueType.tooltip_text = "Change type"
-
+ %FlexValue.value_changed.connect(emit_signal.bind("value_changed"))
%Delete.icon = get_theme_icon("Remove", "EditorIcons")
func set_value(value:Variant):
- change_field_type(deduce_type(value))
- %ValueType.set_value(deduce_type(value))
- current_value = value
- match value_type:
- TYPE_BOOL:
- value_field.button_pressed = value
- TYPE_STRING:
- value_field.text = value
- TYPE_FLOAT, TYPE_INT:
- value_field.set_value(value)
- TYPE_MAX, _:
- value_field.text = value.trim_prefix('@')
-
-
-func deduce_type(value:Variant) -> int:
- if value is String and value.begins_with('@'):
- return TYPE_MAX
- else:
- return typeof(value)
-
-
-func _on_type_changed(prop:String, type:Variant) -> void:
- if type == value_type:
- return
-
- match type:
- TYPE_BOOL:
- if typeof(current_value) == TYPE_STRING:
- current_value = DialogicUtil.str_to_bool(current_value)
- elif value_type == TYPE_FLOAT or value_type == TYPE_INT:
- current_value = bool(current_value)
- else:
- current_value = true if current_value else false
- set_value(current_value)
- TYPE_STRING:
- current_value = str(current_value).trim_prefix('@')
- set_value(current_value)
- TYPE_FLOAT, TYPE_INT:
- current_value = float(current_value)
- set_value(current_value)
- TYPE_MAX,_:
- current_value = var_to_str(current_value)
- set_value('@'+current_value)
-
-
- emit_signal.call_deferred('value_changed')
+ %FlexValue.set_value(value)
func get_value() -> Variant:
- return current_value
+ return %FlexValue.current_value
func _on_delete_pressed() -> void:
queue_free()
value_changed.emit()
-
-
-func change_field_type(type:int) -> void:
- if type == value_type:
- return
-
- value_type = type
-
- if value_field:
- value_field.queue_free()
- match type:
- TYPE_BOOL:
- value_field = CheckBox.new()
- value_field.toggled.connect(_on_bool_toggled)
- TYPE_STRING:
- value_field = LineEdit.new()
- value_field.text_changed.connect(_on_str_text_changed)
- value_field.expand_to_text_length = true
- TYPE_FLOAT, TYPE_INT:
- value_field = load("res://addons/dialogic/Editor/Events/Fields/field_number.tscn").instantiate()
- if type == TYPE_FLOAT:
- value_field.use_float_mode()
- else:
- value_field.use_int_mode()
- value_field.value_changed.connect(_on_number_value_changed.bind(type == TYPE_INT))
- TYPE_MAX, _:
- value_field = LineEdit.new()
- value_field.expand_to_text_length = true
- value_field.text_changed.connect(_on_expression_changed)
- $Value.add_child(value_field)
- $Value.move_child(value_field, 1)
-
-func _on_bool_toggled(value:bool) -> void:
- current_value = value
- value_changed.emit()
-
-func _on_str_text_changed(value:String) -> void:
- current_value = value
- value_changed.emit()
-
-func _on_expression_changed(value:String) -> void:
- current_value = '@'+value
- value_changed.emit()
-
-func _on_number_value_changed(prop:String, value:float, int := false) -> void:
- if int:
- current_value = int(value)
- else:
- current_value = value
- value_changed.emit()
diff --git a/addons/dialogic/Editor/Events/Fields/array_part.tscn b/addons/dialogic/Editor/Events/Fields/array_part.tscn
index 72ae7ebdc..7ec2d25a4 100644
--- a/addons/dialogic/Editor/Events/Fields/array_part.tscn
+++ b/addons/dialogic/Editor/Events/Fields/array_part.tscn
@@ -1,26 +1,9 @@
-[gd_scene load_steps=7 format=3 uid="uid://ch4j2lesn1sis"]
+[gd_scene load_steps=5 format=3 uid="uid://ch4j2lesn1sis"]
[ext_resource type="Script" path="res://addons/dialogic/Editor/Events/Fields/array_part.gd" id="1"]
-[ext_resource type="Theme" uid="uid://d3g4i4dshtdpu" path="res://addons/dialogic/Editor/Events/styles/InputFieldsStyle.tres" id="2"]
-[ext_resource type="PackedScene" uid="uid://d3bhehatwoio" path="res://addons/dialogic/Editor/Events/Fields/field_options_fixed.tscn" id="3_otpho"]
-
-[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_fe32l"]
-content_margin_left = 2.0
-content_margin_top = 2.0
-content_margin_right = 2.0
-content_margin_bottom = 2.0
-draw_center = false
-border_width_left = 1
-border_width_top = 1
-border_width_right = 1
-border_width_bottom = 1
-border_color = Color(0.282353, 0.486275, 0.458824, 1)
-corner_radius_top_left = 4
-corner_radius_top_right = 4
-corner_radius_bottom_right = 4
-corner_radius_bottom_left = 4
-
-[sub_resource type="Image" id="Image_sbk5s"]
+[ext_resource type="PackedScene" uid="uid://dl08ubinx6ugu" path="res://addons/dialogic/Editor/Events/Fields/field_flex_value.tscn" id="3_s4j7i"]
+
+[sub_resource type="Image" id="Image_dcsrk"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -29,30 +12,28 @@ data = {
"width": 16
}
-[sub_resource type="ImageTexture" id="ImageTexture_16rly"]
-image = SubResource("Image_sbk5s")
+[sub_resource type="ImageTexture" id="ImageTexture_cpbga"]
+image = SubResource("Image_dcsrk")
[node name="ArrayValue" type="PanelContainer"]
offset_left = 2.0
offset_right = 76.0
offset_bottom = 24.0
-theme_override_styles/panel = SubResource("StyleBoxFlat_fe32l")
+theme_type_variation = &"DialogicEventEditGroup"
script = ExtResource("1")
[node name="Value" type="HBoxContainer" parent="."]
layout_mode = 2
-theme = ExtResource("2")
-[node name="ValueType" parent="Value" instance=ExtResource("3_otpho")]
+[node name="FlexValue" parent="Value" instance=ExtResource("3_s4j7i")]
unique_name_in_owner = true
layout_mode = 2
-tooltip_text = "Change type"
-text = ""
[node name="Delete" type="Button" parent="Value"]
unique_name_in_owner = true
layout_mode = 2
-icon = SubResource("ImageTexture_16rly")
+tooltip_text = "Remove"
+icon = SubResource("ImageTexture_cpbga")
flat = true
[connection signal="pressed" from="Value/Delete" to="." method="_on_delete_pressed"]
diff --git a/addons/dialogic/Editor/Events/Fields/dictionary_part.gd b/addons/dialogic/Editor/Events/Fields/dictionary_part.gd
index f6a7277ab..7c28572d7 100644
--- a/addons/dialogic/Editor/Events/Fields/dictionary_part.gd
+++ b/addons/dialogic/Editor/Events/Fields/dictionary_part.gd
@@ -1,39 +1,44 @@
@tool
-extends HBoxContainer
+extends PanelContainer
-## Event block field part for the Array field.
+## Event block field part for the Dictionary field.
signal value_changed()
func set_key(value:String) -> void:
- $Key.text = str(value)
+ %Key.text = str(value)
func get_key() -> String:
- return $Key.text
+ return %Key.text
-func set_value(value:String):
- $Value.text = str(value)
+func set_value(value:Variant) -> void:
+ %FlexValue.set_value(value)
-func get_value() -> String:
- return $Value.text
+func get_value() -> Variant:
+ return %FlexValue.current_value
func _ready() -> void:
- $Delete.icon = get_theme_icon("Remove", "EditorIcons")
+ %Delete.icon = get_theme_icon("Remove", "EditorIcons")
-func _on_Delete_pressed() -> void:
- queue_free()
+func focus_key() -> void:
+ %Key.grab_focus()
+
+
+func _on_key_text_changed(new_text: String) -> void:
value_changed.emit()
-func _on_Key_text_changed(new_text:String) -> void:
+func _on_flex_value_value_changed() -> void:
value_changed.emit()
-func _on_Value_text_changed(new_text:String) -> void:
+func _on_delete_pressed() -> void:
+ queue_free()
value_changed.emit()
+
diff --git a/addons/dialogic/Editor/Events/Fields/dictionary_part.tscn b/addons/dialogic/Editor/Events/Fields/dictionary_part.tscn
index aa012bb62..dc1f961f8 100644
--- a/addons/dialogic/Editor/Events/Fields/dictionary_part.tscn
+++ b/addons/dialogic/Editor/Events/Fields/dictionary_part.tscn
@@ -1,9 +1,9 @@
[gd_scene load_steps=5 format=3 uid="uid://b27yweami3mxi"]
-[ext_resource type="Theme" uid="uid://d3g4i4dshtdpu" path="res://addons/dialogic/Editor/Events/styles/InputFieldsStyle.tres" id="1_4ehmb"]
[ext_resource type="Script" path="res://addons/dialogic/Editor/Events/Fields/dictionary_part.gd" id="2_q88pg"]
+[ext_resource type="PackedScene" uid="uid://dl08ubinx6ugu" path="res://addons/dialogic/Editor/Events/Fields/field_flex_value.tscn" id="3_p082d"]
-[sub_resource type="Image" id="Image_esvau"]
+[sub_resource type="Image" id="Image_dcsrk"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -12,27 +12,43 @@ data = {
"width": 16
}
-[sub_resource type="ImageTexture" id="ImageTexture_bywig"]
-image = SubResource("Image_esvau")
+[sub_resource type="ImageTexture" id="ImageTexture_cpbga"]
+image = SubResource("Image_dcsrk")
-[node name="Value" type="HBoxContainer"]
-theme = ExtResource("1_4ehmb")
+[node name="DictionaryPart" type="PanelContainer"]
+offset_left = 1.0
+offset_top = -1.0
+offset_right = 131.0
+offset_bottom = 32.0
+theme_type_variation = &"DialogicEventEditGroup"
script = ExtResource("2_q88pg")
-[node name="Key" type="LineEdit" parent="."]
+[node name="HBox" type="HBoxContainer" parent="."]
layout_mode = 2
-size_flags_horizontal = 3
-expand_to_text_length = true
-[node name="Value" type="LineEdit" parent="."]
+[node name="Key" type="LineEdit" parent="HBox"]
+unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 3
+theme_type_variation = &"DialogicEventEdit"
expand_to_text_length = true
+select_all_on_focus = true
+
+[node name="Label" type="Label" parent="HBox"]
+layout_mode = 2
+text = ":"
+
+[node name="FlexValue" parent="HBox" instance=ExtResource("3_p082d")]
+unique_name_in_owner = true
+layout_mode = 2
-[node name="Delete" type="Button" parent="."]
+[node name="Delete" type="Button" parent="HBox"]
+unique_name_in_owner = true
layout_mode = 2
-icon = SubResource("ImageTexture_bywig")
+tooltip_text = "Remove"
+icon = SubResource("ImageTexture_cpbga")
+flat = true
-[connection signal="text_changed" from="Key" to="." method="_on_Key_text_changed"]
-[connection signal="text_changed" from="Value" to="." method="_on_Value_text_changed"]
-[connection signal="pressed" from="Delete" to="." method="_on_Delete_pressed"]
+[connection signal="text_changed" from="HBox/Key" to="." method="_on_key_text_changed"]
+[connection signal="value_changed" from="HBox/FlexValue" to="." method="_on_flex_value_value_changed"]
+[connection signal="pressed" from="HBox/Delete" to="." method="_on_delete_pressed"]
diff --git a/addons/dialogic/Editor/Events/Fields/field_array.gd b/addons/dialogic/Editor/Events/Fields/field_array.gd
index 6e0d59c5f..301ade502 100644
--- a/addons/dialogic/Editor/Events/Fields/field_array.gd
+++ b/addons/dialogic/Editor/Events/Fields/field_array.gd
@@ -7,7 +7,7 @@ extends DialogicVisualEditorField
const ArrayValue := "res://addons/dialogic/Editor/Events/Fields/array_part.tscn"
-func _ready():
+func _ready() -> void:
%Add.icon = get_theme_icon("Add", "EditorIcons")
%Add.pressed.connect(_on_AddButton_pressed)
@@ -39,7 +39,7 @@ func recalculate_values() -> void:
func _on_AddButton_pressed() -> void:
- var x :Control = load(ArrayValue).instantiate()
+ var x: Control = load(ArrayValue).instantiate()
add_child(x)
x.set_value("")
x.value_changed.connect(recalculate_values)
diff --git a/addons/dialogic/Editor/Events/Fields/field_array.tscn b/addons/dialogic/Editor/Events/Fields/field_array.tscn
index 7cffed150..ff5ac6c64 100644
--- a/addons/dialogic/Editor/Events/Fields/field_array.tscn
+++ b/addons/dialogic/Editor/Events/Fields/field_array.tscn
@@ -2,7 +2,7 @@
[ext_resource type="Script" path="res://addons/dialogic/Editor/Events/Fields/field_array.gd" id="2"]
-[sub_resource type="Image" id="Image_u0aqk"]
+[sub_resource type="Image" id="Image_dcsrk"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -11,8 +11,8 @@ data = {
"width": 16
}
-[sub_resource type="ImageTexture" id="ImageTexture_7iwuk"]
-image = SubResource("Image_u0aqk")
+[sub_resource type="ImageTexture" id="ImageTexture_cpbga"]
+image = SubResource("Image_dcsrk")
[node name="Field_Array" type="HFlowContainer"]
offset_right = 329.0
@@ -23,5 +23,6 @@ script = ExtResource("2")
[node name="Add" type="Button" parent="."]
unique_name_in_owner = true
layout_mode = 2
-tooltip_text = "Add another value"
-icon = SubResource("ImageTexture_7iwuk")
+tooltip_text = "Add value"
+icon = SubResource("ImageTexture_cpbga")
+flat = true
diff --git a/addons/dialogic/Editor/Events/Fields/field_bool_button.gd b/addons/dialogic/Editor/Events/Fields/field_bool_button.gd
index b4373e79f..1593be3d8 100644
--- a/addons/dialogic/Editor/Events/Fields/field_bool_button.gd
+++ b/addons/dialogic/Editor/Events/Fields/field_bool_button.gd
@@ -17,6 +17,8 @@ func _ready() -> void:
func _load_display_info(info:Dictionary) -> void:
if info.has('editor_icon'):
+ if not is_inside_tree():
+ await ready
self.icon = callv('get_theme_icon', info.editor_icon)
else:
self.icon = info.get('icon', null)
diff --git a/addons/dialogic/Editor/Events/Fields/field_color.gd b/addons/dialogic/Editor/Events/Fields/field_color.gd
new file mode 100644
index 000000000..707dfc51b
--- /dev/null
+++ b/addons/dialogic/Editor/Events/Fields/field_color.gd
@@ -0,0 +1,30 @@
+@tool
+extends DialogicVisualEditorField
+
+## Event block field for color values.
+
+#region MAIN METHODS
+################################################################################
+
+func _ready() -> void:
+ self.color_changed.connect(_on_value_changed)
+
+
+func _load_display_info(info:Dictionary) -> void:
+ self.edit_alpha = info.get("edit_alpha", true)
+
+
+func _set_value(value:Variant) -> void:
+ if value is Color:
+ self.color = Color(value)
+
+#endregion
+
+
+#region SIGNAL METHODS
+################################################################################
+
+func _on_value_changed(value: Color) -> void:
+ value_changed.emit(property_name, value)
+
+#endregion
diff --git a/addons/dialogic/Editor/Events/Fields/field_color.tscn b/addons/dialogic/Editor/Events/Fields/field_color.tscn
new file mode 100644
index 000000000..5fd3ff287
--- /dev/null
+++ b/addons/dialogic/Editor/Events/Fields/field_color.tscn
@@ -0,0 +1,12 @@
+[gd_scene load_steps=2 format=3 uid="uid://4e0kjekan5e7"]
+
+[ext_resource type="Script" path="res://addons/dialogic/Editor/Events/Fields/field_color.gd" id="1_l666a"]
+
+[node name="Field_Color" type="ColorPickerButton"]
+custom_minimum_size = Vector2(48, 0)
+offset_right = 64.0
+offset_bottom = 31.0
+theme_type_variation = &"DialogicEventEdit"
+text = " "
+color = Color(1, 1, 1, 1)
+script = ExtResource("1_l666a")
diff --git a/addons/dialogic/Editor/Events/Fields/field_condition.gd b/addons/dialogic/Editor/Events/Fields/field_condition.gd
index d7a149fb8..db40270b5 100644
--- a/addons/dialogic/Editor/Events/Fields/field_condition.gd
+++ b/addons/dialogic/Editor/Events/Fields/field_condition.gd
@@ -3,8 +3,8 @@ extends DialogicVisualEditorField
## Event block field for displaying conditions in either a simple or complex way.
-var _current_value1 :Variant = ""
-var _current_value2 :Variant = ""
+var _current_value1: Variant = ""
+var _current_value2: Variant = ""
#region MAIN METHODS
################################################################################
@@ -21,7 +21,7 @@ func _set_value(value:Variant) -> void:
-func _autofocus():
+func _autofocus() -> void:
%Value1Variable.grab_focus()
#endregion
@@ -96,7 +96,7 @@ func value_type_changed(property:String, value_type:int, value_name:String) -> v
get_node('%'+value_name+'Text').hide()
get_node('%'+value_name+'Number').hide()
get_node('%'+value_name+'Bool').hide()
- var current_val :Variant = ""
+ var current_val: Variant = ""
if '1' in value_name:
current_val = _current_value1
else:
@@ -237,7 +237,7 @@ func _on_complex_editor_text_changed(new_text:String) -> void:
func get_variable_suggestions(filter:String) -> Dictionary:
var suggestions := {}
- var vars :Dictionary= ProjectSettings.get_setting('dialogic/variables', {})
+ var vars: Dictionary = ProjectSettings.get_setting('dialogic/variables', {})
for var_path in DialogicUtil.list_variables(vars):
suggestions[var_path] = {'value':var_path, 'editor_icon':["ClassList", "EditorIcons"]}
return suggestions
diff --git a/addons/dialogic/Editor/Events/Fields/field_condition.tscn b/addons/dialogic/Editor/Events/Fields/field_condition.tscn
index ea515f7fd..8024c5b40 100644
--- a/addons/dialogic/Editor/Events/Fields/field_condition.tscn
+++ b/addons/dialogic/Editor/Events/Fields/field_condition.tscn
@@ -7,7 +7,7 @@
[ext_resource type="PackedScene" uid="uid://dm5hxmhyyxgq" path="res://addons/dialogic/Editor/Events/Fields/field_bool_check.tscn" id="5_1x02a"]
[ext_resource type="PackedScene" uid="uid://dpwhshre1n4t6" path="res://addons/dialogic/Editor/Events/Fields/field_options_dynamic.tscn" id="6_5a2xd"]
-[sub_resource type="Image" id="Image_cgfp5"]
+[sub_resource type="Image" id="Image_je1w7"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -16,8 +16,8 @@ data = {
"width": 16
}
-[sub_resource type="ImageTexture" id="ImageTexture_4jujf"]
-image = SubResource("Image_cgfp5")
+[sub_resource type="ImageTexture" id="ImageTexture_81s3d"]
+image = SubResource("Image_je1w7")
[node name="Field_Condition" type="HBoxContainer"]
offset_right = 77.0
@@ -94,7 +94,7 @@ unique_name_in_owner = true
layout_mode = 2
tooltip_text = "Use complex expression"
toggle_mode = true
-icon = SubResource("ImageTexture_4jujf")
+icon = SubResource("ImageTexture_81s3d")
[connection signal="value_changed" from="SimpleEditor/Value1Variable" to="." method="_on_value_1_variable_value_changed"]
[connection signal="text_changed" from="ComplexEditor" to="." method="_on_complex_editor_text_changed"]
diff --git a/addons/dialogic/Editor/Events/Fields/field_dictionary.gd b/addons/dialogic/Editor/Events/Fields/field_dictionary.gd
index 194f130a5..f76ef2794 100644
--- a/addons/dialogic/Editor/Events/Fields/field_dictionary.gd
+++ b/addons/dialogic/Editor/Events/Fields/field_dictionary.gd
@@ -1,42 +1,40 @@
@tool
extends DialogicVisualEditorField
-## Event block field for editing arrays.
+## Event block field for editing dictionaries.
-const PairValue = "res://addons/dialogic/Editor/Events/Fields/dictionary_part.tscn"
+const DictionaryValue = "res://addons/dialogic/Editor/Events/Fields/dictionary_part.tscn"
-func _ready():
+func _ready() -> void:
%Add.icon = get_theme_icon("Add", "EditorIcons")
func _set_value(value:Variant) -> void:
- for child in %Values.get_children():
- child.queue_free()
+ for child in get_children():
+ if child != %Add:
+ child.queue_free()
- var dict : Dictionary
+ var dict: Dictionary
# attempt to take dictionary values, create a fresh one if not possible
if typeof(value) == TYPE_DICTIONARY:
dict = value
elif typeof(value) == TYPE_STRING:
if value.begins_with('{'):
- var result = JSON.parse_string(value)
+ var result: Variant = JSON.parse_string(value)
if result != null:
dict = result as Dictionary
- else:
- dict = Dictionary()
- else:
- dict = Dictionary()
var keys := dict.keys()
var values := dict.values()
for index in dict.size():
- var x :Node = load(PairValue).instantiate()
- %Values.add_child(x)
- x.set_key(keys[index])
+ var x: Node = load(DictionaryValue).instantiate()
+ add_child(x)
x.set_value(values[index])
+ x.set_key(keys[index])
x.value_changed.connect(recalculate_values)
+ move_child(%Add, -1)
func _on_value_changed(value:Variant) -> void:
@@ -45,16 +43,18 @@ func _on_value_changed(value:Variant) -> void:
func recalculate_values() -> void:
var dict := {}
- for child in %Values.get_children():
- if !child.is_queued_for_deletion():
+ for child in get_children():
+ if child != %Add and !child.is_queued_for_deletion():
dict[child.get_key()] = child.get_value()
_on_value_changed(dict)
func _on_AddButton_pressed() -> void:
- var x :Control = load(PairValue).instantiate()
- %Values.add_child(x)
+ var x: Control = load(DictionaryValue).instantiate()
+ add_child(x)
x.set_key("")
x.set_value("")
x.value_changed.connect(recalculate_values)
+ x.focus_key()
recalculate_values()
+ move_child(%Add, -1)
diff --git a/addons/dialogic/Editor/Events/Fields/field_dictionary.tscn b/addons/dialogic/Editor/Events/Fields/field_dictionary.tscn
index 3bcaa1188..c5c73e9a7 100644
--- a/addons/dialogic/Editor/Events/Fields/field_dictionary.tscn
+++ b/addons/dialogic/Editor/Events/Fields/field_dictionary.tscn
@@ -1,9 +1,8 @@
-[gd_scene load_steps=5 format=3 uid="uid://c74bnmhefu72w"]
+[gd_scene load_steps=4 format=3 uid="uid://c74bnmhefu72w"]
[ext_resource type="Script" path="res://addons/dialogic/Editor/Events/Fields/field_dictionary.gd" id="1_p4kmu"]
-[ext_resource type="PackedScene" uid="uid://b27yweami3mxi" path="res://addons/dialogic/Editor/Events/Fields/dictionary_part.tscn" id="2_fg1gy"]
-[sub_resource type="Image" id="Image_5s534"]
+[sub_resource type="Image" id="Image_dcsrk"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -12,35 +11,18 @@ data = {
"width": 16
}
-[sub_resource type="ImageTexture" id="ImageTexture_bnwpy"]
-image = SubResource("Image_5s534")
+[sub_resource type="ImageTexture" id="ImageTexture_cpbga"]
+image = SubResource("Image_dcsrk")
-[node name="Pairs" type="VBoxContainer"]
-script = ExtResource("1_p4kmu")
-
-[node name="Editing" type="HBoxContainer" parent="."]
-layout_mode = 2
-size_flags_horizontal = 3
-alignment = 2
-
-[node name="LeftText" type="Label" parent="Editing"]
-unique_name_in_owner = true
-layout_mode = 2
+[node name="Field_Dictionary" type="HFlowContainer"]
size_flags_horizontal = 3
+script = ExtResource("1_p4kmu")
-[node name="Add" type="Button" parent="Editing"]
-unique_name_in_owner = true
-layout_mode = 2
-icon = SubResource("ImageTexture_bnwpy")
-
-[node name="Values" type="VBoxContainer" parent="."]
+[node name="Add" type="Button" parent="."]
unique_name_in_owner = true
layout_mode = 2
+tooltip_text = "Add key-value pair"
+icon = SubResource("ImageTexture_cpbga")
+flat = true
-[node name="Value" parent="Values" instance=ExtResource("2_fg1gy")]
-layout_mode = 2
-
-[node name="Value2" parent="Values" instance=ExtResource("2_fg1gy")]
-layout_mode = 2
-
-[connection signal="pressed" from="Editing/Add" to="." method="_on_AddButton_pressed"]
+[connection signal="pressed" from="Add" to="." method="_on_AddButton_pressed"]
diff --git a/addons/dialogic/Editor/Events/Fields/field_file.gd b/addons/dialogic/Editor/Events/Fields/field_file.gd
index 15d3dd8b9..1227dfaf6 100644
--- a/addons/dialogic/Editor/Events/Fields/field_file.gd
+++ b/addons/dialogic/Editor/Events/Fields/field_file.gd
@@ -8,8 +8,8 @@ extends DialogicVisualEditorField
@export var file_filter := ""
@export var placeholder := ""
-@export var file_mode : EditorFileDialog.FileMode = EditorFileDialog.FILE_MODE_OPEN_FILE
-var resource_icon:Texture:
+@export var file_mode: EditorFileDialog.FileMode = EditorFileDialog.FILE_MODE_OPEN_FILE
+var resource_icon: Texture:
get:
return resource_icon
set(new_icon):
@@ -21,8 +21,8 @@ var resource_icon:Texture:
%Field.theme_type_variation = "LineEditWithIcon"
var max_width := 200
-var current_value : String
-var hide_reset:bool = false
+var current_value: String
+var hide_reset := false
#endregion
@@ -49,13 +49,15 @@ func _load_display_info(info:Dictionary) -> void:
placeholder = info.get('placeholder', '')
resource_icon = info.get('icon', null)
await ready
+
if resource_icon == null and info.has('editor_icon'):
resource_icon = callv('get_theme_icon', info.editor_icon)
-func _set_value(value:Variant) -> void:
+func _set_value(value: Variant) -> void:
current_value = value
- var text := value
+ var text: String = value
+
if file_mode != EditorFileDialog.FILE_MODE_OPEN_DIR:
text = value.get_file()
%Field.tooltip_text = value
@@ -70,9 +72,11 @@ func _set_value(value:Variant) -> void:
%Field.custom_minimum_size.x = 0
%Field.expand_to_text_length = true
- %Field.text = text
+ if not %Field.text == text:
+ value_changed.emit(property_name, current_value)
+ %Field.text = text
- %ClearButton.visible = !value.is_empty() and !hide_reset
+ %ClearButton.visible = not value.is_empty() and not hide_reset
#endregion
@@ -87,12 +91,12 @@ func _on_OpenButton_pressed() -> void:
func _on_file_dialog_selected(path:String) -> void:
_set_value(path)
- emit_signal("value_changed", property_name, path)
+ value_changed.emit(property_name, path)
func clear_path() -> void:
_set_value("")
- emit_signal("value_changed", property_name, "")
+ value_changed.emit(property_name, "")
#endregion
@@ -100,16 +104,22 @@ func clear_path() -> void:
#region DRAG AND DROP
################################################################################
-func _can_drop_data_fw(at_position: Vector2, data: Variant) -> bool:
+func _can_drop_data_fw(_at_position: Vector2, data: Variant) -> bool:
if typeof(data) == TYPE_DICTIONARY and data.has('files') and len(data.files) == 1:
+
if file_filter:
+
if '*.'+data.files[0].get_extension() in file_filter:
return true
+
else: return true
+
return false
-func _drop_data_fw(at_position: Vector2, data: Variant) -> void:
- _on_file_dialog_selected(data.files[0])
+
+func _drop_data_fw(_at_position: Vector2, data: Variant) -> void:
+ var file: String = data.files[0]
+ _on_file_dialog_selected(file)
#endregion
@@ -117,11 +127,13 @@ func _drop_data_fw(at_position: Vector2, data: Variant) -> void:
#region VISUALS FOR FOCUS
################################################################################
-func _on_field_focus_entered():
+func _on_field_focus_entered() -> void:
$FocusStyle.show()
-func _on_field_focus_exited():
+
+func _on_field_focus_exited() -> void:
$FocusStyle.hide()
- _on_file_dialog_selected(%Field.text)
+ var field_text: String = %Field.text
+ _on_file_dialog_selected(field_text)
#endregion
diff --git a/addons/dialogic/Editor/Events/Fields/field_file.tscn b/addons/dialogic/Editor/Events/Fields/field_file.tscn
index c0e51dace..8b47de7de 100644
--- a/addons/dialogic/Editor/Events/Fields/field_file.tscn
+++ b/addons/dialogic/Editor/Events/Fields/field_file.tscn
@@ -8,7 +8,7 @@
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_6b7on"]
-[sub_resource type="Image" id="Image_kg01j"]
+[sub_resource type="Image" id="Image_bpoe1"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -17,10 +17,10 @@ data = {
"width": 16
}
-[sub_resource type="ImageTexture" id="ImageTexture_j8aof"]
-image = SubResource("Image_kg01j")
+[sub_resource type="ImageTexture" id="ImageTexture_dkuon"]
+image = SubResource("Image_bpoe1")
-[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_raavq"]
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_yv1pn"]
content_margin_left = 4.0
content_margin_top = 4.0
content_margin_right = 4.0
@@ -67,20 +67,20 @@ expand_to_text_length = true
[node name="OpenButton" type="Button" parent="BG/HBox"]
unique_name_in_owner = true
layout_mode = 2
-icon = SubResource("ImageTexture_j8aof")
+icon = SubResource("ImageTexture_dkuon")
flat = true
[node name="ClearButton" type="Button" parent="BG/HBox"]
unique_name_in_owner = true
layout_mode = 2
-icon = SubResource("ImageTexture_j8aof")
+icon = SubResource("ImageTexture_dkuon")
flat = true
[node name="FocusStyle" type="Panel" parent="."]
visible = false
layout_mode = 2
mouse_filter = 2
-theme_override_styles/panel = SubResource("StyleBoxFlat_raavq")
+theme_override_styles/panel = SubResource("StyleBoxFlat_yv1pn")
[connection signal="focus_entered" from="BG/HBox/Field" to="." method="_on_field_focus_entered"]
[connection signal="focus_exited" from="BG/HBox/Field" to="." method="_on_field_focus_exited"]
diff --git a/addons/dialogic/Editor/Events/Fields/field_flex_value.gd b/addons/dialogic/Editor/Events/Fields/field_flex_value.gd
new file mode 100644
index 000000000..be7a98d6a
--- /dev/null
+++ b/addons/dialogic/Editor/Events/Fields/field_flex_value.gd
@@ -0,0 +1,154 @@
+@tool
+extends HBoxContainer
+
+## Event block field part for a value that can change type.
+
+signal value_changed
+
+var value_field: Node
+var value_type: int = -1
+
+var current_value: Variant
+
+func _ready() -> void:
+ %ValueType.options = [{
+ 'label': 'String',
+ 'icon': ["String", "EditorIcons"],
+ 'value': TYPE_STRING
+ },{
+ 'label': 'Number (int)',
+ 'icon': ["int", "EditorIcons"],
+ 'value': TYPE_INT
+ },{
+ 'label': 'Number (float)',
+ 'icon': ["float", "EditorIcons"],
+ 'value': TYPE_FLOAT
+ },{
+ 'label': 'Boolean',
+ 'icon': ["bool", "EditorIcons"],
+ 'value': TYPE_BOOL
+ },{
+ 'label': 'Expression',
+ 'icon': ["Variant", "EditorIcons"],
+ 'value': TYPE_MAX
+ }
+ ]
+ %ValueType.symbol_only = true
+ %ValueType.value_changed.connect(_on_type_changed.bind())
+ %ValueType.tooltip_text = "Change type"
+
+
+func set_value(value:Variant):
+ change_field_type(deduce_type(value))
+ %ValueType.set_value(deduce_type(value))
+ current_value = value
+ match value_type:
+ TYPE_BOOL:
+ value_field.button_pressed = value
+ TYPE_STRING:
+ value_field.text = value
+ TYPE_FLOAT, TYPE_INT:
+ value_field.set_value(value)
+ TYPE_MAX, _:
+ value_field.text = value.trim_prefix('@')
+
+
+func deduce_type(value:Variant) -> int:
+ if value is String and value.begins_with('@'):
+ return TYPE_MAX
+ else:
+ return typeof(value)
+
+
+func _on_type_changed(prop:String, type:Variant) -> void:
+ if type == value_type:
+ return
+
+ match type:
+ TYPE_BOOL:
+ if typeof(current_value) == TYPE_STRING:
+ current_value = DialogicUtil.str_to_bool(current_value)
+ elif value_type == TYPE_FLOAT or value_type == TYPE_INT:
+ current_value = bool(current_value)
+ else:
+ current_value = true if current_value else false
+ set_value(current_value)
+ TYPE_STRING:
+ current_value = str(current_value).trim_prefix('@')
+ set_value(current_value)
+ TYPE_FLOAT:
+ current_value = float(current_value)
+ set_value(current_value)
+ TYPE_INT:
+ current_value = int(current_value)
+ set_value(current_value)
+ TYPE_MAX,_:
+ current_value = var_to_str(current_value)
+ set_value('@'+current_value)
+
+
+ emit_signal.call_deferred('value_changed')
+
+
+func get_value() -> Variant:
+ return current_value
+
+
+func _on_delete_pressed() -> void:
+ queue_free()
+ value_changed.emit()
+
+
+func change_field_type(type:int) -> void:
+ if type == value_type:
+ return
+
+ value_type = type
+
+ if value_field:
+ value_field.queue_free()
+ match type:
+ TYPE_BOOL:
+ value_field = CheckBox.new()
+ value_field.toggled.connect(_on_bool_toggled)
+ TYPE_STRING:
+ value_field = LineEdit.new()
+ value_field.theme_type_variation = "DialogicEventEdit"
+ value_field.text_changed.connect(_on_str_text_changed)
+ value_field.expand_to_text_length = true
+ TYPE_FLOAT, TYPE_INT:
+ value_field = load("res://addons/dialogic/Editor/Events/Fields/field_number.tscn").instantiate()
+ if type == TYPE_FLOAT:
+ value_field.use_float_mode()
+ else:
+ value_field.use_int_mode()
+ value_field.value_changed.connect(_on_number_value_changed.bind(type == TYPE_INT))
+ TYPE_MAX, _:
+ value_field = LineEdit.new()
+ value_field.expand_to_text_length = true
+ value_field.text_changed.connect(_on_expression_changed)
+ add_child(value_field)
+ move_child(value_field, 1)
+
+
+func _on_bool_toggled(value:bool) -> void:
+ current_value = value
+ value_changed.emit()
+
+
+func _on_str_text_changed(value:String) -> void:
+ current_value = value
+ value_changed.emit()
+
+
+func _on_expression_changed(value:String) -> void:
+ current_value = '@'+value
+ value_changed.emit()
+
+
+func _on_number_value_changed(prop:String, value:float, int := false) -> void:
+ if int:
+ current_value = int(value)
+ else:
+ current_value = value
+ value_changed.emit()
diff --git a/addons/dialogic/Editor/Events/Fields/field_flex_value.tscn b/addons/dialogic/Editor/Events/Fields/field_flex_value.tscn
new file mode 100644
index 000000000..2d461865f
--- /dev/null
+++ b/addons/dialogic/Editor/Events/Fields/field_flex_value.tscn
@@ -0,0 +1,15 @@
+[gd_scene load_steps=3 format=3 uid="uid://dl08ubinx6ugu"]
+
+[ext_resource type="Script" path="res://addons/dialogic/Editor/Events/Fields/field_flex_value.gd" id="1_m5nnp"]
+[ext_resource type="PackedScene" uid="uid://d3bhehatwoio" path="res://addons/dialogic/Editor/Events/Fields/field_options_fixed.tscn" id="3_h10fc"]
+
+[node name="FlexValue" type="HBoxContainer"]
+offset_right = 65.0
+offset_bottom = 22.0
+script = ExtResource("1_m5nnp")
+
+[node name="ValueType" parent="." instance=ExtResource("3_h10fc")]
+unique_name_in_owner = true
+layout_mode = 2
+tooltip_text = "Change type"
+text = ""
diff --git a/addons/dialogic/Editor/Events/Fields/field_number.gd b/addons/dialogic/Editor/Events/Fields/field_number.gd
index ff3527d9d..c2733b9f2 100644
--- a/addons/dialogic/Editor/Events/Fields/field_number.gd
+++ b/addons/dialogic/Editor/Events/Fields/field_number.gd
@@ -4,12 +4,12 @@ extends DialogicVisualEditorField
## Event block field for integers and floats. Improved version of the native spinbox.
-@export var allow_string : bool = false
+@export var allow_string: bool = false
@export var step: float = 0.1
@export var enforce_step: bool = true
@export var limit_value: bool = false
-@export var min: float = 0.0
-@export var max: float = 999.0
+@export var min: float = -INF
+@export var max: float = INF
@export var only_positive: bool = false
@export var value = 0.0
@export var prefix: String = ""
@@ -26,7 +26,6 @@ func _ready() -> void:
update_prefix(prefix)
update_suffix(suffix)
- $Value_Panel.add_theme_stylebox_override('panel', get_theme_stylebox('panel', 'DialogicEventEdit'))
func _load_display_info(info: Dictionary) -> void:
@@ -161,6 +160,8 @@ func _on_decrement_button_down(button: NodePath) -> void:
func _on_value_text_submitted(new_text: String, no_signal:= false) -> void:
+ if new_text.is_empty() and not allow_string:
+ new_text = "0.0"
if new_text.is_valid_float():
var final_value := new_text.to_float()
diff --git a/addons/dialogic/Editor/Events/Fields/field_number.tscn b/addons/dialogic/Editor/Events/Fields/field_number.tscn
index bc4a8f23c..5053a87d8 100644
--- a/addons/dialogic/Editor/Events/Fields/field_number.tscn
+++ b/addons/dialogic/Editor/Events/Fields/field_number.tscn
@@ -40,10 +40,10 @@ grow_horizontal = 2
grow_vertical = 2
theme_override_constants/separation = 0
script = ExtResource("1_0jdnn")
-prefix = null
[node name="Value_Panel" type="PanelContainer" parent="."]
layout_mode = 2
+theme_type_variation = &"DialogicEventEdit"
[node name="Layout" type="HBoxContainer" parent="Value_Panel"]
layout_mode = 2
@@ -106,26 +106,17 @@ shortcut_keys_enabled = false
drag_and_drop_selection_enabled = false
text_direction = 1
-[node name="HBoxContainer" type="HBoxContainer" parent="Value_Panel/Layout"]
-layout_mode = 2
-theme_override_constants/separation = 0
-
-[node name="Spacer" type="MarginContainer" parent="Value_Panel/Layout/HBoxContainer"]
-layout_mode = 2
-mouse_filter = 2
-theme_override_constants/margin_right = 1
-
-[node name="Spin" type="VBoxContainer" parent="Value_Panel/Layout/HBoxContainer"]
+[node name="Spin" type="VBoxContainer" parent="Value_Panel/Layout"]
unique_name_in_owner = true
layout_mode = 2
theme_override_constants/separation = 0
alignment = 1
-[node name="Increment" type="Button" parent="Value_Panel/Layout/HBoxContainer/Spin"]
+[node name="Increment" type="Button" parent="Value_Panel/Layout/Spin"]
layout_mode = 2
size_flags_vertical = 3
auto_translate = false
-focus_neighbor_left = NodePath("../../../Value")
+focus_neighbor_left = NodePath("../../Value")
focus_neighbor_top = NodePath(".")
focus_neighbor_bottom = NodePath("../Decrement")
theme_override_colors/icon_hover_color = Color(0.412738, 0.550094, 0.760917, 1)
@@ -139,11 +130,11 @@ icon = ExtResource("3_v5cne")
flat = true
vertical_icon_alignment = 2
-[node name="Decrement" type="Button" parent="Value_Panel/Layout/HBoxContainer/Spin"]
+[node name="Decrement" type="Button" parent="Value_Panel/Layout/Spin"]
layout_mode = 2
size_flags_vertical = 3
auto_translate = false
-focus_neighbor_left = NodePath("../../../Value")
+focus_neighbor_left = NodePath("../../Value")
focus_neighbor_top = NodePath("../Increment")
focus_neighbor_bottom = NodePath(".")
theme_override_colors/icon_hover_color = Color(0.412738, 0.550094, 0.760917, 1)
@@ -157,17 +148,13 @@ icon = ExtResource("4_ph52o")
flat = true
vertical_icon_alignment = 2
-[node name="Spacer" type="Control" parent="."]
-custom_minimum_size = Vector2(3, 0)
-layout_mode = 2
-
[connection signal="gui_input" from="Value_Panel/Layout/Prefix" to="." method="_on_sublabel_clicked"]
[connection signal="focus_entered" from="Value_Panel/Layout/Value" to="." method="_on_value_focus_entered"]
[connection signal="focus_exited" from="Value_Panel/Layout/Value" to="." method="_on_value_focus_exited"]
[connection signal="gui_input" from="Value_Panel/Layout/Value" to="." method="_on_gui_input"]
[connection signal="text_submitted" from="Value_Panel/Layout/Value" to="." method="_on_value_text_submitted"]
[connection signal="gui_input" from="Value_Panel/Layout/Suffix" to="." method="_on_sublabel_clicked"]
-[connection signal="button_down" from="Value_Panel/Layout/HBoxContainer/Spin/Increment" to="." method="_on_increment_button_down" binds= [NodePath("%Spin/Increment")]]
-[connection signal="gui_input" from="Value_Panel/Layout/HBoxContainer/Spin/Increment" to="." method="_on_gui_input"]
-[connection signal="button_down" from="Value_Panel/Layout/HBoxContainer/Spin/Decrement" to="." method="_on_decrement_button_down" binds= [NodePath("%Spin/Decrement")]]
-[connection signal="gui_input" from="Value_Panel/Layout/HBoxContainer/Spin/Decrement" to="." method="_on_gui_input"]
+[connection signal="button_down" from="Value_Panel/Layout/Spin/Increment" to="." method="_on_increment_button_down" binds= [NodePath("%Spin/Increment")]]
+[connection signal="gui_input" from="Value_Panel/Layout/Spin/Increment" to="." method="_on_gui_input"]
+[connection signal="button_down" from="Value_Panel/Layout/Spin/Decrement" to="." method="_on_decrement_button_down" binds= [NodePath("%Spin/Decrement")]]
+[connection signal="gui_input" from="Value_Panel/Layout/Spin/Decrement" to="." method="_on_gui_input"]
diff --git a/addons/dialogic/Editor/Events/Fields/field_options_dynamic.gd b/addons/dialogic/Editor/Events/Fields/field_options_dynamic.gd
index eb25d3987..16a315f14 100644
--- a/addons/dialogic/Editor/Events/Fields/field_options_dynamic.gd
+++ b/addons/dialogic/Editor/Events/Fields/field_options_dynamic.gd
@@ -60,6 +60,7 @@ func _load_display_info(info:Dictionary) -> void:
placeholder_text = info.get('placeholder', 'Select Resource')
mode = info.get("mode", 0)
resource_icon = info.get('icon', null)
+ %Search.tooltip_text = info.get('tooltip_text', '')
await ready
if resource_icon == null and info.has('editor_icon'):
resource_icon = callv('get_theme_icon', info.editor_icon)
@@ -75,7 +76,10 @@ func _autofocus() -> void:
################################################################################
func _ready() -> void:
- %Focus.add_theme_stylebox_override('panel', get_theme_stylebox('focus', 'DialogicEventEdit'))
+ var focus := get_theme_stylebox("focus", "LineEdit")
+ if has_theme_stylebox("focus", "DialogicEventEdit"):
+ focus = get_theme_stylebox('focus', 'DialogicEventEdit')
+ %Focus.add_theme_stylebox_override('panel', focus)
%Search.text_changed.connect(_on_Search_text_changed)
%Search.text_submitted.connect(_on_Search_text_entered)
@@ -126,8 +130,8 @@ func _on_Search_text_changed(new_text:String, just_update:bool = false) -> void:
var suggestions: Dictionary = get_suggestions_func.call(new_text)
- var line_length = 0
- var idx: int = 0
+ var line_length := 0
+ var idx := 0
for element in suggestions:
if new_text.is_empty() or new_text.to_lower() in element.to_lower() or new_text.to_lower() in str(suggestions[element].value).to_lower() or new_text.to_lower() in suggestions[element].get('tooltip', '').to_lower():
var curr_line_length: int = 0
@@ -178,7 +182,7 @@ func _on_Search_text_changed(new_text:String, just_update:bool = false) -> void:
%Suggestions.size.x = max(%PanelContainer.size.x, line_length)
-func suggestion_selected(index : int, position:=Vector2(), button_index:=MOUSE_BUTTON_LEFT) -> void:
+func suggestion_selected(index: int, position := Vector2(), button_index := MOUSE_BUTTON_LEFT) -> void:
if button_index != MOUSE_BUTTON_LEFT:
return
if %Suggestions.is_item_disabled(index):
diff --git a/addons/dialogic/Editor/Events/Fields/field_options_dynamic.tscn b/addons/dialogic/Editor/Events/Fields/field_options_dynamic.tscn
index c4ce234c0..1f4e2200e 100644
--- a/addons/dialogic/Editor/Events/Fields/field_options_dynamic.tscn
+++ b/addons/dialogic/Editor/Events/Fields/field_options_dynamic.tscn
@@ -6,7 +6,7 @@
[sub_resource type="StyleBoxEmpty" id="StyleBoxEmpty_vennf"]
-[sub_resource type="Image" id="Image_jcy4w"]
+[sub_resource type="Image" id="Image_5e7lo"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -15,10 +15,10 @@ data = {
"width": 16
}
-[sub_resource type="ImageTexture" id="ImageTexture_8v6yx"]
-image = SubResource("Image_jcy4w")
+[sub_resource type="ImageTexture" id="ImageTexture_g63da"]
+image = SubResource("Image_5e7lo")
-[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_2yd2x"]
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_g74jb"]
content_margin_left = 4.0
content_margin_top = 4.0
content_margin_right = 4.0
@@ -116,7 +116,7 @@ layout_mode = 2
focus_mode = 0
toggle_mode = true
shortcut_in_tooltip = false
-icon = SubResource("ImageTexture_8v6yx")
+icon = SubResource("ImageTexture_g63da")
flat = true
[node name="Focus" type="Panel" parent="PanelContainer"]
@@ -124,7 +124,7 @@ unique_name_in_owner = true
visible = false
layout_mode = 2
mouse_filter = 2
-theme_override_styles/panel = SubResource("StyleBoxFlat_2yd2x")
+theme_override_styles/panel = SubResource("StyleBoxFlat_g74jb")
metadata/_edit_use_anchors_ = true
[connection signal="focus_entered" from="." to="." method="_on_focus_entered"]
diff --git a/addons/dialogic/Editor/Events/Fields/field_options_fixed.gd b/addons/dialogic/Editor/Events/Fields/field_options_fixed.gd
index f88866eda..ff404698e 100644
--- a/addons/dialogic/Editor/Events/Fields/field_options_fixed.gd
+++ b/addons/dialogic/Editor/Events/Fields/field_options_fixed.gd
@@ -3,10 +3,7 @@ extends DialogicVisualEditorField
## Event block field for constant options. For varying options use ComplexPicker.
-
-@export var placeholder_text := "Placeholder Text"
-
-var options : Array = []
+var options: Array = []
## if true, only the symbol will be displayed. In the dropdown text will be visible.
## Useful for making UI simpler
diff --git a/addons/dialogic/Editor/Events/Fields/field_text_multiline.gd b/addons/dialogic/Editor/Events/Fields/field_text_multiline.gd
index 5b63d31e5..aaeb4c4d5 100644
--- a/addons/dialogic/Editor/Events/Fields/field_text_multiline.gd
+++ b/addons/dialogic/Editor/Events/Fields/field_text_multiline.gd
@@ -5,10 +5,6 @@ extends DialogicVisualEditorField
@onready var code_completion_helper: Node = find_parent('EditorsManager').get_node('CodeCompletionHelper')
-var previous_width := 0
-var height_recalculation_queued := false
-
-var line_count := 0
#region MAIN METHODS
################################################################################
@@ -16,7 +12,6 @@ var line_count := 0
func _ready() -> void:
self.text_changed.connect(_on_text_changed)
self.syntax_highlighter = code_completion_helper.text_syntax_highlighter
- resized.connect(_resized)
func _load_display_info(info:Dictionary) -> void:
@@ -25,7 +20,6 @@ func _load_display_info(info:Dictionary) -> void:
func _set_value(value:Variant) -> void:
self.text = str(value)
- queue_height_recalculation()
func _autofocus() -> void:
@@ -39,42 +33,6 @@ func _autofocus() -> void:
func _on_text_changed(value := "") -> void:
value_changed.emit(property_name, self.text)
- _request_code_completion(true)
- queue_height_recalculation()
-
-
-func _resized() -> void:
- if previous_width != size.x:
- queue_height_recalculation()
- previous_width = size.x
-
-#endregion
-
-
-#region HEIGHT CALCULATION
-################################################################################
-
-func queue_height_recalculation():
- if !is_node_ready():
- await _ready()
- await get_tree().process_frame
- if !height_recalculation_queued:
- height_recalculation_queued = true
- recalculate_height.call_deferred()
-
-
-## This shouldn't be necessary bug [fit_content_height] creates a crash.
-## TODO Remove again once https://github.com/godotengine/godot/issues/80546 is fixed.
-func recalculate_height() -> void:
- height_recalculation_queued = false
- var font: Font = get_theme_font("font")
- var text_size = font.get_multiline_string_size(self.text+' ', HORIZONTAL_ALIGNMENT_LEFT, size.x-14, get_theme_font_size("font_size"))
- custom_minimum_size.y = text_size.y+20+4*(ceil(text_size.y/get_theme_font_size("font_size")))
- self.scroll_vertical = 0
- if get_parent().get_child(get_index()).get_visible_line_count() != line_count:
- if find_parent("VisualEditor"):
- find_parent("VisualEditor").indent_events()
- line_count = get_parent().get_child(get_index()).get_visible_line_count()
#endregion
diff --git a/addons/dialogic/Editor/Events/Fields/field_text_multiline.tscn b/addons/dialogic/Editor/Events/Fields/field_text_multiline.tscn
index b73197b80..6ab8fb660 100644
--- a/addons/dialogic/Editor/Events/Fields/field_text_multiline.tscn
+++ b/addons/dialogic/Editor/Events/Fields/field_text_multiline.tscn
@@ -1,6 +1,5 @@
-[gd_scene load_steps=5 format=3 uid="uid://dyp7m2nvab1aj"]
+[gd_scene load_steps=4 format=3 uid="uid://dyp7m2nvab1aj"]
-[ext_resource type="StyleBox" uid="uid://cu8otiwksn8ma" path="res://addons/dialogic/Editor/Events/styles/TextBackground.tres" id="1_xq18n"]
[ext_resource type="Script" path="res://addons/dialogic/Editor/TimelineEditor/TextEditor/syntax_highlighter.gd" id="2_ww6ga"]
[ext_resource type="Script" path="res://addons/dialogic/Editor/Events/Fields/field_text_multiline.gd" id="3_q7600"]
@@ -12,8 +11,9 @@ offset_right = 413.0
offset_bottom = 15.0
size_flags_horizontal = 3
size_flags_vertical = 3
-theme_override_styles/normal = ExtResource("1_xq18n")
+theme_type_variation = &"DialogicTextEventTextEdit"
wrap_mode = 1
+scroll_fit_content_height = true
syntax_highlighter = SubResource("SyntaxHighlighter_2q5dk")
symbol_lookup_on_click = true
delimiter_strings = Array[String]([])
diff --git a/addons/dialogic/Editor/Events/Fields/field_text_singleline.gd b/addons/dialogic/Editor/Events/Fields/field_text_singleline.gd
index c6378eec4..765f86236 100644
--- a/addons/dialogic/Editor/Events/Fields/field_text_singleline.gd
+++ b/addons/dialogic/Editor/Events/Fields/field_text_singleline.gd
@@ -4,7 +4,7 @@ extends DialogicVisualEditorField
## Event block field for a single line of text.
-var placeholder :String= "":
+var placeholder := "":
set(value):
placeholder = value
self.placeholder_text = placeholder
@@ -25,7 +25,7 @@ func _set_value(value:Variant) -> void:
self.text = str(value)
-func _autofocus():
+func _autofocus() -> void:
grab_focus()
#endregion
diff --git a/addons/dialogic/Editor/HomePage/home_page.gd b/addons/dialogic/Editor/HomePage/home_page.gd
index c666c3282..15aff2522 100644
--- a/addons/dialogic/Editor/HomePage/home_page.gd
+++ b/addons/dialogic/Editor/HomePage/home_page.gd
@@ -3,7 +3,7 @@ extends DialogicEditor
## A Main page in the dialogic editor.
-var tips : Array = []
+var tips: Array = []
@@ -11,7 +11,7 @@ func _get_icon() -> Texture:
return load("res://addons/dialogic/Editor/Images/plugin-icon.svg")
-func _ready():
+func _ready() -> void:
self_modulate = get_theme_color("font_color", "Editor")
self_modulate.a = 0.2
@@ -30,7 +30,7 @@ func _ready():
-func _register():
+func _register() -> void:
editors_manager.register_simple_editor(self)
self.alternative_text = "Welcome to dialogic!"
@@ -44,7 +44,7 @@ func _open(extra_info:Variant="") -> void:
tips = tips.filter(func(item): return !item.is_empty())
randomize()
- var tip :String = tips[randi()%len(tips)]
+ var tip: String = tips[randi()%len(tips)]
var text := tip.get_slice(';',0).strip_edges()
var action := tip.get_slice(';',1).strip_edges()
if action == text:
diff --git a/addons/dialogic/Editor/HomePage/home_page.tscn b/addons/dialogic/Editor/HomePage/home_page.tscn
index a7733f26b..0272d3457 100644
--- a/addons/dialogic/Editor/HomePage/home_page.tscn
+++ b/addons/dialogic/Editor/HomePage/home_page.tscn
@@ -102,7 +102,7 @@ corner_radius_top_right = 5
corner_radius_bottom_right = 5
corner_radius_bottom_left = 5
-[sub_resource type="Image" id="Image_ubn0t"]
+[sub_resource type="Image" id="Image_e1dkh"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -111,8 +111,8 @@ data = {
"width": 16
}
-[sub_resource type="ImageTexture" id="ImageTexture_jsefb"]
-image = SubResource("Image_ubn0t")
+[sub_resource type="ImageTexture" id="ImageTexture_sr7s6"]
+image = SubResource("Image_e1dkh")
[node name="HomePage" type="TextureRect"]
self_modulate = Color(0, 0, 0, 0.2)
@@ -234,7 +234,7 @@ modulate = Color(1, 1, 1, 0.501961)
layout_mode = 2
size_flags_vertical = 8
theme_override_font_sizes/font_size = 10
-text = "2.0-Alpha-13 (Godot 4.2+)"
+text = "2.0-Alpha-15 WIP (Godot 4.2+)"
horizontal_alignment = 2
[node name="ScrollContainer" type="ScrollContainer" parent="CenterContainer/HomePageBox/BottomPanel"]
@@ -305,7 +305,7 @@ layout_mode = 2
theme_type_variation = &"DialogicLink"
text = " Donate"
underline = 2
-uri = "https://www.patreon.com/coppolaemilio"
+uri = "https://www.patreon.com/JowanSpooner"
[node name="CenterContainer2" type="VBoxContainer" parent="CenterContainer/HomePageBox/BottomPanel/ScrollContainer/HBoxContainer"]
layout_mode = 2
@@ -369,5 +369,5 @@ grow_vertical = 0
tooltip_text = "Check it out!"
theme_override_styles/normal = SubResource("StyleBoxFlat_ckyhx")
theme_override_styles/hover = SubResource("StyleBoxFlat_l1doy")
-icon = SubResource("ImageTexture_jsefb")
+icon = SubResource("ImageTexture_sr7s6")
expand_icon = true
diff --git a/addons/dialogic/Editor/HomePage/tips.txt b/addons/dialogic/Editor/HomePage/tips.txt
index c8b6f07be..4ca5ec764 100644
--- a/addons/dialogic/Editor/HomePage/tips.txt
+++ b/addons/dialogic/Editor/HomePage/tips.txt
@@ -4,8 +4,8 @@ If there are events you never need, you can hide them from the list in the edito
Did you know that dialogic supports translations? It does!; editor://Settings->Translations
You can use [b]bbcode effects[/b] in text events! What are they though???; https://docs.godotengine.org/en/latest/tutorials/ui/bbcode_in_richtextlabel.html
Writing [/i][i] in a text event will pick a random one of the three strings!
-There are a number of cool text effects like [pause=x], [speed=x] and [portrait=x]. Try them out!; editor://Settings->Text
-You can use scenes as portraits! This gives you basically limiteless freedom.; https://dialogic-docs.coppolaemilio.com/custom-portraits.html
+There are a number of cool text effects like [pause=x], [speed=x] and [portrait=x]. Try them out!;
+You can use scenes as portraits! This gives you basically limitless freedom.; https://dialogic-docs.coppolaemilio.com/custom-portraits.html
You can use scenes as backgrounds. This way they can be animated or whatever you want!
Dialogic has a built in save and load system! It's pretty powerful!; editor://Settings->Saving
You can add multiple glossary files, each containing words that can be hovered for information!; editor://GlossaryEditor
diff --git a/addons/dialogic/Editor/Images/Pieces/close-icon.svg b/addons/dialogic/Editor/Images/Pieces/close-icon.svg
new file mode 100644
index 000000000..3e3f7af3b
--- /dev/null
+++ b/addons/dialogic/Editor/Images/Pieces/close-icon.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/addons/dialogic/Editor/Images/Pieces/close-icon.svg.import b/addons/dialogic/Editor/Images/Pieces/close-icon.svg.import
new file mode 100644
index 000000000..cbc36f218
--- /dev/null
+++ b/addons/dialogic/Editor/Images/Pieces/close-icon.svg.import
@@ -0,0 +1,38 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://bff65e82555qr"
+path="res://.godot/imported/close-icon.svg-c630c93ada599b08938f4854f5376f2f.ctex"
+metadata={
+"has_editor_variant": true,
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/dialogic/Editor/Images/Pieces/close-icon.svg"
+dest_files=["res://.godot/imported/close-icon.svg-c630c93ada599b08938f4854f5376f2f.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=true
+editor/convert_colors_with_editor_theme=true
diff --git a/addons/dialogic/Editor/Inspector/inspector_plugin.gd b/addons/dialogic/Editor/Inspector/inspector_plugin.gd
new file mode 100644
index 000000000..0a40bc388
--- /dev/null
+++ b/addons/dialogic/Editor/Inspector/inspector_plugin.gd
@@ -0,0 +1,15 @@
+@tool
+extends EditorInspectorPlugin
+
+
+func _can_handle(object: Object) -> bool:
+ return true
+
+
+func _parse_property(object: Object, type: Variant.Type, name: String, hint_type: PropertyHint, hint_string: String, usage_flags: int, wide: bool) -> bool:
+ if type == TYPE_OBJECT and hint_type == PROPERTY_HINT_RESOURCE_TYPE:
+ if hint_string == "DialogicTimeline":
+ var editor: EditorProperty = load("res://addons/dialogic/Editor/Inspector/timeline_inspector_field.gd").new()
+ add_property_editor(name, editor)
+ return true
+ return false
diff --git a/addons/dialogic/Editor/Inspector/timeline_inspector_field.gd b/addons/dialogic/Editor/Inspector/timeline_inspector_field.gd
new file mode 100644
index 000000000..6e617fead
--- /dev/null
+++ b/addons/dialogic/Editor/Inspector/timeline_inspector_field.gd
@@ -0,0 +1,82 @@
+@tool
+extends EditorProperty
+
+var field: Control = null
+var button: Button = null
+# An internal value of the property.
+var current_value: DialogicTimeline = null
+# A guard against internal changes when the property is updated.
+var updating = false
+
+
+func _init() -> void:
+ var hbox := HBoxContainer.new()
+ add_child(hbox)
+
+ field = load("res://addons/dialogic/Editor/Events/Fields/field_options_dynamic.tscn").instantiate()
+ hbox.add_child(field)
+ field.placeholder_text = "No Timeline"
+ field.size_flags_horizontal = Control.SIZE_EXPAND_FILL
+ field.size_flags_vertical = Control.SIZE_SHRINK_CENTER
+ field.mode = field.Modes.IDENTIFIER
+ field.fit_text_length = false
+ field.valid_file_drop_extension = ".dtl"
+ field.value_changed.connect(_on_field_value_changed)
+ field.get_suggestions_func = get_timeline_suggestions
+
+ button = Button.new()
+ hbox.add_child(button)
+ button.hide()
+ button.pressed.connect(_on_button_pressed, CONNECT_DEFERRED)
+
+
+func _on_field_value_changed(property:String, value:Variant) -> void:
+ # Ignore the signal if the property is currently being updated.
+ if updating:
+ return
+
+ var new_value: DialogicTimeline = null
+ if value:
+ new_value = DialogicResourceUtil.get_timeline_resource(value)
+
+ if current_value != new_value:
+ current_value = new_value
+ if current_value:
+ button.show()
+ else:
+ button.hide()
+ emit_changed(get_edited_property(), current_value)
+
+
+func _update_property() -> void:
+ field.resource_icon = get_theme_icon("TripleBar", "EditorIcons")
+ button.icon = get_theme_icon("ExternalLink", "EditorIcons")
+
+ # Read the current value from the property.
+ var new_value = get_edited_object()[get_edited_property()]
+ if (new_value == current_value):
+ return
+
+ # Update the control with the new value.
+ updating = true
+ current_value = new_value
+ if current_value:
+ field.set_value(DialogicResourceUtil.get_unique_identifier(current_value.resource_path))
+ button.show()
+ else:
+ button.hide()
+ field.set_value("")
+ updating = false
+
+
+func get_timeline_suggestions(filter:String) -> Dictionary:
+ var suggestions := {}
+ var timeline_directory := DialogicResourceUtil.get_timeline_directory()
+ for identifier in timeline_directory.keys():
+ suggestions[identifier] = {'value': identifier, 'tooltip':timeline_directory[identifier], 'editor_icon': ["TripleBar", "EditorIcons"]}
+ return suggestions
+
+
+func _on_button_pressed() -> void:
+ if current_value:
+ EditorInterface.edit_resource(current_value)
diff --git a/addons/dialogic/Editor/Settings/HintLabelStylingScript.gd b/addons/dialogic/Editor/Settings/HintLabelStylingScript.gd
index 1b51f30d4..f5f11e3a6 100644
--- a/addons/dialogic/Editor/Settings/HintLabelStylingScript.gd
+++ b/addons/dialogic/Editor/Settings/HintLabelStylingScript.gd
@@ -2,7 +2,7 @@
extends Label
# Called when the node enters the scene tree for the first time.
-func _ready():
+func _ready() -> void:
# don't load the label settings when opening as a scene
# prevents HUGE diffs
if owner.get_parent() is SubViewport:
diff --git a/addons/dialogic/Editor/Settings/csv_file.gd b/addons/dialogic/Editor/Settings/csv_file.gd
index 28db80e5b..3f8fb3a98 100644
--- a/addons/dialogic/Editor/Settings/csv_file.gd
+++ b/addons/dialogic/Editor/Settings/csv_file.gd
@@ -55,7 +55,7 @@ func _init(file_path: String, original_locale: String, separator_enabled: bool)
var locale_array_line := PackedStringArray(["keys", original_locale])
lines.append(locale_array_line)
- if not FileAccess.file_exists(file_path):
+ if not ResourceLoader.exists(file_path):
is_new_file = true
# The "keys" and original locale are the only columns in a new file.
diff --git a/addons/dialogic/Editor/Settings/settings_editor.gd b/addons/dialogic/Editor/Settings/settings_editor.gd
index 7c51b4d8d..3d87c4abc 100644
--- a/addons/dialogic/Editor/Settings/settings_editor.gd
+++ b/addons/dialogic/Editor/Settings/settings_editor.gd
@@ -4,7 +4,7 @@ extends DialogicEditor
## Editor that contains all settings
var button_group := ButtonGroup.new()
-var registered_sections :Array[DialogicSettingsPage] = []
+var registered_sections: Array[DialogicSettingsPage] = []
func _get_title() -> String:
@@ -15,12 +15,12 @@ func _get_icon() -> Texture:
return get_theme_icon("PluginScript", "EditorIcons")
-func _register():
+func _register() -> void:
editors_manager.register_simple_editor(self)
self.alternative_text = "Customize dialogic and it's behaviour"
-func _ready():
+func _ready() -> void:
if get_parent() is SubViewport:
return
@@ -38,7 +38,7 @@ func _ready():
func register_settings_section(path:String) -> void:
- var section :Control = load(path).instantiate()
+ var section: Control = load(path).instantiate()
registered_sections.append(section)
@@ -71,7 +71,7 @@ func add_registered_sections() -> void:
if !section.short_info.is_empty():
- var tooltip_hint :Control = load("res://addons/dialogic/Editor/Common/hint_tooltip_icon.tscn").instantiate()
+ var tooltip_hint: Control = load("res://addons/dialogic/Editor/Common/hint_tooltip_icon.tscn").instantiate()
tooltip_hint.hint_text = section.short_info
hbox.add_child(tooltip_hint)
@@ -91,7 +91,7 @@ func add_registered_sections() -> void:
inner_vbox.add_child(panel)
- var info_section :Control = section._get_info_section()
+ var info_section: Control = section._get_info_section()
if info_section != null:
inner_vbox.add_child(Control.new())
inner_vbox.get_child(-1).custom_minimum_size.y = 50
@@ -156,13 +156,13 @@ func _open(extra_information:Variant = null) -> void:
open_tab(%SettingsContent.get_node(extra_information))
-func _close():
+func _close() -> void:
for child in %SettingsContent.get_children():
if child.get_meta('section').has_method('_about_to_close'):
child.get_meta('section')._about_to_close()
-func refresh():
+func refresh() -> void:
for child in %SettingsContent.get_children():
if child.get_meta('section').has_method('_refresh'):
child.get_meta('section')._refresh()
diff --git a/addons/dialogic/Editor/Settings/settings_general.gd b/addons/dialogic/Editor/Settings/settings_general.gd
index 172095862..07500c4e1 100644
--- a/addons/dialogic/Editor/Settings/settings_general.gd
+++ b/addons/dialogic/Editor/Settings/settings_general.gd
@@ -41,11 +41,11 @@ func _refresh() -> void:
%SectionList.create_item()
var cached_events := DialogicResourceUtil.get_event_cache()
var sections := []
- var section_order :Array = DialogicUtil.get_editor_setting('event_section_order', ['Main', 'Logic', 'Timeline', 'Audio', 'Godot','Other', 'Helper'])
+ var section_order: Array = DialogicUtil.get_editor_setting('event_section_order', ['Main', 'Logic', 'Flow', 'Audio', 'Visuals','Other', 'Helper'])
for ev in cached_events:
if !ev.event_category in sections:
sections.append(ev.event_category)
- var item :TreeItem = %SectionList.create_item(null)
+ var item: TreeItem = %SectionList.create_item(null)
item.set_text(0, ev.event_category)
item.add_button(0, get_theme_icon("ArrowUp", "EditorIcons"))
item.add_button(0, get_theme_icon("ArrowDown", "EditorIcons"))
@@ -86,10 +86,9 @@ func update_color_palette() -> void:
# Color Palette
for child in %Colors.get_children():
child.queue_free()
- var _scale := DialogicUtil.get_editor_scale()
for color in DialogicUtil.get_color_palette():
var button := ColorPickerButton.new()
- button.custom_minimum_size = Vector2(50 ,50)*scale
+ button.custom_minimum_size = Vector2(50 ,50) * DialogicUtil.get_editor_scale()
%Colors.add_child(button)
button.color = DialogicUtil.get_color(color)
button.color_changed.connect(_on_color_change)
@@ -141,13 +140,13 @@ func _on_submit_extension_button_pressed() -> void:
if %NameEdit.text.is_empty():
return
- var extensions_folder :String = ProjectSettings.get_setting('dialogic/extensions_folder', 'res://addons/dialogic_additions')
+ var extensions_folder: String = ProjectSettings.get_setting('dialogic/extensions_folder', 'res://addons/dialogic_additions')
extensions_folder = extensions_folder.path_join(%NameEdit.text.to_pascal_case())
DirAccess.make_dir_recursive_absolute(extensions_folder)
- var mode :int= %ExtensionMode.selected
+ var mode: int = %ExtensionMode.selected
- var file : FileAccess
+ var file: FileAccess
var indexer_content := "@tool\nextends DialogicIndexer\n\n"
if mode != 1: # don't add event in Subsystem Only mode
indexer_content += """func _get_events() -> Array:
diff --git a/addons/dialogic/Editor/Settings/settings_modules.gd b/addons/dialogic/Editor/Settings/settings_modules.gd
index a870a6923..008453e8c 100644
--- a/addons/dialogic/Editor/Settings/settings_modules.gd
+++ b/addons/dialogic/Editor/Settings/settings_modules.gd
@@ -37,6 +37,8 @@ func _refresh() -> void:
func _on_refresh_pressed() -> void:
+ DialogicUtil.get_indexers(true, true)
+ DialogicResourceUtil.update_event_cache()
load_modules_tree()
@@ -61,7 +63,7 @@ func _on_search_text_changed(new_text:String) -> void:
filter.text = ""
filter.set_meta("counter", 0)
- var hidden_events :Array= DialogicUtil.get_editor_setting('hidden_event_buttons', [])
+ var hidden_events: Array = DialogicUtil.get_editor_setting('hidden_event_buttons', [])
for child in %Tree.get_root().get_children():
if new_text.to_lower() in child.get_text(0).to_lower() or new_text.is_empty():
@@ -86,7 +88,7 @@ func _on_search_text_changed(new_text:String) -> void:
if sub_child.visible:
child.add_button(0, sub_child.get_icon(0), counter, false, sub_child.get_text(0))
if sub_child.get_metadata(0) and sub_child.get_metadata(0)['type'] == 'Event' and sub_child.get_metadata(0)['hidden']:
- var color : Color = sub_child.get_icon_modulate(0)
+ var color: Color = sub_child.get_icon_modulate(0)
color.a = 0.5
child.set_button_color(0, counter, color)
else:
@@ -99,26 +101,26 @@ func _on_search_text_changed(new_text:String) -> void:
func load_modules_tree() -> void:
%Tree.clear()
- var root :TreeItem = %Tree.create_item()
+ var root: TreeItem = %Tree.create_item()
var cached_events := DialogicResourceUtil.get_event_cache()
var hidden_events: Array = DialogicUtil.get_editor_setting('hidden_event_buttons', [])
var indexers := DialogicUtil.get_indexers()
for i in indexers:
- var module_item :TreeItem = %Tree.create_item(root)
+ var module_item: TreeItem = %Tree.create_item(root)
module_item.set_text(0, i.get_script().resource_path.trim_suffix('/index.gd').get_file())
module_item.set_metadata(0, {'type':'Module'})
# Events
for ev in i._get_events():
- if not FileAccess.file_exists(ev):
+ if not ResourceLoader.exists(ev):
continue
- var event_item : TreeItem = %Tree.create_item(module_item)
+ var event_item: TreeItem = %Tree.create_item(module_item)
event_item.set_icon(0, get_theme_icon("Favorites", "EditorIcons"))
for cached_event in cached_events:
if cached_event.get_script().resource_path == ev:
event_item.set_text(0, cached_event.event_name + " Event")
event_item.set_icon_modulate(0, cached_event.event_color)
- var hidden :bool = cached_event.event_name in hidden_events
+ var hidden: bool = cached_event.event_name in hidden_events
event_item.set_metadata(0, {'type':'Event', 'event':cached_event, 'hidden':hidden})
event_item.add_button(0, get_theme_icon("GuiVisibilityVisible", "EditorIcons"), 0, false, "Toggle Event Button Visibility")
if hidden:
@@ -128,7 +130,7 @@ func load_modules_tree() -> void:
# Subsystems
for subsys in i._get_subsystems():
- var subsys_item : TreeItem = %Tree.create_item(module_item)
+ var subsys_item: TreeItem = %Tree.create_item(module_item)
subsys_item.set_icon(0, get_theme_icon("Callable", "EditorIcons"))
subsys_item.set_text(0, subsys.name + " Subsystem")
subsys_item.set_icon_modulate(0, get_theme_color("readonly_color", "Editor"))
@@ -138,7 +140,7 @@ func load_modules_tree() -> void:
# Style scenes
for style in i._get_layout_parts():
- var style_item : TreeItem = %Tree.create_item(module_item)
+ var style_item: TreeItem = %Tree.create_item(module_item)
style_item.set_icon(0, get_theme_icon("PopupMenu", "EditorIcons"))
style_item.set_text(0, style.name)
style_item.set_icon_modulate(0, get_theme_color("property_color_x", "Editor"))
@@ -148,7 +150,7 @@ func load_modules_tree() -> void:
# Text Effects
for effect in i._get_text_effects():
- var effect_item : TreeItem = %Tree.create_item(module_item)
+ var effect_item: TreeItem = %Tree.create_item(module_item)
effect_item.set_icon(0, get_theme_icon("RichTextEffect", "EditorIcons"))
effect_item.set_text(0, "Text effect ["+effect.command+"]")
effect_item.set_icon_modulate(0, get_theme_color("property_color_z", "Editor"))
@@ -158,7 +160,7 @@ func load_modules_tree() -> void:
# Text Modifiers
for mod in i._get_text_modifiers():
- var mod_item : TreeItem = %Tree.create_item(module_item)
+ var mod_item: TreeItem = %Tree.create_item(module_item)
mod_item.set_icon(0, get_theme_icon("RichTextEffect", "EditorIcons"))
mod_item.set_text(0, mod.method.capitalize())
mod_item.set_icon_modulate(0, get_theme_color("property_color_z", "Editor"))
@@ -168,7 +170,7 @@ func load_modules_tree() -> void:
# Settings
for settings in i._get_settings_pages():
- var settings_item : TreeItem = %Tree.create_item(module_item)
+ var settings_item: TreeItem = %Tree.create_item(module_item)
settings_item.set_icon(0, get_theme_icon("PluginScript", "EditorIcons"))
settings_item.set_text(0, module_item.get_text(0) + " Settings")
settings_item.set_icon_modulate(0, get_theme_color("readonly_color", "Editor"))
@@ -178,7 +180,7 @@ func load_modules_tree() -> void:
# Editors
for editor in i._get_editors():
- var editor_item : TreeItem = %Tree.create_item(module_item)
+ var editor_item: TreeItem = %Tree.create_item(module_item)
editor_item.set_icon(0, get_theme_icon("ConfirmationDialog", "EditorIcons"))
editor_item.set_text(0, editor.get_file().trim_suffix('.tscn').capitalize())
editor_item.set_icon_modulate(0, get_theme_color("readonly_color", "Editor"))
@@ -200,7 +202,7 @@ func _on_tree_button_clicked(item:TreeItem, column:int, id:int, mouse_button_ind
'Event':
# Visibility item clicked
if id == 0:
- var meta :Dictionary= item.get_metadata(0)
+ var meta: Dictionary= item.get_metadata(0)
if meta['hidden']:
item.set_button(0, 0, get_theme_icon("GuiVisibilityVisible", "EditorIcons"))
item.get_parent().set_button_color(0, item.get_index(), item.get_icon_modulate(0))
@@ -208,7 +210,7 @@ func _on_tree_button_clicked(item:TreeItem, column:int, id:int, mouse_button_ind
%VisibilityToggle.button_pressed = true
else:
item.set_button(0, 0, get_theme_icon("GuiVisibilityHidden", "EditorIcons"))
- var color : Color = item.get_icon_modulate(0)
+ var color: Color = item.get_icon_modulate(0)
color.a = 0.5
item.get_parent().set_button_color(0, item.get_index(), color)
if item == %Tree.get_selected():
@@ -219,9 +221,9 @@ func _on_tree_button_clicked(item:TreeItem, column:int, id:int, mouse_button_ind
func _on_tree_item_selected() -> void:
- var selected_item :TreeItem = %Tree.get_selected()
+ var selected_item: TreeItem = %Tree.get_selected()
- var metadata :Variant = selected_item.get_metadata(0)
+ var metadata: Variant = selected_item.get_metadata(0)
%Title.text = selected_item.get_text(0)
%EventDefaultsPanel.hide()
@@ -272,14 +274,14 @@ func _on_tree_item_selected() -> void:
%GeneralInfo.text = ""
-func _on_external_link_pressed():
+func _on_external_link_pressed() -> void:
if %ExternalLink.has_meta('url'):
OS.shell_open(%ExternalLink.get_meta('url'))
func change_event_visibility(event:DialogicEvent, visibility:bool) -> void:
if event:
- var list :Array= DialogicUtil.get_editor_setting('hidden_event_buttons', [])
+ var list: Array= DialogicUtil.get_editor_setting('hidden_event_buttons', [])
if visibility:
list.erase(event.event_name)
else:
@@ -298,7 +300,7 @@ func _on_visibility_toggle_toggled(button_pressed:bool) -> void:
else:
%VisibilityToggle.icon = get_theme_icon("GuiVisibilityHidden", "EditorIcons")
%Tree.get_selected().set_button(0, 0, get_theme_icon("GuiVisibilityHidden", "EditorIcons"))
- var color : Color = %Tree.get_selected().get_icon_modulate(0)
+ var color: Color = %Tree.get_selected().get_icon_modulate(0)
color.a = 0.5
%Tree.get_selected().get_parent().set_button_color(0, %Tree.get_selected().get_index(), color)
@@ -314,21 +316,27 @@ func load_event_settings(event:DialogicEvent) -> void:
for child in %EventDefaults.get_children():
child.queue_free()
- var event_default_overrides :Dictionary = ProjectSettings.get_setting('dialogic/event_default_overrides', {})
+ var event_default_overrides: Dictionary = ProjectSettings.get_setting('dialogic/event_default_overrides', {})
var params := event.get_shortcode_parameters()
for prop in params:
+ var current_value: Variant = params[prop].default
+ if event_default_overrides.get(event.event_name, {}).has(params[prop].property):
+ current_value = event_default_overrides.get(event.event_name, {}).get(params[prop].property)
+
# Label
var label := Label.new()
label.text = prop.capitalize()
%EventDefaults.add_child(label)
- # Editing field
- var editor_node :Node = null
- var current_value :Variant = params[prop].default
- if event_default_overrides.get(event.event_name, {}).has(params[prop].property):
- current_value = event_default_overrides.get(event.event_name, {}).get(params[prop].property)
+ var reset := Button.new()
+ reset.icon = get_theme_icon("Clear", "EditorIcons")
+ reset.flat = true
+
+ %EventDefaults.add_child(reset)
+ # Editing field
+ var editor_node: Node = null
match typeof(event.get(params[prop].property)):
TYPE_STRING:
editor_node = LineEdit.new()
@@ -356,7 +364,7 @@ func load_event_settings(event:DialogicEvent) -> void:
editor_node.value_changed.connect(_on_event_default_number_changed.bind(params[prop].property))
TYPE_VECTOR2:
- editor_node = load("res://addons/dialogic/Editor/Events/Fields/Vector2.tscn").instantiate()
+ editor_node = load("res://addons/dialogic/Editor/Events/Fields/field_vector2.tscn").instantiate()
editor_node.set_value(current_value)
editor_node.property_name = params[prop].property
editor_node.value_changed.connect(_on_event_default_value_changed)
@@ -367,17 +375,23 @@ func load_event_settings(event:DialogicEvent) -> void:
editor_node.toggled.connect(_on_event_default_bool_toggled.bind(params[prop].property))
TYPE_ARRAY:
- editor_node = load("res://addons/dialogic/Editor/Events/Fields/Array.tscn").instantiate()
+ editor_node = load("res://addons/dialogic/Editor/Events/Fields/field_array.tscn").instantiate()
editor_node.set_value(current_value)
editor_node.property_name = params[prop].property
editor_node.value_changed.connect(_on_event_default_value_changed)
+ TYPE_DICTIONARY:
+ editor_node = load("res://addons/dialogic/Editor/Events/Fields/field_dictionary.tscn").instantiate()
+ editor_node.set_value(current_value)
+ editor_node.property_name = params[prop].property
+ editor_node.value_changed.connect(_on_event_default_value_changed)
%EventDefaults.add_child(editor_node)
+ reset.pressed.connect(reset_event_default_override.bind(prop, editor_node, params[prop].default))
func set_event_default_override(prop:String, value:Variant) -> void:
- var event_default_overrides :Dictionary = ProjectSettings.get_setting('dialogic/event_default_overrides', {})
- var event :DialogicEvent = %Tree.get_selected().get_metadata(0).event
+ var event_default_overrides: Dictionary = ProjectSettings.get_setting('dialogic/event_default_overrides', {})
+ var event: DialogicEvent = %Tree.get_selected().get_metadata(0).event
if not event_default_overrides.has(event.event_name):
event_default_overrides[event.event_name] = {}
@@ -387,6 +401,29 @@ func set_event_default_override(prop:String, value:Variant) -> void:
ProjectSettings.set_setting('dialogic/event_default_overrides', event_default_overrides)
+func reset_event_default_override(prop:String, node:Node, default:Variant) -> void:
+ var event_default_overrides: Dictionary = ProjectSettings.get_setting('dialogic/event_default_overrides', {})
+ var event: DialogicEvent = %Tree.get_selected().get_metadata(0).event
+
+ if not event_default_overrides.has(event.event_name):
+ return
+
+ event_default_overrides[event.event_name].erase(prop)
+
+ ProjectSettings.set_setting('dialogic/event_default_overrides', event_default_overrides)
+
+ if node is CheckBox:
+ node.button_pressed = default
+ elif node is LineEdit:
+ node.text = default
+ elif node.has_method('set_value'):
+ node.set_value(default)
+ elif node is ColorPickerButton:
+ node.color = default
+ elif node is OptionButton:
+ node.select(default)
+ elif node is SpinBox:
+ node.value = default
func _on_event_default_string_submitted(text:String, prop:String) -> void:
@@ -398,7 +435,7 @@ func _on_event_default_option_selected(index:int, option_button:OptionButton, pr
func _on_event_default_number_changed(value:float, prop:String) -> void:
set_event_default_override(prop, value)
-func _on_event_default_value_changed(prop:String, value:Vector2) -> void:
+func _on_event_default_value_changed(prop:String, value:Variant) -> void:
set_event_default_override(prop, value)
func _on_event_default_bool_toggled(value:bool, prop:String) -> void:
diff --git a/addons/dialogic/Editor/Settings/settings_modules.tscn b/addons/dialogic/Editor/Settings/settings_modules.tscn
index bd5bf0ae2..e43a96ae7 100644
--- a/addons/dialogic/Editor/Settings/settings_modules.tscn
+++ b/addons/dialogic/Editor/Settings/settings_modules.tscn
@@ -2,7 +2,7 @@
[ext_resource type="Script" path="res://addons/dialogic/Editor/Settings/settings_modules.gd" id="1_l2hk0"]
-[sub_resource type="Image" id="Image_pu0o6"]
+[sub_resource type="Image" id="Image_570p8"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -12,9 +12,9 @@ data = {
}
[sub_resource type="ImageTexture" id="ImageTexture_lce2m"]
-image = SubResource("Image_pu0o6")
+image = SubResource("Image_570p8")
-[sub_resource type="Image" id="Image_g84xy"]
+[sub_resource type="Image" id="Image_ihhvm"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 131, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 128, 128, 4, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 93, 93, 55, 255, 97, 97, 58, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 98, 98, 47, 255, 97, 97, 42, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 94, 94, 46, 255, 93, 93, 236, 255, 93, 93, 233, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 93, 93, 252, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -24,7 +24,7 @@ data = {
}
[sub_resource type="ImageTexture" id="ImageTexture_137g7"]
-image = SubResource("Image_g84xy")
+image = SubResource("Image_ihhvm")
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_315cl"]
content_margin_left = 4.0
@@ -213,7 +213,7 @@ text = "Edit event defaults:"
[node name="EventDefaults" type="GridContainer" parent="Scroll/Settings/EventDefaultsPanel/VBox"]
unique_name_in_owner = true
layout_mode = 2
-columns = 2
+columns = 3
[node name="GeneralInfo" type="Label" parent="Scroll/Settings"]
unique_name_in_owner = true
diff --git a/addons/dialogic/Editor/Settings/settings_translation.gd b/addons/dialogic/Editor/Settings/settings_translation.gd
index 5e40a6585..fe0714edd 100644
--- a/addons/dialogic/Editor/Settings/settings_translation.gd
+++ b/addons/dialogic/Editor/Settings/settings_translation.gd
@@ -8,7 +8,7 @@ enum TranslationModes {PER_PROJECT, PER_TIMELINE, NONE}
enum SaveLocationModes {INSIDE_TRANSLATION_FOLDER, NEXT_TO_TIMELINE, NONE}
var loading := false
-@onready var settings_editor :Control = find_parent('Settings')
+@onready var settings_editor: Control = find_parent('Settings')
## The default CSV filename that contains the translations for character
## properties.
@@ -185,7 +185,6 @@ func _handle_glossary_translation(
translation_mode: TranslationModes,
translation_folder_path: String,
orig_locale: String) -> void:
- var glossary_csv_path := ""
var glossary_csv: DialogicCsvFile = null
var glossary_paths: Array = ProjectSettings.get_setting('dialogic/glossary/glossary_files', [])
@@ -207,6 +206,7 @@ func _handle_glossary_translation(
var file_name := path_parts[-1]
csv_name = "dialogic_" + file_name + '_translation.csv'
+ var glossary_csv_path := ""
# Get glossary CSV file path.
match save_location_mode:
SaveLocationModes.INSIDE_TRANSLATION_FOLDER:
@@ -228,13 +228,10 @@ func _handle_glossary_translation(
glossary_csv.add_translation_keys_to_glossary(glossary)
ResourceSaver.save(glossary)
- match translation_mode:
- TranslationModes.PER_PROJECT:
- pass
-
- TranslationModes.PER_TIMELINE:
- glossary_csv.update_csv_file_on_disk()
- glossary_csv = null
+ #If per-file mode is used, save this csv and begin a new one
+ if translation_mode == TranslationModes.PER_TIMELINE:
+ glossary_csv.update_csv_file_on_disk()
+ glossary_csv = null
# If a Per-Project glossary is still open, we need to save it.
if glossary_csv != null:
@@ -380,7 +377,7 @@ func update_csv_files() -> void:
%StatusMessage.text = status_message.format(status_message_args)
ProjectSettings.set_setting(_USED_LOCALES_SETTING, _unique_locales)
- get_locales("")
+
## Iterates over all character resource files and creates or updates CSV files
## that contain the translations for character properties.
@@ -452,7 +449,7 @@ func collect_translations() -> void:
for file_path: String in translation_files:
# If the file path is not valid, we must clean it up.
- if FileAccess.file_exists(file_path):
+ if ResourceLoader.exists(file_path):
found_file_paths.append(file_path)
else:
removed_translation_files += 1
@@ -460,10 +457,10 @@ func collect_translations() -> void:
if not file_path in all_translation_files:
all_translation_files.append(file_path)
- var path_without_suffix := file_path.trim_suffix('.translation')
- var path_parts := path_without_suffix.split(".")
- var locale_part := path_parts[-1]
- _collect_locale(locale_part)
+
+ var path_without_suffix := file_path.trim_suffix('.translation')
+ var locale_part := path_without_suffix.split(".")[-1]
+ _collect_locale(locale_part)
var valid_translation_files := PackedStringArray(all_translation_files)
@@ -517,7 +514,6 @@ func erase_translations() -> void:
var files: PackedStringArray = ProjectSettings.get_setting('internationalization/locale/translations', [])
var translation_files := Array(files)
ProjectSettings.set_setting(_USED_LOCALES_SETTING, [])
- get_locales("")
var deleted_csv_files := 0
var deleted_translation_files := 0
@@ -661,4 +657,4 @@ func _collect_locale(locale: String) -> void:
if _unique_locales.has(locale):
return
- _unique_locales.append(locale)
\ No newline at end of file
+ _unique_locales.append(locale)
diff --git a/addons/dialogic/Editor/TimelineEditor/TextEditor/CodeCompletionHelper.gd b/addons/dialogic/Editor/TimelineEditor/TextEditor/CodeCompletionHelper.gd
index 7d3b92a2d..8a12cd5e3 100644
--- a/addons/dialogic/Editor/TimelineEditor/TextEditor/CodeCompletionHelper.gd
+++ b/addons/dialogic/Editor/TimelineEditor/TextEditor/CodeCompletionHelper.gd
@@ -15,17 +15,20 @@ var completion_word_regex := RegEx.new()
var completion_shortcode_getter_regex := RegEx.new()
# To find the parameter name of the current if typing a value
var completion_shortcode_param_getter_regex := RegEx.new()
+# To find the value of a paramater that is being typed
+var completion_shortcode_value_regex := RegEx.new()
# Stores references to all shortcode events for parameter and value suggestions
var shortcode_events := {}
var custom_syntax_events := []
-var text_event :DialogicTextEvent = null
+var text_event: DialogicTextEvent = null
-func _ready():
+func _ready() -> void:
# Compile RegEx's
completion_word_regex.compile("(?(\\W)|^)(?\\w*)\\x{FFFF}")
completion_shortcode_getter_regex.compile("\\[(?\\w*)")
completion_shortcode_param_getter_regex.compile("(?\\w*)\\W*=\\s*\"?(\\w|\\s)*"+String.chr(0xFFFF))
+ completion_shortcode_value_regex.compile(r'(\[|\s)[^\[\s=]*="(?[^"$]*)'+String.chr(0xFFFF))
text_syntax_highlighter.mode = text_syntax_highlighter.Modes.TEXT_EVENT_ONLY
@@ -42,6 +45,11 @@ func get_code_completion_word(text:CodeEdit) -> String:
var result := completion_word_regex.search(get_code_completion_line(text))
return result.get_string('word') if result else ""
+# Helper that gets the currently typed parameter
+func get_code_completion_parameter_value(text:CodeEdit) -> String:
+ var result := completion_shortcode_value_regex.search(get_code_completion_line(text))
+ return result.get_string('value') if result else ""
+
# Helper that gets the symbol before the current word
func get_code_completion_prev_symbol(text:CodeEdit) -> String:
@@ -98,8 +106,8 @@ func request_code_completion(force:bool, text:CodeEdit, mode:=Modes.FULL_HIGHLIG
# word in option
## Note on VALUE key
- # The value key is used to store a potential closing letter for the completion.
- # The completion will check if the letter is already present and add it otherwise.
+ # The value key is used to store a potential closing string for the completion.
+ # The completion will check if the string is already present and add it otherwise.
# Shortcode event suggestions
if mode == Modes.FULL_HIGHLIGHTING and syntax_highlighter.line_is_shortcode_event(text.get_caret_line()):
@@ -134,7 +142,7 @@ func request_code_completion(force:bool, text:CodeEdit, mode:=Modes.FULL_HIGHLIG
text.add_code_completion_option(CodeEdit.KIND_MEMBER, param, param+'="' , shortcode_events[code].event_color.lerp(syntax_highlighter.normal_color, 0.3), text.get_theme_icon("MemberProperty", "EditorIcons"))
# suggest values
- elif symbol == '=' or symbol == '"' or get_code_completion_prev_symbol(text) == '"':
+ elif symbol == '=' or symbol == '"':
var current_parameter_gex := completion_shortcode_param_getter_regex.search(line)
if !current_parameter_gex:
text.update_code_completion_options(false)
@@ -148,17 +156,12 @@ func request_code_completion(force:bool, text:CodeEdit, mode:=Modes.FULL_HIGHLIG
if typeof(shortcode_events[code].get_shortcode_parameters()[current_parameter].default) == TYPE_BOOL:
suggest_bool(text, shortcode_events[code].event_color.lerp(syntax_highlighter.normal_color, 0.3))
elif len(word) > 0:
- text.add_code_completion_option(CodeEdit.KIND_MEMBER, word, word, shortcode_events[code].event_color.lerp(syntax_highlighter.normal_color, 0.3), text.get_theme_icon("GuiScrollArrowRight", "EditorIcons"), '" ')
+ text.add_code_completion_option(CodeEdit.KIND_VARIABLE, word, word, shortcode_events[code].event_color.lerp(syntax_highlighter.normal_color, 0.3), text.get_theme_icon("GuiScrollArrowRight", "EditorIcons"), '" ')
text.update_code_completion_options(true)
return
- var suggestions: Dictionary= shortcode_events[code].get_shortcode_parameters()[current_parameter]['suggestions'].call()
- for key in suggestions.keys():
- if suggestions[key].has('text_alt'):
- text.add_code_completion_option(CodeEdit.KIND_MEMBER, key, suggestions[key].text_alt[0], shortcode_events[code].event_color.lerp(syntax_highlighter.normal_color, 0.3), suggestions[key].get('icon', null), '" ')
- else:
- text.add_code_completion_option(CodeEdit.KIND_MEMBER, key, str(suggestions[key].value), shortcode_events[code].event_color.lerp(syntax_highlighter.normal_color, 0.3), suggestions[key].get('icon', null), '" ')
-
+ var suggestions: Dictionary = shortcode_events[code].get_shortcode_parameters()[current_parameter]['suggestions'].call()
+ suggest_custom_suggestions(suggestions, text, shortcode_events[code].event_color.lerp(syntax_highlighter.normal_color, 0.3))
# Force update and showing of the popup
text.update_code_completion_options(true)
@@ -184,7 +187,7 @@ func request_code_completion(force:bool, text:CodeEdit, mode:=Modes.FULL_HIGHLIG
# Helper that adds all characters as options
func suggest_characters(text:CodeEdit, type := CodeEdit.KIND_MEMBER, text_event_start:=false) -> void:
for character in DialogicResourceUtil.get_character_directory():
- var result :String = character
+ var result: String = character
if " " in character:
result = '"'+character+'"'
if text_event_start and load(DialogicResourceUtil.get_character_directory()[character]).portraits.is_empty():
@@ -223,8 +226,16 @@ func suggest_variables(text:CodeEdit):
# Helper that adds true and false as options
func suggest_bool(text:CodeEdit, color:Color):
- text.add_code_completion_option(CodeEdit.KIND_MEMBER, 'true', 'true', color, text.get_theme_icon("GuiChecked", "EditorIcons"), '" ')
- text.add_code_completion_option(CodeEdit.KIND_MEMBER, 'false', 'false', color, text.get_theme_icon("GuiUnchecked", "EditorIcons"), '" ')
+ text.add_code_completion_option(CodeEdit.KIND_VARIABLE, 'true', 'true', color, text.get_theme_icon("GuiChecked", "EditorIcons"), '" ')
+ text.add_code_completion_option(CodeEdit.KIND_VARIABLE, 'false', 'false', color, text.get_theme_icon("GuiUnchecked", "EditorIcons"), '" ')
+
+
+func suggest_custom_suggestions(suggestions:Dictionary, text:CodeEdit, color:Color) -> void:
+ for key in suggestions.keys():
+ if suggestions[key].has('text_alt'):
+ text.add_code_completion_option(CodeEdit.KIND_VARIABLE, key, suggestions[key].text_alt[0], color, suggestions[key].get('icon', null), '" ')
+ else:
+ text.add_code_completion_option(CodeEdit.KIND_VARIABLE, key, str(suggestions[key].value), color, suggestions[key].get('icon', null), '" ')
# Filters the list of all possible options, depending on what was typed
@@ -239,6 +250,10 @@ func filter_code_completion_candidates(candidates:Array, text:CodeEdit) -> Array
elif candidate.kind == text.KIND_MEMBER:
if current_word.is_empty() or current_word.to_lower() in candidate.insert_text.to_lower():
valid_candidates.append(candidate)
+ elif candidate.kind == text.KIND_VARIABLE:
+ var current_param_value := get_code_completion_parameter_value(text)
+ if current_param_value.is_empty() or current_param_value.to_lower() in candidate.insert_text.to_lower():
+ valid_candidates.append(candidate)
elif candidate.kind == text.KIND_CONSTANT:
if current_word.is_empty() or candidate.insert_text.begins_with(current_word):
valid_candidates.append(candidate)
@@ -252,17 +267,32 @@ func filter_code_completion_candidates(candidates:Array, text:CodeEdit) -> Array
# Inserts the selected item
func confirm_code_completion(replace:bool, text:CodeEdit) -> void:
# Note: I decided to ALWAYS use replace mode, as dialogic is supposed to be beginner friendly
- var word := get_code_completion_word(text)
+
var code_completion := text.get_code_completion_option(text.get_code_completion_selected_index())
+
+ var word := get_code_completion_word(text)
+ if code_completion.kind == CodeEdit.KIND_VARIABLE:
+ word = get_code_completion_parameter_value(text)
+
text.remove_text(text.get_caret_line(), text.get_caret_column()-len(word), text.get_caret_line(), text.get_caret_column())
- text.set_caret_column(text.get_caret_column()-len(word))
- text.insert_text_at_caret(code_completion.insert_text)#
+
+ # Something has changed between 4.2 and 4.3
+ # Probably about how carets are reset when text is removed or idk.
+ # To keep compatibility with 4.2 for at least a while this should do the trick:
+ # TODO: Remove once compatibility for 4.2 is dropped.
+ if Engine.get_version_info().hex >= 0x040300:
+ text.set_caret_column(text.get_caret_column())
+ else:
+ text.set_caret_column(text.get_caret_column()-len(word))
+
+ text.insert_text_at_caret(code_completion.insert_text)
+
if code_completion.has('default_value') and typeof(code_completion['default_value']) == TYPE_STRING:
- var next_letter := text.get_line(text.get_caret_line()).substr(text.get_caret_column(), 1)
- if next_letter != code_completion['default_value']:
- text.insert_text_at_caret(code_completion['default_value'])
- else:
+ var next_letter := text.get_line(text.get_caret_line()).substr(text.get_caret_column(), len(code_completion['default_value']))
+ if next_letter == code_completion['default_value'] or next_letter[0] == code_completion['default_value'][0]:
text.set_caret_column(text.get_caret_column()+1)
+ else:
+ text.insert_text_at_caret(code_completion['default_value'])
#endregion
diff --git a/addons/dialogic/Editor/TimelineEditor/TextEditor/syntax_highlighter.gd b/addons/dialogic/Editor/TimelineEditor/TextEditor/syntax_highlighter.gd
index 56f6b83bd..400dbe236 100644
--- a/addons/dialogic/Editor/TimelineEditor/TextEditor/syntax_highlighter.gd
+++ b/addons/dialogic/Editor/TimelineEditor/TextEditor/syntax_highlighter.gd
@@ -10,39 +10,44 @@ var mode := Modes.FULL_HIGHLIGHTING
## RegEx's
var word_regex := RegEx.new()
var region_regex := RegEx.new()
-var number_regex := RegEx.create_from_string("(\\d|\\.)+")
-var shortcode_regex := RegEx.create_from_string("\\W*\\[(?\\w*)(?[^\\]]*)?")
-var shortcode_param_regex := RegEx.create_from_string('((?[^\\s=]*)\\s*=\\s*"(?([^=]|\\\\=)*)(?\w*)(?[^\]]*)?")
+var shortcode_param_regex := RegEx.create_from_string(r'((?[^\s=]*)\s*=\s*"(?([^=]|\\=)*)(? void:
+ update_colors()
+ DialogicUtil.get_dialogic_plugin().get_editor_interface().get_base_control().theme_changed.connect(update_colors)
- code_flow_color = editor_settings.get("text_editor/theme/highlighting/control_flow_keyword_color")
- boolean_operator_color = code_flow_color.lightened(0.5)
- variable_color = editor_settings.get('text_editor/theme/highlighting/engine_type_color')
- string_color = editor_settings.get('text_editor/theme/highlighting/string_color')
- character_name_color = editor_settings.get('text_editor/theme/highlighting/symbol_color').lerp(normal_color, 0.3)
- character_portrait_color = character_name_color.lerp(normal_color, 0.5)
+
+func update_colors() -> void:
+ if not DialogicUtil.get_dialogic_plugin():
+ return
+ var editor_settings: EditorSettings = DialogicUtil.get_dialogic_plugin().get_editor_interface().get_editor_settings()
+ normal_color = editor_settings.get('text_editor/theme/highlighting/text_color')
+ translation_id_color = editor_settings.get('text_editor/theme/highlighting/comment_color')
+
+ code_flow_color = editor_settings.get("text_editor/theme/highlighting/control_flow_keyword_color")
+ boolean_operator_color = code_flow_color.lightened(0.5)
+ variable_color = editor_settings.get('text_editor/theme/highlighting/engine_type_color')
+ string_color = editor_settings.get('text_editor/theme/highlighting/string_color')
+ character_name_color = editor_settings.get('text_editor/theme/highlighting/symbol_color').lerp(normal_color, 0.3)
+ character_portrait_color = character_name_color.lerp(normal_color, 0.5)
func _get_line_syntax_highlighting(line:int) -> Dictionary:
@@ -176,7 +181,7 @@ func color_region(dict:Dictionary, color:Color, line:String, start:String, end:S
if end.is_empty():
region_regex.compile("(?[^\n]+)')
-func _ready():
+func _ready() -> void:
await find_parent('EditorView').ready
syntax_highlighter = code_completion_helper.syntax_highlighter
timeline_editor.editors_manager.sidebar.content_item_activated.connect(_on_content_item_clicked)
-func _on_text_editor_text_changed():
+
+func _on_text_editor_text_changed() -> void:
timeline_editor.current_resource_state = DialogicEditor.ResourceStates.UNSAVED
request_code_completion(true)
$UpdateTimer.start()
-func clear_timeline():
+func clear_timeline() -> void:
text = ''
update_content_list()
@@ -36,11 +37,11 @@ func load_timeline(timeline:DialogicTimeline) -> void:
update_content_list()
-func save_timeline():
+func save_timeline() -> void:
if !timeline_editor.current_resource:
return
- var text_array:Array = text_timeline_to_array(text)
+ var text_array: Array = text_timeline_to_array(text)
timeline_editor.current_resource.events = text_array
timeline_editor.current_resource.events_processed = false
@@ -60,8 +61,8 @@ func text_timeline_to_array(text:String) -> Array:
while idx < len(lines)-1:
idx += 1
- var line :String = lines[idx]
- var line_stripped :String = line.strip_edges(true, true)
+ var line: String = lines[idx]
+ var line_stripped: String = line.strip_edges(true, true)
events.append(line)
return events
@@ -90,6 +91,9 @@ func _gui_input(event):
# Toggle the selected lines as comments
func toggle_comment() -> void:
var cursor: Vector2 = Vector2(get_caret_column(), get_caret_line())
+ var selection := Rect2i(
+ Vector2i(get_selection_origin_line(), get_selection_origin_column()),
+ Vector2i(get_caret_line(), get_caret_column()))
var from: int = cursor.y
var to: int = cursor.y
if has_selection():
@@ -97,14 +101,27 @@ func toggle_comment() -> void:
to = get_selection_to_line()
var lines: PackedStringArray = text.split("\n")
- var will_comment: bool = not lines[from].begins_with("# ")
+ var will_comment: bool = false
+ for i in range(from, to+1):
+ if not lines[i].begins_with("#"):
+ will_comment = true
+
for i in range(from, to + 1):
- lines[i] = "# " + lines[i] if will_comment else lines[i].substr(2)
+ if will_comment:
+ lines[i] = "#" + lines[i]
+ else:
+ lines[i] = lines[i].trim_prefix("#")
text = "\n".join(lines)
- select(from, 0, to, get_line_width(to))
- set_caret_line(cursor.y)
- set_caret_column(cursor.x)
+ if will_comment:
+ cursor.x += 1
+ selection.position.y += 1
+ selection.size.y += 1
+ else:
+ cursor.x -= 1
+ selection.position.y -= 1
+ selection.size.y -= 1
+ select(selection.position.x, selection.position.y, selection.size.x, selection.size.y)
text_changed.emit()
@@ -182,12 +199,12 @@ func _drop_data(at_position:Vector2, data:Variant) -> void:
insert_text_at_caret(result)
-func _on_update_timer_timeout():
+func _on_update_timer_timeout() -> void:
update_content_list()
-func update_content_list():
- var labels :PackedStringArray = []
+func update_content_list() -> void:
+ var labels: PackedStringArray = []
for i in label_regex.search_all(text):
labels.append(i.get_string('name'))
timeline_editor.editors_manager.sidebar.update_content_list(labels)
@@ -208,6 +225,52 @@ func _on_content_item_clicked(label:String) -> void:
return
+func _search_timeline(search_text:String) -> bool:
+ set_search_text(search_text)
+ queue_redraw()
+ set_meta("current_search", search_text)
+
+ return search(search_text, 0, 0, 0).y != -1
+
+
+func _search_navigate_down() -> void:
+ search_navigate(false)
+
+
+func _search_navigate_up() -> void:
+ search_navigate(true)
+
+
+func search_navigate(navigate_up := false) -> void:
+ if not has_meta("current_search"):
+ return
+ var pos: Vector2i
+ var search_from_line := 0
+ var search_from_column := 0
+ if has_selection():
+ if navigate_up:
+ search_from_line = get_selection_from_line()
+ search_from_column = get_selection_from_column()-1
+ if search_from_column == -1:
+ if search_from_line == 0:
+ search_from_line = get_line_count()
+ else:
+ search_from_line -= 1
+ search_from_column = max(get_line(search_from_line).length()-1,0)
+ else:
+ search_from_line = get_selection_to_line()
+ search_from_column = get_selection_to_column()
+ else:
+ search_from_line = get_caret_line()
+ search_from_column = get_caret_column()
+
+ pos = search(get_meta("current_search"), 4 if navigate_up else 0, search_from_line, search_from_column)
+ select(pos.y, pos.x, pos.y, pos.x+len(get_meta("current_search")))
+ set_caret_line(pos.y)
+ center_viewport_to_caret()
+ queue_redraw()
+
+
################################################################################
## AUTO COMPLETION
################################################################################
diff --git a/addons/dialogic/Editor/TimelineEditor/VisualEditor/AddEventButton.gd b/addons/dialogic/Editor/TimelineEditor/VisualEditor/AddEventButton.gd
index db48ec1d0..7318bd4e4 100644
--- a/addons/dialogic/Editor/TimelineEditor/VisualEditor/AddEventButton.gd
+++ b/addons/dialogic/Editor/TimelineEditor/VisualEditor/AddEventButton.gd
@@ -1,36 +1,35 @@
@tool
extends Button
-@export var visible_name:String = ""
-@export var event_id:String = ''
-@export var event_icon:Texture :
+@export var visible_name := ""
+@export var event_id := ""
+@export var event_icon: Texture:
get:
return event_icon
set(texture):
event_icon = texture
icon = event_icon
-@export var event_sorting_index:int = 0
-@export var resource:DialogicEvent
-@export var dialogic_color_name:String = ''
+@export var event_sorting_index: int = 0
+@export var resource: DialogicEvent
+@export var dialogic_color_name := ""
func _ready() -> void:
tooltip_text = visible_name
-
- custom_minimum_size = Vector2(get_theme_font("font", 'Label').get_string_size(text).x+35,30)* DialogicUtil.get_editor_scale()
-
+
+ custom_minimum_size = Vector2(get_theme_font("font", "Label").get_string_size(text).x+35,30) * DialogicUtil.get_editor_scale()
+
add_theme_color_override("font_color", get_theme_color("font_color", "Editor"))
add_theme_color_override("font_color_hover", get_theme_color("accent_color", "Editor"))
apply_base_button_style()
func apply_base_button_style() -> void:
- var scale := DialogicUtil.get_editor_scale()
- var nstyle :StyleBoxFlat= get_parent().get_theme_stylebox('normal', 'Button').duplicate()
- nstyle.border_width_left = 5 *scale
+ var nstyle: StyleBoxFlat = get_parent().get_theme_stylebox('normal', 'Button').duplicate()
+ nstyle.border_width_left = 5 * DialogicUtil.get_editor_scale()
add_theme_stylebox_override('normal', nstyle)
- var hstyle :StyleBoxFlat= get_parent().get_theme_stylebox('hover', 'Button').duplicate()
- hstyle.border_width_left = 5 *scale
+ var hstyle: StyleBoxFlat = get_parent().get_theme_stylebox('hover', 'Button').duplicate()
+ hstyle.border_width_left = 5 * DialogicUtil.get_editor_scale()
add_theme_stylebox_override('hover', hstyle)
set_color(resource.event_color)
@@ -47,7 +46,7 @@ func set_color(color:Color) -> void:
func toggle_name(on:= false) -> void:
if !on:
text = ""
- custom_minimum_size = Vector2(40, 40)*DialogicUtil.get_editor_scale()
+ custom_minimum_size = Vector2(40, 40) * DialogicUtil.get_editor_scale()
var style := get_theme_stylebox('normal', 'Button')
style.bg_color = style.border_color.darkened(0.2)
add_theme_stylebox_override('normal', style)
@@ -56,9 +55,9 @@ func toggle_name(on:= false) -> void:
add_theme_stylebox_override('hover', style)
else:
text = visible_name
- custom_minimum_size = Vector2(get_theme_font("font", 'Label').get_string_size(text).x+35,30)* DialogicUtil.get_editor_scale()
+ custom_minimum_size = Vector2(get_theme_font("font", 'Label').get_string_size(text).x+35,30) * DialogicUtil.get_editor_scale()
apply_base_button_style()
-func _on_button_down():
+func _on_button_down() -> void:
find_parent('VisualEditor').get_node('%TimelineArea').start_dragging(1, resource)
diff --git a/addons/dialogic/Editor/TimelineEditor/VisualEditor/TimelineArea.gd b/addons/dialogic/Editor/TimelineEditor/VisualEditor/TimelineArea.gd
index d6041907e..0baa46b57 100644
--- a/addons/dialogic/Editor/TimelineEditor/VisualEditor/TimelineArea.gd
+++ b/addons/dialogic/Editor/TimelineEditor/VisualEditor/TimelineArea.gd
@@ -7,8 +7,8 @@ extends ScrollContainer
enum DragTypes {NOTHING, NEW_EVENT, EXISTING_EVENTS}
-var drag_type : DragTypes = DragTypes.NOTHING
-var drag_data : Variant
+var drag_type: DragTypes = DragTypes.NOTHING
+var drag_data: Variant
var drag_to_position := 0
var dragging := false
@@ -59,7 +59,7 @@ func _process(delta:float) -> void:
queue_redraw()
-func finish_dragging():
+func finish_dragging() -> void:
dragging = false
if get_global_rect().has_point(get_global_mouse_position()):
drag_completed.emit(drag_type, drag_to_position, drag_data)
@@ -74,16 +74,15 @@ func finish_dragging():
################################################################################
func _draw() -> void:
- var _scale := DialogicUtil.get_editor_scale()
- var line_width := 5 * _scale
- var horizontal_line_length := 100*_scale
+ var line_width := 5 * DialogicUtil.get_editor_scale()
+ var horizontal_line_length := 100 * DialogicUtil.get_editor_scale()
var color_multiplier := Color(1,1,1,0.25)
var selected_color_multiplier := Color(1,1,1,1)
## Draw Event Lines
for idx in range($Timeline.get_child_count()):
- var block : Control = $Timeline.get_child(idx)
+ var block: Control = $Timeline.get_child(idx)
if not "resource" in block:
continue
diff --git a/addons/dialogic/Editor/TimelineEditor/VisualEditor/timeline_editor_visual.gd b/addons/dialogic/Editor/TimelineEditor/VisualEditor/timeline_editor_visual.gd
index fbc5e8c36..bd350cbe1 100644
--- a/addons/dialogic/Editor/TimelineEditor/VisualEditor/timeline_editor_visual.gd
+++ b/addons/dialogic/Editor/TimelineEditor/VisualEditor/timeline_editor_visual.gd
@@ -23,17 +23,18 @@ signal timeline_loaded
var _batches := []
var _building_timeline := false
var _timeline_changed_while_loading := false
-
+var _initialized := false
################## TIMELINE EVENT MANAGEMENT ###################################
################################################################################
-var selected_items : Array = []
+var selected_items: Array = []
+var drag_allowed := false
#region CREATE/SAVE/LOAD
################################################################################
-func something_changed():
+func something_changed() -> void:
timeline_editor.current_resource_state = DialogicEditor.ResourceStates.UNSAVED
@@ -58,7 +59,8 @@ func save_timeline() -> void:
timeline_editor.current_resource.events = new_events
timeline_editor.current_resource.events_processed = true
- var error :int = ResourceSaver.save(timeline_editor.current_resource, timeline_editor.current_resource.resource_path)
+ var error: int = ResourceSaver.save(timeline_editor.current_resource, timeline_editor.current_resource.resource_path)
+
if error != OK:
print('[Dialogic] Saving error: ', error)
@@ -102,7 +104,7 @@ func load_timeline(resource:DialogicTimeline) -> void:
%TimelineArea.scroll_vertical = 0
-func batch_events(array, size, batch_number):
+func batch_events(array: Array, size: int, batch_number: int) -> Array:
return array.slice((batch_number - 1) * size, batch_number * size)
@@ -110,7 +112,7 @@ func batch_events(array, size, batch_number):
var opener_events_stack := []
func load_batch(data:Array) -> void:
- var current_batch :Array = _batches.pop_front()
+ var current_batch: Array = _batches.pop_front()
if current_batch:
for i in current_batch:
if i is DialogicEndBranchEvent:
@@ -121,7 +123,8 @@ func load_batch(data:Array) -> void:
opener_events_stack.push_back(piece)
batch_loaded.emit()
-func _on_batch_loaded():
+
+func _on_batch_loaded() -> void:
if _timeline_changed_while_loading:
return
if _batches.size() > 0:
@@ -131,15 +134,17 @@ func _on_batch_loaded():
return
if opener_events_stack:
+
for ev in opener_events_stack:
create_end_branch_event(%Timeline.get_child_count(), ev)
+
opener_events_stack = []
indent_events()
update_content_list()
_building_timeline = false
-func clear_timeline_nodes():
+func clear_timeline_nodes() -> void:
deselect_all_items()
for event in %Timeline.get_children():
event.free()
@@ -149,8 +154,7 @@ func clear_timeline_nodes():
#region SETUP
################################################################################
-func _ready():
- DialogicUtil.get_dialogic_plugin().dialogic_save.connect(save_timeline)
+func _ready() -> void:
event_node = load("res://addons/dialogic/Editor/Events/EventBlock/event_block.tscn")
batch_loaded.connect(_on_batch_loaded)
@@ -159,25 +163,39 @@ func _ready():
timeline_editor.editors_manager.sidebar.content_item_activated.connect(_on_content_item_clicked)
%Timeline.child_order_changed.connect(update_content_list)
+ var editor_scale := DialogicUtil.get_editor_scale()
+ %RightSidebar.size.x = DialogicUtil.get_editor_setting("dialogic/editor/right_sidebar_width", 200 * editor_scale)
+ $View.split_offset = -DialogicUtil.get_editor_setting("dialogic/editor/right_sidebar_width", 200 * editor_scale)
+ sidebar_collapsed = DialogicUtil.get_editor_setting("dialogic/editor/right_sidebar_collapsed", false)
+
+ load_event_buttons()
+ _on_right_sidebar_resized()
+ _initialized = true
+
func load_event_buttons() -> void:
+ sidebar_collapsed = DialogicUtil.get_editor_setting("dialogic/editor/right_sidebar_collapsed", false)
+
# Clear previous event buttons
for child in %RightSidebar.get_child(0).get_children():
+
if child is FlowContainer:
+
for button in child.get_children():
button.queue_free()
- var scripts := DialogicResourceUtil.get_event_cache()
+
+ for child in %RightSidebar.get_child(0).get_children():
+ child.get_parent().remove_child(child)
+ child.queue_free()
# Event buttons
- var buttonScene := load("res://addons/dialogic/Editor/TimelineEditor/VisualEditor/AddEventButton.tscn")
+ var button_scene := load("res://addons/dialogic/Editor/TimelineEditor/VisualEditor/AddEventButton.tscn")
+ var scripts := DialogicResourceUtil.get_event_cache()
var hidden_buttons :Array = DialogicUtil.get_editor_setting('hidden_event_buttons', [])
var sections := {}
- for child in %RightSidebar.get_child(0).get_children():
- child.queue_free()
-
for event_script in scripts:
var event_resource: Variant
@@ -192,7 +210,7 @@ func load_event_buttons() -> void:
if event_resource.event_name in hidden_buttons:
continue
- var button :Button = buttonScene.instantiate()
+ var button: Button = button_scene.instantiate()
button.resource = event_resource
button.visible_name = event_resource.event_name
button.event_icon = event_resource._get_icon()
@@ -219,28 +237,27 @@ func load_event_buttons() -> void:
section.add_child(button_container)
sections[event_resource.event_category] = button_container
- %RightSidebar.get_child(0).add_child(section)
-
+ %RightSidebar.get_child(0).add_child(section, true)
sections[event_resource.event_category].add_child(button)
+ button.toggle_name(!sidebar_collapsed)
# Sort event button
while event_resource.event_sorting_index < sections[event_resource.event_category].get_child(max(0, button.get_index()-1)).resource.event_sorting_index:
sections[event_resource.event_category].move_child(button, button.get_index()-1)
- var sections_order :Array= DialogicUtil.get_editor_setting('event_section_order',
- ['Main', 'Flow', 'Logic', 'Audio', 'Godot','Other', 'Helper'])
-
# Sort event sections
- for section in sections_order:
- if %RightSidebar.get_child(0).has_node(section):
- %RightSidebar.get_child(0).move_child(%RightSidebar.get_child(0).get_node(section), sections_order.find(section))
+ var sections_order: Array = DialogicUtil.get_editor_setting('event_section_order',
+ ['Main', 'Flow', 'Logic', 'Audio', 'Visual','Other', 'Helper'])
+
+ sections_order.reverse()
+ for section_name in sections_order:
+ if %RightSidebar.get_child(0).has_node(section_name):
+ %RightSidebar.get_child(0).move_child(%RightSidebar.get_child(0).get_node(section_name), 0)
# Resize RightSidebar
- var _scale := DialogicUtil.get_editor_scale()
- %RightSidebar.custom_minimum_size.x = 50 * _scale
+ %RightSidebar.custom_minimum_size.x = 50 * DialogicUtil.get_editor_scale()
- $View.split_offset = -200*_scale
_on_right_sidebar_resized()
#endregion
@@ -260,12 +277,20 @@ func _on_content_item_clicked(label:String) -> void:
return
-func update_content_list():
- var labels :PackedStringArray = []
+func update_content_list() -> void:
+ if not is_inside_tree():
+ return
+
+ var labels: PackedStringArray = []
+
for event in %Timeline.get_children():
+
if 'event_name' in event.resource and event.resource is DialogicLabelEvent:
labels.append(event.resource.name)
+
timeline_editor.editors_manager.sidebar.update_content_list(labels)
+
+
#endregion
@@ -273,7 +298,7 @@ func update_content_list():
#################################################################################
# SIGNAL handles input on the events mainly for selection and moving events
-func _on_event_block_gui_input(event, item: Node):
+func _on_event_block_gui_input(event: InputEvent, item: Node) -> void:
if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT:
if event.is_pressed():
if len(selected_items) > 1 and item in selected_items and !Input.is_key_pressed(KEY_CTRL):
@@ -283,9 +308,11 @@ func _on_event_block_gui_input(event, item: Node):
elif len(selected_items) > 1 or Input.is_key_pressed(KEY_CTRL):
select_item(item)
+ drag_allowed = true
+
if len(selected_items) > 0 and event is InputEventMouseMotion:
if Input.is_mouse_button_pressed(MOUSE_BUTTON_LEFT):
- if !%TimelineArea.dragging and !get_viewport().gui_is_dragging():
+ if !%TimelineArea.dragging and !get_viewport().gui_is_dragging() and drag_allowed:
sort_selection()
%TimelineArea.start_dragging(%TimelineArea.DragTypes.EXISTING_EVENTS, selected_items)
@@ -293,7 +320,7 @@ func _on_event_block_gui_input(event, item: Node):
## Activated by TimelineArea drag_completed
func _on_timeline_area_drag_completed(type:int, index:int, data:Variant) -> void:
if type == %TimelineArea.DragTypes.NEW_EVENT:
- var resource :DialogicEvent = data.duplicate()
+ var resource: DialogicEvent = data.duplicate()
resource._load_custom_defaults()
add_event_undoable(resource, index)
@@ -322,7 +349,7 @@ func add_event_node(event_resource:DialogicEvent, at_index:int = -1, auto_select
var block: Control = event_node.instantiate()
block.resource = event_resource
- event_resource._editor_node = block
+ event_resource.editor_node = block
event_resource._enter_visual_editor(timeline_editor)
block.content_changed.connect(something_changed)
@@ -353,7 +380,7 @@ func add_event_node(event_resource:DialogicEvent, at_index:int = -1, auto_select
func create_end_branch_event(at_index:int, parent_node:Node) -> Node:
- var end_branch_event :Control = load("res://addons/dialogic/Editor/Events/BranchEnd.tscn").instantiate()
+ var end_branch_event: Control = load("res://addons/dialogic/Editor/Events/BranchEnd.tscn").instantiate()
end_branch_event.resource = DialogicEndBranchEvent.new()
end_branch_event.gui_input.connect(_on_event_block_gui_input.bind(end_branch_event))
parent_node.end_node = end_branch_event
@@ -365,13 +392,13 @@ func create_end_branch_event(at_index:int, parent_node:Node) -> Node:
# combination of the above that establishes the correct connection between the event and it's end branch
-func add_event_with_end_branch(resource, at_index:int=-1, auto_select:bool = false, indent:bool = false):
+func add_event_with_end_branch(resource, at_index:int=-1, auto_select:bool = false, indent:bool = false) -> void:
var event := add_event_node(resource, at_index, auto_select, indent)
create_end_branch_event(at_index+1, event)
## Adds an event (either single nodes or with end branches) to the timeline with UndoRedo support
-func add_event_undoable(event_resource: DialogicEvent, at_index: int = -1):
+func add_event_undoable(event_resource: DialogicEvent, at_index: int = -1) -> void:
TimelineUndoRedo.create_action("[D] Add "+event_resource.event_name+" event.")
if event_resource.can_contain_events:
TimelineUndoRedo.add_do_method(add_event_with_end_branch.bind(event_resource, at_index, true, true))
@@ -447,7 +474,7 @@ func add_events_indexed(indexed_events:Dictionary) -> void:
# now create the visual block.
deselect_all_items()
if event_resource is DialogicEndBranchEvent:
- var idx :String = indexed_events[event_idx].trim_prefix('<>')
+ var idx: String = indexed_events[event_idx].trim_prefix('<>')
if idx.begins_with('#'): # a global index
events.append(create_end_branch_event(%Timeline.get_child_count(), %Timeline.get_child(int(idx.trim_prefix('#')))))
else: # a local index (index in the added events list)
@@ -460,6 +487,7 @@ func add_events_indexed(indexed_events:Dictionary) -> void:
selected_items = events
visual_update_selection()
indent_events()
+ something_changed()
## Deletes events based on an indexed dictionary
@@ -478,8 +506,8 @@ func delete_events_indexed(indexed_events:Dictionary) -> void:
%Timeline.get_child(idx-idx_shift).get_parent().remove_child(%Timeline.get_child(idx-idx_shift))
idx_shift += 1
- something_changed()
indent_events()
+ something_changed()
func delete_selected_events() -> void:
@@ -504,7 +532,6 @@ func cut_events_indexed(indexed_events:Dictionary) -> void:
select_events_indexed(indexed_events)
copy_selected_events()
delete_events_indexed(indexed_events)
- indent_events()
func copy_selected_events() -> void:
@@ -526,12 +553,12 @@ func copy_selected_events() -> void:
func get_clipboard_data() -> Array:
- var clipboard_parse :Variant= str_to_var(DisplayServer.clipboard_get())
+ var clipboard_parse: Variant = str_to_var(DisplayServer.clipboard_get())
if clipboard_parse is Dictionary:
if clipboard_parse.has("project_name"):
if clipboard_parse.project_name != ProjectSettings.get_setting("application/config/name"):
- print("[D] Be careful when copying from another project!")
+ print("[Dialogic] Be careful when copying from another project!")
if clipboard_parse.has('events'):
return clipboard_parse.events
return []
@@ -578,7 +605,7 @@ func select_item(item: Node, multi_possible:bool = true) -> void:
if len(selected_items) == 0:
selected_items = [item]
else:
- var index :int= selected_items[-1].get_index()
+ var index: int = selected_items[-1].get_index()
var goal_idx := item.get_index()
while true:
if index < goal_idx: index += 1
@@ -652,7 +679,7 @@ func _add_event_button_pressed(event_resource:DialogicEvent, force_resource := f
else:
at_index = %Timeline.get_child_count()
- var resource :DialogicEvent = null
+ var resource: DialogicEvent = null
if force_resource:
resource = event_resource
else:
@@ -809,8 +836,8 @@ func offset_blocks_by_index(blocks:Array, offset:int):
func scroll_to_piece(piece_index:int) -> void:
await get_tree().process_frame
- var height :float = %Timeline.get_child(min(piece_index, %Timeline.get_child_count()-1)).position.y
- if height < %TimelineArea.scroll_vertical or height > %TimelineArea.scroll_vertical+%TimelineArea.size.y-(200*DialogicUtil.get_editor_scale()):
+ var height: float = %Timeline.get_child(min(piece_index, %Timeline.get_child_count()-1)).position.y
+ if height < %TimelineArea.scroll_vertical or height > %TimelineArea.scroll_vertical+%TimelineArea.size.y:
%TimelineArea.scroll_vertical = height
@@ -877,7 +904,7 @@ func indent_events() -> void:
################################################################################
func _on_event_popup_menu_index_pressed(index:int) -> void:
- var item :Control = %EventPopupMenu.current_event
+ var item: Control = %EventPopupMenu.current_event
if index == 0:
if not item in selected_items:
selected_items = [item]
@@ -905,34 +932,51 @@ func _on_event_popup_menu_index_pressed(index:int) -> void:
TimelineUndoRedo.add_undo_method(add_events_indexed.bind(events_indexed))
TimelineUndoRedo.commit_action()
indent_events()
- something_changed()
-func _on_right_sidebar_resized():
+func _on_right_sidebar_resized() -> void:
var _scale := DialogicUtil.get_editor_scale()
- if %RightSidebar.size.x < 160*_scale and !sidebar_collapsed:
+
+ if %RightSidebar.size.x < 160 * _scale and (not sidebar_collapsed or not _initialized):
sidebar_collapsed = true
+
for section in %RightSidebar.get_node('EventContainer').get_children():
+
for con in section.get_children():
+
if con.get_child_count() == 0:
continue
+
if con.get_child(0) is Label:
con.get_child(0).hide()
+
elif con.get_child(0) is Button:
+
for button in con.get_children():
button.toggle_name(false)
- elif %RightSidebar.size.x > 160*_scale and sidebar_collapsed:
+
+ elif %RightSidebar.size.x > 160 * _scale and (sidebar_collapsed or not _initialized):
sidebar_collapsed = false
+
for section in %RightSidebar.get_node('EventContainer').get_children():
+
for con in section.get_children():
+
if con.get_child_count() == 0:
continue
+
if con.get_child(0) is Label:
con.get_child(0).show()
+
elif con.get_child(0) is Button:
for button in con.get_children():
button.toggle_name(true)
+
+ if _initialized:
+ DialogicUtil.set_editor_setting("dialogic/editor/right_sidebar_width", %RightSidebar.size.x)
+ DialogicUtil.set_editor_setting("dialogic/editor/right_sidebar_collapsed", sidebar_collapsed)
+
#endregion
@@ -945,22 +989,25 @@ func duplicate_selected() -> void:
var at_index: int = selected_items[-1].get_index()+1
TimelineUndoRedo.create_action("[D] Duplicate "+str(len(events))+" event(s).")
TimelineUndoRedo.add_do_method(add_events_at_index.bind(events, at_index))
- TimelineUndoRedo.add_do_method(something_changed)
TimelineUndoRedo.add_undo_method(delete_events_at_index.bind(at_index, len(events)))
- TimelineUndoRedo.add_undo_method(something_changed)
TimelineUndoRedo.commit_action()
func _input(event:InputEvent) -> void:
+ if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed == false:
+ drag_allowed = false
+
# we protect this with is_visible_in_tree to not
# invoke a shortcut by accident
if !((event is InputEventKey or !event is InputEventWithModifiers) and is_visible_in_tree()):
return
+
if "pressed" in event:
if !event.pressed:
return
+
## Some shortcuts should always work
match event.as_text():
"Ctrl+T": # Add text event
@@ -997,7 +1044,7 @@ func _input(event:InputEvent) -> void:
get_viewport().set_input_as_handled()
## Some shortcuts should be disabled when writing text.
- var focus_owner : Control = get_viewport().gui_get_focus_owner()
+ var focus_owner: Control = get_viewport().gui_get_focus_owner()
if focus_owner is TextEdit or focus_owner is LineEdit or (focus_owner is Button and focus_owner.get_parent_control().name == "Spin"):
return
@@ -1067,6 +1114,7 @@ func _input(event:InputEvent) -> void:
TimelineUndoRedo.commit_action()
get_viewport().set_input_as_handled()
+
"Ctrl+X":
var events_indexed := get_events_indexed(selected_items)
TimelineUndoRedo.create_action("[D] Cut "+str(len(selected_items))+" event(s).")
@@ -1093,8 +1141,8 @@ func _input(event:InputEvent) -> void:
func get_previous_character(double_previous := false) -> DialogicCharacter:
- var character :DialogicCharacter = null
- var idx :int = %Timeline.get_child_count()
+ var character: DialogicCharacter = null
+ var idx: int = %Timeline.get_child_count()
if idx == 0:
return null
if len(selected_items):
@@ -1123,3 +1171,109 @@ func get_previous_character(double_previous := false) -> DialogicCharacter:
return character
#endregion
+
+#region SEARCH
+################################################################################
+
+var search_results := {}
+func _search_timeline(search_text:String) -> bool:
+ for event in search_results:
+ if is_instance_valid(search_results[event]):
+ search_results[event].set_search_text("")
+ search_results[event].deselect()
+ search_results[event].queue_redraw()
+ search_results.clear()
+
+ for block in %Timeline.get_children():
+ if block.resource is DialogicTextEvent:
+ var text_field: TextEdit = block.get_node("%BodyContent").find_child("Field_Text_Multiline", true, false)
+ text_field.set_search_text(search_text)
+ if text_field.search(search_text, 0, 0, 0).x != -1:
+ search_results[block] = text_field
+ text_field.queue_redraw()
+ set_meta("current_search", search_text)
+ search_navigate(false)
+ return not search_results.is_empty()
+
+
+func _search_navigate_down() -> void:
+ search_navigate(false)
+
+
+func _search_navigate_up() -> void:
+ search_navigate(true)
+
+
+func search_navigate(navigate_up := false) -> void:
+ var search_text: String = get_meta("current_search", "")
+
+ if search_results.is_empty() or %Timeline.get_child_count() == 0:
+ return
+ if selected_items.is_empty():
+ select_item(%Timeline.get_child(0), false)
+
+ while not selected_items[0] in search_results:
+ select_item(%Timeline.get_child(wrapi(selected_items[0].get_index()+1, 0, %Timeline.get_child_count()-1)), false)
+
+ var event: Node = selected_items[0]
+ var counter := 0
+ while true:
+ counter += 1
+ var field: TextEdit = search_results[event]
+ field.queue_redraw()
+ var result := search_text_field(field, search_text, navigate_up)
+ var current_line := field.get_selection_from_line() if field.has_selection() else -1
+ var current_column := field.get_selection_from_column() if field.has_selection() else -1
+ var next_is_in_this_event := false
+ if result.y == -1:
+ next_is_in_this_event = false
+ elif navigate_up:
+ if current_line == -1:
+ current_line = field.get_line_count()-1
+ current_column = field.get_line(current_line).length()
+ next_is_in_this_event = result.x < current_column or result.y < current_line
+ else:
+ next_is_in_this_event = result.x > current_column or result.y > current_line
+
+ if next_is_in_this_event:
+ if not event in selected_items:
+ select_item(event, false)
+ %TimelineArea.ensure_control_visible(event)
+ event._on_ToggleBodyVisibility_toggled(true)
+ field.select(result.y, result.x, result.y, result.x+len(search_text))
+ break
+
+ else:
+ field.deselect()
+ var index := search_results.keys().find(event)
+ event = search_results.keys()[wrapi(index+(-1 if navigate_up else 1), 0, search_results.size())]
+
+ if counter > 5:
+ print("[Dialogic] Search failed.")
+ break
+
+
+func search_text_field(field:TextEdit, search_text := "", navigate_up:= false) -> Vector2i:
+ var search_from_line: int = 0
+ var search_from_column: int = 0
+ if field.has_selection():
+ if navigate_up:
+ search_from_line = field.get_selection_from_line()
+ search_from_column = field.get_selection_from_column()-1
+ if search_from_column == -1:
+ search_from_line -= 1
+ if search_from_line == -1:
+ return Vector2i(-1, -1)
+ search_from_column = field.get_line(search_from_line).length()-1
+ else:
+ search_from_line = field.get_selection_to_line()
+ search_from_column = field.get_selection_to_column()
+ else:
+ if navigate_up:
+ search_from_line = field.get_line_count()-1
+ search_from_column = field.get_line(search_from_line).length()-1
+
+ var search := field.search(search_text, 4 if navigate_up else 0, search_from_line, search_from_column)
+ return search
+
+#endregion
diff --git a/addons/dialogic/Editor/TimelineEditor/test_timeline_scene.gd b/addons/dialogic/Editor/TimelineEditor/test_timeline_scene.gd
index 2658995f3..3c1d170b6 100644
--- a/addons/dialogic/Editor/TimelineEditor/test_timeline_scene.gd
+++ b/addons/dialogic/Editor/TimelineEditor/test_timeline_scene.gd
@@ -2,7 +2,7 @@ extends Control
func _ready() -> void:
print("[Dialogic] Testing scene was started.")
- if !ProjectSettings.get_setting('internationalization/locale/test', "").is_empty():
+ if not ProjectSettings.get_setting('internationalization/locale/test', "").is_empty():
print("Testing locale is: ", ProjectSettings.get_setting('internationalization/locale/test'))
$PauseIndictator.hide()
@@ -14,8 +14,8 @@ func _ready() -> void:
scene.position = get_viewport_rect().size/2.0
randomize()
- var current_timeline: String = DialogicUtil.get_editor_setting('current_timeline_path', null)
- if !current_timeline:
+ var current_timeline: String = DialogicUtil.get_editor_setting("current_timeline_path", "")
+ if not current_timeline:
get_tree().quit()
DialogicUtil.autoload().start(current_timeline)
DialogicUtil.autoload().timeline_ended.connect(get_tree().quit)
@@ -40,5 +40,5 @@ func _input(event:InputEvent) -> void:
var is_auto_skip_enabled := auto_skip.enabled
auto_skip.disable_on_unread_text = false
- auto_skip.enabled = !is_auto_skip_enabled
+ auto_skip.enabled = not is_auto_skip_enabled
diff --git a/addons/dialogic/Editor/TimelineEditor/timeline_editor.gd b/addons/dialogic/Editor/TimelineEditor/timeline_editor.gd
index 189416a6d..e5302a7ee 100644
--- a/addons/dialogic/Editor/TimelineEditor/timeline_editor.gd
+++ b/addons/dialogic/Editor/TimelineEditor/timeline_editor.gd
@@ -4,8 +4,11 @@ extends DialogicEditor
## Editor that holds both the visual and the text timeline editors.
# references
-var current_editor_mode: int = 0 # 0 = visal, 1 = text
-var play_timeline_button : Button = null
+enum EditorMode {VISUAL, TEXT}
+
+var current_editor_mode := EditorMode.VISUAL
+var play_timeline_button: Button = null
+
## Overwrite. Register to the editor manager in here.
func _register() -> void:
@@ -39,11 +42,11 @@ func _register() -> void:
current_editor_mode = DialogicUtil.get_editor_setting('timeline_editor_mode', 0)
match current_editor_mode:
- 0:
+ EditorMode.VISUAL:
%VisualEditor.show()
%TextEditor.hide()
%SwitchEditorMode.text = "Text Editor"
- 1:
+ EditorMode.TEXT:
%VisualEditor.hide()
%TextEditor.show()
%SwitchEditorMode.text = "Visual Editor"
@@ -65,9 +68,9 @@ func _open_resource(resource:Resource) -> void:
current_resource = resource
current_resource_state = ResourceStates.SAVED
match current_editor_mode:
- 0:
+ EditorMode.VISUAL:
%VisualEditor.load_timeline(current_resource)
- 1:
+ EditorMode.TEXT:
%TextEditor.load_timeline(current_resource)
$NoTimelineScreen.hide()
%TimelineName.text = DialogicResourceUtil.get_unique_identifier(current_resource.resource_path)
@@ -77,26 +80,32 @@ func _open_resource(resource:Resource) -> void:
## If this editor supports editing resources, save them here (overwrite in subclass)
func _save() -> void:
match current_editor_mode:
- 0:
+ EditorMode.VISUAL:
%VisualEditor.save_timeline()
- 1:
+ EditorMode.TEXT:
%TextEditor.save_timeline()
func _input(event: InputEvent) -> void:
- var keycode := KEY_F5
- if OS.get_name() == "macOS":
- keycode = KEY_B
- if event is InputEventKey and event.keycode == keycode and event.pressed:
- if Input.is_key_pressed(KEY_CTRL):
- play_timeline()
+ if event is InputEventKey:
+ var keycode := KEY_F5
+ if OS.get_name() == "macOS":
+ keycode = KEY_B
+ if event.keycode == keycode and event.pressed:
+ if Input.is_key_pressed(KEY_CTRL):
+ play_timeline()
+
+ if event.keycode == KEY_F and event.pressed:
+ if Input.is_key_pressed(KEY_CTRL):
+ if is_ancestor_of(get_viewport().gui_get_focus_owner()):
+ search_timeline()
## Method to play the current timeline. Connected to the button in the sidebar.
-func play_timeline():
+func play_timeline() -> void:
_save()
- var dialogic_plugin = DialogicUtil.get_dialogic_plugin()
+ var dialogic_plugin := DialogicUtil.get_dialogic_plugin()
# Save the current opened timeline
DialogicUtil.set_editor_setting('current_timeline_path', current_resource.resource_path)
@@ -105,32 +114,32 @@ func play_timeline():
## Method to switch from visual to text editor (and vice versa). Connected to the button in the sidebar.
-func toggle_editor_mode():
+func toggle_editor_mode() -> void:
match current_editor_mode:
- 0:
- current_editor_mode = 1
+ EditorMode.VISUAL:
+ current_editor_mode = EditorMode.TEXT
%VisualEditor.save_timeline()
%VisualEditor.hide()
%TextEditor.show()
%TextEditor.load_timeline(current_resource)
%SwitchEditorMode.text = "Visual Editor"
- 1:
- current_editor_mode = 0
+ EditorMode.TEXT:
+ current_editor_mode = EditorMode.VISUAL
%TextEditor.save_timeline()
%TextEditor.hide()
%VisualEditor.load_timeline(current_resource)
%VisualEditor.show()
%SwitchEditorMode.text = "Text Editor"
-
+ _on_search_text_changed(%Search.text)
DialogicUtil.set_editor_setting('timeline_editor_mode', current_editor_mode)
-func _on_resource_unsaved():
+func _on_resource_unsaved() -> void:
if current_resource:
current_resource.set_meta("timeline_not_saved", true)
-func _on_resource_saved():
+func _on_resource_saved() -> void:
if current_resource:
current_resource.set_meta("timeline_not_saved", false)
@@ -145,21 +154,22 @@ func new_timeline(path:String) -> void:
editors_manager.edit_resource(new_timeline)
-func _ready():
+func _ready() -> void:
$NoTimelineScreen.add_theme_stylebox_override("panel", get_theme_stylebox("Background", "EditorStyles"))
# switch editor mode button
%SwitchEditorMode.text = "Text editor"
%SwitchEditorMode.icon = get_theme_icon("ArrowRight", "EditorIcons")
%SwitchEditorMode.pressed.connect(toggle_editor_mode)
- var _scale := DialogicUtil.get_editor_scale()
- %SwitchEditorMode.custom_minimum_size.x = 200 * _scale
-
+ %SwitchEditorMode.custom_minimum_size.x = 200 * DialogicUtil.get_editor_scale()
+ %SearchClose.icon = get_theme_icon("Close", "EditorIcons")
+ %SearchUp.icon = get_theme_icon("MoveUp", "EditorIcons")
+ %SearchDown.icon = get_theme_icon("MoveDown", "EditorIcons")
-func _on_create_timeline_button_pressed():
+func _on_create_timeline_button_pressed() -> void:
editors_manager.show_add_resource_dialog(
new_timeline,
'*.dtl; DialogicTimeline',
@@ -168,13 +178,61 @@ func _on_create_timeline_button_pressed():
)
-func _clear():
+func _clear() -> void:
current_resource = null
current_resource_state = ResourceStates.SAVED
match current_editor_mode:
- 0:
+ EditorMode.VISUAL:
%VisualEditor.clear_timeline_nodes()
- 1:
+ EditorMode.TEXT:
%TextEditor.clear_timeline()
$NoTimelineScreen.show()
play_timeline_button.disabled = true
+
+
+func get_current_editor() -> Node:
+ if current_editor_mode == 1:
+ return %TextEditor
+ return %VisualEditor
+
+#region SEARCH
+
+func search_timeline() -> void:
+ %SearchSection.show()
+ if get_viewport().gui_get_focus_owner() is TextEdit:
+ %Search.text = get_viewport().gui_get_focus_owner().get_selected_text()
+ _on_search_text_changed(%Search.text)
+ else:
+ %Search.text = ""
+ %Search.grab_focus()
+
+
+func _on_close_search_pressed() -> void:
+ %SearchSection.hide()
+ %Search.text = ""
+ _on_search_text_changed('')
+
+
+func _on_search_text_changed(new_text: String) -> void:
+ var editor: Node = null
+ var anything_found: bool = get_current_editor()._search_timeline(new_text)
+ if anything_found or new_text.is_empty():
+ %SearchLabel.hide()
+ %Search.add_theme_color_override("font_color", get_theme_color("font_color", "Editor"))
+ else:
+ %SearchLabel.show()
+ %SearchLabel.add_theme_color_override("font_color", get_theme_color("error_color", "Editor"))
+ %Search.add_theme_color_override("font_color", get_theme_color("error_color", "Editor"))
+ %SearchLabel.text = "No Match"
+
+
+func _on_search_down_pressed() -> void:
+ get_current_editor()._search_navigate_down()
+
+
+func _on_search_up_pressed() -> void:
+ get_current_editor()._search_navigate_up()
+
+#endregion
+
+
diff --git a/addons/dialogic/Editor/TimelineEditor/timeline_editor.tscn b/addons/dialogic/Editor/TimelineEditor/timeline_editor.tscn
index 799d24d1e..ba77fb4f6 100644
--- a/addons/dialogic/Editor/TimelineEditor/timeline_editor.tscn
+++ b/addons/dialogic/Editor/TimelineEditor/timeline_editor.tscn
@@ -6,7 +6,7 @@
[ext_resource type="PackedScene" uid="uid://defdeav8rli6o" path="res://addons/dialogic/Editor/TimelineEditor/TextEditor/timeline_editor_text.tscn" id="3_up2bn"]
[ext_resource type="Script" path="res://addons/dialogic/Editor/TimelineEditor/TextEditor/syntax_highlighter.gd" id="4_1t6bf"]
-[sub_resource type="Image" id="Image_3cd31"]
+[sub_resource type="Image" id="Image_43fqw"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -15,13 +15,13 @@ data = {
"width": 16
}
-[sub_resource type="ImageTexture" id="ImageTexture_wvrw5"]
-image = SubResource("Image_3cd31")
+[sub_resource type="ImageTexture" id="ImageTexture_lvr8x"]
+image = SubResource("Image_43fqw")
[sub_resource type="SyntaxHighlighter" id="SyntaxHighlighter_7lpql"]
script = ExtResource("4_1t6bf")
-[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_3migc"]
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_lpeon"]
content_margin_left = 4.0
content_margin_top = 4.0
content_margin_right = 4.0
@@ -62,11 +62,11 @@ text = "Cool Name"
[node name="NameTooltip" parent="VBox/HBox" instance=ExtResource("2_yqd26")]
layout_mode = 2
-tooltip_text = "The name of the timeline is determined from the file name.
+tooltip_text = "This unique identifier is based on the file name. You can change it in the Reference Manager.
This is what you should use in a jump event to reference this timeline.
-Besides the file path, you can also use this name in Dialogic.start()"
-texture = SubResource("ImageTexture_wvrw5")
+You can also use this name in Dialogic.start()."
+texture = SubResource("ImageTexture_lvr8x")
hint_text = "This unique identifier is based on the file name. You can change it in the Reference Manager.
This is what you should use in a jump event to reference this timeline.
@@ -80,7 +80,7 @@ size_flags_horizontal = 10
size_flags_vertical = 4
tooltip_text = "Switch between Text Editor and Visual Editor"
text = "Text editor"
-icon = SubResource("ImageTexture_wvrw5")
+icon = SubResource("ImageTexture_lvr8x")
[node name="VisualEditor" parent="VBox" instance=ExtResource("2_qs7vc")]
unique_name_in_owner = true
@@ -100,6 +100,34 @@ symbol_lookup_on_click = true
line_folding = false
gutters_draw_fold_gutter = false
+[node name="SearchSection" type="HBoxContainer" parent="VBox"]
+unique_name_in_owner = true
+visible = false
+layout_mode = 2
+
+[node name="Search" type="LineEdit" parent="VBox/SearchSection"]
+unique_name_in_owner = true
+layout_mode = 2
+size_flags_horizontal = 3
+placeholder_text = "Search"
+
+[node name="SearchLabel" type="Label" parent="VBox/SearchSection"]
+unique_name_in_owner = true
+visible = false
+layout_mode = 2
+
+[node name="SearchUp" type="Button" parent="VBox/SearchSection"]
+unique_name_in_owner = true
+layout_mode = 2
+
+[node name="SearchDown" type="Button" parent="VBox/SearchSection"]
+unique_name_in_owner = true
+layout_mode = 2
+
+[node name="SearchClose" type="Button" parent="VBox/SearchSection"]
+unique_name_in_owner = true
+layout_mode = 2
+
[node name="NoTimelineScreen" type="PanelContainer" parent="."]
visible = false
layout_mode = 1
@@ -108,7 +136,7 @@ anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
-theme_override_styles/panel = SubResource("StyleBoxFlat_3migc")
+theme_override_styles/panel = SubResource("StyleBoxFlat_lpeon")
[node name="CenterContainer" type="CenterContainer" parent="NoTimelineScreen"]
layout_mode = 2
@@ -128,4 +156,8 @@ autowrap_mode = 3
layout_mode = 2
text = "Create New Timeline"
+[connection signal="text_changed" from="VBox/SearchSection/Search" to="." method="_on_search_text_changed"]
+[connection signal="pressed" from="VBox/SearchSection/SearchUp" to="." method="_on_search_up_pressed"]
+[connection signal="pressed" from="VBox/SearchSection/SearchDown" to="." method="_on_search_down_pressed"]
+[connection signal="pressed" from="VBox/SearchSection/SearchClose" to="." method="_on_close_search_pressed"]
[connection signal="pressed" from="NoTimelineScreen/CenterContainer/VBoxContainer/CreateTimelineButton" to="." method="_on_create_timeline_button_pressed"]
diff --git a/addons/dialogic/Editor/dialogic_editor.gd b/addons/dialogic/Editor/dialogic_editor.gd
index 3bb813feb..353958ac5 100644
--- a/addons/dialogic/Editor/dialogic_editor.gd
+++ b/addons/dialogic/Editor/dialogic_editor.gd
@@ -41,7 +41,7 @@ func _get_title() -> String:
## If this editor supports editing resources, load them here (overwrite in subclass)
-func _open_resource(resource:Resource) -> void:
+func _open_resource(_resource:Resource) -> void:
pass
@@ -51,7 +51,7 @@ func _save() -> void:
## Overwrite. Called when this editor is shown. (show() doesn't have to be called)
-func _open(extra_info:Variant = null) -> void:
+func _open(_extra_info:Variant = null) -> void:
pass
diff --git a/addons/dialogic/Editor/editor_main.gd b/addons/dialogic/Editor/editor_main.gd
index 533470c38..599405756 100644
--- a/addons/dialogic/Editor/editor_main.gd
+++ b/addons/dialogic/Editor/editor_main.gd
@@ -8,159 +8,256 @@ var editors_manager: Control = null
var editor_file_dialog: EditorFileDialog
-## Styling
-@export var editor_tab_bg := StyleBoxFlat.new()
-
+@onready var sidebar := %Sidebar as DialogicSidebar
func _ready() -> void:
if get_parent() is SubViewport:
return
+ ## CONNECTIONS
+ sidebar.show_sidebar.connect(_on_sidebar_toggled)
+
## REFERENCES
- editors_manager = $Margin/EditorsManager
- var button :Button = editors_manager.add_icon_button(get_theme_icon("MakeFloating", "EditorIcons"), 'Make floating')
+ editors_manager = $EditorsManager
+ var button: Button = editors_manager.add_icon_button(
+ get_theme_icon("MakeFloating", "EditorIcons"), "Make floating"
+ )
button.pressed.connect(toggle_floating_window)
-
-
- ## STYLING
- $BG.color = get_theme_color("base_color", "Editor")
- editor_tab_bg.border_color = get_theme_color("base_color", "Editor")
- editor_tab_bg.bg_color = get_theme_color("dark_color_2", "Editor")
- $Margin/EditorsManager.editors_holder.add_theme_stylebox_override('panel', editor_tab_bg)
-
# File dialog
editor_file_dialog = EditorFileDialog.new()
add_child(editor_file_dialog)
var info_message := Label.new()
- info_message.add_theme_color_override('font_color', get_theme_color("warning_color", "Editor"))
+ info_message.add_theme_color_override("font_color", get_theme_color("warning_color", "Editor"))
editor_file_dialog.get_line_edit().get_parent().add_sibling(info_message)
- info_message.get_parent().move_child(info_message, info_message.get_index()-1)
- editor_file_dialog.set_meta('info_message_label', info_message)
+ info_message.get_parent().move_child(info_message, info_message.get_index() - 1)
+ editor_file_dialog.set_meta("info_message_label", info_message)
- $SaveConfirmationDialog.add_button('No Saving Please!', true, 'nosave')
+ $SaveConfirmationDialog.add_button("No Saving Please!", true, "nosave")
$SaveConfirmationDialog.hide()
update_theme_additions()
+ EditorInterface.get_base_control().theme_changed.connect(update_theme_additions)
-func update_theme_additions():
+func _on_sidebar_toggled(sidebar_shown: bool) -> void:
+ var h_split := (%HSplit as HSplitContainer)
+ if sidebar_shown:
+ h_split.dragger_visibility = SplitContainer.DRAGGER_VISIBLE
+ h_split.split_offset = 150
+ h_split.collapsed = false
+ else:
+ h_split.dragger_visibility = SplitContainer.DRAGGER_HIDDEN_COLLAPSED
+ h_split.split_offset = 0
+ h_split.collapsed = true
+
+
+func update_theme_additions() -> void:
+ add_theme_stylebox_override(
+ "panel",
+ (
+ DCSS
+ . inline(
+ {
+ "background": get_theme_color("base_color", "Editor"),
+ "padding":
+ [5 * DialogicUtil.get_editor_scale(), 5 * DialogicUtil.get_editor_scale()],
+ }
+ )
+ )
+ )
+ var holder_panel := (
+ DCSS
+ . inline(
+ {
+ "border-radius": 5,
+ #'border': 2,
+ #'border-color': get_theme_color("base_color", "Editor"),
+ "background": get_theme_color("dark_color_2", "Editor"),
+ "padding":
+ [5 * DialogicUtil.get_editor_scale(), 5 * DialogicUtil.get_editor_scale()],
+ }
+ )
+ )
+ holder_panel.border_width_top = 0
+ holder_panel.corner_radius_top_left = 0
+ editors_manager.editors_holder.add_theme_stylebox_override("panel", holder_panel)
+
if theme == null:
theme = Theme.new()
theme.clear()
- theme.set_type_variation('DialogicTitle', 'Label')
- theme.set_font('font', 'DialogicTitle', get_theme_font("title", "EditorFonts"))
- theme.set_color('font_color', 'DialogicTitle', get_theme_color('warning_color', 'Editor'))
- theme.set_color('font_uneditable_color', 'DialogicTitle', get_theme_color('warning_color', 'Editor'))
- theme.set_color('font_selected_color', 'DialogicTitle', get_theme_color('warning_color', 'Editor'))
- theme.set_font_size('font_size', 'DialogicTitle', get_theme_font_size("doc_size", "EditorFonts"))
-
- theme.set_type_variation('DialogicSubTitle', 'Label')
- theme.set_font('font', 'DialogicSubTitle', get_theme_font("title", "EditorFonts"))
- theme.set_font_size('font_size', 'DialogicSubTitle', get_theme_font_size("doc_size", "EditorFonts"))
- theme.set_color('font_color', 'DialogicSubTitle', get_theme_color('accent_color', 'Editor'))
-
- theme.set_type_variation('DialogicPanelA', 'PanelContainer')
- var panel_style := DCSS.inline({
- 'border-radius': 10,
- 'border': 0,
- 'border_color':get_theme_color("dark_color_3", "Editor"),
- 'background': get_theme_color("base_color", "Editor"),
- 'padding': [5, 5],
- })
- theme.set_stylebox('panel', 'DialogicPanelA', panel_style)
- theme.set_stylebox('normal', 'DialogicPanelA', panel_style)
+ theme.set_type_variation("DialogicTitle", "Label")
+ theme.set_font("font", "DialogicTitle", get_theme_font("title", "EditorFonts"))
+ theme.set_color("font_color", "DialogicTitle", get_theme_color("warning_color", "Editor"))
+ theme.set_color(
+ "font_uneditable_color", "DialogicTitle", get_theme_color("warning_color", "Editor")
+ )
+ theme.set_color(
+ "font_selected_color", "DialogicTitle", get_theme_color("warning_color", "Editor")
+ )
+ theme.set_font_size(
+ "font_size", "DialogicTitle", get_theme_font_size("doc_size", "EditorFonts")
+ )
+
+ theme.set_type_variation("DialogicSubTitle", "Label")
+ theme.set_font("font", "DialogicSubTitle", get_theme_font("title", "EditorFonts"))
+ theme.set_font_size(
+ "font_size", "DialogicSubTitle", get_theme_font_size("doc_size", "EditorFonts")
+ )
+ theme.set_color("font_color", "DialogicSubTitle", get_theme_color("accent_color", "Editor"))
+
+ theme.set_type_variation("DialogicPanelA", "PanelContainer")
+ var panel_style := (
+ DCSS
+ . inline(
+ {
+ "border-radius": 10,
+ "background": get_theme_color("base_color", "Editor"),
+ "padding": [5, 5],
+ }
+ )
+ )
+ theme.set_stylebox("panel", "DialogicPanelA", panel_style)
+ theme.set_stylebox("normal", "DialogicPanelA", panel_style)
var dark_panel := panel_style.duplicate()
dark_panel.bg_color = get_theme_color("dark_color_3", "Editor")
- theme.set_stylebox('panel', 'DialogicPanelDarkA', dark_panel)
+ theme.set_stylebox("panel", "DialogicPanelDarkA", dark_panel)
var cornerless_panel := panel_style.duplicate()
cornerless_panel.corner_radius_top_left = 0
- theme.set_stylebox('panel', 'DialogicPanelA_cornerless', cornerless_panel)
-
+ theme.set_stylebox("panel", "DialogicPanelA_cornerless", cornerless_panel)
# panel used for example for portrait previews in character editor
- theme.set_type_variation('DialogicPanelB', 'PanelContainer')
- var side_panel :StyleBoxFlat= panel_style.duplicate()
+ theme.set_type_variation("DialogicPanelB", "PanelContainer")
+ var side_panel: StyleBoxFlat = panel_style.duplicate()
side_panel.corner_radius_top_left = 0
side_panel.corner_radius_bottom_left = 0
- side_panel.expand_margin_left = 8
+ side_panel.expand_margin_left = get_theme_constant("separation", "SplitContainer")
side_panel.bg_color = get_theme_color("dark_color_2", "Editor")
side_panel.set_border_width_all(1)
side_panel.border_width_left = 0
side_panel.border_color = get_theme_color("contrast_color_2", "Editor")
- theme.set_stylebox('panel', 'DialogicPanelB', side_panel)
+ theme.set_stylebox("panel", "DialogicPanelB", side_panel)
-
- theme.set_type_variation('DialogicEventEdit', 'Control')
+ theme.set_type_variation("DialogicEventEdit", "Control")
var edit_panel := StyleBoxFlat.new()
edit_panel.draw_center = true
edit_panel.bg_color = get_theme_color("accent_color", "Editor")
edit_panel.bg_color.a = 0.05
edit_panel.border_width_bottom = 2
- edit_panel.border_color = get_theme_color("accent_color", "Editor").lerp(get_theme_color("dark_color_2", "Editor"), 0.4)
+ edit_panel.border_color = get_theme_color("accent_color", "Editor").lerp(
+ get_theme_color("dark_color_2", "Editor"), 0.4
+ )
edit_panel.content_margin_left = 5
edit_panel.content_margin_right = 5
edit_panel.set_corner_radius_all(1)
- theme.set_stylebox('panel', 'DialogicEventEdit', edit_panel)
- theme.set_stylebox('normal', 'DialogicEventEdit', edit_panel)
+ theme.set_stylebox("panel", "DialogicEventEdit", edit_panel)
+ theme.set_stylebox("normal", "DialogicEventEdit", edit_panel)
var focus_edit := edit_panel.duplicate()
focus_edit.border_color = get_theme_color("property_color_z", "Editor")
focus_edit.draw_center = false
- theme.set_stylebox('focus', 'DialogicEventEdit', focus_edit)
+ theme.set_stylebox("focus", "DialogicEventEdit", focus_edit)
var hover_edit := edit_panel.duplicate()
hover_edit.border_color = get_theme_color("warning_color", "Editor")
- theme.set_stylebox('hover', 'DialogicEventEdit', hover_edit)
+ theme.set_stylebox("hover", "DialogicEventEdit", hover_edit)
var disabled_edit := edit_panel.duplicate()
disabled_edit.border_color = get_theme_color("property_color", "Editor")
- theme.set_stylebox('disabled', 'DialogicEventEdit', disabled_edit)
-
- theme.set_type_variation('DialogicHintText', 'Label')
- theme.set_color('font_color', 'DialogicHintText', get_theme_color("readonly_color", "Editor"))
- theme.set_font('font', 'DialogicHintText', get_theme_font("doc_italic", "EditorFonts"))
-
- theme.set_type_variation('DialogicHintText2', 'Label')
- theme.set_color('font_color', 'DialogicHintText2', get_theme_color("property_color_w", "Editor"))
- theme.set_font('font', 'DialogicHintText2', get_theme_font("doc_italic", "EditorFonts"))
-
- theme.set_type_variation('DialogicSection', 'Label')
- theme.set_font('font', 'DialogicSection', get_theme_font("main_msdf", "EditorFonts"))
- theme.set_color('font_color', 'DialogicSection', get_theme_color("property_color_z", "Editor"))
- theme.set_font_size('font_size', 'DialogicSection', get_theme_font_size("doc_size", "EditorFonts"))
-
- theme.set_type_variation('DialogicSettingsSection', 'DialogicSection')
- theme.set_font('font', 'DialogicSettingsSection', get_theme_font("main_msdf", "EditorFonts"))
- theme.set_color('font_color', 'DialogicSettingsSection', get_theme_color("property_color_z", "Editor"))
- theme.set_font_size('font_size', 'DialogicSettingsSection', get_theme_font_size("doc_size", "EditorFonts"))
-
- theme.set_type_variation('DialogicSectionBig', 'DialogicSection')
- theme.set_color('font_color', 'DialogicSectionBig', get_theme_color("accent_color", "Editor"))
- theme.set_font_size('font_size', 'DialogicSectionBig', get_theme_font_size("doc_title_size", "EditorFonts"))
-
- theme.set_type_variation('DialogicLink', 'LinkButton')
- theme.set_color('font_hover_color', 'DialogicLink', get_theme_color("warning_color", "Editor"))
-
- theme.set_type_variation('DialogicMegaSeparator', 'HSeparator')
- theme.set_stylebox('separator', 'DialogicMegaSeparator', DCSS.inline({
- 'border-radius': 10,
- 'border': 0,
- 'background': get_theme_color("accent_color", "Editor"),
- 'padding': [5, 5],
- }))
- theme.set_constant('separation', 'DialogicMegaSeparator', 50)
-
-
+ theme.set_stylebox("disabled", "DialogicEventEdit", disabled_edit)
+
+ theme.set_type_variation("DialogicHintText", "Label")
+ theme.set_color("font_color", "DialogicHintText", get_theme_color("readonly_color", "Editor"))
+ theme.set_font("font", "DialogicHintText", get_theme_font("doc_italic", "EditorFonts"))
+
+ theme.set_type_variation("DialogicHintText2", "Label")
+ theme.set_color(
+ "font_color", "DialogicHintText2", get_theme_color("property_color_w", "Editor")
+ )
+ theme.set_font("font", "DialogicHintText2", get_theme_font("doc_italic", "EditorFonts"))
+
+ theme.set_type_variation("DialogicSection", "Label")
+ theme.set_font("font", "DialogicSection", get_theme_font("main_msdf", "EditorFonts"))
+ theme.set_color("font_color", "DialogicSection", get_theme_color("property_color_z", "Editor"))
+ theme.set_font_size(
+ "font_size", "DialogicSection", get_theme_font_size("doc_size", "EditorFonts")
+ )
+
+ theme.set_type_variation("DialogicSettingsSection", "DialogicSection")
+ theme.set_font("font", "DialogicSettingsSection", get_theme_font("main_msdf", "EditorFonts"))
+ theme.set_color(
+ "font_color", "DialogicSettingsSection", get_theme_color("property_color_z", "Editor")
+ )
+ theme.set_font_size(
+ "font_size", "DialogicSettingsSection", get_theme_font_size("doc_size", "EditorFonts")
+ )
+
+ theme.set_type_variation("DialogicSectionBig", "DialogicSection")
+ theme.set_color("font_color", "DialogicSectionBig", get_theme_color("accent_color", "Editor"))
+ theme.set_font_size(
+ "font_size", "DialogicSectionBig", get_theme_font_size("doc_title_size", "EditorFonts")
+ )
+
+ theme.set_type_variation("DialogicLink", "LinkButton")
+ theme.set_color("font_hover_color", "DialogicLink", get_theme_color("warning_color", "Editor"))
+
+ theme.set_type_variation("DialogicMegaSeparator", "HSeparator")
+ (
+ theme
+ . set_stylebox(
+ "separator",
+ "DialogicMegaSeparator",
+ (
+ DCSS
+ . inline(
+ {
+ "border-radius": 10,
+ "border": 0,
+ "background": get_theme_color("accent_color", "Editor"),
+ "padding": [5, 5],
+ }
+ )
+ )
+ )
+ )
+ theme.set_constant("separation", "DialogicMegaSeparator", 50)
+
+ theme.set_type_variation("DialogicTextEventTextEdit", "CodeEdit")
+ var editor_settings := plugin_reference.get_editor_interface().get_editor_settings()
+ var text_panel := (
+ DCSS
+ . inline(
+ {
+ "border-radius": 8,
+ "background":
+ editor_settings.get_setting("text_editor/theme/highlighting/background_color").lerp(
+ editor_settings.get_setting("text_editor/theme/highlighting/text_color"), 0.05
+ ),
+ "padding": [8, 8],
+ }
+ )
+ )
+ text_panel.content_margin_bottom = 5
+ text_panel.content_margin_left = 13
+ theme.set_stylebox("normal", "DialogicTextEventTextEdit", text_panel)
+
+ var event_field_group_panel := DCSS.inline({
+ 'border-radius': 8,
+ "border":1,
+ "padding":2,
+ "boder-color": get_theme_color("property_color", "Editor"),
+ "background":"none"})
+ theme.set_type_variation("DialogicEventEditGroup", "PanelContainer")
+ theme.set_stylebox("panel", "DialogicEventEditGroup", event_field_group_panel)
theme.set_icon('Plugin', 'Dialogic', load("res://addons/dialogic/Editor/Images/plugin-icon.svg"))
## Switches from floating window mode to embedded mode based on current mode
-func toggle_floating_window():
+func toggle_floating_window() -> void:
if get_parent() is Window:
swap_to_embedded_editor()
else:
@@ -168,7 +265,7 @@ func toggle_floating_window():
## Removes the main control from it's parent and adds it to a new Window node
-func swap_to_floating_window():
+func swap_to_floating_window() -> void:
if get_parent() is Window:
return
@@ -187,23 +284,31 @@ func swap_to_floating_window():
window.disable_3d = true
window.wrap_controls = true
window.popup_centered()
- plugin_reference.get_editor_interface().set_main_screen_editor('2D')
+ plugin_reference.get_editor_interface().set_main_screen_editor("2D")
## Removes the main control from the window node and adds it to it's grandparent
## which is the original owner.
-func swap_to_embedded_editor():
+func swap_to_embedded_editor() -> void:
if not get_parent() is Window:
return
var window := get_parent()
get_parent().remove_child(self)
- plugin_reference.get_editor_interface().set_main_screen_editor('Dialogic')
+ plugin_reference.get_editor_interface().set_main_screen_editor("Dialogic")
window.get_parent().add_child(self)
window.queue_free()
-func godot_file_dialog(callable:Callable, filter:String, mode := EditorFileDialog.FILE_MODE_OPEN_FILE, window_title := "Save", current_file_name := 'New_File', saving_something := false, extra_message:String = "") -> EditorFileDialog:
+func godot_file_dialog(
+ callable: Callable,
+ filter: String,
+ mode := EditorFileDialog.FILE_MODE_OPEN_FILE,
+ window_title := "Save",
+ current_file_name := "New_File",
+ saving_something := false,
+ extra_message: String = ""
+) -> EditorFileDialog:
for connection in editor_file_dialog.file_selected.get_connections():
editor_file_dialog.file_selected.disconnect(connection.callable)
for connection in editor_file_dialog.dir_selected.get_connections():
@@ -216,10 +321,10 @@ func godot_file_dialog(callable:Callable, filter:String, mode := EditorFileDialo
editor_file_dialog.current_file = current_file_name
editor_file_dialog.disable_overwrite_warning = !saving_something
if extra_message:
- editor_file_dialog.get_meta('info_message_label').show()
- editor_file_dialog.get_meta('info_message_label').text = extra_message
+ editor_file_dialog.get_meta("info_message_label").show()
+ editor_file_dialog.get_meta("info_message_label").text = extra_message
else:
- editor_file_dialog.get_meta('info_message_label').hide()
+ editor_file_dialog.get_meta("info_message_label").hide()
if mode == EditorFileDialog.FILE_MODE_OPEN_FILE or mode == EditorFileDialog.FILE_MODE_SAVE_FILE:
editor_file_dialog.file_selected.connect(callable)
@@ -229,4 +334,3 @@ func godot_file_dialog(callable:Callable, filter:String, mode := EditorFileDialo
editor_file_dialog.dir_selected.connect(callable)
editor_file_dialog.file_selected.connect(callable)
return editor_file_dialog
-
diff --git a/addons/dialogic/Editor/editor_main.tscn b/addons/dialogic/Editor/editor_main.tscn
index 435b5a9f4..849ad796b 100644
--- a/addons/dialogic/Editor/editor_main.tscn
+++ b/addons/dialogic/Editor/editor_main.tscn
@@ -1,4 +1,4 @@
-[gd_scene load_steps=19 format=3 uid="uid://de6yhw4r8jqb3"]
+[gd_scene load_steps=18 format=3 uid="uid://de6yhw4r8jqb3"]
[ext_resource type="Script" path="res://addons/dialogic/Editor/editor_main.gd" id="1_x88ov"]
[ext_resource type="Script" path="res://addons/dialogic/Editor/editors_manager.gd" id="2_pe2tl"]
@@ -15,22 +15,7 @@
[ext_resource type="Script" path="res://addons/dialogic/Editor/Common/update_manager.gd" id="14_l6b1p"]
[ext_resource type="PackedScene" uid="uid://vv3m5m68fwg7" path="res://addons/dialogic/Editor/Common/update_install_window.tscn" id="15_cu4xj"]
-[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_mdik5"]
-content_margin_left = 4.0
-content_margin_top = 4.0
-content_margin_right = 6.0
-content_margin_bottom = 6.0
-bg_color = Color(0.1155, 0.132, 0.1595, 1)
-border_width_left = 2
-border_width_bottom = 2
-border_color = Color(0.21, 0.24, 0.29, 1)
-corner_radius_top_right = 5
-corner_radius_bottom_right = 5
-corner_radius_bottom_left = 5
-expand_margin_left = 2.0
-expand_margin_top = 2.0
-
-[sub_resource type="Image" id="Image_rog03"]
+[sub_resource type="Image" id="Image_uqxml"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -40,19 +25,18 @@ data = {
}
[sub_resource type="ImageTexture" id="ImageTexture_drcn6"]
-image = SubResource("Image_rog03")
+image = SubResource("Image_uqxml")
-[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_hwjob"]
-content_margin_left = 4.0
-content_margin_top = 4.0
-content_margin_right = 4.0
-content_margin_bottom = 4.0
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_5bs7k"]
+content_margin_left = 8.0
+content_margin_top = 8.0
+content_margin_right = 8.0
+content_margin_bottom = 8.0
bg_color = Color(0.1155, 0.132, 0.1595, 1)
corner_detail = 1
anti_aliasing = false
-[node name="EditorView" type="Control"]
-layout_mode = 3
+[node name="EditorView" type="ScrollContainer"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
@@ -61,30 +45,15 @@ grow_vertical = 2
size_flags_horizontal = 3
size_flags_vertical = 3
script = ExtResource("1_x88ov")
-editor_tab_bg = SubResource("StyleBoxFlat_mdik5")
-
-[node name="BG" type="ColorRect" parent="."]
-layout_mode = 2
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-color = Color(0.0588235, 0.0980392, 0.141176, 1)
-
-[node name="Margin" type="MarginContainer" parent="."]
-layout_mode = 2
-anchor_right = 1.0
-anchor_bottom = 1.0
-grow_horizontal = 2
-grow_vertical = 2
-theme_override_constants/margin_right = 4
-theme_override_constants/margin_bottom = 2
-[node name="EditorsManager" type="Control" parent="Margin"]
+[node name="EditorsManager" type="Control" parent="."]
layout_mode = 2
+size_flags_horizontal = 3
+size_flags_vertical = 3
script = ExtResource("2_pe2tl")
-[node name="HSplit" type="HSplitContainer" parent="Margin/EditorsManager"]
+[node name="HSplit" type="HSplitContainer" parent="EditorsManager"]
+unique_name_in_owner = true
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
@@ -95,29 +64,28 @@ size_flags_vertical = 3
theme_override_constants/separation = 0
split_offset = 150
-[node name="Sidebar" parent="Margin/EditorsManager/HSplit" instance=ExtResource("3_lp6hj")]
+[node name="Sidebar" parent="EditorsManager/HSplit" instance=ExtResource("3_lp6hj")]
unique_name_in_owner = true
custom_minimum_size = Vector2(20, 0)
layout_mode = 2
split_offset = 0
-[node name="VBox" type="VBoxContainer" parent="Margin/EditorsManager/HSplit"]
+[node name="VBox" type="VBoxContainer" parent="EditorsManager/HSplit"]
layout_mode = 2
theme_override_constants/separation = 0
-[node name="Toolbar" type="HBoxContainer" parent="Margin/EditorsManager/HSplit/VBox"]
+[node name="Toolbar" type="HBoxContainer" parent="EditorsManager/HSplit/VBox"]
layout_mode = 2
size_flags_vertical = 0
mouse_filter = 2
alignment = 2
script = ExtResource("4_6cx8s")
-[node name="EditorTabBar" type="TabBar" parent="Margin/EditorsManager/HSplit/VBox/Toolbar"]
+[node name="EditorTabBar" type="TabBar" parent="EditorsManager/HSplit/VBox/Toolbar"]
layout_mode = 2
size_flags_horizontal = 3
size_flags_vertical = 8
tab_count = 7
-tab_0/title = ""
tab_0/icon = ExtResource("2_scwcl")
tab_1/title = "Timeline"
tab_1/icon = SubResource("ImageTexture_drcn6")
@@ -132,15 +100,15 @@ tab_5/icon = ExtResource("9_k4reh")
tab_6/title = "Settings"
tab_6/icon = SubResource("ImageTexture_drcn6")
-[node name="CustomButtons" type="HBoxContainer" parent="Margin/EditorsManager/HSplit/VBox/Toolbar"]
+[node name="CustomButtons" type="HBoxContainer" parent="EditorsManager/HSplit/VBox/Toolbar"]
unique_name_in_owner = true
layout_mode = 2
-[node name="Editors" type="PanelContainer" parent="Margin/EditorsManager/HSplit/VBox"]
+[node name="Editors" type="PanelContainer" parent="EditorsManager/HSplit/VBox"]
layout_mode = 2
size_flags_vertical = 3
-[node name="CodeCompletionHelper" type="Node" parent="Margin/EditorsManager"]
+[node name="CodeCompletionHelper" type="Node" parent="EditorsManager"]
script = ExtResource("11_fyce4")
[node name="SaveConfirmationDialog" type="AcceptDialog" parent="."]
@@ -166,7 +134,7 @@ content_scale_aspect = 4
script = ExtResource("10_xbkrt")
[node name="Manager" parent="ReferenceManager" instance=ExtResource("10_l1rf8")]
-theme_override_styles/panel = SubResource("StyleBoxFlat_hwjob")
+theme_override_styles/panel = SubResource("StyleBoxFlat_5bs7k")
[node name="UpdateManager" type="Node" parent="."]
script = ExtResource("14_l6b1p")
diff --git a/addons/dialogic/Editor/editors_manager.gd b/addons/dialogic/Editor/editors_manager.gd
index af959a1d7..029a9199f 100644
--- a/addons/dialogic/Editor/editors_manager.gd
+++ b/addons/dialogic/Editor/editors_manager.gd
@@ -7,21 +7,22 @@ signal resource_opened(resource)
signal editor_changed(previous, current)
### References
-@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
+@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")
+ 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 = []
+var used_resources_cache: Array = []
################################################################################
@@ -55,7 +56,7 @@ func _ready() -> void:
DialogicResourceUtil.update()
- await get_parent().get_parent().ready
+ await get_parent().ready
await get_tree().process_frame
load_saved_state()
@@ -65,6 +66,8 @@ func _ready() -> void:
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()
@@ -117,7 +120,7 @@ func _on_editors_tab_changed(tab:int) -> void:
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.')
+ print("[Dialogic] The resource you are trying to edit doesn't exist any more.")
return
if current_editor and save_previous:
@@ -166,7 +169,7 @@ func open_editor(editor:DialogicEditor, save_previous: bool = true, extra_info:V
tabbar.current_tab = editor.get_index()
if editor.current_resource:
- var text:String = editor.current_resource.resource_path.get_file()
+ var text: String = editor.current_resource.resource_path.get_file()
if editor.current_resource_state == DialogicEditor.ResourceStates.UNSAVED:
text += "(*)"
@@ -198,7 +201,7 @@ func show_add_resource_dialog(accept_callable:Callable, filter:String = "*", tit
func _on_add_resource_dialog_accepted(path:String, callable:Callable) -> void:
- var file_name :String= path.get_file().trim_suffix('.'+path.get_extension())
+ 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())
@@ -206,7 +209,8 @@ func _on_add_resource_dialog_accepted(path:String, callable:Callable) -> void:
## Called by the plugin.gd script on CTRL+S or Debug Game start
func save_current_resource() -> void:
- current_editor._save()
+ if current_editor:
+ current_editor._save()
## Change the resource state
@@ -276,5 +280,5 @@ func get_current_editor() -> DialogicEditor:
return current_editor
-func _exit_tree():
+func _exit_tree() -> void:
DialogicUtil.set_editor_setting('last_resources', used_resources_cache)
diff --git a/addons/dialogic/Example Assets/already_read_indicator.gd b/addons/dialogic/Example Assets/already_read_indicator.gd
index 8ead30869..4dbf5d392 100644
--- a/addons/dialogic/Example Assets/already_read_indicator.gd
+++ b/addons/dialogic/Example Assets/already_read_indicator.gd
@@ -1,6 +1,6 @@
extends Control
-func _ready():
+func _ready() -> void:
if DialogicUtil.autoload().has_subsystem('History'):
DialogicUtil.autoload().History.visited_event.connect(_on_visited_event)
DialogicUtil.autoload().History.unvisited_event.connect(_on_not_read_event)
diff --git a/addons/dialogic/Example Assets/default_event.gd b/addons/dialogic/Example Assets/default_event.gd
index a2cfa1ed0..6ffbc7145 100644
--- a/addons/dialogic/Example Assets/default_event.gd
+++ b/addons/dialogic/Example Assets/default_event.gd
@@ -2,7 +2,7 @@
extends DialogicEvent
# DEFINE ALL PROPERTIES OF THE EVENT
-# var MySetting :String = ""
+# var MySetting: String = ""
func _execute() -> void:
# I have no idea how this event works ;)
diff --git a/addons/dialogic/Example Assets/portraits/CustomPortrait_AnimatedSprite.gd b/addons/dialogic/Example Assets/portraits/CustomPortrait_AnimatedSprite.gd
index e2378dd3b..5595991f9 100644
--- a/addons/dialogic/Example Assets/portraits/CustomPortrait_AnimatedSprite.gd
+++ b/addons/dialogic/Example Assets/portraits/CustomPortrait_AnimatedSprite.gd
@@ -9,7 +9,7 @@ func _update_portrait(passed_character:DialogicCharacter, passed_portrait:String
if $Sprite.sprite_frames.has_animation(passed_portrait):
$Sprite.play(passed_portrait)
-func _on_animated_sprite_2d_animation_finished():
+func _on_animated_sprite_2d_animation_finished() -> void:
$Sprite.frame = randi()%$Sprite.sprite_frames.get_frame_count($Sprite.animation)
$Sprite.play()
diff --git a/addons/dialogic/Example Assets/portraits/CustomPortrait_FaceAtlas.gd b/addons/dialogic/Example Assets/portraits/CustomPortrait_FaceAtlas.gd
index acb600aa6..7b1b74a8b 100644
--- a/addons/dialogic/Example Assets/portraits/CustomPortrait_FaceAtlas.gd
+++ b/addons/dialogic/Example Assets/portraits/CustomPortrait_FaceAtlas.gd
@@ -3,7 +3,7 @@ extends DialogicPortrait
enum Faces {BASED_ON_PORTRAIT_NAME, NEUTRAL, HAPPY, SAD, JOY, SHOCK, ANGRY}
-@export var emotion : Faces = Faces.BASED_ON_PORTRAIT_NAME
+@export var emotion: Faces = Faces.BASED_ON_PORTRAIT_NAME
@export var portrait_width: int
@export var portrait_height: int
@export var alien := true
diff --git a/addons/dialogic/Modules/Audio/event_music.gd b/addons/dialogic/Modules/Audio/event_music.gd
index dd5c923d0..c54c5bd9d 100644
--- a/addons/dialogic/Modules/Audio/event_music.gd
+++ b/addons/dialogic/Modules/Audio/event_music.gd
@@ -8,15 +8,15 @@ extends DialogicEvent
### Settings
## The file to play. If empty, the previous music will be faded out.
-var file_path: String = ""
+var file_path := ""
## The length of the fade. If 0 (by default) it's an instant change.
var fade_length: float = 0
## The volume the music will be played at.
var volume: float = 0
## The audio bus the music will be played at.
-var audio_bus: String = "Master"
+var audio_bus := ""
## If true, the audio will loop, otherwise only play once.
-var loop: bool = true
+var loop := true
################################################################################
@@ -57,7 +57,7 @@ func get_shortcode_parameters() -> Dictionary:
"path" : {"property": "file_path", "default": ""},
"fade" : {"property": "fade_length", "default": 0},
"volume" : {"property": "volume", "default": 0},
- "bus" : {"property": "audio_bus", "default": "Master",
+ "bus" : {"property": "audio_bus", "default": "",
"suggestions": get_bus_suggestions},
"loop" : {"property": "loop", "default": true},
}
diff --git a/addons/dialogic/Modules/Audio/event_sound.gd b/addons/dialogic/Modules/Audio/event_sound.gd
index 3d8308bc4..844006177 100644
--- a/addons/dialogic/Modules/Audio/event_sound.gd
+++ b/addons/dialogic/Modules/Audio/event_sound.gd
@@ -8,13 +8,13 @@ extends DialogicEvent
### Settings
## The path to the file to play.
-var file_path: String = ""
+var file_path := ""
## The volume to play the sound at.
var volume: float = 0
## The bus to play the sound on.
-var audio_bus: String = "Master"
+var audio_bus := ""
## If true, the sound will loop infinitely. Not recommended (as there is no way to stop it).
-var loop: bool = false
+var loop := false
################################################################################
@@ -54,7 +54,7 @@ func get_shortcode_parameters() -> Dictionary:
#param_name : property_name
"path" : {"property": "file_path", "default": "",},
"volume" : {"property": "volume", "default": 0},
- "bus" : {"property": "audio_bus", "default": "Master",
+ "bus" : {"property": "audio_bus", "default": "",
"suggestions": get_bus_suggestions},
"loop" : {"property": "loop", "default": false},
}
@@ -64,7 +64,7 @@ func get_shortcode_parameters() -> Dictionary:
## EDITOR REPRESENTATION
################################################################################
-func build_event_editor():
+func build_event_editor() -> void:
add_header_edit('file_path', ValueType.FILE,
{'left_text' : 'Play',
'file_filter' : '*.mp3, *.ogg, *.wav; Supported Audio Files',
@@ -73,6 +73,7 @@ func build_event_editor():
add_body_edit('volume', ValueType.NUMBER, {'left_text':'Volume:', 'mode':2}, '!file_path.is_empty()')
add_body_edit('audio_bus', ValueType.SINGLELINE_TEXT, {'left_text':'Audio Bus:'}, '!file_path.is_empty()')
+
func get_bus_suggestions() -> Dictionary:
var bus_name_list := {}
for i in range(AudioServer.bus_count):
diff --git a/addons/dialogic/Modules/Audio/subsystem_audio.gd b/addons/dialogic/Modules/Audio/subsystem_audio.gd
index 5a22680fd..e27fbeb42 100644
--- a/addons/dialogic/Modules/Audio/subsystem_audio.gd
+++ b/addons/dialogic/Modules/Audio/subsystem_audio.gd
@@ -34,6 +34,8 @@ signal sound_started(info: Dictionary)
##
## Background music is long audio.
var base_music_player := AudioStreamPlayer.new()
+## Reference to the last used music player.
+var current_music_player: AudioStreamPlayer
## Audio player base, that will be duplicated to play sound effects.
##
## Sound effects are short audio.
@@ -46,7 +48,7 @@ var base_sound_player := AudioStreamPlayer.new()
## Clears the state on this subsystem and stops all audio.
##
## If you want to stop sounds only, use [method stop_all_sounds].
-func clear_game_state(clear_flag := DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
+func clear_game_state(_clear_flag := DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
update_music()
stop_all_sounds()
@@ -73,6 +75,11 @@ func resume() -> void:
for child in get_children():
child.stream_paused = false
+
+func _on_dialogic_timeline_ended() -> void:
+ if not dialogic.Styles.get_layout_node():
+ clear_game_state()
+ pass
#endregion
@@ -80,6 +87,8 @@ func resume() -> void:
####################################################################################################
func _ready() -> void:
+ dialogic.timeline_ended.connect(_on_dialogic_timeline_ended)
+
base_music_player.name = "Music"
add_child(base_music_player)
@@ -88,36 +97,45 @@ func _ready() -> void:
## Updates the background music. Will fade out previous music.
-func update_music(path := "", volume := 0.0, audio_bus := "Master", fade_time := 0.0, loop := true) -> void:
+func update_music(path := "", volume := 0.0, audio_bus := "", fade_time := 0.0, loop := true) -> void:
+
dialogic.current_state_info['music'] = {'path':path, 'volume':volume, 'audio_bus':audio_bus, 'loop':loop}
music_started.emit(dialogic.current_state_info['music'])
+
var fader: Tween = null
- if base_music_player.playing or !path.is_empty():
+ if is_instance_valid(current_music_player) and current_music_player.playing or !path.is_empty():
fader = create_tween()
+
var prev_node: Node = null
- if base_music_player.playing:
- prev_node = base_music_player.duplicate()
+ if is_instance_valid(current_music_player) and current_music_player.playing:
+ prev_node = current_music_player.duplicate()
add_child(prev_node)
- prev_node.play(base_music_player.get_playback_position())
- prev_node.remove_from_group('dialogic_music_player')
+ prev_node.play(current_music_player.get_playback_position())
fader.tween_method(interpolate_volume_linearly.bind(prev_node), db_to_linear(prev_node.volume_db),0.0,fade_time)
+
if path:
- base_music_player.stream = load(path)
- base_music_player.volume_db = volume
- base_music_player.bus = audio_bus
- if not base_music_player.stream is AudioStreamWAV:
- if "loop" in base_music_player.stream:
- base_music_player.stream.loop = loop
- elif "loop_mode" in base_music_player.stream:
+ current_music_player = base_music_player.duplicate()
+ add_child(current_music_player)
+ current_music_player.stream = load(path)
+ current_music_player.volume_db = volume
+ if audio_bus:
+ current_music_player.bus = audio_bus
+ if not current_music_player.stream is AudioStreamWAV:
+ if "loop" in current_music_player.stream:
+ current_music_player.stream.loop = loop
+ elif "loop_mode" in current_music_player.stream:
if loop:
- base_music_player.stream.loop_mode = AudioStreamWAV.LOOP_FORWARD
+ current_music_player.stream.loop_mode = AudioStreamWAV.LOOP_FORWARD
else:
- base_music_player.stream.loop_mode = AudioStreamWAV.LOOP_DISABLED
+ current_music_player.stream.loop_mode = AudioStreamWAV.LOOP_DISABLED
- base_music_player.play(0)
- fader.parallel().tween_method(interpolate_volume_linearly.bind(base_music_player), 0.0, db_to_linear(volume),fade_time)
+ current_music_player.play(0)
+ fader.parallel().tween_method(interpolate_volume_linearly.bind(current_music_player), 0.0, db_to_linear(volume),fade_time)
else:
- base_music_player.stop()
+ if is_instance_valid(current_music_player):
+ current_music_player.stop()
+ current_music_player.queue_free()
+
if prev_node:
fader.tween_callback(prev_node.queue_free)
@@ -128,12 +146,14 @@ func has_music() -> bool:
## Plays a given sound file.
-func play_sound(path: String, volume := 0.0, audio_bus := "Master", loop := false) -> void:
+func play_sound(path: String, volume := 0.0, audio_bus := "", loop := false) -> void:
if base_sound_player != null and !path.is_empty():
sound_started.emit({'path':path, 'volume':volume, 'audio_bus':audio_bus, 'loop':loop})
+
var new_sound_node := base_sound_player.duplicate()
new_sound_node.name += "Sound"
new_sound_node.stream = load(path)
+
if "loop" in new_sound_node.stream:
new_sound_node.stream.loop = loop
elif "loop_mode" in new_sound_node.stream:
@@ -141,8 +161,11 @@ func play_sound(path: String, volume := 0.0, audio_bus := "Master", loop := fals
new_sound_node.stream.loop_mode = AudioStreamWAV.LOOP_FORWARD
else:
new_sound_node.stream.loop_mode = AudioStreamWAV.LOOP_DISABLED
+
new_sound_node.volume_db = volume
- new_sound_node.bus = audio_bus
+ if audio_bus:
+ new_sound_node.bus = audio_bus
+
add_child(new_sound_node)
new_sound_node.play()
new_sound_node.finished.connect(new_sound_node.queue_free)
diff --git a/addons/dialogic/Modules/Background/DefaultBackgroundScene/default_background.gd b/addons/dialogic/Modules/Background/DefaultBackgroundScene/default_background.gd
index ce4d217bb..ef3c57058 100644
--- a/addons/dialogic/Modules/Background/DefaultBackgroundScene/default_background.gd
+++ b/addons/dialogic/Modules/Background/DefaultBackgroundScene/default_background.gd
@@ -3,8 +3,8 @@ extends DialogicBackground
## The default background scene.
## Extend the DialogicBackground class to create your own background scene.
-@onready var image_node = $Image
-@onready var color_node = $ColorRect
+@onready var image_node: TextureRect = $Image
+@onready var color_node: ColorRect = $ColorRect
func _ready() -> void:
@@ -15,7 +15,7 @@ func _ready() -> void:
image_node.anchor_bottom = 1
-func _update_background(argument:String, time:float) -> void:
+func _update_background(argument:String, _time:float) -> void:
if argument.begins_with('res://'):
image_node.texture = load(argument)
color_node.color = Color.TRANSPARENT
diff --git a/addons/dialogic/Modules/Background/Transitions/Defaults/swipe_diagonal_up_left.gd b/addons/dialogic/Modules/Background/Transitions/Defaults/swipe_diagonal_up_left.gd
index 787ed404f..061f943c7 100644
--- a/addons/dialogic/Modules/Background/Transitions/Defaults/swipe_diagonal_up_left.gd
+++ b/addons/dialogic/Modules/Background/Transitions/Defaults/swipe_diagonal_up_left.gd
@@ -2,7 +2,7 @@ extends "res://addons/dialogic/Modules/Background/Transitions/simple_swipe_trans
func _fade() -> void:
var shader := setup_swipe_shader()
- var texture :GradientTexture2D = shader.get_shader_parameter('wipe_texture')
+ var texture: GradientTexture2D = shader.get_shader_parameter('wipe_texture')
texture.fill_from = Vector2.DOWN
texture.fill_to = Vector2.RIGHT
tween_shader_progress()
diff --git a/addons/dialogic/Modules/Background/Transitions/Defaults/swipe_left_to_right.gd b/addons/dialogic/Modules/Background/Transitions/Defaults/swipe_left_to_right.gd
index 32084e92e..8b55d4147 100644
--- a/addons/dialogic/Modules/Background/Transitions/Defaults/swipe_left_to_right.gd
+++ b/addons/dialogic/Modules/Background/Transitions/Defaults/swipe_left_to_right.gd
@@ -2,7 +2,7 @@ extends "res://addons/dialogic/Modules/Background/Transitions/simple_swipe_trans
func _fade() -> void:
var shader := setup_swipe_shader()
- var texture :GradientTexture2D = shader.get_shader_parameter('wipe_texture')
+ var texture: GradientTexture2D = shader.get_shader_parameter('wipe_texture')
texture.fill_from = Vector2.ZERO
texture.fill_to = Vector2.RIGHT
diff --git a/addons/dialogic/Modules/Background/Transitions/Defaults/swipe_right_to_left.gd b/addons/dialogic/Modules/Background/Transitions/Defaults/swipe_right_to_left.gd
index 14005d9aa..5433d595b 100644
--- a/addons/dialogic/Modules/Background/Transitions/Defaults/swipe_right_to_left.gd
+++ b/addons/dialogic/Modules/Background/Transitions/Defaults/swipe_right_to_left.gd
@@ -2,7 +2,7 @@ extends "res://addons/dialogic/Modules/Background/Transitions/simple_swipe_trans
func _fade() -> void:
var shader := setup_swipe_shader()
- var texture :GradientTexture2D = shader.get_shader_parameter('wipe_texture')
+ var texture: GradientTexture2D = shader.get_shader_parameter('wipe_texture')
texture.fill_from = Vector2.RIGHT
texture.fill_to = Vector2.ZERO
tween_shader_progress()
diff --git a/addons/dialogic/Modules/Background/Transitions/class_dialogic_background_transition.gd b/addons/dialogic/Modules/Background/Transitions/class_dialogic_background_transition.gd
index f5465d5a1..3f4f1f015 100644
--- a/addons/dialogic/Modules/Background/Transitions/class_dialogic_background_transition.gd
+++ b/addons/dialogic/Modules/Background/Transitions/class_dialogic_background_transition.gd
@@ -2,7 +2,7 @@ class_name DialogicBackgroundTransition
extends Node
## Helper
-var this_folder : String = get_script().resource_path.get_base_dir()
+var this_folder: String = get_script().resource_path.get_base_dir()
## Set before _fade() is called, will be the root node of the previous bg scene.
@@ -42,7 +42,7 @@ func set_shader(path_to_shader:String=DialogicUtil.get_module_path('Background')
return null
-func tween_shader_progress(progress_parameter:="progress") -> PropertyTweener:
+func tween_shader_progress(_progress_parameter:="progress") -> PropertyTweener:
if !bg_holder:
return
diff --git a/addons/dialogic/Modules/Background/dialogic_background.gd b/addons/dialogic/Modules/Background/dialogic_background.gd
index a7794c31b..9e84a91af 100644
--- a/addons/dialogic/Modules/Background/dialogic_background.gd
+++ b/addons/dialogic/Modules/Background/dialogic_background.gd
@@ -15,24 +15,24 @@ var viewport: SubViewport
## Load the new background in here.
## The time argument is given for when [_should_do_background_update] returns true
## (then you have to do a transition in here)
-func _update_background(argument:String, time:float) -> void:
+func _update_background(_argument:String, _time:float) -> void:
pass
## If a background event with this scene is encountered while this background is used,
## this decides whether to create a new instance and call fade_out or just call [_update_background] # on this scene. Default is false
-func _should_do_background_update(argument:String) -> bool:
+func _should_do_background_update(_argument:String) -> bool:
return false
## Called by dialogic when first created.
## If you return false (by default) it will attempt to animate the "modulate" property.
-func _custom_fade_in(time:float) -> bool:
+func _custom_fade_in(_time:float) -> bool:
return false
## Called by dialogic before removing (done by dialogic).
## If you return false (by default) it will attempt to animate the "modulate" property.
-func _custom_fade_out(time:float) -> bool:
+func _custom_fade_out(_time:float) -> bool:
return false
diff --git a/addons/dialogic/Modules/Background/event_background.gd b/addons/dialogic/Modules/Background/event_background.gd
index 3fac581c9..0380e6981 100644
--- a/addons/dialogic/Modules/Background/event_background.gd
+++ b/addons/dialogic/Modules/Background/event_background.gd
@@ -10,14 +10,14 @@ extends DialogicEvent
## This scene supports images and fading.
## If you set it to a scene path, then that scene will be instanced.
## Learn more about custom backgrounds in the Subsystem_Background.gd docs.
-var scene: String = ""
+var scene := ""
## The argument that is passed to the background scene.
## For the default scene it's the path to the image to show.
-var argument: String = ""
+var argument := ""
## The time the fade animation will take. Leave at 0 for instant change.
var fade: float = 0.0
## Name of the transition to use.
-var transition: String = ""
+var transition := ""
## Helpers for visual editor
enum ArgumentTypes {IMAGE, CUSTOM}
@@ -95,7 +95,7 @@ func get_shortcode_parameters() -> Dictionary:
#region EDITOR REPRESENTATION
################################################################################
-func build_event_editor():
+func build_event_editor() -> void:
add_header_edit('_scene_type', ValueType.FIXED_OPTIONS, {
'left_text' :'Show',
'options': [
@@ -146,8 +146,8 @@ func build_event_editor():
add_body_edit("fade", ValueType.NUMBER, {'left_text':'Fade time:'})
-func get_transition_suggestions(filter:String="") -> Dictionary:
- var transitions := DialogicResourceUtil.list_special_resources_of_type("BackgroundTransition")
+func get_transition_suggestions(_filter:String="") -> Dictionary:
+ var transitions := DialogicResourceUtil.list_special_resources("BackgroundTransition")
var suggestions := {}
for i in transitions:
suggestions[DialogicUtil.pretty_name(i)] = {'value': DialogicUtil.pretty_name(i), 'editor_icon': ["PopupMenu", "EditorIcons"]}
diff --git a/addons/dialogic/Modules/Background/index.gd b/addons/dialogic/Modules/Background/index.gd
index e25806421..d40f03020 100644
--- a/addons/dialogic/Modules/Background/index.gd
+++ b/addons/dialogic/Modules/Background/index.gd
@@ -9,5 +9,5 @@ func _get_subsystems() -> Array:
return [{'name':'Backgrounds', 'script':this_folder.path_join('subsystem_backgrounds.gd')}]
-func _get_special_resources() -> Array[Dictionary]:
- return list_special_resources("Transitions/Defaults", "BackgroundTransition", ".gd")
+func _get_special_resources() -> Dictionary:
+ return {&"BackgroundTransition":list_special_resources("Transitions/Defaults", ".gd")}
diff --git a/addons/dialogic/Modules/Background/node_background_holder.gd b/addons/dialogic/Modules/Background/node_background_holder.gd
index 6b2c3b520..11a262872 100644
--- a/addons/dialogic/Modules/Background/node_background_holder.gd
+++ b/addons/dialogic/Modules/Background/node_background_holder.gd
@@ -2,5 +2,5 @@ class_name DialogicNode_BackgroundHolder
extends ColorRect
-func _ready():
+func _ready() -> void:
add_to_group('dialogic_background_holders')
diff --git a/addons/dialogic/Modules/Background/subsystem_backgrounds.gd b/addons/dialogic/Modules/Background/subsystem_backgrounds.gd
index 6b9fcac45..f98d83031 100644
--- a/addons/dialogic/Modules/Background/subsystem_backgrounds.gd
+++ b/addons/dialogic/Modules/Background/subsystem_backgrounds.gd
@@ -99,7 +99,7 @@ func update_background(scene := "", argument := "", fade_time := 0.0, transition
else:
new_viewport = null
- var trans_script: Script = load(DialogicResourceUtil.guess_special_resource("BackgroundTransition", transition_path, default_transition))
+ var trans_script: Script = load(DialogicResourceUtil.guess_special_resource("BackgroundTransition", transition_path, {"path":default_transition}).path)
var trans_node := Node.new()
trans_node.set_script(trans_script)
trans_node = (trans_node as DialogicBackgroundTransition)
@@ -143,6 +143,7 @@ func _on_transition_finished(background_node:DialogicNode_BackgroundHolder, tran
background_node.color = Color.TRANSPARENT
transition_node.queue_free()
+
## Adds sub-viewport with the given background scene as child to
## Dialogic scene.
func add_background_node(scene:PackedScene, parent:DialogicNode_BackgroundHolder) -> SubViewportContainer:
@@ -166,6 +167,7 @@ func add_background_node(scene:PackedScene, parent:DialogicNode_BackgroundHolder
viewport.transparent_bg = true
viewport.disable_3d = true
viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
+ viewport.canvas_item_default_texture_filter = ProjectSettings.get_setting("rendering/textures/canvas_textures/default_texture_filter")
viewport.add_child(b_scene)
b_scene.viewport = viewport
@@ -176,6 +178,7 @@ func add_background_node(scene:PackedScene, parent:DialogicNode_BackgroundHolder
return v_con
+
## Returns the current background node.
func get_current_background_node() -> Node:
var background_holder: DialogicNode_BackgroundHolder = null
@@ -191,7 +194,6 @@ func get_current_background_node() -> Node:
return current_background_node
-
## Whether a background is set.
func has_background() -> bool:
return !dialogic.current_state_info.get('background_scene', '').is_empty() or !dialogic.current_state_info.get('background_argument','').is_empty()
diff --git a/addons/dialogic/Modules/Call/event_call.gd b/addons/dialogic/Modules/Call/event_call.gd
index 7b4b10e3a..0f2c05ddc 100644
--- a/addons/dialogic/Modules/Call/event_call.gd
+++ b/addons/dialogic/Modules/Call/event_call.gd
@@ -7,16 +7,16 @@ extends DialogicEvent
### Settings
## The name of the autoload to call the method on.
-var autoload_name: String = ""
+var autoload_name := ""
## The name of the method to call on the given autoload.
-var method: String = "":
+var method := "":
set(value):
method = value
if Engine.is_editor_hint():
update_argument_info()
check_arguments_and_update_warning()
## A list of arguments to give to the call.
-var arguments: Array = []:
+var arguments := []:
set(value):
arguments = value
if Engine.is_editor_hint():
@@ -88,7 +88,6 @@ func to_text() -> String:
result += '()'
else:
result += '('
- var arr := []
for i in arguments:
if i is String and i.begins_with('@'):
result += i.trim_prefix('@')
@@ -137,7 +136,7 @@ func get_shortcode_parameters() -> Dictionary:
## EDITOR REPRESENTATION
################################################################################
-func build_event_editor():
+func build_event_editor() -> void:
add_header_edit('autoload_name', ValueType.DYNAMIC_OPTIONS, {'left_text':'On autoload',
'empty_text':'Autoload',
'suggestions_func':get_autoload_suggestions,
@@ -166,15 +165,24 @@ func get_method_suggestions(filter:String="", temp_autoload:String = "") -> Dict
var suggestions := {}
var script: Script
- if temp_autoload:
+ if temp_autoload and ProjectSettings.has_setting('autoload/'+temp_autoload):
script = load(ProjectSettings.get_setting('autoload/'+temp_autoload).trim_prefix('*'))
+
elif autoload_name and ProjectSettings.has_setting('autoload/'+autoload_name):
- script = load(ProjectSettings.get_setting('autoload/'+autoload_name).trim_prefix('*'))
+ var loaded_autoload := load(ProjectSettings.get_setting('autoload/'+autoload_name).trim_prefix('*'))
+
+ if loaded_autoload is PackedScene:
+ var packed_scene: PackedScene = loaded_autoload
+ script = packed_scene.instantiate().get_script()
+
+ else:
+ script = loaded_autoload
+
if script:
- for method in script.get_script_method_list():
- if method.name.begins_with('@') or method.name.begins_with('_'):
+ for script_method in script.get_script_method_list():
+ if script_method.name.begins_with('@') or script_method.name.begins_with('_'):
continue
- suggestions[method.name] = {'value': method.name, 'tooltip':method.name, 'editor_icon': ["Callable", "EditorIcons"]}
+ suggestions[script_method.name] = {'value': script_method.name, 'tooltip':script_method.name, 'editor_icon': ["Callable", "EditorIcons"]}
if !filter.is_empty():
suggestions[filter] = {'value': filter, 'editor_icon':["GuiScrollArrowRight", "EditorIcons"]}
return suggestions
@@ -185,14 +193,14 @@ func update_argument_info() -> void:
if !ResourceLoader.exists(ProjectSettings.get_setting('autoload/'+autoload_name, '').trim_prefix('*')):
_current_method_arg_hints = {}
return
- var script :Script = load(ProjectSettings.get_setting('autoload/'+autoload_name, '').trim_prefix('*'))
+ var script: Script = load(ProjectSettings.get_setting('autoload/'+autoload_name, '').trim_prefix('*'))
for m in script.get_script_method_list():
if m.name == method:
_current_method_arg_hints = {'a':autoload_name, 'm':method, 'info':m}
break
-func check_arguments_and_update_warning():
+func check_arguments_and_update_warning() -> void:
if not _current_method_arg_hints.has("info") or _current_method_arg_hints.info.is_empty():
ui_update_warning.emit()
return
@@ -206,7 +214,7 @@ func check_arguments_and_update_warning():
if _current_method_arg_hints.info.args[idx].type != typeof(arg):
if arg is String and arg.begins_with('@'):
continue
- var expected_type :String = ""
+ var expected_type: String = ""
match _current_method_arg_hints.info.args[idx].type:
TYPE_BOOL: expected_type = "bool"
TYPE_STRING: expected_type = "string"
@@ -228,7 +236,7 @@ func check_arguments_and_update_warning():
####################### CODE COMPLETION ########################################
################################################################################
-func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, word:String, symbol:String) -> void:
+func _get_code_completion(_CodeCompletionHelper:Node, TextNode:TextEdit, line:String, _word:String, symbol:String) -> void:
if line.count(' ') == 1 and not '.' in line:
for i in get_autoload_suggestions():
TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, i, i+'.', event_color.lerp(TextNode.syntax_highlighter.normal_color, 0.3), TextNode.get_theme_icon("Node", "EditorIcons"))
@@ -237,7 +245,7 @@ func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:Str
TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, i, i+'(', event_color.lerp(TextNode.syntax_highlighter.normal_color, 0.3), TextNode.get_theme_icon("Callable", "EditorIcons"))
-func _get_start_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit) -> void:
+func _get_start_code_completion(_CodeCompletionHelper:Node, TextNode:TextEdit) -> void:
TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'do', 'do ', event_color.lerp(TextNode.syntax_highlighter.normal_color, 0.3), _get_icon())
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/bounce.gd b/addons/dialogic/Modules/Character/DefaultAnimations/bounce.gd
index 2d006a540..b99e409ab 100644
--- a/addons/dialogic/Modules/Character/DefaultAnimations/bounce.gd
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/bounce.gd
@@ -1,11 +1,16 @@
extends DialogicAnimation
-func animate():
+func animate() -> void:
var tween := (node.create_tween() as Tween)
tween.set_ease(Tween.EASE_OUT)
-
- tween.tween_property(node, 'position:y', orig_pos.y-node.get_viewport().size.y/10, time*0.4).set_trans(Tween.TRANS_EXPO)
- tween.parallel().tween_property(node, 'scale:y', 1.05, time*0.4).set_trans(Tween.TRANS_EXPO)
- tween.tween_property(node, 'position:y', orig_pos.y, time*0.6).set_trans(Tween.TRANS_BOUNCE)
- tween.parallel().tween_property(node, 'scale:y', 1, time*0.6).set_trans(Tween.TRANS_BOUNCE)
+ tween.tween_property(node, 'position:y', base_position.y-node.get_viewport().size.y/10, time*0.4).set_trans(Tween.TRANS_EXPO)
+ tween.parallel().tween_property(node, 'scale:y', base_scale.y*1.05, time*0.4).set_trans(Tween.TRANS_EXPO)
+ tween.tween_property(node, 'position:y', base_position.y, time*0.6).set_trans(Tween.TRANS_BOUNCE)
+ tween.parallel().tween_property(node, 'scale:y', base_scale.y, time*0.6).set_trans(Tween.TRANS_BOUNCE)
tween.finished.connect(emit_signal.bind('finished_once'))
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "bounce": {"type": AnimationType.ACTION},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/bounce_in.gd b/addons/dialogic/Modules/Character/DefaultAnimations/bounce_in.gd
deleted file mode 100644
index 941d1e4e9..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/bounce_in.gd
+++ /dev/null
@@ -1,13 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- node.scale = Vector2()
- node.modulate.a = 0
-
- tween.set_ease(Tween.EASE_IN_OUT)
- tween.set_trans(Tween.TRANS_SINE)
- tween.set_parallel()
- tween.tween_property(node, 'scale', Vector2(1,1), time).set_trans(Tween.TRANS_SPRING).set_ease(Tween.EASE_OUT)
- tween.tween_property(node, 'modulate:a', 1.0, time)
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/bounce_in_out.gd b/addons/dialogic/Modules/Character/DefaultAnimations/bounce_in_out.gd
new file mode 100644
index 000000000..d5484d901
--- /dev/null
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/bounce_in_out.gd
@@ -0,0 +1,39 @@
+extends DialogicAnimation
+
+
+func animate() -> void:
+ var tween := (node.create_tween() as Tween)
+
+ var end_scale: Vector2 = node.scale
+ var end_modulate_alpha := 1.0
+ var modulation_property := get_modulation_property()
+
+ if is_reversed:
+ end_scale = Vector2(0, 0)
+ end_modulate_alpha = 0.0
+
+ else:
+ node.scale = Vector2(0, 0)
+ var original_modulation: Color = node.get(modulation_property)
+ original_modulation.a = 0.0
+ node.set(modulation_property, original_modulation)
+
+
+ tween.set_ease(Tween.EASE_IN_OUT)
+ tween.set_trans(Tween.TRANS_SINE)
+ tween.set_parallel()
+
+ (tween.tween_property(node, "scale", end_scale, time)
+ .set_trans(Tween.TRANS_SPRING)
+ .set_ease(Tween.EASE_OUT))
+ tween.tween_property(node, modulation_property + ":a", end_modulate_alpha, time)
+
+ await tween.finished
+ finished_once.emit()
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "bounce in": {"reversed": false, "type": AnimationType.IN},
+ "bounce out": {"reversed": true, "type": AnimationType.OUT},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/bounce_out.gd b/addons/dialogic/Modules/Character/DefaultAnimations/bounce_out.gd
deleted file mode 100644
index bc9764282..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/bounce_out.gd
+++ /dev/null
@@ -1,15 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- node.scale = Vector2(1,1)
- node.modulate.a = 1
-
- tween.set_ease(Tween.EASE_IN_OUT)
- tween.set_trans(Tween.TRANS_LINEAR)
- tween.set_parallel()
-
- tween.tween_property(node, 'scale', Vector2(), time).set_trans(Tween.TRANS_ELASTIC).set_ease(Tween.EASE_IN)
- tween.tween_property(node, 'modulate:a', 0.0, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/fade_down_in_out.gd b/addons/dialogic/Modules/Character/DefaultAnimations/fade_down_in_out.gd
new file mode 100644
index 000000000..847bda793
--- /dev/null
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/fade_down_in_out.gd
@@ -0,0 +1,44 @@
+extends DialogicAnimation
+
+func animate() -> void:
+ var tween := (node.create_tween() as Tween)
+
+ var start_height: float = base_position.y - node.get_viewport().size.y / 5
+ var end_height := base_position.y
+
+ var start_modulation := 0.0
+ var end_modulation := 1.0
+
+ if is_reversed:
+ end_height = start_height
+ start_height = base_position.y
+ end_modulation = 0.0
+ start_modulation = 1.0
+
+ node.position.y = start_height
+
+ tween.set_ease(Tween.EASE_OUT)
+ tween.set_trans(Tween.TRANS_SINE)
+ tween.set_parallel()
+
+ var end_postion := Vector2(base_position.x, end_height)
+ tween.tween_property(node, "position", end_postion, time)
+
+ var property := get_modulation_property()
+
+ var original_modulation: Color = node.get(property)
+ original_modulation.a = start_modulation
+ node.set(property, original_modulation)
+ var modulation_alpha := property + ":a"
+
+ tween.tween_property(node, modulation_alpha, end_modulation, time)
+
+ await tween.finished
+ finished_once.emit()
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "fade in down": {"reversed": false, "type": AnimationType.IN},
+ "fade out up": {"reversed": true, "type": AnimationType.OUT},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/fade_in_out.gd b/addons/dialogic/Modules/Character/DefaultAnimations/fade_in_out.gd
new file mode 100644
index 000000000..e432ecd43
--- /dev/null
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/fade_in_out.gd
@@ -0,0 +1,34 @@
+extends DialogicAnimation
+
+func animate() -> void:
+
+ var modulation_property := get_modulation_property()
+ var end_modulation_alpha := 1.0
+
+ if is_reversed:
+ end_modulation_alpha = 0.0
+
+ else:
+ var original_modulation: Color = node.get(modulation_property)
+ original_modulation.a = 0.0
+ node.set(modulation_property, original_modulation)
+
+ var tween := (node.create_tween() as Tween)
+ if is_reversed:
+ tween.set_ease(Tween.EASE_IN)
+ else:
+ tween.set_ease(Tween.EASE_OUT)
+ tween.set_trans(Tween.TRANS_SINE)
+ tween.tween_property(node, modulation_property + ":a", end_modulation_alpha, time)
+
+ await tween.finished
+ finished_once.emit()
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "fade in": {"reversed": false, "type": AnimationType.IN},
+ "fade out": {"reversed": true, "type": AnimationType.OUT},
+ "fade cross": {"type": AnimationType.CROSSFADE},
+ }
+
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/fade_in_up.gd b/addons/dialogic/Modules/Character/DefaultAnimations/fade_in_up.gd
deleted file mode 100644
index 4ee09eca2..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/fade_in_up.gd
+++ /dev/null
@@ -1,14 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- node.position.y = orig_pos.y + node.get_viewport().size.y/5
- node.modulate.a = 0
- tween.set_ease(Tween.EASE_OUT)
- tween.set_trans(Tween.TRANS_SINE)
- tween.set_parallel()
-
- tween.tween_property(node, 'position', orig_pos, time)
- tween.tween_property(node, 'modulate:a', 1.0, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/fade_out_down.gd b/addons/dialogic/Modules/Character/DefaultAnimations/fade_out_down.gd
deleted file mode 100644
index 45adeef1f..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/fade_out_down.gd
+++ /dev/null
@@ -1,12 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- tween.set_ease(Tween.EASE_IN_OUT)
- tween.set_trans(Tween.TRANS_SINE)
- tween.set_parallel()
-
- tween.tween_property(node, 'position:y', orig_pos.y + node.get_viewport().size.y/5, time)
- tween.tween_property(node, 'modulate:a', 0.0, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/fade_up_in_out.gd b/addons/dialogic/Modules/Character/DefaultAnimations/fade_up_in_out.gd
new file mode 100644
index 000000000..83a8ba822
--- /dev/null
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/fade_up_in_out.gd
@@ -0,0 +1,44 @@
+extends DialogicAnimation
+
+func animate() -> void:
+ var tween := (node.create_tween() as Tween)
+
+ var start_height: float = base_position.y + node.get_viewport().size.y / 5
+ var end_height := base_position.y
+
+ var start_modulation := 0.0
+ var end_modulation := 1.0
+
+ if is_reversed:
+ end_height = start_height
+ start_height = base_position.y
+ end_modulation = 0.0
+ start_modulation = 1.0
+
+ node.position.y = start_height
+
+ tween.set_ease(Tween.EASE_OUT)
+ tween.set_trans(Tween.TRANS_SINE)
+ tween.set_parallel()
+
+ var end_postion := Vector2(base_position.x, end_height)
+ tween.tween_property(node, "position", end_postion, time)
+
+ var property := get_modulation_property()
+
+ var original_modulation: Color = node.get(property)
+ original_modulation.a = start_modulation
+ node.set(property, original_modulation)
+ var modulation_alpha := property + ":a"
+
+ tween.tween_property(node, modulation_alpha, end_modulation, time)
+
+ await tween.finished
+ finished_once.emit()
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "fade in up": {"reversed": false, "type": AnimationType.IN},
+ "fade out down": {"reversed": true, "type": AnimationType.OUT},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/heartbeat.gd b/addons/dialogic/Modules/Character/DefaultAnimations/heartbeat.gd
index f83a8ee80..36e8eab83 100644
--- a/addons/dialogic/Modules/Character/DefaultAnimations/heartbeat.gd
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/heartbeat.gd
@@ -1,7 +1,13 @@
extends DialogicAnimation
-func animate():
+func animate() -> void:
var tween := (node.create_tween() as Tween)
tween.tween_property(node, 'scale', Vector2(1,1)*1.2, time*0.5).set_trans(Tween.TRANS_ELASTIC).set_ease(Tween.EASE_OUT)
tween.tween_property(node, 'scale', Vector2(1,1), time*0.5).set_trans(Tween.TRANS_BOUNCE).set_ease(Tween.EASE_OUT)
tween.finished.connect(emit_signal.bind('finished_once'))
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "heartbeat": {"type": AnimationType.ACTION},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/instant_in_or_out.gd b/addons/dialogic/Modules/Character/DefaultAnimations/instant_in_or_out.gd
deleted file mode 100644
index 873225bb5..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/instant_in_or_out.gd
+++ /dev/null
@@ -1,5 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- await node.get_tree().process_frame
- emit_signal('finished')
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/instant_in_out.gd b/addons/dialogic/Modules/Character/DefaultAnimations/instant_in_out.gd
new file mode 100644
index 000000000..3044c69fd
--- /dev/null
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/instant_in_out.gd
@@ -0,0 +1,12 @@
+extends DialogicAnimation
+
+func animate() -> void:
+ await node.get_tree().process_frame
+ finished.emit()
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "instant in": {"reversed": false, "type": AnimationType.IN},
+ "instant out": {"reversed": true, "type": AnimationType.OUT},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/shake_x.gd b/addons/dialogic/Modules/Character/DefaultAnimations/shake_x.gd
index 6b22c9974..de445fc95 100644
--- a/addons/dialogic/Modules/Character/DefaultAnimations/shake_x.gd
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/shake_x.gd
@@ -1,17 +1,20 @@
extends DialogicAnimation
-func animate():
+func animate() -> void:
var tween := (node.create_tween() as Tween)
tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_SINE)
-
- var strength :float = node.get_viewport().size.x/60
- tween.tween_property(node, 'position:x', orig_pos.x+strength, time*0.2)
- tween.tween_property(node, 'position:x', orig_pos.x-strength, time*0.1)
- tween.tween_property(node, 'position:x', orig_pos.x+strength, time*0.1)
- tween.tween_property(node, 'position:x', orig_pos.x-strength, time*0.1)
- tween.tween_property(node, 'position:x', orig_pos.x+strength, time*0.1)
- tween.tween_property(node, 'position:x', orig_pos.x-strength, time*0.1)
- tween.tween_property(node, 'position:x', orig_pos.x+strength, time*0.1)
- tween.tween_property(node, 'position:x', orig_pos.x, time*0.2)
-
+ var strength: float = node.get_viewport().size.x/60
+ var bound_multitween := DialogicUtil.multitween.bind(node, "position", "animation_shake_x")
+ tween.tween_method(bound_multitween, Vector2(), Vector2(1, 0)*strength, time*0.2)
+ tween.tween_method(bound_multitween, Vector2(), Vector2(-1,0)*strength, time*0.1)
+ tween.tween_method(bound_multitween, Vector2(), Vector2(1, 0)*strength, time*0.1)
+ tween.tween_method(bound_multitween, Vector2(), Vector2(-1,0)*strength, time*0.1)
+ tween.tween_method(bound_multitween, Vector2(), Vector2(1, 0)*strength, time*0.1)
+ tween.tween_method(bound_multitween, Vector2(), Vector2(-1,0)*strength, time*0.1)
+ tween.tween_method(bound_multitween, Vector2(), Vector2(1, 0)*strength, time*0.2)
tween.finished.connect(emit_signal.bind('finished_once'))
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "shake x": {"type": AnimationType.ACTION},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/shake_y.gd b/addons/dialogic/Modules/Character/DefaultAnimations/shake_y.gd
index 63f78ba5c..6a0224c46 100644
--- a/addons/dialogic/Modules/Character/DefaultAnimations/shake_y.gd
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/shake_y.gd
@@ -1,17 +1,23 @@
extends DialogicAnimation
-func animate():
+func animate() -> void:
var tween := (node.create_tween() as Tween)
tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_SINE)
-
- var strength :float = node.get_viewport().size.y/40
- tween.tween_property(node, 'position:y', orig_pos.y+strength, time*0.2)
- tween.tween_property(node, 'position:y', orig_pos.y-strength, time*0.1)
- tween.tween_property(node, 'position:y', orig_pos.y+strength, time*0.1)
- tween.tween_property(node, 'position:y', orig_pos.y-strength, time*0.1)
- tween.tween_property(node, 'position:y', orig_pos.y+strength, time*0.1)
- tween.tween_property(node, 'position:y', orig_pos.y-strength, time*0.1)
- tween.tween_property(node, 'position:y', orig_pos.y+strength, time*0.1)
- tween.tween_property(node, 'position:y', orig_pos.y, time*0.2)
-
+
+ var strength: float = node.get_viewport().size.y/40
+ tween.tween_property(node, 'position:y', base_position.y + strength, time * 0.2)
+ tween.tween_property(node, 'position:y', base_position.y - strength, time * 0.1)
+ tween.tween_property(node, 'position:y', base_position.y + strength, time * 0.1)
+ tween.tween_property(node, 'position:y', base_position.y - strength, time * 0.1)
+ tween.tween_property(node, 'position:y', base_position.y + strength, time * 0.1)
+ tween.tween_property(node, 'position:y', base_position.y - strength, time * 0.1)
+ tween.tween_property(node, 'position:y', base_position.y + strength, time * 0.1)
+ tween.tween_property(node, 'position:y', base_position.y, time * 0.2)
+
tween.finished.connect(emit_signal.bind('finished_once'))
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "shake y": {"type": AnimationType.ACTION},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/slide_down_in_out.gd b/addons/dialogic/Modules/Character/DefaultAnimations/slide_down_in_out.gd
new file mode 100644
index 000000000..af0124812
--- /dev/null
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/slide_down_in_out.gd
@@ -0,0 +1,26 @@
+extends DialogicAnimation
+
+func animate() -> void:
+ var tween := (node.create_tween() as Tween)
+ tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
+
+ var target_position := base_position.y
+ var start_position: float = -node.get_viewport().size.y
+
+ if is_reversed:
+ target_position = -node.get_viewport().size.y
+ start_position = base_position.y
+
+ node.position.y = start_position
+
+ tween.tween_property(node, 'position:y', target_position, time)
+
+ await tween.finished
+ finished_once.emit()
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "slide in down": {"reversed": false, "type": AnimationType.IN},
+ "slide out up": {"reversed": true, "type": AnimationType.OUT},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/slide_in_down.gd b/addons/dialogic/Modules/Character/DefaultAnimations/slide_in_down.gd
deleted file mode 100644
index d448e1284..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/slide_in_down.gd
+++ /dev/null
@@ -1,10 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
-
- node.position.y = -node.get_viewport().size.y
- tween.tween_property(node, 'position:y', end_position.y, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/slide_in_left.gd b/addons/dialogic/Modules/Character/DefaultAnimations/slide_in_left.gd
deleted file mode 100644
index 77bf984f3..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/slide_in_left.gd
+++ /dev/null
@@ -1,10 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
-
- node.position.x = -node.get_viewport().size.x/5
- tween.tween_property(node, 'position:x', end_position.x, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/slide_in_right.gd b/addons/dialogic/Modules/Character/DefaultAnimations/slide_in_right.gd
deleted file mode 100644
index 7df50cdc2..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/slide_in_right.gd
+++ /dev/null
@@ -1,10 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
-
- node.position.x = node.get_viewport().size.x+node.get_viewport().size.x/5
- tween.tween_property(node, 'position:x', end_position.x, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/slide_in_up.gd b/addons/dialogic/Modules/Character/DefaultAnimations/slide_in_up.gd
deleted file mode 100644
index 9c48695a4..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/slide_in_up.gd
+++ /dev/null
@@ -1,10 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
-
- node.position.y = node.get_viewport().size.y*2
- tween.tween_property(node, 'position:y', end_position.y, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/slide_left_in_out.gd b/addons/dialogic/Modules/Character/DefaultAnimations/slide_left_in_out.gd
new file mode 100644
index 000000000..f0d7df38a
--- /dev/null
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/slide_left_in_out.gd
@@ -0,0 +1,26 @@
+extends DialogicAnimation
+
+
+func animate() -> void:
+ var tween := (node.create_tween() as Tween)
+ tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
+
+ var end_position_x: float = base_position.x
+
+ if is_reversed:
+ end_position_x = -node.get_viewport().size.x / 2
+
+ else:
+ node.position.x = -node.get_viewport().size.x / 5
+
+ tween.tween_property(node, 'position:x', end_position_x, time)
+
+ await tween.finished
+ finished_once.emit()
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "slide in left": {"reversed": false, "type": AnimationType.IN},
+ "slide out right": {"reversed": true, "type": AnimationType.OUT},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/slide_out_down.gd b/addons/dialogic/Modules/Character/DefaultAnimations/slide_out_down.gd
deleted file mode 100644
index 66de11015..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/slide_out_down.gd
+++ /dev/null
@@ -1,9 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- tween.set_ease(Tween.EASE_IN).set_trans(Tween.TRANS_EXPO)
-
- tween.tween_property(node, 'position:y', node.get_viewport().size.y*2, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/slide_out_left.gd b/addons/dialogic/Modules/Character/DefaultAnimations/slide_out_left.gd
deleted file mode 100644
index 123b84412..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/slide_out_left.gd
+++ /dev/null
@@ -1,9 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- tween.set_ease(Tween.EASE_IN).set_trans(Tween.TRANS_EXPO)
-
- tween.tween_property(node, 'position:x', -node.get_viewport().size.x/5, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/slide_out_right.gd b/addons/dialogic/Modules/Character/DefaultAnimations/slide_out_right.gd
deleted file mode 100644
index 102412470..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/slide_out_right.gd
+++ /dev/null
@@ -1,9 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- tween.set_ease(Tween.EASE_IN).set_trans(Tween.TRANS_EXPO)
-
- tween.tween_property(node, 'position:x', node.get_viewport().size.x+node.get_viewport().size.x/5, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/slide_out_up.gd b/addons/dialogic/Modules/Character/DefaultAnimations/slide_out_up.gd
deleted file mode 100644
index 1eeeeeffd..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/slide_out_up.gd
+++ /dev/null
@@ -1,9 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_EXPO)
-
- tween.tween_property(node, 'position:y', -node.get_viewport().size.y, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/slide_right_in_out.gd b/addons/dialogic/Modules/Character/DefaultAnimations/slide_right_in_out.gd
new file mode 100644
index 000000000..3e4a5a4bb
--- /dev/null
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/slide_right_in_out.gd
@@ -0,0 +1,27 @@
+extends DialogicAnimation
+
+func animate() -> void:
+ var tween := (node.create_tween() as Tween)
+ tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
+
+ var viewport_x: float = node.get_viewport().size.x
+
+ var start_position_x: float = viewport_x + viewport_x / 5
+ var end_position_x := base_position.x
+
+ if is_reversed:
+ start_position_x = base_position.x
+ end_position_x = viewport_x + node.get_viewport().size.x / 5
+
+
+ node.position.x = start_position_x
+ tween.tween_property(node, 'position:x', end_position_x, time)
+
+ tween.finished.connect(emit_signal.bind('finished_once'))
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "slide in right": {"reversed": false, "type": AnimationType.IN},
+ "slide out left": {"reversed": true, "type": AnimationType.OUT},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/slide_up_in.gd b/addons/dialogic/Modules/Character/DefaultAnimations/slide_up_in.gd
new file mode 100644
index 000000000..fcb1e3376
--- /dev/null
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/slide_up_in.gd
@@ -0,0 +1,25 @@
+extends DialogicAnimation
+
+func animate() -> void:
+ var tween := (node.create_tween() as Tween)
+ tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
+
+ var start_position_y: float = node.get_viewport().size.y * 2
+ var end_position_y := base_position.y
+
+ if is_reversed:
+ start_position_y = base_position.y
+ end_position_y = node.get_viewport().size.y * 2
+
+ node.position.y = start_position_y
+ tween.tween_property(node, 'position:y', end_position_y, time)
+
+ await tween.finished
+ finished_once.emit()
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "slide in up": {"reversed": false, "type": AnimationType.IN},
+ "slide out down": {"reversed": true, "type": AnimationType.OUT},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/tada.gd b/addons/dialogic/Modules/Character/DefaultAnimations/tada.gd
index ee9f001ec..0d578b186 100644
--- a/addons/dialogic/Modules/Character/DefaultAnimations/tada.gd
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/tada.gd
@@ -1,11 +1,11 @@
extends DialogicAnimation
-func animate():
+func animate() -> void:
var tween := (node.create_tween() as Tween)
tween.set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_OUT)
-
- var strength :float = 0.01
-
+
+ var strength: float = 0.01
+
tween.set_parallel(true)
tween.tween_property(node, 'scale', Vector2(1,1)*(1+strength), time*0.3)
tween.tween_property(node, 'rotation', -strength, time*0.1).set_delay(time*0.2)
@@ -15,5 +15,11 @@ func animate():
tween.tween_property(node, 'rotation', -strength, time*0.1).set_delay(time*0.6)
tween.chain().tween_property(node, 'scale', Vector2(1,1), time*0.3)
tween.parallel().tween_property(node, 'rotation', 0.0, time*0.3)
-
+
tween.finished.connect(emit_signal.bind('finished_once'))
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "tada": {"type": AnimationType.ACTION},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/zoom_center_in_out.gd b/addons/dialogic/Modules/Character/DefaultAnimations/zoom_center_in_out.gd
new file mode 100644
index 000000000..fad8b614e
--- /dev/null
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/zoom_center_in_out.gd
@@ -0,0 +1,36 @@
+extends DialogicAnimation
+
+func animate() -> void:
+ var modulate_property := get_modulation_property()
+ var modulate_alpha_property := modulate_property + ":a"
+
+ var end_scale: Vector2 = node.scale
+ var end_modulation_alpha := 1.0
+
+ if is_reversed:
+ end_modulation_alpha = 0.0
+
+ else:
+ node.scale = Vector2(0, 0)
+ node.position.y = base_position.y - node.get_viewport().size.y * 0.5
+
+ var original_modulation: Color = node.get(modulate_property)
+ original_modulation.a = 0.0
+ node.set(modulate_property, original_modulation)
+
+ var tween := (node.create_tween() as Tween)
+ tween.set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_EXPO)
+ tween.set_parallel(true)
+ tween.tween_property(node, "scale", end_scale, time)
+ tween.tween_property(node, "position", base_position, time)
+ tween.tween_property(node, modulate_alpha_property, end_modulation_alpha, time)
+
+ await tween.finished
+ finished_once.emit()
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "zoom center in": {"reversed": false, "type": AnimationType.IN},
+ "zoom center out": {"reversed": true, "type": AnimationType.OUT},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/zoom_in.gd b/addons/dialogic/Modules/Character/DefaultAnimations/zoom_in.gd
deleted file mode 100644
index 749c2db7a..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/zoom_in.gd
+++ /dev/null
@@ -1,15 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- node.scale = Vector2(0,0)
- node.modulate.a = 0
- tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_EXPO)
- tween.set_parallel(true)
-
-# node.position.y = node.get_viewport().size.y/2
- tween.tween_property(node, 'scale', Vector2(1,1), time)
-# tween.tween_property(node, 'position:y', end_position.y, time)
- tween.tween_property(node, 'modulate:a', 1, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/zoom_in_center.gd b/addons/dialogic/Modules/Character/DefaultAnimations/zoom_in_center.gd
deleted file mode 100644
index 7472a196c..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/zoom_in_center.gd
+++ /dev/null
@@ -1,15 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- node.scale = Vector2(0,0)
- node.modulate.a = 0
- node.position = node.get_parent().size/2
- tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_EXPO)
- tween.set_parallel(true)
-
- tween.tween_property(node, 'scale', Vector2(1,1), time)
- tween.tween_property(node, 'position', end_position, time)
- tween.tween_property(node, 'modulate:a', 1, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/zoom_in_out.gd b/addons/dialogic/Modules/Character/DefaultAnimations/zoom_in_out.gd
new file mode 100644
index 000000000..21cc3382d
--- /dev/null
+++ b/addons/dialogic/Modules/Character/DefaultAnimations/zoom_in_out.gd
@@ -0,0 +1,35 @@
+extends DialogicAnimation
+
+func animate() -> void:
+ var modulate_property := get_modulation_property()
+ var modulate_alpha_property := modulate_property + ":a"
+
+ var end_scale: Vector2 = node.scale
+ var end_modulation_alpha := 1.0
+
+ if is_reversed:
+ end_scale = Vector2(0, 0)
+ end_modulation_alpha = 0.0
+
+ else:
+ node.scale = Vector2(0,0)
+
+ var original_modulation: Color = node.get(modulate_property)
+ original_modulation.a = 0.0
+ node.set(modulate_property, original_modulation)
+
+ var tween := (node.create_tween() as Tween)
+ tween.set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_EXPO)
+ tween.set_parallel(true)
+ tween.tween_property(node, "scale", end_scale, time)
+ tween.tween_property(node, modulate_alpha_property, end_modulation_alpha, time)
+
+ await tween.finished
+ finished_once.emit()
+
+
+func _get_named_variations() -> Dictionary:
+ return {
+ "zoom in": {"reversed": false, "type": AnimationType.IN},
+ "zoom out": {"reversed": true, "type": AnimationType.OUT},
+ }
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/zoom_out.gd b/addons/dialogic/Modules/Character/DefaultAnimations/zoom_out.gd
deleted file mode 100644
index dedf61900..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/zoom_out.gd
+++ /dev/null
@@ -1,13 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- tween.set_ease(Tween.EASE_IN).set_trans(Tween.TRANS_EXPO)
- tween.set_parallel(true)
-
-# node.position.y = node.get_viewport().size.y/2
- tween.tween_property(node, 'scale', Vector2(0,0), time)
-# tween.tween_property(node, 'position:y', end_position.y, time)
- tween.tween_property(node, 'modulate:a', 0, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DefaultAnimations/zoom_out_center.gd b/addons/dialogic/Modules/Character/DefaultAnimations/zoom_out_center.gd
deleted file mode 100644
index 1860259e3..000000000
--- a/addons/dialogic/Modules/Character/DefaultAnimations/zoom_out_center.gd
+++ /dev/null
@@ -1,12 +0,0 @@
-extends DialogicAnimation
-
-func animate():
- var tween := (node.create_tween() as Tween)
- tween.set_ease(Tween.EASE_IN).set_trans(Tween.TRANS_EXPO)
- tween.set_parallel(true)
-
- tween.tween_property(node, 'scale', Vector2(0,0), time)
- tween.tween_property(node, 'position', node.get_parent().size/2, time)
- tween.tween_property(node, 'modulate:a', 0, time)
-
- tween.finished.connect(emit_signal.bind('finished_once'))
diff --git a/addons/dialogic/Modules/Character/DialogicPortraitAnimationsUtil.gd b/addons/dialogic/Modules/Character/DialogicPortraitAnimationsUtil.gd
new file mode 100644
index 000000000..66908e330
--- /dev/null
+++ b/addons/dialogic/Modules/Character/DialogicPortraitAnimationsUtil.gd
@@ -0,0 +1,47 @@
+@tool
+class_name DialogicPortraitAnimationUtil
+
+enum AnimationType {ALL=-1, IN=1, OUT=2, ACTION=3, CROSSFADE=4}
+
+
+static func guess_animation(string:String, type := AnimationType.ALL) -> String:
+ var default := {}
+ var filter := {}
+ var ignores := []
+ match type:
+ AnimationType.ALL:
+ pass
+ AnimationType.IN:
+ filter = {"type":AnimationType.IN}
+ ignores = ["in"]
+ AnimationType.OUT:
+ filter = {"type":AnimationType.OUT}
+ ignores = ["out"]
+ AnimationType.ACTION:
+ filter = {"type":AnimationType.ACTION}
+ AnimationType.CROSSFADE:
+ filter = {"type":AnimationType.CROSSFADE}
+ ignores = ["cross"]
+ return DialogicResourceUtil.guess_special_resource(&"PortraitAnimation", string, default, filter, ignores).get("path", "")
+
+
+static func get_portrait_animations_filtered(type := AnimationType.ALL) -> Dictionary:
+ var filter := {"type":type}
+ if type == AnimationType.ALL:
+ filter["type"] = [AnimationType.IN, AnimationType.OUT, AnimationType.ACTION]
+ return DialogicResourceUtil.list_special_resources("PortraitAnimation", filter)
+
+
+static func get_suggestions(_search_text := "", current_value:= "", empty_text := "Default", action := AnimationType.ALL) -> Dictionary:
+ var suggestions := {}
+
+ if empty_text and current_value:
+ suggestions[empty_text] = {'value':"", 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
+
+ for anim_name in get_portrait_animations_filtered(action):
+ suggestions[DialogicUtil.pretty_name(anim_name)] = {
+ 'value' : DialogicUtil.pretty_name(anim_name),
+ 'editor_icon' : ["Animation", "EditorIcons"]
+ }
+
+ return suggestions
diff --git a/addons/dialogic/Modules/Character/class_dialogic_animation.gd b/addons/dialogic/Modules/Character/class_dialogic_animation.gd
index b050c0286..9792ab237 100644
--- a/addons/dialogic/Modules/Character/class_dialogic_animation.gd
+++ b/addons/dialogic/Modules/Character/class_dialogic_animation.gd
@@ -3,45 +3,75 @@ extends Node
## Class that can be used to animate portraits. Can be extended to create animations.
+enum AnimationType {IN=1, OUT=2, ACTION=3, CROSSFADE=4}
+
signal finished_once
signal finished
## Set at runtime, will be the node to animate.
-var node :Node
+var node: Node
+
## Set at runtime, will be the length of the animation.
-var time : float
-## Set at runtime, will be the position at which to end the animation.
-var end_position : Vector2
-## Set at runtime. The position the node started at.
-var orig_pos : Vector2
+var time: float
+
+## Set at runtime, will be the base position of the node.
+## Depending on the animation, this might be the start, end or both.
+var base_position: Vector2
+## Set at runtime, will be the base scale of the node.
+var base_scale: Vector2
## Used to repeate the animation for a number of times.
-var repeats : int
+var repeats: int
+## If `true`, the animation will be reversed.
+## This must be implemented by each animation or it will have no effect.
+var is_reversed: bool = false
-func _ready():
- connect('finished_once', finished_one_loop)
+
+func _ready() -> void:
+ finished_once.connect(finished_one_loop)
## To be overridden. Do the actual animating/tweening in here.
-## Use the properties [node], [time], [end_position], [orig_pos].
-func animate():
+## Use the properties [member node], [member time], [member base_position], etc.
+func animate() -> void:
pass
-func finished_one_loop():
+## This method controls whether to repeat the animation or not.
+## Animations must call this once they finished an animation.
+func finished_one_loop() -> void:
repeats -= 1
+
if repeats > 0:
animate()
- elif repeats == 0:
- emit_signal("finished")
+ else:
+ finished.emit()
-func pause():
+
+func pause() -> void:
if node:
node.process_mode = Node.PROCESS_MODE_DISABLED
-func resume():
+func resume() -> void:
if node:
node.process_mode = Node.PROCESS_MODE_INHERIT
+
+
+func _get_named_variations() -> Dictionary:
+ return {}
+
+
+## If the animation wants to change the modulation, this method
+## will return the property to change.
+##
+## The [class CanvasGroup] can use `self_modulate` instead of `modulate`
+## to uniformly change the modulation of all children without additively
+## overlaying the modulations.
+func get_modulation_property() -> String:
+ if node is CanvasGroup:
+ return "self_modulate"
+ else:
+ return "modulate"
diff --git a/addons/dialogic/Modules/Character/custom_portrait_thumbnail.png b/addons/dialogic/Modules/Character/custom_portrait_thumbnail.png
new file mode 100644
index 000000000..77d3cf323
Binary files /dev/null and b/addons/dialogic/Modules/Character/custom_portrait_thumbnail.png differ
diff --git a/addons/dialogic/Modules/Text/icon.png.import b/addons/dialogic/Modules/Character/custom_portrait_thumbnail.png.import
similarity index 62%
rename from addons/dialogic/Modules/Text/icon.png.import
rename to addons/dialogic/Modules/Character/custom_portrait_thumbnail.png.import
index 7a22d4c56..c570321de 100644
--- a/addons/dialogic/Modules/Text/icon.png.import
+++ b/addons/dialogic/Modules/Character/custom_portrait_thumbnail.png.import
@@ -2,16 +2,16 @@
importer="texture"
type="CompressedTexture2D"
-uid="uid://qjpkitm0gily"
-path="res://.godot/imported/icon.png-24a13267459b061f88f2248f23206b6d.ctex"
+uid="uid://c5tu88x32sjkf"
+path="res://.godot/imported/custom_portrait_thumbnail.png-0513583853d87342a634d56bc0bec965.ctex"
metadata={
"vram_texture": false
}
[deps]
-source_file="res://addons/dialogic/Modules/Text/icon.png"
-dest_files=["res://.godot/imported/icon.png-24a13267459b061f88f2248f23206b6d.ctex"]
+source_file="res://addons/dialogic/Modules/Character/custom_portrait_thumbnail.png"
+dest_files=["res://.godot/imported/custom_portrait_thumbnail.png-0513583853d87342a634d56bc0bec965.ctex"]
[params]
diff --git a/addons/dialogic/Modules/Character/default_portrait.gd b/addons/dialogic/Modules/Character/default_portrait.gd
index 25edb32e5..dcd89b01e 100644
--- a/addons/dialogic/Modules/Character/default_portrait.gd
+++ b/addons/dialogic/Modules/Character/default_portrait.gd
@@ -5,7 +5,7 @@ extends DialogicPortrait
## The parent class has a character and portrait variable.
@export_group('Main')
-@export_file var image : String = ""
+@export_file var image := ""
## Load anything related to the given character and portrait
diff --git a/addons/dialogic/Modules/Character/default_portrait_thumbnail.png b/addons/dialogic/Modules/Character/default_portrait_thumbnail.png
new file mode 100644
index 000000000..369a1118b
Binary files /dev/null and b/addons/dialogic/Modules/Character/default_portrait_thumbnail.png differ
diff --git a/addons/dialogic/Modules/Character/icon_character.png.import b/addons/dialogic/Modules/Character/default_portrait_thumbnail.png.import
similarity index 62%
rename from addons/dialogic/Modules/Character/icon_character.png.import
rename to addons/dialogic/Modules/Character/default_portrait_thumbnail.png.import
index 05efb2416..5ecc041b4 100644
--- a/addons/dialogic/Modules/Character/icon_character.png.import
+++ b/addons/dialogic/Modules/Character/default_portrait_thumbnail.png.import
@@ -2,16 +2,16 @@
importer="texture"
type="CompressedTexture2D"
-uid="uid://b1i3ttk36kghm"
-path="res://.godot/imported/icon_character.png-df3b6adf2508bd6ab91af526266b4aaa.ctex"
+uid="uid://b0eisk30btlx2"
+path="res://.godot/imported/default_portrait_thumbnail.png-f9f92adb946f409def18655d6ab5c5df.ctex"
metadata={
"vram_texture": false
}
[deps]
-source_file="res://addons/dialogic/Modules/Character/icon_character.png"
-dest_files=["res://.godot/imported/icon_character.png-df3b6adf2508bd6ab91af526266b4aaa.ctex"]
+source_file="res://addons/dialogic/Modules/Character/default_portrait_thumbnail.png"
+dest_files=["res://.godot/imported/default_portrait_thumbnail.png-f9f92adb946f409def18655d6ab5c5df.ctex"]
[params]
diff --git a/addons/dialogic/Modules/Character/dialogic_portrait.gd b/addons/dialogic/Modules/Character/dialogic_portrait.gd
index 438506d60..b2bf47ad4 100644
--- a/addons/dialogic/Modules/Character/dialogic_portrait.gd
+++ b/addons/dialogic/Modules/Character/dialogic_portrait.gd
@@ -12,11 +12,12 @@ var portrait: String
################################################################################
## This function can be overridden.
-## If this returns true, it won't insatnce a new scene, but call _update_portrait on this one.
+## If this returns true, it won't instance a new scene, but call
+## [method _update_portrait] on this one.
## This is only relevant if the next portrait uses the same scene.
-## This allows implmenting transitions between portraits that use the same scene.
-func _should_do_portrait_update(character:DialogicCharacter, portrait:String) -> bool:
- return true
+## This allows implementing transitions between portraits that use the same scene.
+func _should_do_portrait_update(_character: DialogicCharacter, _portrait: String) -> bool:
+ return false
## If the custom portrait accepts a change, then accept it here
@@ -25,17 +26,18 @@ func _should_do_portrait_update(character:DialogicCharacter, portrait:String) ->
## >>> $Sprite.position = $Sprite.get_rect().size * Vector2(-0.5, -1)
##
## * this depends on the portrait containers, but it will most likely be the bottom center (99% of cases)
-func _update_portrait(passed_character:DialogicCharacter, passed_portrait:String) -> void:
+func _update_portrait(_passed_character: DialogicCharacter, _passed_portrait: String) -> void:
pass
## This should be implemented. It is used for sizing in the
-## character editor preview and in portrait containers.
-## Scale and offset will be applied by dialogic.
-## For example for a simple sprite this should work:
+## character editor preview and in portrait containers.
+## Scale and offset will be applied by Dialogic.
+## For example, a simple sprite:
## >>> return Rect2($Sprite.position, $Sprite.get_rect().size)
##
-## This will only work as expected if the portrait is positioned so that the root is at the pivot point.
+## This will only work as expected if the portrait is positioned so that the
+## root is at the pivot point.
##
## If you've used apply_texture this should work automatically.
func _get_covered_rect() -> Rect2:
@@ -55,7 +57,7 @@ func _set_mirror(mirror:bool) -> void:
## Function to accept and use the extra data, if the custom portrait wants to accept it
-func _set_extra_data(data: String) -> void:
+func _set_extra_data(_data: String) -> void:
pass
#endregion
diff --git a/addons/dialogic/Modules/Character/event_character.gd b/addons/dialogic/Modules/Character/event_character.gd
index 154287059..1294d51e0 100644
--- a/addons/dialogic/Modules/Character/event_character.gd
+++ b/addons/dialogic/Modules/Character/event_character.gd
@@ -5,45 +5,75 @@ extends DialogicEvent
enum Actions {JOIN, LEAVE, UPDATE}
-
### Settings
## The type of action of this event (JOIN/LEAVE/UPDATE). See [Actions].
-var action : int = Actions.JOIN
+var action := Actions.JOIN
## The character that will join/leave/update.
-var character : DialogicCharacter = null
+var character: DialogicCharacter = null
## For Join/Update, this will be the portrait of the character that is shown.
## Not used on Leave.
## If empty, the default portrait will be used.
-var portrait: String = ""
+var portrait := ""
## The index of the position this character should move to
-var position: int = 1
+var transform := "center"
+
## Name of the animation script (extending DialogicAnimation).
## On Join/Leave empty (default) will fallback to the animations set in the settings.
## On Update empty will mean no animation.
-var animation_name: String = ""
+var animation_name := ""
## Length of the animation.
var animation_length: float = 0.5
## How often the animation is repeated. Only for Update events.
var animation_repeats: int = 1
## If true, the events waits for the animation to finish before the next event starts.
-var animation_wait: bool = false
+var animation_wait := false
+
+## The fade animation to use. If left empty, the default cross-fade animation AND time will be used.
+var fade_animation := ""
+var fade_length := 0.5
+
## For Update only. If bigger then 0, the portrait will tween to the
## new position (if changed) in this time (in seconds).
-var position_move_time: float = 0.0
+var transform_time: float = 0.0
+var transform_ease := Tween.EaseType.EASE_IN_OUT
+var transform_trans := Tween.TransitionType.TRANS_SINE
+
+var ease_options := [
+ {'label': 'In', 'value': Tween.EASE_IN},
+ {'label': 'Out', 'value': Tween.EASE_OUT},
+ {'label': 'In_Out', 'value': Tween.EASE_IN_OUT},
+ {'label': 'Out_In', 'value': Tween.EASE_OUT_IN},
+ ]
+
+var trans_options := [
+ {'label': 'Linear', 'value': Tween.TRANS_LINEAR},
+ {'label': 'Sine', 'value': Tween.TRANS_SINE},
+ {'label': 'Quint', 'value': Tween.TRANS_QUINT},
+ {'label': 'Quart', 'value': Tween.TRANS_QUART},
+ {'label': 'Quad', 'value': Tween.TRANS_QUAD},
+ {'label': 'Expo', 'value': Tween.TRANS_EXPO},
+ {'label': 'Elastic', 'value': Tween.TRANS_ELASTIC},
+ {'label': 'Cubic', 'value': Tween.TRANS_CUBIC},
+ {'label': 'Circ', 'value': Tween.TRANS_CIRC},
+ {'label': 'Bounce', 'value': Tween.TRANS_BOUNCE},
+ {'label': 'Back', 'value': Tween.TRANS_BACK},
+ {'label': 'Spring', 'value': Tween.TRANS_SPRING}
+ ]
+
## The z_index that the portrait should have.
var z_index: int = 0
## If true, the portrait will be set to mirrored.
-var mirrored: bool = false
+var mirrored := false
## If set, will be passed to the portrait scene.
-var extra_data: String = ""
+var extra_data := ""
### Helpers
## Indicators for whether something should be updated (UPDATE mode only)
var set_portrait := false
-var set_position := false
+var set_transform := false
var set_z_index := false
var set_mirrored := false
## Used to set the character resource from the unique name identifier and vice versa
@@ -60,112 +90,107 @@ var character_identifier: String:
character_identifier = value
character = DialogicResourceUtil.get_character_resource(value)
-# Reference regex without Godot escapes: (?Join|Update|Leave)\s*(")?(?(?(2)[^"\n]*|[^(: \n]*))(?(2)"|)(\W*\((?.*)\))?(\s*(?\d))?(\s*\[(?.*)\])?
-var regex := RegEx.create_from_string("(?join|update|leave)\\s*(\")?(?(?(2)[^\"\\n]*|[^(: \\n]*))(?(2)\"|)(\\W*\\((?.*)\\))?(\\s*(?\\d))?(\\s*\\[(?.*)\\])?")
+var regex := RegEx.create_from_string(r'(?join|update|leave)\s*(")?(?(?(2)[^"\n]*|[^(: \n]*))(?(2)"|)(\W*\((?.*)\))?(\s*(?[^\[]*))?(\s*\[(?.*)\])?')
################################################################################
## EXECUTION
################################################################################
func _execute() -> void:
- match action:
- Actions.JOIN:
- if character:
- if dialogic.has_subsystem('History') and !dialogic.Portraits.is_character_joined(character):
- var character_name_text := dialogic.Text.get_character_name_parsed(character)
- dialogic.History.store_simple_history_entry(character_name_text + " joined", event_name, {'character': character_name_text, 'mode':'Join'})
-
- var final_animation_length: float = animation_length
+ if not character and not character_identifier == "--All--":
+ finish()
+ return
- if dialogic.Inputs.auto_skip.enabled:
- var max_time: float = dialogic.Inputs.auto_skip.time_per_event
- final_animation_length = min(max_time, animation_length)
+ # Calculate animation time (can be shortened during skipping)
+ var final_animation_length: float = animation_length
+ var final_position_move_time: float = transform_time
+ if dialogic.Inputs.auto_skip.enabled:
+ var max_time: float = dialogic.Inputs.auto_skip.time_per_event
+ final_animation_length = min(max_time, animation_length)
+ final_position_move_time = min(max_time, transform_time)
- await dialogic.Portraits.join_character(
- character, portrait, position,
- mirrored, z_index, extra_data,
- animation_name, final_animation_length, animation_wait)
- Actions.LEAVE:
- var final_animation_length: float = animation_length
+ # JOIN -------------------------------------
+ if action == Actions.JOIN:
+ if dialogic.has_subsystem('History') and !dialogic.Portraits.is_character_joined(character):
+ var character_name_text := dialogic.Text.get_character_name_parsed(character)
+ dialogic.History.store_simple_history_entry(character_name_text + " joined", event_name, {'character': character_name_text, 'mode':'Join'})
- if dialogic.Inputs.auto_skip.enabled:
- var max_time: float = dialogic.Inputs.auto_skip.time_per_event
- final_animation_length = min(max_time, animation_length)
+ await dialogic.Portraits.join_character(
+ character, portrait, transform,
+ mirrored, z_index, extra_data,
+ animation_name, final_animation_length, animation_wait)
- if character_identifier == '--All--':
+ # LEAVE -------------------------------------
+ elif action == Actions.LEAVE:
+ if character_identifier == '--All--':
+ if dialogic.has_subsystem('History') and len(dialogic.Portraits.get_joined_characters()):
+ dialogic.History.store_simple_history_entry("Everyone left", event_name, {'character': "All", 'mode':'Leave'})
- if dialogic.has_subsystem('History') and len(dialogic.Portraits.get_joined_characters()):
- dialogic.History.store_simple_history_entry("Everyone left", event_name, {'character': "All", 'mode':'Leave'})
+ await dialogic.Portraits.leave_all_characters(
+ animation_name,
+ final_animation_length,
+ animation_wait
+ )
- await dialogic.Portraits.leave_all_characters(
- animation_name,
- final_animation_length,
- animation_wait
- )
+ elif character:
+ if dialogic.has_subsystem('History') and dialogic.Portraits.is_character_joined(character):
+ var character_name_text := dialogic.Text.get_character_name_parsed(character)
+ dialogic.History.store_simple_history_entry(character_name_text+" left", event_name, {'character': character_name_text, 'mode':'Leave'})
- elif character:
- if dialogic.has_subsystem('History') and dialogic.Portraits.is_character_joined(character):
- var character_name_text := dialogic.Text.get_character_name_parsed(character)
- dialogic.History.store_simple_history_entry(character_name_text+" left", event_name, {'character': character_name_text, 'mode':'Leave'})
+ await dialogic.Portraits.leave_character(
+ character,
+ animation_name,
+ final_animation_length,
+ animation_wait
+ )
- await dialogic.Portraits.leave_character(
- character,
- animation_name,
- final_animation_length,
- animation_wait
- )
+ # UPDATE -------------------------------------
+ elif action == Actions.UPDATE:
+ if not character or not dialogic.Portraits.is_character_joined(character):
+ finish()
+ return
- Actions.UPDATE:
- if !character or !dialogic.Portraits.is_character_joined(character):
- finish()
- return
+ dialogic.Portraits.change_character_extradata(character, extra_data)
- if set_portrait:
- dialogic.Portraits.change_character_portrait(character, portrait, false)
+ if set_portrait:
+ dialogic.Portraits.change_character_portrait(character, portrait, fade_animation, fade_length)
- if set_mirrored:
- dialogic.Portraits.change_character_mirror(character, mirrored)
+ if set_mirrored:
+ dialogic.Portraits.change_character_mirror(character, mirrored)
- if set_z_index:
- dialogic.Portraits.change_character_z_index(character, z_index)
+ if set_z_index:
+ dialogic.Portraits.change_character_z_index(character, z_index)
- if set_position:
- var final_position_move_time: float = position_move_time
+ if set_transform:
+ dialogic.Portraits.move_character(character, transform, final_position_move_time, transform_ease, transform_trans)
- if dialogic.Inputs.auto_skip.enabled:
- var max_time: float = dialogic.Inputs.auto_skip.time_per_event
- final_position_move_time = min(max_time, position_move_time)
+ if animation_name:
+ var final_animation_repetitions: int = animation_repeats
- dialogic.Portraits.move_character(character, position, final_position_move_time)
-
- if animation_name:
- var final_animation_length: float = animation_length
- var final_animation_repitions: int = animation_repeats
+ if dialogic.Inputs.auto_skip.enabled:
+ var time_per_event: float = dialogic.Inputs.auto_skip.time_per_event
+ var time_for_repetitions: float = time_per_event / animation_repeats
+ final_animation_length = time_for_repetitions
- if dialogic.Inputs.auto_skip.enabled:
- var time_per_event: float = dialogic.Inputs.auto_skip.time_per_event
- var time_for_repitions: float = time_per_event / animation_repeats
- final_animation_length = time_for_repitions
+ var animation := dialogic.Portraits.animate_character(
+ character,
+ animation_name,
+ final_animation_length,
+ final_animation_repetitions,
+ )
- var anim: DialogicAnimation = dialogic.Portraits.animate_character(
- character,
- animation_name,
- final_animation_length,
- final_animation_repitions
- )
+ if animation_wait:
+ dialogic.current_state = DialogicGameHandler.States.ANIMATING
+ await animation.finished
+ dialogic.current_state = DialogicGameHandler.States.IDLE
- if animation_wait:
- dialogic.current_state = DialogicGameHandler.States.ANIMATING
- await anim.finished
- dialogic.current_state = DialogicGameHandler.States.IDLE
finish()
-################################################################################
-## INITIALIZE
-################################################################################
+#region INITIALIZE
+###############################################################################
func _init() -> void:
event_name = "Character"
@@ -175,15 +200,17 @@ func _init() -> void:
func _get_icon() -> Resource:
- return load(self.get_script().get_path().get_base_dir().path_join('icon_character.png'))
+ return load(self.get_script().get_path().get_base_dir().path_join('icon.svg'))
-################################################################################
-## SAVING/LOADING
+#endregion
+
+#region SAVING, LOADING, DEFAULTS
################################################################################
func to_text() -> String:
var result_string := ""
+ # ACTIONS
match action:
Actions.JOIN: result_string += "join "
Actions.LEAVE: result_string += "leave "
@@ -191,137 +218,105 @@ func to_text() -> String:
var default_values := DialogicUtil.get_custom_event_defaults(event_name)
- if character or character_identifier == '--All--':
- if action == Actions.LEAVE and character_identifier == '--All--':
- result_string += "--All--"
- else:
- var name := DialogicResourceUtil.get_unique_identifier(character.resource_path)
- if name.count(" ") > 0:
- name = '"' + name + '"'
- result_string += name
- if portrait.strip_edges() != default_values.get('portrait', '') and action != Actions.LEAVE and (action != Actions.UPDATE or set_portrait):
- result_string+= " ("+portrait+")"
-
- if action != Actions.LEAVE and (action != Actions.UPDATE or set_position):
- result_string += " "+str(position)
+ # CHARACTER IDENTIFIER
+ if action == Actions.LEAVE and character_identifier == '--All--':
+ result_string += "--All--"
+ elif character:
+ var name := DialogicResourceUtil.get_unique_identifier(character.resource_path)
- var shortcode := "["
- if animation_name:
- shortcode += 'animation="'+animation_name+'"'
+ if name.count(" ") > 0:
+ name = '"' + name + '"'
- if animation_length != default_values.get('animation_length', 0.5):
- shortcode += ' length="'+str(animation_length)+'"'
+ result_string += name
- if animation_wait != default_values.get('animation_wait', false):
- shortcode += ' wait="'+str(animation_wait)+'"'
+ # PORTRAIT
+ if portrait.strip_edges() != default_values.get('portrait', ''):
+ if action != Actions.LEAVE and (action != Actions.UPDATE or set_portrait):
+ result_string += " (" + portrait + ")"
- if animation_repeats != default_values.get('animation_repeats', 1) and action == Actions.UPDATE:
- shortcode += ' repeat="'+str(animation_repeats)+'"'
+ # TRANSFORM
+ if action == Actions.JOIN or (action == Actions.UPDATE and set_transform):
+ result_string += " " + str(transform)
- if z_index != default_values.get('z_index', 0) or (action == Actions.UPDATE and set_z_index):
- shortcode += ' z_index="' + str(z_index) + '"'
+ # SETS:
+ if action == Actions.JOIN or action == Actions.LEAVE:
+ set_mirrored = mirrored != default_values.get("mirrored", false)
+ set_z_index = z_index != default_values.get("z_index", 0)
- if mirrored != default_values.get('mirrored', false) or (action == Actions.UPDATE and set_mirrored):
- shortcode += ' mirrored="' + str(mirrored) + '"'
+ var shortcode := store_to_shortcode_parameters()
- if position_move_time != default_values.get('position_move_time', 0) and action == Actions.UPDATE and set_position:
- shortcode += ' move_time="' + str(position_move_time) + '"'
+ if shortcode != "":
+ result_string += " [" + shortcode + "]"
- if extra_data != "":
- shortcode += ' extra_data="' + extra_data + '"'
-
- shortcode += "]"
-
- if shortcode != "[]":
- result_string += " "+shortcode
return result_string
func from_text(string:String) -> void:
- var character_directory := DialogicResourceUtil.get_character_directory()
-
- # load default character
+ # Load default character
character = DialogicResourceUtil.get_character_resource(character_identifier)
var result := regex.search(string)
+ # ACTION
match result.get_string('type'):
- "join":
- action = Actions.JOIN
- "leave":
- action = Actions.LEAVE
- "update":
- action = Actions.UPDATE
-
- if result.get_string('name').strip_edges():
- if action == Actions.LEAVE and result.get_string('name').strip_edges() == "--All--":
- character_identifier = '--All--'
- else:
- var name := result.get_string('name').strip_edges()
- character = DialogicResourceUtil.get_character_resource(name)
-
-
- if !result.get_string('portrait').is_empty():
- portrait = result.get_string('portrait').strip_edges().trim_prefix('(').trim_suffix(')')
- set_portrait = true
+ "join": action = Actions.JOIN
+ "leave": action = Actions.LEAVE
+ "update": action = Actions.UPDATE
- if result.get_string('position'):
- position = int(result.get_string('position'))
- set_position = true
+ # CHARACTER
+ var given_name := result.get_string('name').strip_edges()
+ var given_portrait := result.get_string('portrait').strip_edges()
+ var given_transform := result.get_string('transform').strip_edges()
- if result.get_string('shortcode'):
- var shortcode_params = parse_shortcode_parameters(result.get_string('shortcode'))
- animation_name = shortcode_params.get('animation', '')
-
- var animLength = shortcode_params.get('length', '0.5').to_float()
- if typeof(animLength) == TYPE_FLOAT:
- animation_length = animLength
+ if given_name:
+ if action == Actions.LEAVE and given_name == "--All--":
+ character_identifier = '--All--'
else:
- animation_length = animLength.to_float()
+ character = DialogicResourceUtil.get_character_resource(given_name)
- animation_wait = DialogicUtil.str_to_bool(shortcode_params.get('wait', 'false'))
-
- #repeat is supported on Update, the other two should not be checking this
- if action == Actions.UPDATE:
- animation_repeats = int(shortcode_params.get('repeat', animation_repeats))
- position_move_time = float(shortcode_params.get('move_time', position_move_time))
+ # PORTRAIT
+ if given_portrait:
+ portrait = given_portrait.trim_prefix('(').trim_suffix(')')
+ set_portrait = true
- #move time is only supported on Update, but it isnt part of the animations so its separate
- if action == Actions.UPDATE:
- position_move_time = float(shortcode_params.get('move_time', position_move_time))
+ # TRANSFORM
+ if given_transform:
+ transform = given_transform
+ set_transform = true
- z_index = int(shortcode_params.get('z_index', z_index))
- set_z_index = shortcode_params.has('z_index')
+ # SHORTCODE
+ if not result.get_string('shortcode'):
+ return
- mirrored = DialogicUtil.str_to_bool(shortcode_params.get('mirrored', str(mirrored)))
- set_mirrored = shortcode_params.has('mirrored')
- extra_data = shortcode_params.get('extra_data', "")
+ load_from_shortcode_parameters(result.get_string('shortcode'))
-## this is only here to provide a list of default values
-## this way the module manager can add custom default overrides to this event.
-## this is also why some properties are commented out,
-## because it's not recommended to overwrite them this way
func get_shortcode_parameters() -> Dictionary:
return {
#param_name : property_info
- "action" : {"property": "action", "default": 0,
+ "action" : {"property": "action", "default": 0, "custom_stored":true,
"suggestions": func(): return {'Join':
{'value':Actions.JOIN},
'Leave':{'value':Actions.LEAVE},
'Update':{'value':Actions.UPDATE}}},
- "character" : {"property": "character_identifier", "default": ""},
- "portrait" : {"property": "portrait", "default": ""},
- "position" : {"property": "position", "default": 1},
+ "character" : {"property": "character_identifier", "default": "", "custom_stored":true,},
+ "portrait" : {"property": "portrait", "default": "", "custom_stored":true,},
+ "transform" : {"property": "transform", "default": "center", "custom_stored":true,},
-# "animation_name" : {"property": "animation_name", "default": ""},
- "animation_length" : {"property": "animation_length", "default": 0.5},
- "animation_wait" : {"property": "animation_wait", "default": false},
- "animation_repeats" : {"property": "animation_repeats", "default": 1},
+ "animation" : {"property": "animation_name", "default": ""},
+ "length" : {"property": "animation_length", "default": 0.5},
+ "wait" : {"property": "animation_wait", "default": false},
+ "repeat" : {"property": "animation_repeats", "default": 1},
"z_index" : {"property": "z_index", "default": 0},
- "move_time" : {"property": "position_move_time", "default": 0.0},
"mirrored" : {"property": "mirrored", "default": false},
+ "fade" : {"property": "fade_animation", "default":""},
+ "fade_length" : {"property": "fade_length", "default":0.5},
+ "move_time" : {"property": "transform_time", "default": 0.0},
+ "move_ease" : {"property": "transform_ease", "default": Tween.EaseType.EASE_IN_OUT,
+ "suggestions": func(): return list_to_suggestions(ease_options)},
+ "move_trans" : {"property": "transform_trans", "default": Tween.TransitionType.TRANS_SINE,
+ "suggestions": func(): return list_to_suggestions(trans_options)},
"extra_data" : {"property": "extra_data", "default": ""},
}
@@ -331,6 +326,7 @@ func is_valid_event(string:String) -> bool:
return true
return false
+#endregion
################################################################################
## EDITOR REPRESENTATION
@@ -363,7 +359,6 @@ func build_event_editor() -> void:
'suggestions_func' : get_character_suggestions,
'icon' : load("res://addons/dialogic/Editor/Images/Resources/character.svg"),
'autofocus' : true})
-# add_header_button('', _on_character_edit_pressed, 'Edit character', ["ExternalLink", "EditorIcons"], 'character != null and character_identifier != "--All--"')
add_header_edit('set_portrait', ValueType.BOOL_BUTTON,
{'icon':load("res://addons/dialogic/Modules/Character/update_portrait.svg"),
@@ -374,14 +369,28 @@ func build_event_editor() -> void:
'suggestions_func' : get_portrait_suggestions,
'icon' : load("res://addons/dialogic/Editor/Images/Resources/portrait.svg")},
'should_show_portrait_selector() and (action != Actions.UPDATE or set_portrait)')
- add_header_edit('set_position', ValueType.BOOL_BUTTON,
+ add_header_edit('set_transform', ValueType.BOOL_BUTTON,
{'icon': load("res://addons/dialogic/Modules/Character/update_position.svg"), 'tooltip':'Change Position'}, "character != null and !has_no_portraits() and action == Actions.UPDATE")
add_header_label('at position', 'character != null and !has_no_portraits() and action == Actions.JOIN')
- add_header_label('to position', 'character != null and !has_no_portraits() and action == Actions.UPDATE and set_position')
- add_header_edit('position', ValueType.NUMBER, {'mode':1},
- 'character != null and !has_no_portraits() and action != %s and (action != Actions.UPDATE or set_position)' %Actions.LEAVE)
+ add_header_label('to position', 'character != null and !has_no_portraits() and action == Actions.UPDATE and set_transform')
+ add_header_edit('transform', ValueType.DYNAMIC_OPTIONS,
+ {'placeholder' : 'center',
+ 'mode' : 0,
+ 'suggestions_func' : get_position_suggestions,
+ 'tooltip' : "You can use a predefined position or a custom transform like 'pos=x0.5y1 size=x0.5y1 rot=10'.\nLearn more about this in the documentation."},
+ 'character != null and !has_no_portraits() and action != %s and (action != Actions.UPDATE or set_transform)' %Actions.LEAVE)
# Body
+ add_body_edit('fade_animation', ValueType.DYNAMIC_OPTIONS,
+ {'left_text' : 'Fade:',
+ 'suggestions_func' : get_fade_suggestions,
+ 'editor_icon' : ["Animation", "EditorIcons"],
+ 'placeholder' : 'Default',
+ 'enable_pretty_name' : true},
+ 'should_show_fade_options()')
+ add_body_edit('fade_length', ValueType.NUMBER, {'left_text':'Length:', 'suffix':'s', "min":0},
+ 'should_show_fade_options() and !fade_animation.is_empty()')
+ add_body_line_break("should_show_fade_options()")
add_body_edit('animation_name', ValueType.DYNAMIC_OPTIONS,
{'left_text' : 'Animation:',
'suggestions_func' : get_animation_suggestions,
@@ -389,130 +398,148 @@ func build_event_editor() -> void:
'placeholder' : 'Default',
'enable_pretty_name' : true},
'should_show_animation_options()')
- add_body_edit('animation_length', ValueType.NUMBER, {'left_text':'Length:', 'suffix':'s'},
+ add_body_edit('animation_length', ValueType.NUMBER, {'left_text':'Length:', 'suffix':'s', "min":0},
'should_show_animation_options() and !animation_name.is_empty()')
add_body_edit('animation_wait', ValueType.BOOL, {'left_text':'Await end:'},
'should_show_animation_options() and !animation_name.is_empty()')
- add_body_edit('animation_repeats', ValueType.NUMBER, {'left_text':'Repeat:', 'mode':1},
+ add_body_edit('animation_repeats', ValueType.NUMBER, {'left_text':'Repeat:', 'mode':1, "min":1},
'should_show_animation_options() and !animation_name.is_empty() and action == %s)' %Actions.UPDATE)
add_body_line_break()
- add_body_edit('position_move_time', ValueType.NUMBER, {'left_text':'Movement duration:'},
- 'action == %s and set_position' %Actions.UPDATE)
+ add_body_edit('transform_time', ValueType.NUMBER, {'left_text':'Movement duration:', "min":0},
+ "should_show_transform_options()")
+ add_body_edit("transform_trans", ValueType.FIXED_OPTIONS, {'options':trans_options, 'left_text':"Trans:"}, 'should_show_transform_options() and transform_time > 0')
+ add_body_edit("transform_ease", ValueType.FIXED_OPTIONS, {'options':ease_options, 'left_text':"Ease:"}, 'should_show_transform_options() and transform_time > 0')
+
add_body_edit('set_z_index', ValueType.BOOL_BUTTON, {'icon':load("res://addons/dialogic/Modules/Character/update_z_index.svg"), 'tooltip':'Change Z-Index'}, "character != null and action == Actions.UPDATE")
add_body_edit('z_index', ValueType.NUMBER, {'left_text':'Z-index:', 'mode':1},
'action != %s and (action != Actions.UPDATE or set_z_index)' %Actions.LEAVE)
add_body_edit('set_mirrored', ValueType.BOOL_BUTTON, {'icon':load("res://addons/dialogic/Modules/Character/update_mirror.svg"), 'tooltip':'Change Mirroring'}, "character != null and action == Actions.UPDATE")
add_body_edit('mirrored', ValueType.BOOL, {'left_text':'Mirrored:'},
'action != %s and (action != Actions.UPDATE or set_mirrored)' %Actions.LEAVE)
+ add_body_edit('extra_data', ValueType.SINGLELINE_TEXT, {'left_text':'Extra Data:'}, 'action != Actions.LEAVE')
+
+
+func should_show_transform_options() -> bool:
+ return action == Actions.UPDATE and set_transform
func should_show_animation_options() -> bool:
- return (character != null and !character.portraits.is_empty()) or character_identifier == '--All--'
+ return (character and !character.portraits.is_empty()) or character_identifier == '--All--'
+
+
+func should_show_fade_options() -> bool:
+ return action == Actions.UPDATE and set_portrait and character and not character.portraits.is_empty()
+
func should_show_portrait_selector() -> bool:
- return character != null and len(character.portraits) > 1 and action != Actions.LEAVE
+ return character and len(character.portraits) > 1 and action != Actions.LEAVE
+
func has_no_portraits() -> bool:
return character and character.portraits.is_empty()
func get_character_suggestions(search_text:String) -> Dictionary:
- var suggestions := {}
- #override the previous _character_directory with the meta, specifically for searching otherwise new nodes wont work
-
- var icon = load("res://addons/dialogic/Editor/Images/Resources/character.svg")
-
- suggestions['(No one)'] = {'value':'', 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
- var character_directory = DialogicResourceUtil.get_character_directory()
- if action == Actions.LEAVE:
- suggestions['ALL'] = {'value':'--All--', 'tooltip':'All currently joined characters leave', 'editor_icon':["GuiEllipsis", "EditorIcons"]}
- for resource in character_directory.keys():
- suggestions[resource] = {'value': resource, 'tooltip': character_directory[resource], 'icon': icon.duplicate()}
- return suggestions
+ return DialogicUtil.get_character_suggestions(search_text, character, false, action == Actions.LEAVE, editor_node)
func get_portrait_suggestions(search_text:String) -> Dictionary:
- var suggestions := {}
- var icon = load("res://addons/dialogic/Editor/Images/Resources/portrait.svg")
- if action == Actions.UPDATE:
- suggestions["Don't Change"] = {'value':'', 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
+ var empty_text := "Don't Change"
if action == Actions.JOIN:
- suggestions["Default portrait"] = {'value':'', 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
- if character != null:
- for portrait in character.portraits:
- suggestions[portrait] = {'value':portrait, 'icon':icon.duplicate()}
- return suggestions
+ empty_text = "Default portrait"
+ return DialogicUtil.get_portrait_suggestions(search_text, character, true, empty_text)
-func get_animation_suggestions(search_text:String) -> Dictionary:
- var suggestions := {}
+func get_position_suggestions(search_text:String='') -> Dictionary:
+ return DialogicUtil.get_portrait_position_suggestions(search_text)
+
+func get_animation_suggestions(search_text:String='') -> Dictionary:
+ var DPAU := DialogicPortraitAnimationUtil
match action:
- Actions.JOIN, Actions.LEAVE:
- suggestions['Default'] = {'value':"", 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
+ Actions.JOIN:
+ return DPAU.get_suggestions(search_text, animation_name, "Default", DPAU.AnimationType.IN)
+ Actions.LEAVE:
+ return DPAU.get_suggestions(search_text, animation_name, "Default", DPAU.AnimationType.OUT)
Actions.UPDATE:
- suggestions['None'] = {'value':"", 'editor_icon':["GuiRadioUnchecked", "EditorIcons"]}
-
- for anim in DialogicUtil.get_portrait_animation_scripts(action+1):
- suggestions[DialogicUtil.pretty_name(anim)] = {'value':DialogicUtil.pretty_name(anim), 'editor_icon':["Animation", "EditorIcons"]}
+ return DPAU.get_suggestions(search_text, animation_name, "None", DPAU.AnimationType.ACTION)
+ return {}
- return suggestions
-
-func _on_character_edit_pressed() -> void:
- var editor_manager := _editor_node.find_parent('EditorsManager')
- if editor_manager:
- editor_manager.edit_resource(character)
+func get_fade_suggestions(search_text:String='') -> Dictionary:
+ return DialogicPortraitAnimationUtil.get_suggestions(search_text, fade_animation, "Default", DialogicPortraitAnimationUtil.AnimationType.CROSSFADE)
####################### CODE COMPLETION ########################################
################################################################################
-func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, word:String, symbol:String) -> void:
- if symbol == ' ' and line.count(' ') == 1:
+func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, _word:String, symbol:String) -> void:
+ var line_until_caret: String = CodeCompletionHelper.get_line_untill_caret(line)
+ if symbol == ' ' and line_until_caret.count(' ') == 1:
CodeCompletionHelper.suggest_characters(TextNode, CodeEdit.KIND_MEMBER)
if line.begins_with('leave'):
TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, 'All', '--All-- ', event_color, TextNode.get_theme_icon("GuiEllipsis", "EditorIcons"))
if symbol == '(':
- var character:= regex.search(line).get_string('name')
- CodeCompletionHelper.suggest_portraits(TextNode, character)
-
- if '[' in line and (symbol == "[" or symbol == " "):
- if !'animation=' in line:
- TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, 'animation', 'animation="', TextNode.syntax_highlighter.normal_color)
- if !'length=' in line:
- TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, 'length', 'length="', TextNode.syntax_highlighter.normal_color)
- if !'wait=' in line:
- TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, 'wait', 'wait="', TextNode.syntax_highlighter.normal_color)
- if line.begins_with('update'):
- if !'repeat=' in line:
- TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, 'repeat', 'repeat="', TextNode.syntax_highlighter.normal_color)
- if !'move_time=' in line:
- TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, 'move_time', 'move_time="', TextNode.syntax_highlighter.normal_color)
- if !line.begins_with('leave'):
- if !'mirrored=' in line:
- TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, 'mirrored', 'mirrored="', TextNode.syntax_highlighter.normal_color)
- if !'z_index=' in line:
- TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, 'z_index', 'z_index="', TextNode.syntax_highlighter.normal_color)
- TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, 'extra_data', 'extra_data="', TextNode.syntax_highlighter.normal_color)
-
- if '[' in line:
- if CodeCompletionHelper.get_line_untill_caret(line).ends_with('animation="'):
- var animations := []
- if line.begins_with('join'):
- animations = DialogicUtil.get_portrait_animation_scripts(DialogicUtil.AnimationType.IN)
- if line.begins_with('update'):
- animations = DialogicUtil.get_portrait_animation_scripts(DialogicUtil.AnimationType.ACTION)
- if line.begins_with('leave'):
- animations = DialogicUtil.get_portrait_animation_scripts(DialogicUtil.AnimationType.OUT)
- for script in animations:
- TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, DialogicUtil.pretty_name(script), DialogicUtil.pretty_name(script)+'" ', TextNode.syntax_highlighter.normal_color)
- elif CodeCompletionHelper.get_line_untill_caret(line).ends_with('wait="') or CodeCompletionHelper.get_line_untill_caret(line).ends_with('mirrored="'):
- CodeCompletionHelper.suggest_bool(TextNode, TextNode.syntax_highlighter.normal_color)
-
-
-func _get_start_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit) -> void:
+ var completion_character := regex.search(line).get_string('name')
+ CodeCompletionHelper.suggest_portraits(TextNode, completion_character)
+
+ elif not '[' in line_until_caret and symbol == ' ':
+ if not line.begins_with("leave"):
+ for position in get_position_suggestions():
+ TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, position, position+' ', TextNode.syntax_highlighter.normal_color)
+
+ # Shortcode Part
+ if '[' in line_until_caret:
+ # Suggest Parameters
+ if symbol == '[' or symbol == ' ' and line_until_caret.count('"')%2 == 0:# and (symbol == "[" or (symbol == " " and line_until_caret.rfind('="') < line_until_caret.rfind('"')-1)):
+ suggest_parameter("animation", line, TextNode)
+
+ if "animation=" in line:
+ for param in ["length", "wait"]:
+ suggest_parameter(param, line, TextNode)
+ if line.begins_with('update'):
+ suggest_parameter("repeat", line, TextNode)
+ if line.begins_with("update"):
+ for param in ["move_time", "move_trans", "move_ease"]:
+ suggest_parameter(param, line, TextNode)
+ if not line.begins_with('leave'):
+ for param in ["mirrored", "z_index", "extra_data"]:
+ suggest_parameter(param, line, TextNode)
+
+ # Suggest Values
+ else:
+ var current_param: RegExMatch = CodeCompletionHelper.completion_shortcode_param_getter_regex.search(line)
+ if not current_param:
+ return
+
+ match current_param.get_string("param"):
+ "animation":
+ var animations := {}
+ if line.begins_with('join'):
+ animations = DialogicPortraitAnimationUtil.get_portrait_animations_filtered(DialogicPortraitAnimationUtil.AnimationType.IN)
+ elif line.begins_with('update'):
+ animations = DialogicPortraitAnimationUtil.get_portrait_animations_filtered(DialogicPortraitAnimationUtil.AnimationType.ACTION)
+ elif line.begins_with('leave'):
+ animations = DialogicPortraitAnimationUtil.get_portrait_animations_filtered(DialogicPortraitAnimationUtil.AnimationType.OUT)
+
+ for script: String in animations:
+ TextNode.add_code_completion_option(CodeEdit.KIND_VARIABLE, DialogicUtil.pretty_name(script), DialogicUtil.pretty_name(script), TextNode.syntax_highlighter.normal_color, null, '" ')
+
+ "wait", "mirrored":
+ CodeCompletionHelper.suggest_bool(TextNode, TextNode.syntax_highlighter.normal_color)
+ "move_trans":
+ CodeCompletionHelper.suggest_custom_suggestions(list_to_suggestions(trans_options), TextNode, TextNode.syntax_highlighter.normal_color)
+ "move_ease":
+ CodeCompletionHelper.suggest_custom_suggestions(list_to_suggestions(ease_options), TextNode, TextNode.syntax_highlighter.normal_color)
+
+
+func suggest_parameter(parameter:String, line:String, TextNode:TextEdit) -> void:
+ if not parameter + "=" in line:
+ TextNode.add_code_completion_option(CodeEdit.KIND_MEMBER, parameter, parameter + '="', TextNode.syntax_highlighter.normal_color)
+
+
+func _get_start_code_completion(_CodeCompletionHelper:Node, TextNode:TextEdit) -> void:
TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'join', 'join ', event_color, load('res://addons/dialogic/Editor/Images/Dropdown/join.svg'))
TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'leave', 'leave ', event_color, load('res://addons/dialogic/Editor/Images/Dropdown/leave.svg'))
TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'update', 'update ', event_color, load('res://addons/dialogic/Editor/Images/Dropdown/update.svg'))
@@ -536,3 +563,13 @@ func _get_syntax_highlighting(Highlighter:SyntaxHighlighter, dict:Dictionary, li
if result.get_string('shortcode'):
dict = Highlighter.color_shortcode_content(dict, line, result.get_start('shortcode'), result.get_end('shortcode'), event_color)
return dict
+
+
+## HELPER
+func list_to_suggestions(list:Array) -> Dictionary:
+ return list.reduce(
+ func(accum, value):
+ accum[value.label] = value
+ accum[value.label]["text_alt"] = [value.label.to_lower()]
+ return accum,
+ {})
diff --git a/addons/dialogic/Modules/Character/event_position.gd b/addons/dialogic/Modules/Character/event_position.gd
deleted file mode 100644
index f46ae9af4..000000000
--- a/addons/dialogic/Modules/Character/event_position.gd
+++ /dev/null
@@ -1,110 +0,0 @@
-@tool
-class_name DialogicPositionEvent
-extends DialogicEvent
-
-## Event that allows moving of positions (and characters that are on that position).
-## Requires the Portraits subsystem to be present!
-
-enum Actions {SET_RELATIVE, SET_ABSOLUTE, RESET, RESET_ALL}
-
-
-### Settings
-
-## The type of action: SetRelative, SetAbsolute, Reset, ResetAll
-var action := Actions.SET_RELATIVE
-## The position that should be affected
-var position: int = 0
-## A vector representing a relative change or an absolute position (for SetRelative and SetAbsolute)
-var vector: Vector2 = Vector2()
-## The time the tweening will take.
-var movement_time: float = 0
-
-
-################################################################################
-## EXECUTE
-################################################################################
-func _execute() -> void:
- var final_movement_time: float = movement_time
-
- if dialogic.Inputs.auto_skip.enabled:
- var time_per_event: float = dialogic.Inputs.auto_skip.time_per_event
- final_movement_time = max(movement_time, time_per_event)
-
- match action:
- Actions.SET_RELATIVE:
- dialogic.Portraits.move_portrait_position(position, vector, true, final_movement_time)
- Actions.SET_ABSOLUTE:
- dialogic.Portraits.move_portrait_position(position, vector, false, final_movement_time)
- Actions.RESET_ALL:
- dialogic.Portraits.reset_all_portrait_positions(final_movement_time)
- Actions.RESET:
- dialogic.Portraits.reset_portrait_position(position, final_movement_time)
-
- finish()
-
-
-################################################################################
-## INITIALIZE
-################################################################################
-
-func _init() -> void:
- event_name = "Position"
- set_default_color('Color2')
- event_category = "Other"
- event_sorting_index = 2
-
-
-func _get_icon() -> Resource:
- return load(self.get_script().get_path().get_base_dir().path_join('event_portrait_position.svg'))
-
-################################################################################
-## SAVING/LOADING
-################################################################################
-
-func get_shortcode() -> String:
- return "update_position"
-
-
-func get_shortcode_parameters() -> Dictionary:
- return {
- #param_name : property_info
- "action" : {"property": "action", "default": Actions.SET_RELATIVE,
- "suggestions": func(): return {"Set Relative":{'value':0, 'text_alt':['set_relative', 'relative']}, "Set Absolute":{'value':1, 'text_alt':['set_absolute', 'absolute']}, "Reset":{'value':2,'text_alt':['reset'] }, "Reset All":{'value':3,'text_alt':['reset_all']}}},
- "position" : {"property": "position", "default": 0},
- "vector" : {"property": "vector", "default": Vector2()},
- "time" : {"property": "movement_time", "default": 0},
- }
-
-
-################################################################################
-## EDITOR REPRESENTATION
-################################################################################
-
-func build_event_editor():
- add_header_edit('action', ValueType.FIXED_OPTIONS, {
- 'options': [
- {
- 'label': 'Change',
- 'value': Actions.SET_RELATIVE,
- },
- {
- 'label': 'Set',
- 'value': Actions.SET_ABSOLUTE,
- },
- {
- 'label': 'Reset',
- 'value': Actions.RESET,
- },
- {
- 'label': 'Reset All',
- 'value': Actions.RESET_ALL,
- }
- ]
- })
- add_header_edit("position", ValueType.NUMBER, {'left_text':"position", 'mode':1},
- 'action != Actions.RESET_ALL')
- add_header_label('to (absolute)', 'action == Actions.SET_ABSOLUTE')
- add_header_label('by (relative)', 'action == Actions.SET_RELATIVE')
- add_header_edit("vector", ValueType.VECTOR2, {},
- 'action != Actions.RESET and action != Actions.RESET_ALL')
- add_body_edit("movement_time", ValueType.NUMBER, {'left_text':"AnimationTime:", "right_text":"(0 for instant)"})
diff --git a/addons/dialogic/Modules/Character/icon.svg b/addons/dialogic/Modules/Character/icon.svg
new file mode 100644
index 000000000..66382274d
--- /dev/null
+++ b/addons/dialogic/Modules/Character/icon.svg
@@ -0,0 +1,4 @@
+
diff --git a/addons/dialogic/Modules/Character/icon.svg.import b/addons/dialogic/Modules/Character/icon.svg.import
new file mode 100644
index 000000000..1c9857538
--- /dev/null
+++ b/addons/dialogic/Modules/Character/icon.svg.import
@@ -0,0 +1,38 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://q6lanmf18ii6"
+path="res://.godot/imported/icon.svg-4f340f6efbb83004dbd5c761dd1dc448.ctex"
+metadata={
+"has_editor_variant": true,
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/dialogic/Modules/Character/icon.svg"
+dest_files=["res://.godot/imported/icon.svg-4f340f6efbb83004dbd5c761dd1dc448.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
+svg/scale=1.0
+editor/scale_with_editor_scale=true
+editor/convert_colors_with_editor_theme=true
diff --git a/addons/dialogic/Modules/Character/icon_character.png b/addons/dialogic/Modules/Character/icon_character.png
deleted file mode 100644
index 585885474..000000000
Binary files a/addons/dialogic/Modules/Character/icon_character.png and /dev/null differ
diff --git a/addons/dialogic/Modules/Character/index.gd b/addons/dialogic/Modules/Character/index.gd
index 02fb5a0aa..805d62af8 100644
--- a/addons/dialogic/Modules/Character/index.gd
+++ b/addons/dialogic/Modules/Character/index.gd
@@ -3,12 +3,11 @@ extends DialogicIndexer
func _get_events() -> Array:
- return [this_folder.path_join('event_character.gd'), this_folder.path_join('event_position.gd')]
+ return [this_folder.path_join('event_character.gd')]
func _get_subsystems() -> Array:
- return [{'name':'Portraits', 'script':this_folder.path_join('subsystem_portraits.gd')}]
-
+ return [{'name':'Portraits', 'script':this_folder.path_join('subsystem_portraits.gd')}, {'name':'PortraitContainers', 'script':this_folder.path_join('subsystem_containers.gd')}]
func _get_settings_pages() -> Array:
return [this_folder.path_join('settings_portraits.tscn')]
@@ -17,5 +16,40 @@ func _get_text_effects() -> Array[Dictionary]:
return [{'command':'portrait', 'subsystem':'Portraits', 'method':'text_effect_portrait', 'arg':true}]
-func _get_special_resources() -> Array[Dictionary]:
- return list_special_resources('DefaultAnimations', &'PortraitAnimation')
+func _get_special_resources() -> Dictionary:
+ return {&'PortraitAnimation': list_animations("DefaultAnimations")}
+
+
+func _get_portrait_scene_presets() -> Array[Dictionary]:
+ return [
+ {
+ "path": "",
+ "name": "Default Scene",
+ "description": "The default scene defined in Settings>Portraits.",
+ "author":"Dialogic",
+ "type": "Default",
+ "icon":"",
+ "preview_image":[this_folder.path_join("default_portrait_thumbnail.png")],
+ "documentation":"",
+ },
+ {
+ "path": "CUSTOM",
+ "name": "Custom Scene",
+ "description": "A custom scene. Should extend DialogicPortrait and be in @tool mode.",
+ "author":"Dialogic",
+ "type": "Custom",
+ "icon":"",
+ "preview_image":[this_folder.path_join("custom_portrait_thumbnail.png")],
+ "documentation":"https://docs.dialogic.pro/custom-portraits.html",
+ },
+ {
+ "path": this_folder.path_join("default_portrait.tscn"),
+ "name": "Simple Image Portrait",
+ "description": "Can display images as portraits. Does nothing else.",
+ "author":"Dialogic",
+ "type": "General",
+ "icon":"",
+ "preview_image":[this_folder.path_join("simple_image_portrait_thumbnail.png")],
+ "documentation":"",
+ }
+ ]
diff --git a/addons/dialogic/Modules/Character/node_portrait_container.gd b/addons/dialogic/Modules/Character/node_portrait_container.gd
index 9a2307f36..5b483983b 100644
--- a/addons/dialogic/Modules/Character/node_portrait_container.gd
+++ b/addons/dialogic/Modules/Character/node_portrait_container.gd
@@ -2,18 +2,18 @@
class_name DialogicNode_PortraitContainer
extends Control
-## Node that defines a position for dialogic portraits and how to display portrait at that position.
+## Node that defines a position for dialogic portraits and how to display portraits at that position.
enum PositionModes {
- POSITION, ## This container has an index and can be joined/moved to with the Character Event
- SPEAKER, ## This container has no index and is joined/left automatically based on the speaker.
+ POSITION, ## This container can be joined/moved to with the Character Event
+ SPEAKER, ## This container is joined/left automatically based on the speaker.
}
@export var mode := PositionModes.POSITION
@export_subgroup('Mode: Position')
## The position this node corresponds to.
-@export var position_index := 0
+@export var container_ids: PackedStringArray = ["1"]
@export_subgroup('Mode: Speaker')
@@ -22,12 +22,17 @@ enum PositionModes {
@export var portrait_prefix := ''
@export_subgroup('Portrait Placement')
-enum SizeModes {KEEP, FIT_STRETCH, FIT_IGNORE_SCALE, FIT_SCALE_HEIGHT}
+enum SizeModes {
+ KEEP, ## The height and width of the container have no effect, only the origin.
+ FIT_STRETCH, ## The portrait will be fitted into the container, ignoring it's aspect ratio and the character/portrait scale.
+ FIT_IGNORE_SCALE, ## The portrait will be fitted into the container, ignoring the character/portrait scale, but preserving the aspect ratio.
+ FIT_SCALE_HEIGHT ## Recommended. The portrait will be scaled to fit the container height. A character/portrait scale of 100% means 100% container height. Aspect ratio will be preserved.
+ }
## Defines how to affect the scale of the portrait
-@export var size_mode : SizeModes = SizeModes.FIT_SCALE_HEIGHT :
+@export var size_mode: SizeModes = SizeModes.FIT_SCALE_HEIGHT :
set(mode):
size_mode = mode
- _update_debug_portrait_size_position()
+ _update_debug_portrait_transform()
## If true, portraits will be mirrored in this position.
@export var mirrored := false :
@@ -39,7 +44,7 @@ enum SizeModes {KEEP, FIT_STRETCH, FIT_IGNORE_SCALE, FIT_SCALE_HEIGHT}
@export_group('Origin', 'origin')
enum OriginAnchors {TOP_LEFT, TOP_CENTER, TOP_RIGHT, LEFT_MIDDLE, CENTER, RIGHT_MIDDLE, BOTTOM_LEFT, BOTTOM_CENTER, BOTTOM_RIGHT}
## The portrait will be placed relative to this point in the container.
-@export var origin_anchor : OriginAnchors = OriginAnchors.BOTTOM_CENTER :
+@export var origin_anchor: OriginAnchors = OriginAnchors.BOTTOM_CENTER :
set(anchor):
origin_anchor = anchor
_update_debug_origin()
@@ -50,27 +55,35 @@ enum OriginAnchors {TOP_LEFT, TOP_CENTER, TOP_RIGHT, LEFT_MIDDLE, CENTER, RIGHT_
origin_offset = offset
_update_debug_origin()
+enum PivotModes {AT_ORIGIN, PERCENTAGE, PIXELS}
+## Usually you want to rotate or scale around the portrait origin.
+## For the moments where that is not the case, set the mode to PERCENTAGE or PIXELS and use [member pivot_value].
+@export var pivot_mode: PivotModes = PivotModes.AT_ORIGIN
+## Only has an effect when [member pivot_mode] is not AT_ORIGIN. Meaning depends on whether [member pivot_mode] is PERCENTAGE or PIXELS.
+@export var pivot_value := Vector2()
@export_group('Debug', 'debug')
## A character that will be displayed in the editor, useful for getting the right size.
-@export var debug_character : DialogicCharacter = null:
+@export var debug_character: DialogicCharacter = null:
set(character):
debug_character = character
_update_debug_portrait_scene()
-@export var debug_character_portrait :String = "":
+@export var debug_character_portrait := "":
set(portrait):
debug_character_portrait = portrait
_update_debug_portrait_scene()
-var debug_character_holder_node :Node2D = null
-var debug_character_scene_node : Node = null
-var debug_origin : Sprite2D = null
-var default_portrait_scene :String = DialogicUtil.get_module_path('Character').path_join("default_portrait.tscn")
+var debug_character_holder_node: Node2D = null
+var debug_character_scene_node: Node = null
+var debug_origin: Sprite2D = null
+var default_portrait_scene: String = DialogicUtil.get_module_path('Character').path_join("default_portrait.tscn")
# Used if no debug character is specified
var default_debug_character := load(DialogicUtil.get_module_path('Character').path_join("preview_character.tres"))
+var ignore_resize := false
+
-func _ready():
+func _ready() -> void:
match mode:
PositionModes.POSITION:
add_to_group('dialogic_portrait_con_position')
@@ -85,7 +98,7 @@ func _ready():
debug_origin = Sprite2D.new()
add_child(debug_origin)
- debug_origin.texture = get_theme_icon("EditorPosition", "EditorIcons")
+ debug_origin.texture = load("res://addons/dialogic/Editor/Images/Dropdown/default.svg")
_update_debug_origin()
_update_debug_portrait_scene()
@@ -97,18 +110,30 @@ func _ready():
## MAIN METHODS
################################################################################
-func update_portrait_transforms():
+func update_portrait_transforms() -> void:
+ if ignore_resize:
+ return
+
+ match pivot_mode:
+ PivotModes.AT_ORIGIN:
+ pivot_offset = _get_origin_position()
+ PivotModes.PERCENTAGE:
+ pivot_offset = size*pivot_value
+ PivotModes.PIXELS:
+ pivot_offset = pivot_value
+
for child in get_children():
- DialogicUtil.autoload().Portraits._update_portrait_transform(child)
+ DialogicUtil.autoload().Portraits._update_character_transform(child)
+
## Returns a Rect2 with the position as the position and the scale as the size.
func get_local_portrait_transform(portrait_rect:Rect2, character_scale:=1.0) -> Rect2:
var transform := Rect2()
transform.position = _get_origin_position()
-
+
# Mode that ignores the containers size
if size_mode == SizeModes.KEEP:
- transform.size = Vector2(1,1)*character_scale
+ transform.size = Vector2(1,1) * character_scale
# Mode that makes sure neither height nor width go out of container
elif size_mode == SizeModes.FIT_IGNORE_SCALE:
@@ -123,18 +148,31 @@ func get_local_portrait_transform(portrait_rect:Rect2, character_scale:=1.0) ->
# Mode that size the character so 100% size fills the height
elif size_mode == SizeModes.FIT_SCALE_HEIGHT:
- transform.size = Vector2(1,1) * size.y/portrait_rect.size.y*character_scale
+ transform.size = Vector2(1,1) * size.y / portrait_rect.size.y*character_scale
return transform
## Returns the current origin position
-func _get_origin_position() -> Vector2:
- return size*Vector2(origin_anchor%3/2.0, floor(origin_anchor/3.0)/2.0) + origin_offset
+func _get_origin_position(rect_size = null) -> Vector2:
+ if rect_size == null:
+ rect_size = size
+ return rect_size * Vector2(origin_anchor%3 / 2.0, floor(origin_anchor/3.0) / 2.0) + origin_offset
+
+func is_container(id:Variant) -> bool:
+ return str(id) in container_ids
+
+#region DEBUG METHODS
################################################################################
-## DEBUG METHODS
-################################################################################
+### USE THIS TO DEBUG THE POSITIONS
+#func _draw():
+ #draw_rect(Rect2(Vector2(), size), Color(1, 0.3098039329052, 1), false, 2)
+ #draw_string(get_theme_default_font(),get_theme_default_font().get_string_size(container_ids[0], HORIZONTAL_ALIGNMENT_LEFT, 1, get_theme_default_font_size()) , container_ids[0], HORIZONTAL_ALIGNMENT_CENTER)
+#
+#func _process(delta:float) -> void:
+ #queue_redraw()
+
## Loads the debug_character with the debug_character_portrait
## Creates a holder node and applies mirror
@@ -145,35 +183,55 @@ func _update_debug_portrait_scene() -> void:
for child in get_children():
if child != debug_origin:
child.free()
-
+
+ # Get character
var character := _get_debug_character()
if not character is DialogicCharacter or character.portraits.is_empty():
return
-
+
+ # Determine portrait
var debug_portrait := debug_character_portrait
- if debug_portrait.is_empty(): debug_portrait = character.default_portrait
+ if debug_portrait.is_empty():
+ debug_portrait = character.default_portrait
if mode == PositionModes.SPEAKER and !portrait_prefix.is_empty():
if portrait_prefix+debug_portrait in character.portraits:
debug_portrait = portrait_prefix+debug_portrait
- var portrait_info :Dictionary = character.get_portrait_info(debug_portrait)
- var portrait_scene_path :String = portrait_info.get('scene', default_portrait_scene)
- if portrait_scene_path.is_empty(): portrait_scene_path = default_portrait_scene
+ if not debug_portrait in character.portraits:
+ debug_portrait = character.default_portrait
+
+ var portrait_info: Dictionary = character.get_portrait_info(debug_portrait)
+
+ # Determine scene
+ var portrait_scene_path: String = portrait_info.get('scene', default_portrait_scene)
+ if portrait_scene_path.is_empty():
+ portrait_scene_path = default_portrait_scene
+
debug_character_scene_node = load(portrait_scene_path).instantiate()
+
if !is_instance_valid(debug_character_scene_node):
return
+
+ # Load portrait
+ DialogicUtil.apply_scene_export_overrides(debug_character_scene_node, character.portraits[debug_portrait].get('export_overrides', {}))
debug_character_scene_node._update_portrait(character, debug_portrait)
+
+ # Add character node
if !is_instance_valid(debug_character_holder_node):
debug_character_holder_node = Node2D.new()
add_child(debug_character_holder_node)
+ print(debug_character_holder_node)
+
+ # Add portrait node
debug_character_holder_node.add_child(debug_character_scene_node)
move_child(debug_character_holder_node, 0)
debug_character_scene_node._set_mirror(character.mirror != mirrored != portrait_info.get('mirror', false))
- _update_debug_portrait_size_position()
+
+ _update_debug_portrait_transform()
## Set's the size and position of the holder and scene node
## according to the size_mode
-func _update_debug_portrait_size_position() -> void:
+func _update_debug_portrait_transform() -> void:
if !Engine.is_editor_hint() or !is_instance_valid(debug_character_scene_node) or !is_instance_valid(debug_origin):
return
var character := _get_debug_character()
@@ -184,15 +242,18 @@ func _update_debug_portrait_size_position() -> void:
debug_character_holder_node.scale = transform.size
-## Updates the debug origins position. Also calls _update_debug_portrait_size_position()
+
+## Updates the debug origins position. Also calls _update_debug_portrait_transform()
func _update_debug_origin() -> void:
if !Engine.is_editor_hint() or !is_instance_valid(debug_origin):
return
debug_origin.position = _get_origin_position()
- _update_debug_portrait_size_position()
+ _update_debug_portrait_transform()
## Returns the debug character or the default debug character
func _get_debug_character() -> DialogicCharacter:
return debug_character if debug_character != null else default_debug_character
+
+#endregion
diff --git a/addons/dialogic/Modules/Character/event_portrait_position.svg b/addons/dialogic/Modules/Character/portrait_position.svg
similarity index 100%
rename from addons/dialogic/Modules/Character/event_portrait_position.svg
rename to addons/dialogic/Modules/Character/portrait_position.svg
diff --git a/addons/dialogic/Modules/Character/event_portrait_position.svg.import b/addons/dialogic/Modules/Character/portrait_position.svg.import
similarity index 70%
rename from addons/dialogic/Modules/Character/event_portrait_position.svg.import
rename to addons/dialogic/Modules/Character/portrait_position.svg.import
index 3755883b9..763036af5 100644
--- a/addons/dialogic/Modules/Character/event_portrait_position.svg.import
+++ b/addons/dialogic/Modules/Character/portrait_position.svg.import
@@ -3,7 +3,7 @@
importer="texture"
type="CompressedTexture2D"
uid="uid://bn3nq7gw67kye"
-path="res://.godot/imported/event_portrait_position.svg-f91e8e0cc02545b0b28152d6ef70ff10.ctex"
+path="res://.godot/imported/portrait_position.svg-f025767e40032b9ebdeab1f9e882467a.ctex"
metadata={
"has_editor_variant": true,
"vram_texture": false
@@ -11,8 +11,8 @@ metadata={
[deps]
-source_file="res://addons/dialogic/Modules/Character/event_portrait_position.svg"
-dest_files=["res://.godot/imported/event_portrait_position.svg-f91e8e0cc02545b0b28152d6ef70ff10.ctex"]
+source_file="res://addons/dialogic/Modules/Character/portrait_position.svg"
+dest_files=["res://.godot/imported/portrait_position.svg-f025767e40032b9ebdeab1f9e882467a.ctex"]
[params]
diff --git a/addons/dialogic/Modules/Character/settings_portraits.gd b/addons/dialogic/Modules/Character/settings_portraits.gd
index a637d9f45..5e13819ca 100644
--- a/addons/dialogic/Modules/Character/settings_portraits.gd
+++ b/addons/dialogic/Modules/Character/settings_portraits.gd
@@ -2,79 +2,94 @@
extends DialogicSettingsPage
+const POSITION_SUGGESTION_KEY := 'dialogic/portraits/position_suggestion_names'
+
+const DEFAULT_PORTRAIT_SCENE_KEY := 'dialogic/portraits/default_portrait'
+
+const ANIMATION_JOIN_DEFAULT_KEY := 'dialogic/animations/join_default'
+const ANIMATION_JOIN_DEFAULT_LENGTH_KEY := 'dialogic/animations/join_default_length'
+const ANIMATION_JOIN_DEFAULT_WAIT_KEY := 'dialogic/animations/join_default_wait'
+const ANIMATION_LEAVE_DEFAULT_KEY := 'dialogic/animations/leave_default'
+const ANIMATION_LEAVE_DEFAULT_LENGTH_KEY := 'dialogic/animations/leave_default_length'
+const ANIMATION_LEAVE_DEFAULT_WAIT_KEY := 'dialogic/animations/leave_default_wait'
+const ANIMATION_CROSSFADE_DEFAULT_KEY := 'dialogic/animations/cross_fade_default'
+const ANIMATION_CROSSFADE_DEFAULT_LENGTH_KEY:= 'dialogic/animations/cross_fade_default_length'
+
+
func _ready():
%JoinDefault.get_suggestions_func = get_join_animation_suggestions
%JoinDefault.mode = 1
%LeaveDefault.get_suggestions_func = get_leave_animation_suggestions
%LeaveDefault.mode = 1
+ %CrossFadeDefault.get_suggestions_func = get_crossfade_animation_suggestions
+ %CrossFadeDefault.mode = 1
+ %PositionSuggestions.text_submitted.connect(save_setting.bind(POSITION_SUGGESTION_KEY))
+ %CustomPortraitScene.value_changed.connect(save_setting_with_name.bind(DEFAULT_PORTRAIT_SCENE_KEY))
-func _refresh():
- %CustomPortraitScene.resource_icon = get_theme_icon("PackedScene", "EditorIcons")
- %CustomPortraitScene.set_value(ProjectSettings.get_setting('dialogic/portraits/default_portrait', ''))
+ %JoinDefault.value_changed.connect(
+ save_setting_with_name.bind(ANIMATION_JOIN_DEFAULT_KEY))
+ %JoinDefaultLength.value_changed.connect(
+ save_setting.bind(ANIMATION_JOIN_DEFAULT_LENGTH_KEY))
+ %JoinDefaultWait.toggled.connect(
+ save_setting.bind(ANIMATION_JOIN_DEFAULT_WAIT_KEY))
+ %LeaveDefault.value_changed.connect(
+ save_setting_with_name.bind(ANIMATION_LEAVE_DEFAULT_KEY))
+ %LeaveDefaultLength.value_changed.connect(
+ save_setting.bind(ANIMATION_LEAVE_DEFAULT_LENGTH_KEY))
+ %LeaveDefaultWait.toggled.connect(
+ save_setting.bind(ANIMATION_LEAVE_DEFAULT_WAIT_KEY))
- %JoinDefault.resource_icon = get_theme_icon("Animation", "EditorIcons")
- %LeaveDefault.resource_icon = get_theme_icon("Animation", "EditorIcons")
- %JoinDefault.set_value(DialogicUtil.pretty_name(ProjectSettings.get_setting('dialogic/animations/join_default',
- get_script().resource_path.get_base_dir().path_join('DefaultAnimations/fade_in_up.gd'))))
- %LeaveDefault.set_value(ProjectSettings.get_setting('dialogic/animations/leave_default',
- get_script().resource_path.get_base_dir().path_join('DefaultAnimations/fade_out_down.gd')))
- %JoinDefaultLength.set_value(ProjectSettings.get_setting('dialogic/animations/join_default_length', 0.5))
- %LeaveDefaultLength.set_value(ProjectSettings.get_setting('dialogic/animations/leave_default_length', 0.5))
- %LeaveDefaultWait.button_pressed = ProjectSettings.get_setting('dialogic/animations/leave_default_wait', true)
- %JoinDefaultWait.button_pressed = ProjectSettings.get_setting('dialogic/animations/join_default_wait', true)
+ %CrossFadeDefault.value_changed.connect(
+ save_setting_with_name.bind(ANIMATION_CROSSFADE_DEFAULT_KEY))
+ %CrossFadeDefaultLength.value_changed.connect(
+ save_setting.bind(ANIMATION_CROSSFADE_DEFAULT_LENGTH_KEY))
-func _on_custom_portrait_scene_value_changed(property_name:String, value:String) -> void:
- ProjectSettings.set_setting('dialogic/portraits/default_portrait', value)
- ProjectSettings.save()
+func _refresh():
+ %PositionSuggestions.text = ProjectSettings.get_setting(POSITION_SUGGESTION_KEY, 'leftmost, left, center, right, rightmost')
+ %CustomPortraitScene.resource_icon = get_theme_icon(&"PackedScene", &"EditorIcons")
+ %CustomPortraitScene.set_value(ProjectSettings.get_setting(DEFAULT_PORTRAIT_SCENE_KEY, ''))
-func _on_LeaveDefault_value_changed(property_name:String, value:String) -> void:
- ProjectSettings.set_setting('dialogic/animations/leave_default', value)
- ProjectSettings.save()
+ # JOIN
+ %JoinDefault.resource_icon = get_theme_icon(&"Animation", &"EditorIcons")
+ %JoinDefault.set_value(ProjectSettings.get_setting(ANIMATION_JOIN_DEFAULT_KEY, "Fade In Up"))
+ %JoinDefaultLength.set_value(ProjectSettings.get_setting(ANIMATION_JOIN_DEFAULT_LENGTH_KEY, 0.5))
+ %JoinDefaultWait.button_pressed = ProjectSettings.get_setting(ANIMATION_JOIN_DEFAULT_WAIT_KEY, true)
+ # LEAVE
+ %LeaveDefault.resource_icon = get_theme_icon(&"Animation", &"EditorIcons")
+ %LeaveDefault.set_value(ProjectSettings.get_setting(ANIMATION_LEAVE_DEFAULT_KEY, "Fade Out Down"))
+ %LeaveDefaultLength.set_value(ProjectSettings.get_setting(ANIMATION_LEAVE_DEFAULT_LENGTH_KEY, 0.5))
+ %LeaveDefaultWait.button_pressed = ProjectSettings.get_setting(ANIMATION_LEAVE_DEFAULT_WAIT_KEY, true)
-func _on_JoinDefault_value_changed(property_name:String, value:String) -> void:
- ProjectSettings.set_setting('dialogic/animations/join_default', value)
- ProjectSettings.save()
+ # CROSS FADE
+ %CrossFadeDefault.resource_icon = get_theme_icon(&"Animation", &"EditorIcons")
+ %CrossFadeDefault.set_value(ProjectSettings.get_setting(ANIMATION_CROSSFADE_DEFAULT_KEY, "Fade Cross"))
+ %CrossFadeDefaultLength.set_value(ProjectSettings.get_setting(ANIMATION_CROSSFADE_DEFAULT_LENGTH_KEY, 0.5))
-func _on_JoinDefaultLength_value_changed(value:float) -> void:
- ProjectSettings.set_setting('dialogic/animations/join_default_length', value)
- ProjectSettings.save()
+func save_setting_with_name(property_name:String, value:Variant, settings_key:String) -> void:
+ save_setting(value, settings_key)
-func _on_LeaveDefaultLength_value_changed(value:float) -> void:
- ProjectSettings.set_setting('dialogic/animations/leave_default_length', value)
- ProjectSettings.save()
-
-func _on_JoinDefaultWait_toggled(button_pressed:bool) -> void:
- ProjectSettings.set_setting('dialogic/animations/join_default_wait', button_pressed)
- ProjectSettings.save()
-
-func _on_LeaveDefaultWait_toggled(button_pressed:bool) -> void:
- ProjectSettings.set_setting('dialogic/animations/leave_default_wait', button_pressed)
+func save_setting(value:Variant, settings_key:String) -> void:
+ ProjectSettings.set_setting(settings_key, value)
ProjectSettings.save()
func get_join_animation_suggestions(search_text:String) -> Dictionary:
- var suggestions = {}
- for anim in list_animations():
- if '_in' in anim.get_file():
- suggestions[DialogicUtil.pretty_name(anim)] = {'value':anim, 'icon':get_theme_icon('Animation', 'EditorIcons')}
- return suggestions
+ return DialogicPortraitAnimationUtil.get_suggestions(search_text, %JoinDefault.current_value, "", DialogicPortraitAnimationUtil.AnimationType.IN)
+
func get_leave_animation_suggestions(search_text:String) -> Dictionary:
- var suggestions = {}
- for anim in list_animations():
- if '_out' in anim.get_file():
- suggestions[DialogicUtil.pretty_name(anim)] = {'value':anim, 'icon':get_theme_icon('Animation', 'EditorIcons')}
- return suggestions
-
-func list_animations() -> Array:
- var list = DialogicUtil.listdir(get_script().resource_path.get_base_dir().path_join('DefaultAnimations'), true, false, true)
- list.append_array(DialogicUtil.listdir(ProjectSettings.get_setting('dialogic/animations/custom_folder', 'res://addons/dialogic_additions/Animations'), true, false, true))
- return list
+ return DialogicPortraitAnimationUtil.get_suggestions(search_text, %LeaveDefault.current_value, "", DialogicPortraitAnimationUtil.AnimationType.OUT)
+
+
+func get_crossfade_animation_suggestions(search_text:String) -> Dictionary:
+ return DialogicPortraitAnimationUtil.get_suggestions(search_text, %CrossFadeDefault.current_value, "", DialogicPortraitAnimationUtil.AnimationType.CROSSFADE)
+
+
diff --git a/addons/dialogic/Modules/Character/settings_portraits.tscn b/addons/dialogic/Modules/Character/settings_portraits.tscn
index ad39f9174..5689200cd 100644
--- a/addons/dialogic/Modules/Character/settings_portraits.tscn
+++ b/addons/dialogic/Modules/Character/settings_portraits.tscn
@@ -1,53 +1,62 @@
-[gd_scene load_steps=7 format=3 uid="uid://cp463rpri5j8a"]
+[gd_scene load_steps=5 format=3 uid="uid://cp463rpri5j8a"]
[ext_resource type="Script" path="res://addons/dialogic/Modules/Character/settings_portraits.gd" id="2"]
[ext_resource type="PackedScene" uid="uid://dbpkta2tjsqim" path="res://addons/dialogic/Editor/Common/hint_tooltip_icon.tscn" id="2_dce78"]
[ext_resource type="PackedScene" uid="uid://dpwhshre1n4t6" path="res://addons/dialogic/Editor/Events/Fields/field_options_dynamic.tscn" id="3"]
[ext_resource type="PackedScene" uid="uid://7mvxuaulctcq" path="res://addons/dialogic/Editor/Events/Fields/field_file.tscn" id="3_m06d8"]
-[sub_resource type="Image" id="Image_8p738"]
-data = {
-"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
-"format": "RGBA8",
-"height": 16,
-"mipmaps": false,
-"width": 16
-}
-
-[sub_resource type="ImageTexture" id="ImageTexture_wre7v"]
-image = SubResource("Image_8p738")
-
[node name="Portraits" type="VBoxContainer"]
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
script = ExtResource("2")
-[node name="Animations3" type="HBoxContainer" parent="."]
+[node name="PositionsTitle" type="HBoxContainer" parent="."]
+layout_mode = 2
+size_flags_horizontal = 3
+size_flags_stretch_ratio = 0.5
+
+[node name="Title2" type="Label" parent="PositionsTitle"]
+layout_mode = 2
+theme_type_variation = &"DialogicSettingsSection"
+text = "Position Suggestions
+"
+
+[node name="HintTooltip" parent="PositionsTitle" instance=ExtResource("2_dce78")]
+layout_mode = 2
+tooltip_text = "You can change the position names that will be suggested in the timeline editor here."
+texture = null
+hint_text = "You can change the position names that will be suggested in the timeline editor here."
+
+[node name="PositionSuggestions" type="LineEdit" parent="."]
+unique_name_in_owner = true
+layout_mode = 2
+
+[node name="DefaultSceneTitle" type="HBoxContainer" parent="."]
layout_mode = 2
size_flags_horizontal = 3
size_flags_stretch_ratio = 0.5
-[node name="Title2" type="Label" parent="Animations3"]
+[node name="Title2" type="Label" parent="DefaultSceneTitle"]
layout_mode = 2
theme_type_variation = &"DialogicSettingsSection"
text = "Default Portrait Scene
"
-[node name="HintTooltip" parent="Animations3" instance=ExtResource("2_dce78")]
+[node name="HintTooltip" parent="DefaultSceneTitle" instance=ExtResource("2_dce78")]
layout_mode = 2
tooltip_text = "If this is set, this scene will be what is used by default for any portrait that has no scene specified"
-texture = SubResource("ImageTexture_wre7v")
+texture = null
hint_text = "If this is set, this scene will be what is used by default for any portrait that has no scene specified"
-[node name="HBoxContainer" type="HBoxContainer" parent="."]
+[node name="DefaultScene" type="HBoxContainer" parent="."]
layout_mode = 2
-[node name="Label" type="Label" parent="HBoxContainer"]
+[node name="Label" type="Label" parent="DefaultScene"]
layout_mode = 2
text = "Scene"
-[node name="CustomPortraitScene" parent="HBoxContainer" instance=ExtResource("3_m06d8")]
+[node name="CustomPortraitScene" parent="DefaultScene" instance=ExtResource("3_m06d8")]
unique_name_in_owner = true
layout_mode = 2
file_filter = "*.tscn, *.scn; PortraitScene"
@@ -66,15 +75,21 @@ text = "Default Animations
[node name="HintTooltip" parent="Animations2" instance=ExtResource("2_dce78")]
layout_mode = 2
-tooltip_text = "These settings are used for Leave and Join events if no animation is selected."
-texture = SubResource("ImageTexture_wre7v")
-hint_text = "These settings are used for Leave and Join events if no animation is selected."
+tooltip_text = "These settings are used for Leave and Join events if no animation is selected.
+
+The Cross-Fade will play if the portrait of a character changes and
+no animation is set."
+texture = null
+hint_text = "These settings are used for Leave and Join events if no animation is selected.
+
+The Cross-Fade will play if the portrait of a character changes and
+no animation is set."
[node name="GridContainer" type="GridContainer" parent="."]
layout_mode = 2
columns = 2
-[node name="Label3" type="Label" parent="GridContainer"]
+[node name="DefaultJoinLabel" type="Label" parent="GridContainer"]
layout_mode = 2
text = "Join"
@@ -84,6 +99,7 @@ layout_mode = 2
[node name="JoinDefault" parent="GridContainer/DefaultIn" instance=ExtResource("3")]
unique_name_in_owner = true
layout_mode = 2
+mode = 1
[node name="JoinDefaultLength" type="SpinBox" parent="GridContainer/DefaultIn"]
unique_name_in_owner = true
@@ -95,7 +111,7 @@ unique_name_in_owner = true
layout_mode = 2
text = "Wait:"
-[node name="Label4" type="Label" parent="GridContainer"]
+[node name="DefaultOutLabel" type="Label" parent="GridContainer"]
layout_mode = 2
text = "Leave"
@@ -105,6 +121,7 @@ layout_mode = 2
[node name="LeaveDefault" parent="GridContainer/DefaultOut" instance=ExtResource("3")]
unique_name_in_owner = true
layout_mode = 2
+mode = 1
[node name="LeaveDefaultLength" type="SpinBox" parent="GridContainer/DefaultOut"]
unique_name_in_owner = true
@@ -116,10 +133,28 @@ unique_name_in_owner = true
layout_mode = 2
text = "Wait:"
-[connection signal="value_changed" from="HBoxContainer/CustomPortraitScene" to="." method="_on_custom_portrait_scene_value_changed"]
+[node name="CrossFadeLabel" type="Label" parent="GridContainer"]
+layout_mode = 2
+text = "Cross-Fade"
+
+[node name="DefaultCrossFade" type="HBoxContainer" parent="GridContainer"]
+layout_mode = 2
+
+[node name="CrossFadeDefault" parent="GridContainer/DefaultCrossFade" instance=ExtResource("3")]
+unique_name_in_owner = true
+layout_mode = 2
+mode = 1
+
+[node name="CrossFadeDefaultLength" type="SpinBox" parent="GridContainer/DefaultCrossFade"]
+unique_name_in_owner = true
+layout_mode = 2
+step = 0.1
+
[connection signal="value_changed" from="GridContainer/DefaultIn/JoinDefault" to="." method="_on_JoinDefault_value_changed"]
[connection signal="value_changed" from="GridContainer/DefaultIn/JoinDefaultLength" to="." method="_on_JoinDefaultLength_value_changed"]
[connection signal="toggled" from="GridContainer/DefaultIn/JoinDefaultWait" to="." method="_on_JoinDefaultWait_toggled"]
[connection signal="value_changed" from="GridContainer/DefaultOut/LeaveDefault" to="." method="_on_LeaveDefault_value_changed"]
[connection signal="value_changed" from="GridContainer/DefaultOut/LeaveDefaultLength" to="." method="_on_LeaveDefaultLength_value_changed"]
[connection signal="toggled" from="GridContainer/DefaultOut/LeaveDefaultWait" to="." method="_on_LeaveDefaultWait_toggled"]
+[connection signal="value_changed" from="GridContainer/DefaultCrossFade/CrossFadeDefault" to="." method="_on_LeaveDefault_value_changed"]
+[connection signal="value_changed" from="GridContainer/DefaultCrossFade/CrossFadeDefaultLength" to="." method="_on_LeaveDefaultLength_value_changed"]
diff --git a/addons/dialogic/Modules/Character/simple_image_portrait_thumbnail.png b/addons/dialogic/Modules/Character/simple_image_portrait_thumbnail.png
new file mode 100644
index 000000000..656215f70
Binary files /dev/null and b/addons/dialogic/Modules/Character/simple_image_portrait_thumbnail.png differ
diff --git a/addons/dialogic/Modules/Character/simple_image_portrait_thumbnail.png.import b/addons/dialogic/Modules/Character/simple_image_portrait_thumbnail.png.import
new file mode 100644
index 000000000..d049ed00d
--- /dev/null
+++ b/addons/dialogic/Modules/Character/simple_image_portrait_thumbnail.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://qihj11n7kx3m"
+path="res://.godot/imported/simple_image_portrait_thumbnail.png-3d6c6de8187fd7911017e2ef9d3c40a4.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/dialogic/Modules/Character/simple_image_portrait_thumbnail.png"
+dest_files=["res://.godot/imported/simple_image_portrait_thumbnail.png-3d6c6de8187fd7911017e2ef9d3c40a4.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/addons/dialogic/Modules/Character/subsystem_containers.gd b/addons/dialogic/Modules/Character/subsystem_containers.gd
new file mode 100644
index 000000000..ba968f131
--- /dev/null
+++ b/addons/dialogic/Modules/Character/subsystem_containers.gd
@@ -0,0 +1,284 @@
+extends DialogicSubsystem
+
+## Subsystem that manages portrait positions.
+
+signal position_changed(info: Dictionary)
+
+
+var transform_regex := r"(?position|pos|size|siz|rotation|rot)\W*=(?((?!(pos|siz|rot)).)*)"
+
+#region STATE
+####################################################################################################
+
+
+#endregion
+
+
+#region MAIN METHODS
+####################################################################################################
+
+func get_container(position_id: String) -> DialogicNode_PortraitContainer:
+ for portrait_position:DialogicNode_PortraitContainer in get_tree().get_nodes_in_group(&'dialogic_portrait_con_position'):
+ if portrait_position.is_visible_in_tree() and portrait_position.is_container(position_id):
+ return portrait_position
+ return null
+
+
+func get_containers(position_id: String) -> Array[DialogicNode_PortraitContainer]:
+ return get_tree().get_nodes_in_group(&'dialogic_portrait_con_position').filter(
+ func(node:DialogicNode_PortraitContainer):
+ return node.is_visible_in_tree() and node.is_container(position_id))
+
+
+func get_container_container() -> CanvasItem:
+ var any_portrait_container := get_tree().get_first_node_in_group(&'dialogic_portrait_con_position')
+ if any_portrait_container:
+ return any_portrait_container.get_parent()
+ return null
+
+
+## Creates a new portrait container node.
+## It will copy it's size and most settings from the first p_container in the tree.
+## It will be added as a sibling of the first p_container in the tree.
+func add_container(position_id: String) -> DialogicNode_PortraitContainer:
+ var example_position := get_tree().get_first_node_in_group(&'dialogic_portrait_con_position')
+ if example_position:
+ var new_position := DialogicNode_PortraitContainer.new()
+ example_position.get_parent().add_child(new_position)
+ new_position.name = "Portrait_"+position_id.validate_node_name()
+ copy_container_setup(example_position, new_position)
+ new_position.container_ids = [position_id]
+ position_changed.emit({&'change':'added', &'container_node':new_position, &'position_id':position_id})
+ return new_position
+ return null
+
+
+## Moves the [container] to the [destionation] (using [tween] and [time]).
+## The destination can be a position_id (e.g. "center") or translation, roataion and scale.
+## When moving to a preset container, then some more will be "copied" (e.g. anchors, etc.)
+func move_container(container:DialogicNode_PortraitContainer, destination:String, tween:Tween = null, time:float=1.0) -> void:
+ var target_position: Vector2 = container.position + container._get_origin_position()
+ var target_rotation: float = container.rotation
+ var target_size: Vector2 = container.size
+
+ var destination_container := get_container(destination)
+ if destination_container:
+ container.set_meta("target_container", destination_container)
+ target_position = destination_container.position + destination_container._get_origin_position()
+ target_rotation = destination_container.rotation_degrees
+ target_size = destination_container.size
+ else:
+ var regex := RegEx.create_from_string(transform_regex)
+ for found in regex.search_all(destination):
+ match found.get_string('part'):
+ 'pos', 'position':
+ target_position = str_to_vector(found.get_string("value"), target_position)
+ 'rot', 'rotation':
+ target_rotation = float(found.get_string("value"))
+ 'siz', 'size':
+ target_size = str_to_vector(found.get_string("value"), target_size)
+
+ translate_container(container, target_position, false, tween, time)
+ rotate_container(container, target_rotation, false, tween, time)
+ resize_container(container, target_size, false, tween, time)
+
+ if destination_container:
+ if time:
+ tween.finished.connect(func():
+ if container.has_meta("target_container"):
+ if container.get_meta("target_container") == destination_container:
+ copy_container_setup(destination_container, container)
+ )
+ else:
+ copy_container_setup(destination_container, container)
+
+
+func copy_container_setup(from:DialogicNode_PortraitContainer, to:DialogicNode_PortraitContainer) -> void:
+ to.ignore_resize = true
+ to.layout_mode = from.layout_mode
+ to.anchors_preset = from.anchors_preset
+ to.anchor_bottom = from.anchor_bottom
+ to.anchor_left = from.anchor_left
+ to.anchor_right = from.anchor_right
+ to.anchor_top = from.anchor_top
+ to.offset_bottom = from.offset_bottom
+ to.offset_top = from.offset_top
+ to.offset_right = from.offset_right
+ to.offset_left = from.offset_left
+ to.size_mode = from.size_mode
+ to.origin_anchor = from.origin_anchor
+ to.ignore_resize = false
+ to.update_portrait_transforms()
+
+
+## Translates the given container.
+## The given translation should be the target position of the ORIGIN point, not the container!
+func translate_container(container:DialogicNode_PortraitContainer, translation:Variant, relative := false, tween:Tween=null, time:float=1.0) -> void:
+ if !container.has_meta(&'default_translation'):
+ container.set_meta(&'default_translation', container.position + container._get_origin_position())
+
+ var final_translation: Vector2
+ if typeof(translation) == TYPE_STRING:
+ final_translation = str_to_vector(translation, container.position+container._get_origin_position())
+ elif typeof(translation) == TYPE_VECTOR2:
+ final_translation = translation
+
+ if relative:
+ final_translation += container.position
+ else:
+ final_translation -= container._get_origin_position()
+
+ if tween:
+ tween.tween_method(DialogicUtil.multitween.bind(container, "position", "base"), container.position, final_translation, time)
+ if not tween.finished.is_connected(save_position_container):
+ tween.finished.connect(save_position_container.bind(container))
+ else:
+ container.position = final_translation
+ save_position_container(container)
+ position_changed.emit({&'change':'moved', &'container_node':container})
+
+
+func rotate_container(container:DialogicNode_PortraitContainer, rotation:float, relative := false, tween:Tween=null, time:float=1.0) -> void:
+ if !container.has_meta(&'default_rotation'):
+ container.set_meta(&'default_rotation', container.rotation_degrees)
+
+ var final_rotation := rotation
+
+ if relative:
+ final_rotation += container.rotation_degrees
+
+ container.pivot_offset = container._get_origin_position()
+
+ if tween:
+ tween.tween_property(container, 'rotation_degrees', final_rotation, time)
+ if not tween.finished.is_connected(save_position_container):
+ tween.finished.connect(save_position_container.bind(container))
+ else:
+ container.rotation_degrees = final_rotation
+ save_position_container(container)
+
+ position_changed.emit({&'change':'rotated', &'container_node':container})
+
+
+func resize_container(container: DialogicNode_PortraitContainer, rect_size: Variant, relative := false, tween:Tween=null, time:float=1.0) -> void:
+ if !container.has_meta(&'default_size'):
+ container.set_meta(&'default_size', container.size)
+
+ var final_rect_resize: Vector2
+ if typeof(rect_size) == TYPE_STRING:
+ final_rect_resize = str_to_vector(rect_size, container.size)
+ elif typeof(rect_size) == TYPE_VECTOR2:
+ final_rect_resize = rect_size
+
+ if relative:
+ final_rect_resize += container.rect_size
+
+ var relative_position_change := container._get_origin_position()-container._get_origin_position(final_rect_resize)
+
+ if tween:
+ tween.tween_method(DialogicUtil.multitween.bind(container, "position", "resize_move"), Vector2(), relative_position_change, time)
+ tween.tween_property(container, 'size', final_rect_resize, time)
+ if not tween.finished.is_connected(save_position_container):
+ tween.finished.connect(save_position_container.bind(container))
+ else:
+ container.position = container.position + relative_position_change
+ container.size = final_rect_resize
+ save_position_container(container)
+
+ position_changed.emit({&'change':'resized', &'container_node':container})
+
+
+func save_position_container(container: DialogicNode_PortraitContainer) -> void:
+ if not dialogic.current_state_info.has('portrait_containers'):
+ dialogic.current_state_info['portrait_containers'] = {}
+
+ var info := {
+ "container_ids" : container.container_ids,
+ "position" : container.position,
+ "rotation" : container.rotation_degrees,
+ "size" : container.size,
+ "pivot_mode" : container.pivot_mode,
+ "pivot_value" : container.pivot_value,
+ "origin_anchor" : container.origin_anchor,
+ "anchor_left" : container.anchor_left,
+ "anchor_right" : container.anchor_right,
+ "anchor_top" : container.anchor_top,
+ "anchor_bottom" : container.anchor_bottom,
+ "offset_left" : container.offset_left,
+ "offset_right" : container.offset_right,
+ "offset_top" : container.offset_top,
+ "offset_bottom" : container.offset_bottom,
+ }
+
+ dialogic.current_state_info.portrait_containers[container.container_ids[0]] = info
+
+
+func load_position_container(position_id: String) -> DialogicNode_PortraitContainer:
+ # First check whether the container already exists:
+ var container := get_container(position_id)
+ if container:
+ return container
+
+ if not dialogic.current_state_info.has('portrait_containers') or not dialogic.current_state_info.portrait_containers.has(position_id):
+ return null
+
+ var info: Dictionary = dialogic.current_state_info.portrait_containers[position_id]
+ container = add_container(position_id)
+
+ if not container:
+ return null
+
+ container.container_ids = info.container_ids
+ container.position = info.position
+ container.rotation = info.rotation
+ container.size = info.size
+ container.pivot_mode = info.pivot_mode
+ container.pivot_value = info.pivot_value
+ container.origin_anchor = info.origin_anchor
+ container.anchor_left = info.anchor_left
+ container.anchor_right = info.anchor_right
+ container.anchor_top = info.anchor_top
+ container.anchor_bottom = info.anchor_bottom
+ container.offset_left = info.offset_left
+ container.offset_right = info.offset_right
+ container.offset_top = info.offset_top
+ container.offset_bottom = info.offset_bottom
+
+ return container
+
+
+func str_to_vector(input: String, base_vector:=Vector2()) -> Vector2:
+ var vector_regex := RegEx.create_from_string(r"(?x|y)\s*(?(-|\+)?(\d|\.|)*)(\s*(?%|px))?")
+ var vec := base_vector
+ for i in vector_regex.search_all(input):
+ var value := float(i.get_string(&'number'))
+ match i.get_string(&'type'):
+ 'px':
+ pass # Keep values as they are
+ '%', _:
+ match i.get_string(&'part'):
+ 'x': value *= get_viewport().get_window().size.x
+ 'y': value *= get_viewport().get_window().size.y
+
+ match i.get_string(&'part'):
+ 'x': vec.x = value
+ 'y': vec.y = value
+ return vec
+
+
+func vector_to_str(vec:Vector2) -> String:
+ return "x" + str(vec.x) + "px y" + str(vec.y) + "px"
+
+
+func reset_all_containers(time:= 0.0, tween:Tween = null) -> void:
+ for container in get_tree().get_nodes_in_group(&'dialogic_portrait_con_position'):
+ reset_container(container, time, tween)
+
+
+func reset_container(container:DialogicNode_PortraitContainer, time := 0.0, tween: Tween = null ) -> void:
+ if container.has_meta(&'default_translation'):
+ translate_container(container, vector_to_str(container.get_meta(&'default_translation')), false, tween, time)
+ if container.has_meta(&'default_rotation'):
+ rotate_container(container, container.get_meta(&'default_rotation'), false, tween, time)
+ if container.has_meta(&'default_size'):
+ resize_container(container, vector_to_str(container.get_meta(&'default_size')), false, tween, time)
diff --git a/addons/dialogic/Modules/Character/subsystem_portraits.gd b/addons/dialogic/Modules/Character/subsystem_portraits.gd
index 6c836f2b5..b78abd21d 100644
--- a/addons/dialogic/Modules/Character/subsystem_portraits.gd
+++ b/addons/dialogic/Modules/Character/subsystem_portraits.gd
@@ -6,7 +6,9 @@ signal character_joined(info:Dictionary)
signal character_left(info:Dictionary)
signal character_portrait_changed(info:Dictionary)
signal character_moved(info:Dictionary)
-signal position_changed(info:Dictionary)
+
+## Emitted when a portrait starts animating.
+#signal portrait_animating(character_node: Node, portrait_node: Node, animation_name: String, animation_length: float)
## The default portrait scene.
@@ -16,23 +18,29 @@ var default_portrait_scene: PackedScene = load(get_script().resource_path.get_ba
#region STATE
####################################################################################################
-func clear_game_state(clear_flag:=DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
+func clear_game_state(_clear_flag:=DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
for character in dialogic.current_state_info.get('portraits', {}).keys():
remove_character(load(character))
dialogic.current_state_info['portraits'] = {}
-func load_game_state(load_flag:=LoadFlags.FULL_LOAD) -> void:
+func load_game_state(_load_flag:=LoadFlags.FULL_LOAD) -> void:
+ if not "portraits" in dialogic.current_state_info:
+ dialogic.current_state_info["portraits"] = {}
+
+ # Load Position Portraits
var portraits_info: Dictionary = dialogic.current_state_info.portraits.duplicate()
dialogic.current_state_info.portraits = {}
for character_path in portraits_info:
var character_info: Dictionary = portraits_info[character_path]
- await join_character(load(character_path), character_info.portrait,
- character_info.position_index,
- character_info.get('custom_mirror', false),
- character_info.get('z_index', 0),
- character_info.get('extra_data', ""),
- "InstantInOrOut", 0, false)
+ var character: DialogicCharacter = load(character_path)
+ var container := dialogic.PortraitContainers.load_position_container(character.get_character_name())
+ add_character(character, container, character_info.portrait, character_info.position_id)
+ change_character_mirror(character, character_info.get('custom_mirror', false))
+ change_character_z_index(character, character_info.get('z_index', 0))
+ change_character_extradata(character, character_info.get('extra_data', ""))
+
+ # Load Speaker Portrait
var speaker: Variant = dialogic.current_state_info.get('speaker', "")
if speaker:
dialogic.current_state_info['speaker'] = ""
@@ -56,8 +64,6 @@ func _ready() -> void:
if !ProjectSettings.get_setting('dialogic/portraits/default_portrait', '').is_empty():
default_portrait_scene = load(ProjectSettings.get_setting('dialogic/portraits/default_portrait', ''))
-#endregion
-
#region MAIN METHODS
####################################################################################################
@@ -72,8 +78,11 @@ func _ready() -> void:
## For a VN style, the "character" methods (next section) provide access based on the character.
## - (That is what the character event uses)
+
## Creates a new [character node] for the given [character], and add it to the given [portrait container].
func _create_character_node(character:DialogicCharacter, container:DialogicNode_PortraitContainer) -> Node:
+ if container == null:
+ return null
var character_node := Node2D.new()
character_node.name = character.get_character_name()
character_node.set_meta('character', character)
@@ -81,9 +90,10 @@ func _create_character_node(character:DialogicCharacter, container:DialogicNode_
return character_node
-# Changes the portrait of a specific [character node].
-func _change_portrait(character_node:Node2D, portrait:String, update_transform:=true) -> Dictionary:
+## Changes the portrait of a specific [character node].
+func _change_portrait(character_node: Node2D, portrait: String, fade_animation:="", fade_length := 0.5) -> Dictionary:
var character: DialogicCharacter = character_node.get_meta('character')
+
if portrait.is_empty():
portrait = character.default_portrait
@@ -93,27 +103,29 @@ func _change_portrait(character_node:Node2D, portrait:String, update_transform:=
print_debug('[Dialogic] Change to not-existing portrait will be ignored!')
return info
- # path to the scene to use
+ # Path to the scene to use.
var scene_path: String = character.portraits[portrait].get('scene', '')
var portrait_node: Node = null
-
- # check if the scene is the same as the currently loaded scene
- if (character_node.get_child_count() and
- character_node.get_child(0).get_meta('scene', '') == scene_path and
- # also check if the scene supports changing to the given portrait
- (!character_node.get_child(0).has_method('_should_do_portrait_update') or character_node.get_child(0)._should_do_portrait_update(character, portrait))):
- portrait_node = character_node.get_child(0)
+ var previous_portrait: Node = null
+ var portrait_count := character_node.get_child_count()
+
+ if portrait_count > 0:
+ previous_portrait = character_node.get_child(-1)
+
+ # Check if the scene is the same as the currently loaded scene.
+ if (not previous_portrait == null and
+ previous_portrait.get_meta('scene', '') == scene_path and
+ # Also check if the scene supports changing to the given portrait.
+ previous_portrait._should_do_portrait_update(character, portrait)):
+ portrait_node = previous_portrait
info['same_scene'] = true
else:
- # remove previous portrait
- if character_node.get_child_count():
- character_node.get_child(0).queue_free()
- character_node.remove_child(character_node.get_child(0))
if ResourceLoader.exists(scene_path):
var packed_scene: PackedScene = load(scene_path)
+
if packed_scene:
portrait_node = packed_scene.instantiate()
else:
@@ -124,7 +136,9 @@ func _change_portrait(character_node:Node2D, portrait:String, update_transform:=
portrait_node.set_meta('scene', scene_path)
+
if portrait_node:
+ portrait_node.set_meta('portrait', portrait)
character_node.set_meta('portrait', portrait)
DialogicUtil.apply_scene_export_overrides(portrait_node, character.portraits[portrait].get('export_overrides', {}))
@@ -132,11 +146,19 @@ func _change_portrait(character_node:Node2D, portrait:String, update_transform:=
if portrait_node.has_method('_update_portrait'):
portrait_node._update_portrait(character, portrait)
- if !portrait_node.is_inside_tree():
+ if not portrait_node.is_inside_tree():
character_node.add_child(portrait_node)
- if update_transform:
- _update_portrait_transform(character_node)
+ _update_portrait_transform(portrait_node)
+
+ ## Handle Cross-Animating
+ if previous_portrait and previous_portrait != portrait_node:
+ if not fade_animation.is_empty() and fade_length > 0:
+ var fade_out := _animate_node(previous_portrait, fade_animation, fade_length, 1, true)
+ var _fade_in := _animate_node(portrait_node, fade_animation, fade_length, 1, false)
+ fade_out.finished.connect(previous_portrait.queue_free)
+ else:
+ previous_portrait.queue_free()
return info
@@ -144,84 +166,106 @@ func _change_portrait(character_node:Node2D, portrait:String, update_transform:=
## Changes the mirroring of the given portrait.
## Unless @force is false, this will take into consideration the character mirror,
## portrait mirror and portrait position mirror settings.
-func _change_portrait_mirror(character_node:Node2D, mirrored:=false, force:=false) -> void:
- if character_node.get_child(0).has_method('_set_mirror'):
- var character: DialogicCharacter= character_node.get_meta('character')
+func _change_portrait_mirror(character_node: Node2D, mirrored := false, force := false) -> void:
+ var latest_portrait := character_node.get_child(-1)
+
+ if latest_portrait.has_method('_set_mirror'):
+ var character: DialogicCharacter = character_node.get_meta('character')
var current_portrait_info := character.get_portrait_info(character_node.get_meta('portrait'))
- character_node.get_child(0)._set_mirror(force or (mirrored != character.mirror != character_node.get_parent().mirrored != current_portrait_info.get('mirror', false)))
+ latest_portrait._set_mirror(force or (mirrored != character.mirror != character_node.get_parent().mirrored != current_portrait_info.get('mirror', false)))
+
+
+func _change_portrait_extradata(character_node: Node2D, extra_data := "") -> void:
+ var latest_portrait := character_node.get_child(-1)
+ if latest_portrait.has_method('_set_extra_data'):
+ latest_portrait._set_extra_data(extra_data)
-func _change_portrait_extradata(character_node:Node2D, extra_data:="") -> void:
- if character_node.get_child(0).has_method('_set_extra_data'):
- character_node.get_child(0)._set_extra_data(extra_data)
+func _update_character_transform(character_node:Node, time := 0.0) -> void:
+ for child in character_node.get_children():
+ _update_portrait_transform(child, time)
-func _update_portrait_transform(character_node:Node2D, time:float = 0.0) -> void:
- var character: DialogicCharacter= character_node.get_meta('character')
- var portrait_node: Node = character_node.get_child(0)
- var portrait_info: Dictionary = character.portraits.get(character_node.get_meta('portrait'), {})
+func _update_portrait_transform(portrait_node: Node, time:float = 0.0) -> void:
+ var character_node: Node = portrait_node.get_parent()
+
+ var character: DialogicCharacter = character_node.get_meta('character')
+ var portrait_info: Dictionary = character.portraits.get(portrait_node.get_meta('portrait'), {})
# ignore the character scale on custom portraits that have 'ignore_char_scale' set to true
- var apply_character_scale: bool= !portrait_info.get('ignore_char_scale', false)
+ var apply_character_scale: bool = not portrait_info.get('ignore_char_scale', false)
+
var transform: Rect2 = character_node.get_parent().get_local_portrait_transform(
portrait_node._get_covered_rect(),
(character.scale * portrait_info.get('scale', 1))*int(apply_character_scale)+portrait_info.get('scale', 1)*int(!apply_character_scale))
var tween: Tween
+
if character_node.has_meta('move_tween'):
if character_node.get_meta('move_tween').is_running():
time = character_node.get_meta('move_time')-character_node.get_meta('move_tween').get_total_elapsed_time()
tween = character_node.get_meta('move_tween')
+ tween.stop()
if time == 0:
character_node.position = transform.position
portrait_node.position = character.offset + portrait_info.get('offset', Vector2())
portrait_node.scale = transform.size
else:
- if !tween:
+ if not tween:
tween = character_node.create_tween().set_parallel().set_ease(Tween.EASE_IN_OUT).set_trans(Tween.TRANS_SINE)
character_node.set_meta('move_tween', tween)
character_node.set_meta('move_time', time)
- tween.tween_property(character_node, 'position', transform.position, time)
+ tween.tween_method(DialogicUtil.multitween.bind(character_node, "position", "base"), character_node.position, transform.position, time)
tween.tween_property(portrait_node, 'position',character.offset + portrait_info.get('offset', Vector2()), time)
tween.tween_property(portrait_node, 'scale', transform.size, time)
-## Animates the portrait in the given container with the given animation.
-func _animate_portrait(character_node:Node2D, animation_path:String, length:float, repeats := 1) -> DialogicAnimation:
- if character_node.has_meta('animation_node') and is_instance_valid(character_node.get_meta('animation_node')):
- character_node.get_meta('animation_node').queue_free()
+## Animates the node with the given animation.
+## Is used both on the character node (most animations) and the portrait nodes (cross-fade animations)
+func _animate_node(node: Node, animation_path: String, length: float, repeats := 1, is_reversed := false) -> DialogicAnimation:
+ if node.has_meta('animation_node') and is_instance_valid(node.get_meta('animation_node')):
+ node.get_meta('animation_node').queue_free()
var anim_script: Script = load(animation_path)
var anim_node := Node.new()
anim_node.set_script(anim_script)
anim_node = (anim_node as DialogicAnimation)
- anim_node.node = character_node
- anim_node.orig_pos = character_node.position
- anim_node.end_position = character_node.position
+ anim_node.node = node
+ anim_node.base_position = node.position
+ anim_node.base_scale = node.scale
anim_node.time = length
anim_node.repeats = repeats
+ anim_node.is_reversed = is_reversed
+
add_child(anim_node)
anim_node.animate()
- character_node.set_meta('animation_node', anim_node)
- return anim_node
+ node.set_meta("animation_path", animation_path)
+ node.set_meta("animation_length", length)
+ node.set_meta("animation_node", anim_node)
+ #if not is_silent:
+ #portrait_animating.emit(portrait_node.get_parent(), portrait_node, animation_path, length)
-## Moves the given portrait to the given container.
-func _move_portrait(character_node:Node2D, portrait_container:DialogicNode_PortraitContainer, time:= 0.0) -> void:
+ return anim_node
- var global_pos := character_node.global_position
- if character_node.get_parent(): character_node.get_parent().remove_child(character_node)
- portrait_container.add_child(character_node)
+## Moves the given portrait to the given container.
+func _move_character(character_node: Node2D, transform:="", time := 0.0, easing:= Tween.EASE_IN_OUT, trans:= Tween.TRANS_SINE) -> void:
+ var tween := character_node.create_tween().set_ease(easing).set_trans(trans).set_parallel()
+ if time == 0:
+ tween.kill()
+ tween = null
+ var container: DialogicNode_PortraitContainer = character_node.get_parent()
+ dialogic.PortraitContainers.move_container(container, transform, tween, time)
- character_node.position = global_pos-character_node.get_parent().global_position
- _update_portrait_transform(character_node, time)
+ for portrait_node in character_node.get_children():
+ _update_portrait_transform(portrait_node, time)
## Changes the given portraits z_index.
-func _change_portrait_z_index(character_node:Node2D, z_index:int, update_zindex:= true) -> void:
+func _change_portrait_z_index(character_node: Node, z_index:int, update_zindex:= true) -> void:
if update_zindex:
character_node.get_parent().set_meta('z_index', z_index)
@@ -233,15 +277,33 @@ func _change_portrait_z_index(character_node:Node2D, z_index:int, update_zindex:
idx += 1
-func z_sort_portrait_containers(con1:DialogicNode_PortraitContainer, con2:DialogicNode_PortraitContainer) -> bool:
+## Checks if [para, character] has joined the scene, if so, returns its
+## active [DialogicPortrait] node.
+##
+## The difference between an active and inactive nodes is whether the node is
+## the latest node. [br]
+## If a portrait is fading/animating from portrait A and B, both will exist
+## in the scene, but only the new portrait is active, even if it is not
+## fully visible yet.
+func get_character_portrait(character: DialogicCharacter) -> DialogicPortrait:
+ if is_character_joined(character):
+ var portrait_node: DialogicPortrait = dialogic.current_state_info['portraits'][character.resource_path].node.get_child(-1)
+ return portrait_node
+
+ return null
+
+
+func z_sort_portrait_containers(con1: DialogicNode_PortraitContainer, con2: DialogicNode_PortraitContainer) -> bool:
if con1.get_meta('z_index', 0) < con2.get_meta('z_index', 0):
return true
+
return false
-func _remove_portrait(character_node:Node2D) -> void:
- character_node.get_parent().remove_child(character_node)
- character_node.queue_free()
+## Private method to remove a [param portrait_node].
+func _remove_portrait(portrait_node: Node) -> void:
+ portrait_node.get_parent().remove_child(portrait_node)
+ portrait_node.queue_free()
## Gets the default animation length for joining characters
@@ -265,6 +327,30 @@ func _get_leave_default_length() -> float:
return default_time
+
+## Checks multiple cases to return a valid portrait to use.
+func get_valid_portrait(character:DialogicCharacter, portrait:String) -> String:
+ if character == null:
+ printerr('[Dialogic] Tried to use portrait "', portrait, '" on character.')
+ dialogic.print_debug_moment()
+ return ""
+
+ if "{" in portrait and dialogic.has_subsystem("Expressions"):
+ var test: Variant = dialogic.Expressions.execute_string(portrait)
+ if test:
+ portrait = str(test)
+
+ if not portrait in character.portraits:
+ if not portrait.is_empty():
+ printerr('[Dialogic] Tried to use invalid portrait "', portrait, '" on character "', DialogicResourceUtil.get_unique_identifier(character.resource_path), '". Using default portrait instead.')
+ dialogic.print_debug_moment()
+ portrait = character.default_portrait
+
+ if portrait.is_empty():
+ portrait = character.default_portrait
+
+ return portrait
+
#endregion
@@ -277,24 +363,27 @@ func _get_leave_default_length() -> float:
## Adds a character at a position and sets it's portrait.
## If the character is already joined it will only update, portrait, position, etc.
-func join_character(character:DialogicCharacter, portrait:String, position_idx:int, mirrored:= false, z_index:= 0, extra_data:= "", animation_name:= "", animation_length:= 0.0, animation_wait := false) -> Node:
+func join_character(character:DialogicCharacter, portrait:String, position_id:String, mirrored:= false, z_index:= 0, extra_data:= "", animation_name:= "", animation_length:= 0.0, animation_wait := false) -> Node:
if is_character_joined(character):
change_character_portrait(character, portrait)
+
if animation_name.is_empty():
animation_length = _get_join_default_length()
+
if animation_wait:
dialogic.current_state = DialogicGameHandler.States.ANIMATING
await get_tree().create_timer(animation_length).timeout
dialogic.current_state = DialogicGameHandler.States.IDLE
- move_character(character, position_idx, animation_length)
+ move_character(character, position_id, animation_length)
change_character_mirror(character, mirrored)
return
- var character_node := add_character(character, portrait, position_idx)
+ var container := dialogic.PortraitContainers.add_container(character.get_character_name())
+ var character_node := add_character(character, container, portrait, position_id)
if character_node == null:
return null
- dialogic.current_state_info['portraits'][character.resource_path] = {'portrait':portrait, 'node':character_node, 'position_index':position_idx, 'custom_mirror':mirrored}
+ dialogic.current_state_info['portraits'][character.resource_path] = {'portrait':portrait, 'node':character_node, 'position_id':position_id, 'custom_mirror':mirrored}
_change_portrait_mirror(character_node, mirrored)
_change_portrait_extradata(character_node, extra_data)
@@ -309,11 +398,10 @@ func join_character(character:DialogicCharacter, portrait:String, position_idx:
animation_length = _get_join_default_length()
animation_wait = ProjectSettings.get_setting('dialogic/animations/join_default_wait', true)
- animation_name = DialogicResourceUtil.guess_special_resource("PortraitAnimation", animation_name, "")
+ animation_name = DialogicPortraitAnimationUtil.guess_animation(animation_name, DialogicPortraitAnimationUtil.AnimationType.IN)
if animation_name and animation_length > 0:
- var anim: DialogicAnimation = _animate_portrait(character_node, animation_name, animation_length)
-
+ var anim: DialogicAnimation = _animate_node(character_node, animation_name, animation_length)
if animation_wait:
dialogic.current_state = DialogicGameHandler.States.ANIMATING
await anim.finished
@@ -322,52 +410,52 @@ func join_character(character:DialogicCharacter, portrait:String, position_idx:
return character_node
-func add_character(character:DialogicCharacter, portrait:String, position_idx:int) -> Node:
+func add_character(character:DialogicCharacter, container: DialogicNode_PortraitContainer, portrait:String, position_id:String) -> Node:
if is_character_joined(character):
printerr('[DialogicError] Cannot add a already joined character. If this is intended call _create_character_node manually.')
return null
+ portrait = get_valid_portrait(character, portrait)
+
if portrait.is_empty():
- portrait = character.default_portrait
+ return null
if not character:
printerr('[DialogicError] Cannot call add_portrait() with null character.')
return null
- if not portrait in character.portraits:
- printerr("[DialogicError] Tried joining ",character.display_name, " with not-existing portrait '", portrait, "'. Will use default portrait instead.")
- portrait = character.default_portrait
- if portrait.is_empty():
- printerr("[DialogicError] Character ",character.display_name, " has no default portrait to use.")
- return null
-
- var character_node: Node = null
-
- for portrait_position in get_tree().get_nodes_in_group('dialogic_portrait_con_position'):
- if portrait_position.is_visible_in_tree() and portrait_position.position_index == position_idx:
- character_node = _create_character_node(character, portrait_position)
- break
+ var character_node := _create_character_node(character, container)
if character_node == null:
- printerr('[Dialogic] Failed to join character to position ', position_idx, ". Could not find position container.")
+ printerr('[Dialogic] Failed to join character to position ', position_id, ". Could not find position container.")
return null
- dialogic.current_state_info['portraits'][character.resource_path] = {'portrait':portrait, 'node':character_node, 'position_index':position_idx}
+ dialogic.current_state_info['portraits'][character.resource_path] = {'portrait':portrait, 'node':character_node, 'position_id':position_id}
+
+ _move_character(character_node, position_id)
_change_portrait(character_node, portrait)
return character_node
## Changes the portrait of a character. Only works with joined characters.
-func change_character_portrait(character:DialogicCharacter, portrait:String, update_transform:=true) -> void:
- if !is_character_joined(character):
+func change_character_portrait(character: DialogicCharacter, portrait: String, fade_animation:="DEFAULT", fade_length := -1.0) -> void:
+ if not is_character_joined(character):
return
+ portrait = get_valid_portrait(character, portrait)
+
if dialogic.current_state_info.portraits[character.resource_path].portrait == portrait:
return
- var info := _change_portrait(dialogic.current_state_info.portraits[character.resource_path].node, portrait, update_transform)
+ if fade_animation == "DEFAULT":
+ fade_animation = ProjectSettings.get_setting('dialogic/animations/cross_fade_default', "Fade Cross")
+ fade_length = ProjectSettings.get_setting('dialogic/animations/cross_fade_default_length', 0.5)
+
+ fade_animation = DialogicPortraitAnimationUtil.guess_animation(fade_animation, DialogicPortraitAnimationUtil.AnimationType.CROSSFADE)
+
+ var info := _change_portrait(dialogic.current_state_info.portraits[character.resource_path].node, portrait, fade_animation, fade_length)
dialogic.current_state_info.portraits[character.resource_path].portrait = info.portrait
_change_portrait_mirror(
dialogic.current_state_info.portraits[character.resource_path].node,
@@ -389,6 +477,7 @@ func change_character_mirror(character:DialogicCharacter, mirrored:= false, forc
func change_character_z_index(character:DialogicCharacter, z_index:int, update_zindex:= true) -> void:
if !is_character_joined(character):
return
+
_change_portrait_z_index(dialogic.current_state_info.portraits[character.resource_path].node, z_index, update_zindex)
if update_zindex:
dialogic.current_state_info.portraits[character.resource_path]['z_index'] = z_index
@@ -403,105 +492,115 @@ func change_character_extradata(character:DialogicCharacter, extra_data:="") ->
## Starts the given animation on the given character. Only works with joined characters
-func animate_character(character:DialogicCharacter, animation_path:String, length:float, repeats := 1) -> DialogicAnimation:
- if !is_character_joined(character):
+func animate_character(character: DialogicCharacter, animation_path: String, length: float, repeats := 1, is_reversed := false) -> DialogicAnimation:
+ if not is_character_joined(character):
return null
- animation_path = DialogicResourceUtil.guess_special_resource("PortraitAnimation", animation_path, "")
+ animation_path = DialogicPortraitAnimationUtil.guess_animation(animation_path)
- return _animate_portrait(dialogic.current_state_info.portraits[character.resource_path].node, animation_path, length, repeats)
+ var character_node: Node = dialogic.current_state_info.portraits[character.resource_path].node
+
+ return _animate_node(character_node, animation_path, length, repeats, is_reversed)
## Moves the given character to the given position. Only works with joined characters
-func move_character(character:DialogicCharacter, position_idx:int, time:= 0.0) -> void:
+func move_character(character:DialogicCharacter, position_id:String, time:= 0.0, easing:=Tween.EASE_IN_OUT, trans:=Tween.TRANS_SINE) -> void:
if !is_character_joined(character):
return
- if dialogic.current_state_info.portraits[character.resource_path].position_index == position_idx:
+ if dialogic.current_state_info.portraits[character.resource_path].position_id == position_id:
return
- for portrait_position in get_tree().get_nodes_in_group('dialogic_portrait_con_position'):
- if portrait_position.is_visible_in_tree() and portrait_position.position_index == position_idx:
- _move_portrait(dialogic.current_state_info.portraits[character.resource_path].node, portrait_position, time)
- dialogic.current_state_info.portraits[character.resource_path].position_index = position_idx
- character_moved.emit({'character':character, 'position_index':position_idx, 'time':time})
- return
-
- printerr('[Dialogic] Unable to move character to position ', position_idx, ". Couldn't find position container.")
+ _move_character(dialogic.current_state_info.portraits[character.resource_path].node, position_id, time, easing, trans)
+ dialogic.current_state_info.portraits[character.resource_path].position_id = position_id
+ character_moved.emit({'character':character, 'position_id':position_id, 'time':time})
## Removes a character with a given animation or the default animation.
-func leave_character(character:DialogicCharacter, animation_name:= "", animation_length:= 0.0, animation_wait := false) -> void:
- if !is_character_joined(character):
+func leave_character(character: DialogicCharacter, animation_name:= "", animation_length:= 0.0, animation_wait := false) -> void:
+ if not is_character_joined(character):
return
if animation_name.is_empty():
- animation_name = ProjectSettings.get_setting('dialogic/animations/leave_default',
- get_script().resource_path.get_base_dir().path_join('DefaultAnimations/fade_out_down.gd'))
+ animation_name = ProjectSettings.get_setting('dialogic/animations/leave_default', "Fade Out Down")
animation_length = _get_leave_default_length()
animation_wait = ProjectSettings.get_setting('dialogic/animations/leave_default_wait', true)
- animation_name = DialogicResourceUtil.guess_special_resource("PortraitAnimation", animation_name, "")
-
- if !animation_name.is_empty():
- var anim := animate_character(character, animation_name, animation_length)
+ animation_name = DialogicPortraitAnimationUtil.guess_animation(animation_name, DialogicPortraitAnimationUtil.AnimationType.OUT)
- anim.finished.connect(remove_character.bind(character))
+ if not animation_name.is_empty():
+ var character_node := get_character_node(character)
- if animation_wait:
- dialogic.current_state = DialogicGameHandler.States.ANIMATING
- await anim.finished
- dialogic.current_state = DialogicGameHandler.States.IDLE
- else:
- remove_character(character)
+ var animation := _animate_node(character_node, animation_name, animation_length, 1, true)
+ if animation_length > 0:
+ if animation_wait:
+ dialogic.current_state = DialogicGameHandler.States.ANIMATING
+ await animation.finished
+ dialogic.current_state = DialogicGameHandler.States.IDLE
+ remove_character(character)
+ else:
+ animation.finished.connect(func(): remove_character(character))
+ else:
+ remove_character(character)
## Removes all joined characters with a given animation or the default animation.
-func leave_all_characters(animation_name:="", animation_length:=0.0, animation_wait:= false) -> void:
+func leave_all_characters(animation_name:="", animation_length:=0.0, animation_wait := false) -> void:
for character in get_joined_characters():
- leave_character(character, animation_name, animation_length, false)
+ await leave_character(character, animation_name, animation_length, animation_wait)
- if animation_name.is_empty():
- animation_length = _get_leave_default_length()
- animation_wait = ProjectSettings.get_setting('dialogic/animations/leave_default_wait', true)
- if animation_wait:
- dialogic.current_state = DialogicGameHandler.States.ANIMATING
- await get_tree().create_timer(animation_length).timeout
- dialogic.current_state = DialogicGameHandler.States.IDLE
+## Finds the character node for a [param character].
+## Return `null` if the [param character] is not part of the scene.
+func get_character_node(character: DialogicCharacter) -> Node:
+ if is_character_joined(character):
+ if is_instance_valid(dialogic.current_state_info['portraits'][character.resource_path].node):
+ return dialogic.current_state_info['portraits'][character.resource_path].node
+ return null
-## Removes the given characters portrait. Only works with joined characters
-func remove_character(character:DialogicCharacter) -> void:
- if !is_character_joined(character):
- return
- if is_instance_valid(dialogic.current_state_info['portraits'][character.resource_path].node) and \
- dialogic.current_state_info['portraits'][character.resource_path].node is Node:
- _remove_portrait(dialogic.current_state_info['portraits'][character.resource_path].node)
- character_left.emit({'character':character})
+## Removes the given characters portrait.
+## Only works with joined characters.
+func remove_character(character: DialogicCharacter) -> void:
+ var character_node := get_character_node(character)
+
+ if is_instance_valid(character_node) and character_node is Node:
+ var container := character_node.get_parent()
+ container.get_parent().remove_child(container)
+ container.queue_free()
+ character_node.queue_free()
+ character_left.emit({'character': character})
+
dialogic.current_state_info['portraits'].erase(character.resource_path)
+func get_current_character() -> DialogicCharacter:
+ if dialogic.current_state_info.get('speaker', null):
+ return load(dialogic.current_state_info.speaker)
+ return null
+
+
+
## Returns true if the given character is currently joined.
-func is_character_joined(character:DialogicCharacter) -> bool:
- if not character or !character.resource_path in dialogic.current_state_info['portraits']:
+func is_character_joined(character: DialogicCharacter) -> bool:
+ if character == null or not character.resource_path in dialogic.current_state_info['portraits']:
return false
- if dialogic.current_state_info['portraits'][character.resource_path].get('node', null) != null and \
- is_instance_valid(dialogic.current_state_info['portraits'][character.resource_path].node):
- return true
- return false
+
+ return true
## Returns a list of the joined charcters (as resources)
func get_joined_characters() -> Array[DialogicCharacter]:
- var chars: Array[DialogicCharacter]= []
- for char_path in dialogic.current_state_info.get('portraits', {}).keys():
+ var chars: Array[DialogicCharacter] = []
+
+ for char_path: String in dialogic.current_state_info.get('portraits', {}).keys():
chars.append(load(char_path))
+
return chars
## Returns a dictionary with info on a given character.
-## Keys can be [joined, character, node (for the portrait node), position_index]
+## Keys can be [joined, character, node (for the portrait node), position_id]
## Only joined is included (and false) for not joined characters
func get_character_info(character:DialogicCharacter) -> Dictionary:
if is_character_joined(character):
@@ -514,105 +613,78 @@ func get_character_info(character:DialogicCharacter) -> Dictionary:
#endregion
-#region Positions
-####################################################################################################
-
-func get_portrait_container(postion_index:int) -> DialogicNode_PortraitContainer:
- for portrait_position in get_tree().get_nodes_in_group('dialogic_portrait_con_position'):
- if portrait_position.is_visible_in_tree() and portrait_position.position_index == postion_index:
- return portrait_position
- return null
-
-
-## Creates a new portrait container node.
-## It will copy it's size and most settings from the first p_container in the tree.
-## It will be added as a sibling of the first p_container in the tree.
-func add_portrait_position(position_index: int, position:Vector2) -> void:
- var example_position := get_tree().get_first_node_in_group('dialogic_portrait_con_position')
- if example_position:
- var new_position := DialogicNode_PortraitContainer.new()
- example_position.get_parent().add_child(new_position)
- new_position.size = example_position.size
- new_position.size_mode = example_position.size_mode
- new_position.origin_anchor = example_position.origin_anchor
- new_position.position_index = position_index
- new_position.position = position-new_position._get_origin_position()
- position_changed.emit({'change':'added', 'container_node':new_position, 'position_index':position_index})
-
-
-func move_portrait_position(position_index: int, vector:Vector2, relative:= false, time:= 0.0) -> void:
- for portrait_container in get_tree().get_nodes_in_group('dialogic_portrait_con_position'):
- if portrait_container.is_visible_in_tree() and portrait_container.position_index == position_index:
- if !portrait_container.has_meta('default_position'):
- portrait_container.set_meta('default_position', portrait_container.position)
- var tween := portrait_container.create_tween()
- if !relative:
- tween.tween_property(portrait_container, 'position', vector, time)
- else:
- tween.tween_property(portrait_container, 'position', vector, time).as_relative()
- position_changed.emit({'change':'moved', 'container_node':portrait_container, 'position_index':position_index})
- return
-
- # If this is reached, no position could be found. If the position is absolute, we will add it.
- if !relative:
- add_portrait_position(position_index, vector)
-
-
-func reset_all_portrait_positions(time:= 0.0) -> void:
- for portrait_position in get_tree().get_nodes_in_group('dialogic_portrait_con_position'):
- if portrait_position.is_visible_in_tree():
- if portrait_position.has_meta('default_position'):
- move_portrait_position(portrait_position.position_index, portrait_position.get_meta('default_position'), false, time)
-
-
-func reset_portrait_position(position_index:int, time:= 0.0) -> void:
- for portrait_position in get_tree().get_nodes_in_group('dialogic_portrait_con_position'):
- if portrait_position.is_visible_in_tree() and portrait_position.position_index == position_index:
- if portrait_position.has_meta('default_position'):
- move_portrait_position(position_index, portrait_position.get_meta('default_position'), false, time)
-
-#endregion
-
-
#region SPEAKER PORTRAIT CONTAINERS
####################################################################################################
## Updates all portrait containers set to SPEAKER.
-func change_speaker(speaker:DialogicCharacter = null, portrait:= ""):
- for con in get_tree().get_nodes_in_group('dialogic_portrait_con_speaker'):
- for character_node in con.get_children():
- if character_node.get_meta('character') != speaker:
- _remove_portrait(character_node)
+func change_speaker(speaker: DialogicCharacter = null, portrait := "") -> void:
+ for container: Node in get_tree().get_nodes_in_group('dialogic_portrait_con_speaker'):
+ var just_joined := true
+ for character_node: Node in container.get_children():
+ if not character_node.get_meta('character') == speaker:
+ var leave_animation: String = ProjectSettings.get_setting('dialogic/animations/leave_default', "Fade Out")
+ leave_animation = DialogicPortraitAnimationUtil.guess_animation(leave_animation, DialogicPortraitAnimationUtil.AnimationType.OUT)
+ var leave_animation_length := _get_leave_default_length()
+
+ if leave_animation and leave_animation_length:
+ var animate_out := _animate_node(character_node, leave_animation, leave_animation_length, 1, true)
+ animate_out.finished.connect(character_node.queue_free)
+ else:
+ character_node.get_parent().remove_child(character_node)
+ character_node.queue_free()
+ else:
+ just_joined = false
if speaker == null or speaker.portraits.is_empty():
continue
- if con.get_children().is_empty():
- _create_character_node(speaker, con)
+ if just_joined:
+ _create_character_node(speaker, container)
+
elif portrait.is_empty():
continue
if portrait.is_empty(): portrait = speaker.default_portrait
- if con.portrait_prefix+portrait in speaker.portraits:
- _change_portrait(con.get_child(0), con.portrait_prefix+portrait)
- else:
- _change_portrait(con.get_child(0), portrait)
+ var fade_animation: String = ProjectSettings.get_setting('dialogic/animations/cross_fade_default', "Fade Cross")
+ var fade_length: float = ProjectSettings.get_setting('dialogic/animations/cross_fade_default_length', 0.5)
+
+ fade_animation = DialogicPortraitAnimationUtil.guess_animation(fade_animation, DialogicPortraitAnimationUtil.AnimationType.CROSSFADE)
+
+ if container.portrait_prefix+portrait in speaker.portraits:
+ portrait = container.portrait_prefix+portrait
+
+ _change_portrait(container.get_child(-1), portrait, fade_animation, fade_length)
# if the character has no portraits _change_portrait won't actually add a child node
- if con.get_child(0).get_child_count() == 0:
+ if container.get_child(-1).get_child_count() == 0:
continue
- _change_portrait_mirror(con.get_child(0))
+ if just_joined:
+ # Change speaker is called before the text is changed.
+ # In styles where the speaker is IN the textbox,
+ # this can mean the portrait container isn't sized correctly yet.
+ if not container.is_visible_in_tree():
+ await get_tree().process_frame
+ var join_animation: String = ProjectSettings.get_setting('dialogic/animations/join_default', "Fade In Up")
+ join_animation = DialogicPortraitAnimationUtil.guess_animation(join_animation, DialogicPortraitAnimationUtil.AnimationType.IN)
+ var join_animation_length := _get_join_default_length()
+
+ if join_animation and join_animation_length:
+ _animate_node(container.get_child(-1), join_animation, join_animation_length)
+
+ _change_portrait_mirror(container.get_child(-1))
if speaker:
if speaker.resource_path != dialogic.current_state_info['speaker']:
if dialogic.current_state_info['speaker'] and is_character_joined(load(dialogic.current_state_info['speaker'])):
- dialogic.current_state_info['portraits'][dialogic.current_state_info['speaker']].node.get_child(0)._unhighlight()
+ dialogic.current_state_info['portraits'][dialogic.current_state_info['speaker']].node.get_child(-1)._unhighlight()
+
if speaker and is_character_joined(speaker):
- dialogic.current_state_info['portraits'][speaker.resource_path].node.get_child(0)._highlight()
+ dialogic.current_state_info['portraits'][speaker.resource_path].node.get_child(-1)._highlight()
+
elif dialogic.current_state_info['speaker'] and is_character_joined(load(dialogic.current_state_info['speaker'])):
- dialogic.current_state_info['portraits'][dialogic.current_state_info['speaker']].node.get_child(0)._unhighlight()
+ dialogic.current_state_info['portraits'][dialogic.current_state_info['speaker']].node.get_child(-1)._unhighlight()
#endregion
@@ -621,7 +693,7 @@ func change_speaker(speaker:DialogicCharacter = null, portrait:= ""):
####################################################################################################
## Called from the [portrait=something] text effect.
-func text_effect_portrait(text_node:Control, skipped:bool, argument:String) -> void:
+func text_effect_portrait(_text_node:Control, _skipped:bool, argument:String) -> void:
if argument:
if dialogic.current_state_info.get('speaker', null):
change_character_portrait(load(dialogic.current_state_info.speaker), argument)
diff --git a/addons/dialogic/Modules/Choice/event_choice.gd b/addons/dialogic/Modules/Choice/event_choice.gd
index 1eef08c14..7e4364c32 100644
--- a/addons/dialogic/Modules/Choice/event_choice.gd
+++ b/addons/dialogic/Modules/Choice/event_choice.gd
@@ -9,25 +9,32 @@ enum ElseActions {HIDE=0, DISABLE=1, DEFAULT=2}
### Settings
## The text that is displayed on the choice button.
-var text :String = ""
+var text := ""
## If not empty this condition will determine if this choice is active.
-var condition: String = ""
+var condition := ""
## Determines what happens if [condition] is false. Default will use the action set in the settings.
-var else_action: = ElseActions.DEFAULT
+var else_action := ElseActions.DEFAULT
## The text that is displayed if [condition] is false and [else_action] is Disable.
## If empty [text] will be used for disabled button as well.
-var disabled_text: String = ""
+var disabled_text := ""
+## A dictionary that can be filled with arbitrary information
+## This can then be interpreted by a custom choice layer
+var extra_data := {}
+
+
+## UI helper
+var _has_condition := false
#endregion
+var regex := RegEx.create_from_string(r'- (?(?>\\\||(?(?=.*\|)[^|]|(?!\[if)[^|]))*)\|?\s*(\[if(?([^\]\[]|\[[^\]]*\])+)\])?\s*(\[(?[^]]*)\])?')
#region EXECUTION
################################################################################
func _execute() -> void:
-
if dialogic.Choices.is_question(dialogic.current_event_idx):
- dialogic.Choices.show_current_choices(false)
+ dialogic.Choices.show_current_question(false)
dialogic.current_state = dialogic.States.AWAITING_CHOICE
#endregion
@@ -58,40 +65,51 @@ func to_text() -> String:
var result_string := ""
result_string = "- "+text.strip_edges()
- if condition:
- result_string += " [if "+condition+"]"
-
+ var shortcode := store_to_shortcode_parameters()
+ if (condition and _has_condition) or shortcode or extra_data:
+ result_string += " |"
+ if condition and _has_condition:
+ result_string += " [if " + condition + "]"
+
+ if shortcode or extra_data:
+ result_string += " [" + shortcode
+ if extra_data:
+ var extra_data_string := ""
+ for i in extra_data:
+ extra_data_string += " " + i + '="' + value_to_string(extra_data[i]) + '"'
+ if shortcode:
+ result_string += " "
+ result_string += extra_data_string.strip_edges()
+ result_string += "]"
- var shortcode = '['
- if else_action == ElseActions.HIDE:
- shortcode += 'else="hide"'
- elif else_action == ElseActions.DISABLE:
- shortcode += 'else="disable"'
-
- if disabled_text:
- shortcode += " alt_text="+'"'+disabled_text+'"'
-
- if len(shortcode) > 1:
- result_string += shortcode + "]"
return result_string
func from_text(string:String) -> void:
- var regex = RegEx.new()
- regex.compile('- (?(?(?=\\[if)|.)*)(\\[if (?[^\\]]+)])?\\s?(\\s*\\[(?.*)\\])?')
- var result = regex.search(string.strip_edges())
+ var result := regex.search(string.strip_edges())
if result == null:
return
- text = result.get_string('text')
- condition = result.get_string('condition')
+ text = result.get_string('text').strip_edges()
+ condition = result.get_string('condition').strip_edges()
+ _has_condition = not condition.is_empty()
if result.get_string('shortcode'):
- var shortcode_params = parse_shortcode_parameters(result.get_string('shortcode'))
- else_action = {
- 'default':ElseActions.DEFAULT,
- 'hide':ElseActions.HIDE,
- 'disable':ElseActions.DISABLE}.get(shortcode_params.get('else', ''), ElseActions.DEFAULT)
+ load_from_shortcode_parameters(result.get_string("shortcode"))
+ var shortcode := parse_shortcode_parameters(result.get_string('shortcode'))
+ shortcode.erase("else")
+ shortcode.erase("alt_text")
+ extra_data = shortcode.duplicate()
- disabled_text = shortcode_params.get('alt_text', '')
+
+func get_shortcode_parameters() -> Dictionary:
+ return {
+ "else" : {"property": "else_action", "default": ElseActions.DEFAULT,
+ "suggestions": func(): return {
+ "Default" :{'value':ElseActions.DEFAULT, 'text_alt':['default']},
+ "Hide" :{'value':ElseActions.HIDE,'text_alt':['hide'] },
+ "Disable" :{'value':ElseActions.DISABLE,'text_alt':['disable']}}},
+ "alt_text" : {"property": "disabled_text", "default": ""},
+ "extra_data" : {"property": "extra_data", "default": {}, "custom_stored":true},
+ }
func is_valid_event(string:String) -> bool:
@@ -123,8 +141,11 @@ func _get_property_original_translation(property:String) -> String:
func build_event_editor() -> void:
add_header_edit("text", ValueType.SINGLELINE_TEXT, {'autofocus':true})
- add_body_edit("condition", ValueType.CONDITION, {'left_text':'if '})
- add_body_edit("else_action", ValueType.FIXED_OPTIONS, {'left_text':'else ',
+ add_body_edit("", ValueType.LABEL, {"text":"Condition:"})
+ add_body_edit("_has_condition", ValueType.BOOL_BUTTON, {"editor_icon":["Add", "EditorIcons"], "tooltip":"Add Condition"}, "not _has_condition")
+ add_body_edit("condition", ValueType.CONDITION, {}, "_has_condition")
+ add_body_edit("_has_condition", ValueType.BOOL_BUTTON, {"editor_icon":["Remove", "EditorIcons"], "tooltip":"Remove Condition"}, "_has_condition")
+ add_body_edit("else_action", ValueType.FIXED_OPTIONS, {'left_text':'Else:',
'options': [
{
'label': 'Default',
@@ -138,14 +159,16 @@ func build_event_editor() -> void:
'label': 'Disable',
'value': ElseActions.DISABLE,
}
- ]}, '!condition.is_empty()')
+ ]}, '_has_condition')
add_body_edit("disabled_text", ValueType.SINGLELINE_TEXT, {
'left_text':'Disabled text:',
'placeholder':'(Empty for same)'}, 'allow_alt_text()')
+ add_body_line_break()
+ add_body_edit("extra_data", ValueType.DICTIONARY, {"left_text":"Extra Data:"})
func allow_alt_text() -> bool:
- return condition and (
+ return _has_condition and (
else_action == ElseActions.DISABLE or
(else_action == ElseActions.DEFAULT and
ProjectSettings.get_setting("dialogic/choices/def_false_behaviour", 0) == 1))
@@ -155,10 +178,9 @@ func allow_alt_text() -> bool:
#region CODE COMPLETION
################################################################################
-func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, word:String, symbol:String) -> void:
+func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, _word:String, symbol:String) -> void:
line = CodeCompletionHelper.get_line_untill_caret(line)
-
if !'[if' in line:
if symbol == '{':
CodeCompletionHelper.suggest_variables(TextNode)
@@ -184,14 +206,27 @@ func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:Str
################################################################################
func _get_syntax_highlighting(Highlighter:SyntaxHighlighter, dict:Dictionary, line:String) -> Dictionary:
+ var result := regex.search(line)
+
dict[0] = {'color':event_color}
- dict = Highlighter.color_region(dict, event_color.lerp(Highlighter.variable_color, 0.5), line, '{','}', 0, line.find('[if'), event_color)
- if '[if' in line:
+
+ if not result:
+ return dict
+
+ var condition_begin := result.get_start("condition")
+ var condition_end := result.get_end("condition")
+
+ var shortcode_begin := result.get_start("shortcode")
+
+ dict = Highlighter.color_region(dict, event_color.lerp(Highlighter.variable_color, 0.5), line, '{','}', 0, condition_begin, event_color)
+
+ if condition_begin > 0:
var from := line.find('[if')
dict[from] = {"color":Highlighter.normal_color}
- dict = Highlighter.color_word(dict, Highlighter.code_flow_color, line, 'if', from, line.find(']', from))
- dict = Highlighter.color_condition(dict, line, from, line.find(']', from))
- dict = Highlighter.color_shortcode_content(dict, line, line.find(']', from), 0,event_color)
+ dict[from+1] = {"color":Highlighter.code_flow_color}
+ dict[condition_begin] = {"color":Highlighter.normal_color}
+ dict = Highlighter.color_condition(dict, line, condition_begin, condition_end)
+ if shortcode_begin:
+ dict = Highlighter.color_shortcode_content(dict, line, shortcode_begin, 0, event_color)
return dict
#endregion
-
diff --git a/addons/dialogic/Modules/Choice/node_button_sound.gd b/addons/dialogic/Modules/Choice/node_button_sound.gd
index e6d7e5217..3f6cdbefd 100644
--- a/addons/dialogic/Modules/Choice/node_button_sound.gd
+++ b/addons/dialogic/Modules/Choice/node_button_sound.gd
@@ -3,15 +3,15 @@ extends AudioStreamPlayer
## Node that is used for playing sound effects on hover/focus/press of sibling DialogicNode_ChoiceButtons.
-## Sound to be played if one of the sibling ChoiceButtons is pressed.
+## Sound to be played if one of the sibling ChoiceButtons is pressed.
## If sibling ChoiceButton has a sound_pressed set, that is prioritized.
-@export var sound_pressed:AudioStream
+@export var sound_pressed: AudioStream
## Sound to be played on hover. See [sound_pressed] for more.
-@export var sound_hover:AudioStream
+@export var sound_hover: AudioStream
## Sound to be played on focus. See [sound_pressed] for more.
-@export var sound_focus:AudioStream
+@export var sound_focus: AudioStream
-func _ready():
+func _ready() -> void:
add_to_group('dialogic_button_sound')
_connect_all_buttons()
@@ -21,7 +21,7 @@ func play_sound(sound) -> void:
stream = sound
play()
-func _connect_all_buttons():
+func _connect_all_buttons() -> void:
for child in get_parent().get_children():
if child is DialogicNode_ChoiceButton:
child.button_up.connect(_on_pressed.bind(child.sound_pressed))
diff --git a/addons/dialogic/Modules/Choice/node_choice_button.gd b/addons/dialogic/Modules/Choice/node_choice_button.gd
index 1b0dfe8a8..8e82436b6 100644
--- a/addons/dialogic/Modules/Choice/node_choice_button.gd
+++ b/addons/dialogic/Modules/Choice/node_choice_button.gd
@@ -12,7 +12,6 @@ extends Button
## not supported on buttons at this point.
-
## Used to identify what choices to put on. If you leave it at -1, choices will be distributed automatically.
@export var choice_index: int = -1
@@ -26,16 +25,22 @@ extends Button
@export var text_node: Node
-## Called when the text changes.
-func _set_text_changed(new_text: String) -> void:
- if text_node == null:
- text = new_text
-
- else:
- text_node.text = new_text
-
-
func _ready() -> void:
add_to_group('dialogic_choice_button')
shortcut_in_tooltip = false
hide()
+
+
+func _load_info(choice_info: Dictionary) -> void:
+ set_choice_text(choice_info.text)
+ visible = choice_info.visible
+ disabled = choice_info.disabled
+
+
+## Called when the text changes.
+func set_choice_text(new_text: String) -> void:
+ if text_node:
+ text_node.text = new_text
+ else:
+ text = new_text
+
diff --git a/addons/dialogic/Modules/Choice/settings_choices.gd b/addons/dialogic/Modules/Choice/settings_choices.gd
index cfd736d8b..66e4482a4 100644
--- a/addons/dialogic/Modules/Choice/settings_choices.gd
+++ b/addons/dialogic/Modules/Choice/settings_choices.gd
@@ -7,8 +7,8 @@ func _refresh() -> void:
%FalseBehaviour.select(ProjectSettings.get_setting('dialogic/choices/def_false_behaviour', 0))
%HotkeyType.select(ProjectSettings.get_setting('dialogic/choices/hotkey_behaviour', 0))
- var reveal_delay :float = ProjectSettings.get_setting('dialogic/choices/reveal_delay', 0)
- var reveal_by_input :bool = ProjectSettings.get_setting('dialogic/choices/reveal_by_input', false)
+ var reveal_delay: float = ProjectSettings.get_setting('dialogic/choices/reveal_delay', 0)
+ var reveal_by_input: bool = ProjectSettings.get_setting('dialogic/choices/reveal_by_input', false)
if not reveal_by_input and reveal_delay == 0:
_on_appear_mode_item_selected(0)
if not reveal_by_input and reveal_delay != 0:
diff --git a/addons/dialogic/Modules/Choice/subsystem_choices.gd b/addons/dialogic/Modules/Choice/subsystem_choices.gd
index 3ee43f831..14e61a140 100644
--- a/addons/dialogic/Modules/Choice/subsystem_choices.gd
+++ b/addons/dialogic/Modules/Choice/subsystem_choices.gd
@@ -6,19 +6,20 @@ extends DialogicSubsystem
signal choice_selected(info:Dictionary)
## Emitted when a set of choices is reached and shown.
## Info includes the keys 'choices' (an array of dictionaries with infos on all the choices).
-signal choices_shown(info:Dictionary)
+signal question_shown(info:Dictionary)
## Contains information on the latest question.
var last_question_info := {}
## The delay between the text finishing revealing and the choices appearing
-var reveal_delay: float = 0.0
+var reveal_delay := 0.0
## If true the player has to click to reveal choices when they are reached
-var reveal_by_input: bool = false
+var reveal_by_input := false
## The delay between the choices becoming visible and being clickable. Can prevent accidental selection.
-var block_delay: float = 0.2
+var block_delay := 0.2
## If true, the first (top-most) choice will be focused
-var autofocus_first_choice: bool = true
+var autofocus_first_choice := true
+
enum FalseBehaviour {HIDE=0, DISABLE=1}
## The behaviour of choices with a false condition and else_action set to DEFAULT.
@@ -37,7 +38,7 @@ var _choice_blocker := Timer.new()
#region STATE
####################################################################################################
-func clear_game_state(clear_flag:=DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
+func clear_game_state(_clear_flag:=DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
hide_all_choices()
@@ -63,123 +64,161 @@ func _ready() -> void:
func hide_all_choices() -> void:
for node in get_tree().get_nodes_in_group('dialogic_choice_button'):
node.hide()
- if node.is_connected('button_up', _on_ChoiceButton_choice_selected):
- node.disconnect('button_up', _on_ChoiceButton_choice_selected)
+ if node.is_connected('button_up', _on_choice_selected):
+ node.disconnect('button_up', _on_choice_selected)
+
+
+## Collects information on all the choices of the current question.
+## The result is a dictionary like this:
+## {'choices':
+## [
+## {'event_index':10, 'button_index':1, 'disabled':false, 'text':"My Choice", 'visible':true},
+## {'event_index':15, 'button_index':2, 'disabled':false, 'text':"My Choice2", 'visible':true},
+## ]
+func get_current_question_info() -> Dictionary:
+ var question_info := {'choices':[]}
+
+ var button_idx := 1
+ last_question_info = {'choices':[]}
+
+ for choice_index in get_current_choice_indexes():
+ var event: DialogicEvent = dialogic.current_timeline_events[choice_index]
+
+ if not event is DialogicChoiceEvent:
+ continue
+
+ var choice_event: DialogicChoiceEvent = event
+ var choice_info := {}
+ choice_info['event_index'] = choice_index
+ choice_info['button_index'] = button_idx
+
+ # Check Condition
+ var condition: String = choice_event.condition
+
+ if condition.is_empty() or dialogic.Expressions.execute_condition(choice_event.condition):
+ choice_info['disabled'] = false
+ choice_info['text'] = choice_event.get_property_translated('text')
+ choice_info['visible'] = true
+ button_idx += 1
+ else:
+ choice_info['disabled'] = true
+ if not choice_event.disabled_text.is_empty():
+ choice_info['text'] = choice_event.get_property_translated('disabled_text')
+ else:
+ choice_info['text'] = choice_event.get_property_translated('text')
+
+ var hide := choice_event.else_action == DialogicChoiceEvent.ElseActions.HIDE
+ hide = hide or choice_event.else_action == DialogicChoiceEvent.ElseActions.DEFAULT and default_false_behaviour == DialogicChoiceEvent.ElseActions.HIDE
+ choice_info['visible'] = not hide
+
+ if not hide:
+ button_idx += 1
+
+ choice_info.text = dialogic.Text.parse_text(choice_info.text, true, true, false, true, false, false)
+
+ choice_info.merge(choice_event.extra_data)
+
+ if dialogic.has_subsystem('History'):
+ choice_info['visited_before'] = dialogic.History.has_event_been_visited(choice_index)
+
+ question_info['choices'].append(choice_info)
+
+ return question_info
## Lists all current choices and shows buttons.
-func show_current_choices(instant:=true) -> void:
+func show_current_question(instant:=true) -> void:
hide_all_choices()
_choice_blocker.stop()
if !instant and (reveal_delay != 0 or reveal_by_input):
if reveal_delay != 0:
_choice_blocker.start(reveal_delay)
- _choice_blocker.timeout.connect(show_current_choices)
+ _choice_blocker.timeout.connect(show_current_question)
if reveal_by_input:
- dialogic.Inputs.dialogic_action.connect(show_current_choices)
+ dialogic.Inputs.dialogic_action.connect(show_current_question)
return
- if _choice_blocker.timeout.is_connected(show_current_choices):
- _choice_blocker.timeout.disconnect(show_current_choices)
- if dialogic.Inputs.dialogic_action.is_connected(show_current_choices):
- dialogic.Inputs.dialogic_action.disconnect(show_current_choices)
+ if _choice_blocker.timeout.is_connected(show_current_question):
+ _choice_blocker.timeout.disconnect(show_current_question)
+ if dialogic.Inputs.dialogic_action.is_connected(show_current_question):
+ dialogic.Inputs.dialogic_action.disconnect(show_current_question)
+ var missing_button := false
- var button_idx := 1
- last_question_info = {'choices':[]}
- for choice_index in get_current_choice_indexes():
- var choice_event: DialogicEvent = dialogic.current_timeline_events[choice_index]
- # check if condition is false
- if not choice_event.condition.is_empty() and not dialogic.Expressions.execute_condition(choice_event.condition):
- if choice_event.else_action == DialogicChoiceEvent.ElseActions.DEFAULT:
- choice_event.else_action = default_false_behaviour
-
- # check what to do in this case
- if choice_event.else_action == DialogicChoiceEvent.ElseActions.DISABLE:
- if !choice_event.disabled_text.is_empty():
- show_choice(button_idx, choice_event.get_property_translated('disabled_text'), false, choice_index)
- last_question_info['choices'].append(choice_event.get_property_translated('disabled_text')+'#disabled')
- else:
- show_choice(button_idx, choice_event.get_property_translated('text'), false, choice_index)
- last_question_info['choices'].append(choice_event.get_property_translated('text')+'#disabled')
- button_idx += 1
- # else just show it
- else:
- show_choice(button_idx, choice_event.get_property_translated('text'), true, choice_index)
- last_question_info['choices'].append(choice_event.get_property_translated('text'))
- button_idx += 1
- choices_shown.emit(last_question_info)
- _choice_blocker.start(block_delay)
+ var question_info := get_current_question_info()
+ for choice in question_info.choices:
+ var node: DialogicNode_ChoiceButton = get_choice_button_node(choice.button_index)
-## Adds a button with the given text that leads to the given event.
-func show_choice(button_index:int, text:String, enabled:bool, event_index:int) -> void:
- var idx := 1
- var shown_at_all := false
- for node: DialogicNode_ChoiceButton in get_tree().get_nodes_in_group('dialogic_choice_button'):
- if !node.get_parent().is_visible_in_tree():
+ if not node:
+ missing_button = true
continue
- if (node.choice_index == button_index) or (idx == button_index and node.choice_index == -1):
- node.show()
+ node._load_info(choice)
- if dialogic.has_subsystem('Text'):
- text = dialogic.Text.parse_text(text, true, true, false, true, false, false)
+ if choice.button_index == 1 and autofocus_first_choice:
+ node.grab_focus()
- node._set_text_changed(text)
+ match hotkey_behaviour:
+ ## Add 1 to 9 as shortcuts if it's enabled
+ HotkeyBehaviour.NUMBERS:
+ if choice.button_index > 0 or choice.button_index < 10:
+ var shortcut: Shortcut
+ if node.shortcut != null:
+ shortcut = node.shortcut
+ else:
+ shortcut = Shortcut.new()
+
+ var input_key := InputEventKey.new()
+ input_key.keycode = OS.find_keycode_from_string(str(choice.button_index))
+ shortcut.events.append(input_key)
+ node.shortcut = shortcut
+
+ if node.pressed.is_connected(_on_choice_selected):
+ node.pressed.disconnect(_on_choice_selected)
+ node.pressed.connect(_on_choice_selected.bind(choice))
+
+ _choice_blocker.start(block_delay)
+ question_shown.emit(question_info)
+
+ if missing_button:
+ printerr("[Dialogic] The layout you are using doesn't have enough Choice Buttons for the choices you are trying to display.")
- if idx == 1 and autofocus_first_choice:
- node.grab_focus()
- ## Add 1 to 9 as shortcuts if it's enabled
- match hotkey_behaviour:
- HotkeyBehaviour.NUMBERS:
- if idx > 0 or idx < 10:
- var shortcut: Shortcut
- if node.shortcut != null:
- shortcut = node.shortcut
- else:
- shortcut = Shortcut.new()
-
- var shortcut_events: Array[InputEventKey] = []
- var input_key := InputEventKey.new()
- input_key.keycode = OS.find_keycode_from_string(str(idx))
- shortcut.events.append(input_key)
- node.shortcut = shortcut
-
- node.disabled = not enabled
-
- if node.pressed.is_connected(_on_ChoiceButton_choice_selected):
- node.pressed.disconnect(_on_ChoiceButton_choice_selected)
-
- node.pressed.connect(_on_ChoiceButton_choice_selected.bind(event_index,
- {'button_index':button_index, 'text':text, 'enabled':enabled, 'event_index':event_index}))
- shown_at_all = true
+
+func get_choice_button_node(button_index:int) -> DialogicNode_ChoiceButton:
+ var idx := 1
+ for node: DialogicNode_ChoiceButton in get_tree().get_nodes_in_group('dialogic_choice_button'):
+ if !node.get_parent().is_visible_in_tree():
+ continue
+ if node.choice_index == button_index or (node.choice_index == -1 and idx == button_index):
+ return node
if node.choice_index > 0:
idx = node.choice_index
idx += 1
- if not shown_at_all:
- printerr("[Dialogic] The layout you are using doesn't have enough Choice Buttons for the choices you are trying to display.")
+ return null
-func _on_ChoiceButton_choice_selected(event_index:int, choice_info:={}) -> void:
+func _on_choice_selected(choice_info := {}) -> void:
if dialogic.paused or not _choice_blocker.is_stopped():
return
- choice_selected.emit(choice_info)
- hide_all_choices()
- dialogic.current_state = dialogic.States.IDLE
- dialogic.handle_event(event_index+1)
-
if dialogic.has_subsystem('History'):
var all_choices: Array = dialogic.Choices.last_question_info['choices']
if dialogic.has_subsystem('VAR'):
dialogic.History.store_simple_history_entry(dialogic.VAR.parse_variables(choice_info.text), "Choice", {'all_choices': all_choices})
else:
dialogic.History.store_simple_history_entry(choice_info.text, "Choice", {'all_choices': all_choices})
+ if dialogic.has_subsystem("History"):
+ dialogic.History.mark_event_as_visited(choice_info.event_index)
+
+ choice_selected.emit(choice_info)
+ hide_all_choices()
+ dialogic.current_state = dialogic.States.IDLE
+ dialogic.handle_event(choice_info.event_index + 1)
@@ -219,7 +258,7 @@ func is_question(index:int) -> bool:
if dialogic.current_timeline_events[index] is DialogicChoiceEvent:
if index != 0 and dialogic.current_timeline_events[index-1] is DialogicEndBranchEvent:
- if dialogic.current_timeline_events[dialogic.current_timeline_events[index-1].find_opening_index()] is DialogicChoiceEvent:
+ if dialogic.current_timeline_events[dialogic.current_timeline_events[index-1].find_opening_index(index-1)] is DialogicChoiceEvent:
return false
else:
return true
diff --git a/addons/dialogic/Modules/Choice/ui_choice_end.gd b/addons/dialogic/Modules/Choice/ui_choice_end.gd
index 8bfb21873..acc5d827b 100644
--- a/addons/dialogic/Modules/Choice/ui_choice_end.gd
+++ b/addons/dialogic/Modules/Choice/ui_choice_end.gd
@@ -3,7 +3,7 @@ extends HBoxContainer
var parent_resource: DialogicChoiceEvent = null
-func refresh():
+func refresh() -> void:
$AddChoice.icon = get_theme_icon("Add", "EditorIcons")
if parent_resource is DialogicChoiceEvent:
@@ -17,9 +17,9 @@ func refresh():
func _on_add_choice_pressed() -> void:
- var timeline = find_parent('VisualEditor')
+ var timeline := find_parent('VisualEditor')
if timeline:
- var resource = DialogicChoiceEvent.new()
+ var resource := DialogicChoiceEvent.new()
resource.created_by_button = true
timeline.add_event_undoable(resource, get_parent().get_index()+1)
timeline.indent_events()
diff --git a/addons/dialogic/Modules/Clear/event_clear.gd b/addons/dialogic/Modules/Clear/event_clear.gd
index c69acaa9d..c125ae96d 100644
--- a/addons/dialogic/Modules/Clear/event_clear.gd
+++ b/addons/dialogic/Modules/Clear/event_clear.gd
@@ -1,5 +1,5 @@
@tool
-class_name DialogiClearEvent
+class_name DialogicClearEvent
extends DialogicEvent
## Event that clears audio & visuals (not variables).
@@ -34,7 +34,7 @@ func _execute() -> void:
if clear_portraits and dialogic.has_subsystem('Portraits') and len(dialogic.Portraits.get_joined_characters()) != 0:
if final_time == 0:
- dialogic.Portraits.leave_all_characters(DialogicResourceUtil.guess_special_resource("PortraitAnimation", 'Instant In Or Out'), final_time, step_by_step)
+ dialogic.Portraits.leave_all_characters("Instant", final_time, step_by_step)
else:
dialogic.Portraits.leave_all_characters("", final_time, step_by_step)
if step_by_step: await dialogic.get_tree().create_timer(final_time).timeout
@@ -48,11 +48,14 @@ func _execute() -> void:
if step_by_step: await dialogic.get_tree().create_timer(final_time).timeout
if clear_style and dialogic.has_subsystem('Styles'):
- dialogic.Styles.load_style()
+ dialogic.Styles.change_style()
if clear_portrait_positions and dialogic.has_subsystem('Portraits'):
- dialogic.Portraits.reset_all_portrait_positions()
-
+ dialogic.PortraitContainers.reset_all_containers()
+
+ if not step_by_step:
+ await dialogic.get_tree().create_timer(final_time).timeout
+
finish()
@@ -93,7 +96,7 @@ func get_shortcode_parameters() -> Dictionary:
## EDITOR REPRESENTATION
################################################################################
-func build_event_editor():
+func build_event_editor() -> void:
add_header_label('Clear')
add_body_edit('time', ValueType.NUMBER, {'left_text':'Time:'})
diff --git a/addons/dialogic/Modules/Comment/event_comment.gd b/addons/dialogic/Modules/Comment/event_comment.gd
index d70a34ac5..ad0b1dd2b 100644
--- a/addons/dialogic/Modules/Comment/event_comment.gd
+++ b/addons/dialogic/Modules/Comment/event_comment.gd
@@ -8,7 +8,7 @@ extends DialogicEvent
### Settings
## Content of the comment.
-var text :String = ""
+var text := ""
################################################################################
@@ -36,8 +36,7 @@ func _init() -> void:
################################################################################
func to_text() -> String:
- var result_string = "# "+text
- return result_string
+ return "# "+text
func from_text(string:String) -> void:
@@ -54,13 +53,13 @@ func is_valid_event(string:String) -> bool:
## EDITOR REPRESENTATION
################################################################################
-func build_event_editor():
+func build_event_editor() -> void:
add_header_edit('text', ValueType.SINGLELINE_TEXT, {'left_text':'#', 'autofocus':true})
#################### SYNTAX HIGHLIGHTING #######################################
################################################################################
-func _get_syntax_highlighting(Highlighter:SyntaxHighlighter, dict:Dictionary, line:String) -> Dictionary:
+func _get_syntax_highlighting(Highlighter:SyntaxHighlighter, dict:Dictionary, _line:String) -> Dictionary:
dict[0] = {'color':event_color.lerp(Highlighter.normal_color, 0.3)}
return dict
diff --git a/addons/dialogic/Modules/Condition/event_condition.gd b/addons/dialogic/Modules/Condition/event_condition.gd
index 3902a894d..d56f34ac6 100644
--- a/addons/dialogic/Modules/Condition/event_condition.gd
+++ b/addons/dialogic/Modules/Condition/event_condition.gd
@@ -10,7 +10,7 @@ enum ConditionTypes {IF, ELIF, ELSE}
## condition type (see [ConditionTypes]). Defaults to if.
var condition_type := ConditionTypes.IF
## The condition as a string. Will be executed as an Expression.
-var condition: String = ""
+var condition := ""
################################################################################
@@ -24,9 +24,9 @@ func _execute() -> void:
if condition.is_empty(): condition = "true"
- var result :bool= dialogic.Expressions.execute_condition(condition)
+ var result: bool = dialogic.Expressions.execute_condition(condition)
if not result:
- var idx :int= dialogic.current_event_idx
+ var idx: int = dialogic.current_event_idx
var ignore := 1
while true:
idx += 1
@@ -103,7 +103,7 @@ func is_valid_event(string:String) -> bool:
## EDITOR REPRESENTATION
################################################################################
-func build_event_editor():
+func build_event_editor() -> void:
add_header_edit('condition_type', ValueType.FIXED_OPTIONS, {
'options': [
{
@@ -125,12 +125,12 @@ func build_event_editor():
####################### CODE COMPLETION ########################################
################################################################################
-func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, word:String, symbol:String) -> void:
+func _get_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit, line:String, _word:String, symbol:String) -> void:
if (line.begins_with('if') or line.begins_with('elif')) and symbol == '{':
CodeCompletionHelper.suggest_variables(TextNode)
-func _get_start_code_completion(CodeCompletionHelper:Node, TextNode:TextEdit) -> void:
+func _get_start_code_completion(_CodeCompletionHelper:Node, TextNode:TextEdit) -> void:
TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'if', 'if ', TextNode.syntax_highlighter.code_flow_color)
TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'elif', 'elif ', TextNode.syntax_highlighter.code_flow_color)
TextNode.add_code_completion_option(CodeEdit.KIND_PLAIN_TEXT, 'else', 'else:\n ', TextNode.syntax_highlighter.code_flow_color)
diff --git a/addons/dialogic/Modules/Condition/ui_condition_end.gd b/addons/dialogic/Modules/Condition/ui_condition_end.gd
index 747955cef..4a5ac1d0e 100644
--- a/addons/dialogic/Modules/Condition/ui_condition_end.gd
+++ b/addons/dialogic/Modules/Condition/ui_condition_end.gd
@@ -1,13 +1,15 @@
@tool
extends HBoxContainer
-var parent_resource = null
+var parent_resource: DialogicEvent = null
-func _ready():
+
+func _ready() -> void:
$AddElif.button_up.connect(add_elif)
$AddElse.button_up.connect(add_else)
-func refresh():
+
+func refresh() -> void:
if parent_resource is DialogicConditionEvent:
# hide add elif and add else button on ELSE event
$AddElif.visible = parent_resource.condition_type != DialogicConditionEvent.ConditionTypes.ELSE
@@ -15,9 +17,9 @@ func refresh():
$Label.text = "End of "+["IF", "ELIF", "ELSE"][parent_resource.condition_type]+" ("+parent_resource.condition+")"
# hide add add else button if followed by ELIF or ELSE event
- var timeline_editor = find_parent('VisualEditor')
+ var timeline_editor := find_parent('VisualEditor')
if timeline_editor:
- var next_event = null
+ var next_event: DialogicEvent = null
if timeline_editor.get_block_below(get_parent()):
next_event = timeline_editor.get_block_below(get_parent()).resource
if next_event is DialogicConditionEvent:
@@ -28,19 +30,21 @@ func refresh():
else:
hide()
-func add_elif():
- var timeline = find_parent('VisualEditor')
+
+func add_elif() -> void:
+ var timeline := find_parent('VisualEditor')
if timeline:
- var resource = DialogicConditionEvent.new()
+ var resource := DialogicConditionEvent.new()
resource.condition_type = DialogicConditionEvent.ConditionTypes.ELIF
timeline.add_event_undoable(resource, get_parent().get_index()+1)
timeline.indent_events()
timeline.something_changed()
-func add_else():
- var timeline = find_parent('VisualEditor')
+
+func add_else() -> void:
+ var timeline := find_parent('VisualEditor')
if timeline:
- var resource = DialogicConditionEvent.new()
+ var resource := DialogicConditionEvent.new()
resource.condition_type = DialogicConditionEvent.ConditionTypes.ELSE
timeline.add_event_undoable(resource, get_parent().get_index()+1)
timeline.indent_events()
diff --git a/addons/dialogic/Modules/Core/event_end_branch.gd b/addons/dialogic/Modules/Core/event_end_branch.gd
index c9dc90c0b..60a53dd0d 100644
--- a/addons/dialogic/Modules/Core/event_end_branch.gd
+++ b/addons/dialogic/Modules/Core/event_end_branch.gd
@@ -34,8 +34,8 @@ func find_next_index() -> int:
return idx
-func find_opening_index() -> int:
- var idx: int = dialogic.current_event_idx
+func find_opening_index(at_index:int) -> int:
+ var idx: int = at_index
var ignore: int = 1
while true:
@@ -72,7 +72,7 @@ func to_text() -> String:
return "<>"
-func from_text(string:String) -> void:
+func from_text(_string:String) -> void:
pass
diff --git a/addons/dialogic/Modules/Core/index.gd b/addons/dialogic/Modules/Core/index.gd
index a9a17919a..7082d4bac 100644
--- a/addons/dialogic/Modules/Core/index.gd
+++ b/addons/dialogic/Modules/Core/index.gd
@@ -20,3 +20,8 @@ func _get_text_effects() -> Array[Dictionary]:
{'command':'ns', 'subsystem':'Inputs', 'method':'effect_noskip'},
{'command':'input', 'subsystem':'Inputs', 'method':'effect_input'},
]
+
+func _get_text_modifiers() -> Array[Dictionary]:
+ return [
+ {'subsystem':'Expressions', 'method':"modifier_condition", 'command':'if', 'mode':-1},
+ ]
diff --git a/addons/dialogic/Modules/Core/subsystem_animation.gd b/addons/dialogic/Modules/Core/subsystem_animation.gd
index 8ab0f2841..476913442 100644
--- a/addons/dialogic/Modules/Core/subsystem_animation.gd
+++ b/addons/dialogic/Modules/Core/subsystem_animation.gd
@@ -3,24 +3,40 @@ extends DialogicSubsystem
## Subsystem that allows entering and leaving an animation state.
signal finished
+signal animation_interrupted
-var prev_state: int = 0
+var prev_state: DialogicGameHandler.States = DialogicGameHandler.States.IDLE
+var _is_animating := false
#region MAIN METHODS
####################################################################################################
+func clear_game_state(_clear_flag := DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
+ stop_animation()
+
+
func is_animating() -> bool:
- return dialogic.current_state == dialogic.States.ANIMATING
+ return _is_animating
func start_animating() -> void:
prev_state = dialogic.current_state
dialogic.current_state = dialogic.States.ANIMATING
+ _is_animating = true
-func animation_finished(arg := "") -> void:
- dialogic.current_state = prev_state
+func animation_finished(_arg := "") -> void:
+ # It can happen that the animation state has already been stopped
+ if not is_animating():
+ return
+ _is_animating = false
+ dialogic.current_state = prev_state as DialogicGameHandler.States
finished.emit()
+
+func stop_animation() -> void:
+ animation_finished()
+ animation_interrupted.emit()
+
#endregion
diff --git a/addons/dialogic/Modules/Core/subsystem_expression.gd b/addons/dialogic/Modules/Core/subsystem_expression.gd
index 9bc2eccd0..fd4489aa6 100644
--- a/addons/dialogic/Modules/Core/subsystem_expression.gd
+++ b/addons/dialogic/Modules/Core/subsystem_expression.gd
@@ -20,6 +20,9 @@ func execute_string(string:String, default: Variant = null, no_warning := false)
for res in regex.search_all(string):
var value: Variant = dialogic.VAR.get_variable(res.get_string())
string = string.replace(res.get_string(), var_to_str(value))
+
+ if string.begins_with("{") and string.ends_with('}') and string.count("{") == 1:
+ string = string.trim_prefix("{").trim_suffix("}")
var expr := Expression.new()
@@ -31,17 +34,17 @@ func execute_string(string:String, default: Variant = null, no_warning := false)
if expr.parse(string, autoload_names) != OK:
if not no_warning:
- printerr('Dialogic: Expression failed to parse: ', expr.get_error_text())
- printerr(' Expression: ', string)
- print("\n")
+ printerr('[Dialogic] Expression "', string, '" failed to parse.')
+ printerr(' ', expr.get_error_text())
+ dialogic.print_debug_moment()
return default
var result: Variant = expr.execute(autoloads, self)
if expr.has_execute_failed():
if not no_warning:
- printerr('Dialogic: Expression failed to execute: ', expr.get_error_text())
- printerr(' Expression: ', string)
- print("\n")
+ printerr('[Dialogic] Expression "', string, '" failed to parse.')
+ printerr(' ', expr.get_error_text())
+ dialogic.print_debug_moment()
return default
return result
@@ -51,6 +54,15 @@ func execute_condition(condition:String) -> bool:
return true
return false
+
+var condition_modifier_regex := RegEx.create_from_string(r"(?(DEFINE)(?([^{}]|\{(?P>nobraces)\})*))\[if *(?\{(?P>nobraces)\})(?(\\\]|\\\/|[^\]\/])*)(\/(?(\\\]|[^\]])*))?\]")
+func modifier_condition(text:String) -> String:
+ for find in condition_modifier_regex.search_all(text):
+ if execute_condition(find.get_string("condition")):
+ text = text.replace(find.get_string(), find.get_string("truetext").strip_edges())
+ else:
+ text = text.replace(find.get_string(), find.get_string("falsetext").strip_edges())
+ return text
#endregion
diff --git a/addons/dialogic/Modules/Core/subsystem_input.gd b/addons/dialogic/Modules/Core/subsystem_input.gd
index b94fd71d1..1c21f695f 100644
--- a/addons/dialogic/Modules/Core/subsystem_input.gd
+++ b/addons/dialogic/Modules/Core/subsystem_input.gd
@@ -12,12 +12,15 @@ signal dialogic_action
signal autoskip_timer_finished
+const _SETTING_INPUT_ACTION := "dialogic/text/input_action"
+const _SETTING_INPUT_ACTION_DEFAULT := "dialogic_default_action"
+
var input_block_timer := Timer.new()
var _auto_skip_timer_left: float = 0.0
var action_was_consumed := false
var auto_skip: DialogicAutoSkip = null
-var auto_advance : DialogicAutoAdvance = null
+var auto_advance: DialogicAutoAdvance = null
var manual_advance: DialogicManualAdvance = null
@@ -28,8 +31,8 @@ func clear_game_state(_clear_flag := DialogicGameHandler.ClearFlags.FULL_CLEAR)
if not is_node_ready():
await ready
- manual_advance.enabled_until_next_event = false
- manual_advance.enabled_forced = true
+ manual_advance.disabled_until_next_event = false
+ manual_advance.system_enabled = true
func pause() -> void:
@@ -48,6 +51,7 @@ func resume() -> void:
func post_install() -> void:
dialogic.Settings.connect_to_change('autoadvance_delay_modifier', auto_advance._update_autoadvance_delay_modifier)
auto_skip.toggled.connect(_on_autoskip_toggled)
+ auto_skip._init()
add_child(input_block_timer)
input_block_timer.one_shot = true
@@ -88,8 +92,8 @@ func handle_input() -> void:
## Unhandled Input is used for all NON-Mouse based inputs.
func _unhandled_input(event:InputEvent) -> void:
- if Input.is_action_pressed(ProjectSettings.get_setting('dialogic/text/input_action', 'dialogic_default_action')):
- if event is InputEventMouse:
+ if is_input_pressed(event, true):
+ if event is InputEventMouse or event is InputEventScreenTouch:
return
handle_input()
@@ -97,21 +101,32 @@ func _unhandled_input(event:InputEvent) -> void:
## Input is used for all mouse based inputs.
## If any DialogicInputNode is present this won't do anything (because that node handles MouseInput then).
func _input(event:InputEvent) -> void:
- if Input.is_action_pressed(ProjectSettings.get_setting('dialogic/text/input_action', 'dialogic_default_action')):
-
+ if is_input_pressed(event):
if not event is InputEventMouse or get_tree().get_nodes_in_group('dialogic_input').any(func(node):return node.is_visible_in_tree()):
return
handle_input()
+func is_input_pressed(event: InputEvent, exact := false) -> bool:
+ var action: String = ProjectSettings.get_setting(_SETTING_INPUT_ACTION, _SETTING_INPUT_ACTION_DEFAULT)
+ return (event is InputEventAction and event.action == action) or Input.is_action_just_pressed(action, exact)
+
+
+## This is called from the gui_input of the InputCatcher and DialogText nodes
+func handle_node_gui_input(event:InputEvent) -> void:
+ if Input.is_action_just_pressed(ProjectSettings.get_setting(_SETTING_INPUT_ACTION, _SETTING_INPUT_ACTION_DEFAULT)):
+ if event is InputEventMouseButton and event.pressed:
+ DialogicUtil.autoload().Inputs.handle_input()
+
+
func is_input_blocked() -> bool:
return input_block_timer.time_left > 0.0
func block_input(time:=0.1) -> void:
if time > 0:
- input_block_timer.wait_time = time
+ input_block_timer.wait_time = max(time, input_block_timer.time_left)
input_block_timer.start()
@@ -169,7 +184,7 @@ func _process(delta: float) -> void:
################################################################################
-func effect_input(text_node:Control, skipped:bool, argument:String) -> void:
+func effect_input(_text_node:Control, skipped:bool, _argument:String) -> void:
if skipped:
return
dialogic.Text.show_next_indicators()
@@ -180,11 +195,11 @@ func effect_input(text_node:Control, skipped:bool, argument:String) -> void:
func effect_noskip(text_node:Control, skipped:bool, argument:String) -> void:
dialogic.Text.set_text_reveal_skippable(false, true)
- manual_advance.enabled_until_next_event = true
+ manual_advance.disabled_until_next_event = true
effect_autoadvance(text_node, skipped, argument)
-func effect_autoadvance(text_node: Control, skipped:bool, argument:String) -> void:
+func effect_autoadvance(_text_node: Control, _skipped:bool, argument:String) -> void:
if argument.ends_with('?'):
argument = argument.trim_suffix('?')
else:
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Base_Default/default_layout_base.gd b/addons/dialogic/Modules/DefaultLayoutParts/Base_Default/default_layout_base.gd
index 648b2cd26..af6878cac 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Base_Default/default_layout_base.gd
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Base_Default/default_layout_base.gd
@@ -4,6 +4,7 @@ extends DialogicLayoutBase
## The default layout base scene.
@export var canvas_layer: int = 1
+@export var follow_viewport: bool = false
@export_subgroup("Global")
@export var global_bg_color: Color = Color(0, 0, 0, 0.9)
@@ -15,5 +16,6 @@ extends DialogicLayoutBase
func _apply_export_overrides() -> void:
# apply layer
set(&'layer', canvas_layer)
+ set(&'follow_viewport_enabled', follow_viewport)
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Base_TextBubble/text_bubble_base.gd b/addons/dialogic/Modules/DefaultLayoutParts/Base_TextBubble/text_bubble_base.gd
index 99a2dbf49..ed4707ab4 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Base_TextBubble/text_bubble_base.gd
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Base_TextBubble/text_bubble_base.gd
@@ -1,50 +1,94 @@
@tool
extends DialogicLayoutBase
-## This layout won't do anything on it's own
+## This layout won't do anything on its own
-var bubbles: Dictionary = {}
-var fallback_bubble :Control = null
+var bubbles: Array = []
+var registered_characters: Dictionary = {}
+@export_group("Main")
+@export_range(1, 25, 1) var bubble_count: int = 2
-func _ready():
+
+func _ready() -> void:
if Engine.is_editor_hint():
return
DialogicUtil.autoload().Text.about_to_show_text.connect(_on_dialogic_text_event)
- $Example/ExamplePoint.position = $Example.get_viewport_rect().size/2
+ $Example/CRT.position = $Example.get_viewport_rect().size/2
if not has_node('TextBubbleLayer'):
return
- fallback_bubble = get_node("TextBubbleLayer").add_bubble()
- fallback_bubble.speaker_node = $Example/ExamplePoint
+ if len(bubbles) < bubble_count:
+ add_bubble()
+
+
+func register_character(character:Variant, node:Node):
+ if typeof(character) == TYPE_STRING:
+ var character_string: String = character
+ if character.begins_with("res://"):
+ character = load(character)
+ else:
+ character = DialogicResourceUtil.get_character_resource(character)
+ if not character:
+ printerr("[Dialogic] Textbubble: Tried registering character from invalid string '", character_string, "'.")
+
+ registered_characters[character] = node
+ if len(registered_characters) > len(bubbles) and len(bubbles) < bubble_count:
+ add_bubble()
+
+
+func _get_persistent_info() -> Dictionary:
+ return {"textbubble_registers": registered_characters}
+
+
+func _load_persistent_info(info: Dictionary) -> void:
+ var register_info: Dictionary = info.get("textbubble_registers", {})
+ for character in register_info:
+ if is_instance_valid(register_info[character]):
+ register_character(character, register_info[character])
-func register_character(character:DialogicCharacter, node:Node2D):
+func add_bubble() -> void:
if not has_node('TextBubbleLayer'):
return
var new_bubble: Control = get_node("TextBubbleLayer").add_bubble()
- new_bubble.speaker_node = node
- new_bubble.character = character
- new_bubble.name = character.resource_path.get_file().trim_suffix("."+character.resource_path.get_extension()) + "Bubble"
- bubbles[character] = new_bubble
+ bubbles.append(new_bubble)
+
func _on_dialogic_text_event(info:Dictionary):
- var no_bubble_open := true
+ var bubble_to_use: Node
+ for bubble in bubbles:
+ if bubble.current_character == info.character:
+ bubble_to_use = bubble
- for character in bubbles:
- if info.character == character:
- no_bubble_open = false
- bubbles[character].open()
- else:
- bubbles[character].close()
+ if bubble_to_use == null:
+ for bubble in bubbles:
+ if bubble.current_character == null:
+ bubble_to_use = bubble
- if no_bubble_open:
- $Example.show()
- fallback_bubble.open()
- else:
+ if bubble_to_use == null:
+ bubble_to_use = bubbles[0]
+
+ var node_to_point_at: Node
+ if info.character in registered_characters:
+ node_to_point_at = registered_characters[info.character]
$Example.hide()
- fallback_bubble.close()
+ else:
+ node_to_point_at = $Example/CRT/Marker
+ $Example.show()
+
+ bubble_to_use.current_character = info.character
+ bubble_to_use.node_to_point_at = node_to_point_at
+ bubble_to_use.reset()
+ if has_node('TextBubbleLayer'):
+ get_node("TextBubbleLayer").bubble_apply_overrides(bubble_to_use)
+ bubble_to_use.open()
+ ## Now close other bubbles
+ for bubble in bubbles:
+ if bubble != bubble_to_use:
+ bubble.close()
+ bubble.current_character = null
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Base_TextBubble/text_bubble_base.tscn b/addons/dialogic/Modules/DefaultLayoutParts/Base_TextBubble/text_bubble_base.tscn
index 312c47185..27a00fc6d 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Base_TextBubble/text_bubble_base.tscn
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Base_TextBubble/text_bubble_base.tscn
@@ -1,11 +1,19 @@
-[gd_scene load_steps=2 format=3 uid="uid://syki6k0e6aac"]
+[gd_scene load_steps=3 format=3 uid="uid://syki6k0e6aac"]
[ext_resource type="Script" path="res://addons/dialogic/Modules/DefaultLayoutParts/Base_TextBubble/text_bubble_base.gd" id="1_urqwc"]
+[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_70ljh"]
+content_margin_left = 5.0
+content_margin_top = 5.0
+content_margin_right = 5.0
+content_margin_bottom = 5.0
+bg_color = Color(0, 0, 0, 0.654902)
+
[node name="TextBubbleHolder" type="CanvasLayer"]
script = ExtResource("1_urqwc")
[node name="Example" type="Control" parent="."]
+visible = false
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
@@ -13,25 +21,35 @@ anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
-[node name="ExamplePoint" type="Polygon2D" parent="Example"]
-polygon = PackedVector2Array(0, -24, -22, 0, 0, 28, 24, 0)
-
[node name="Label" type="RichTextLabel" parent="Example"]
layout_mode = 1
anchors_preset = 2
anchor_top = 1.0
anchor_bottom = 1.0
-offset_left = 13.0
-offset_top = -227.0
-offset_right = 836.0
-offset_bottom = -16.0
+offset_left = 12.0
+offset_top = -235.0
+offset_right = 835.0
+offset_bottom = -14.0
grow_vertical = 0
+theme_override_styles/normal = SubResource("StyleBoxFlat_70ljh")
bbcode_enabled = true
text = "This is a fallback bubble, that is not actually connected to any character. In game use the following code to add speech bubbles to a character:
[color=darkgray]
var layout = Dialogic.start(timeline_path)
layout.register_character(character_resource, node)
[/color]
-[color=lightblue]@character_resource[/color] should be a loaded DialogicCharacter (a .dch file).
-[color=lightblue]@node[/color] should be the 2D node the bubble should point at.
+- [color=lightblue]character_resource[/color] should be a loaded DialogicCharacter (a .dch file).
+- [color=lightblue]node[/color] should be the 2D or 3D node the bubble should point at.
-> E.g. [color=darkgray]layout.register_character(load(\"res://path/to/my/character.dch\"), $BubbleMarker)"
+
+[node name="CRT" type="ColorRect" parent="Example"]
+layout_mode = 0
+offset_left = 504.0
+offset_top = 290.0
+offset_right = 540.0
+offset_bottom = 324.0
+rotation = 0.785397
+color = Color(1, 0.313726, 1, 1)
+
+[node name="Marker" type="Marker2D" parent="Example/CRT"]
+position = Vector2(10.6066, 9.1924)
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_FullBackground/full_background_layer.tscn b/addons/dialogic/Modules/DefaultLayoutParts/Layer_FullBackground/full_background_layer.tscn
index b4766352f..f1d44c03d 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_FullBackground/full_background_layer.tscn
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_FullBackground/full_background_layer.tscn
@@ -4,6 +4,7 @@
[ext_resource type="Script" path="res://addons/dialogic/Modules/Background/node_background_holder.gd" id="2_ghan2"]
[node name="BackgroundLayer" type="Control"]
+layout_direction = 2
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
@@ -20,4 +21,5 @@ anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
+color = Color(1, 1, 1, 0)
script = ExtResource("2_ghan2")
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_Glossary/glossary_popup_layer.gd b/addons/dialogic/Modules/DefaultLayoutParts/Layer_Glossary/glossary_popup_layer.gd
index 8d9600a5a..60f4e9142 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_Glossary/glossary_popup_layer.gd
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_Glossary/glossary_popup_layer.gd
@@ -74,90 +74,34 @@ func _ready() -> void:
_error = text_system.connect(&'animation_textbox_hide', get_pointer().hide)
_error = text_system.connect(&'meta_hover_started', _on_dialogic_display_dialog_text_meta_hover_started)
_error = text_system.connect(&'meta_hover_ended', _on_dialogic_display_dialog_text_meta_hover_ended)
- _error = text_system.connect(&'meta_clicked', _on_dialogic_display_dialog_text_meta_clicked)
-func _try_translate(tr_base: String, property: StringName, fallback_entry: Dictionary) -> String:
- var tr_key := tr_base.path_join(property)
- var tr_value := tr(tr_key)
-
- if tr_key == tr_value:
- tr_value = fallback_entry.get(property, "")
-
- return tr_value
-
## Method that shows the bubble and fills in the info
func _on_dialogic_display_dialog_text_meta_hover_started(meta: String) -> void:
- var glossary: DialogicGlossary = DialogicUtil.autoload().Glossary.find_glossary(meta)
-
- var entry_title := ""
- var entry_text := ""
- var entry_extra := ""
- var entry_color: Variant = null
-
- var title_color := title_custom_color
- var text_color := text_custom_color
- var extra_color := extra_custom_color
+ var entry_info := DialogicUtil.autoload().Glossary.get_entry(meta)
- if glossary == null:
+ if entry_info.is_empty():
return
- var is_translation_enabled: bool = ProjectSettings.get_setting('dialogic/translation/enabled', false)
-
- if not is_translation_enabled or glossary._translation_id.is_empty():
- var entry := glossary.get_entry(meta)
-
- if entry.is_empty():
- return
-
- entry_title = entry.get("title", "")
- entry_text = entry.get("text", "")
- entry_extra = entry.get("extra", "")
- entry_color = entry.get("color")
-
- else:
- var translation_key: String = glossary._translation_keys.get(meta)
- var last_slash := translation_key.rfind('/')
-
- if last_slash == MISSING_INDEX:
- return
-
- var tr_base := translation_key.substr(0, last_slash)
-
- var entry := glossary.get_entry(meta)
- entry_color = entry.get('color')
-
- entry_title = _try_translate(tr_base, "title", entry)
- entry_text = _try_translate(tr_base, "text", entry)
- entry_extra = _try_translate(tr_base, "extra", entry)
-
- if not entry_color == null:
- title_color = entry_color
- text_color = entry_color
- extra_color = entry_color
-
get_pointer().show()
- get_title().text = entry_title
- get_text().text = entry_text
+ get_title().text = entry_info.title
+ get_text().text = entry_info.text
get_text().text = ['', '[center]', '[right]'][text_alignment] + get_text().text
- get_extra().text = entry_extra
+ get_extra().text = entry_info.extra
get_extra().text = ['', '[center]', '[right]'][extra_alignment] + get_extra().text
get_pointer().global_position = get_pointer().get_global_mouse_position()
-
if title_color_mode == TextColorModes.ENTRY:
- get_title().add_theme_color_override(&"font_color", title_color)
+ get_title().add_theme_color_override(&"font_color", entry_info.color)
if text_color_mode == TextColorModes.ENTRY:
- get_text().add_theme_color_override(&"default_color", text_color)
+ get_text().add_theme_color_override(&"default_color", entry_info.color)
if extra_color_mode == TextColorModes.ENTRY:
- get_extra().add_theme_color_override(&"default_color", extra_color)
+ get_extra().add_theme_color_override(&"default_color", entry_info.color)
match box_modulate_mode:
ModulateModes.ENTRY_COLOR_ON_BOX:
- get_panel().self_modulate = title_color
- get_panel_point().self_modulate = title_color
-
- DialogicUtil.autoload().Inputs.action_was_consumed = true
+ get_panel().self_modulate = entry_info.color
+ get_panel_point().self_modulate = entry_info.color
## Method that keeps the bubble at mouse position when visible
@@ -173,20 +117,15 @@ func _process(_delta: float) -> void:
## Method that hides the bubble
func _on_dialogic_display_dialog_text_meta_hover_ended(_meta:String) -> void:
get_pointer().hide()
- DialogicUtil.autoload().Inputs.action_was_consumed = false
-func _on_dialogic_display_dialog_text_meta_clicked(_meta:String) -> void:
- DialogicUtil.autoload().Inputs.action_was_consumed = true
-
func _apply_export_overrides() -> void:
- var font_setting: String = get_global_setting("font", "")
-
# Apply fonts
var font: FontFile
- if font_use_global and ResourceLoader.exists(get_global_setting(&'font', '') as String):
- font = load(get_global_setting(&'font', '') as String)
+ var global_font_setting: String = get_global_setting(&"font", '')
+ if font_use_global and ResourceLoader.exists(global_font_setting):
+ font = load(global_font_setting)
elif ResourceLoader.exists(font_custom):
font = load(font_custom)
@@ -211,16 +150,17 @@ func _apply_export_overrides() -> void:
# Apply text colors
+ # this applies Global or Custom colors, entry colors are applied on hover
var controls: Array[Control] = [get_title(), get_text(), get_extra()]
- var global_settings: Array[StringName] = [&'font_color', &'default_color', &'default_color']
+ var settings: Array[StringName] = [&'font_color', &'default_color', &'default_color']
var color_modes: Array[TextColorModes] = [title_color_mode, text_color_mode, extra_color_mode]
var custom_colors: PackedColorArray = [title_custom_color, text_custom_color, extra_custom_color]
for i : int in len(controls):
match color_modes[i]:
TextColorModes.GLOBAL:
- controls[i].add_theme_color_override(global_settings[i], get_global_setting(&'font_color', custom_colors[i]) as Color)
+ controls[i].add_theme_color_override(settings[i], get_global_setting(&'font_color', custom_colors[i]) as Color)
TextColorModes.CUSTOM:
- controls[i].add_theme_color_override(global_settings[i], custom_colors[i])
+ controls[i].add_theme_color_override(settings[i], custom_colors[i])
# Apply box size
var panel: PanelContainer = get_panel()
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_History/example_history_item.gd b/addons/dialogic/Modules/DefaultLayoutParts/Layer_History/example_history_item.gd
index f01fa0ffa..83fef5013 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_History/example_history_item.gd
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_History/example_history_item.gd
@@ -14,17 +14,17 @@ func get_icon() -> TextureRect:
func load_info(text:String, character:String = "", character_color: Color =Color(), icon:Texture= null) -> void:
get_text_box().text = text
- var name_label : Label = get_name_label()
+ var name_label: Label = get_name_label()
if character:
name_label.text = character
name_label.add_theme_color_override('font_color', character_color)
name_label.show()
else:
name_label.hide()
-
- var icon_node : TextureRect = get_icon()
+
+ var icon_node: TextureRect = get_icon()
if icon == null:
icon_node.hide()
else:
icon_node.show()
- icon_node.texture = icon
\ No newline at end of file
+ icon_node.texture = icon
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_History/history_layer.gd b/addons/dialogic/Modules/DefaultLayoutParts/Layer_History/history_layer.gd
index 8d3a8b28c..d4200214e 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_History/history_layer.gd
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_History/history_layer.gd
@@ -53,8 +53,8 @@ func get_history_log() -> VBoxContainer:
func _ready() -> void:
if Engine.is_editor_hint():
return
- Dialogic.History.open_requested.connect(_on_show_history_pressed)
- Dialogic.History.close_requested.connect(_on_hide_history_pressed)
+ DialogicUtil.autoload().History.open_requested.connect(_on_show_history_pressed)
+ DialogicUtil.autoload().History.close_requested.connect(_on_hide_history_pressed)
func _apply_export_overrides() -> void:
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_SpeakerPortraitTextbox/speaker_portrait_textbox_layer.gd b/addons/dialogic/Modules/DefaultLayoutParts/Layer_SpeakerPortraitTextbox/speaker_portrait_textbox_layer.gd
index 5e28d9f73..61e3714b0 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_SpeakerPortraitTextbox/speaker_portrait_textbox_layer.gd
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_SpeakerPortraitTextbox/speaker_portrait_textbox_layer.gd
@@ -94,7 +94,7 @@ func _apply_export_overrides() -> void:
panel.position = Vector2(-box_size.x/2, -box_size.y-box_distance)
portrait_panel.size_flags_stretch_ratio = portrait_stretch_factor
- var stylebox: StyleBoxFlat = load(box_panel)
+ var stylebox: StyleBox = load(box_panel)
panel.add_theme_stylebox_override(&'panel', stylebox)
## PORTRAIT SETTINGS
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_SpeakerPortraitTextbox/textbox_with_speaker_portrait.tscn b/addons/dialogic/Modules/DefaultLayoutParts/Layer_SpeakerPortraitTextbox/textbox_with_speaker_portrait.tscn
index 766783c55..369973c4c 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_SpeakerPortraitTextbox/textbox_with_speaker_portrait.tscn
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_SpeakerPortraitTextbox/textbox_with_speaker_portrait.tscn
@@ -1,9 +1,10 @@
-[gd_scene load_steps=6 format=3 uid="uid://by6waso0mjpjp"]
+[gd_scene load_steps=7 format=3 uid="uid://by6waso0mjpjp"]
[ext_resource type="Script" path="res://addons/dialogic/Modules/Character/node_portrait_container.gd" id="1_4jxq7"]
[ext_resource type="Script" path="res://addons/dialogic/Modules/DefaultLayoutParts/Layer_SpeakerPortraitTextbox/speaker_portrait_textbox_layer.gd" id="1_7jt4d"]
[ext_resource type="Script" path="res://addons/dialogic/Modules/Text/node_name_label.gd" id="2_y0h34"]
[ext_resource type="Script" path="res://addons/dialogic/Modules/Text/node_dialog_text.gd" id="3_11puy"]
+[ext_resource type="Script" path="res://addons/dialogic/Modules/Text/node_type_sound.gd" id="5_sr2qw"]
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_dmg1w"]
bg_color = Color(0.254902, 0.254902, 0.254902, 1)
@@ -20,6 +21,7 @@ anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
+mouse_filter = 2
script = ExtResource("1_7jt4d")
box_panel = "res://addons/dialogic/Modules/DefaultLayoutParts/Layer_SpeakerPortraitTextbox/default_stylebox.tres"
@@ -32,6 +34,7 @@ anchor_right = 0.5
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 0
+mouse_filter = 2
[node name="Panel" type="PanelContainer" parent="Anchor"]
unique_name_in_owner = true
@@ -48,9 +51,11 @@ offset_right = 250.0
offset_bottom = -50.0
grow_horizontal = 2
grow_vertical = 0
+mouse_filter = 2
[node name="HBox" type="HBoxContainer" parent="Anchor/Panel"]
layout_mode = 2
+mouse_filter = 2
theme_override_constants/separation = 15
[node name="PortraitPanel" type="Panel" parent="Anchor/Panel/HBox"]
@@ -59,6 +64,7 @@ clip_children = 1
layout_mode = 2
size_flags_horizontal = 3
size_flags_stretch_ratio = 0.3
+mouse_filter = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_dmg1w")
[node name="PortraitBackgroundColor" type="ColorRect" parent="Anchor/Panel/HBox/PortraitPanel"]
@@ -73,6 +79,7 @@ offset_right = 7.0
offset_bottom = 3.0
grow_horizontal = 2
grow_vertical = 2
+mouse_filter = 2
color = Color(0, 0, 0, 0.231373)
[node name="DialogicNode_PortraitContainer" type="Control" parent="Anchor/Panel/HBox/PortraitPanel/PortraitBackgroundColor"]
@@ -83,13 +90,16 @@ anchor_bottom = 1.0
offset_top = 4.0
grow_horizontal = 2
grow_vertical = 2
+mouse_filter = 2
script = ExtResource("1_4jxq7")
mode = 1
+container_ids = PackedStringArray("1")
debug_character_portrait = "speaker"
[node name="VBoxContainer" type="VBoxContainer" parent="Anchor/Panel/HBox"]
layout_mode = 2
size_flags_horizontal = 3
+mouse_filter = 2
[node name="DialogicNode_NameLabel" type="Label" parent="Anchor/Panel/HBox/VBoxContainer"]
unique_name_in_owner = true
@@ -98,7 +108,7 @@ theme_override_font_sizes/font_size = 8
text = "Name"
script = ExtResource("2_y0h34")
-[node name="DialogicNode_DialogText" type="RichTextLabel" parent="Anchor/Panel/HBox/VBoxContainer"]
+[node name="DialogicNode_DialogText" type="RichTextLabel" parent="Anchor/Panel/HBox/VBoxContainer" node_paths=PackedStringArray("textbox_root")]
unique_name_in_owner = true
layout_mode = 2
size_flags_vertical = 3
@@ -106,4 +116,9 @@ theme_override_font_sizes/normal_font_size = 6
bbcode_enabled = true
text = "Some text"
scroll_following = true
+visible_characters_behavior = 1
script = ExtResource("3_11puy")
+textbox_root = NodePath("../../..")
+
+[node name="DialogicNode_TypeSounds" type="AudioStreamPlayer" parent="Anchor/Panel/HBox/VBoxContainer/DialogicNode_DialogText"]
+script = ExtResource("5_sr2qw")
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/speech_bubble.gdshader b/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/speech_bubble.gdshader
index 17c529aab..c1e348fc8 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/speech_bubble.gdshader
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/speech_bubble.gdshader
@@ -1,24 +1,17 @@
shader_type canvas_item;
-uniform sampler2D deformation_sampler : filter_linear, repeat_enable;
-uniform sampler2D spikes_sampler : filter_linear, repeat_enable;
-uniform sampler2D curve_sampler;
-uniform float radius :hint_range(0.1, 5, 0.01)= 0.25;
-uniform vec2 ratio = vec2(1.0, 1.0);
-uniform float crease : hint_range(0.0, 1.0, 0.01) = 0.1;
-uniform float speed : hint_range(0.0, 10.0, 0.01) = 1;
-uniform float texture_scale : hint_range(0.0, 0.5, 0.01) = 0.2;
-uniform float texture_offset : hint_range(0.0, 300, 0.5) = 1;
+uniform sampler2D deformation_sampler : filter_linear, repeat_enable;
+uniform float radius :hint_range(1.0, 200, 0.01)= 25;
+uniform vec2 box_size = vec2(100, 100);
+uniform float box_padding = 15;
+uniform float wobble_amount : hint_range(0.0, 1.0, 0.01) = 0.2;
+uniform float wobble_speed : hint_range(0.0, 10.0, 0.01) = 1;
+uniform float wobble_detail : hint_range(0.01, 1, 0.01) = 0.5;
void fragment() {
- vec2 ratio_uv = UV * ratio;
- float spikes = texture(spikes_sampler, ratio_uv * texture_scale + vec2(texture_offset)).x;
-//
- float d = length(max(abs(ratio_uv - vec2(0.5) * ratio) + radius - vec2(0.5) * ratio,0.0)) - radius;
- d += (distance(vec2(0.5), UV) - 0.5) * radius;
- float curve = texture(curve_sampler, vec2(d + spikes, 0.0)).x;
- d += curve * crease;
- d += texture(deformation_sampler, ratio_uv * 0.05 + TIME * speed*0.01).x * 0.1;
- float mask = smoothstep(0.0, -0.005, d);
- COLOR.a = mask;
+ float adjusted_radius = min(min(radius, box_size.x/2.0), box_size.y/2.0);
+ vec2 deformation_sample = texture(deformation_sampler, UV*wobble_detail+TIME*wobble_speed*0.05).xy*(vec2(box_padding)/box_size)*0.9;
+ vec2 deformed_UV = UV+((deformation_sample)-vec2(0.5)*vec2(box_padding)/box_size)*wobble_amount;
+ float rounded_box = length(max(abs(deformed_UV*(box_size+vec2(box_padding))-vec2(0.5)*(box_size+vec2(box_padding)))+adjusted_radius-vec2(0.5)*box_size,0))-adjusted_radius;
+ COLOR.a = min(smoothstep(0.0, -1, rounded_box), COLOR.a);
}
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.gd b/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.gd
index 05781033a..669c2e2ff 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.gd
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.gd
@@ -1,57 +1,58 @@
extends Control
-class_name DialogicNode_TextBubble
-var speaker_node : Node = null
-var character : DialogicCharacter = null
+@onready var tail: Line2D = ($Group/Tail as Line2D)
+@onready var bubble: Control = ($Group/Background as Control)
+@onready var text: DialogicNode_DialogText = (%DialogText as DialogicNode_DialogText)
+# The choice container is added by the TextBubble layer
+@onready var choice_container: Container = null
+@onready var name_label: Label = (%NameLabel as Label)
+@onready var name_label_box: PanelContainer = (%NameLabelPanel as PanelContainer)
+@onready var name_label_holder: HBoxContainer = $DialogText/NameLabelPositioner
+
+var node_to_point_at: Node = null
+var current_character: DialogicCharacter = null
+
var max_width := 300
-var bubble_rect : Rect2 = Rect2(0.0, 0.0, 2.0, 2.0)
+var bubble_rect: Rect2 = Rect2(0.0, 0.0, 2.0, 2.0)
var base_position := Vector2.ZERO
var base_direction := Vector2(1.0, -1.0).normalized()
var safe_zone := 50.0
var padding := Vector2()
+var name_label_alignment := HBoxContainer.ALIGNMENT_BEGIN
+var name_label_offset := Vector2()
+var force_choices_on_separate_lines := false
-func get_tail() -> Line2D:
- return $Tail
-
-
-func get_bubble() -> Control:
- return $Background
-
-
-func get_choice_container() -> Container:
- return $DialogText/ChoiceContainer
-
-
-func get_name_label_panel() -> PanelContainer:
- return $DialogText/NameLabel
-
-
-func get_name_label() -> DialogicNode_NameLabel:
- return %NameLabel
+# Sets the padding shader paramter.
+# It's the amount of spacing around the background to allow some wobbeling.
+var bg_padding := 30
-func get_dialog_text() -> DialogicNode_DialogText:
- return %DialogText
+func _ready() -> void:
+ reset()
+ DialogicUtil.autoload().Choices.question_shown.connect(_on_question_shown)
-func _ready() -> void:
+func reset() -> void:
scale = Vector2.ZERO
modulate.a = 0.0
- if speaker_node:
- position = speaker_node.get_global_transform_with_canvas().origin
+ tail.points = []
+ bubble_rect = Rect2(0,0,2,2)
+
+ base_position = get_speaker_canvas_position()
+ position = base_position
-func _process(delta):
- if speaker_node:
- base_position = speaker_node.get_global_transform_with_canvas().origin
+
+func _process(delta:float) -> void:
+ base_position = get_speaker_canvas_position()
var center := get_viewport_rect().size / 2.0
- var dist_x := abs(base_position.x - center.x)
- var dist_y := abs(base_position.y - center.y)
+ var dist_x := absf(base_position.x - center.x)
+ var dist_y := absf(base_position.y - center.y)
var x_e := center.x - bubble_rect.size.x
var y_e := center.y - bubble_rect.size.y
var influence_x := remap(clamp(dist_x, x_e, center.x), x_e, center.x * 0.8, 0.0, 1.0)
@@ -62,15 +63,17 @@ func _process(delta):
var direction := (base_direction + edge_influence).normalized()
- var p : Vector2 = base_position + direction * (safe_zone + lerp(bubble_rect.size.y, bubble_rect.size.x, abs(direction.x)) * 0.4)
+ var p: Vector2 = base_position + direction * (
+ safe_zone + lerp(bubble_rect.size.y, bubble_rect.size.x, abs(direction.x)) * 0.4
+ )
p = p.clamp(bubble_rect.size / 2.0, get_viewport_rect().size - bubble_rect.size / 2.0)
- position = lerp(position, p, 10.0 * delta)
+ position = position.lerp(p, 5 * delta)
- var point_a : Vector2 = Vector2.ZERO
- var point_b : Vector2 = (base_position - position) * 0.5
+ var point_a: Vector2 = Vector2.ZERO
+ var point_b: Vector2 = (base_position - position) * 0.75
- var offset = Vector2.from_angle(point_a.angle_to_point(point_b)) * bubble_rect.size * abs(direction.x) * 0.4
+ var offset: Vector2 = Vector2.from_angle(point_a.angle_to_point(point_b)) * bubble_rect.size * abs(direction.x) * 0.4
point_a += offset
point_b += offset * 0.5
@@ -79,59 +82,121 @@ func _process(delta):
var direction_point := Vector2(0, (point_b.y - point_a.y))
curve.add_point(point_a, Vector2.ZERO, direction_point * 0.5)
curve.add_point(point_b)
- get_tail().points = curve.tessellate(5)
- get_tail().width = bubble_rect.size.x * 0.15
+ tail.points = curve.tessellate(5)
+ tail.width = bubble_rect.size.x * 0.15
func open() -> void:
+ set_process(true)
show()
- get_dialog_text().enabled = true
+ text.enabled = true
var open_tween := create_tween().set_parallel(true)
open_tween.tween_property(self, "scale", Vector2.ONE, 0.1).from(Vector2.ZERO)
open_tween.tween_property(self, "modulate:a", 1.0, 0.1).from(0.0)
-
func close() -> void:
- get_dialog_text().enabled = false
+ text.enabled = false
var close_tween := create_tween().set_parallel(true)
- close_tween.tween_property(self, "scale", Vector2.ONE * 0.8, 0.1)
- close_tween.tween_property(self, "modulate:a", 0.0, 0.1)
+ close_tween.tween_property(self, "scale", Vector2.ONE * 0.8, 0.2)
+ close_tween.tween_property(self, "modulate:a", 0.0, 0.2)
await close_tween.finished
hide()
+ set_process(false)
-func _on_dialog_text_started_revealing_text():
- var dialog_text : DialogicNode_DialogText = get_dialog_text()
- var font :Font = dialog_text.get_theme_font("normal_font")
- dialog_text.size = font.get_multiline_string_size(dialog_text.get_parsed_text(), HORIZONTAL_ALIGNMENT_LEFT, max_width, dialog_text.get_theme_font_size("normal_font_size"))
- if DialogicUtil.autoload().Choices.is_question(DialogicUtil.autoload().current_event_idx):
- font = $DialogText/ChoiceContainer/DialogicNode_ChoiceButton.get_theme_font('font')
- dialog_text.size.y += font.get_string_size(dialog_text.get_parsed_text(), HORIZONTAL_ALIGNMENT_LEFT, max_width, $DialogText/ChoiceContainer/DialogicNode_ChoiceButton.get_theme_font_size("font_size")).y
- dialog_text.position = -dialog_text.size/2
+func _on_dialog_text_started_revealing_text() -> void:
+ _resize_bubble(get_base_content_size(), true)
- _resize_bubble()
-
-func _resize_bubble() -> void:
- var bubble : Control = get_bubble()
- var bubble_size :Vector2 = get_dialog_text().size+(padding*2)
- var half_size :Vector2= (bubble_size / 2.0)
- get_dialog_text().pivot_offset = half_size
+func _resize_bubble(content_size:Vector2, popup:=false) -> void:
+ var bubble_size: Vector2 = content_size+(padding*2)+Vector2.ONE*bg_padding
+ var half_size: Vector2= (bubble_size / 2.0)
bubble.pivot_offset = half_size
bubble_rect = Rect2(position, bubble_size * Vector2(1.1, 1.1))
- bubble.size = bubble_size
bubble.position = -half_size
+ bubble.size = bubble_size
- var t : Tween = create_tween().set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
- t.tween_property(bubble, ^"scale", Vector2.ONE, 0.2).from(Vector2.ZERO)
+ text.size = content_size
+ text.position = -(content_size/2.0)
- # set bubble's ratio
- var bubble_ratio := Vector2.ONE
- if bubble_rect.size.x < bubble_rect.size.y:
- bubble_ratio.y = bubble_rect.size.y / bubble_rect.size.x
+ if popup:
+ var t := create_tween().set_ease(Tween.EASE_OUT).set_trans(Tween.TRANS_BACK)
+ t.tween_property(bubble, "scale", Vector2.ONE, 0.2).from(Vector2.ZERO)
else:
- bubble_ratio.x = bubble_rect.size.x / bubble_rect.size.y
-
- bubble.material.set(&"shader_parameter/ratio", bubble_ratio)
-
+ bubble.scale = Vector2.ONE
+
+ bubble.material.set(&"shader_parameter/box_size", bubble_size)
+ name_label_holder.position = Vector2(0, bubble.position.y - text.position.y - name_label_holder.size.y/2.0)
+ name_label_holder.position += name_label_offset
+ name_label_holder.alignment = name_label_alignment
+ name_label_holder.size.x = text.size.x
+
+
+func _on_question_shown(info:Dictionary) -> void:
+ if !is_visible_in_tree():
+ return
+
+ await get_tree().process_frame
+
+ var content_size := get_base_content_size()
+ content_size.y += choice_container.size.y
+ content_size.x = max(content_size.x, choice_container.size.x)
+ _resize_bubble(content_size)
+
+
+func get_base_content_size() -> Vector2:
+ var font: Font = text.get_theme_font(&"normal_font")
+ return font.get_multiline_string_size(
+ text.get_parsed_text(),
+ HORIZONTAL_ALIGNMENT_LEFT,
+ max_width,
+ text.get_theme_font_size(&"normal_font_size")
+ )
+
+
+func add_choice_container(node:Container, alignment:=FlowContainer.ALIGNMENT_BEGIN) -> void:
+ if choice_container:
+ choice_container.get_parent().remove_child(choice_container)
+ choice_container.queue_free()
+
+ node.name = "ChoiceContainer"
+ choice_container = node
+ node.set_anchors_preset(LayoutPreset.PRESET_BOTTOM_WIDE)
+ node.grow_vertical = Control.GROW_DIRECTION_BEGIN
+ text.add_child(node)
+
+ if node is HFlowContainer:
+ (node as HFlowContainer).alignment = alignment
+
+ for i:int in range(5):
+ choice_container.add_child(DialogicNode_ChoiceButton.new())
+ if node is HFlowContainer:
+ continue
+ match alignment:
+ HBoxContainer.ALIGNMENT_BEGIN:
+ (choice_container.get_child(-1) as Control).size_flags_horizontal = SIZE_SHRINK_BEGIN
+ HBoxContainer.ALIGNMENT_CENTER:
+ (choice_container.get_child(-1) as Control).size_flags_horizontal = SIZE_SHRINK_CENTER
+ HBoxContainer.ALIGNMENT_END:
+ (choice_container.get_child(-1) as Control).size_flags_horizontal = SIZE_SHRINK_END
+
+ for child:Button in choice_container.get_children():
+ var prev := child.get_parent().get_child(wrap(child.get_index()-1, 0, choice_container.get_child_count()-1)).get_path()
+ var next := child.get_parent().get_child(wrap(child.get_index()+1, 0, choice_container.get_child_count()-1)).get_path()
+ child.focus_next = next
+ child.focus_previous = prev
+ child.focus_neighbor_left = prev
+ child.focus_neighbor_top = prev
+ child.focus_neighbor_right = next
+ child.focus_neighbor_bottom = next
+
+
+func get_speaker_canvas_position() -> Vector2:
+ if is_instance_valid(node_to_point_at):
+ if node_to_point_at is Node3D:
+ base_position = get_viewport().get_camera_3d().unproject_position(
+ (node_to_point_at as Node3D).global_position)
+ if node_to_point_at is CanvasItem:
+ base_position = (node_to_point_at as CanvasItem).get_global_transform_with_canvas().origin
+ return base_position
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.gdshader b/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.gdshader
new file mode 100644
index 000000000..60ebcee12
--- /dev/null
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.gdshader
@@ -0,0 +1,17 @@
+shader_type canvas_item;
+
+uniform sampler2D deformation_sampler : filter_linear, repeat_enable;
+uniform float radius : hint_range(1.0, 200, 0.01) = 25;
+uniform vec2 box_size = vec2(100, 100);
+uniform float box_padding = 15;
+uniform float wobble_amount : hint_range(0.0, 1.0, 0.01) = 0.2;
+uniform float wobble_speed : hint_range(0.0, 10.0, 0.01) = 1;
+uniform float wobble_detail : hint_range(0.01, 1, 0.01) = 0.5;
+
+void fragment() {
+ float adjusted_radius = min(min(radius, box_size.x/2.0), box_size.y/2.0);
+ vec2 deformation_sample = texture(deformation_sampler, UV*wobble_detail+TIME*wobble_speed*0.05).xy*(vec2(box_padding)/box_size)*0.9;
+ vec2 deformed_UV = UV+((deformation_sample)-vec2(0.5)*vec2(box_padding)/box_size)*wobble_amount;
+ float rounded_box = length(max(abs(deformed_UV*(box_size+vec2(box_padding))-vec2(0.5)*(box_size+vec2(box_padding)))+adjusted_radius-vec2(0.5)*box_size,0))-adjusted_radius;
+ COLOR.a = min(smoothstep(0.0, -1, rounded_box), COLOR.a);
+}
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.tscn b/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.tscn
index 4e0d4cc77..6277c5f5b 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.tscn
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.tscn
@@ -1,23 +1,15 @@
-[gd_scene load_steps=17 format=3 uid="uid://dlx7jcvm52tyw"]
+[gd_scene load_steps=11 format=3 uid="uid://dlx7jcvm52tyw"]
[ext_resource type="Script" path="res://addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.gd" id="1_jdhpk"]
-[ext_resource type="Shader" path="res://addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/speech_bubble.gdshader" id="2_1mhvf"]
+[ext_resource type="Shader" path="res://addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.gdshader" id="2_1mhvf"]
[ext_resource type="Script" path="res://addons/dialogic/Modules/Text/node_dialog_text.gd" id="3_syv35"]
[ext_resource type="Script" path="res://addons/dialogic/Modules/Text/node_type_sound.gd" id="4_7bm4b"]
[ext_resource type="Script" path="res://addons/dialogic/Modules/Text/node_name_label.gd" id="6_5gd03"]
-[ext_resource type="Script" path="res://addons/dialogic/Modules/Choice/node_choice_button.gd" id="7_0tnh1"]
[sub_resource type="Curve" id="Curve_0j8nu"]
_data = [Vector2(0, 1), 0.0, -1.0, 0, 1, Vector2(1, 0), -1.0, 0.0, 1, 0]
point_count = 2
-[sub_resource type="Curve" id="Curve_4meji"]
-_data = [Vector2(0, 0), 0.0, 0.0, 0, 0, Vector2(1, 1), 2.61284, 0.0, 0, 0]
-point_count = 2
-
-[sub_resource type="CurveTexture" id="CurveTexture_q6qf6"]
-curve = SubResource("Curve_4meji")
-
[sub_resource type="FastNoiseLite" id="FastNoiseLite_lsfnp"]
noise_type = 0
fractal_type = 0
@@ -27,64 +19,51 @@ cellular_jitter = 0.15
seamless = true
noise = SubResource("FastNoiseLite_lsfnp")
-[sub_resource type="FastNoiseLite" id="FastNoiseLite_ejxnv"]
-noise_type = 2
-frequency = 0.012
-fractal_type = 0
-cellular_jitter = 0.008
-
-[sub_resource type="NoiseTexture2D" id="NoiseTexture2D_4la3x"]
-seamless = true
-noise = SubResource("FastNoiseLite_ejxnv")
-
[sub_resource type="ShaderMaterial" id="ShaderMaterial_60xbe"]
+resource_local_to_scene = true
shader = ExtResource("2_1mhvf")
-shader_parameter/radius = 1.39
-shader_parameter/ratio = Vector2(2.251, 1)
-shader_parameter/crease = 0.12
-shader_parameter/speed = 2.53
-shader_parameter/texture_scale = 0.24
-shader_parameter/texture_offset = 172.5
+shader_parameter/radius = 200.0
+shader_parameter/box_size = Vector2(100, 100)
+shader_parameter/box_padding = 10.0
+shader_parameter/wobble_amount = 0.75
+shader_parameter/wobble_speed = 10.0
+shader_parameter/wobble_detail = 0.51
shader_parameter/deformation_sampler = SubResource("NoiseTexture2D_kr7hw")
-shader_parameter/spikes_sampler = SubResource("NoiseTexture2D_4la3x")
-shader_parameter/curve_sampler = SubResource("CurveTexture_q6qf6")
[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_h6ls0"]
content_margin_left = 5.0
content_margin_right = 5.0
-bg_color = Color(0.901961, 0.901961, 0.901961, 1)
+bg_color = Color(1, 1, 1, 1)
corner_radius_top_left = 10
corner_radius_top_right = 10
corner_radius_bottom_right = 10
corner_radius_bottom_left = 10
-shadow_color = Color(0, 0, 0, 0.278431)
+shadow_color = Color(0.152941, 0.152941, 0.152941, 0.12549)
shadow_size = 5
-[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_g4yjl"]
-draw_center = false
-border_width_bottom = 3
-border_color = Color(0, 0, 0, 0.498039)
-
[node name="TextBubble" type="Control"]
layout_mode = 3
anchors_preset = 0
-mouse_filter = 2
script = ExtResource("1_jdhpk")
-[node name="Tail" type="Line2D" parent="."]
+[node name="Group" type="CanvasGroup" parent="."]
+
+[node name="Tail" type="Line2D" parent="Group"]
+unique_name_in_owner = true
+points = PackedVector2Array(-9, 7, -29, 118, -95, 174, -193, 195)
width = 96.0
width_curve = SubResource("Curve_0j8nu")
-[node name="Background" type="ColorRect" parent="."]
+[node name="Background" type="ColorRect" parent="Group"]
+unique_name_in_owner = true
material = SubResource("ShaderMaterial_60xbe")
-layout_mode = 1
-offset_left = -69.0
-offset_top = -21.0
-offset_right = 225.0
-offset_bottom = 79.0
+offset_left = -115.0
+offset_top = -69.0
+offset_right = 108.0
+offset_bottom = 83.0
mouse_filter = 2
-[node name="DialogText" type="RichTextLabel" parent="."]
+[node name="DialogText" type="RichTextLabel" parent="." node_paths=PackedStringArray("textbox_root")]
unique_name_in_owner = true
clip_contents = false
layout_mode = 1
@@ -99,77 +78,34 @@ offset_right = 53.0
offset_bottom = 12.0
grow_horizontal = 2
grow_vertical = 2
-mouse_filter = 2
theme_override_colors/default_color = Color(0, 0, 0, 1)
-text = "Some Text"
scroll_active = false
visible_characters_behavior = 1
script = ExtResource("3_syv35")
+textbox_root = NodePath("..")
[node name="DialogicNode_TypeSounds" type="AudioStreamPlayer" parent="DialogText"]
script = ExtResource("4_7bm4b")
-[node name="NameLabel" type="PanelContainer" parent="DialogText"]
+[node name="NameLabelPositioner" type="HBoxContainer" parent="DialogText"]
layout_mode = 1
-anchors_preset = -1
-offset_left = 16.0
-offset_top = -26.0
-offset_right = 27.0
+anchors_preset = 10
+anchor_right = 1.0
+offset_bottom = 23.0
grow_horizontal = 2
-mouse_filter = 2
+alignment = 1
+
+[node name="NameLabelPanel" type="PanelContainer" parent="DialogText/NameLabelPositioner"]
+unique_name_in_owner = true
+layout_mode = 2
theme_override_styles/panel = SubResource("StyleBoxFlat_h6ls0")
-[node name="NameLabel" type="Label" parent="DialogText/NameLabel" node_paths=PackedStringArray("name_label_root")]
+[node name="NameLabel" type="Label" parent="DialogText/NameLabelPositioner/NameLabelPanel" node_paths=PackedStringArray("name_label_root")]
unique_name_in_owner = true
layout_mode = 2
horizontal_alignment = 1
script = ExtResource("6_5gd03")
name_label_root = NodePath("..")
-
-[node name="ChoiceContainer" type="HBoxContainer" parent="DialogText"]
-layout_mode = 1
-anchors_preset = 12
-anchor_top = 1.0
-anchor_right = 1.0
-anchor_bottom = 1.0
-offset_left = 5.0
-offset_top = -31.0
-offset_right = -4.0
-grow_horizontal = 2
-grow_vertical = 0
-mouse_filter = 2
-alignment = 2
-
-[node name="DialogicNode_ChoiceButton" type="Button" parent="DialogText/ChoiceContainer"]
-layout_mode = 2
-size_flags_horizontal = 4
-theme_override_styles/focus = SubResource("StyleBoxFlat_g4yjl")
-text = "A"
-flat = true
-script = ExtResource("7_0tnh1")
-
-[node name="DialogicNode_ChoiceButton2" type="Button" parent="DialogText/ChoiceContainer"]
-layout_mode = 2
-size_flags_horizontal = 4
-theme_override_styles/focus = SubResource("StyleBoxFlat_g4yjl")
-text = "A"
-flat = true
-script = ExtResource("7_0tnh1")
-
-[node name="DialogicNode_ChoiceButton3" type="Button" parent="DialogText/ChoiceContainer"]
-layout_mode = 2
-size_flags_horizontal = 4
-theme_override_styles/focus = SubResource("StyleBoxFlat_g4yjl")
-text = "A"
-flat = true
-script = ExtResource("7_0tnh1")
-
-[node name="DialogicNode_ChoiceButton4" type="Button" parent="DialogText/ChoiceContainer"]
-layout_mode = 2
-size_flags_horizontal = 4
-theme_override_styles/focus = SubResource("StyleBoxFlat_g4yjl")
-text = "A"
-flat = true
-script = ExtResource("7_0tnh1")
+use_character_color = false
[connection signal="started_revealing_text" from="DialogText" to="." method="_on_dialog_text_started_revealing_text"]
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble_layer.gd b/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble_layer.gd
index c155de286..27644745f 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble_layer.gd
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble_layer.gd
@@ -1,7 +1,7 @@
@tool
extends DialogicLayoutLayer
-## This layout won't do anything on it's own
+## This layout won't do anything on its own
@export_group("Main")
@export_subgroup("Text")
@@ -17,60 +17,69 @@ extends DialogicLayoutLayer
@export var box_modulate: Color = Color.WHITE
@export var box_modulate_by_character_color: bool = false
@export var box_padding: Vector2 = Vector2(10,10)
-@export_range(0.1, 2) var box_corner_radius: float = 0.3
-@export_range(0.1, 5) var box_wobble_speed: float= 1
-@export_range(0, 1) var box_wobbliness: float = 0.2
+@export_range(1, 999) var box_corner_radius: int = 25
+@export_range(0.1, 5) var box_wobble_speed: float = 1
+@export_range(0, 1) var box_wobble_amount: float = 0.5
+@export_range(0, 1) var box_wobble_detail: float = 0.2
@export_subgroup('Behaviour')
@export var behaviour_distance: int = 50
@export var behaviour_direction: Vector2 = Vector2(1, -1)
-@export_group('Name Label & Choices')
+@export_group('Name Label')
@export_subgroup("Name Label")
@export var name_label_enabled: bool = true
@export var name_label_font_size: int = 15
@export_file('*.ttf') var name_label_font: String = ""
@export var name_label_use_character_color: bool = true
@export var name_label_color: Color = Color.BLACK
+@export_subgroup("Name Label Box")
@export var name_label_box_modulate: Color = Color.WHITE
+@export var name_label_box_modulate_use_character_color: bool = false
@export var name_label_padding: Vector2 = Vector2(5,0)
@export var name_label_offset: Vector2 = Vector2(0,0)
+@export var name_label_alignment := HBoxContainer.ALIGNMENT_BEGIN
+
+@export_group('Choices')
@export_subgroup('Choices Text')
@export var choices_text_size: int = 15
-@export var choices_text_color: Color = Color.LIGHT_SLATE_GRAY
-@export var choices_text_color_hover: Color = Color.DARK_GRAY
-@export var choices_text_color_focus: Color = Color.BLACK
+@export_file('*.ttf') var choices_text_font: String = ""
+@export var choices_text_color: Color = Color.DARK_SLATE_GRAY
+@export var choices_text_color_hover: Color = Color.DARK_MAGENTA
+@export var choices_text_color_focus: Color = Color.DARK_MAGENTA
+@export var choices_text_color_disabled: Color = Color.DARK_GRAY
+
+@export_subgroup('Choices Layout')
+@export var choices_layout_alignment := FlowContainer.ALIGNMENT_END
+@export var choices_layout_force_lines: bool = false
+@export_file('*.tres', "*.res") var choices_base_theme: String = ""
+const TextBubble := preload("res://addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.gd")
-var bubbles: Array[DialogicNode_TextBubble] = []
-var fallback_bubble: DialogicNode_TextBubble = null
+var bubbles: Array[TextBubble] = []
+var fallback_bubble: TextBubble = null
-@export_group('Private')
-@export var textbubble_scene: PackedScene = null
+const textbubble_scene: PackedScene = preload("res://addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.tscn")
-func add_bubble() -> DialogicNode_TextBubble:
- var new_bubble: DialogicNode_TextBubble = textbubble_scene.instantiate()
+func add_bubble() -> TextBubble:
+ var new_bubble: TextBubble = textbubble_scene.instantiate()
add_child(new_bubble)
- bubble_apply_overrides(new_bubble)
bubbles.append(new_bubble)
return new_bubble
-
## Called by dialogic whenever export overrides might change
func _apply_export_overrides() -> void:
- for bubble: DialogicNode_TextBubble in bubbles:
- bubble_apply_overrides(bubble)
+ pass
- if fallback_bubble:
- bubble_apply_overrides(fallback_bubble)
-func bubble_apply_overrides(bubble:DialogicNode_TextBubble) -> void:
+## Called by the base layer before opening the bubble
+func bubble_apply_overrides(bubble:TextBubble) -> void:
## TEXT FONT AND COLOR
- var rtl: RichTextLabel = bubble.get_dialog_text()
+ var rtl: RichTextLabel = bubble.text
rtl.add_theme_font_size_override(&'normal_font', text_size)
rtl.add_theme_font_size_override(&"normal_font_size", text_size)
rtl.add_theme_font_size_override(&"bold_font_size", text_size)
@@ -91,55 +100,86 @@ func bubble_apply_overrides(bubble:DialogicNode_TextBubble) -> void:
## BOX & TAIL COLOR
- var tail: Line2D = bubble.get_tail()
- var background: Control = bubble.get_bubble()
- var bubble_material: ShaderMaterial = background.get(&'material')
-
- tail.default_color = box_modulate
- background.set(&'color', box_modulate)
- bubble_material.set_shader_parameter(&'radius', box_corner_radius)
- bubble_material.set_shader_parameter(&'crease', box_wobbliness*0.1)
- bubble_material.set_shader_parameter(&'speed', box_wobble_speed)
- if box_modulate_by_character_color and bubble.character != null:
- tail.modulate = bubble.character.color
- background.modulate = bubble.character.color
+ var tail_and_bg_group := (bubble.get_node("Group") as CanvasGroup)
+ tail_and_bg_group.self_modulate = box_modulate
+ if box_modulate_by_character_color and bubble.current_character != null:
+ tail_and_bg_group.self_modulate = bubble.current_character.color
+
+ var background := (bubble.get_node('%Background') as ColorRect)
+ var bg_material: ShaderMaterial = (background.material as ShaderMaterial)
+ bg_material.set_shader_parameter(&'radius', box_corner_radius)
+ bg_material.set_shader_parameter(&'wobble_amount', box_wobble_amount)
+ bg_material.set_shader_parameter(&'wobble_speed', box_wobble_speed)
+ bg_material.set_shader_parameter(&'wobble_detail', box_wobble_detail)
+
bubble.padding = box_padding
+
+ ## BEHAVIOUR
+ bubble.safe_zone = behaviour_distance
+ bubble.base_direction = behaviour_direction
+
+
## NAME LABEL SETTINGS
- var nl: DialogicNode_NameLabel = bubble.get_name_label()
+ var nl: DialogicNode_NameLabel = bubble.name_label
nl.add_theme_font_size_override(&"font_size", name_label_font_size)
if !name_label_font.is_empty():
nl.add_theme_font_override(&'font', load(name_label_font) as Font)
- nl.use_character_color = name_label_use_character_color
- if !nl.use_character_color:
+
+ if name_label_use_character_color and bubble.current_character:
+ nl.add_theme_color_override(&"font_color", bubble.current_character.color)
+ else:
nl.add_theme_color_override(&"font_color", name_label_color)
- var nlp: PanelContainer = bubble.get_name_label_panel()
+ var nlp: PanelContainer = bubble.name_label_box
nlp.self_modulate = name_label_box_modulate
+ if name_label_box_modulate_use_character_color and bubble.current_character:
+ nlp.self_modulate = bubble.current_character.color
nlp.get_theme_stylebox(&'panel').content_margin_left = name_label_padding.x
nlp.get_theme_stylebox(&'panel').content_margin_right = name_label_padding.x
nlp.get_theme_stylebox(&'panel').content_margin_top = name_label_padding.y
nlp.get_theme_stylebox(&'panel').content_margin_bottom = name_label_padding.y
- nlp.position += name_label_offset
-
- if !name_label_enabled:
- nlp.queue_free()
-
+ bubble.name_label_offset = name_label_offset
+ bubble.name_label_alignment = name_label_alignment
+
+ nlp.get_parent().visible = name_label_enabled
## CHOICE SETTINGS
- var choice_theme: Theme = Theme.new()
+ if choices_layout_force_lines:
+ bubble.add_choice_container(VBoxContainer.new(), choices_layout_alignment)
+ else:
+ bubble.add_choice_container(HFlowContainer.new(), choices_layout_alignment)
+
+ var choice_theme: Theme = null
+ if choices_base_theme.is_empty() or not ResourceLoader.exists(choices_base_theme):
+ choice_theme = Theme.new()
+ var base_style := StyleBoxFlat.new()
+ base_style.draw_center = false
+ base_style.border_width_bottom = 2
+ base_style.border_color = choices_text_color
+ choice_theme.set_stylebox(&'normal', &'Button', base_style)
+ var focus_style := (base_style.duplicate() as StyleBoxFlat)
+ focus_style.border_color = choices_text_color_focus
+ choice_theme.set_stylebox(&'focus', &'Button', focus_style)
+ var hover_style := (base_style.duplicate() as StyleBoxFlat)
+ hover_style.border_color = choices_text_color_hover
+ choice_theme.set_stylebox(&'hover', &'Button', hover_style)
+ var disabled_style := (base_style.duplicate() as StyleBoxFlat)
+ disabled_style.border_color = choices_text_color_disabled
+ choice_theme.set_stylebox(&'disabled', &'Button', disabled_style)
+ choice_theme.set_stylebox(&'pressed', &'Button', base_style)
+ else:
+ choice_theme = (load(choices_base_theme) as Theme)
+
+ if !choices_text_font.is_empty():
+ choice_theme.default_font = (load(choices_text_font) as Font)
+
choice_theme.set_font_size(&'font_size', &'Button', choices_text_size)
choice_theme.set_color(&'font_color', &'Button', choices_text_color)
choice_theme.set_color(&'font_pressed_color', &'Button', choices_text_color)
choice_theme.set_color(&'font_hover_color', &'Button', choices_text_color_hover)
choice_theme.set_color(&'font_focus_color', &'Button', choices_text_color_focus)
-
- bubble.get_choice_container().theme = choice_theme
-
- ## BEHAVIOUR
- bubble.safe_zone = behaviour_distance
- bubble.base_direction = behaviour_direction
-
-
+ choice_theme.set_color(&'font_disabled_color', &'Button', choices_text_color_disabled)
+ bubble.choice_container.theme = choice_theme
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble_layer.tscn b/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble_layer.tscn
index 6ed91452c..5909325e3 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble_layer.tscn
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble_layer.tscn
@@ -1,11 +1,9 @@
-[gd_scene load_steps=3 format=3 uid="uid://d2it0xiap3gnt"]
+[gd_scene load_steps=2 format=3 uid="uid://d2it0xiap3gnt"]
[ext_resource type="Script" path="res://addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble_layer.gd" id="1_b37je"]
-[ext_resource type="PackedScene" uid="uid://dlx7jcvm52tyw" path="res://addons/dialogic/Modules/DefaultLayoutParts/Layer_Textbubble/text_bubble.tscn" id="2_xncjh"]
[node name="TextBubbleLayer" type="Control"]
layout_mode = 3
anchors_preset = 0
mouse_filter = 2
script = ExtResource("1_b37je")
-textbubble_scene = ExtResource("2_xncjh")
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Choices/vn_choice_layer.gd b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Choices/vn_choice_layer.gd
index a0371f0e5..97195f5bb 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Choices/vn_choice_layer.gd
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Choices/vn_choice_layer.gd
@@ -31,6 +31,7 @@ extends DialogicLayoutLayer
@export var boxes_v_separation: int = 10
@export var boxes_fill_width: bool = true
@export var boxes_min_size: Vector2 = Vector2()
+@export var boxes_offset: Vector2 = Vector2()
@export_group('Sounds')
@export_range(-80, 24, 0.01) var sounds_volume: float = -10
@@ -96,6 +97,7 @@ func _apply_export_overrides() -> void:
layer_theme.set_stylebox(&'focus', &'Button', load(boxes_stylebox_focused) as StyleBox)
get_choices().add_theme_constant_override(&"separation", boxes_v_separation)
+ self.position = boxes_offset
for child: Node in get_choices().get_children():
if not child is DialogicNode_ChoiceButton:
@@ -109,6 +111,7 @@ func _apply_export_overrides() -> void:
choice.custom_minimum_size = boxes_min_size
+
set(&'theme', layer_theme)
# apply sound settings
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Choices/vn_choice_layer.tscn b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Choices/vn_choice_layer.tscn
index 75482d9e0..7c9fb00f3 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Choices/vn_choice_layer.tscn
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Choices/vn_choice_layer.tscn
@@ -25,10 +25,10 @@ anchor_left = 0.5
anchor_top = 0.5
anchor_right = 0.5
anchor_bottom = 0.5
-offset_left = -86.5
-offset_top = -103.0
-offset_right = 86.5
-offset_bottom = 103.0
+offset_left = -41.0
+offset_top = -47.0
+offset_right = 42.0
+offset_bottom = 47.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Portraits/vn_portrait_layer.tscn b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Portraits/vn_portrait_layer.tscn
index b5e79f022..bb803eeb5 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Portraits/vn_portrait_layer.tscn
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Portraits/vn_portrait_layer.tscn
@@ -25,58 +25,60 @@ mouse_filter = 2
[node name="DialogicNode_PortraitContainer1" type="Control" parent="Portraits"]
layout_mode = 1
-anchor_right = 0.231771
+anchor_right = 0.2
anchor_bottom = 1.0
+offset_right = -1.52588e-05
grow_vertical = 2
+pivot_offset = Vector2(115.2, 648)
mouse_filter = 2
script = ExtResource("1_rxdcc")
+container_ids = PackedStringArray("leftmost", "0")
metadata/_edit_use_anchors_ = true
[node name="DialogicNode_PortraitContainer2" type="Control" parent="Portraits"]
layout_mode = 1
-anchor_left = 0.190104
-anchor_right = 0.401042
+anchor_left = 0.2
+anchor_right = 0.4
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
script = ExtResource("1_rxdcc")
-position_index = 1
+container_ids = PackedStringArray("left", "1")
metadata/_edit_use_anchors_ = true
[node name="DialogicNode_PortraitContainer3" type="Control" parent="Portraits"]
layout_mode = 1
-anchor_left = 0.371528
-anchor_right = 0.625868
+anchor_left = 0.4
+anchor_right = 0.6
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
script = ExtResource("1_rxdcc")
-position_index = 2
+container_ids = PackedStringArray("center", "middle", "2")
metadata/_edit_use_anchors_ = true
[node name="DialogicNode_PortraitContainer4" type="Control" parent="Portraits"]
layout_mode = 1
-anchor_left = 0.592882
-anchor_right = 0.805556
-anchor_bottom = 0.996914
+anchor_left = 0.6
+anchor_right = 0.8
+anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
script = ExtResource("1_rxdcc")
-position_index = 3
+container_ids = PackedStringArray("right", "3")
metadata/_edit_use_anchors_ = true
[node name="DialogicNode_PortraitContainer5" type="Control" parent="Portraits"]
layout_mode = 1
-anchor_left = 0.776042
-anchor_top = -0.00462963
-anchor_right = 1.00434
+anchor_left = 0.8
+anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
mouse_filter = 2
script = ExtResource("1_rxdcc")
-position_index = 4
+container_ids = PackedStringArray("rightmost", "4")
metadata/_edit_use_anchors_ = true
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/animations.gd b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/animations.gd
index 43eca1f7d..c03b3ee0d 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/animations.gd
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/animations.gd
@@ -7,11 +7,12 @@ enum AnimationsIn {NONE, POP_IN, FADE_UP}
enum AnimationsOut {NONE, POP_OUT, FADE_DOWN}
enum AnimationsNewText {NONE, WIGGLE}
-var animation_in : AnimationsIn
-var animation_out : AnimationsOut
-var animation_new_text : AnimationsNewText
+var animation_in: AnimationsIn
+var animation_out: AnimationsOut
+var animation_new_text: AnimationsNewText
+
+var full_clear := true
-var full_clear : bool = true
func get_text_panel() -> PanelContainer:
return %DialogTextPanel
@@ -22,19 +23,20 @@ func get_dialog() -> DialogicNode_DialogText:
func _ready() -> void:
- var text_system : Node = DialogicUtil.autoload().get(&'Text')
- var _error : int = 0
- _error = text_system.connect(&'animation_textbox_hide', _on_textbox_hide)
- _error = text_system.connect(&'animation_textbox_show', _on_textbox_show)
- _error = text_system.connect(&'animation_textbox_new_text', _on_textbox_new_text)
- _error = text_system.connect(&'about_to_show_text', _on_about_to_show_text)
+ var text_system: Node = DialogicUtil.autoload().get(&'Text')
+ text_system.connect(&'animation_textbox_hide', _on_textbox_hide)
+ text_system.connect(&'animation_textbox_show', _on_textbox_show)
+ text_system.connect(&'animation_textbox_new_text', _on_textbox_new_text)
+ text_system.connect(&'about_to_show_text', _on_about_to_show_text)
+ var animation_system: Node = DialogicUtil.autoload().get(&'Animations')
+ animation_system.connect(&'animation_interrupted', _on_animation_interrupted)
func _on_textbox_show() -> void:
if animation_in == AnimationsIn.NONE:
return
play('RESET')
- var animation_system : Node = DialogicUtil.autoload().get(&'Animations')
+ var animation_system: Node = DialogicUtil.autoload().get(&'Animations')
animation_system.call(&'start_animating')
get_text_panel().get_parent().get_parent().set(&'modulate', Color.TRANSPARENT)
get_dialog().text = ""
@@ -43,15 +45,15 @@ func _on_textbox_show() -> void:
play("textbox_pop")
AnimationsIn.FADE_UP:
play("textbox_fade_up")
- if not is_connected(&'animation_finished', Callable(animation_system, &'animation_finished')):
- var _error : int = connect(&'animation_finished', Callable(animation_system, &'animation_finished'), CONNECT_ONE_SHOT)
+ if not animation_finished.is_connected(Callable(animation_system, &'animation_finished')):
+ animation_finished.connect(Callable(animation_system, &'animation_finished'), CONNECT_ONE_SHOT)
func _on_textbox_hide() -> void:
if animation_out == AnimationsOut.NONE:
return
play('RESET')
- var animation_system : Node = DialogicUtil.autoload().get(&'Animations')
+ var animation_system: Node = DialogicUtil.autoload().get(&'Animations')
animation_system.call(&'start_animating')
match animation_out:
AnimationsOut.POP_OUT:
@@ -59,8 +61,8 @@ func _on_textbox_hide() -> void:
AnimationsOut.FADE_DOWN:
play_backwards("textbox_fade_up")
- if not is_connected(&'animation_finished', Callable(animation_system, &'animation_finished')):
- var _error : int = connect(&'animation_finished', Callable(animation_system, &'animation_finished'), CONNECT_ONE_SHOT)
+ if not animation_finished.is_connected(Callable(animation_system, &'animation_finished')):
+ animation_finished.connect(Callable(animation_system, &'animation_finished'), CONNECT_ONE_SHOT)
func _on_about_to_show_text(info:Dictionary) -> void:
@@ -74,7 +76,7 @@ func _on_textbox_new_text() -> void:
if animation_new_text == AnimationsNewText.NONE:
return
- var animation_system : Node = DialogicUtil.autoload().get(&'Animation')
+ var animation_system: Node = DialogicUtil.autoload().get(&'Animations')
animation_system.call(&'start_animating')
if full_clear:
get_dialog().text = ""
@@ -82,5 +84,10 @@ func _on_textbox_new_text() -> void:
AnimationsNewText.WIGGLE:
play("new_text")
- if not is_connected(&'animation_finished', Callable(animation_system, &'animation_finished')):
- var _error : int = connect(&'animation_finished', Callable(animation_system, &'animation_finished'), CONNECT_ONE_SHOT)
+ if not animation_finished.is_connected(Callable(animation_system, &'animation_finished')):
+ animation_finished.connect(Callable(animation_system, &'animation_finished'), CONNECT_ONE_SHOT)
+
+
+func _on_animation_interrupted() -> void:
+ if is_playing():
+ stop()
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/autoadvance_indicator.gd b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/autoadvance_indicator.gd
index fa8bbffcb..a4384bd60 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/autoadvance_indicator.gd
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/autoadvance_indicator.gd
@@ -1,6 +1,6 @@
extends Range
-var enabled : bool = true
+var enabled: bool = true
func _process(_delta : float) -> void:
if !enabled:
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/vn_textbox_layer.gd b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/vn_textbox_layer.gd
index 8a1645394..95a4ce3cb 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/vn_textbox_layer.gd
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/vn_textbox_layer.gd
@@ -38,10 +38,10 @@ enum AnimationsNewText {NONE, WIGGLE}
@export_subgroup('Font')
@export var text_use_global_font: bool = true
-@export_file('*.ttf', '*.tres') var normal_font:String = ""
-@export_file('*.ttf', '*.tres') var bold_font:String = ""
-@export_file('*.ttf', '*.tres') var italics_font:String = ""
-@export_file('*.ttf', '*.tres') var bold_italics_font:String = ""
+@export_file('*.ttf', '*.tres') var normal_font: String = ""
+@export_file('*.ttf', '*.tres') var bold_font: String = ""
+@export_file('*.ttf', '*.tres') var italics_font: String = ""
+@export_file('*.ttf', '*.tres') var bold_italics_font: String = ""
@export_group("Box")
@@ -246,8 +246,8 @@ func _apply_indicator_settings() -> void:
next_indicator.enabled = next_indicator_enabled
if next_indicator_enabled:
- next_indicator.animation = next_indicator_animation
- if FileAccess.file_exists(next_indicator_texture):
+ next_indicator.animation = next_indicator_animation as DialogicNode_NextIndicator.Animations
+ if ResourceLoader.exists(next_indicator_texture):
next_indicator.texture = load(next_indicator_texture)
next_indicator.show_on_questions = next_indicator_show_on_questions
next_indicator.show_on_autoadvance = next_indicator_show_on_autoadvance
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/vn_textbox_layer.tscn b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/vn_textbox_layer.tscn
index f8f8e4203..5521ef82a 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/vn_textbox_layer.tscn
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Layer_VN_Textbox/vn_textbox_layer.tscn
@@ -258,11 +258,11 @@ offset_top = -50.0
offset_right = 150.0
grow_horizontal = 2
grow_vertical = 0
+mouse_filter = 2
[node name="DialogTextPanel" type="PanelContainer" parent="Anchor/AnimationParent/Sizer"]
unique_name_in_owner = true
self_modulate = Color(0.00784314, 0.00784314, 0.00784314, 0.843137)
-custom_minimum_size = Vector2(300, 50)
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
@@ -298,6 +298,7 @@ unique_name_in_owner = true
layout_mode = 2
size_flags_horizontal = 8
size_flags_vertical = 8
+mouse_filter = 2
script = ExtResource("5_40a50")
show_on_questions = true
texture = ExtResource("6_uch03")
@@ -309,6 +310,7 @@ modulate = Color(1, 1, 1, 0.188235)
custom_minimum_size = Vector2(0, 10)
layout_mode = 2
size_flags_vertical = 8
+mouse_filter = 2
max_value = 1.0
step = 0.001
value = 0.5
@@ -326,6 +328,7 @@ layout_mode = 1
offset_top = -50.0
offset_right = 9.0
offset_bottom = -25.0
+mouse_filter = 2
theme_override_styles/panel = ExtResource("9_yg8ig")
metadata/_edit_layout_mode = 1
metadata/_edit_use_custom_anchors = true
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Style_SpeakerTextbox/speaker_textbox_style.tres b/addons/dialogic/Modules/DefaultLayoutParts/Style_SpeakerTextbox/speaker_textbox_style.tres
index 627d991c2..9ff8d5b21 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Style_SpeakerTextbox/speaker_textbox_style.tres
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Style_SpeakerTextbox/speaker_textbox_style.tres
@@ -15,14 +15,14 @@ script = ExtResource("2_i34tx")
scene = ExtResource("1_sde84")
overrides = {}
-[sub_resource type="Resource" id="Resource_gc1b5"]
+[sub_resource type="Resource" id="Resource_x576n"]
script = ExtResource("2_i34tx")
-scene = ExtResource("3_epko4")
+scene = ExtResource("4_8y2vo")
overrides = {}
-[sub_resource type="Resource" id="Resource_x576n"]
+[sub_resource type="Resource" id="Resource_gc1b5"]
script = ExtResource("2_i34tx")
-scene = ExtResource("4_8y2vo")
+scene = ExtResource("3_epko4")
overrides = {}
[sub_resource type="Resource" id="Resource_otikm"]
@@ -51,4 +51,4 @@ name = "Speaker Textbox Style"
base_overrides = {
"global_bg_color": "Color(0.298039, 0.2, 0.113725, 0.901961)"
}
-layers = Array[ExtResource("2_i34tx")]([SubResource("Resource_35sbo"), SubResource("Resource_gc1b5"), SubResource("Resource_x576n"), SubResource("Resource_otikm"), SubResource("Resource_w8ec6"), SubResource("Resource_qmo1y"), SubResource("Resource_legp8")])
+layers = Array[ExtResource("2_i34tx")]([SubResource("Resource_35sbo"), SubResource("Resource_x576n"), SubResource("Resource_gc1b5"), SubResource("Resource_otikm"), SubResource("Resource_w8ec6"), SubResource("Resource_qmo1y"), SubResource("Resource_legp8")])
diff --git a/addons/dialogic/Modules/DefaultLayoutParts/Style_VN_Default/default_vn_style.tres b/addons/dialogic/Modules/DefaultLayoutParts/Style_VN_Default/default_vn_style.tres
index 7413de116..d9200d673 100644
--- a/addons/dialogic/Modules/DefaultLayoutParts/Style_VN_Default/default_vn_style.tres
+++ b/addons/dialogic/Modules/DefaultLayoutParts/Style_VN_Default/default_vn_style.tres
@@ -21,14 +21,14 @@ script = ExtResource("2_3b8ue")
scene = ExtResource("4_q1t5h")
overrides = {}
-[sub_resource type="Resource" id="Resource_adxfb"]
+[sub_resource type="Resource" id="Resource_eqyxb"]
script = ExtResource("2_3b8ue")
-scene = ExtResource("5_o6sv8")
+scene = ExtResource("6_j6olx")
overrides = {}
-[sub_resource type="Resource" id="Resource_eqyxb"]
+[sub_resource type="Resource" id="Resource_adxfb"]
script = ExtResource("2_3b8ue")
-scene = ExtResource("6_j6olx")
+scene = ExtResource("5_o6sv8")
overrides = {}
[sub_resource type="Resource" id="Resource_nmutb"]
@@ -55,4 +55,4 @@ overrides = {}
script = ExtResource("1_mvpc0")
name = "Visual Novel Style"
base_overrides = {}
-layers = Array[ExtResource("2_3b8ue")]([SubResource("Resource_x8thn"), SubResource("Resource_g5yti"), SubResource("Resource_adxfb"), SubResource("Resource_eqyxb"), SubResource("Resource_nmutb"), SubResource("Resource_dwo52"), SubResource("Resource_by0l6"), SubResource("Resource_fd6co")])
+layers = Array[ExtResource("2_3b8ue")]([SubResource("Resource_x8thn"), SubResource("Resource_g5yti"), SubResource("Resource_eqyxb"), SubResource("Resource_adxfb"), SubResource("Resource_nmutb"), SubResource("Resource_dwo52"), SubResource("Resource_by0l6"), SubResource("Resource_fd6co")])
diff --git a/addons/dialogic/Modules/End/event_end.gd b/addons/dialogic/Modules/End/event_end.gd
index 0e6738365..b853119a7 100644
--- a/addons/dialogic/Modules/End/event_end.gd
+++ b/addons/dialogic/Modules/End/event_end.gd
@@ -38,7 +38,7 @@ func get_shortcode() -> String:
#region EDITOR REPRESENTATION
################################################################################
-func build_event_editor():
+func build_event_editor() -> void:
add_header_label('End Timeline')
#endregion
diff --git a/addons/dialogic/Modules/Glossary/event_glossary.gd b/addons/dialogic/Modules/Glossary/event_glossary.gd
index a9881e5df..d8fce3ac2 100644
--- a/addons/dialogic/Modules/Glossary/event_glossary.gd
+++ b/addons/dialogic/Modules/Glossary/event_glossary.gd
@@ -38,5 +38,5 @@ func get_shortcode_parameters() -> Dictionary:
## EDITOR REPRESENTATION
################################################################################
-func build_event_editor():
+func build_event_editor() -> void:
pass
diff --git a/addons/dialogic/Modules/Glossary/glossary_editor.gd b/addons/dialogic/Modules/Glossary/glossary_editor.gd
index a4e7de8dc..403ed6d72 100644
--- a/addons/dialogic/Modules/Glossary/glossary_editor.gd
+++ b/addons/dialogic/Modules/Glossary/glossary_editor.gd
@@ -62,7 +62,7 @@ func _open(_argument: Variant = null) -> void:
var idx := 0
for file: String in ProjectSettings.get_setting('dialogic/glossary/glossary_files', []):
- if FileAccess.file_exists(file):
+ if ResourceLoader.exists(file):
%GlossaryList.add_item(DialogicUtil.pretty_name(file), get_theme_icon('FileList', 'EditorIcons'))
else:
%GlossaryList.add_item(DialogicUtil.pretty_name(file), get_theme_icon('FileDead', 'EditorIcons'))
@@ -86,7 +86,7 @@ func _on_GlossaryList_item_selected(idx: int) -> void:
%EntryList.clear()
var tooltip_item: String = %GlossaryList.get_item_tooltip(idx)
- if FileAccess.file_exists(tooltip_item):
+ if ResourceLoader.exists(tooltip_item):
var glossary_item := load(tooltip_item)
if not glossary_item is DialogicGlossary:
@@ -144,7 +144,7 @@ func _on_load_glossary_file_pressed() -> void:
func load_glossary_file(path:String) -> void:
- var list :Array= ProjectSettings.get_setting('dialogic/glossary/glossary_files', [])
+ var list: Array = ProjectSettings.get_setting('dialogic/glossary/glossary_files', [])
if not path in list:
list.append(path)
diff --git a/addons/dialogic/Modules/Glossary/glossary_resource.gd b/addons/dialogic/Modules/Glossary/glossary_resource.gd
index 9a9f43d0b..638d03697 100644
--- a/addons/dialogic/Modules/Glossary/glossary_resource.gd
+++ b/addons/dialogic/Modules/Glossary/glossary_resource.gd
@@ -10,7 +10,7 @@ extends Resource
## a string, representing the actual key for the key used.
## The string key-value pairs are the alias keys, they allow to redirect
## the actual glossary entry.
-@export var entries: Dictionary = {}
+@export var entries := {}
## If false, no entries from this glossary will be shown
@export var enabled: bool = true
@@ -37,21 +37,17 @@ const REGEX_OPTION_PROPERTY := "regex_options"
## Ignored when entries are translated.
const PRIVATE_PROPERTY_PREFIX := "_"
-const _MISSING_ENTRY_INDEX := -1
## Private ID assigned when this glossary is translated.
-@export var _translation_id: String = ""
+@export var _translation_id := ""
## Private lookup table used to find the translation ID of a glossary entry.
## The keys (String) are all translated words that may trigger a glossary entry to
## be shown.
## The values (String) are the translation ID.
-@export var _translation_keys: Dictionary = {}
+@export var _translation_keys := {}
-func __get_property_list() -> Array:
- return []
-
## Removes an entry and all its aliases (alternative property) from
## the glossary.
@@ -226,6 +222,8 @@ func get_set_regex_option(entry_key: String) -> String:
return regex_option
+#region ADD AND CLEAR TRANSLATION KEYS
+
## This is automatically called, no need to use this.
func add_translation_id() -> String:
_translation_id = DialogicUtil.get_next_translation_id()
@@ -260,6 +258,10 @@ func clear_translation_keys() -> void:
_translation_keys.clear()
+#endregion
+
+
+#region GET AND SET TRANSLATION IDS AND KEYS
## Returns a key used to reference this glossary in the translation CSV file.
##
@@ -283,19 +285,6 @@ func get_property_translation_key(entry_key: String, property: String) -> String
return glossary_csv_key
-## Returns the matching translation key for the given [param word].
-## This key can be used via [method tr] to get the translation.
-##
-## Time complexity: O(1)
-## Uses an internal dictionary to find the translation key.
-## This dictionary is generated when the glossary is translated.
-## See [member _translation_keys].
-func get_word_translation_key(word: String) -> String:
- if _translation_keys.has(word):
- return _translation_keys[word]
-
- return ""
-
## Returns the translation key prefix for this glossary.
## The resulting format will look like this: Glossary/a2/
@@ -348,3 +337,4 @@ func get_set_glossary_translation_id() -> String:
return _translation_id
+#endregion
diff --git a/addons/dialogic/Modules/Glossary/subsystem_glossary.gd b/addons/dialogic/Modules/Glossary/subsystem_glossary.gd
index 389069db9..d438bc4bc 100644
--- a/addons/dialogic/Modules/Glossary/subsystem_glossary.gd
+++ b/addons/dialogic/Modules/Glossary/subsystem_glossary.gd
@@ -10,6 +10,8 @@ var enabled := true
## Any key in this dictionary will overwrite the color for any item with that name.
var color_overrides := {}
+const SETTING_DEFAULT_COLOR := 'dialogic/glossary/default_color'
+
#region STATE
####################################################################################################
@@ -31,7 +33,7 @@ func parse_glossary(text: String) -> String:
return text
var def_case_sensitive: bool = ProjectSettings.get_setting('dialogic/glossary/default_case_sensitive', true)
- var def_color: Color = ProjectSettings.get_setting('dialogic/glossary/default_color', Color.POWDER_BLUE)
+ var def_color: Color = ProjectSettings.get_setting(SETTING_DEFAULT_COLOR, Color.POWDER_BLUE)
var regex := RegEx.new()
for glossary: DialogicGlossary in glossaries:
@@ -98,10 +100,6 @@ func add_glossary(path:String) -> void:
## Iterates over all glossaries and returns the first one that matches the
## [param entry_key].
##
-## Returns null if none of the glossaries has an entry with that key.
-## If translation is enabled, uses the [param entry_key] as well to check
-## [member _translation_keys].
-##
## Runtime complexity:
## O(n), where n is the number of glossaries.
func find_glossary(entry_key: String) -> DialogicGlossary:
@@ -110,7 +108,67 @@ func find_glossary(entry_key: String) -> DialogicGlossary:
if glossary.entries.has(entry_key):
return glossary
- if glossary.entries.has(entry_key):
- return glossary
-
return null
+
+
+## Returns the first match for a given entry key.
+## If translation is available and enabled, it will be translated
+func get_entry(entry_key: String) -> Dictionary:
+ var glossary: DialogicGlossary = dialogic.Glossary.find_glossary(entry_key)
+
+ var result := {
+ "title": "",
+ "text": "",
+ "extra": "",
+ "color": Color.WHITE,
+ }
+
+ if glossary == null:
+ return {}
+
+ var is_translation_enabled: bool = ProjectSettings.get_setting('dialogic/translation/enabled', false)
+
+ var entry := glossary.get_entry(entry_key)
+
+ if entry.is_empty():
+ return {}
+
+ result.color = entry.get("color")
+ if result.color == null:
+ result.color = ProjectSettings.get_setting(SETTING_DEFAULT_COLOR, Color.POWDER_BLUE)
+
+ if is_translation_enabled and not glossary._translation_id.is_empty():
+ var translation_key: String = glossary._translation_keys.get(entry_key)
+ var last_slash := translation_key.rfind('/')
+
+ if last_slash == -1:
+ return {}
+
+ var tr_base := translation_key.substr(0, last_slash)
+
+ result.title = translate(tr_base, "title", entry)
+ result.text = translate(tr_base, "text", entry)
+ result.extra = translate(tr_base, "extra", entry)
+ else:
+ result.title = entry.get("title", "")
+ result.text = entry.get("text", "")
+ result.extra = entry.get("extra", "")
+
+ ## PARSE TEXTS FOR VARIABLES
+ result.title = dialogic.VAR.parse_variables(result.title)
+ result.text = dialogic.VAR.parse_variables(result.text)
+ result.extra = dialogic.VAR.parse_variables(result.extra)
+
+ return result
+
+
+
+## Tries to translate the property with the given
+func translate(tr_base: String, property: StringName, fallback_entry: Dictionary) -> String:
+ var tr_key := tr_base.path_join(property)
+ var tr_value := tr(tr_key)
+
+ if tr_key == tr_value:
+ tr_value = fallback_entry.get(property, "")
+
+ return tr_value
diff --git a/addons/dialogic/Modules/HighlightPortrait/highlight_portrait_thumbnail.png b/addons/dialogic/Modules/HighlightPortrait/highlight_portrait_thumbnail.png
new file mode 100644
index 000000000..33a594c77
Binary files /dev/null and b/addons/dialogic/Modules/HighlightPortrait/highlight_portrait_thumbnail.png differ
diff --git a/addons/dialogic/Modules/HighlightPortrait/highlight_portrait_thumbnail.png.import b/addons/dialogic/Modules/HighlightPortrait/highlight_portrait_thumbnail.png.import
new file mode 100644
index 000000000..5efd4a71f
--- /dev/null
+++ b/addons/dialogic/Modules/HighlightPortrait/highlight_portrait_thumbnail.png.import
@@ -0,0 +1,34 @@
+[remap]
+
+importer="texture"
+type="CompressedTexture2D"
+uid="uid://dtt0l7qbkknfx"
+path="res://.godot/imported/highlight_portrait_thumbnail.png-6fa128edf7f6ec29e7a5313b9c3e7412.ctex"
+metadata={
+"vram_texture": false
+}
+
+[deps]
+
+source_file="res://addons/dialogic/Modules/HighlightPortrait/highlight_portrait_thumbnail.png"
+dest_files=["res://.godot/imported/highlight_portrait_thumbnail.png-6fa128edf7f6ec29e7a5313b9c3e7412.ctex"]
+
+[params]
+
+compress/mode=0
+compress/high_quality=false
+compress/lossy_quality=0.7
+compress/hdr_compression=1
+compress/normal_map=0
+compress/channel_pack=0
+mipmaps/generate=false
+mipmaps/limit=-1
+roughness/mode=0
+roughness/src_normal=""
+process/fix_alpha_border=true
+process/premult_alpha=false
+process/normal_map_invert_y=false
+process/hdr_as_srgb=false
+process/hdr_clamp_exposure=false
+process/size_limit=0
+detect_3d/compress_to=1
diff --git a/addons/dialogic/Modules/HighlightPortrait/index.gd b/addons/dialogic/Modules/HighlightPortrait/index.gd
new file mode 100644
index 000000000..ec9b31537
--- /dev/null
+++ b/addons/dialogic/Modules/HighlightPortrait/index.gd
@@ -0,0 +1,17 @@
+@tool
+extends DialogicIndexer
+
+
+func _get_portrait_scene_presets() -> Array[Dictionary]:
+ return [
+ {
+ "path": this_folder.path_join("simple_highlight_portrait.tscn"),
+ "name": "Simple Highlight Portrait",
+ "description": "A portrait scene that displays a simple image, but changes color and moves to the front when this character is speaking.",
+ "author":"Dialogic",
+ "type": "General",
+ "icon":"",
+ "preview_image":[this_folder.path_join("highlight_portrait_thumbnail.png")],
+ "documentation":"",
+ },
+ ]
diff --git a/addons/dialogic/Example Assets/portraits/simple_highlight_portrait.gd b/addons/dialogic/Modules/HighlightPortrait/simple_highlight_portrait.gd
similarity index 76%
rename from addons/dialogic/Example Assets/portraits/simple_highlight_portrait.gd
rename to addons/dialogic/Modules/HighlightPortrait/simple_highlight_portrait.gd
index 64aac03b4..5ed6649df 100644
--- a/addons/dialogic/Example Assets/portraits/simple_highlight_portrait.gd
+++ b/addons/dialogic/Modules/HighlightPortrait/simple_highlight_portrait.gd
@@ -2,10 +2,10 @@
extends DialogicPortrait
@export_group('Main')
-@export_file var image: String = ""
+@export_file var image := ""
var unhighlighted_color := Color.DARK_GRAY
-var prev_z_index := 0
+var _prev_z_index := 0
## Load anything related to the given character and portrait
func _update_portrait(passed_character:DialogicCharacter, passed_portrait:String) -> void:
@@ -19,12 +19,12 @@ func _ready() -> void:
self.modulate = unhighlighted_color
-func _highlight():
+func _highlight() -> void:
create_tween().tween_property(self, 'modulate', Color.WHITE, 0.15)
- prev_z_index = DialogicUtil.autoload().Portraits.get_character_info(character).get('z_index', 0)
+ _prev_z_index = DialogicUtil.autoload().Portraits.get_character_info(character).get('z_index', 0)
DialogicUtil.autoload().Portraits.change_character_z_index(character, 99)
-func _unhighlight():
+func _unhighlight() -> void:
create_tween().tween_property(self, 'modulate', unhighlighted_color, 0.15)
- DialogicUtil.autoload().Portraits.change_character_z_index(character, prev_z_index)
+ DialogicUtil.autoload().Portraits.change_character_z_index(character, _prev_z_index)
diff --git a/addons/dialogic/Example Assets/portraits/simple_highlight_portrait.tscn b/addons/dialogic/Modules/HighlightPortrait/simple_highlight_portrait.tscn
similarity index 61%
rename from addons/dialogic/Example Assets/portraits/simple_highlight_portrait.tscn
rename to addons/dialogic/Modules/HighlightPortrait/simple_highlight_portrait.tscn
index 44cb571c6..cf814ebb9 100644
--- a/addons/dialogic/Example Assets/portraits/simple_highlight_portrait.tscn
+++ b/addons/dialogic/Modules/HighlightPortrait/simple_highlight_portrait.tscn
@@ -1,6 +1,6 @@
[gd_scene load_steps=2 format=3 uid="uid://br18lgpga2y2v"]
-[ext_resource type="Script" path="res://addons/dialogic/Example Assets/portraits/simple_highlight_portrait.gd" id="1_ceqva"]
+[ext_resource type="Script" path="res://addons/dialogic/Modules/HighlightPortrait/simple_highlight_portrait.gd" id="1_ceqva"]
[node name="DefaultPortrait" type="Node2D"]
script = ExtResource("1_ceqva")
diff --git a/addons/dialogic/Modules/History/event_history.gd b/addons/dialogic/Modules/History/event_history.gd
index 0b0297d7c..180d7f095 100644
--- a/addons/dialogic/Modules/History/event_history.gd
+++ b/addons/dialogic/Modules/History/event_history.gd
@@ -57,7 +57,7 @@ func get_shortcode_parameters() -> Dictionary:
## EDITOR REPRESENTATION
################################################################################
-func build_event_editor():
+func build_event_editor() -> void:
add_header_edit('action', ValueType.FIXED_OPTIONS, {
'options': [
{
diff --git a/addons/dialogic/Modules/History/settings_history.gd b/addons/dialogic/Modules/History/settings_history.gd
index 756071201..97b5cd98b 100644
--- a/addons/dialogic/Modules/History/settings_history.gd
+++ b/addons/dialogic/Modules/History/settings_history.gd
@@ -8,7 +8,9 @@ func _get_priority() -> int:
func _ready() -> void:
%SimpleHistoryEnabled.toggled.connect(setting_toggled.bind('dialogic/history/simple_history_enabled'))
+ %SimpleHistorySave.toggled.connect(setting_toggled.bind('dialogic/history/simple_history_save'))
%FullHistoryEnabled.toggled.connect(setting_toggled.bind('dialogic/history/full_history_enabled'))
+ %FullHistorySave.toggled.connect(setting_toggled.bind('dialogic/history/full_history_save'))
%AlreadyReadHistoryEnabled.toggled.connect(setting_toggled.bind('dialogic/history/visited_event_history_enabled'))
%SaveOnAutoSaveToggle.toggled.connect(setting_toggled.bind('dialogic/history/save_on_autosave'))
%SaveOnSaveToggle.toggled.connect(setting_toggled.bind('dialogic/history/save_on_save'))
@@ -16,7 +18,9 @@ func _ready() -> void:
func _refresh() -> void:
%SimpleHistoryEnabled.button_pressed = ProjectSettings.get_setting('dialogic/history/simple_history_enabled', false)
+ %SimpleHistorySave.button_pressed = ProjectSettings.get_setting('dialogic/history/simple_history_save', false)
%FullHistoryEnabled.button_pressed = ProjectSettings.get_setting('dialogic/history/full_history_enabled', false)
+ %FullHistorySave.button_pressed = ProjectSettings.get_setting('dialogic/history/full_history_save', false)
%AlreadyReadHistoryEnabled.button_pressed = ProjectSettings.get_setting('dialogic/history/visited_event_history_enabled', false)
diff --git a/addons/dialogic/Modules/History/settings_history.tscn b/addons/dialogic/Modules/History/settings_history.tscn
index 7bf916d7e..ed55edb85 100644
--- a/addons/dialogic/Modules/History/settings_history.tscn
+++ b/addons/dialogic/Modules/History/settings_history.tscn
@@ -3,7 +3,7 @@
[ext_resource type="Script" path="res://addons/dialogic/Modules/History/settings_history.gd" id="1_hbhst"]
[ext_resource type="PackedScene" uid="uid://dbpkta2tjsqim" path="res://addons/dialogic/Editor/Common/hint_tooltip_icon.tscn" id="2_wefye"]
-[sub_resource type="Image" id="Image_3h4fk"]
+[sub_resource type="Image" id="Image_3clns"]
data = {
"data": PackedByteArray(255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 94, 94, 127, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 231, 255, 94, 94, 54, 255, 94, 94, 57, 255, 93, 93, 233, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 93, 93, 41, 255, 255, 255, 0, 255, 255, 255, 0, 255, 97, 97, 42, 255, 93, 93, 233, 255, 93, 93, 232, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 44, 255, 255, 255, 0, 255, 97, 97, 42, 255, 97, 97, 42, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 96, 96, 45, 255, 93, 93, 235, 255, 94, 94, 234, 255, 95, 95, 43, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 93, 93, 235, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 233, 255, 95, 95, 59, 255, 96, 96, 61, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 93, 93, 255, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0, 255, 255, 255, 0),
"format": "RGBA8",
@@ -12,8 +12,8 @@ data = {
"width": 16
}
-[sub_resource type="ImageTexture" id="ImageTexture_8li2l"]
-image = SubResource("Image_3h4fk")
+[sub_resource type="ImageTexture" id="ImageTexture_irr0a"]
+image = SubResource("Image_3clns")
[node name="History" type="PanelContainer"]
anchors_preset = 15
@@ -45,7 +45,7 @@ text = "Enabled"
layout_mode = 2
tooltip_text = "When enabled, some events (Text, Join, Leave, Choice) will store a log.
Also, the default layout will feature the log panel option."
-texture = SubResource("ImageTexture_8li2l")
+texture = SubResource("ImageTexture_irr0a")
hint_text = "When enabled, some events (Text, Join, Leave, Choice) will store a log.
Also, the default layout will feature the log panel option."
@@ -53,6 +53,23 @@ Also, the default layout will feature the log panel option."
unique_name_in_owner = true
layout_mode = 2
+[node name="HBoxContainer2" type="HBoxContainer" parent="HistoryOptions"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="HistoryOptions/HBoxContainer2"]
+layout_mode = 2
+text = "Save and Load"
+
+[node name="HintTooltip" parent="HistoryOptions/HBoxContainer2" instance=ExtResource("2_wefye")]
+layout_mode = 2
+tooltip_text = "When enabled, the simple history is included in the savegame."
+texture = SubResource("ImageTexture_irr0a")
+hint_text = "When enabled, the simple history is included in the savegame. Also, it is reset on Dialogic.clear(FULL_CLEAR)."
+
+[node name="SimpleHistorySave" type="CheckBox" parent="HistoryOptions/HBoxContainer2"]
+unique_name_in_owner = true
+layout_mode = 2
+
[node name="Title" type="Label" parent="HistoryOptions"]
layout_mode = 2
theme_type_variation = &"DialogicSettingsSection"
@@ -68,13 +85,30 @@ text = "Enabled"
[node name="HintTooltip" parent="HistoryOptions/HBoxContainer5" instance=ExtResource("2_wefye")]
layout_mode = 2
tooltip_text = "When enabled, stores a copy of each event."
-texture = SubResource("ImageTexture_8li2l")
+texture = SubResource("ImageTexture_irr0a")
hint_text = "When enabled, stores a copy of each event."
[node name="FullHistoryEnabled" type="CheckBox" parent="HistoryOptions/HBoxContainer5"]
unique_name_in_owner = true
layout_mode = 2
+[node name="HBoxContainer6" type="HBoxContainer" parent="HistoryOptions"]
+layout_mode = 2
+
+[node name="Label" type="Label" parent="HistoryOptions/HBoxContainer6"]
+layout_mode = 2
+text = "Save and Load"
+
+[node name="HintTooltip" parent="HistoryOptions/HBoxContainer6" instance=ExtResource("2_wefye")]
+layout_mode = 2
+tooltip_text = "When enabled, the full history is included in the savegame."
+texture = SubResource("ImageTexture_irr0a")
+hint_text = "When enabled, the full history is included in the savegame. Also, it is reset on Dialogic.clear(FULL_CLEAR)."
+
+[node name="FullHistorySave" type="CheckBox" parent="HistoryOptions/HBoxContainer6"]
+unique_name_in_owner = true
+layout_mode = 2
+
[node name="Title2" type="Label" parent="HistoryOptions"]
layout_mode = 2
theme_type_variation = &"DialogicSettingsSection"
@@ -92,7 +126,7 @@ layout_mode = 2
tooltip_text = "Remembers whether events were already met in the timeline.
When enabled the signals \"Dialogic.History.visited_event\" and \"Dialogic.History.unvisited_event\" are emitted.
"
-texture = SubResource("ImageTexture_8li2l")
+texture = SubResource("ImageTexture_irr0a")
hint_text = "Remembers whether events were already met in the timeline.
When enabled the signals \"Dialogic.History.visited_event\" and \"Dialogic.History.unvisited_event\" are emitted.
"
@@ -112,7 +146,7 @@ text = "Save on Auto-Save signal"
layout_mode = 2
tooltip_text = "Stores the already-visited history in a global save file when an Auto-Save occurs.
The Auto-Save is part of the Save settings."
-texture = SubResource("ImageTexture_8li2l")
+texture = SubResource("ImageTexture_irr0a")
hint_text = "Stores the already-visited history in a global save file when an Auto-Save occurs.
The Auto-Save is part of the Save settings."
@@ -132,7 +166,7 @@ layout_mode = 2
tooltip_text = "Stores the already-visited history in a global save file when a normal Save occurs.
This can be done via the Dialogic.Save.save method.
This setting ignores Auto-Saves."
-texture = SubResource("ImageTexture_8li2l")
+texture = SubResource("ImageTexture_irr0a")
hint_text = "Stores the already-visited history in a global save file when a normal Save occurs.
This can be done via the Dialogic.Save.save method.
This setting ignores Auto-Saves."
diff --git a/addons/dialogic/Modules/History/subsystem_history.gd b/addons/dialogic/Modules/History/subsystem_history.gd
index 01f910fb0..d1371ea4c 100644
--- a/addons/dialogic/Modules/History/subsystem_history.gd
+++ b/addons/dialogic/Modules/History/subsystem_history.gd
@@ -8,16 +8,18 @@ signal close_requested
## Simple history that stores limited information
## Used for the history display
-var simple_history_enabled := true
+var simple_history_enabled := false
+var simple_history_save := false
var simple_history_content : Array[Dictionary] = []
signal simple_history_changed
## Whether to keep a history of every Dialogic event encountered.
var full_event_history_enabled := false
+var full_event_history_save := false
## The full history of all Dialogic events encountered.
## Requires [member full_event_history_enabled] to be true.
-var full_event_history_content := []
+var full_event_history_content: Array[DialogicEvent] = []
## Emitted if a new event has been inserted into the full event history.
signal full_event_history_changed
@@ -63,12 +65,10 @@ var save_visited_history_on_save := false:
## Starts and stops the connection to the [subsystem Save] subsystem's [signal saved] signal.
func _update_saved_connection(to_connect: bool) -> void:
if to_connect:
-
if not DialogicUtil.autoload().Save.saved.is_connected(_on_save):
- var _result := DialogicUtil.autoload().Save.saved.connect(_on_save)
+ DialogicUtil.autoload().Save.saved.connect(_on_save)
else:
-
if DialogicUtil.autoload().Save.saved.is_connected(_on_save):
DialogicUtil.autoload().Save.saved.disconnect(_on_save)
@@ -77,11 +77,13 @@ func _update_saved_connection(to_connect: bool) -> void:
####################################################################################################
func _ready() -> void:
- var _result := dialogic.event_handled.connect(store_full_event)
- _result = dialogic.event_handled.connect(_check_seen)
+ dialogic.event_handled.connect(store_full_event)
+ dialogic.event_handled.connect(_check_seen)
- simple_history_enabled = ProjectSettings.get_setting('dialogic/history/simple_history_enabled', simple_history_enabled )
+ simple_history_enabled = ProjectSettings.get_setting('dialogic/history/simple_history_enabled', simple_history_enabled)
+ simple_history_save = ProjectSettings.get_setting('dialogic/history/simple_history_save', simple_history_save)
full_event_history_enabled = ProjectSettings.get_setting('dialogic/history/full_history_enabled', full_event_history_enabled)
+ full_event_history_save = ProjectSettings.get_setting('dialogic/history/full_history_save', full_event_history_save)
visited_event_history_enabled = ProjectSettings.get_setting('dialogic/history/visited_event_history_enabled', visited_event_history_enabled)
@@ -101,6 +103,47 @@ func post_install() -> void:
save_visited_history_on_save = ProjectSettings.get_setting('dialogic/history/save_on_save', save_visited_history_on_save)
+func clear_game_state(clear_flag := DialogicGameHandler.ClearFlags.FULL_CLEAR) -> void:
+ if clear_flag == DialogicGameHandler.ClearFlags.FULL_CLEAR:
+ if simple_history_save:
+ simple_history_content = []
+ dialogic.current_state_info.erase("history_simple")
+ if full_event_history_save:
+ full_event_history_content = []
+ dialogic.current_state_info.erase("history_full")
+
+
+func load_game_state(load_flag := LoadFlags.FULL_LOAD) -> void:
+ if load_flag == LoadFlags.FULL_LOAD:
+ if simple_history_save and dialogic.current_state_info.has("history_simple"):
+ simple_history_content.assign(dialogic.current_state_info["history_simple"])
+
+ if full_event_history_save and dialogic.current_state_info.has("history_full"):
+ full_event_history_content = []
+
+ for event_text in dialogic.current_state_info["history_full"]:
+ var event: DialogicEvent
+ for i in DialogicResourceUtil.get_event_cache():
+ if i.is_valid_event(event_text):
+ event = i.duplicate()
+ break
+ event.from_text(event_text)
+ full_event_history_content.append(event)
+
+
+func save_game_state() -> void:
+ if simple_history_save:
+ dialogic.current_state_info["history_simple"] = Array(simple_history_content)
+ else:
+ dialogic.current_state_info.erase("history_simple")
+ if full_event_history_save:
+ dialogic.current_state_info["history_full"] = []
+ for event in full_event_history_content:
+ dialogic.current_state_info["history_full"].append(event.to_text())
+ else:
+ dialogic.current_state_info.erase("history_full")
+
+
func open_history() -> void:
open_requested.emit()
@@ -161,16 +204,17 @@ func _get_event_key(event_index: int, timeline_path: String) -> String:
return event_key
-# Called if a Text event marks an unvisited Text event as visited.
-func mark_event_as_visited(_event: DialogicEvent) -> void:
+## Called if an event is marked as visited.
+func mark_event_as_visited(event_index := dialogic.current_event_idx, timeline := dialogic.current_timeline) -> void:
if !visited_event_history_enabled:
return
- var event_key := _current_event_key()
+ var event_key := _get_event_key(event_index, timeline.resource_path)
+
+ visited_event_history_content[event_key] = event_index
- visited_event_history_content[event_key] = dialogic.current_event_idx
-# Called on each event, but we filter for Text events.
+## Called on each event, but we filter for Text events.
func _check_seen(event: DialogicEvent) -> void:
if !visited_event_history_enabled:
return
diff --git a/addons/dialogic/Modules/Jump/event_jump.gd b/addons/dialogic/Modules/Jump/event_jump.gd
index 1760147b0..050dfa9a4 100644
--- a/addons/dialogic/Modules/Jump/event_jump.gd
+++ b/addons/dialogic/Modules/Jump/event_jump.gd
@@ -8,15 +8,15 @@ extends DialogicEvent
### Settings
## The timeline to jump to, if null then it's the current one. This setting should be a dialogic timeline resource.
-var timeline : DialogicTimeline
+var timeline: DialogicTimeline
## If not empty, the event will try to find a Label event with this set as name. Empty by default..
-var label_name : String = ""
+var label_name := ""
### Helpers
## Used to set the timeline resource from the unique name identifier and vice versa
-var timeline_identifier: String = "":
+var timeline_identifier := "":
get:
if timeline:
var identifier := DialogicResourceUtil.get_unique_identifier(timeline.resource_path)
@@ -75,7 +75,7 @@ func to_text() -> String:
func from_text(string:String) -> void:
- var result := RegEx.create_from_string('jump (?.*\\/)?(?