Browse Source

Add feature to Button to make its icon expand/shrink with the button's size

Michael Alexsander Silva Dias 6 years ago
parent
commit
9b09daa8c5
4 changed files with 182 additions and 130 deletions
  1. 3 0
      doc/classes/Button.xml
  2. 166 121
      scene/gui/button.cpp
  3. 4 2
      scene/gui/button.h
  4. 9 7
      scene/gui/texture_button.cpp

+ 3 - 0
doc/classes/Button.xml

@@ -17,6 +17,9 @@
 		<member name="clip_text" type="bool" setter="set_clip_text" getter="get_clip_text" default="false">
 		<member name="clip_text" type="bool" setter="set_clip_text" getter="get_clip_text" default="false">
 			When this property is enabled, text that is too large to fit the button is clipped, when disabled the Button will always be wide enough to hold the text.
 			When this property is enabled, text that is too large to fit the button is clipped, when disabled the Button will always be wide enough to hold the text.
 		</member>
 		</member>
+		<member name="expand_icon" type="bool" setter="set_expand_icon" getter="is_expand_icon" default="false">
+			When enabled, the button's icon will expand/shrink to fit the button's size while keeping its aspect.
+		</member>
 		<member name="flat" type="bool" setter="set_flat" getter="is_flat" default="false">
 		<member name="flat" type="bool" setter="set_flat" getter="is_flat" default="false">
 			Flat buttons don't display decoration.
 			Flat buttons don't display decoration.
 		</member>
 		</member>

+ 166 - 121
scene/gui/button.cpp

@@ -39,162 +39,191 @@ Size2 Button::get_minimum_size() const {
 	if (clip_text)
 	if (clip_text)
 		minsize.width = 0;
 		minsize.width = 0;
 
 
-	Ref<Texture> _icon;
-	if (icon.is_null() && has_icon("icon"))
-		_icon = Control::get_icon("icon");
-	else
-		_icon = icon;
-
-	if (!_icon.is_null()) {
-
-		minsize.height = MAX(minsize.height, _icon->get_height());
-		minsize.width += _icon->get_width();
-		if (xl_text != "")
-			minsize.width += get_constant("hseparation");
+	if (!expand_icon) {
+		Ref<Texture> _icon;
+		if (icon.is_null() && has_icon("icon"))
+			_icon = Control::get_icon("icon");
+		else
+			_icon = icon;
+
+		if (!_icon.is_null()) {
+
+			minsize.height = MAX(minsize.height, _icon->get_height());
+			minsize.width += _icon->get_width();
+			if (xl_text != "")
+				minsize.width += get_constant("hseparation");
+		}
 	}
 	}
 
 
 	return get_stylebox("normal")->get_minimum_size() + minsize;
 	return get_stylebox("normal")->get_minimum_size() + minsize;
 }
 }
 
 
 void Button::_set_internal_margin(Margin p_margin, float p_value) {
 void Button::_set_internal_margin(Margin p_margin, float p_value) {
+
 	_internal_margin[p_margin] = p_value;
 	_internal_margin[p_margin] = p_value;
 }
 }
 
 
 void Button::_notification(int p_what) {
 void Button::_notification(int p_what) {
 
 
-	if (p_what == NOTIFICATION_TRANSLATION_CHANGED) {
+	switch (p_what) {
+		case NOTIFICATION_TRANSLATION_CHANGED: {
 
 
-		xl_text = tr(text);
-		minimum_size_changed();
-		update();
-	}
+			xl_text = tr(text);
+			minimum_size_changed();
+			update();
+		} break;
+		case NOTIFICATION_DRAW: {
 
 
-	if (p_what == NOTIFICATION_DRAW) {
+			RID ci = get_canvas_item();
+			Size2 size = get_size();
+			Color color;
+			Color color_icon(1, 1, 1, 1);
 
 
-		RID ci = get_canvas_item();
-		Size2 size = get_size();
-		Color color;
-		Color color_icon(1, 1, 1, 1);
+			Ref<StyleBox> style = get_stylebox("normal");
 
 
-		Ref<StyleBox> style = get_stylebox("normal");
+			switch (get_draw_mode()) {
+				case DRAW_NORMAL: {
 
 
-		switch (get_draw_mode()) {
-
-			case DRAW_NORMAL: {
+					style = get_stylebox("normal");
+					if (!flat)
+						style->draw(ci, Rect2(Point2(0, 0), size));
+					color = get_color("font_color");
+					if (has_color("icon_color_normal"))
+						color_icon = get_color("icon_color_normal");
+				} break;
+				case DRAW_HOVER_PRESSED: {
+
+					if (has_stylebox("hover_pressed") && has_stylebox_override("hover_pressed")) {
+						style = get_stylebox("hover_pressed");
+						if (!flat)
+							style->draw(ci, Rect2(Point2(0, 0), size));
+						if (has_color("font_color_hover_pressed"))
+							color = get_color("font_color_hover_pressed");
+						else
+							color = get_color("font_color");
+						if (has_color("icon_color_hover_pressed"))
+							color_icon = get_color("icon_color_hover_pressed");
+
+						break;
+					}
+					FALLTHROUGH;
+				}
+				case DRAW_PRESSED: {
 
 
-				style = get_stylebox("normal");
-				if (!flat)
-					style->draw(ci, Rect2(Point2(0, 0), size));
-				color = get_color("font_color");
-				if (has_color("icon_color_normal"))
-					color_icon = get_color("icon_color_normal");
-			} break;
-			case DRAW_HOVER_PRESSED: {
-				if (has_stylebox("hover_pressed") && has_stylebox_override("hover_pressed")) {
-					style = get_stylebox("hover_pressed");
+					style = get_stylebox("pressed");
 					if (!flat)
 					if (!flat)
 						style->draw(ci, Rect2(Point2(0, 0), size));
 						style->draw(ci, Rect2(Point2(0, 0), size));
-					if (has_color("font_color_hover_pressed"))
-						color = get_color("font_color_hover_pressed");
+					if (has_color("font_color_pressed"))
+						color = get_color("font_color_pressed");
 					else
 					else
 						color = get_color("font_color");
 						color = get_color("font_color");
-					if (has_color("icon_color_hover_pressed"))
-						color_icon = get_color("icon_color_hover_pressed");
+					if (has_color("icon_color_pressed"))
+						color_icon = get_color("icon_color_pressed");
 
 
-					break;
-				}
-				FALLTHROUGH;
+				} break;
+				case DRAW_HOVER: {
+
+					style = get_stylebox("hover");
+					if (!flat)
+						style->draw(ci, Rect2(Point2(0, 0), size));
+					color = get_color("font_color_hover");
+					if (has_color("icon_color_hover"))
+						color_icon = get_color("icon_color_hover");
+
+				} break;
+				case DRAW_DISABLED: {
+
+					style = get_stylebox("disabled");
+					if (!flat)
+						style->draw(ci, Rect2(Point2(0, 0), size));
+					color = get_color("font_color_disabled");
+					if (has_color("icon_color_disabled"))
+						color_icon = get_color("icon_color_disabled");
+
+				} break;
 			}
 			}
-			case DRAW_PRESSED: {
-
-				style = get_stylebox("pressed");
-				if (!flat)
-					style->draw(ci, Rect2(Point2(0, 0), size));
-				if (has_color("font_color_pressed"))
-					color = get_color("font_color_pressed");
-				else
-					color = get_color("font_color");
-				if (has_color("icon_color_pressed"))
-					color_icon = get_color("icon_color_pressed");
-
-			} break;
-			case DRAW_HOVER: {
-
-				style = get_stylebox("hover");
-				if (!flat)
-					style->draw(ci, Rect2(Point2(0, 0), size));
-				color = get_color("font_color_hover");
-				if (has_color("icon_color_hover"))
-					color_icon = get_color("icon_color_hover");
-
-			} break;
-			case DRAW_DISABLED: {
-
-				style = get_stylebox("disabled");
-				if (!flat)
-					style->draw(ci, Rect2(Point2(0, 0), size));
-				color = get_color("font_color_disabled");
-				if (has_color("icon_color_disabled"))
-					color_icon = get_color("icon_color_disabled");
-
-			} break;
-		}
 
 
-		if (has_focus()) {
+			if (has_focus()) {
 
 
-			Ref<StyleBox> style2 = get_stylebox("focus");
-			style2->draw(ci, Rect2(Point2(), size));
-		}
+				Ref<StyleBox> style2 = get_stylebox("focus");
+				style2->draw(ci, Rect2(Point2(), size));
+			}
 
 
-		Ref<Font> font = get_font("font");
-		Ref<Texture> _icon;
-		if (icon.is_null() && has_icon("icon"))
-			_icon = Control::get_icon("icon");
-		else
-			_icon = icon;
+			Ref<Font> font = get_font("font");
+			Ref<Texture> _icon;
+			if (icon.is_null() && has_icon("icon"))
+				_icon = Control::get_icon("icon");
+			else
+				_icon = icon;
 
 
-		Point2 icon_ofs = (!_icon.is_null()) ? Point2(_icon->get_width() + get_constant("hseparation"), 0) : Point2();
-		int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width;
-		Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - font->get_string_size(xl_text) - Point2(_internal_margin[MARGIN_RIGHT] - _internal_margin[MARGIN_LEFT], 0)) / 2.0;
+			Rect2 icon_region = Rect2();
+			if (!_icon.is_null()) {
 
 
-		switch (align) {
-			case ALIGN_LEFT: {
+				int valign = size.height - style->get_minimum_size().y;
+				if (is_disabled()) {
+					color_icon.a = 0.4;
+				}
+
+				float icon_ofs_region = 0;
 				if (_internal_margin[MARGIN_LEFT] > 0) {
 				if (_internal_margin[MARGIN_LEFT] > 0) {
-					text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x + _internal_margin[MARGIN_LEFT] + get_constant("hseparation");
-				} else {
-					text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x;
+					icon_ofs_region = _internal_margin[MARGIN_LEFT] + get_constant("hseparation");
 				}
 				}
-				text_ofs.y += style->get_offset().y;
-			} break;
-			case ALIGN_CENTER: {
-				if (text_ofs.x < 0)
-					text_ofs.x = 0;
-				text_ofs += icon_ofs;
-				text_ofs += style->get_offset();
-			} break;
-			case ALIGN_RIGHT: {
-				if (_internal_margin[MARGIN_RIGHT] > 0) {
-					text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x - _internal_margin[MARGIN_RIGHT] - get_constant("hseparation");
+
+				if (expand_icon) {
+					Size2 _size = get_size() - style->get_offset() * 2;
+					_size.width -= get_constant("hseparation") + icon_ofs_region;
+					if (!clip_text)
+						_size.width -= get_font("font")->get_string_size(xl_text).width;
+					float icon_width = icon->get_width() * _size.height / icon->get_height();
+					float icon_height = _size.height;
+
+					if (icon_width > _size.width) {
+						icon_width = _size.width;
+						icon_height = icon->get_height() * icon_width / icon->get_width();
+					}
+
+					icon_region = Rect2(style->get_offset() + Point2(icon_ofs_region, (_size.height - icon_height) / 2), Size2(icon_width, icon_height));
 				} else {
 				} else {
-					text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x;
+					icon_region = Rect2(style->get_offset() + Point2(icon_ofs_region, Math::floor((valign - _icon->get_height()) / 2.0)), icon->get_size());
 				}
 				}
-				text_ofs.y += style->get_offset().y;
-			} break;
-		}
+			}
 
 
-		text_ofs.y += font->get_ascent();
-		font->draw(ci, text_ofs.floor(), xl_text, color, clip_text ? text_clip : -1);
-		if (!_icon.is_null()) {
+			Point2 icon_ofs = !_icon.is_null() ? Point2(icon_region.size.width + get_constant("hseparation"), 0) : Point2();
+			int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width;
+			Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - font->get_string_size(xl_text) - Point2(_internal_margin[MARGIN_RIGHT] - _internal_margin[MARGIN_LEFT], 0)) / 2.0;
+
+			switch (align) {
+				case ALIGN_LEFT: {
+					if (_internal_margin[MARGIN_LEFT] > 0) {
+						text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x + _internal_margin[MARGIN_LEFT] + get_constant("hseparation");
+					} else {
+						text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x;
+					}
+					text_ofs.y += style->get_offset().y;
+				} break;
+				case ALIGN_CENTER: {
+					if (text_ofs.x < 0)
+						text_ofs.x = 0;
+					text_ofs += icon_ofs;
+					text_ofs += style->get_offset();
+				} break;
+				case ALIGN_RIGHT: {
+					if (_internal_margin[MARGIN_RIGHT] > 0) {
+						text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x - _internal_margin[MARGIN_RIGHT] - get_constant("hseparation");
+					} else {
+						text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x;
+					}
+					text_ofs.y += style->get_offset().y;
+				} break;
+			}
+
+			text_ofs.y += font->get_ascent();
+			font->draw(ci, text_ofs.floor(), xl_text, color, clip_text ? text_clip : -1);
 
 
-			int valign = size.height - style->get_minimum_size().y;
-			if (is_disabled())
-				color_icon.a = 0.4;
-			if (_internal_margin[MARGIN_LEFT] > 0) {
-				_icon->draw(ci, style->get_offset() + Point2(_internal_margin[MARGIN_LEFT] + get_constant("hseparation"), Math::floor((valign - _icon->get_height()) / 2.0)), color_icon);
-			} else {
-				_icon->draw(ci, style->get_offset() + Point2(0, Math::floor((valign - _icon->get_height()) / 2.0)), color_icon);
+			if (!_icon.is_null() && icon_region.size.width > 0) {
+				draw_texture_rect_region(_icon, icon_region, Rect2(Point2(), icon->get_size()), color_icon);
 			}
 			}
-		}
+		} break;
 	}
 	}
 }
 }
 
 
@@ -228,6 +257,18 @@ Ref<Texture> Button::get_icon() const {
 	return icon;
 	return icon;
 }
 }
 
 
+void Button::set_expand_icon(bool p_expand_icon) {
+
+	expand_icon = p_expand_icon;
+	update();
+	minimum_size_changed();
+}
+
+bool Button::is_expand_icon() const {
+
+	return expand_icon;
+}
+
 void Button::set_flat(bool p_flat) {
 void Button::set_flat(bool p_flat) {
 
 
 	flat = p_flat;
 	flat = p_flat;
@@ -269,6 +310,8 @@ void Button::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("get_text"), &Button::get_text);
 	ClassDB::bind_method(D_METHOD("get_text"), &Button::get_text);
 	ClassDB::bind_method(D_METHOD("set_button_icon", "texture"), &Button::set_icon);
 	ClassDB::bind_method(D_METHOD("set_button_icon", "texture"), &Button::set_icon);
 	ClassDB::bind_method(D_METHOD("get_button_icon"), &Button::get_icon);
 	ClassDB::bind_method(D_METHOD("get_button_icon"), &Button::get_icon);
+	ClassDB::bind_method(D_METHOD("set_expand_icon"), &Button::set_expand_icon);
+	ClassDB::bind_method(D_METHOD("is_expand_icon"), &Button::is_expand_icon);
 	ClassDB::bind_method(D_METHOD("set_flat", "enabled"), &Button::set_flat);
 	ClassDB::bind_method(D_METHOD("set_flat", "enabled"), &Button::set_flat);
 	ClassDB::bind_method(D_METHOD("set_clip_text", "enabled"), &Button::set_clip_text);
 	ClassDB::bind_method(D_METHOD("set_clip_text", "enabled"), &Button::set_clip_text);
 	ClassDB::bind_method(D_METHOD("get_clip_text"), &Button::get_clip_text);
 	ClassDB::bind_method(D_METHOD("get_clip_text"), &Button::get_clip_text);
@@ -285,12 +328,14 @@ void Button::_bind_methods() {
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "get_clip_text");
 	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "get_clip_text");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_text_align", "get_text_align");
 	ADD_PROPERTY(PropertyInfo(Variant::INT, "align", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_text_align", "get_text_align");
+	ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_icon"), "set_expand_icon", "is_expand_icon");
 }
 }
 
 
 Button::Button(const String &p_text) {
 Button::Button(const String &p_text) {
 
 
 	flat = false;
 	flat = false;
 	clip_text = false;
 	clip_text = false;
+	expand_icon = false;
 	set_mouse_filter(MOUSE_FILTER_STOP);
 	set_mouse_filter(MOUSE_FILTER_STOP);
 	set_text(p_text);
 	set_text(p_text);
 	align = ALIGN_CENTER;
 	align = ALIGN_CENTER;

+ 4 - 2
scene/gui/button.h

@@ -49,6 +49,7 @@ private:
 	String text;
 	String text;
 	String xl_text;
 	String xl_text;
 	Ref<Texture> icon;
 	Ref<Texture> icon;
+	bool expand_icon;
 	bool clip_text;
 	bool clip_text;
 	TextAlign align;
 	TextAlign align;
 	float _internal_margin[4];
 	float _internal_margin[4];
@@ -59,8 +60,6 @@ protected:
 	static void _bind_methods();
 	static void _bind_methods();
 
 
 public:
 public:
-	//
-
 	virtual Size2 get_minimum_size() const;
 	virtual Size2 get_minimum_size() const;
 
 
 	void set_text(const String &p_text);
 	void set_text(const String &p_text);
@@ -69,6 +68,9 @@ public:
 	void set_icon(const Ref<Texture> &p_icon);
 	void set_icon(const Ref<Texture> &p_icon);
 	Ref<Texture> get_icon() const;
 	Ref<Texture> get_icon() const;
 
 
+	void set_expand_icon(bool p_expand_icon);
+	bool is_expand_icon() const;
+
 	void set_flat(bool p_flat);
 	void set_flat(bool p_flat);
 	bool is_flat() const;
 	bool is_flat() const;
 
 

+ 9 - 7
scene/gui/texture_button.cpp

@@ -205,24 +205,26 @@ void TextureButton::_notification(int p_what) {
 						case STRETCH_KEEP_ASPECT_COVERED: {
 						case STRETCH_KEEP_ASPECT_COVERED: {
 							size = get_size();
 							size = get_size();
 							Size2 tex_size = texdraw->get_size();
 							Size2 tex_size = texdraw->get_size();
-							Size2 scaleSize(size.width / tex_size.width, size.height / tex_size.height);
-							float scale = scaleSize.width > scaleSize.height ? scaleSize.width : scaleSize.height;
-							Size2 scaledTexSize = tex_size * scale;
-							Point2 ofs2 = ((scaledTexSize - size) / scale).abs() / 2.0f;
+							Size2 scale_size(size.width / tex_size.width, size.height / tex_size.height);
+							float scale = scale_size.width > scale_size.height ? scale_size.width : scale_size.height;
+							Size2 scaled_tex_size = tex_size * scale;
+							Point2 ofs2 = ((scaled_tex_size - size) / scale).abs() / 2.0f;
 							_texture_region = Rect2(ofs2, size / scale);
 							_texture_region = Rect2(ofs2, size / scale);
 						} break;
 						} break;
 					}
 					}
 				}
 				}
+
 				_position_rect = Rect2(ofs, size);
 				_position_rect = Rect2(ofs, size);
-				if (_tile)
+				if (_tile) {
 					draw_texture_rect(texdraw, _position_rect, _tile);
 					draw_texture_rect(texdraw, _position_rect, _tile);
-				else
+				} else {
 					draw_texture_rect_region(texdraw, _position_rect, _texture_region);
 					draw_texture_rect_region(texdraw, _position_rect, _texture_region);
+				}
 			} else {
 			} else {
 				_position_rect = Rect2();
 				_position_rect = Rect2();
 			}
 			}
-			if (has_focus() && focused.is_valid()) {
 
 
+			if (has_focus() && focused.is_valid()) {
 				draw_texture_rect(focused, _position_rect, false);
 				draw_texture_rect(focused, _position_rect, false);
 			};
 			};
 		} break;
 		} break;