Browse Source

Merge pull request #67788 from 98teg/flow-container-alignment

Add alignment options to flow container
Rémi Verschelde 2 years ago
parent
commit
7488b4724e
3 changed files with 68 additions and 0 deletions
  1. 14 0
      doc/classes/FlowContainer.xml
  2. 41 0
      scene/gui/flow_container.cpp
  3. 13 0
      scene/gui/flow_container.h

+ 14 - 0
doc/classes/FlowContainer.xml

@@ -18,11 +18,25 @@
 		</method>
 	</methods>
 	<members>
+		<member name="alignment" type="int" setter="set_alignment" getter="get_alignment" enum="FlowContainer.AlignmentMode" default="0">
+			The alignment of the container's children (must be one of [constant ALIGNMENT_BEGIN], [constant ALIGNMENT_CENTER], or [constant ALIGNMENT_END]).
+		</member>
 		<member name="vertical" type="bool" setter="set_vertical" getter="is_vertical" default="false">
 			If [code]true[/code], the [FlowContainer] will arrange its children vertically, rather than horizontally.
 			Can't be changed when using [HFlowContainer] and [VFlowContainer].
 		</member>
 	</members>
+	<constants>
+		<constant name="ALIGNMENT_BEGIN" value="0" enum="AlignmentMode">
+			The child controls will be arranged at the beginning of the container, i.e. top if orientation is vertical, left if orientation is horizontal (right for RTL layout).
+		</constant>
+		<constant name="ALIGNMENT_CENTER" value="1" enum="AlignmentMode">
+			The child controls will be centered in the container.
+		</constant>
+		<constant name="ALIGNMENT_END" value="2" enum="AlignmentMode">
+			The child controls will be arranged at the end of the container, i.e. bottom if orientation is vertical, right if orientation is horizontal (left for RTL layout).
+		</constant>
+	</constants>
 	<theme_items>
 		<theme_item name="h_separation" data_type="constant" type="int" default="4">
 			The horizontal separation of children nodes.

+ 41 - 0
scene/gui/flow_container.cpp

@@ -152,6 +152,28 @@ void FlowContainer::_resort() {
 			line_data = lines_data[current_line_idx];
 		}
 
+		// The first child of each line adds the offset caused by the alignment,
+		// but only if the line doesn't contain a child that expands.
+		if (child_idx_in_line == 0 && Math::is_equal_approx(line_data.stretch_ratio_total, 0)) {
+			int alignment_ofs = 0;
+			switch (alignment) {
+				case ALIGNMENT_CENTER:
+					alignment_ofs = line_data.stretch_avail / 2;
+					break;
+				case ALIGNMENT_END:
+					alignment_ofs = line_data.stretch_avail;
+					break;
+				default:
+					break;
+			}
+
+			if (vertical) { /* VERTICAL */
+				ofs.y += alignment_ofs;
+			} else { /* HORIZONTAL */
+				ofs.x += alignment_ofs;
+			}
+		}
+
 		if (vertical) { /* VERTICAL */
 			if (child->get_h_size_flags() & (SIZE_FILL | SIZE_SHRINK_CENTER | SIZE_SHRINK_END)) {
 				child_size.width = line_data.min_line_height;
@@ -282,6 +304,18 @@ int FlowContainer::get_line_count() const {
 	return cached_line_count;
 }
 
+void FlowContainer::set_alignment(AlignmentMode p_alignment) {
+	if (alignment == p_alignment) {
+		return;
+	}
+	alignment = p_alignment;
+	_resort();
+}
+
+FlowContainer::AlignmentMode FlowContainer::get_alignment() const {
+	return alignment;
+}
+
 void FlowContainer::set_vertical(bool p_vertical) {
 	ERR_FAIL_COND_MSG(is_fixed, "Can't change orientation of " + get_class() + ".");
 	vertical = p_vertical;
@@ -300,8 +334,15 @@ FlowContainer::FlowContainer(bool p_vertical) {
 void FlowContainer::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_line_count"), &FlowContainer::get_line_count);
 
+	ClassDB::bind_method(D_METHOD("set_alignment", "alignment"), &FlowContainer::set_alignment);
+	ClassDB::bind_method(D_METHOD("get_alignment"), &FlowContainer::get_alignment);
 	ClassDB::bind_method(D_METHOD("set_vertical", "vertical"), &FlowContainer::set_vertical);
 	ClassDB::bind_method(D_METHOD("is_vertical"), &FlowContainer::is_vertical);
 
+	BIND_ENUM_CONSTANT(ALIGNMENT_BEGIN);
+	BIND_ENUM_CONSTANT(ALIGNMENT_CENTER);
+	BIND_ENUM_CONSTANT(ALIGNMENT_END);
+
+	ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Begin,Center,End"), "set_alignment", "get_alignment");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
 }

+ 13 - 0
scene/gui/flow_container.h

@@ -36,11 +36,19 @@
 class FlowContainer : public Container {
 	GDCLASS(FlowContainer, Container);
 
+public:
+	enum AlignmentMode {
+		ALIGNMENT_BEGIN,
+		ALIGNMENT_CENTER,
+		ALIGNMENT_END
+	};
+
 private:
 	int cached_size = 0;
 	int cached_line_count = 0;
 
 	bool vertical = false;
+	AlignmentMode alignment = ALIGNMENT_BEGIN;
 
 	struct ThemeCache {
 		int h_separation = 0;
@@ -61,6 +69,9 @@ protected:
 public:
 	int get_line_count() const;
 
+	void set_alignment(AlignmentMode p_alignment);
+	AlignmentMode get_alignment() const;
+
 	void set_vertical(bool p_vertical);
 	bool is_vertical() const;
 
@@ -88,4 +99,6 @@ public:
 			FlowContainer(true) { is_fixed = true; }
 };
 
+VARIANT_ENUM_CAST(FlowContainer::AlignmentMode);
+
 #endif // FLOW_CONTAINER_H