├── .github └── FUNDING.yml ├── .gitignore ├── LICENSE ├── README.md ├── addons └── multi_spliter_container │ ├── example │ ├── example_scene.tscn │ ├── example_scene_as_child.tscn │ ├── example_scene_as_child_with_custom_offsets.tscn │ ├── example_scene_runtime.gd │ ├── example_scene_runtime.gd.uid │ └── example_scene_runtime.tscn │ ├── icon │ ├── MultiSpliter.svg │ ├── MultiSpliter.svg.import │ ├── MultiSpliterButton.svg │ ├── MultiSpliterButton.svg.import │ ├── MultiSpliterItem.svg │ └── MultiSpliterItem.svg.import │ ├── multi_split_container.gd │ ├── multi_split_container.gd.uid │ ├── plugin.cfg │ ├── plugin.gd │ ├── plugin.gd.uid │ ├── split_container_item.gd │ └── split_container_item.gd.uid └── images ├── .gdignore ├── example.png ├── example_full.png └── example_wchild.png /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | ko_fi: cntwister 4 | buy_me_a_coffee: twister 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Godot 4+ specific ignores 2 | .godot/ 3 | 4 | # Godot-specific ignores 5 | .import/ 6 | export.cfg 7 | export_credentials.cfg 8 | 9 | # Imported translations (automatically generated from CSV files) 10 | *.translation 11 | 12 | # Mono-specific ignores 13 | .mono/ 14 | data_*/ 15 | mono_crash.*.json 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 Twister 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Multi-Split-Container 2 | Allow splitting elements into containers with the same size in the canvas rectangle. 3 | 4 | Buy Me A Coffee 5 | 6 | [![Godot Engine 4.3](https://img.shields.io/badge/Godot_Engine-4.x-blue)](https://godotengine.org/) ![ToolHack](https://img.shields.io/badge/Tool-Addon-green) ![Copyrights License](https://img.shields.io/badge/License-MIT-blue) 7 | 8 | >[!NOTE] 9 | >This plugin was initially created to be used by [Script-Spliter v0.2](https://github.com/CodeNameTwister/Script-Spliter) addon. 10 | 11 | # Features 12 | * Auto Split in columns by child node count. (Work on nodes with base as Control) 13 | * Auto Split in rows by you max columns value setted. 14 | * Lines Size/Color Changeables. 15 | * Drag Button Size/Color Changeables. 16 | * Drag Button Icon Changeables. 17 | * Reset offset splited container on double click on line. 18 | * Auto show content on focus. 19 | * Smooth Expand Container. 20 | * Custom Initial Offset. 21 | 22 | 23 | # Preview 24 | ### Video Example Scene. 25 | [![video preview](https://github.com/CodeNameTwister/Misc/blob/main/media/video/gd_msc.png?raw=true)](https://youtu.be/5JU3snjbRMU) 26 | ### Image Example Scene before/after move splited container by drag buttons. 27 | ![image_preview2](images/example_full.png) 28 | ### Image Example Scene 2 nested child. 29 | ![image_preview2](images/example_wchild.png) 30 | 31 | 32 | # How Work 33 | After enable this plugin, you can see the new node called **MultiSplitContainer**. 34 | 35 | This node automatically creates a **SplitContainerItem** node that will be managed by **MultiSplitContainer** for split/resize. 36 | 37 | ### Custom Separator Line Offset 38 | Modify the values ​​to set a custom offset, each box of the array represents in order a line starting from the first container to the last. 39 | 40 | # Nodes 41 | 42 | >[!TIP] 43 | >This nodes are extends by Control and work with any nodes type control. 44 | > 45 | >*example: Label, ColorRect, TextureRect, other controls...* 46 | ### MultiSplitContainer 47 | This is the root and you can add any child node, this node auto add the child node to a new **SplitContainerItem**. 48 | 49 | ### SplitContainerItem 50 | This node is created by **MultiSplitContainer** and you can add any child to this node. 51 | 52 | ## 53 | 54 | > You can put a issue request for bugs/changes and remember support me for more good things hey! 55 | 56 | Copyrights (c) CodeNameTwister. See [LICENSE](LICENSE) for details. 57 | 58 | [godot engine]: https://godotengine.org/ 59 | 60 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/example/example_scene.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=5 format=3 uid="uid://bsf5475jlmf12"] 2 | 3 | [ext_resource type="Script" uid="uid://db6mrqis6mthu" path="res://addons/multi_spliter_container/multi_split_container.gd" id="1_erthe"] 4 | [ext_resource type="Script" uid="uid://beplmlbkjbofd" path="res://addons/multi_spliter_container/split_container_item.gd" id="2_jlu11"] 5 | [ext_resource type="Texture2D" uid="uid://cwvyucfkxwjqw" path="res://addons/multi_spliter_container/icon/MultiSpliterItem.svg" id="3_geasv"] 6 | [ext_resource type="Texture2D" uid="uid://bjaei3q7x2hux" path="res://addons/multi_spliter_container/icon/MultiSpliter.svg" id="4_flrsd"] 7 | 8 | [node name="Example" type="Container"] 9 | anchors_preset = 15 10 | anchor_right = 1.0 11 | anchor_bottom = 1.0 12 | grow_horizontal = 2 13 | grow_vertical = 2 14 | size_flags_horizontal = 3 15 | size_flags_vertical = 3 16 | script = ExtResource("1_erthe") 17 | max_columns = 3 18 | separator_line_size = 23.085 19 | separator_line_color = Color(0.21, 0.24, 0.29, 1) 20 | separators_line_offsets = Array[float]([0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]) 21 | _rect_size_editor = Vector2i(1288, 745) 22 | drag_button_size = 32.0 23 | drag_button_modulate = Color(0.605, 0.62, 0.645, 1) 24 | 25 | [node name="SplitContainerItem" type="Control" parent="."] 26 | clip_contents = true 27 | layout_mode = 2 28 | script = ExtResource("2_jlu11") 29 | 30 | [node name="ColorRect" type="ColorRect" parent="SplitContainerItem"] 31 | layout_mode = 1 32 | anchors_preset = 15 33 | anchor_right = 1.0 34 | anchor_bottom = 1.0 35 | grow_horizontal = 2 36 | grow_vertical = 2 37 | color = Color(0.289933, 0.678044, 0.717213, 1) 38 | 39 | [node name="Label" type="Label" parent="SplitContainerItem"] 40 | layout_mode = 1 41 | anchors_preset = 15 42 | anchor_right = 1.0 43 | anchor_bottom = 1.0 44 | grow_horizontal = 2 45 | grow_vertical = 2 46 | text = "Splited Content" 47 | horizontal_alignment = 1 48 | vertical_alignment = 1 49 | 50 | [node name="SplitContainerItem2" type="Control" parent="."] 51 | clip_contents = true 52 | layout_mode = 2 53 | script = ExtResource("2_jlu11") 54 | 55 | [node name="ColorRect" type="ColorRect" parent="SplitContainerItem2"] 56 | layout_mode = 1 57 | anchors_preset = 15 58 | anchor_right = 1.0 59 | anchor_bottom = 1.0 60 | grow_horizontal = 2 61 | grow_vertical = 2 62 | color = Color(0.91285, 0.000445113, 0.865852, 1) 63 | 64 | [node name="Label" type="Label" parent="SplitContainerItem2"] 65 | layout_mode = 1 66 | anchors_preset = 15 67 | anchor_right = 1.0 68 | anchor_bottom = 1.0 69 | grow_horizontal = 2 70 | grow_vertical = 2 71 | text = "You can change line size and color" 72 | horizontal_alignment = 1 73 | vertical_alignment = 1 74 | 75 | [node name="SplitContainerItem3" type="Control" parent="."] 76 | clip_contents = true 77 | layout_mode = 2 78 | script = ExtResource("2_jlu11") 79 | 80 | [node name="ColorRect2" type="ColorRect" parent="SplitContainerItem3"] 81 | layout_mode = 1 82 | anchors_preset = 15 83 | anchor_right = 1.0 84 | anchor_bottom = 1.0 85 | grow_horizontal = 2 86 | grow_vertical = 2 87 | color = Color(0, 0.630427, 0.698456, 1) 88 | 89 | [node name="Label" type="Label" parent="SplitContainerItem3"] 90 | layout_mode = 1 91 | anchors_preset = 15 92 | anchor_right = 1.0 93 | anchor_bottom = 1.0 94 | grow_horizontal = 2 95 | grow_vertical = 2 96 | text = "Also change drag button size and color" 97 | horizontal_alignment = 1 98 | vertical_alignment = 1 99 | 100 | [node name="SplitContainerItem4" type="Control" parent="."] 101 | clip_contents = true 102 | layout_mode = 2 103 | script = ExtResource("2_jlu11") 104 | 105 | [node name="ColorRect2" type="ColorRect" parent="SplitContainerItem4"] 106 | layout_mode = 1 107 | anchors_preset = 15 108 | anchor_right = 1.0 109 | anchor_bottom = 1.0 110 | grow_horizontal = 2 111 | grow_vertical = 2 112 | color = Color(0.245328, 0.637411, 0.53248, 1) 113 | 114 | [node name="Label" type="Label" parent="SplitContainerItem4"] 115 | layout_mode = 1 116 | anchors_preset = 15 117 | anchor_right = 1.0 118 | anchor_bottom = 1.0 119 | grow_horizontal = 2 120 | grow_vertical = 2 121 | text = "This scene is only used as example" 122 | horizontal_alignment = 1 123 | vertical_alignment = 1 124 | 125 | [node name="SplitContainerItem5" type="Control" parent="."] 126 | clip_contents = true 127 | layout_mode = 2 128 | script = ExtResource("2_jlu11") 129 | 130 | [node name="ColorRect2" type="ColorRect" parent="SplitContainerItem5"] 131 | layout_mode = 1 132 | anchors_preset = 15 133 | anchor_right = 1.0 134 | anchor_bottom = 1.0 135 | grow_horizontal = 2 136 | grow_vertical = 2 137 | color = Color(0.422539, 0.299198, 0.747823, 1) 138 | 139 | [node name="TextureRect" type="TextureRect" parent="SplitContainerItem5"] 140 | modulate = Color(0.458405, 0.458405, 0.458405, 1) 141 | layout_mode = 1 142 | anchors_preset = 8 143 | anchor_left = 0.5 144 | anchor_top = 0.5 145 | anchor_right = 0.5 146 | anchor_bottom = 0.5 147 | offset_left = -64.0 148 | offset_top = -64.0 149 | offset_right = 64.0 150 | offset_bottom = 64.0 151 | grow_horizontal = 2 152 | grow_vertical = 2 153 | texture = ExtResource("3_geasv") 154 | 155 | [node name="Label" type="Label" parent="SplitContainerItem5"] 156 | layout_mode = 1 157 | anchors_preset = 15 158 | anchor_right = 1.0 159 | anchor_bottom = 1.0 160 | grow_horizontal = 2 161 | grow_vertical = 2 162 | text = "You can test this scene push play button" 163 | horizontal_alignment = 1 164 | vertical_alignment = 1 165 | 166 | [node name="SplitContainerItem6" type="Control" parent="."] 167 | clip_contents = true 168 | layout_mode = 2 169 | script = ExtResource("2_jlu11") 170 | 171 | [node name="ColorRect2" type="ColorRect" parent="SplitContainerItem6"] 172 | layout_mode = 1 173 | anchors_preset = 15 174 | anchor_right = 1.0 175 | anchor_bottom = 1.0 176 | grow_horizontal = 2 177 | grow_vertical = 2 178 | color = Color(0.319354, 0.598646, 0.721516, 1) 179 | 180 | [node name="Label" type="Label" parent="SplitContainerItem6"] 181 | layout_mode = 1 182 | anchors_preset = 15 183 | anchor_right = 1.0 184 | anchor_bottom = 1.0 185 | grow_horizontal = 2 186 | grow_vertical = 2 187 | text = "The content automatic splited 188 | in columns by childs" 189 | horizontal_alignment = 1 190 | vertical_alignment = 1 191 | 192 | [node name="SplitContainerItem7" type="Control" parent="."] 193 | clip_contents = true 194 | layout_mode = 2 195 | script = ExtResource("2_jlu11") 196 | 197 | [node name="ColorRect2" type="ColorRect" parent="SplitContainerItem7"] 198 | layout_mode = 1 199 | anchors_preset = 15 200 | anchor_right = 1.0 201 | anchor_bottom = 1.0 202 | grow_horizontal = 2 203 | grow_vertical = 2 204 | color = Color(0.790303, 0.463822, 0.258149, 1) 205 | 206 | [node name="Label" type="Label" parent="SplitContainerItem7"] 207 | layout_mode = 1 208 | anchors_preset = 15 209 | anchor_right = 1.0 210 | anchor_bottom = 1.0 211 | grow_horizontal = 2 212 | grow_vertical = 2 213 | text = "If you defined rows; 214 | so split by rows count defined" 215 | horizontal_alignment = 1 216 | vertical_alignment = 1 217 | 218 | [node name="SplitContainerItem8" type="Control" parent="."] 219 | clip_contents = true 220 | layout_mode = 2 221 | script = ExtResource("2_jlu11") 222 | 223 | [node name="MarginContainer" type="MarginContainer" parent="SplitContainerItem8"] 224 | layout_mode = 1 225 | anchors_preset = 15 226 | anchor_right = 1.0 227 | anchor_bottom = 1.0 228 | grow_horizontal = 2 229 | grow_vertical = 2 230 | 231 | [node name="ColorRect2" type="ColorRect" parent="SplitContainerItem8/MarginContainer"] 232 | layout_mode = 2 233 | color = Color(0.22928, 0.144101, 0.436279, 1) 234 | 235 | [node name="TextureRect" type="TextureRect" parent="SplitContainerItem8/MarginContainer"] 236 | modulate = Color(0.489622, 0.489622, 0.489622, 1) 237 | layout_mode = 2 238 | texture = ExtResource("4_flrsd") 239 | stretch_mode = 5 240 | 241 | [node name="Label" type="Label" parent="SplitContainerItem8/MarginContainer"] 242 | layout_mode = 2 243 | text = "SplitContainerItem is a simple container 244 | You can add in child whatever you want" 245 | horizontal_alignment = 1 246 | vertical_alignment = 1 247 | 248 | [node name="SplitContainerItem9" type="Control" parent="."] 249 | clip_contents = true 250 | layout_mode = 2 251 | script = ExtResource("2_jlu11") 252 | 253 | [node name="ColorRect2" type="ColorRect" parent="SplitContainerItem9"] 254 | layout_mode = 1 255 | anchors_preset = 15 256 | anchor_right = 1.0 257 | anchor_bottom = 1.0 258 | grow_horizontal = 2 259 | grow_vertical = 2 260 | color = Color(0.596458, 0.423716, 1.92523e-07, 1) 261 | 262 | [node name="Label" type="Label" parent="SplitContainerItem9"] 263 | layout_mode = 1 264 | anchors_preset = 15 265 | anchor_right = 1.0 266 | anchor_bottom = 1.0 267 | grow_horizontal = 2 268 | grow_vertical = 2 269 | text = "But keep in mind, this plugins work with 270 | SplitContainerItem" 271 | horizontal_alignment = 1 272 | vertical_alignment = 1 273 | 274 | [node name="SplitContainerItem10" type="Control" parent="."] 275 | clip_contents = true 276 | layout_mode = 2 277 | script = ExtResource("2_jlu11") 278 | 279 | [node name="ColorRect2" type="ColorRect" parent="SplitContainerItem10"] 280 | layout_mode = 1 281 | anchors_preset = 15 282 | anchor_right = 1.0 283 | anchor_bottom = 1.0 284 | grow_horizontal = 2 285 | grow_vertical = 2 286 | color = Color(0, 0.304393, 0.507182, 1) 287 | 288 | [node name="Label" type="Label" parent="SplitContainerItem10"] 289 | layout_mode = 1 290 | anchors_preset = 15 291 | anchor_right = 1.0 292 | anchor_bottom = 1.0 293 | grow_horizontal = 2 294 | grow_vertical = 2 295 | text = "Plugin create SplitContainerItem on added child and remove if has not childs, is that all..." 296 | horizontal_alignment = 1 297 | vertical_alignment = 1 298 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/example/example_scene_as_child.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=7 format=3 uid="uid://cp2b7c6ttxv2p"] 2 | 3 | [ext_resource type="Script" uid="uid://db6mrqis6mthu" path="res://addons/multi_spliter_container/multi_split_container.gd" id="1_q7yv4"] 4 | [ext_resource type="Script" uid="uid://beplmlbkjbofd" path="res://addons/multi_spliter_container/split_container_item.gd" id="2_xa37v"] 5 | [ext_resource type="Texture2D" uid="uid://bjaei3q7x2hux" path="res://addons/multi_spliter_container/icon/MultiSpliter.svg" id="3_pt6aj"] 6 | [ext_resource type="Texture2D" uid="uid://cwvyucfkxwjqw" path="res://addons/multi_spliter_container/icon/MultiSpliterItem.svg" id="4_xa37v"] 7 | 8 | [sub_resource type="LabelSettings" id="LabelSettings_82db5"] 9 | font_size = 24 10 | outline_size = 4 11 | outline_color = Color(0, 0, 0, 1) 12 | 13 | [sub_resource type="LabelSettings" id="LabelSettings_q7yv4"] 14 | font_size = 20 15 | outline_size = 4 16 | outline_color = Color(0, 0, 0, 1) 17 | 18 | [node name="ExampleSceneChild" type="Control"] 19 | layout_mode = 3 20 | anchors_preset = 15 21 | anchor_right = 1.0 22 | anchor_bottom = 1.0 23 | grow_horizontal = 2 24 | grow_vertical = 2 25 | 26 | [node name="MultiSplitContainer" type="Container" parent="."] 27 | layout_mode = 1 28 | anchors_preset = 15 29 | anchor_right = 1.0 30 | anchor_bottom = 1.0 31 | grow_horizontal = 2 32 | grow_vertical = 2 33 | size_flags_horizontal = 3 34 | size_flags_vertical = 3 35 | script = ExtResource("1_q7yv4") 36 | max_columns = 2 37 | separator_line_color = Color(0.21, 0.24, 0.29, 1) 38 | behaviour_can_expand_focus_same_container = true 39 | separators_line_offsets = Array[float]([0.0, 0.0, 0.0]) 40 | _rect_size_editor = Vector2(1152, 648) 41 | drag_button_modulate = Color(0.605, 0.62, 0.645, 1) 42 | metadata/_custom_type_script = "uid://db6mrqis6mthu" 43 | 44 | [node name="SplitContainerItem" type="Control" parent="MultiSplitContainer"] 45 | clip_contents = true 46 | layout_mode = 2 47 | script = ExtResource("2_xa37v") 48 | 49 | [node name="ColorRect" type="ColorRect" parent="MultiSplitContainer/SplitContainerItem"] 50 | self_modulate = Color(0.783524, 0.783523, 0.783523, 1) 51 | layout_mode = 1 52 | anchors_preset = 15 53 | anchor_right = 1.0 54 | anchor_bottom = 1.0 55 | grow_horizontal = 2 56 | grow_vertical = 2 57 | color = Color(0.233148, 0.457125, 1, 1) 58 | 59 | [node name="TextureRect" type="TextureRect" parent="MultiSplitContainer/SplitContainerItem"] 60 | modulate = Color(1, 1, 1, 0.494118) 61 | layout_mode = 1 62 | anchors_preset = 15 63 | anchor_right = 1.0 64 | anchor_bottom = 1.0 65 | grow_horizontal = 2 66 | grow_vertical = 2 67 | texture = ExtResource("3_pt6aj") 68 | stretch_mode = 5 69 | 70 | [node name="Label" type="Label" parent="MultiSplitContainer/SplitContainerItem"] 71 | layout_mode = 1 72 | anchors_preset = 8 73 | anchor_left = 0.5 74 | anchor_top = 0.5 75 | anchor_right = 0.5 76 | anchor_bottom = 0.5 77 | offset_left = -20.0 78 | offset_top = -11.5 79 | offset_right = 20.0 80 | offset_bottom = 11.5 81 | grow_horizontal = 2 82 | grow_vertical = 2 83 | text = "Try Change Max Columns 84 | Container 1" 85 | label_settings = SubResource("LabelSettings_82db5") 86 | horizontal_alignment = 1 87 | 88 | [node name="SplitContainerItem2" type="Control" parent="MultiSplitContainer"] 89 | clip_contents = true 90 | layout_mode = 2 91 | script = ExtResource("2_xa37v") 92 | 93 | [node name="ColorRect" type="ColorRect" parent="MultiSplitContainer/SplitContainerItem2"] 94 | self_modulate = Color(0.783524, 0.783523, 0.783523, 1) 95 | layout_mode = 2 96 | anchor_right = 1.0 97 | anchor_bottom = 1.0 98 | grow_horizontal = 2 99 | grow_vertical = 2 100 | color = Color(5.77569e-06, 0.559168, 0, 1) 101 | 102 | [node name="TextureRect" type="TextureRect" parent="MultiSplitContainer/SplitContainerItem2"] 103 | modulate = Color(1, 1, 1, 0.470588) 104 | layout_mode = 1 105 | anchors_preset = 15 106 | anchor_right = 1.0 107 | anchor_bottom = 1.0 108 | grow_horizontal = 2 109 | grow_vertical = 2 110 | texture = ExtResource("4_xa37v") 111 | expand_mode = 1 112 | stretch_mode = 5 113 | 114 | [node name="Label" type="Label" parent="MultiSplitContainer/SplitContainerItem2"] 115 | layout_mode = 1 116 | anchors_preset = 8 117 | anchor_left = 0.5 118 | anchor_top = 0.5 119 | anchor_right = 0.5 120 | anchor_bottom = 0.5 121 | offset_left = -20.0 122 | offset_top = -11.5 123 | offset_right = 20.0 124 | offset_bottom = 11.5 125 | grow_horizontal = 2 126 | grow_vertical = 2 127 | text = "Container 2" 128 | 129 | [node name="SplitContainerItem3" type="Control" parent="MultiSplitContainer"] 130 | clip_contents = true 131 | layout_mode = 2 132 | script = ExtResource("2_xa37v") 133 | 134 | [node name="ColorRect" type="ColorRect" parent="MultiSplitContainer/SplitContainerItem3"] 135 | self_modulate = Color(0.783524, 0.783523, 0.783523, 1) 136 | layout_mode = 2 137 | anchor_right = 1.0 138 | anchor_bottom = 1.0 139 | grow_horizontal = 2 140 | grow_vertical = 2 141 | color = Color(0.699196, 6.37732e-07, 2.88785e-07, 1) 142 | 143 | [node name="TextureRect" type="TextureRect" parent="MultiSplitContainer/SplitContainerItem3"] 144 | modulate = Color(1, 1, 1, 0.470588) 145 | layout_mode = 1 146 | anchors_preset = 15 147 | anchor_right = 1.0 148 | anchor_bottom = 1.0 149 | grow_horizontal = 2 150 | grow_vertical = 2 151 | texture = ExtResource("4_xa37v") 152 | expand_mode = 1 153 | stretch_mode = 5 154 | 155 | [node name="Label" type="Label" parent="MultiSplitContainer/SplitContainerItem3"] 156 | layout_mode = 1 157 | anchors_preset = 8 158 | anchor_left = 0.5 159 | anchor_top = 0.5 160 | anchor_right = 0.5 161 | anchor_bottom = 0.5 162 | offset_left = -20.0 163 | offset_top = -11.5 164 | offset_right = 20.0 165 | offset_bottom = 11.5 166 | grow_horizontal = 2 167 | grow_vertical = 2 168 | text = "Container 3" 169 | 170 | [node name="SplitContainerItem4" type="Control" parent="MultiSplitContainer"] 171 | clip_contents = true 172 | layout_mode = 2 173 | script = ExtResource("2_xa37v") 174 | 175 | [node name="MultiSplitContainer2" type="Container" parent="MultiSplitContainer/SplitContainerItem4"] 176 | layout_mode = 1 177 | anchors_preset = 15 178 | anchor_right = 1.0 179 | anchor_bottom = 1.0 180 | grow_horizontal = 2 181 | grow_vertical = 2 182 | size_flags_horizontal = 3 183 | size_flags_vertical = 3 184 | script = ExtResource("1_q7yv4") 185 | max_columns = 1 186 | separator_line_color = Color(0.21, 0.24, 0.29, 1) 187 | separators_line_offsets = Array[float]([-22.0, 22.0]) 188 | _rect_size_editor = Vector2(1152, 648) 189 | drag_button_modulate = Color(0.605, 0.62, 0.645, 1) 190 | metadata/_custom_type_script = "uid://db6mrqis6mthu" 191 | 192 | [node name="SplitContainerItem" type="Control" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2"] 193 | clip_contents = true 194 | layout_mode = 2 195 | script = ExtResource("2_xa37v") 196 | 197 | [node name="ColorRect" type="ColorRect" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem"] 198 | self_modulate = Color(0.783524, 0.783523, 0.783523, 1) 199 | layout_mode = 1 200 | anchors_preset = 15 201 | anchor_right = 1.0 202 | anchor_bottom = 1.0 203 | grow_horizontal = 2 204 | grow_vertical = 2 205 | color = Color(0.150172, 0.683607, 0.853672, 1) 206 | 207 | [node name="TextureRect" type="TextureRect" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem"] 208 | modulate = Color(1, 1, 1, 0.470588) 209 | layout_mode = 1 210 | anchors_preset = 15 211 | anchor_right = 1.0 212 | anchor_bottom = 1.0 213 | grow_horizontal = 2 214 | grow_vertical = 2 215 | texture = ExtResource("4_xa37v") 216 | expand_mode = 1 217 | stretch_mode = 5 218 | 219 | [node name="Label" type="Label" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem"] 220 | layout_mode = 1 221 | anchors_preset = 8 222 | anchor_left = 0.5 223 | anchor_top = 0.5 224 | anchor_right = 0.5 225 | anchor_bottom = 0.5 226 | offset_left = -20.0 227 | offset_top = -11.5 228 | offset_right = 20.0 229 | offset_bottom = 11.5 230 | grow_horizontal = 2 231 | grow_vertical = 2 232 | text = "This is sub multi split with max columns 1 container 233 | Sub Container 1" 234 | label_settings = SubResource("LabelSettings_q7yv4") 235 | horizontal_alignment = 1 236 | 237 | [node name="SplitContainerItem2" type="Control" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2"] 238 | clip_contents = true 239 | layout_mode = 2 240 | script = ExtResource("2_xa37v") 241 | 242 | [node name="ColorRect" type="ColorRect" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem2"] 243 | self_modulate = Color(0.783524, 0.783523, 0.783523, 1) 244 | layout_mode = 2 245 | anchor_right = 1.0 246 | anchor_bottom = 1.0 247 | grow_horizontal = 2 248 | grow_vertical = 2 249 | color = Color(0, 0.741547, 0.519434, 1) 250 | 251 | [node name="TextureRect" type="TextureRect" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem2"] 252 | modulate = Color(1, 1, 1, 0.470588) 253 | layout_mode = 1 254 | anchors_preset = 15 255 | anchor_right = 1.0 256 | anchor_bottom = 1.0 257 | grow_horizontal = 2 258 | grow_vertical = 2 259 | texture = ExtResource("4_xa37v") 260 | expand_mode = 1 261 | stretch_mode = 5 262 | 263 | [node name="Label" type="Label" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem2"] 264 | layout_mode = 1 265 | anchors_preset = 8 266 | anchor_left = 0.5 267 | anchor_top = 0.5 268 | anchor_right = 0.5 269 | anchor_bottom = 0.5 270 | offset_left = -20.0 271 | offset_top = -11.5 272 | offset_right = 20.0 273 | offset_bottom = 11.5 274 | grow_horizontal = 2 275 | grow_vertical = 2 276 | text = "Sub Container 2" 277 | 278 | [node name="SplitContainerItem3" type="Control" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2"] 279 | clip_contents = true 280 | layout_mode = 2 281 | script = ExtResource("2_xa37v") 282 | 283 | [node name="ColorRect" type="ColorRect" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem3"] 284 | self_modulate = Color(0.783524, 0.783523, 0.783523, 1) 285 | layout_mode = 2 286 | anchor_right = 1.0 287 | anchor_bottom = 1.0 288 | grow_horizontal = 2 289 | grow_vertical = 2 290 | color = Color(0.817285, 0.196588, 0.506349, 1) 291 | 292 | [node name="TextureRect" type="TextureRect" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem3"] 293 | modulate = Color(1, 1, 1, 0.470588) 294 | layout_mode = 1 295 | anchors_preset = 15 296 | anchor_right = 1.0 297 | anchor_bottom = 1.0 298 | grow_horizontal = 2 299 | grow_vertical = 2 300 | texture = ExtResource("4_xa37v") 301 | expand_mode = 1 302 | stretch_mode = 5 303 | 304 | [node name="Label" type="Label" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem3"] 305 | layout_mode = 1 306 | anchors_preset = 8 307 | anchor_left = 0.5 308 | anchor_top = 0.5 309 | anchor_right = 0.5 310 | anchor_bottom = 0.5 311 | offset_left = -20.0 312 | offset_top = -11.5 313 | offset_right = 20.0 314 | offset_bottom = 11.5 315 | grow_horizontal = 2 316 | grow_vertical = 2 317 | text = "Sub Container 3" 318 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/example/example_scene_as_child_with_custom_offsets.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=7 format=3 uid="uid://bxgosuocnk2pp"] 2 | 3 | [ext_resource type="Script" uid="uid://db6mrqis6mthu" path="res://addons/multi_spliter_container/multi_split_container.gd" id="1_hf1r7"] 4 | [ext_resource type="Script" uid="uid://beplmlbkjbofd" path="res://addons/multi_spliter_container/split_container_item.gd" id="2_uhw85"] 5 | [ext_resource type="Texture2D" uid="uid://bjaei3q7x2hux" path="res://addons/multi_spliter_container/icon/MultiSpliter.svg" id="3_kuapk"] 6 | [ext_resource type="Texture2D" uid="uid://cwvyucfkxwjqw" path="res://addons/multi_spliter_container/icon/MultiSpliterItem.svg" id="4_82k4v"] 7 | 8 | [sub_resource type="LabelSettings" id="LabelSettings_82db5"] 9 | font_size = 24 10 | outline_size = 4 11 | outline_color = Color(0, 0, 0, 1) 12 | 13 | [sub_resource type="LabelSettings" id="LabelSettings_q7yv4"] 14 | font_size = 20 15 | outline_size = 4 16 | outline_color = Color(0, 0, 0, 1) 17 | 18 | [node name="ExampleSceneChild" type="Control"] 19 | layout_mode = 3 20 | anchors_preset = 15 21 | anchor_right = 1.0 22 | anchor_bottom = 1.0 23 | grow_horizontal = 2 24 | grow_vertical = 2 25 | 26 | [node name="MultiSplitContainer" type="Container" parent="."] 27 | layout_mode = 1 28 | anchors_preset = 15 29 | anchor_right = 1.0 30 | anchor_bottom = 1.0 31 | grow_horizontal = 2 32 | grow_vertical = 2 33 | size_flags_horizontal = 3 34 | size_flags_vertical = 3 35 | script = ExtResource("1_hf1r7") 36 | max_columns = 2 37 | separator_line_color = Color(0.21, 0.24, 0.29, 1) 38 | behaviour_can_expand_focus_same_container = true 39 | separators_line_offsets = Array[float]([150.0, 32.0, -150.0]) 40 | _rect_size_editor = Vector2(1152, 648) 41 | drag_button_modulate = Color(0.605, 0.62, 0.645, 1) 42 | metadata/_custom_type_script = "uid://db6mrqis6mthu" 43 | 44 | [node name="SplitContainerItem" type="Control" parent="MultiSplitContainer"] 45 | clip_contents = true 46 | layout_mode = 2 47 | script = ExtResource("2_uhw85") 48 | 49 | [node name="ColorRect" type="ColorRect" parent="MultiSplitContainer/SplitContainerItem"] 50 | self_modulate = Color(0.783524, 0.783523, 0.783523, 1) 51 | layout_mode = 1 52 | anchors_preset = 15 53 | anchor_right = 1.0 54 | anchor_bottom = 1.0 55 | grow_horizontal = 2 56 | grow_vertical = 2 57 | color = Color(0.233148, 0.457125, 1, 1) 58 | 59 | [node name="TextureRect" type="TextureRect" parent="MultiSplitContainer/SplitContainerItem"] 60 | modulate = Color(1, 1, 1, 0.494118) 61 | layout_mode = 1 62 | anchors_preset = 15 63 | anchor_right = 1.0 64 | anchor_bottom = 1.0 65 | grow_horizontal = 2 66 | grow_vertical = 2 67 | texture = ExtResource("3_kuapk") 68 | stretch_mode = 5 69 | 70 | [node name="Label" type="Label" parent="MultiSplitContainer/SplitContainerItem"] 71 | layout_mode = 1 72 | anchors_preset = 8 73 | anchor_left = 0.5 74 | anchor_top = 0.5 75 | anchor_right = 0.5 76 | anchor_bottom = 0.5 77 | offset_left = -20.0 78 | offset_top = -11.5 79 | offset_right = 20.0 80 | offset_bottom = 11.5 81 | grow_horizontal = 2 82 | grow_vertical = 2 83 | text = "Try Change 84 | 85 | \"Separators Line Offsets\" 86 | in the inspector 87 | 88 | Container 1" 89 | label_settings = SubResource("LabelSettings_82db5") 90 | horizontal_alignment = 1 91 | 92 | [node name="SplitContainerItem2" type="Control" parent="MultiSplitContainer"] 93 | clip_contents = true 94 | layout_mode = 2 95 | script = ExtResource("2_uhw85") 96 | 97 | [node name="ColorRect" type="ColorRect" parent="MultiSplitContainer/SplitContainerItem2"] 98 | self_modulate = Color(0.783524, 0.783523, 0.783523, 1) 99 | layout_mode = 2 100 | anchor_right = 1.0 101 | anchor_bottom = 1.0 102 | grow_horizontal = 2 103 | grow_vertical = 2 104 | color = Color(5.77569e-06, 0.559168, 0, 1) 105 | 106 | [node name="TextureRect" type="TextureRect" parent="MultiSplitContainer/SplitContainerItem2"] 107 | modulate = Color(1, 1, 1, 0.470588) 108 | layout_mode = 1 109 | anchors_preset = 15 110 | anchor_right = 1.0 111 | anchor_bottom = 1.0 112 | grow_horizontal = 2 113 | grow_vertical = 2 114 | texture = ExtResource("4_82k4v") 115 | expand_mode = 1 116 | stretch_mode = 5 117 | 118 | [node name="Label" type="Label" parent="MultiSplitContainer/SplitContainerItem2"] 119 | layout_mode = 1 120 | anchors_preset = 8 121 | anchor_left = 0.5 122 | anchor_top = 0.5 123 | anchor_right = 0.5 124 | anchor_bottom = 0.5 125 | offset_left = -20.0 126 | offset_top = -11.5 127 | offset_right = 20.0 128 | offset_bottom = 11.5 129 | grow_horizontal = 2 130 | grow_vertical = 2 131 | text = "Container 2" 132 | 133 | [node name="SplitContainerItem3" type="Control" parent="MultiSplitContainer"] 134 | clip_contents = true 135 | layout_mode = 2 136 | script = ExtResource("2_uhw85") 137 | 138 | [node name="ColorRect" type="ColorRect" parent="MultiSplitContainer/SplitContainerItem3"] 139 | self_modulate = Color(0.783524, 0.783523, 0.783523, 1) 140 | layout_mode = 2 141 | anchor_right = 1.0 142 | anchor_bottom = 1.0 143 | grow_horizontal = 2 144 | grow_vertical = 2 145 | color = Color(0.699196, 6.37732e-07, 2.88785e-07, 1) 146 | 147 | [node name="TextureRect" type="TextureRect" parent="MultiSplitContainer/SplitContainerItem3"] 148 | modulate = Color(1, 1, 1, 0.470588) 149 | layout_mode = 1 150 | anchors_preset = 15 151 | anchor_right = 1.0 152 | anchor_bottom = 1.0 153 | grow_horizontal = 2 154 | grow_vertical = 2 155 | texture = ExtResource("4_82k4v") 156 | expand_mode = 1 157 | stretch_mode = 5 158 | 159 | [node name="Label" type="Label" parent="MultiSplitContainer/SplitContainerItem3"] 160 | layout_mode = 1 161 | anchors_preset = 8 162 | anchor_left = 0.5 163 | anchor_top = 0.5 164 | anchor_right = 0.5 165 | anchor_bottom = 0.5 166 | offset_left = -20.0 167 | offset_top = -11.5 168 | offset_right = 20.0 169 | offset_bottom = 11.5 170 | grow_horizontal = 2 171 | grow_vertical = 2 172 | text = "Container 3" 173 | 174 | [node name="SplitContainerItem4" type="Control" parent="MultiSplitContainer"] 175 | clip_contents = true 176 | layout_mode = 2 177 | script = ExtResource("2_uhw85") 178 | 179 | [node name="MultiSplitContainer2" type="Container" parent="MultiSplitContainer/SplitContainerItem4"] 180 | layout_mode = 1 181 | anchors_preset = 15 182 | anchor_right = 1.0 183 | anchor_bottom = 1.0 184 | grow_horizontal = 2 185 | grow_vertical = 2 186 | size_flags_horizontal = 3 187 | size_flags_vertical = 3 188 | script = ExtResource("1_hf1r7") 189 | max_columns = 1 190 | separator_line_color = Color(0.21, 0.24, 0.29, 1) 191 | separators_line_offsets = Array[float]([-22.0, 22.0]) 192 | _rect_size_editor = Vector2(1152, 648) 193 | drag_button_modulate = Color(0.605, 0.62, 0.645, 1) 194 | metadata/_custom_type_script = "uid://db6mrqis6mthu" 195 | 196 | [node name="SplitContainerItem" type="Control" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2"] 197 | clip_contents = true 198 | layout_mode = 2 199 | script = ExtResource("2_uhw85") 200 | 201 | [node name="ColorRect" type="ColorRect" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem"] 202 | self_modulate = Color(0.783524, 0.783523, 0.783523, 1) 203 | layout_mode = 1 204 | anchors_preset = 15 205 | anchor_right = 1.0 206 | anchor_bottom = 1.0 207 | grow_horizontal = 2 208 | grow_vertical = 2 209 | color = Color(0.150172, 0.683607, 0.853672, 1) 210 | 211 | [node name="TextureRect" type="TextureRect" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem"] 212 | modulate = Color(1, 1, 1, 0.470588) 213 | layout_mode = 1 214 | anchors_preset = 15 215 | anchor_right = 1.0 216 | anchor_bottom = 1.0 217 | grow_horizontal = 2 218 | grow_vertical = 2 219 | texture = ExtResource("4_82k4v") 220 | expand_mode = 1 221 | stretch_mode = 5 222 | 223 | [node name="Label" type="Label" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem"] 224 | layout_mode = 1 225 | anchors_preset = 8 226 | anchor_left = 0.5 227 | anchor_top = 0.5 228 | anchor_right = 0.5 229 | anchor_bottom = 0.5 230 | offset_left = -20.0 231 | offset_top = -11.5 232 | offset_right = 20.0 233 | offset_bottom = 11.5 234 | grow_horizontal = 2 235 | grow_vertical = 2 236 | text = "This is sub multi split with max columns 1 container 237 | Sub Container 1" 238 | label_settings = SubResource("LabelSettings_q7yv4") 239 | horizontal_alignment = 1 240 | 241 | [node name="SplitContainerItem2" type="Control" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2"] 242 | clip_contents = true 243 | layout_mode = 2 244 | script = ExtResource("2_uhw85") 245 | 246 | [node name="ColorRect" type="ColorRect" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem2"] 247 | self_modulate = Color(0.783524, 0.783523, 0.783523, 1) 248 | layout_mode = 2 249 | anchor_right = 1.0 250 | anchor_bottom = 1.0 251 | grow_horizontal = 2 252 | grow_vertical = 2 253 | color = Color(0, 0.741547, 0.519434, 1) 254 | 255 | [node name="TextureRect" type="TextureRect" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem2"] 256 | modulate = Color(1, 1, 1, 0.470588) 257 | layout_mode = 1 258 | anchors_preset = 15 259 | anchor_right = 1.0 260 | anchor_bottom = 1.0 261 | grow_horizontal = 2 262 | grow_vertical = 2 263 | texture = ExtResource("4_82k4v") 264 | expand_mode = 1 265 | stretch_mode = 5 266 | 267 | [node name="Label" type="Label" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem2"] 268 | layout_mode = 1 269 | anchors_preset = 8 270 | anchor_left = 0.5 271 | anchor_top = 0.5 272 | anchor_right = 0.5 273 | anchor_bottom = 0.5 274 | offset_left = -20.0 275 | offset_top = -11.5 276 | offset_right = 20.0 277 | offset_bottom = 11.5 278 | grow_horizontal = 2 279 | grow_vertical = 2 280 | text = "Sub Container 2" 281 | 282 | [node name="SplitContainerItem3" type="Control" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2"] 283 | clip_contents = true 284 | layout_mode = 2 285 | script = ExtResource("2_uhw85") 286 | 287 | [node name="ColorRect" type="ColorRect" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem3"] 288 | self_modulate = Color(0.783524, 0.783523, 0.783523, 1) 289 | layout_mode = 2 290 | anchor_right = 1.0 291 | anchor_bottom = 1.0 292 | grow_horizontal = 2 293 | grow_vertical = 2 294 | color = Color(0.817285, 0.196588, 0.506349, 1) 295 | 296 | [node name="TextureRect" type="TextureRect" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem3"] 297 | modulate = Color(1, 1, 1, 0.470588) 298 | layout_mode = 1 299 | anchors_preset = 15 300 | anchor_right = 1.0 301 | anchor_bottom = 1.0 302 | grow_horizontal = 2 303 | grow_vertical = 2 304 | texture = ExtResource("4_82k4v") 305 | expand_mode = 1 306 | stretch_mode = 5 307 | 308 | [node name="Label" type="Label" parent="MultiSplitContainer/SplitContainerItem4/MultiSplitContainer2/SplitContainerItem3"] 309 | layout_mode = 1 310 | anchors_preset = 8 311 | anchor_left = 0.5 312 | anchor_top = 0.5 313 | anchor_right = 0.5 314 | anchor_bottom = 0.5 315 | offset_left = -20.0 316 | offset_top = -11.5 317 | offset_right = 20.0 318 | offset_bottom = 11.5 319 | grow_horizontal = 2 320 | grow_vertical = 2 321 | text = "Sub Container 3" 322 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/example/example_scene_runtime.gd: -------------------------------------------------------------------------------- 1 | extends Control 2 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 3 | # https://github.com/CodeNameTwister/Multi-Split-Container 4 | # 5 | # Multi-Split-Container addon for godot 4 6 | # author: "Twister" 7 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 8 | 9 | 10 | func _ready() -> void: 11 | $Panel/Label.text = """Press DOWN button For Add Container Example 12 | 13 | Press UP button For Remove Container Example 14 | 15 | Press [0 - 9] number for change max columns value!""" 16 | 17 | func _create_node() -> Control: 18 | var c : ColorRect = ColorRect.new() 19 | var label : Label = Label.new() 20 | label.text = "Split Container" 21 | label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER 22 | label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER 23 | label.size_flags_horizontal = Control.SIZE_EXPAND_FILL 24 | label.size_flags_vertical = Control.SIZE_EXPAND_FILL 25 | c.size_flags_horizontal = Control.SIZE_EXPAND_FILL 26 | c.size_flags_vertical = Control.SIZE_EXPAND_FILL 27 | c.color = Color(randf_range(0.0, 1.0),randf_range(0.0, 1.0),randf_range(0.0, 1.0), 1.0) 28 | c.add_child(label) 29 | return c 30 | 31 | func _unhandled_input(event: InputEvent) -> void: 32 | if event.is_action_pressed(&"ui_down"): 33 | var n : Control = _create_node() 34 | var r : Control = get_child(1) 35 | r.add_child(n) 36 | n.size = r.size 37 | n.get_child(0).text += str(" ",n.get_index()) 38 | elif event.is_action_pressed(&"ui_up"): 39 | var n : Node = get_child(1) 40 | if n.get_child_count() > 0: 41 | n.get_child(n.get_child_count() - 1).queue_free() 42 | elif event is InputEventKey: 43 | if event.keycode == KEY_0: 44 | get_child(1).max_columns = 0 45 | elif event.keycode == KEY_1: 46 | get_child(1).max_columns = 1 47 | elif event.keycode == KEY_2: 48 | get_child(1).max_columns = 2 49 | elif event.keycode == KEY_3: 50 | get_child(1).max_columns = 3 51 | elif event.keycode == KEY_4: 52 | get_child(1).max_columns = 4 53 | elif event.keycode == KEY_5: 54 | get_child(1).max_columns = 5 55 | elif event.keycode == KEY_6: 56 | get_child(1).max_columns = 6 57 | elif event.keycode == KEY_7: 58 | get_child(1).max_columns = 7 59 | elif event.keycode == KEY_8: 60 | get_child(1).max_columns = 8 61 | elif event.keycode == KEY_9: 62 | get_child(1).max_columns = 9 63 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/example/example_scene_runtime.gd.uid: -------------------------------------------------------------------------------- 1 | uid://tpl2mn7ig66b 2 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/example/example_scene_runtime.tscn: -------------------------------------------------------------------------------- 1 | [gd_scene load_steps=3 format=3 uid="uid://cwmmpb30w0bue"] 2 | 3 | [ext_resource type="Script" uid="uid://tpl2mn7ig66b" path="res://addons/multi_spliter_container/example/example_scene_runtime.gd" id="1_117hh"] 4 | [ext_resource type="Script" uid="uid://db6mrqis6mthu" path="res://addons/multi_spliter_container/multi_split_container.gd" id="2_iutt7"] 5 | 6 | [node name="ExampleSceneChilds" type="Control"] 7 | layout_mode = 3 8 | anchors_preset = 15 9 | anchor_right = 1.0 10 | anchor_bottom = 1.0 11 | grow_horizontal = 2 12 | grow_vertical = 2 13 | script = ExtResource("1_117hh") 14 | 15 | [node name="Panel" type="Panel" parent="."] 16 | layout_mode = 1 17 | anchors_preset = 15 18 | anchor_right = 1.0 19 | anchor_bottom = 1.0 20 | grow_horizontal = 2 21 | grow_vertical = 2 22 | mouse_filter = 2 23 | 24 | [node name="Label" type="Label" parent="Panel"] 25 | layout_mode = 1 26 | anchors_preset = 15 27 | anchor_right = 1.0 28 | anchor_bottom = 1.0 29 | grow_horizontal = 2 30 | grow_vertical = 2 31 | text = "Press Play Button" 32 | horizontal_alignment = 1 33 | vertical_alignment = 1 34 | 35 | [node name="MultiSplitContainer" type="Container" parent="."] 36 | layout_mode = 1 37 | anchors_preset = 15 38 | anchor_right = 1.0 39 | anchor_bottom = 1.0 40 | grow_horizontal = 2 41 | grow_vertical = 2 42 | size_flags_horizontal = 3 43 | size_flags_vertical = 3 44 | script = ExtResource("2_iutt7") 45 | max_columns = 5 46 | separator_line_color = Color(0.21, 0.24, 0.29, 1) 47 | _rect_size_editor = Vector2(1152, 648) 48 | drag_button_modulate = Color(0.605, 0.62, 0.645, 1) 49 | metadata/_custom_type_script = "uid://db6mrqis6mthu" 50 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/icon/MultiSpliter.svg: -------------------------------------------------------------------------------- 1 | 2 | 15 | 17 | 26 | 34 | 35 | 43 | 44 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/icon/MultiSpliter.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://bjaei3q7x2hux" 6 | path="res://.godot/imported/MultiSpliter.svg-fd71c678f6c47dac814e86e1a314e8d7.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/multi_spliter_container/icon/MultiSpliter.svg" 14 | dest_files=["res://.godot/imported/MultiSpliter.svg-fd71c678f6c47dac814e86e1a314e8d7.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=8.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/icon/MultiSpliterButton.svg: -------------------------------------------------------------------------------- 1 | 2 | 16 | 18 | 36 | 44 | 45 | 53 | 59 | 65 | 71 | 77 | 83 | 89 | 90 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/icon/MultiSpliterButton.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://tjdwf71mqug4" 6 | path="res://.godot/imported/MultiSpliterButton.svg-368ce182d62c4c172bcc81e6f3b72cce.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/multi_spliter_container/icon/MultiSpliterButton.svg" 14 | dest_files=["res://.godot/imported/MultiSpliterButton.svg-368ce182d62c4c172bcc81e6f3b72cce.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=8.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/icon/MultiSpliterItem.svg: -------------------------------------------------------------------------------- 1 | 2 | 15 | 17 | 26 | 34 | 35 | 43 | 49 | 54 | 59 | 64 | 69 | 70 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/icon/MultiSpliterItem.svg.import: -------------------------------------------------------------------------------- 1 | [remap] 2 | 3 | importer="texture" 4 | type="CompressedTexture2D" 5 | uid="uid://cwvyucfkxwjqw" 6 | path="res://.godot/imported/MultiSpliterItem.svg-6b9028d1ab1bb6441892f346421119eb.ctex" 7 | metadata={ 8 | "vram_texture": false 9 | } 10 | 11 | [deps] 12 | 13 | source_file="res://addons/multi_spliter_container/icon/MultiSpliterItem.svg" 14 | dest_files=["res://.godot/imported/MultiSpliterItem.svg-6b9028d1ab1bb6441892f346421119eb.ctex"] 15 | 16 | [params] 17 | 18 | compress/mode=0 19 | compress/high_quality=false 20 | compress/lossy_quality=0.7 21 | compress/hdr_compression=1 22 | compress/normal_map=0 23 | compress/channel_pack=0 24 | mipmaps/generate=false 25 | mipmaps/limit=-1 26 | roughness/mode=0 27 | roughness/src_normal="" 28 | process/fix_alpha_border=true 29 | process/premult_alpha=false 30 | process/normal_map_invert_y=false 31 | process/hdr_as_srgb=false 32 | process/hdr_clamp_exposure=false 33 | process/size_limit=0 34 | detect_3d/compress_to=1 35 | svg/scale=8.0 36 | editor/scale_with_editor_scale=false 37 | editor/convert_colors_with_editor_theme=false 38 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/multi_split_container.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | @icon("icon/MultiSpliter.svg") 3 | extends Container 4 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 5 | # https://github.com/CodeNameTwister/Multi-Split-Container 6 | # 7 | # Multi-Split-Container addon for godot 4 8 | # author: "Twister" 9 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 10 | 11 | const SplitContainerItem : Script = preload("res://addons/multi_spliter_container/split_container_item.gd") 12 | const SplitButton : Texture = preload("res://addons/multi_spliter_container/icon/MultiSpliterButton.svg") 13 | 14 | @export_category("Multi-Split Settings") 15 | ## Max columns by rows, after added childs this is eparated by row group by columns size! 16 | ## [br][br] 17 | ## if this value is 0, will not create rows spliters. 18 | @export_range(0.0, 1000.0, 1.0) var max_columns : int = 0: 19 | set(e): 20 | max_columns = maxi(0, e) 21 | 22 | #if Engine.is_editor_hint(): 23 | #for x : int in range(separators_line_offsets.size()): 24 | #separators_line_offsets[x] = 0.0 25 | for x : LineSep in _separators: 26 | x.queue_free() 27 | 28 | _separators.clear() 29 | _first = true 30 | update() 31 | 32 | @export_group("Line Separator", "separator_line") 33 | ## Line separator size. 34 | @export var separator_line_size : float = 4.0: 35 | set(e): 36 | separator_line_size = max(e, 0.0) 37 | update() 38 | 39 | ## Separator line color. 40 | @export var separator_line_color : Color = Color.MAGENTA: 41 | set(e): 42 | separator_line_color = e 43 | if separator_line_color == Color.MAGENTA: # That color reminds me of texture not found errors. 44 | var root : Control = EditorInterface.get_base_control() 45 | separator_line_color = root.get_theme_color("base_color", "Editor") 46 | update() 47 | 48 | ## Separator line visibility. 49 | @export var separator_line_visible : bool = true: 50 | set(e): 51 | separator_line_visible = e 52 | for l : LineSep in _separators: 53 | l.visible = separator_line_visible 54 | 55 | @export_subgroup("Behaviour", "behaviour_") 56 | ## Enable function for auto expand lines container on inside focus. 57 | @export var behaviour_expand_on_focus : bool = true 58 | 59 | ## Enable function for auto expand lines container on double click in the line. 60 | @export var behaviour_expand_on_double_click : bool = true: 61 | set(e): 62 | behaviour_expand_on_double_click = e 63 | for l : LineSep in _separators: 64 | l.double_click_handler = behaviour_expand_on_double_click 65 | 66 | ## This allow expand you current focused container if you shrunk it. 67 | @export var behaviour_can_expand_focus_same_container : bool = false 68 | 69 | ## Enable smooth when expand container. 70 | @export var behaviour_expand_smoothed : bool = true: 71 | set(e): 72 | behaviour_expand_smoothed = e 73 | if !e: 74 | if _tween and _tween.is_running(): 75 | _tween.kill() 76 | _tween = null 77 | 78 | ## Time speed duration for reset expand container. 79 | @export_range(0.01, 1000.0, 0.01) var behaviour_expand_smoothed_time : float = 0.24: 80 | set(e): 81 | behaviour_expand_smoothed_time = maxf(0.01, e) 82 | if _tween and _tween.is_running(): 83 | _tween.kill() 84 | _tween = null 85 | 86 | ## Custom initial offset for separator lines. 87 | @export var separators_line_offsets : Array[float] : 88 | set(e): 89 | separators_line_offsets = e 90 | 91 | if Engine.is_editor_hint() and is_node_ready(): 92 | if separators_line_offsets.size() != _separators.size(): 93 | separators_line_offsets.resize(_separators.size()) 94 | update() 95 | 96 | @export_storage var _rect_size_editor : Vector2 = Vector2i.ZERO: 97 | get: 98 | if Engine.is_editor_hint() or _rect_size_editor == Vector2.ZERO: 99 | _rect_size_editor = Vector2(ProjectSettings.get_setting("display/window/size/viewport_width"), ProjectSettings.get_setting("display/window/size/viewport_height")) 100 | return _rect_size_editor 101 | 102 | @export_subgroup("Drag Button", "drag_button") 103 | 104 | ## Set if drag button always be visible (Useful for test button size) 105 | @export var drag_button_always_visible : bool = false: 106 | set(e): 107 | drag_button_always_visible = e 108 | 109 | var min_visible_drag_button : float = 0.0 110 | if drag_button_always_visible: 111 | min_visible_drag_button = 0.4 112 | 113 | for l : LineSep in _separators: 114 | if l.button: 115 | l.button.modulate.a = 0.0 116 | l.button.min_no_focus_transparense = min_visible_drag_button 117 | 118 | ## Min size for drag button visible on split lines. 119 | @export_range(1.0, 200.0, 0.1) var drag_button_size : float = 24.0: 120 | set(e): 121 | drag_button_size = e 122 | update() 123 | 124 | ## Modulate color for the drag button. 125 | @export var drag_button_modulate : Color = Color.MAGENTA: 126 | set(e): 127 | drag_button_modulate = e 128 | if drag_button_modulate == Color.MAGENTA: 129 | if Engine.is_editor_hint(): 130 | var root : Control = EditorInterface.get_base_control() 131 | drag_button_modulate = root.get_theme_color("base_color", "Editor").lightened(0.5) 132 | update() 133 | 134 | ## Change default drag button icon. 135 | @export var drag_button_icon : Texture = null: 136 | set(e): 137 | drag_button_icon = e 138 | update() 139 | 140 | var _separators : Array[LineSep] = [] 141 | var _last_container_focus : Node = null 142 | var _first : bool = true 143 | var _tween : Tween = null 144 | 145 | #region __editor__ 146 | var _last_undoredo : UndoredoSplit = null 147 | #endregion 148 | 149 | ## Get line begin offset limit. 150 | func get_line_seperator_left_offset_limit(index : int) -> float: 151 | if index < _separators.size(): 152 | var line_sep : LineSep = _separators[index] 153 | if !line_sep.is_vertical: 154 | if index < 1: 155 | return -_separators[index].initial_position.x 156 | var next : LineSep = _separators[index - 1] 157 | return (next.initial_position.x + (next.size.x/2.0)) - _separators[index].initial_position.x 158 | else: 159 | if index < 1: 160 | return -_separators[index].initial_position.y 161 | var next : LineSep = _separators[index - 1] 162 | return (next.initial_position.y + (next.size.y/2.0)) - _separators[index].initial_position.y 163 | push_warning("[PLUGIN] Not valid index for line separator!") 164 | return 0.0 165 | 166 | ## Get line end offset limit. 167 | func get_line_seperator_right_offset_limit(index : int) -> float: 168 | if index < _separators.size(): 169 | var line_sep : LineSep = _separators[index] 170 | if !line_sep.is_vertical: 171 | if index + 1 == _separators.size(): 172 | return (size.x/2.0) -_separators[index].initial_position.x 173 | var current : LineSep = _separators[index] 174 | return (_separators[index + 1].initial_position.x - current.initial_position.x + (current.size.x/2.0)) 175 | else: 176 | if index + 1 == _separators.size(): 177 | return size.x -_separators[index].initial_position.y 178 | var current : LineSep = _separators[index] 179 | return (_separators[index + 1].initial_position.y - current.initial_position.y + (current.size.y/2.0)) 180 | push_warning("[PLUGIN] Not valid index for line separator!") 181 | return 0.0 182 | 183 | # This is function is util when you want expand or constraint manualy offset. 184 | ## Update offset of the line 185 | func update_line_separator_offset(index : int, offset : float) -> void: 186 | var line_sep : LineSep = _separators[index] 187 | line_sep.offset = offset 188 | line_sep.force_update() 189 | 190 | ## Get total line count. 191 | func get_line_separator_count() -> int: 192 | return _separators.size() 193 | 194 | ## Get Line reference by index, see get_line_separator_count() 195 | func get_line_separator(index : int) -> LineSep: 196 | return _separators[index] 197 | 198 | ## Get if line separator is vertical. 199 | func is_vertical_line_separator(index : int) -> bool: 200 | if index < _separators.size(): 201 | return _separators[index].is_vertical 202 | push_warning("[PLUGIN] Not valid index for line separator!") 203 | return false 204 | 205 | ## Expand splited container by index container. 206 | func expand_splited_container(node : Node) -> void: 207 | var same : bool = _last_container_focus == node 208 | 209 | if same and !behaviour_can_expand_focus_same_container: 210 | return 211 | 212 | _last_container_focus = node 213 | 214 | if !behaviour_expand_on_focus: 215 | return 216 | 217 | if _tween and _tween.is_running(): 218 | if same: 219 | return 220 | _tween.kill() 221 | _tween = null 222 | 223 | var top_lines : Array[LineSep] = [] 224 | var bottom_lines : Array[LineSep] = [] 225 | 226 | var update_required : bool = false 227 | 228 | if separators_line_offsets.size() > 0: 229 | for x : int in range(0, _separators.size(), 1): 230 | var line : LineSep = _separators[x] 231 | if x < separators_line_offsets.size(): 232 | if node in line.top_items: 233 | update_required = update_required or line.offset < _get_custom_offset(x, line.is_vertical) 234 | top_lines.append(line) 235 | elif node in line.bottom_items: 236 | update_required = update_required or line.offset > _get_custom_offset(x, line.is_vertical) 237 | bottom_lines.append(line) 238 | else: 239 | if node in line.top_items: 240 | update_required = update_required or line.offset < 0.0 241 | top_lines.append(line) 242 | elif node in line.bottom_items: 243 | update_required = update_required or line.offset > 0.0 244 | bottom_lines.append(line) 245 | else: 246 | for line : LineSep in _separators: 247 | if node in line.top_items: 248 | update_required = update_required or line.offset < 0.0 249 | top_lines.append(line) 250 | elif node in line.bottom_items: 251 | update_required = update_required or line.offset > 0.0 252 | bottom_lines.append(line) 253 | 254 | if update_required: 255 | if behaviour_expand_smoothed: 256 | _tween = get_tree().create_tween() 257 | _tween.tween_method(_reset_expanded_lines.bind(top_lines, bottom_lines), 0.0, 1.0, behaviour_expand_smoothed_time) 258 | else: 259 | _reset_expanded_lines(1.0, top_lines, bottom_lines) 260 | 261 | func _reset_expanded_lines(lerp_value : float, top_lines : Array[LineSep], bottom_lines : Array[LineSep]) -> void: 262 | 263 | if separators_line_offsets.size() > 0: 264 | for iline : int in range(top_lines.size() - 1, -1, -1): 265 | var line : LineSep = top_lines[iline] 266 | if is_instance_valid(line): 267 | var index : int = _separators.find(line) 268 | if index < separators_line_offsets.size(): 269 | var custom_offset : float = _get_custom_offset(index, line.is_vertical) 270 | if line.offset < custom_offset: 271 | line.offset = lerp(line.offset, custom_offset, lerp_value) 272 | else: 273 | if line.offset < 0.0: 274 | line.offset = lerp(line.offset, 0.0, lerp_value) 275 | else: 276 | top_lines.remove_at(iline) 277 | 278 | for iline : int in range(bottom_lines.size() - 1, -1, -1): 279 | var line : LineSep = bottom_lines[iline] 280 | if is_instance_valid(line): 281 | var index : int = _separators.find(line) 282 | if index < separators_line_offsets.size(): 283 | var custom_offset : float = _get_custom_offset(index, line.is_vertical) 284 | if line.offset > custom_offset: 285 | line.offset = lerp(line.offset, custom_offset, lerp_value) 286 | else: 287 | if line.offset > 0.0: 288 | line.offset = lerp(line.offset, 0.0, lerp_value) 289 | else: 290 | bottom_lines.remove_at(iline) 291 | else: 292 | for iline : int in range(top_lines.size() - 1, -1, -1): 293 | var line : LineSep = top_lines[iline] 294 | if is_instance_valid(line): 295 | if line.offset < 0.0: 296 | line.offset = lerp(line.offset, 0.0, lerp_value) 297 | else: 298 | top_lines.remove_at(iline) 299 | 300 | for iline : int in range(bottom_lines.size() - 1, -1, -1): 301 | var line : LineSep = bottom_lines[iline] 302 | if is_instance_valid(line): 303 | if line.offset > 0.0: 304 | line.offset = lerp(line.offset, 0.0, lerp_value) 305 | else: 306 | bottom_lines.remove_at(iline) 307 | 308 | for line : LineSep in top_lines: 309 | line.force_update() 310 | for line : LineSep in bottom_lines: 311 | line.force_update() 312 | 313 | 314 | ## Get initial position of a separator line. 315 | func get_line_separator_initial_position(index : int) -> Vector2: 316 | if index < _separators.size(): 317 | return _separators[index].initial_position 318 | push_warning("[PLUGIN] Not valid index for line separator!") 319 | return Vector2.ZERO 320 | 321 | class DragButton extends Button: 322 | var _frm : float = 0.0 323 | var _line_sep : LineSep = null 324 | var _is_pressed : bool = false 325 | 326 | var is_hover : bool = false 327 | 328 | var _hover : Array[bool] = [false, false] 329 | 330 | var min_no_focus_transparense : float = 0.0: 331 | set(e): 332 | min_no_focus_transparense = e 333 | modulate.a = maxf(modulate.a, min_no_focus_transparense) 334 | 335 | static var DEFAULT_STYLE : StyleBox = null 336 | 337 | func set_drag_icon(new_icon : Texture) -> void: 338 | if icon != new_icon: 339 | if new_icon == null: 340 | icon = SplitButton 341 | return 342 | icon = new_icon 343 | 344 | func update_gui() -> void: 345 | if !_line_sep: 346 | return 347 | 348 | if _line_sep.is_vertical: 349 | _line_sep.mouse_default_cursor_shape = Control.CURSOR_VSPLIT 350 | mouse_default_cursor_shape = Control.CURSOR_VSPLIT 351 | else: 352 | _line_sep.mouse_default_cursor_shape = Control.CURSOR_HSPLIT 353 | mouse_default_cursor_shape = Control.CURSOR_HSPLIT 354 | 355 | func set_line(line_sep : LineSep) -> void: 356 | if _line_sep: 357 | if _line_sep.mouse_entered.is_connected(_on_enter): 358 | _line_sep.mouse_entered.disconnect(_on_enter) 359 | if _line_sep.mouse_exited.is_connected(_on_exit): 360 | _line_sep.mouse_exited.disconnect(_on_exit) 361 | if _line_sep.gui_input.is_connected(_on_input): 362 | _line_sep.gui_input.disconnect(_on_input) 363 | 364 | _line_sep = line_sep 365 | 366 | if _line_sep: 367 | if !_line_sep.mouse_entered.is_connected(_on_enter): 368 | _line_sep.mouse_entered.connect(_on_enter.bind(1)) 369 | if !_line_sep.mouse_exited.is_connected(_on_exit): 370 | _line_sep.mouse_exited.connect(_on_exit.bind(1)) 371 | if !_line_sep.gui_input.is_connected(_on_input): 372 | _line_sep.gui_input.connect(_on_input) 373 | 374 | 375 | func _init(line_sep : LineSep = null) -> void: 376 | modulate.a = 0.0 377 | 378 | set_line(line_sep) 379 | 380 | button_down.connect(_on_press) 381 | button_up.connect(_out_press) 382 | mouse_entered.connect(_on_enter.bind(0)) 383 | mouse_exited.connect(_on_exit.bind(0)) 384 | 385 | icon = SplitButton 386 | icon_alignment = HORIZONTAL_ALIGNMENT_CENTER 387 | vertical_icon_alignment = VERTICAL_ALIGNMENT_CENTER 388 | expand_icon = true 389 | 390 | if null != icon: 391 | flat = true 392 | 393 | if DEFAULT_STYLE == null: 394 | DEFAULT_STYLE = StyleBoxEmpty.new() 395 | 396 | focus_mode = Control.FOCUS_CLICK 397 | 398 | set(&"theme_override_styles/focus", DEFAULT_STYLE) 399 | set(&"theme_override_styles/disabled_mirrored", DEFAULT_STYLE) 400 | set(&"theme_override_styles/disabled", DEFAULT_STYLE) 401 | set(&"theme_override_styles/hover_pressed_mirrored", DEFAULT_STYLE) 402 | set(&"theme_override_styles/hover_pressed", DEFAULT_STYLE) 403 | set(&"theme_override_styles/hover_mirrored", DEFAULT_STYLE) 404 | set(&"theme_override_styles/hover", DEFAULT_STYLE) 405 | set(&"theme_override_styles/pressed_mirrored", DEFAULT_STYLE) 406 | set(&"theme_override_styles/pressed", DEFAULT_STYLE) 407 | set(&"theme_override_styles/normal_mirrored", DEFAULT_STYLE) 408 | set(&"theme_override_styles/normal", DEFAULT_STYLE) 409 | 410 | z_as_relative = true 411 | z_index = 2000 412 | 413 | update_gui() 414 | 415 | func _on_input(e : InputEvent) -> void: 416 | if e is InputEventMouseButton: 417 | if e.pressed and e.double_click: 418 | if _line_sep and _line_sep.double_click_handler: 419 | _line_sep.offset = 0.0 420 | _line_sep.offset_updated.emit() 421 | elif e.pressed and e.button_index == 1: 422 | button_down.emit() 423 | elif !e.pressed and e.button_index == 1: 424 | button_up.emit() 425 | 426 | func set_line_sep_reference(ref : LineSep) -> void: 427 | _line_sep = ref 428 | 429 | func _ready() -> void: 430 | set_process(false) 431 | 432 | func _on_enter(x : int = 0) -> void: 433 | _hover[x] = true 434 | 435 | _frm = 0.0 436 | modulate.a = 1.0 437 | is_hover = true 438 | set_process(true) 439 | 440 | func _on_exit(x : int = 0) -> void: 441 | _hover[x] = false 442 | 443 | for h : bool in _hover: 444 | if h != false: 445 | return 446 | 447 | _frm = 0.0 448 | modulate.a = 1.0 449 | is_hover = false 450 | set_process(true) 451 | 452 | func _on_press() -> void: 453 | _is_pressed = true 454 | _frm = 0.0 455 | modulate.a = 1.0 456 | set_process(true) 457 | 458 | func _out_press() -> void: 459 | _is_pressed = false 460 | set_process(true) 461 | 462 | func _process(delta : float) -> void: 463 | if !has_focus() and !is_hover: 464 | _frm += delta * 0.4 465 | if _frm >= 1.0: 466 | _frm = 1.0 467 | set_process(false) 468 | modulate.a = lerp(modulate.a, min_no_focus_transparense, _frm) 469 | if _is_pressed: 470 | var mpos : Vector2 = _line_sep.get_parent().get_local_mouse_position() 471 | if mpos != get_rect().get_center(): 472 | _line_sep.update_offset_by_position(mpos) 473 | 474 | class UndoredoSplit extends RefCounted: 475 | var object : SplitContainerItem = null 476 | var c_objects : Array[Node] = [] 477 | 478 | class LineSep extends ColorRect: 479 | signal offset_updated() 480 | 481 | var top_lines : Array[LineSep] = [] 482 | var bottom_lines : Array[LineSep] = [] 483 | 484 | var top_items : Array[Control] = [] 485 | var bottom_items : Array[Control] = [] 486 | 487 | var is_vertical : bool = false: 488 | set(e): 489 | is_vertical = e 490 | 491 | if button: 492 | button.update_gui() 493 | 494 | var row : int = 0 495 | 496 | var initial_position : Vector2 = Vector2.ZERO 497 | 498 | var offset : float = 0.0 499 | 500 | var min_size_offset : float = 0.0 501 | 502 | var prev_line : LineSep = null 503 | var next_line : LineSep = null 504 | 505 | var button : DragButton = null 506 | 507 | var double_click_handler : bool = true 508 | 509 | func set_next_line(next : LineSep = null) -> void: 510 | next_line = next 511 | next.prev_line = self 512 | 513 | func clear() -> void: 514 | top_items.clear() 515 | bottom_items.clear() 516 | top_lines.clear() 517 | bottom_lines.clear() 518 | 519 | func reset() -> void: 520 | position = initial_position 521 | update_items() 522 | 523 | func update_items() -> void: 524 | if is_vertical: 525 | for item : Control in top_items: 526 | item.size.y = position.y - item.position.y 527 | if !prev_line: 528 | item.position.y = 0.0 529 | 530 | for item : Control in bottom_items: 531 | item.position.y = position.y + size.y 532 | 533 | if next_line: 534 | item.size.y = next_line.position.y - item.position.y 535 | else: 536 | item.size.y = get_parent().size.y - item.position.y 537 | else: 538 | for item : Control in top_items: 539 | item.size.x = position.x - item.position.x 540 | if !prev_line: 541 | item.position.x = 0.0 542 | 543 | for item : Control in bottom_items: 544 | var diff : float = position.x + size.x 545 | item.position.x = diff 546 | 547 | if next_line: 548 | item.size.x = next_line.position.x - item.position.x 549 | else: 550 | item.size.x = get_parent().size.x - item.position.x 551 | 552 | func force_update() -> void: 553 | update_offset_by_position(initial_position + Vector2(offset * int(!is_vertical), offset * int(is_vertical))) 554 | 555 | func get_current_position() -> Vector2: 556 | return initial_position + Vector2(offset * int(!is_vertical), offset * int(is_vertical)) 557 | 558 | func update_offset_by_position(vpos : Vector2) -> void: 559 | if is_vertical: 560 | min_size_offset = 0.0 561 | for x : Control in top_items: 562 | min_size_offset = maxf(min_size_offset, x.get_minimum_size().y) 563 | if prev_line: 564 | prev_line.min_size_offset = 0.0 565 | for x : Control in prev_line.bottom_items: 566 | prev_line.min_size_offset = maxf(prev_line.min_size_offset, x.get_minimum_size().y) 567 | 568 | offset = vpos.y - initial_position.y 569 | offset = minf(offset, get_parent().size.y - (initial_position.y + size.y + min_size_offset)) 570 | offset = maxf(offset, -(initial_position.y - min_size_offset)) 571 | 572 | if next_line: 573 | var val : float = next_line.position.y - (initial_position.y + size.y + min_size_offset) 574 | if offset > val: 575 | offset = val 576 | else: 577 | var val : float = get_parent().size.y - (initial_position.y + (size.y / 2.0) + min_size_offset) 578 | if offset > val: 579 | offset = val 580 | if prev_line: 581 | var val : float = -(initial_position.y - (prev_line.position.y + prev_line.size.y + prev_line.min_size_offset)) 582 | 583 | if offset < val: 584 | offset = val 585 | else: 586 | var top_size_offset : float = 0.0 587 | for x : Control in top_items: 588 | top_size_offset = maxf(top_size_offset, x.get_minimum_size().y) 589 | offset = maxf(offset, top_size_offset-initial_position.y) 590 | 591 | position.y = initial_position.y + offset 592 | 593 | for line : LineSep in top_lines: 594 | line.size.y = position.y - line.position.y 595 | 596 | for line : LineSep in bottom_lines: 597 | line.position.y = position.y + size.y 598 | 599 | if next_line: 600 | line.size.y = next_line.position.y - line.position.y 601 | else: 602 | line.size.y = get_parent().size.y - line.position.y 603 | else: 604 | min_size_offset = 0.0 605 | for x : Control in bottom_items: 606 | min_size_offset = maxf(min_size_offset, x.get_minimum_size().x) 607 | 608 | if prev_line: 609 | prev_line.min_size_offset = 0.0 610 | for x : Control in prev_line.bottom_items: 611 | prev_line.min_size_offset = maxf(prev_line.min_size_offset, x.get_minimum_size().x) 612 | 613 | offset = vpos.x - initial_position.x 614 | offset = minf(offset, get_parent().size.x - (initial_position.x + size.x + min_size_offset)) 615 | offset = maxf(offset, -initial_position.x) 616 | 617 | if next_line: 618 | var val : float = next_line.position.x - (initial_position.x + size.x + min_size_offset) 619 | if offset > val: 620 | offset = val 621 | else: 622 | var val : float = get_parent().size.x - (initial_position.x + (size.x/2.0) + min_size_offset) 623 | if offset > val: 624 | offset = val 625 | if prev_line: 626 | var val : float = -(initial_position.x - (prev_line.position.x + prev_line.size.x + prev_line.min_size_offset)) 627 | 628 | if offset < val: 629 | offset = val 630 | else: 631 | var top_size_offset : float = 0.0 632 | for x : Control in top_items: 633 | top_size_offset = maxf(top_size_offset, x.get_minimum_size().x) 634 | offset = maxf(offset, top_size_offset-initial_position.x) 635 | 636 | position.x = initial_position.x + offset 637 | update_items() 638 | 639 | func _draw() -> void: 640 | update() 641 | 642 | func update() -> void: 643 | button.rotation_degrees = 90.0 * int(is_vertical) 644 | button.pivot_offset = button.size / 2.0 645 | button.position = size / 2.0 - button.pivot_offset 646 | 647 | 648 | 649 | func _init() -> void: 650 | color = Color.RED 651 | 652 | func _ready() -> void: 653 | name = "SplitLine" 654 | if button == null: 655 | button = DragButton.new(self) 656 | add_child(button, false, Node.INTERNAL_MODE_BACK) 657 | 658 | func _test() -> void: 659 | queue_redraw() 660 | 661 | func _init() -> void: 662 | child_entered_tree.connect(_on_enter) 663 | child_exiting_tree.connect(_on_exiting) 664 | 665 | func update() -> void: 666 | set_process(true) 667 | 668 | func _create_separator() -> Control: 669 | var line_sep : LineSep = LineSep.new() 670 | line_sep.offset_updated.connect(update) 671 | return line_sep 672 | 673 | func _undoredo_do(ur : UndoredoSplit) -> void: 674 | if !is_instance_valid(ur): 675 | return 676 | 677 | var split : SplitContainerItem = ur.object 678 | if is_instance_valid(split): 679 | if split.get_parent() == null: 680 | add_child(split) 681 | elif ur.c_objects.size() > 0: 682 | var container : SplitContainerItem = SplitContainerItem.new() 683 | 684 | for c : Node in ur.c_objects: 685 | if c.get_parent() != null: 686 | c.get_parent().remove_child(c) 687 | container.add_child(c) 688 | 689 | add_child(container) 690 | 691 | if Engine.is_editor_hint(): 692 | if owner: 693 | _recuva(container, owner) 694 | else: 695 | _recuva(container, EditorInterface.get_edited_scene_root()) 696 | ur.object = container 697 | 698 | func _recuva(x : Node, _owner : Node) -> void: 699 | if x is DragButton: 700 | return 701 | elif x is LineSep: 702 | return 703 | if x.owner == null: 704 | x.owner = _owner 705 | for z : Node in x.get_children(): 706 | if z.owner == null: 707 | z.owner = _owner 708 | _recuva(z, _owner) 709 | 710 | func _undoredo_undo(ur : UndoredoSplit) -> void: 711 | if !is_instance_valid(ur): 712 | return 713 | 714 | var split : SplitContainerItem = ur.object 715 | if is_instance_valid(split): 716 | if split.get_parent() == self: 717 | ur.c_objects = split.get_children() 718 | for x : Node in ur.c_objects: 719 | split.remove_child(x) 720 | if x is Control: 721 | x.visible = false 722 | add_child(x) 723 | if is_instance_valid(split) and split.get_parent() == self: 724 | remove_child(split) 725 | 726 | func _update() -> void: 727 | var items : Array[Control] = [] 728 | for x : Node in get_children(): 729 | if is_instance_valid(x) and x is Control: 730 | if x.visible and !x.is_queued_for_deletion(): 731 | if x is SplitContainerItem: 732 | if x.get_child_count() > 0: 733 | var _is_visible : bool = false 734 | for y : Node in x.get_children(): 735 | if y is Control and y.visible: 736 | _is_visible = true 737 | break 738 | if !_is_visible: 739 | continue 740 | else: 741 | x.queue_free() 742 | continue 743 | elif x is DragButton or x is LineSep: 744 | x.queue_free() 745 | continue 746 | else: 747 | var container : SplitContainerItem = SplitContainerItem.new() 748 | 749 | add_child(container, true) 750 | 751 | if Engine.is_editor_hint(): 752 | var undoredo : EditorUndoRedoManager = EditorInterface.get_editor_undo_redo() 753 | 754 | var id : int = undoredo.get_object_history_id(x) 755 | var _undoredo : UndoRedo = undoredo.get_history_undo_redo(id) 756 | 757 | var current : String = _undoredo.get_current_action_name() 758 | if current == "Create Node": 759 | var _ur : UndoredoSplit = UndoredoSplit.new() 760 | 761 | _ur.object = container 762 | 763 | undoredo.create_action(current + "2",UndoRedo.MERGE_ALL, null, true) 764 | undoredo.add_do_method(self, "_undoredo_do", _ur) 765 | undoredo.add_undo_method(self, "_undoredo_undo", _ur) 766 | undoredo.force_fixed_history() 767 | undoredo.add_do_reference(_ur) 768 | 769 | if _last_undoredo: 770 | undoredo.add_undo_reference(_last_undoredo) 771 | 772 | _last_undoredo = _ur 773 | 774 | undoredo.commit_action(false) 775 | 776 | if owner: 777 | _recuva(container, owner) 778 | else: 779 | _recuva(container, EditorInterface.get_edited_scene_root()) 780 | 781 | x.reparent(container) 782 | x = container 783 | 784 | 785 | x.size_flags_horizontal = Control.SIZE_FILL 786 | x.size_flags_vertical = Control.SIZE_FILL 787 | x.clip_contents = true 788 | x.custom_minimum_size = Vector2.ZERO 789 | items.append(x) 790 | 791 | var totals : int = items.size() 792 | var rows : int = 0 793 | 794 | if max_columns > 0: 795 | var _totals : int = totals 796 | rows = 0 797 | while _totals > max_columns: 798 | _totals -= max_columns 799 | rows += 1 800 | totals -= rows 801 | 802 | if totals < 1: 803 | for x : int in range(0, _separators.size(), 1): 804 | _separators[x].queue_free() 805 | _separators[x] = null 806 | _separators.clear() 807 | 808 | for x : Control in items: 809 | x.position = Vector2.ZERO 810 | x.size = get_rect().size 811 | return 812 | else: 813 | if separator_line_size <= 0.0: 814 | for x : int in range(0, _separators.size(), 1): 815 | _separators[x].queue_free() 816 | _separators[x] = null 817 | _separators.clear() 818 | else: 819 | var sep : int = totals - 1 + rows 820 | for x : int in range(sep, _separators.size(), 1): 821 | _separators[x].queue_free() 822 | _separators[x] = null 823 | _separators.resize(sep) 824 | for x : int in range(0, _separators.size(), 1): 825 | if _separators[x] == null: 826 | _separators[x] = _create_separator() 827 | 828 | rows += 1 829 | if max_columns > 1: 830 | if totals > max_columns: 831 | totals = max_columns 832 | 833 | var rect_size : Vector2 = get_rect().size 834 | var start_position : Vector2 = Vector2.ZERO 835 | 836 | var size_split : Vector2 = (rect_size / Vector2(totals, rows)) 837 | 838 | var size_sep : Vector2 = Vector2.ONE * separator_line_size 839 | 840 | if totals > 1: 841 | size_sep = (size_sep / (totals - 1)) 842 | 843 | var item_size : Vector2 = Vector2(size_split.x, size_split.y) 844 | var line_size : Vector2 = Vector2(separator_line_size, item_size.y) 845 | 846 | var total_items : int = items.size() 847 | 848 | var vpos : Vector2 = Vector2.ZERO 849 | var current_row : int = 0 850 | 851 | var item_index : int = 0 852 | 853 | var last_vline : LineSep = null 854 | var last_hline : LineSep = null 855 | 856 | for x : Control in items: 857 | x.position = Vector2.ZERO 858 | x.size = x.get_minimum_size() 859 | 860 | for z : int in range(_separators.size()): 861 | var x : LineSep = _separators[z] 862 | 863 | x.clear() 864 | 865 | start_position.x += 1 866 | 867 | if 0 < max_columns and start_position.x + 1 > max_columns: 868 | total_items -= max_columns 869 | start_position.x = 0.0 870 | start_position.y += 1.0 871 | current_row += 1 872 | if total_items <= max_columns and total_items > 0: 873 | size_split = (rect_size / Vector2(total_items, rows)) 874 | if total_items == 1: 875 | size_sep = Vector2.ONE * separator_line_size 876 | else: 877 | size_sep = ((Vector2.ONE * separator_line_size) / (total_items - 1)) 878 | item_size = Vector2(size_split.x, size_split.y) 879 | line_size = Vector2(separator_line_size, rect_size.y - x.position.y) 880 | 881 | vpos = Vector2(0.0, start_position.y) * item_size 882 | x.is_vertical = true 883 | 884 | if x.get_parent() == null: 885 | add_child(x, false, Node.INTERNAL_MODE_BACK) 886 | 887 | 888 | x.row = current_row 889 | 890 | if items.size() > 0: 891 | var it : int = mini(item_index, items.size() - 1) 892 | var min_size : float = 0.0 893 | 894 | var _has : bool = false 895 | 896 | for y : int in range(z - 1, -1, -1): 897 | if it > -1: 898 | var item : Control = items[it] 899 | x.top_items.append(item) 900 | min_size = maxf(item.get_minimum_size().y, min_size) 901 | it -= 1 902 | 903 | var ln : LineSep = _separators[y] 904 | if ln.is_vertical: 905 | _has = true 906 | break 907 | x.top_lines.append(ln) 908 | if !_has: 909 | for _it : int in range(it, -1, -1): 910 | var item : Control = items[it] 911 | x.top_items.append(item) 912 | 913 | if item_index + 1 < items.size(): 914 | it = item_index + 1 915 | _has = false 916 | for y : int in range(z + 1, _separators.size(), 1): 917 | if it < items.size(): 918 | var item : Control = items[it] 919 | x.bottom_items.append(item) 920 | it += 1 921 | 922 | var ln : LineSep = _separators[y] 923 | if ln.is_vertical: 924 | _has = true 925 | break 926 | x.bottom_lines.append(ln) 927 | if !_has: 928 | for _it : int in range(it, items.size(), 1): 929 | var item : Control = items[_it] 930 | x.bottom_items.append(item) 931 | 932 | var vline_size : Vector2 = Vector2(rect_size.x, separator_line_size) 933 | 934 | x.initial_position = vpos 935 | x.initial_position.y -= (vline_size.y) / 2.0 936 | x.position = x.initial_position 937 | 938 | x.button.size = Vector2(drag_button_size, drag_button_size) 939 | 940 | x.set(&"size", vline_size) 941 | x.update() 942 | 943 | if last_vline: 944 | last_vline.set_next_line(x) 945 | 946 | last_vline = x 947 | last_hline = null 948 | item_index += 1 949 | continue 950 | 951 | vpos = start_position * item_size 952 | 953 | if x.get_parent() == null: 954 | add_child(x, false, Node.INTERNAL_MODE_BACK) 955 | 956 | 957 | if item_index < items.size(): 958 | var item : Control = items[item_index] 959 | x.top_items.append(item) 960 | item_index += 1 961 | if item_index < items.size(): 962 | if z + 1 < _separators.size(): 963 | if !_separators[z].is_vertical: 964 | x.bottom_items.append(items[item_index]) 965 | else: 966 | x.bottom_items.append(items[item_index]) 967 | 968 | x.initial_position = vpos 969 | x.initial_position.x -= (line_size.x) / 2.0 970 | 971 | x.button.size = Vector2(drag_button_size, drag_button_size) 972 | 973 | x.row = current_row 974 | x.position = x.initial_position 975 | 976 | x.set(&"size", line_size) 977 | x.update() 978 | 979 | if last_hline: 980 | last_hline.set_next_line(x) 981 | last_hline = x 982 | 983 | for x : Control in items: 984 | x.size = size 985 | 986 | var min_visible_drag_button : float = 0.0 987 | if drag_button_always_visible: 988 | min_visible_drag_button = 0.4 989 | 990 | if _first: 991 | for l : LineSep in _separators: 992 | l.visible = separator_line_visible 993 | l.color = separator_line_color 994 | l.double_click_handler = behaviour_expand_on_double_click 995 | l.button.self_modulate = drag_button_modulate 996 | l.button.min_no_focus_transparense = min_visible_drag_button 997 | l.button.set_drag_icon(drag_button_icon) 998 | 999 | l.reset() 1000 | 1001 | else: 1002 | if separators_line_offsets.size() > 0: 1003 | if Engine.is_editor_hint(): 1004 | for l : int in range(0, _separators.size(), 1): 1005 | if l < separators_line_offsets.size(): 1006 | _separators[l].offset = separators_line_offsets[l] 1007 | continue 1008 | break 1009 | else: 1010 | for l : int in range(0, _separators.size(), 1): 1011 | var line : LineSep = _separators[l] 1012 | line.offset = _get_custom_offset(l, line.is_vertical) 1013 | 1014 | for l : LineSep in _separators: 1015 | l.visible = separator_line_visible 1016 | l.color = separator_line_color 1017 | l.double_click_handler = behaviour_expand_on_double_click 1018 | l.button.self_modulate = drag_button_modulate 1019 | l.button.min_no_focus_transparense = min_visible_drag_button 1020 | l.button.set_drag_icon(drag_button_icon) 1021 | 1022 | l.force_update() 1023 | 1024 | if Engine.is_editor_hint(): 1025 | for l : int in range(0, _separators.size(), 1): 1026 | if l < separators_line_offsets.size(): 1027 | separators_line_offsets[l] = _separators[l].offset 1028 | continue 1029 | break 1030 | 1031 | func _on_enter(n : Node) -> void: 1032 | n.is_inside_tree() 1033 | if n is SplitContainerItem or (n is Control and !Engine.is_editor_hint()): 1034 | if !n.visibility_changed.is_connected(_on_visible): 1035 | n.visibility_changed.connect(_on_visible) 1036 | #if Engine.is_editor_hint() and is_node_ready(): 1037 | #for x : int in range(separators_line_offsets.size()): 1038 | #separators_line_offsets[x] = 0.0 1039 | update() 1040 | 1041 | func _on_visible() -> void: 1042 | update() 1043 | 1044 | func _on_exiting(n : Node) -> void: 1045 | if n is SplitContainerItem or (n is Control and !Engine.is_editor_hint()): 1046 | if is_node_ready(): 1047 | #if Engine.is_editor_hint(): 1048 | #for x : int in range(separators_line_offsets.size()): 1049 | #separators_line_offsets[x] = 0.0 1050 | for x : LineSep in _separators: 1051 | x.offset = 0.0 1052 | if n.visibility_changed.is_connected(_on_visible): 1053 | n.visibility_changed.disconnect(_on_visible) 1054 | update() 1055 | 1056 | func _get_custom_offset(index : int, vertical : bool) -> float: 1057 | if separators_line_offsets.size() > index: 1058 | var root : Vector2 = _rect_size_editor 1059 | if root != Vector2.ZERO: 1060 | var current_size : Vector2 = Vector2(get_viewport().size) / Vector2(root) 1061 | if vertical: 1062 | return separators_line_offsets[index] * current_size.y 1063 | else: 1064 | return separators_line_offsets[index] * current_size.x 1065 | return 0.0 1066 | 1067 | func _process(__ : float) -> void: 1068 | if is_node_ready(): 1069 | _update() 1070 | if _first: 1071 | _first = false 1072 | else: 1073 | set_process(false) 1074 | 1075 | func _on_exiting_tree() -> void: 1076 | var vp : Viewport = get_viewport() 1077 | if vp and vp.size_changed.is_connected(update): 1078 | vp.size_changed.disconnect(update) 1079 | 1080 | var parent : Node = get_parent() 1081 | if parent is Control: 1082 | if parent.item_rect_changed.is_connected(update): 1083 | parent.item_rect_changed.disconnect(update) 1084 | 1085 | func _enter_tree() -> void: 1086 | var vp : Viewport = get_viewport() 1087 | if vp and !vp.size_changed.is_connected(update): 1088 | vp.size_changed.connect(update) 1089 | 1090 | var parent : Node = get_parent() 1091 | if parent is Control: 1092 | if !parent.item_rect_changed.is_connected(update): 1093 | parent.item_rect_changed.connect(update) 1094 | 1095 | if !tree_exiting.is_connected(_on_exiting_tree): 1096 | tree_exiting.connect(_on_exiting_tree) 1097 | 1098 | func _on_draw() -> void: 1099 | update() 1100 | 1101 | func _ready() -> void: 1102 | separator_line_color = separator_line_color 1103 | drag_button_modulate = drag_button_modulate 1104 | 1105 | size_flags_horizontal = Control.SIZE_EXPAND_FILL 1106 | size_flags_vertical =Control.SIZE_EXPAND_FILL 1107 | 1108 | set_deferred(&"anchor_left", 0.0) 1109 | set_deferred(&"anchor_top", 0.0) 1110 | set_deferred(&"anchor_bottom", 1.0) 1111 | set_deferred(&"anchor_right", 1.0) 1112 | 1113 | if Engine.is_editor_hint(): 1114 | draw.connect(_on_draw) 1115 | 1116 | if separators_line_offsets.size() > get_child_count(): 1117 | separators_line_offsets.resize(get_child_count()) 1118 | 1119 | if _first: 1120 | update() 1121 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/multi_split_container.gd.uid: -------------------------------------------------------------------------------- 1 | uid://db6mrqis6mthu 2 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/plugin.cfg: -------------------------------------------------------------------------------- 1 | [plugin] 2 | 3 | name="MultiSpliterContainer" 4 | description="Allow splitting elements into containers with the same size in the canvas rectangle." 5 | author="Twister" 6 | version="1.1" 7 | script="plugin.gd" 8 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/plugin.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends EditorPlugin 3 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 4 | # https://github.com/CodeNameTwister/Multi-Split-Container 5 | # 6 | # Multi-Split-Container addon for godot 4 7 | # author: "Twister" 8 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 9 | 10 | const ICON : Texture = preload("res://addons/multi_spliter_container/icon/MultiSpliter.svg") 11 | const CLASS : Script = preload("res://addons/multi_spliter_container/multi_split_container.gd") 12 | const NAME : StringName = &"MultiSplitContainer" 13 | 14 | func _enter_tree() -> void: 15 | add_custom_type(NAME, &"Container", CLASS, ICON) 16 | 17 | func _exit_tree() -> void: 18 | remove_custom_type(NAME) 19 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/plugin.gd.uid: -------------------------------------------------------------------------------- 1 | uid://dro4p8s2wlpd4 2 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/split_container_item.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | @icon("icon/MultiSpliterItem.svg") 3 | extends Control 4 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 5 | # https://github.com/CodeNameTwister/Multi-Split-Container 6 | # 7 | # Multi-Split-Container addon for godot 4 8 | # author: "Twister" 9 | # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # 10 | 11 | ## Expand if tight by spliter 12 | func show_splited_container() -> void: 13 | var parent : Node = get_parent() 14 | if parent.has_method(&"expand_splited_container"): 15 | parent.call(&"expand_splited_container", self) 16 | 17 | func _on_gui_input(input : InputEvent) -> void: 18 | if input.is_pressed(): 19 | show_splited_container() 20 | 21 | func _ready() -> void: 22 | set_process(false) 23 | 24 | size_flags_horizontal = Control.SIZE_FILL 25 | size_flags_vertical = Control.SIZE_FILL 26 | 27 | set_deferred(&"anchor_left", 0.0) 28 | set_deferred(&"anchor_top", 0.0) 29 | set_deferred(&"anchor_bottom", 1.0) 30 | set_deferred(&"anchor_right", 1.0) 31 | 32 | func _init() -> void: 33 | name = "SplitContainerItem" 34 | 35 | gui_input.connect(_on_gui_input) 36 | 37 | child_exiting_tree.connect(_on_child_exiting_tree) 38 | child_entered_tree.connect(_on_child_entered_tree) 39 | 40 | func _on_child_entered_tree(n : Node) -> void: 41 | if !Engine.is_editor_hint(): 42 | if n is Control: 43 | if !n.gui_input.is_connected(_on_gui_input): 44 | n.gui_input.connect(_on_gui_input) 45 | else: 46 | if n.owner == null: 47 | n.owner = EditorInterface.get_edited_scene_root() 48 | for x : Node in n.get_children(): 49 | _on_child_entered_tree(x) 50 | 51 | func _disconnect(n : Node) -> void: 52 | if n is Control: 53 | if n.gui_input.is_connected(_on_gui_input): 54 | n.gui_input.disconnect(_on_gui_input) 55 | for x : Node in n.get_children(): 56 | _on_child_exiting_tree(x) 57 | 58 | func _on_child_exiting_tree(n : Node) -> void: 59 | if !Engine.is_editor_hint(): 60 | _disconnect(n) 61 | 62 | if get_child_count() > 0: 63 | if get_child(0) != n: 64 | return 65 | 66 | func _enter_tree() -> void: 67 | if Engine.is_editor_hint(): 68 | if owner == null: 69 | if get_parent().owner: 70 | owner = get_parent().owner 71 | else: 72 | owner = EditorInterface.get_edited_scene_root() 73 | if get_child_count() > 0: 74 | if is_queued_for_deletion(): 75 | cancel_free() 76 | for x : Node in get_children(): 77 | _on_child_entered_tree(x) 78 | -------------------------------------------------------------------------------- /addons/multi_spliter_container/split_container_item.gd.uid: -------------------------------------------------------------------------------- 1 | uid://beplmlbkjbofd 2 | -------------------------------------------------------------------------------- /images/.gdignore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeNameTwister/Multi-Split-Container/972afbdf2e45ab594e25dc5fff70fe3842b16a80/images/.gdignore -------------------------------------------------------------------------------- /images/example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeNameTwister/Multi-Split-Container/972afbdf2e45ab594e25dc5fff70fe3842b16a80/images/example.png -------------------------------------------------------------------------------- /images/example_full.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeNameTwister/Multi-Split-Container/972afbdf2e45ab594e25dc5fff70fe3842b16a80/images/example_full.png -------------------------------------------------------------------------------- /images/example_wchild.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CodeNameTwister/Multi-Split-Container/972afbdf2e45ab594e25dc5fff70fe3842b16a80/images/example_wchild.png --------------------------------------------------------------------------------