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

This commit is contained in:
Michael Alexsander Silva Dias 2019-08-20 13:41:14 -03:00
parent 208dd5b4a6
commit 9b09daa8c5
4 changed files with 208 additions and 156 deletions

View File

@ -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>

View File

@ -39,6 +39,7 @@ Size2 Button::get_minimum_size() const {
if (clip_text) if (clip_text)
minsize.width = 0; minsize.width = 0;
if (!expand_icon) {
Ref<Texture> _icon; Ref<Texture> _icon;
if (icon.is_null() && has_icon("icon")) if (icon.is_null() && has_icon("icon"))
_icon = Control::get_icon("icon"); _icon = Control::get_icon("icon");
@ -52,24 +53,26 @@ Size2 Button::get_minimum_size() const {
if (xl_text != "") if (xl_text != "")
minsize.width += get_constant("hseparation"); 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); xl_text = tr(text);
minimum_size_changed(); minimum_size_changed();
update(); update();
} } break;
case NOTIFICATION_DRAW: {
if (p_what == NOTIFICATION_DRAW) {
RID ci = get_canvas_item(); RID ci = get_canvas_item();
Size2 size = get_size(); Size2 size = get_size();
@ -79,7 +82,6 @@ void Button::_notification(int p_what) {
Ref<StyleBox> style = get_stylebox("normal"); Ref<StyleBox> style = get_stylebox("normal");
switch (get_draw_mode()) { switch (get_draw_mode()) {
case DRAW_NORMAL: { case DRAW_NORMAL: {
style = get_stylebox("normal"); style = get_stylebox("normal");
@ -90,6 +92,7 @@ void Button::_notification(int p_what) {
color_icon = get_color("icon_color_normal"); color_icon = get_color("icon_color_normal");
} break; } break;
case DRAW_HOVER_PRESSED: { case DRAW_HOVER_PRESSED: {
if (has_stylebox("hover_pressed") && has_stylebox_override("hover_pressed")) { if (has_stylebox("hover_pressed") && has_stylebox_override("hover_pressed")) {
style = get_stylebox("hover_pressed"); style = get_stylebox("hover_pressed");
if (!flat) if (!flat)
@ -153,7 +156,39 @@ void Button::_notification(int p_what) {
else else
_icon = icon; _icon = icon;
Point2 icon_ofs = (!_icon.is_null()) ? Point2(_icon->get_width() + get_constant("hseparation"), 0) : Point2(); Rect2 icon_region = Rect2();
if (!_icon.is_null()) {
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) {
icon_ofs_region = _internal_margin[MARGIN_LEFT] + 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 {
icon_region = Rect2(style->get_offset() + Point2(icon_ofs_region, Math::floor((valign - _icon->get_height()) / 2.0)), icon->get_size());
}
}
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; 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; 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;
@ -184,17 +219,11 @@ void Button::_notification(int p_what) {
text_ofs.y += font->get_ascent(); text_ofs.y += font->get_ascent();
font->draw(ci, text_ofs.floor(), xl_text, color, clip_text ? text_clip : -1); font->draw(ci, text_ofs.floor(), xl_text, color, clip_text ? text_clip : -1);
if (!_icon.is_null()) {
int valign = size.height - style->get_minimum_size().y; if (!_icon.is_null() && icon_region.size.width > 0) {
if (is_disabled()) draw_texture_rect_region(_icon, icon_region, Rect2(Point2(), icon->get_size()), color_icon);
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);
}
} }
} 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;

View File

@ -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;

View File

@ -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); Size2 scale_size(size.width / tex_size.width, size.height / tex_size.height);
float scale = scaleSize.width > scaleSize.height ? scaleSize.width : scaleSize.height; float scale = scale_size.width > scale_size.height ? scale_size.width : scale_size.height;
Size2 scaledTexSize = tex_size * scale; Size2 scaled_tex_size = tex_size * scale;
Point2 ofs2 = ((scaledTexSize - size) / scale).abs() / 2.0f; 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;