diff --git a/addons/flexible_layout/flexible_dragger.gd b/addons/flexible_layout/flexible_dragger.gd new file mode 100644 index 000000000..fdd48eff7 --- /dev/null +++ b/addons/flexible_layout/flexible_dragger.gd @@ -0,0 +1,31 @@ +extends Control + + +var dragging : bool = false +var flex_split +var dragger_index : int +var vertical : bool + +func _init(): + set_meta("flexlayout", true) + +func _draw(): + draw_rect(Rect2(Vector2(0, 0), size), Color(1, 1, 0)) + +func set_split(s, i : int, v : bool): + flex_split = s + dragger_index = i + vertical = v + +func _on_gui_input(event): + if event is InputEventMouseButton: + if event.button_index == MOUSE_BUTTON_LEFT: + dragging = event.pressed + elif event is InputEventMouseMotion: + if dragging: + if vertical: + position.y += event.position.y-5 + flex_split.drag(dragger_index, position.y) + else: + position.x += event.position.x-5 + flex_split.drag(dragger_index, position.x) diff --git a/addons/flexible_layout/flexible_dragger.tscn b/addons/flexible_layout/flexible_dragger.tscn new file mode 100644 index 000000000..988f7a91e --- /dev/null +++ b/addons/flexible_layout/flexible_dragger.tscn @@ -0,0 +1,15 @@ +[gd_scene load_steps=2 format=3 uid="uid://cucx3oayvvxhu"] + +[ext_resource type="Script" path="res://addons/flexible_layout/flexible_dragger.gd" id="1_3i5mx"] + +[node name="Dragger" type="Control"] +custom_minimum_size = Vector2(10, 10) +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_3i5mx") + +[connection signal="gui_input" from="." to="." method="_on_gui_input"] diff --git a/addons/flexible_layout/flexible_layout.gd b/addons/flexible_layout/flexible_layout.gd new file mode 100644 index 000000000..6f44b4cd8 --- /dev/null +++ b/addons/flexible_layout/flexible_layout.gd @@ -0,0 +1,405 @@ +extends Control + + +class FlexPanel: + var name : String + var widget : Control + + +class FlexNode: + var type : String + var parent : FlexNode = null + var flexible_layout : Control + var rect : Rect2 = Rect2(0, 0, 1000, 1000) + + func _init(p : FlexNode = null,fl : Control = null): + type = "FlexNode" + parent = p + flexible_layout = fl + + func _notification(what): + if what == NOTIFICATION_PREDELETE: + print("removing %s!" % type) + + func get_children() -> Array[FlexNode]: + return [] + + func get_flexnode_at(p : Vector2) -> FlexNode: + if rect.has_point(p): + for c in get_children(): + var rv : FlexNode = c.get_flexnode_at(p) + if rv != null: + return rv + return self + else: + return null + + func replace(fn : FlexNode, new_fn : FlexNode) -> bool: + return false + + +class PanelInfo: + var flex_node : FlexNode + var flex_panel : FlexPanel + + func _init(fn : FlexNode, fp : FlexPanel): + flex_node = fn + flex_panel = fp + flex_node.flexible_layout.start_drag() + + func _notification(what): + if what == NOTIFICATION_PREDELETE: + print("Goodbye!") + flex_node.flexible_layout.end_drag() + + +class FlexTop: + extends FlexNode + var control : Control + var child : FlexNode = null + + func _init(fl : Control, c : Control = null): + type = "FlexTop" + control = c if c else fl + parent = null + flexible_layout = fl + + func get_children() -> Array[FlexNode]: + if child: + return [ child ] + return [] + + func set_child(fn : FlexNode): + child = fn + + func replace(fn : FlexNode, new_fn : FlexNode) -> bool: + if fn != child: + return false + if new_fn: + child = new_fn + new_fn.parent = self + else: + child = null + return true + + func layout(r : Rect2): + rect = r + if child: + child.layout(r) + + +class FlexSplit: + extends FlexNode + var vertical : bool = false + var children : Array[FlexNode] = [] + var draggers : Array[Control] = [] + + const DRAGGER_SCENE = preload("res://addons/flexible_layout/flexible_dragger.tscn") + + func _init(p : FlexNode, fl : Control): + super._init(p, fl) + type = "FlexSplit" + + func get_children() -> Array[FlexNode]: + return children + + func find(fn : FlexNode) -> int: + return children.find(fn) + + func insert(fn : FlexNode, index : int = -1, ref_index : int = -1): + if index == -1: + index = children.size() + if ref_index != -1: + var ref : FlexNode = children[ref_index] + if vertical: + ref.rect.size.y /= 2 + else: + ref.rect.size.x /= 2 + fn.rect = ref.rect + children.insert(index, fn) + fn.parent = self + + func replace(fn : FlexNode, new_fn : FlexNode) -> bool: + var index : int = children.find(fn) + if index == -1: + print("Error replacing FlexNode") + return false + children.remove_at(index) + if new_fn: + new_fn.rect = fn.rect + children.insert(index, new_fn) + new_fn.parent = self + if children.size() == 1: + parent.replace(self, children[0]) + children.remove_at(0) + for d in draggers: + d.queue_free() + return true + + func layout(r : Rect2): + print("Layout FlexSplit (%d children) - %s" % [ children.size(), str(r) ]) + var grip_size : int = 10 + rect = r + var children_count : int = children.size() + var draggers_count : int = draggers.size() + if draggers_count < children_count-1: + for i in children_count-1-draggers_count: + print("Creating dragger") + var dragger = DRAGGER_SCENE.instantiate() + draggers.append(dragger) + flexible_layout.add_child(dragger) + elif draggers_count > children_count-1: + while draggers.size() > children_count-1: + draggers.pop_back().queue_free() + if vertical: + var total_y_size = rect.size.y-(children_count-1)*grip_size + var y : int = r.position.y + var dragger_index : int = -1 + var old_height : int = 0 + var new_height : int = rect.size.y-grip_size*(children_count-1) + for c in children: + old_height += c.rect.size.y + for c in children: + if dragger_index >= 0: + draggers[dragger_index].position = Vector2(r.position.x, y) + draggers[dragger_index].size = Vector2(r.size.x, grip_size) + draggers[dragger_index].set_split(self, dragger_index, vertical) + y += grip_size + dragger_index += 1 + var height : int = c.rect.size.y*new_height/old_height + c.layout(Rect2(r.position.x, y, r.size.x, height)) + y += height + else: + var total_x_size = rect.size.x-(children_count-1)*grip_size + var x: int = r.position.x + var dragger_index : int = -1 + var old_width : int = 0 + var new_width : int = rect.size.x-grip_size*(children_count-1) + for c in children: + old_width += c.rect.size.x + for c in children: + if dragger_index >= 0: + draggers[dragger_index].position = Vector2(x, r.position.y) + draggers[dragger_index].size = Vector2(grip_size, r.size.y) + draggers[dragger_index].set_split(self, dragger_index, vertical) + x += grip_size + dragger_index += 1 + var width : int = (c.rect.size.x*new_width+(old_width>>1))/old_width + c.layout(Rect2(x, r.position.y, width, r.size.y)) + x += width + + func drag(dragger_index : int, p : int): + var c1 = children[dragger_index] + var c2 = children[dragger_index+1] + if vertical: + c1.layout(Rect2(c1.rect.position, Vector2(c1.rect.size.x, p-c1.rect.position.y))) + c2.layout(Rect2(c2.rect.position.x, p+10, c1.rect.size.x, c2.rect.position.y+c2.rect.size.y-(p+10))) + else: + c1.layout(Rect2(c1.rect.position, Vector2(p-c1.rect.position.x, c1.rect.size.y))) + c2.layout(Rect2(p+10, c2.rect.position.y, c2.rect.position.x+c2.rect.size.x-(p+10), c1.rect.size.y)) + + +class FlexTab: + extends FlexNode + var children : Array[FlexPanel] = [] + var tabs : Control + + const TAB_SCENE = preload("res://addons/flexible_layout/flexible_tabs.tscn") + + func _init(p : FlexNode, fl : Control): + super._init(p, fl) + type = "FlexTab" + assert(flexible_layout != null) + tabs = TAB_SCENE.instantiate() + flexible_layout.add_child(tabs) + tabs.set_flex_tab(self) + + func add(fp : FlexPanel): + children.push_back(fp) + tabs.add(fp) + if fp.widget.get_parent() != flexible_layout: + flexible_layout.add_child(fp.widget) + + func remove(fp : FlexPanel): + children.erase(fp) + tabs.erase(fp) + if children.is_empty(): + tabs.queue_free() + parent.replace(self, null) + + func set_current(fp : FlexPanel): + tabs.set_current(tabs.controls.find(fp)) + + func layout(r : Rect2): + print("Layout FlexTab - "+str(r)) + rect = r + tabs.position = rect.position + tabs.size = Vector2i(rect.size.x, 0) + var tabs_height : int = tabs.get_combined_minimum_size().y + for c in children: + c.widget.position = rect.position+Vector2(0, tabs.get_combined_minimum_size().y) + c.widget.size = rect.size-Vector2(0, tabs.get_combined_minimum_size().y) + + +class FlexMain: + extends FlexNode + var child : FlexPanel = null + + func _init(p : FlexNode = null, fl : Control = null): + super._init(p, fl) + type = "FlexMain" + + func add(fp : FlexPanel): + assert(child == null) + child = fp + if fp.widget.get_parent() != flexible_layout: + flexible_layout.add_child(fp.widget) + + func layout(r : Rect2): + print("Layout FlexNode - "+str(r)) + rect = r + child.widget.position = rect.position + child.widget.size = rect.size + + +class FlexWindow: + extends Window + + +var top : FlexTop = null +var unassigned : Array = [] + +var overlay : Control + + +const OVERLAY_SCENE = preload("res://addons/flexible_layout/flexible_overlay.tscn") + + +func _ready(): + var children = get_children() + for c in children: + if c.visible and ! c.has_meta("flexlayout"): + add(c.name, c) + await get_tree().process_frame + layout() + +func get_flexmain(p : FlexNode = top) -> FlexMain: + for c in p.get_children(): + if c is FlexTab: + return c + for c in p.get_children(): + var rv : FlexMain = get_flexmain(c) + if rv != null: + return rv + var main : FlexMain = FlexMain.new(top, top.flexible_layout) + if top.child == null: + top.set_child(main) + else: + if not top.child is FlexSplit: + var flex_split : FlexSplit = FlexSplit.new(top, top.flexible_layout) + flex_split.rect = top.child.rect + flex_split.insert(top.child) + top.set_child(flex_split) + top.child.insert(main) + return main + +func get_default_flextab(p : FlexNode = top) -> FlexTab: + for c in p.get_children(): + if c is FlexTab: + return c + for c in p.get_children(): + var rv : FlexTab = get_default_flextab(c) + if rv != null: + return rv + var tab : FlexTab = FlexTab.new(top, top.flexible_layout) + if top.child == null: + top.set_child(tab) + else: + if not top.child is FlexSplit: + var flex_split : FlexSplit = FlexSplit.new(top, top.flexible_layout) + flex_split.rect = top.child.rect + flex_split.insert(top.child) + top.set_child(flex_split) + top.child.insert(tab) + return tab + +func layout(): + var default_flextab : FlexTab = null + print("layout") + if top == null: + print("creating top") + top = FlexTop.new(self) + for fp in unassigned: + if fp.name == "Main": + get_flexmain().add(fp) + else: + if default_flextab == null: + default_flextab = get_default_flextab() + default_flextab.add(fp) + unassigned = [] + top.layout(get_rect()) + print("done") + +func add(n : String, c : Control): + var fp = FlexPanel.new() + fp.name = n + fp.widget = c + unassigned.push_back(fp) + +func _on_resized(): + print("resized") + layout() + +func start_drag(): + print("Starting drag") + overlay = OVERLAY_SCENE.instantiate() + overlay.position = Vector2(0, 0) + overlay.size = size + add_child(overlay) + +func end_drag(): + overlay.queue_free() + overlay = null + +func get_flexnode_at(p : Vector2) -> FlexNode: + return top.get_flexnode_at(p) + +func move_panel(panel, reference_panel : FlexNode, destination): + var parent_panel : FlexNode = reference_panel.parent + var vertical : bool + var offset : int + var tab : FlexTab = null + match destination: + 0: + if not reference_panel is FlexTab: + return + tab = reference_panel + 1: + vertical = true + offset = 0 + 2: + vertical = false + offset = 0 + 3: + vertical = false + offset = 1 + 4: + vertical = true + offset = 1 + _: + return + if tab == null: + var split : FlexSplit + if parent_panel is FlexSplit and parent_panel.vertical == vertical: + split = parent_panel as FlexSplit + else: + split = FlexSplit.new(parent_panel, reference_panel.flexible_layout) + split.vertical = vertical + parent_panel.replace(reference_panel, split) + split.insert(reference_panel, 0) + tab = FlexTab.new(parent_panel, reference_panel.flexible_layout) + var ref_index : int = split.find(reference_panel) + split.insert(tab, ref_index+offset, ref_index) + panel.flex_node.remove(panel.flex_panel) + tab.add(panel.flex_panel) + layout() diff --git a/addons/flexible_layout/flexible_layout.tscn b/addons/flexible_layout/flexible_layout.tscn new file mode 100644 index 000000000..62d461b61 --- /dev/null +++ b/addons/flexible_layout/flexible_layout.tscn @@ -0,0 +1,14 @@ +[gd_scene load_steps=2 format=3 uid="uid://eiq3i53x72m2"] + +[ext_resource type="Script" path="res://addons/flexible_layout/flexible_layout.gd" id="1"] + +[node name="FlexibleLayout" 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") + +[connection signal="resized" from="." to="." method="_on_resized"] diff --git a/addons/flexible_layout/flexible_overlay.gd b/addons/flexible_layout/flexible_overlay.gd new file mode 100644 index 000000000..9f8259df9 --- /dev/null +++ b/addons/flexible_layout/flexible_overlay.gd @@ -0,0 +1,48 @@ +extends ColorRect + +func find_position_from_target(at_position, target): + const POSITIONS = [ -1, 1, -1, 2, 0, 3, -1, 4, -1] + var pos_x = int(3*(at_position.x-target.rect.position.x) / target.rect.size.x) + var pos_y = int(3*(at_position.y-target.rect.position.y) / target.rect.size.y) + return POSITIONS[pos_x+3*pos_y] + +func _drop_data(at_position, data): + var target = get_parent().get_flexnode_at(at_position) + if target: + var destination = find_position_from_target(at_position, target) + if destination != -1: + get_parent().move_panel(data, target, destination) + +func _can_drop_data(at_position, data): + var target = get_parent().get_flexnode_at(at_position) + if target: + var rect : Rect2 = target.rect + match find_position_from_target(at_position, target): + 0: + if data.flex_node == target: + $Arrow.visible = false + return false + $Arrow.visible = true + $Arrow.position = rect.get_center()-Vector2(32, 32) + $Arrow.rotation_degrees = 0 + 1: + $Arrow.visible = true + $Arrow.position = Vector2(rect.get_center().x-32, rect.position.y) + $Arrow.rotation_degrees = 0 + 2: + $Arrow.visible = true + $Arrow.position = Vector2(rect.position.x, rect.get_center().y-32) + $Arrow.rotation_degrees = -90 + 3: + $Arrow.visible = true + $Arrow.position = Vector2(rect.end.x-64, rect.get_center().y-32) + $Arrow.rotation_degrees = 90 + 4: + $Arrow.visible = true + $Arrow.position = Vector2(rect.get_center().x-32, rect.end.y-64) + $Arrow.rotation_degrees = 180 + _: + $Arrow.visible = false + return false + return true + diff --git a/addons/flexible_layout/flexible_overlay.tscn b/addons/flexible_layout/flexible_overlay.tscn new file mode 100644 index 000000000..8aeab21de --- /dev/null +++ b/addons/flexible_layout/flexible_overlay.tscn @@ -0,0 +1,21 @@ +[gd_scene load_steps=3 format=3 uid="uid://gqucl1dthw6d"] + +[ext_resource type="Script" path="res://addons/flexible_layout/flexible_overlay.gd" id="1_5tomg"] +[ext_resource type="Texture2D" uid="uid://0gespyud2ad" path="res://icon.png" id="2_5qmj0"] + +[node name="Control" type="ColorRect"] +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0.513726, 0.513726, 0.513726, 0.501961) +script = ExtResource("1_5tomg") + +[node name="Arrow" type="TextureRect" parent="."] +visible = false +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 +pivot_offset = Vector2(32, 32) +texture = ExtResource("2_5qmj0") diff --git a/addons/flexible_layout/flexible_tab.gd b/addons/flexible_layout/flexible_tab.gd new file mode 100644 index 000000000..1ac9919ee --- /dev/null +++ b/addons/flexible_layout/flexible_tab.gd @@ -0,0 +1,23 @@ +extends Container + + +var flex_panel + + +func init(fp): + flex_panel = fp + $Container/Label.text = flex_panel.name + +func _draw(): + var is_current : bool = (get_index() == get_parent().get_parent().current) + draw_style_box(get_theme_stylebox("tab_selected" if is_current else "tab_unselected", "TabBar"), Rect2(Vector2(), size)) + $Container/Undock.visible = is_current + $Container/Close.visible = is_current + +func _gui_input(event): + if event is InputEventMouseButton and event.button_index == MOUSE_BUTTON_LEFT and event.pressed: + get_parent().get_parent().set_current(get_index()) + +func _get_drag_data(_position): + var flexible_layout = get_parent().get_parent().flex_tab.flexible_layout + return flexible_layout.PanelInfo.new(get_parent().get_parent().flex_tab, flex_panel) diff --git a/addons/flexible_layout/flexible_tab.tscn b/addons/flexible_layout/flexible_tab.tscn new file mode 100644 index 000000000..3653d98d7 --- /dev/null +++ b/addons/flexible_layout/flexible_tab.tscn @@ -0,0 +1,42 @@ +[gd_scene load_steps=4 format=3 uid="uid://e06xegp2tp3f"] + +[ext_resource type="Script" path="res://addons/flexible_layout/flexible_tab.gd" id="1"] + +[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_b47q6"] +size = Vector2(16, 16) + +[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_bok24"] +size = Vector2(16, 16) + +[node name="Tab" type="MarginContainer"] +offset_right = 41.0 +offset_bottom = 26.0 +size_flags_horizontal = 0 +size_flags_vertical = 0 +mouse_filter = 0 +theme_override_constants/margin_left = 3 +theme_override_constants/margin_right = 3 +script = ExtResource("1") + +[node name="Container" type="HBoxContainer" parent="."] +clip_contents = true +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 0 +mouse_filter = 2 + +[node name="Label" type="Label" parent="Container"] +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 0 +text = "Blah" + +[node name="Undock" type="TextureButton" parent="Container"] +visible = false +layout_mode = 2 +texture_normal = SubResource("PlaceholderTexture2D_b47q6") + +[node name="Close" type="TextureButton" parent="Container"] +visible = false +layout_mode = 2 +texture_normal = SubResource("PlaceholderTexture2D_bok24") diff --git a/addons/flexible_layout/flexible_tabs.gd b/addons/flexible_layout/flexible_tabs.gd new file mode 100644 index 000000000..c3baaadc1 --- /dev/null +++ b/addons/flexible_layout/flexible_tabs.gd @@ -0,0 +1,44 @@ +extends Control + + +var flex_tab +var controls : Array = [] +var current : int = -1 + + +func _init(): + set_meta("flexlayout", true) + +func add(ft): + var tab = load("res://addons/flexible_layout/flexible_tab.tscn").instantiate() + tab.init(ft) + $Tabs.add_child(tab) + custom_minimum_size.y = $Tabs.get_minimum_size().y + controls.push_back(ft) + if current == -1: + set_current(0) + else: + ft.widget.visible = false + +func erase(ft): + var index : int = controls.find(ft) + $Tabs.remove_child($Tabs.get_child(index)) + controls.erase(ft) + if index == current: + if $Tabs.get_child_count() > 0: + set_current(0) + else: + set_current(-1) + +func set_flex_tab(ft): + flex_tab = ft + +func set_current(c : int): + current = c + for i in controls.size(): + controls[i].widget.visible = (i == current) + $Tabs.get_child(i).queue_redraw() + +func _on_resized(): + print("%s: %s - %s" % [ str(self), str(position), str(size) ]) + $Tabs.queue_sort() diff --git a/addons/flexible_layout/flexible_tabs.tscn b/addons/flexible_layout/flexible_tabs.tscn new file mode 100644 index 000000000..458203a5f --- /dev/null +++ b/addons/flexible_layout/flexible_tabs.tscn @@ -0,0 +1,16 @@ +[gd_scene load_steps=2 format=3 uid="uid://cpwg6da5kpsef"] + +[ext_resource type="Script" path="res://addons/flexible_layout/flexible_tabs.gd" id="1"] + +[node name="TabBar" type="Control"] +clip_contents = true +layout_mode = 3 +anchors_preset = 0 +script = ExtResource("1") + +[node name="Tabs" type="HBoxContainer" parent="."] +clip_contents = true +layout_mode = 0 +size_flags_horizontal = 0 +size_flags_vertical = 0 +theme_override_constants/separation = 0 diff --git a/addons/flexible_layout/test.gd b/addons/flexible_layout/test.gd new file mode 100644 index 000000000..db343c98f --- /dev/null +++ b/addons/flexible_layout/test.gd @@ -0,0 +1,5 @@ +extends Control + +func _ready(): + get_window().borderless = false + get_window().size = Vector2i(1024, 768) diff --git a/addons/flexible_layout/test.tscn b/addons/flexible_layout/test.tscn new file mode 100644 index 000000000..a9e6362c9 --- /dev/null +++ b/addons/flexible_layout/test.tscn @@ -0,0 +1,73 @@ +[gd_scene load_steps=3 format=3 uid="uid://dg6wvikeic0k1"] + +[ext_resource type="PackedScene" uid="uid://eiq3i53x72m2" path="res://addons/flexible_layout/flexible_layout.tscn" id="1"] +[ext_resource type="Script" path="res://addons/flexible_layout/test.gd" id="2"] + +[node name="Control" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +size_flags_horizontal = 3 +size_flags_vertical = 3 +script = ExtResource("2") + +[node name="FlexibleLayout" parent="." instance=ExtResource("1")] +layout_mode = 1 +mouse_filter = 2 + +[node name="Main" type="ColorRect" parent="FlexibleLayout"] +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 +color = Color(0.239216, 0.462745, 1, 1) + +[node name="ColorRect1" type="ColorRect" parent="FlexibleLayout"] +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 +color = Color(1, 0.690196, 0.25098, 1) + +[node name="ColorRect2" type="ColorRect" parent="FlexibleLayout"] +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 +color = Color(0.713726, 1, 0.368627, 1) + +[node name="ColorRect3" type="ColorRect" parent="FlexibleLayout"] +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 +color = Color(0.592157, 0.25098, 1, 1) + +[node name="ColorRect4" type="ColorRect" parent="FlexibleLayout"] +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 +color = Color(1, 0.368627, 0.65098, 1) + +[node name="ColorRect5" type="ColorRect" parent="FlexibleLayout"] +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 +color = Color(0.25098, 0.615686, 1, 1) + +[node name="ColorRect6" type="ColorRect" parent="FlexibleLayout"] +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 +color = Color(0.368627, 1, 0.572549, 1) + +[node name="ColorRect7" type="ColorRect" parent="FlexibleLayout"] +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 +color = Color(1, 0.25098, 0.356863, 1) + +[node name="ColorRect8" type="ColorRect" parent="FlexibleLayout"] +layout_mode = 0 +offset_right = 40.0 +offset_bottom = 40.0 +color = Color(1, 0.988235, 0.368627, 1)