Skip to content

Commit 4706ca5

Browse files
committed
Add SizeContainer
Adds a `SizeContainer` node, which supports a `maximum_size` property. The `maximum_size` will serve as a cap on the size of the container. All children of this container will be clipped to fit within that cap.
1 parent 250ef8d commit 4706ca5

File tree

6 files changed

+236
-2
lines changed

6 files changed

+236
-2
lines changed

doc/classes/SizeContainer.xml

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
<?xml version="1.0" encoding="UTF-8" ?>
2+
<class name="SizeContainer" inherits="Container" keywords="size" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
3+
<brief_description>
4+
A container that supports a maximum size for itself.
5+
</brief_description>
6+
<description>
7+
[SizeContainer] allows setting a maximum size for itself. When the container's size exceeds the defined maximum size, it will not grow any larger, effectively capping its dimensions. This is useful for creating UI elements that should not exceed a certain size regardless of their content or parent container's size.
8+
To control the [SizeContainer]'s maximum size, use the [code skip-lint]max_size[/code] property as shown below.
9+
[codeblocks]
10+
[gdscript]
11+
# This code sample assumes the current script is extending SizeContainer.
12+
var max_size_value = Vector2(400, 300)
13+
set_max_size(max_size_value)
14+
[/gdscript]
15+
[csharp]
16+
// This code sample assumes the current script is extending SizeContainer.
17+
Vector2 maxSizeValue = new Vector2(400, 300);
18+
SetMaxSize(maxSizeValue);
19+
[/csharp]
20+
[/codeblocks]
21+
</description>
22+
<tutorials>
23+
<link title="Using Containers">$DOCS_URL/tutorials/ui/gui_containers.html</link>
24+
</tutorials>
25+
<members>
26+
<member name="clip_contents" type="bool" setter="set_clip_contents" getter="is_clipping_contents" overrides="Control" default="true" />
27+
<member name="maximum_size" type="Vector2" setter="set_maximum_size" getter="get_maximum_size" default="Vector2(0, 0)">
28+
If greater than [code]0[/code] on either axis, the container will expand on that axis to fit its children, up to the specified maximum size.
29+
</member>
30+
</members>
31+
</class>

editor/icons/SizeContainer.svg

Lines changed: 1 addition & 0 deletions
Loading

scene/gui/control.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,7 @@ class Control : public CanvasItem {
520520
Point2 get_global_position() const;
521521
Point2 get_screen_position() const;
522522

523-
void set_size(const Size2 &p_size, bool p_keep_offsets = false);
523+
virtual void set_size(const Size2 &p_size, bool p_keep_offsets = false);
524524
Size2 get_size() const;
525525
void reset_size();
526526

@@ -549,7 +549,7 @@ class Control : public CanvasItem {
549549
virtual Size2 get_minimum_size() const;
550550
virtual Size2 get_combined_minimum_size() const;
551551

552-
void set_custom_minimum_size(const Size2 &p_custom);
552+
virtual void set_custom_minimum_size(const Size2 &p_custom);
553553
Size2 get_custom_minimum_size() const;
554554

555555
// Container sizing.

scene/gui/size_container.cpp

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
/**************************************************************************/
2+
/* size_container.cpp */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#include "size_container.h"
32+
33+
void SizeContainer::set_custom_minimum_size(const Size2 &p_custom) {
34+
if ((p_custom.x > maximum_size.x && maximum_size.x > 0) || (p_custom.y > maximum_size.y && maximum_size.y > 0)) {
35+
return;
36+
}
37+
38+
Control::set_custom_minimum_size(p_custom);
39+
}
40+
41+
void SizeContainer::set_size(const Size2 &p_size, bool p_keep_offsets) {
42+
Size2 size = p_size;
43+
if (maximum_size.x > 0) {
44+
size.x = MIN(size.x, maximum_size.x);
45+
}
46+
if (maximum_size.y > 0) {
47+
size.y = MIN(size.y, maximum_size.y);
48+
}
49+
50+
Control::set_size(size, p_keep_offsets);
51+
}
52+
53+
void SizeContainer::set_maximum_size(const Size2 &p_max_size) {
54+
if (maximum_size == p_max_size) {
55+
return;
56+
}
57+
maximum_size = p_max_size.maxf(0.0);
58+
set_size(get_minimum_size());
59+
}
60+
61+
Size2 SizeContainer::get_maximum_size() const {
62+
return maximum_size;
63+
}
64+
65+
Size2 SizeContainer::get_minimum_size() const {
66+
Size2 ms;
67+
for (int i = 0; i < get_child_count(); i++) {
68+
Control *c = as_sortable_control(get_child(i), SortableVisibilityMode::VISIBLE);
69+
if (!c) {
70+
continue;
71+
}
72+
Size2 minsize = c->get_combined_minimum_size();
73+
ms = ms.max(minsize);
74+
}
75+
76+
if (maximum_size.x > 0 && ms.x > maximum_size.x) {
77+
ms.x = maximum_size.x;
78+
}
79+
if (maximum_size.y > 0 && ms.y > maximum_size.y) {
80+
ms.y = maximum_size.y;
81+
}
82+
83+
return ms;
84+
}
85+
86+
Vector<int> SizeContainer::get_allowed_size_flags_horizontal() const {
87+
Vector<int> flags;
88+
flags.append(SIZE_FILL);
89+
flags.append(SIZE_SHRINK_BEGIN);
90+
flags.append(SIZE_SHRINK_CENTER);
91+
flags.append(SIZE_SHRINK_END);
92+
return flags;
93+
}
94+
95+
Vector<int> SizeContainer::get_allowed_size_flags_vertical() const {
96+
Vector<int> flags;
97+
flags.append(SIZE_FILL);
98+
flags.append(SIZE_SHRINK_BEGIN);
99+
flags.append(SIZE_SHRINK_CENTER);
100+
flags.append(SIZE_SHRINK_END);
101+
return flags;
102+
}
103+
104+
void SizeContainer::_notification(int p_what) {
105+
switch (p_what) {
106+
case NOTIFICATION_SORT_CHILDREN: {
107+
Size2 size = get_size();
108+
109+
// Clamp container size to max_size if set
110+
if (maximum_size.x > 0) {
111+
size.x = MIN(size.x, maximum_size.x);
112+
}
113+
if (maximum_size.y > 0) {
114+
size.y = MIN(size.y, maximum_size.y);
115+
}
116+
117+
for (int i = 0; i < get_child_count(); i++) {
118+
Control *c = as_sortable_control(get_child(i));
119+
if (!c) {
120+
continue;
121+
}
122+
123+
// Fit child within the constrained size
124+
fit_child_in_rect(c, Rect2(Point2(), size));
125+
}
126+
} break;
127+
128+
case NOTIFICATION_THEME_CHANGED: {
129+
update_minimum_size();
130+
} break;
131+
}
132+
}
133+
134+
void SizeContainer::_bind_methods() {
135+
ClassDB::bind_method(D_METHOD("set_maximum_size", "maximum_size"), &SizeContainer::set_maximum_size);
136+
ClassDB::bind_method(D_METHOD("get_maximum_size"), &SizeContainer::get_maximum_size);
137+
138+
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "maximum_size"), "set_maximum_size", "get_maximum_size");
139+
}
140+
141+
SizeContainer::SizeContainer() {
142+
set_clip_contents(true);
143+
}

scene/gui/size_container.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/**************************************************************************/
2+
/* size_container.h */
3+
/**************************************************************************/
4+
/* This file is part of: */
5+
/* GODOT ENGINE */
6+
/* https://godotengine.org */
7+
/**************************************************************************/
8+
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
9+
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
10+
/* */
11+
/* Permission is hereby granted, free of charge, to any person obtaining */
12+
/* a copy of this software and associated documentation files (the */
13+
/* "Software"), to deal in the Software without restriction, including */
14+
/* without limitation the rights to use, copy, modify, merge, publish, */
15+
/* distribute, sublicense, and/or sell copies of the Software, and to */
16+
/* permit persons to whom the Software is furnished to do so, subject to */
17+
/* the following conditions: */
18+
/* */
19+
/* The above copyright notice and this permission notice shall be */
20+
/* included in all copies or substantial portions of the Software. */
21+
/* */
22+
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
23+
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
24+
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
25+
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
26+
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
27+
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
28+
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
29+
/**************************************************************************/
30+
31+
#pragma once
32+
33+
#include "scene/gui/container.h"
34+
35+
class SizeContainer : public Container {
36+
GDCLASS(SizeContainer, Container);
37+
38+
private:
39+
Size2 maximum_size;
40+
41+
protected:
42+
void _notification(int p_what);
43+
static void _bind_methods();
44+
45+
public:
46+
virtual Size2 get_minimum_size() const override;
47+
virtual void set_custom_minimum_size(const Size2 &p_custom) override;
48+
virtual void set_size(const Size2 &p_size, bool p_keep_offsets = false) override;
49+
50+
virtual Vector<int> get_allowed_size_flags_horizontal() const override;
51+
virtual Vector<int> get_allowed_size_flags_vertical() const override;
52+
53+
void set_maximum_size(const Size2 &p_max_size);
54+
Size2 get_maximum_size() const;
55+
56+
SizeContainer();
57+
};

scene/register_scene_types.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
#include "scene/gui/scroll_bar.h"
8383
#include "scene/gui/scroll_container.h"
8484
#include "scene/gui/separator.h"
85+
#include "scene/gui/size_container.h"
8586
#include "scene/gui/slider.h"
8687
#include "scene/gui/spin_box.h"
8788
#include "scene/gui/split_container.h"
@@ -491,6 +492,7 @@ void register_scene_types() {
491492
GDREGISTER_CLASS(HFlowContainer);
492493
GDREGISTER_CLASS(VFlowContainer);
493494
GDREGISTER_CLASS(MarginContainer);
495+
GDREGISTER_CLASS(SizeContainer);
494496

495497
OS::get_singleton()->yield(); // may take time to init
496498

0 commit comments

Comments
 (0)