├── .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 |
5 |
6 | [](https://godotengine.org/)  
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 | [](https://youtu.be/5JU3snjbRMU)
26 | ### Image Example Scene before/after move splited container by drag buttons.
27 | 
28 | ### Image Example Scene 2 nested child.
29 | 
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 |
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 |
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 |
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
--------------------------------------------------------------------------------