Browse Source

Merge pull request #47491 from groud/improve_tabs

Implement Tabs node minimum size
Rémi Verschelde 4 years ago
parent
commit
69a78c006c
3 changed files with 49 additions and 17 deletions
  1. 3 0
      doc/classes/Tabs.xml
  2. 42 17
      scene/gui/tabs.cpp
  3. 4 0
      scene/gui/tabs.h

+ 3 - 0
doc/classes/Tabs.xml

@@ -254,6 +254,9 @@
 		</method>
 	</methods>
 	<members>
+		<member name="clip_tabs" type="bool" setter="set_clip_tabs" getter="get_clip_tabs" default="true">
+			If [code]true[/code], tabs overflowing this node's width will be hidden, displaying two navigation buttons instead. Otherwise, this node's minimum size is updated so that all tabs are visible.
+		</member>
 		<member name="current_tab" type="int" setter="set_current_tab" getter="get_current_tab" default="0">
 			Select tab at index [code]tab_idx[/code].
 		</member>

+ 42 - 17
scene/gui/tabs.cpp

@@ -83,7 +83,10 @@ Size2 Tabs::get_minimum_size() const {
 		}
 	}
 
-	ms.width = 0; //TODO: should make this optional
+	if (clip_tabs) {
+		ms.width = 0;
+	}
+
 	return ms;
 }
 
@@ -105,10 +108,10 @@ void Tabs::_gui_input(const Ref<InputEvent> &p_event) {
 					highlight_arrow = 0;
 				}
 			} else {
-				int limit = get_size().width - incr->get_width() - decr->get_width();
-				if (pos.x > limit + decr->get_width()) {
+				int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
+				if (pos.x > limit_minus_buttons + decr->get_width()) {
 					highlight_arrow = 1;
-				} else if (pos.x > limit) {
+				} else if (pos.x > limit_minus_buttons) {
 					highlight_arrow = 0;
 				}
 			}
@@ -305,7 +308,8 @@ void Tabs::_notification(int p_what) {
 			Ref<Texture2D> incr_hl = get_theme_icon("increment_highlight");
 			Ref<Texture2D> decr_hl = get_theme_icon("decrement_highlight");
 
-			int limit = get_size().width - incr->get_size().width - decr->get_size().width;
+			int limit = get_size().width;
+			int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
 
 			missing_right = false;
 
@@ -328,7 +332,8 @@ void Tabs::_notification(int p_what) {
 					col = font_unselected_color;
 				}
 
-				if (w + lsize > limit) {
+				int new_width = w + lsize;
+				if (new_width > limit || (i < tabs.size() - 1 && new_width > limit_minus_buttons)) { // For the last tab, we accept if the tab covers the buttons.
 					max_drawn_tab = i - 1;
 					missing_right = true;
 					break;
@@ -459,15 +464,15 @@ void Tabs::_notification(int p_what) {
 					}
 				} else {
 					if (offset > 0) {
-						draw_texture(highlight_arrow == 0 ? decr_hl : decr, Point2(limit, vofs));
+						draw_texture(highlight_arrow == 0 ? decr_hl : decr, Point2(limit_minus_buttons, vofs));
 					} else {
-						draw_texture(decr, Point2(limit, vofs), Color(1, 1, 1, 0.5));
+						draw_texture(decr, Point2(limit_minus_buttons, vofs), Color(1, 1, 1, 0.5));
 					}
 
 					if (missing_right) {
-						draw_texture(highlight_arrow == 1 ? incr_hl : incr, Point2(limit + decr->get_size().width, vofs));
+						draw_texture(highlight_arrow == 1 ? incr_hl : incr, Point2(limit_minus_buttons + decr->get_size().width, vofs));
 					} else {
-						draw_texture(incr, Point2(limit + decr->get_size().width, vofs), Color(1, 1, 1, 0.5));
+						draw_texture(incr, Point2(limit_minus_buttons + decr->get_size().width, vofs), Color(1, 1, 1, 0.5));
 					}
 				}
 
@@ -666,7 +671,7 @@ void Tabs::_update_cache() {
 	Ref<StyleBox> tab_selected = get_theme_stylebox("tab_selected");
 	Ref<Texture2D> incr = get_theme_icon("increment");
 	Ref<Texture2D> decr = get_theme_icon("decrement");
-	int limit = get_size().width - incr->get_width() - decr->get_width();
+	int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
 
 	int w = 0;
 	int mw = 0;
@@ -686,7 +691,7 @@ void Tabs::_update_cache() {
 	}
 	int m_width = min_width;
 	if (count_resize > 0) {
-		m_width = MAX((limit - size_fixed) / count_resize, min_width);
+		m_width = MAX((limit_minus_buttons - size_fixed) / count_resize, min_width);
 	}
 	for (int i = offset; i < tabs.size(); i++) {
 		Ref<StyleBox> sb;
@@ -699,7 +704,7 @@ void Tabs::_update_cache() {
 		}
 		int lsize = tabs[i].size_cache;
 		int slen = tabs[i].size_text;
-		if (min_width > 0 && mw > limit && i != current) {
+		if (min_width > 0 && mw > limit_minus_buttons && i != current) {
 			if (lsize > m_width) {
 				slen = m_width - (sb->get_margin(SIDE_LEFT) + sb->get_margin(SIDE_RIGHT));
 				if (tabs[i].icon.is_valid()) {
@@ -909,6 +914,19 @@ Tabs::TabAlign Tabs::get_tab_align() const {
 	return tab_align;
 }
 
+void Tabs::set_clip_tabs(bool p_clip_tabs) {
+	if (clip_tabs == p_clip_tabs) {
+		return;
+	}
+	clip_tabs = p_clip_tabs;
+	update();
+	minimum_size_changed();
+}
+
+bool Tabs::get_clip_tabs() const {
+	return clip_tabs;
+}
+
 void Tabs::move_tab(int from, int to) {
 	if (from == to) {
 		return;
@@ -975,7 +993,8 @@ void Tabs::_ensure_no_over_offset() {
 	Ref<Texture2D> incr = get_theme_icon("increment");
 	Ref<Texture2D> decr = get_theme_icon("decrement");
 
-	int limit = get_size().width - incr->get_width() - decr->get_width();
+	int limit = get_size().width;
+	int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
 
 	while (offset > 0) {
 		int total_w = 0;
@@ -983,7 +1002,7 @@ void Tabs::_ensure_no_over_offset() {
 			total_w += tabs[i].size_cache;
 		}
 
-		if (total_w < limit) {
+		if ((buttons_visible && total_w < limit_minus_buttons) || total_w < limit) { // For the last tab, we accept if the tab covers the buttons.
 			offset--;
 			update();
 		} else {
@@ -1014,9 +1033,12 @@ void Tabs::ensure_tab_visible(int p_idx) {
 	int prev_offset = offset;
 	Ref<Texture2D> incr = get_theme_icon("increment");
 	Ref<Texture2D> decr = get_theme_icon("decrement");
-	int limit = get_size().width - incr->get_width() - decr->get_width();
+	int limit = get_size().width;
+	int limit_minus_buttons = get_size().width - incr->get_width() - decr->get_width();
+
 	for (int i = offset; i <= p_idx; i++) {
-		if (tabs[i].ofs_cache + tabs[i].size_cache > limit) {
+		int total_w = tabs[i].ofs_cache + tabs[i].size_cache;
+		if (total_w > limit || (buttons_visible && total_w > limit_minus_buttons)) {
 			offset++;
 		}
 	}
@@ -1105,6 +1127,8 @@ void Tabs::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("add_tab", "title", "icon"), &Tabs::add_tab, DEFVAL(""), DEFVAL(Ref<Texture2D>()));
 	ClassDB::bind_method(D_METHOD("set_tab_align", "align"), &Tabs::set_tab_align);
 	ClassDB::bind_method(D_METHOD("get_tab_align"), &Tabs::get_tab_align);
+	ClassDB::bind_method(D_METHOD("set_clip_tabs", "clip_tabs"), &Tabs::set_clip_tabs);
+	ClassDB::bind_method(D_METHOD("get_clip_tabs"), &Tabs::get_clip_tabs);
 	ClassDB::bind_method(D_METHOD("get_tab_offset"), &Tabs::get_tab_offset);
 	ClassDB::bind_method(D_METHOD("get_offset_buttons_visible"), &Tabs::get_offset_buttons_visible);
 	ClassDB::bind_method(D_METHOD("ensure_tab_visible", "idx"), &Tabs::ensure_tab_visible);
@@ -1131,6 +1155,7 @@ void Tabs::_bind_methods() {
 
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "current_tab", PROPERTY_HINT_RANGE, "-1,4096,1", PROPERTY_USAGE_EDITOR), "set_current_tab", "get_current_tab");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_tab_align", "get_tab_align");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_tabs"), "set_clip_tabs", "get_clip_tabs");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "tab_close_display_policy", PROPERTY_HINT_ENUM, "Show Never,Show Active Only,Show Always"), "set_tab_close_display_policy", "get_tab_close_display_policy");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrolling_enabled"), "set_scrolling_enabled", "get_scrolling_enabled");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled");

+ 4 - 0
scene/gui/tabs.h

@@ -85,6 +85,7 @@ private:
 	int previous = 0;
 	int _get_top_margin() const;
 	TabAlign tab_align = ALIGN_CENTER;
+	bool clip_tabs = true;
 	int rb_hover = -1;
 	bool rb_pressing = false;
 
@@ -148,6 +149,9 @@ public:
 	void set_tab_align(TabAlign p_align);
 	TabAlign get_tab_align() const;
 
+	void set_clip_tabs(bool p_clip_tabs);
+	bool get_clip_tabs() const;
+
 	void move_tab(int from, int to);
 
 	void set_tab_close_display_policy(CloseButtonDisplayPolicy p_policy);