@tool extends Resource class_name DialogicStyle ## A style represents a collection of layers and settings. ## A style can inherit from another style. @export var name := "Style": get: if name.is_empty(): return "Unkown Style" return name @export var inherits: DialogicStyle = null @export var base_scene: PackedScene = null @export var base_overrides := {} @export var layers: Array[DialogicStyleLayer] = [] func _init(_name:="") -> void: if not _name.is_empty(): name = _name ## This always returns the inheritance root's scene! func get_base_scene() -> PackedScene: if base_scene == null: return DialogicUtil.get_default_layout_base() return get_inheritance_root().base_scene ## This always returns the full inherited roots layers! func get_layer_list() -> PackedStringArray: return PackedStringArray(get_inheritance_root().layers.map(func(x:DialogicStyleLayer): return x.scene.resource_path)) func get_layer_count() -> int: return layers.size() func get_layer_info(index:int) -> Dictionary: if index == -1: return {'path':get_base_scene().resource_path, 'overrides':base_overrides.duplicate()} if index < layers.size(): if layers[index].scene != null: return {'path':layers[index].scene.resource_path, 'overrides':layers[index].overrides.duplicate()} else: return {'path':'', 'overrides':layers[index].overrides.duplicate()} return {'path':'', 'overrides':{}} func get_layer_inherited_info(index:int, inherited_only:=false) -> Dictionary: var style := self var info := {'path':'', 'overrides':{}} if not inherited_only: info = get_layer_info(index) while style.inherits != null: style = style.inherits info = merge_layer_infos(info, style.get_layer_info(index)) return info func add_layer(scene:String, overrides:Dictionary = {}) -> void: layers.append(DialogicStyleLayer.new(scene, overrides)) changed.emit() func delete_layer(layer_index:int) -> void: if not has_layer(layer_index): return layers.remove_at(layer_index) changed.emit() func move_layer(from_index:int, to_index:int) -> void: if not has_layer(from_index) or not has_layer(to_index-1): return var info: Resource = layers.pop_at(from_index) layers.insert(to_index, info) changed.emit() func set_layer_scene(layer_index:int, scene:String) -> void: if not has_layer(layer_index): return if layer_index == -1: base_scene = load(scene) else: layers[layer_index].scene = load(scene) changed.emit() func set_layer_setting(layer:int, setting:String, value:Variant) -> void: if not has_layer(layer): return if layer == -1: base_overrides[setting] = value else: layers[layer].overrides[setting] = value changed.emit() func remove_layer_setting(layer:int, setting:String) -> void: if not has_layer(layer): return if layer == -1: base_overrides.erase(setting) else: layers[layer].overrides.erase(setting) changed.emit() ## This merges two layers (mainly their overrides). Layer a has priority! func merge_layer_infos(layer_a:Dictionary, layer_b:Dictionary) -> Dictionary: var combined := layer_a.duplicate(true) combined.path = layer_b.path combined.overrides.merge(layer_b.overrides) return combined func has_layer(index:int) -> bool: return index < layers.size() func inherits_anything() -> bool: return inherits != null func get_inheritance_root() -> DialogicStyle: if inherits == null: return self var style: DialogicStyle = self while style.inherits != null: style = style.inherits return style func realize_inheritance() -> void: base_scene = get_base_scene() base_overrides = get_layer_inherited_info(-1) var _layers: Array[DialogicStyleLayer] = [] for i in range(get_layer_count()): var info := get_layer_inherited_info(i) _layers.append(DialogicStyleLayer.new(info.get("path", ""), info.get("overrides", {}))) layers = _layers inherits = null changed.emit() func clone() -> DialogicStyle: var style := DialogicStyle.new() style.name = name if base_scene != null: style.base_scene = base_scene style.inherits = inherits style.base_overrides = base_overrides for layer_idx in range(get_layer_count()): var info := get_layer_info(layer_idx) style.add_layer(info.path, info.overrides) return style func prepare() -> void: if base_scene: ResourceLoader.load_threaded_request(base_scene.resource_path) for layer in layers: if layer.scene: ResourceLoader.load_threaded_request(layer.scene.resource_path)