├── .gitattributes
├── .gitignore
├── LICENSE
├── README.md
├── Test.tscn
├── addons
└── FlexContainer
│ ├── FlexContainerPlugin.gd
│ ├── LICENSE
│ ├── README.md
│ ├── flex_container.gd
│ ├── plugin.cfg
│ └── res
│ ├── icon.svg
│ └── icon.svg.import
├── default_env.tres
├── icon.png
├── icon.png.import
├── project.godot
├── releases
└── flex-container-v1.0.0.zip
└── screenshots
├── example_1.jpg
├── example_1.jpg.import
├── example_2.jpg
└── example_2.jpg.import
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Godot 4+ specific ignores
2 | .godot/
3 |
4 | # Godot-specific ignores
5 | .import/
6 | export.cfg
7 | export_presets.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
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Nif
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 | # FlexContainer
2 | ### A simple flex container plugin for Godot.
3 |
4 | * Installation
5 | * Usage
6 | * Properties
7 | * Alternatives
8 | * Issues
9 |
10 |
11 | ## Installation
12 | 1. Download the latest version in releases or clone the repository.
13 | 2. Copy the contents of `addons/FlexContainer` into your `res://addons/FlexContainer` directory.
14 | 3. Enable `Dialogue Manager` in your project plugins.
15 |
16 |
17 | ## Usage
18 | 1. Set a grid size using the `Columns` and `Rows` in `Inspector`.
19 | 2. In `Inspector` increase the amount of `Vector2` in `Blocks` property based on the *grid size* (`Columns` × `Rows`).
20 |
This is not required but recommended. It would also be better to avoid going beyond *grid size*.
21 | 3. `Vector2`'s `x` acts as span while `y` acts as row. Customize them depending to your need.
22 | 4. Added children within the node will change size and position corresponding to the `Vector2` in `Blocks`.
23 |
The first `Vector2` corresponds to the first child and so forth.
24 |
25 | **Note: when extending the script, add the `tool` keyword to have the exports show in the `Inspector`.**
26 |
27 | ## Properties
28 | Property | Type | Definition
29 | ---------------- | ---------------- | -------------
30 | Columns | int | the width or amount of column the *container* will have, forming a *grid*.
31 | Rows | int | the height or amount of rows the *container* will have, forming a *grid*.
32 | Blocks | PoolVector2Array |the placeholder for child nodes within the container. Each `Vector2` represents a block within a *grid*, having its own span (`x`) and row (`y`). It moves from left to right and top to bottom.
33 | Compact | boolean | it fills in the empty spaces within the *container*.
34 | Limit Visible | boolean | it hides children that goes beyond the container's size or outside the size of `Blocks`.
35 | Disable Min Size | boolean | it sets the `rect_min_size` of children to `Vector2.ZERO`. This is currently the default as the container can't handle `rect_min_size` of children.
36 |
37 |
38 | ## Alternatives
39 | * I suggest using DockableContainer for a more cleaner and flexible alternative. It does what FlexContainer does but more! Worth a try.
40 |
41 |
42 | ## Issues
43 | * Currently has no way to properly handle `rect_min_size` of chilren.
44 | * Adding non `Control` type nodes may cause errors or even a crash. Bypass by encapsulating it inside a control type node.
45 | * Resizing isn't fully accurate which may cause some jitter and a pixel or two of misalignment. *It's annoying*.
46 |
47 | **Said issues may be fixed in the future updates. However, if you know a way to fix it, do open up an issue or a pull request. Your contribution would be greatly appreciated.**
48 |
49 |
--------------------------------------------------------------------------------
/Test.tscn:
--------------------------------------------------------------------------------
1 | [gd_scene load_steps=3 format=2]
2 |
3 | [ext_resource path="res://addons/FlexContainer/flex_container.gd" type="Script" id=1]
4 |
5 | [sub_resource type="StyleBoxFlat" id=1]
6 | bg_color = Color( 0, 0, 0, 1 )
7 |
8 | [node name="Test" type="Control"]
9 | anchor_right = 1.0
10 | anchor_bottom = 1.0
11 |
12 | [node name="PanelContainer" type="PanelContainer" parent="."]
13 | anchor_right = 1.0
14 | anchor_bottom = 1.0
15 | custom_styles/panel = SubResource( 1 )
16 |
17 | [node name="FlexContainer" type="Container" parent="PanelContainer"]
18 | margin_right = 1024.0
19 | margin_bottom = 600.0
20 | size_flags_horizontal = 3
21 | size_flags_vertical = 3
22 | script = ExtResource( 1 )
23 | _columns = 3
24 | _rows = 7
25 | _blocks = PoolVector2Array( 1, 3, 2, 2, 1, 3, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 )
26 | _compact = true
27 | _limit_visible = true
28 | _disable_min_size = true
29 | _top_margin = 10
30 | _bottom_margin = 10
31 | _left_margin = 10
32 | _right_margin = 10
33 | _horizontal = 4
34 | _vertical = 4
35 |
36 | [node name="ColorRect" type="ColorRect" parent="PanelContainer/FlexContainer"]
37 | margin_left = 10.0
38 | margin_top = 10.0
39 | margin_right = 342.0
40 | margin_bottom = 255.0
41 | size_flags_horizontal = 3
42 | size_flags_vertical = 3
43 | color = Color( 0.760784, 0.243137, 0.243137, 1 )
44 |
45 | [node name="ColorRect2" type="ColorRect" parent="PanelContainer/FlexContainer"]
46 | margin_left = 346.0
47 | margin_top = 10.0
48 | margin_right = 1014.0
49 | margin_bottom = 172.0
50 | size_flags_horizontal = 3
51 | size_flags_vertical = 3
52 | color = Color( 0.556863, 0.937255, 0.65098, 1 )
53 |
54 | [node name="ColorRect3" type="ColorRect" parent="PanelContainer/FlexContainer"]
55 | margin_left = 346.0
56 | margin_top = 176.0
57 | margin_right = 678.0
58 | margin_bottom = 421.0
59 | size_flags_horizontal = 3
60 | size_flags_vertical = 3
61 | color = Color( 0.631373, 0.305882, 0.776471, 1 )
62 |
63 | [node name="ColorRect4" type="ColorRect" parent="PanelContainer/FlexContainer"]
64 | margin_left = 10.0
65 | margin_top = 425.0
66 | margin_right = 678.0
67 | margin_bottom = 504.0
68 | size_flags_horizontal = 3
69 | size_flags_vertical = 3
70 | color = Color( 0.803922, 0.482353, 0.635294, 1 )
71 |
72 | [node name="ColorRect5" type="ColorRect" parent="PanelContainer/FlexContainer"]
73 | margin_left = 682.0
74 | margin_top = 176.0
75 | margin_right = 1014.0
76 | margin_bottom = 255.0
77 | size_flags_horizontal = 3
78 | size_flags_vertical = 3
79 | color = Color( 0.968627, 0.913725, 0.45098, 1 )
80 |
81 | [node name="ColorRect6" type="ColorRect" parent="PanelContainer/FlexContainer"]
82 | margin_left = 10.0
83 | margin_top = 259.0
84 | margin_right = 342.0
85 | margin_bottom = 338.0
86 | size_flags_horizontal = 3
87 | size_flags_vertical = 3
88 | color = Color( 0.372549, 0.752941, 0.854902, 1 )
89 |
90 | [node name="ColorRect7" type="ColorRect" parent="PanelContainer/FlexContainer"]
91 | margin_left = 682.0
92 | margin_top = 259.0
93 | margin_right = 1014.0
94 | margin_bottom = 338.0
95 | size_flags_horizontal = 3
96 | size_flags_vertical = 3
97 | color = Color( 0.337255, 0.447059, 0.815686, 1 )
98 |
99 | [node name="ColorRect8" type="ColorRect" parent="PanelContainer/FlexContainer"]
100 | margin_left = 10.0
101 | margin_top = 342.0
102 | margin_right = 342.0
103 | margin_bottom = 421.0
104 | size_flags_horizontal = 3
105 | size_flags_vertical = 3
106 | color = Color( 0.968627, 0.388235, 0.988235, 1 )
107 |
108 | [node name="ColorRect9" type="ColorRect" parent="PanelContainer/FlexContainer"]
109 | margin_left = 682.0
110 | margin_top = 342.0
111 | margin_right = 1014.0
112 | margin_bottom = 421.0
113 | size_flags_horizontal = 3
114 | size_flags_vertical = 3
115 | color = Color( 0.317647, 0.886275, 0.235294, 1 )
116 |
117 | [node name="ColorRect10" type="ColorRect" parent="PanelContainer/FlexContainer"]
118 | visible = false
119 | margin_left = 262.0
120 | margin_top = 400.0
121 | margin_right = 510.0
122 | margin_bottom = 591.0
123 | size_flags_horizontal = 3
124 | size_flags_vertical = 3
125 | color = Color( 0.317647, 0.886275, 0.235294, 1 )
126 |
127 | [node name="Button" type="Button" parent="PanelContainer/FlexContainer"]
128 | visible = false
129 | margin_right = 332.0
130 | margin_bottom = 245.0
131 |
--------------------------------------------------------------------------------
/addons/FlexContainer/FlexContainerPlugin.gd:
--------------------------------------------------------------------------------
1 | tool
2 | extends EditorPlugin
3 |
4 |
5 | func _enter_tree():
6 | add_custom_type("FlexContainer", "Container", preload("flex_container.gd"), preload("res/icon.svg"))
7 | pass
8 |
9 |
10 | func _exit_tree():
11 | remove_custom_type("FlexContainer")
12 | pass
13 |
--------------------------------------------------------------------------------
/addons/FlexContainer/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 Nif
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 |
--------------------------------------------------------------------------------
/addons/FlexContainer/README.md:
--------------------------------------------------------------------------------
1 | # FlexContainer
2 | ### A simple flex container plugin for Godot.
3 |
4 | * Installation
5 | * Usage
6 | * Properties
7 | * Limitations
8 |
9 |
10 | ## Installation
11 | 1. Download the latest version in releases or clone the repository.
12 | 2. Copy the contents of `addons/FlexContainer` into your `res://addons/FlexContainer` directory.
13 | 3. Enable `Dialogue Manager` in your project plugins.
14 |
15 |
16 | ## Usage
17 | 1. Set a grid size using the `Columns` and `Rows` in `Inspector`.
18 | 2. In `Inspector` increase the amount of `Vector2` in `Blocks` property based on the *grid size* (`Columns` × `Rows`).
19 |
This is not required but recommended. It would also be better to avoid going beyond *grid size*.
20 | 3. `Vector2`'s `x` acts as span while `y` acts as row. Customize them depending to your need.
21 | 4. Added children within the node will change size and position corresponding to the `Vector2` in `Blocks`.
22 |
The first `Vector2` corresponds to the first child and so forth.
23 |
24 | **Note: when extending the script, add the `tool` keyword to have the exports show in the `Inspector`.**
25 |
26 | ## Properties
27 | Property | Type | Definition
28 | ---------------- | ---------------- | -------------
29 | Columns | int | the width or amount of column the *container* will have, forming a *grid*.
30 | Rows | int | the height or amount of rows the *container* will have, forming a *grid*.
31 | Blocks | PoolVector2Array |the placeholder for child nodes within the container. Each `Vector2` represents a block within a *grid*, having its own span (`x`) and row (`y`). It moves from left to right and top to bottom.
32 | Compact | boolean | it fills in the empty spaces within the *container*.
33 | Limit Visible | boolean | it hides children that goes beyond the container's size or outside the size of `Blocks`.
34 | Disable Min Size | boolean | it sets the `rect_min_size` of children to `Vector2.ZERO`. This is currently the default as the container can't handle `rect_min_size` of children.
35 |
36 |
37 | ## Limitations
38 | * Currently has no way to properly handle `rect_min_size` of chilren.
39 | * Adding non `Control` type nodes may cause errors or even a crash. Bypass by encapsulating it inside a control type node.
40 | * Resizing isn't fully accurate which causes jitter and a pixel or two of misalignment. *It's annoying*.
41 |
42 | **Said issues may be fixed in the future updates. However, if you know a way to fix it, do open up an issue or a pull request. Your contribution would be greatly apprciated**
43 |
44 |
--------------------------------------------------------------------------------
/addons/FlexContainer/flex_container.gd:
--------------------------------------------------------------------------------
1 | tool
2 | extends Container
3 |
4 | #TODO:
5 | #>Add a fix/implementation for resizing with rect_min_size of children.
6 |
7 | #Size (of the grid)
8 | var _columns := 1 setget set_columns, get_columns
9 | var _rows := 1 setget set_rows, get_rows
10 |
11 | #Blocks (the placeholder for the span and row of the container's children)
12 | var _blocks := PoolVector2Array([Vector2(1,1)]) setget set_blocks, get_blocks
13 |
14 | #Content Margin
15 | var _top_margin := 0 setget set_top_margin, get_top_margin
16 | var _bottom_margin := 0 setget set_bottom_margin, get_bottom_margin
17 | var _right_margin := 0 setget set_right_margin, get_right_margin
18 | var _left_margin := 0 setget set_left_margin, get_left_margin
19 |
20 | #Separation (or space between Blocks)
21 | var _horizontal := 4 setget set_horizontal, get_horizontal
22 | var _vertical := 4 setget set_vertical, get_vertical
23 |
24 | #Flags
25 | var _compact := false setget set_compact, get_compact #Fill in empty spaces with the next block that fits
26 | var _limit_visible := false setget set_limit_visible, get_limit_visible #Hide children outside of Blocks' array size.
27 | var _disable_min_size := true setget set_disable_min_size, get_disable_min_size
28 | #^Proper resize with minimum has not been implemented. Turning _disable_min_size off can cause unexpected crashes or lag.
29 | #^It is only applicable to use if all children has proper rect_min_size values.
30 | var _child_count := 0 #Refer to _notification method
31 |
32 | #Creates an export for the FlexContainer's inspector.
33 | func _get_property_list() -> Array:
34 | return [
35 | {
36 | "name": "FlexContainer",
37 | "type": TYPE_NIL,
38 | "usage": PROPERTY_USAGE_CATEGORY,
39 | },
40 | {
41 | "name": "_columns",
42 | "type": TYPE_INT,
43 | "usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE,
44 | },
45 | {
46 | "name": "_rows",
47 | "type": TYPE_INT,
48 | "usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
49 | },
50 | {
51 | "name": "_blocks",
52 | "type": TYPE_VECTOR2_ARRAY,
53 | "usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
54 | },
55 | {
56 | "name": "_compact",
57 | "type": TYPE_BOOL,
58 | "usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
59 | },
60 | {
61 | "name": "_limit_visible",
62 | "type": TYPE_BOOL,
63 | "usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
64 | },
65 | {
66 | "name": "_disable_min_size",
67 | "type": TYPE_BOOL,
68 | "usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
69 | },
70 | {
71 | "name": "Content Margin",
72 | "type": TYPE_NIL,
73 | "usage": PROPERTY_USAGE_GROUP,
74 | },
75 | {
76 | "name": "_top_margin",
77 | "type": TYPE_INT,
78 | "usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
79 | },
80 | {
81 | "name": "_bottom_margin",
82 | "type": TYPE_INT,
83 | "usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
84 | },
85 | {
86 | "name": "_left_margin",
87 | "type": TYPE_INT,
88 | "usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
89 | },
90 | {
91 | "name": "_right_margin",
92 | "type": TYPE_INT,
93 | "usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
94 | },
95 | {
96 | "name": "Separation",
97 | "type": TYPE_NIL,
98 | "usage": PROPERTY_USAGE_GROUP,
99 | },
100 | {
101 | "name": "_horizontal",
102 | "type": TYPE_INT,
103 | "usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
104 | },
105 | {
106 | "name": "_vertical",
107 | "type": TYPE_INT,
108 | "usage": PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_SCRIPT_VARIABLE
109 | },
110 | ]
111 |
112 | #Gives the option to revert a property to default state.
113 | func property_can_revert(property):
114 | match property:
115 | "_columns":
116 | return true
117 | "_rows":
118 | return true
119 | "_blocks":
120 | return true
121 | "_top_margin":
122 | return true
123 | "_bottom_margin":
124 | return true
125 | "_left_margin":
126 | return true
127 | "_right_margin":
128 | return true
129 | "_horizontal":
130 | return true
131 | "_vertical":
132 | return true
133 | "_compact":
134 | return true
135 | "_limit_visible":
136 | return true
137 | "_disable_min_size":
138 | return true
139 | _:
140 | return false
141 |
142 | #Sets the default value on revert.
143 | func property_get_revert(property):
144 | match property:
145 | "_columns":
146 | return 1
147 | "_rows":
148 | return 1
149 | "_blocks":
150 | return PoolVector2Array([Vector2(1,1)])
151 | "_top_margin":
152 | return 0
153 | "_bottom_margin":
154 | return 0
155 | "_left_margin":
156 | return 0
157 | "_right_margin":
158 | return 0
159 | "_horizontal":
160 | return 4
161 | "_vertical":
162 | return 4
163 | "_compact":
164 | return false
165 | "_limit_visible":
166 | return false
167 | "_disable_min_size":
168 | return true
169 |
170 |
171 | #Setget _columns
172 | func set_columns(value):
173 | if value > 0:
174 | _columns = value
175 | _sort_display()
176 | return
177 | _columns = 1
178 | _sort_display()
179 |
180 | func get_columns() -> int:
181 | return _columns
182 |
183 |
184 | #Setget _rows
185 | func set_rows(value):
186 | if value > 0:
187 | _rows = value
188 | _sort_display()
189 | return
190 | _rows = 1
191 | _sort_display()
192 |
193 | func get_rows() -> int:
194 | return _rows
195 |
196 |
197 | #Setget Blocks
198 | #Note:
199 | #For-loop changes doesn't affect the array in any way. Thus a count solution.
200 | #Vector values in array also does not visually update instantly, sadly.
201 | func set_blocks(value):
202 | if value.size() > 0:
203 | var new_blocks = value
204 | var count = new_blocks.size()
205 | for vector in new_blocks:
206 | if new_blocks[count-1].x < 1:
207 | new_blocks[count-1].x = 1
208 | if new_blocks[count-1].y < 1:
209 | new_blocks[count-1].y = 1
210 | count-=1
211 | _blocks = new_blocks
212 | _sort_display()
213 | return
214 | _blocks = PoolVector2Array([Vector2(1,1)])
215 | _sort_display()
216 |
217 | func get_blocks() -> PoolVector2Array:
218 | return _blocks
219 |
220 |
221 | #Setget Top Margin
222 | func set_top_margin(value):
223 | if value > 0:
224 | _top_margin = value
225 | _sort_display()
226 | return
227 | _top_margin = 0
228 | _sort_display()
229 |
230 | func get_top_margin() -> int:
231 | return _top_margin
232 |
233 |
234 | #Setget Bottom Margin
235 | func set_bottom_margin(value):
236 | if value > 0:
237 | _bottom_margin = value
238 | _sort_display()
239 | return
240 | _bottom_margin = 0
241 | _sort_display()
242 |
243 | func get_bottom_margin() -> int:
244 | return _bottom_margin
245 |
246 |
247 | #Setget Left Margin
248 | func set_left_margin(value):
249 | if value > 0:
250 | _left_margin = value
251 | _sort_display()
252 | return
253 | _left_margin = 0
254 | _sort_display()
255 |
256 | func get_left_margin() -> int:
257 | return _left_margin
258 |
259 |
260 | #Setget Right Margin
261 | func set_right_margin(value):
262 | if value > 0:
263 | _right_margin = value
264 | _sort_display()
265 | return
266 | _right_margin = 0
267 | _sort_display()
268 |
269 | func get_right_margin() -> int:
270 | return _right_margin
271 |
272 |
273 | #Setget Horizontal
274 | func set_horizontal(value):
275 | if value > 0:
276 | _horizontal = value
277 | _sort_display()
278 | return
279 | _horizontal = 4
280 | _sort_display()
281 |
282 | func get_horizontal() -> int:
283 | return _horizontal
284 |
285 |
286 | #Setget Vertical
287 | func set_vertical(value):
288 | if value > 0:
289 | _vertical = value
290 | _sort_display()
291 | return
292 | _vertical = 4
293 | _sort_display()
294 |
295 | func get_vertical() -> int:
296 | return _vertical
297 |
298 |
299 | #Setget Compact
300 | func set_compact(value):
301 | _compact = value
302 | _sort_display()
303 |
304 | func get_compact() -> bool:
305 | return _compact
306 |
307 |
308 | #Setget Limit Visible
309 | func set_limit_visible(value):
310 | _limit_visible = value
311 | if _limit_visible:
312 | _hide_unused(get_children())
313 | else:
314 | _show_unused(get_children())
315 |
316 | func get_limit_visible() -> bool:
317 | return _limit_visible
318 |
319 |
320 | #Setget Disabled Min Size
321 | func set_disable_min_size(value):
322 | _disable_min_size = value
323 | if _disable_min_size:
324 | _remove_min_rect(get_children())
325 |
326 | func get_disable_min_size() -> bool:
327 | return _disable_min_size
328 |
329 |
330 | # Called when the node enters the scene tree for the first time.
331 | func _ready():
332 | connect("item_rect_changed", self, "_rect_resized")
333 | connect("visibility_changed", self, "_visibility_changed")
334 |
335 |
336 | func _rect_resized():
337 | _sort_display()
338 |
339 |
340 | func _visibility_changed():
341 | _sort_display()
342 |
343 |
344 | func _notification(what):
345 | if Engine.editor_hint:
346 | #The condition below allows checking for any node enter/exit and reposition.
347 | if _child_count != get_child_count() || what == NOTIFICATION_DRAW:
348 | _child_count = get_child_count()
349 | _sort_display()
350 |
351 |
352 | func _sort_display():
353 | var content_size := Vector2((rect_size.x - (_left_margin + _right_margin)), (rect_size.y - (_top_margin + _bottom_margin)))
354 | if _blocks.size() > 1:
355 | if _columns > 1:
356 | content_size.x -= (_columns-1) * _horizontal
357 | if _rows > 1:
358 | content_size.y -= (_rows-1) * _vertical
359 | var children := get_children()
360 | for index in range(0, get_child_count(), 1):
361 | if index+1 <= _blocks.size() and index+1 <= (_columns*_rows):
362 | if not children[index].visible and not children[index] is Popup:
363 | children[index].show()
364 | _resize(index, children, content_size)
365 | if _compact:
366 | _reposition_compact(index, children, content_size)
367 | continue #Goes to next child
368 | _reposition(index, children, content_size)
369 | if _disable_min_size:
370 | _remove_min_rect(children)
371 | if _limit_visible:
372 | _hide_unused(children)
373 | return #Exits
374 | _show_unused(children)
375 |
376 |
377 | func _hide_unused(children):
378 | for i in range(get_child_count()-1, -1, -1):
379 | if children[i].visible == true:
380 | if i+1 > _blocks.size() or i+1 > (_columns*_rows):
381 | children[i].hide()
382 | elif children[i].get_rect().end.y >= rect_size.y:
383 | children[i].hide()
384 |
385 |
386 | func _show_unused(children):
387 | for i in range(get_child_count()-1, -1, -1):
388 | if children[i].visible == false:
389 | if i+1 > _blocks.size() or i+1 > (_columns*_rows):
390 | children[i].show()
391 | elif children[i].get_rect().end.y > rect_size.y:
392 | children[i].show()
393 |
394 |
395 | func _remove_min_rect(children):
396 | for i in range(0, get_child_count(), 1):
397 | if children[i].rect_min_size > Vector2.ZERO:
398 | children[i].rect_min_size = Vector2.ZERO
399 |
400 |
401 | #Note:
402 | #>ceil lessens the jitter but not fully, haven't found a solution.
403 | func _resize(index, children, content_size):
404 | var block = _blocks[index]
405 | if block.x > _columns:
406 | block.x = _columns
407 | if block.y > _rows:
408 | block.y = _rows
409 | var width = (round(content_size.x / _columns) * block.x) + (_horizontal * (block.x-1))
410 | var height = (round(content_size.y / _rows) * block.y) + (_vertical * (block.y-1))
411 | var size := Vector2(width, height)
412 | children[index].rect_size = size
413 |
414 |
415 | #Note:
416 | #>ceil lessens the jitter but not fully, haven't found a solution.
417 | func _reposition(index, children, content_size):
418 | if index > 0:
419 | children[index].rect_position.x = children[index-1].get_rect().end.x + _horizontal
420 | children[index].rect_position.y = children[index-1].rect_position.y
421 | while true:
422 | var flag = 0
423 |
424 | #IF child is outside of (self) parent's rect_size.
425 | if children[index].get_rect().end.x > rect_size.x+(children[index].get_rect().size.x/2)-_right_margin:
426 | children[index].rect_position.y += (round(content_size.y / _rows) + _vertical)
427 | children[index].rect_position.x = _left_margin
428 | flag+=1
429 |
430 | #IF child is intersecting with another child loaded before it.
431 | var intersecting_rect : Rect2 = _get_intersecting_rect(index, children, true)
432 | if !intersecting_rect.has_no_area(): #Double negative
433 | children[index].rect_position.x = intersecting_rect.end.x + _horizontal
434 | flag+=1
435 |
436 | if flag == 0:
437 | break
438 | else: #IF initial
439 | children[index].rect_position = Vector2(_left_margin, _top_margin)
440 |
441 |
442 | func _get_intersecting_rect(index, children, reverse:bool=false) -> Rect2:
443 | var start := 0
444 | var end = index
445 | var step := 1
446 | if reverse:
447 | start = index
448 | end = 0
449 | step = -1
450 | for i in range(start, end, step):
451 | var x = i
452 | if reverse:
453 | x-=1
454 | if children[index].get_rect().intersects(children[x].get_rect()):
455 | return children[i-1].get_rect()
456 | return Rect2() #Empty, because for some reason you can't use null :harold:
457 |
458 |
459 | func _reposition_compact(index, children, content_size):
460 | var block_rect_size := Vector2(round(content_size.x / _columns), round(content_size.y / _rows))
461 | children[index].rect_position = Vector2(_left_margin, _top_margin)
462 | if index > 0:
463 | for i in range(0, (_columns*_rows), 1):
464 | var flag = 0
465 |
466 | if children[index].get_rect().end.x > rect_size.x+(children[index].get_rect().size.x/2)-_right_margin:
467 | flag+=1
468 | if !_get_intersecting_rect(index, children).has_no_area():
469 | flag+=1
470 |
471 | if flag == 0:
472 | children[index].rect_position
473 | break
474 |
475 | children[index].rect_position.x += block_rect_size.x + _horizontal
476 | if (i+1)%_columns == 0:
477 | children[index].rect_position.y += block_rect_size.y + _vertical
478 | children[index].rect_position.x = _left_margin
479 |
--------------------------------------------------------------------------------
/addons/FlexContainer/plugin.cfg:
--------------------------------------------------------------------------------
1 | [plugin]
2 |
3 | name="FlexContainer"
4 | description="A simple flex container that can handle different column and row ratio."
5 | author="Nif"
6 | version="1.0.0"
7 | script="FlexContainerPlugin.gd"
8 |
--------------------------------------------------------------------------------
/addons/FlexContainer/res/icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
48 |
--------------------------------------------------------------------------------
/addons/FlexContainer/res/icon.svg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon.svg-63bdbe80b13834dfdcf2cf219f9eddee.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://addons/FlexContainer/res/icon.svg"
13 | dest_files=[ "res://.import/icon.svg-63bdbe80b13834dfdcf2cf219f9eddee.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/default_env.tres:
--------------------------------------------------------------------------------
1 | [gd_resource type="Environment" load_steps=2 format=2]
2 |
3 | [sub_resource type="ProceduralSky" id=1]
4 |
5 | [resource]
6 | background_mode = 2
7 | background_sky = SubResource( 1 )
8 |
--------------------------------------------------------------------------------
/icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nif-kun/godot-flex-container/a7b6e9dc69e45d80e0da7f826c315cc7cd06398f/icon.png
--------------------------------------------------------------------------------
/icon.png.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://icon.png"
13 | dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/project.godot:
--------------------------------------------------------------------------------
1 | ; Engine configuration file.
2 | ; It's best edited using the editor UI and not directly,
3 | ; since the parameters that go here are not all obvious.
4 | ;
5 | ; Format:
6 | ; [section] ; section goes between []
7 | ; param=value ; assign values to parameters
8 |
9 | config_version=4
10 |
11 | [application]
12 |
13 | config/name="FlexContainer"
14 | run/main_scene="res://Test.tscn"
15 | config/icon="res://icon.png"
16 |
17 | [editor_plugins]
18 |
19 | enabled=PoolStringArray( "res://addons/FlexContainer/plugin.cfg" )
20 |
21 | [gui]
22 |
23 | common/drop_mouse_on_gui_input_disabled=true
24 |
25 | [mono]
26 |
27 | project/assembly_name="FlexContainer"
28 |
29 | [physics]
30 |
31 | common/enable_pause_aware_picking=true
32 |
33 | [rendering]
34 |
35 | environment/default_environment="res://default_env.tres"
36 |
--------------------------------------------------------------------------------
/releases/flex-container-v1.0.0.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nif-kun/godot-flex-container/a7b6e9dc69e45d80e0da7f826c315cc7cd06398f/releases/flex-container-v1.0.0.zip
--------------------------------------------------------------------------------
/screenshots/example_1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nif-kun/godot-flex-container/a7b6e9dc69e45d80e0da7f826c315cc7cd06398f/screenshots/example_1.jpg
--------------------------------------------------------------------------------
/screenshots/example_1.jpg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/example_1.jpg-59bdeb6675c6331eb9123b20d2fc8f1b.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://screenshots/example_1.jpg"
13 | dest_files=[ "res://.import/example_1.jpg-59bdeb6675c6331eb9123b20d2fc8f1b.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------
/screenshots/example_2.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Nif-kun/godot-flex-container/a7b6e9dc69e45d80e0da7f826c315cc7cd06398f/screenshots/example_2.jpg
--------------------------------------------------------------------------------
/screenshots/example_2.jpg.import:
--------------------------------------------------------------------------------
1 | [remap]
2 |
3 | importer="texture"
4 | type="StreamTexture"
5 | path="res://.import/example_2.jpg-ffcc5f90929c7b15328b4b136df41f39.stex"
6 | metadata={
7 | "vram_texture": false
8 | }
9 |
10 | [deps]
11 |
12 | source_file="res://screenshots/example_2.jpg"
13 | dest_files=[ "res://.import/example_2.jpg-ffcc5f90929c7b15328b4b136df41f39.stex" ]
14 |
15 | [params]
16 |
17 | compress/mode=0
18 | compress/lossy_quality=0.7
19 | compress/hdr_mode=0
20 | compress/bptc_ldr=0
21 | compress/normal_map=0
22 | flags/repeat=0
23 | flags/filter=true
24 | flags/mipmaps=false
25 | flags/anisotropic=false
26 | flags/srgb=2
27 | process/fix_alpha_border=true
28 | process/premult_alpha=false
29 | process/HDR_as_SRGB=false
30 | process/invert_color=false
31 | process/normal_map_invert_y=false
32 | stream=false
33 | size_limit=0
34 | detect_3d=true
35 | svg/scale=1.0
36 |
--------------------------------------------------------------------------------