diff --git a/src/Classes/Layers/BaseLayer.gd b/src/Classes/Layers/BaseLayer.gd index 5ae80e9ed..e642ade74 100644 --- a/src/Classes/Layers/BaseLayer.gd +++ b/src/Classes/Layers/BaseLayer.gd @@ -6,6 +6,7 @@ extends RefCounted signal name_changed ## Emits when [member name] is changed. signal visibility_changed ## Emits when [member visible] is changed. signal effects_added_removed ## Emits when an effect is added or removed to/from [member effects]. +signal ui_color_changed ## Emits when [member ui_color] is changed. ## All currently supported layer blend modes between two layers. The upper layer ## is the blend layer, and the bottom layer is the base layer. @@ -13,7 +14,7 @@ signal effects_added_removed ## Emits when an effect is added or removed to/fro enum BlendModes { PASS_THROUGH = -2, ## Only for group layers. Ignores group blending, like it doesn't exist. NORMAL = 0, ## The blend layer colors are simply placed on top of the base colors. - ERASE, ## Subtracts the numerical value of alpha from the base alpha. + ERASE, ## Erases the non-transparent areas of the upper layer from the lower layer's alpha. DARKEN, ## Keeps the darker colors between the blend and the base layers. MULTIPLY, ## Multiplies the numerical values of the two colors, giving a darker result. COLOR_BURN, ## Darkens by increasing the contrast between the blend and base colors. @@ -55,6 +56,11 @@ var cel_link_sets: Array[Dictionary] = [] ## Each Dictionary represents a cel's var effects: Array[LayerEffect] ## An array for non-destructive effects of the layer. var effects_enabled := true ## If [code]true[/code], the effects are being applied. var user_data := "" ## User defined data, set in the layer properties. +## The color of the layer's button in the timeline. By default, it's the theme button color. +var ui_color := Color(0, 0, 0, 0): + set(value): + ui_color = value + ui_color_changed.emit() ## Returns true if this is a direct or indirect parent of layer @@ -236,8 +242,9 @@ func display_effects(cel: BaseCel, image_override: Image = null) -> Image: if not effect.enabled or not is_instance_valid(effect.shader): continue var params := effect.params - params["PXO_time"] = cel.get_frame(project).position_in_seconds(project) - params["PXO_frame_index"] = project.frames.find(cel.get_frame(project)) + var frame := cel.get_frame(project) + params["PXO_time"] = frame.position_in_seconds(project) + params["PXO_frame_index"] = project.frames.find(frame) params["PXO_layer_index"] = index var shader_image_effect := ShaderImageEffect.new() shader_image_effect.generate_image(image, effect.shader, params, image_size) @@ -259,6 +266,17 @@ func emit_effects_added_removed() -> void: effects_added_removed.emit() +## Returns the final color of the layer button, +## iterating through the layer's ancestors, if it has any. +## If the layer has no UI color, it inherits from its parents, otherwise it overwrites it. +func get_ui_color() -> Color: + if not is_zero_approx(ui_color.a): + return ui_color + for ancestor in get_ancestors(): + return ancestor.get_ui_color() + return ui_color + + # Methods to Override: @@ -275,6 +293,7 @@ func serialize() -> Dictionary: "blend_mode": blend_mode, "clipping_mask": clipping_mask, "opacity": opacity, + "ui_color": ui_color, "parent": parent.index if is_instance_valid(parent) else -1, "effects": effect_data } @@ -301,6 +320,7 @@ func deserialize(dict: Dictionary) -> void: clipping_mask = dict.get("clipping_mask", false) opacity = dict.get("opacity", 1.0) user_data = dict.get("user_data", user_data) + ui_color = str_to_var("Color" + dict.get("ui_color", "(0, 0, 0, 0)")) if dict.get("parent", -1) != -1: parent = project.layers[dict.parent] if dict.has("linked_cels") and not dict["linked_cels"].is_empty(): # Backwards compatibility diff --git a/src/UI/Timeline/LayerButton.gd b/src/UI/Timeline/LayerButton.gd index 7afdf65ad..195e2ec69 100644 --- a/src/UI/Timeline/LayerButton.gd +++ b/src/UI/Timeline/LayerButton.gd @@ -35,6 +35,7 @@ var audio_player: AudioStreamPlayer @onready var hierarchy_spacer := %HierarchySpacer as Control @onready var layer_fx_texture_rect := %LayerFXTextureRect as TextureRect @onready var layer_type_texture_rect := %LayerTypeTextureRect as TextureRect +@onready var layer_ui_color := $LayerMainButton/LayerUIColor as ColorRect @onready var linked_button := %LinkButton as BaseButton @onready var clipping_mask_icon := %ClippingMask as TextureRect @onready var popup_menu := $PopupMenu as PopupMenu @@ -47,6 +48,9 @@ func _ready() -> void: var layer := Global.current_project.layers[layer_index] layer.name_changed.connect(func(): label.text = layer.name) layer.visibility_changed.connect(_on_layer_visibility_changed) + layer.ui_color_changed.connect(func(): layer_ui_color.color = layer.get_ui_color()) + for ancestor in layer.get_ancestors(): + ancestor.ui_color_changed.connect(func(): layer_ui_color.color = layer.get_ui_color()) if layer is PixelLayer: linked_button.visible = true elif layer is GroupLayer: @@ -62,6 +66,7 @@ func _ready() -> void: custom_minimum_size.y = Global.animation_timeline.cel_size label.text = layer.name line_edit.text = layer.name + layer_ui_color.color = layer.get_ui_color() layer_fx_texture_rect.visible = layer.effects.size() > 0 layer_type_texture_rect.texture = ARRAY_TEXTURE_TYPES[layer.get_layer_type()] layer.effects_added_removed.connect( diff --git a/src/UI/Timeline/LayerButton.tscn b/src/UI/Timeline/LayerButton.tscn index bac0ea281..1846827c8 100644 --- a/src/UI/Timeline/LayerButton.tscn +++ b/src/UI/Timeline/LayerButton.tscn @@ -127,6 +127,16 @@ theme_type_variation = &"LayerFrameButton" toggle_mode = true script = ExtResource("6_n8q6b") +[node name="LayerUIColor" type="ColorRect" parent="LayerMainButton"] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +mouse_filter = 2 +color = Color(0, 0, 0, 0) + [node name="LayerName" type="HBoxContainer" parent="LayerMainButton"] layout_mode = 1 anchors_preset = 15 diff --git a/src/UI/Timeline/LayerProperties.gd b/src/UI/Timeline/LayerProperties.gd index 028213732..2c83e900a 100644 --- a/src/UI/Timeline/LayerProperties.gd +++ b/src/UI/Timeline/LayerProperties.gd @@ -10,6 +10,7 @@ var layer_indices: PackedInt32Array @onready var blend_modes_button := $GridContainer/BlendModeOptionButton as OptionButton @onready var play_at_frame_slider := $GridContainer/PlayAtFrameSlider as ValueSlider @onready var user_data_text_edit := $GridContainer/UserDataTextEdit as TextEdit +@onready var ui_color_picker_button := $GridContainer/UIColorPickerButton as ColorPickerButton @onready var tileset_option_button := $GridContainer/TilesetOptionButton as OptionButton @onready var audio_file_dialog := $AudioFileDialog as FileDialog @@ -34,6 +35,7 @@ func _on_visibility_changed() -> void: play_at_frame_slider.value = first_layer.playback_frame + 1 play_at_frame_slider.max_value = project.frames.size() user_data_text_edit.text = first_layer.user_data + ui_color_picker_button.color = first_layer.ui_color get_tree().set_group(&"VisualLayers", "visible", first_layer is not AudioLayer) get_tree().set_group(&"TilemapLayers", "visible", first_layer is LayerTileMap) get_tree().set_group(&"AudioLayers", "visible", first_layer is AudioLayer) @@ -130,6 +132,12 @@ func _on_user_data_text_edit_text_changed() -> void: layer.user_data = user_data_text_edit.text +func _on_ui_color_picker_button_color_changed(color: Color) -> void: + for layer_index in layer_indices: + var layer := Global.current_project.layers[layer_index] + layer.ui_color = color + + func _emit_layer_property_signal() -> void: layer_property_changed.emit() diff --git a/src/UI/Timeline/LayerProperties.tscn b/src/UI/Timeline/LayerProperties.tscn index cfa93601c..1b1682e88 100644 --- a/src/UI/Timeline/LayerProperties.tscn +++ b/src/UI/Timeline/LayerProperties.tscn @@ -6,14 +6,14 @@ [node name="LayerProperties" type="AcceptDialog"] title = "Layer properties" position = Vector2i(0, 36) -size = Vector2i(300, 270) +size = Vector2i(425, 300) script = ExtResource("1_54q1t") [node name="GridContainer" type="GridContainer" parent="."] offset_left = 8.0 offset_top = 8.0 -offset_right = 292.0 -offset_bottom = 221.0 +offset_right = 417.0 +offset_bottom = 251.0 columns = 2 [node name="NameLabel" type="Label" parent="GridContainer"] @@ -81,6 +81,16 @@ stretch_margin_right = 3 stretch_margin_bottom = 3 script = ExtResource("2_bwpwc") +[node name="TilesetLabel" type="Label" parent="GridContainer" groups=["TilemapLayers"]] +layout_mode = 2 +size_flags_horizontal = 3 +size_flags_vertical = 0 +text = "Tileset:" + +[node name="TilesetOptionButton" type="OptionButton" parent="GridContainer" groups=["TilemapLayers"]] +layout_mode = 2 +mouse_default_cursor_shape = 2 + [node name="UserDataLabel" type="Label" parent="GridContainer"] layout_mode = 2 size_flags_horizontal = 3 @@ -92,13 +102,13 @@ layout_mode = 2 size_flags_horizontal = 3 scroll_fit_content_height = true -[node name="TilesetLabel" type="Label" parent="GridContainer" groups=["TilemapLayers"]] +[node name="UIColorLabel" type="Label" parent="GridContainer"] layout_mode = 2 size_flags_horizontal = 3 size_flags_vertical = 0 -text = "Tileset:" +text = "Color:" -[node name="TilesetOptionButton" type="OptionButton" parent="GridContainer" groups=["TilemapLayers"]] +[node name="UIColorPickerButton" type="ColorPickerButton" parent="GridContainer"] layout_mode = 2 mouse_default_cursor_shape = 2 @@ -117,6 +127,7 @@ filters = PackedStringArray("*.mp3 ; MP3 Audio") [connection signal="item_selected" from="GridContainer/BlendModeOptionButton" to="." method="_on_blend_mode_option_button_item_selected"] [connection signal="pressed" from="GridContainer/AudioFileButton" to="." method="_on_audio_file_button_pressed"] [connection signal="value_changed" from="GridContainer/PlayAtFrameSlider" to="." method="_on_play_at_frame_slider_value_changed"] -[connection signal="text_changed" from="GridContainer/UserDataTextEdit" to="." method="_on_user_data_text_edit_text_changed"] [connection signal="item_selected" from="GridContainer/TilesetOptionButton" to="." method="_on_tileset_option_button_item_selected"] +[connection signal="text_changed" from="GridContainer/UserDataTextEdit" to="." method="_on_user_data_text_edit_text_changed"] +[connection signal="color_changed" from="GridContainer/UIColorPickerButton" to="." method="_on_ui_color_picker_button_color_changed"] [connection signal="file_selected" from="AudioFileDialog" to="." method="_on_audio_file_dialog_file_selected"]