Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement vertical icon alignment for buttons #74369

Merged
merged 1 commit into from
May 8, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion doc/classes/Button.xml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
To edit margin and spacing of the icon, use [theme_item h_separation] theme property and [code]content_margin_*[/code] properties of the used [StyleBox]es.
</member>
<member name="icon_alignment" type="int" setter="set_icon_alignment" getter="get_icon_alignment" enum="HorizontalAlignment" default="0">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess a better name is horizontal_icon_alignment, but to keep backwards compatibility it is better to not touch it.
Still maybe an idea in the future.

Specifies if the icon should be aligned to the left, right, or center of a button. Uses the same [enum HorizontalAlignment] constants as the text alignment. If centered, text will draw on top of the icon.
Specifies if the icon should be aligned horizontally to the left, right, or center of a button. Uses the same [enum HorizontalAlignment] constants as the text alignment. If centered horizontally and vertically, text will draw on top of the icon.
</member>
<member name="language" type="String" setter="set_language" getter="get_language" default="&quot;&quot;">
Language code used for line-breaking and text shaping algorithms, if left empty current locale is used instead.
Expand All @@ -72,6 +72,9 @@
<member name="text_overrun_behavior" type="int" setter="set_text_overrun_behavior" getter="get_text_overrun_behavior" enum="TextServer.OverrunBehavior" default="0">
Sets the clipping behavior when the text exceeds the node's bounding rectangle. See [enum TextServer.OverrunBehavior] for a description of all modes.
</member>
<member name="vertical_icon_alignment" type="int" setter="set_vertical_icon_alignment" getter="get_vertical_icon_alignment" enum="VerticalAlignment" default="1">
Specifies if the icon should be aligned vertically to the top, bottom, or center of a button. Uses the same [enum VerticalAlignment] constants as the text alignment. If centered horizontally and vertically, text will draw on top of the icon.
</member>
</members>
<theme_items>
<theme_item name="font_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)">
Expand Down
69 changes: 57 additions & 12 deletions scene/gui/button.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,13 +233,13 @@ void Button::_notification(int p_what) {
}

Rect2 icon_region;
HorizontalAlignment icon_align_rtl_checked = icon_alignment;
HorizontalAlignment icon_align_rtl_checked = horizontal_icon_alignment;
HorizontalAlignment align_rtl_checked = alignment;
// Swap icon and text alignment sides if right-to-left layout is set.
if (rtl) {
if (icon_alignment == HORIZONTAL_ALIGNMENT_RIGHT) {
if (horizontal_icon_alignment == HORIZONTAL_ALIGNMENT_RIGHT) {
icon_align_rtl_checked = HORIZONTAL_ALIGNMENT_LEFT;
} else if (icon_alignment == HORIZONTAL_ALIGNMENT_LEFT) {
} else if (horizontal_icon_alignment == HORIZONTAL_ALIGNMENT_LEFT) {
icon_align_rtl_checked = HORIZONTAL_ALIGNMENT_RIGHT;
}
if (alignment == HORIZONTAL_ALIGNMENT_RIGHT) {
Expand All @@ -251,6 +251,14 @@ void Button::_notification(int p_what) {
if (!_icon.is_null()) {
int valign = size.height - style->get_minimum_size().y;

int voffset = 0;
Size2 icon_size = _icon->get_size();

// Fix vertical size.
if (vertical_icon_alignment != VERTICAL_ALIGNMENT_CENTER) {
valign -= text_buf->get_size().height;
}

float icon_ofs_region = 0.0;
Point2 style_offset;
if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_LEFT) {
Expand All @@ -268,14 +276,16 @@ void Button::_notification(int p_what) {
}
style_offset.y = style->get_margin(SIDE_TOP);

Size2 icon_size = _icon->get_size();
if (expand_icon) {
Size2 _size = get_size() - style->get_offset() * 2;
int icon_text_separation = text.is_empty() ? 0 : theme_cache.h_separation;
_size.width -= icon_text_separation + icon_ofs_region;
if (!clip_text && icon_align_rtl_checked != HORIZONTAL_ALIGNMENT_CENTER) {
_size.width -= text_buf->get_size().width;
}
if (vertical_icon_alignment != VERTICAL_ALIGNMENT_CENTER) {
_size.height -= text_buf->get_size().height;
}
float icon_width = _icon->get_width() * _size.height / _icon->get_height();
float icon_height = _size.height;

Expand All @@ -288,12 +298,19 @@ void Button::_notification(int p_what) {
}
icon_size = _fit_icon_size(icon_size);

if (vertical_icon_alignment == VERTICAL_ALIGNMENT_TOP) {
voffset = -(valign - icon_size.y) / 2;
}
if (vertical_icon_alignment == VERTICAL_ALIGNMENT_BOTTOM) {
voffset = (valign - icon_size.y) / 2 + text_buf->get_size().y;
}

if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_LEFT) {
icon_region = Rect2(style_offset + Point2(icon_ofs_region, Math::floor((valign - icon_size.y) * 0.5)), icon_size);
icon_region = Rect2(style_offset + Point2(icon_ofs_region, voffset + Math::floor((valign - icon_size.y) * 0.5)), icon_size);
} else if (icon_align_rtl_checked == HORIZONTAL_ALIGNMENT_CENTER) {
icon_region = Rect2(style_offset + Point2(icon_ofs_region + Math::floor((size.x - icon_size.x) * 0.5), Math::floor((valign - icon_size.y) * 0.5)), icon_size);
icon_region = Rect2(style_offset + Point2(icon_ofs_region + Math::floor((size.x - icon_size.x) * 0.5), voffset + Math::floor((valign - icon_size.y) * 0.5)), icon_size);
} else {
icon_region = Rect2(style_offset + Point2(icon_ofs_region + size.x - icon_size.x, Math::floor((valign - icon_size.y) * 0.5)), icon_size);
icon_region = Rect2(style_offset + Point2(icon_ofs_region + size.x - icon_size.x, voffset + Math::floor((valign - icon_size.y) * 0.5)), icon_size);
}

if (icon_region.size.width > 0) {
Expand All @@ -320,6 +337,13 @@ void Button::_notification(int p_what) {

Point2 text_ofs = (size - style->get_minimum_size() - icon_ofs - text_buf->get_size() - Point2(_internal_margin[SIDE_RIGHT] - _internal_margin[SIDE_LEFT], 0)) / 2.0;

if (vertical_icon_alignment == VERTICAL_ALIGNMENT_TOP) {
text_ofs.y += icon_region.size.height / 2;
}
if (vertical_icon_alignment == VERTICAL_ALIGNMENT_BOTTOM) {
text_ofs.y -= icon_region.size.height / 2;
}

text_buf->set_alignment(align_rtl_checked);
text_buf->set_width(text_width);
switch (align_rtl_checked) {
Expand Down Expand Up @@ -395,9 +419,13 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu

if (!expand_icon && p_icon.is_valid()) {
Size2 icon_size = _fit_icon_size(p_icon->get_size());
minsize.height = MAX(minsize.height, icon_size.height);
if (vertical_icon_alignment == VERTICAL_ALIGNMENT_CENTER) {
minsize.height = MAX(minsize.height, icon_size.height);
} else {
minsize.height += icon_size.height;
}

if (icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) {
if (horizontal_icon_alignment != HORIZONTAL_ALIGNMENT_CENTER) {
minsize.width += icon_size.width;
if (!xl_text.is_empty() || !p_text.is_empty()) {
minsize.width += MAX(0, theme_cache.h_separation);
Expand All @@ -410,7 +438,11 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Ref<Textu
if (!xl_text.is_empty() || !p_text.is_empty()) {
Ref<Font> font = theme_cache.font;
float font_height = font->get_height(theme_cache.font_size);
minsize.height = MAX(font_height, minsize.height);
if (vertical_icon_alignment == VERTICAL_ALIGNMENT_CENTER) {
minsize.height = MAX(font_height, minsize.height);
} else {
minsize.height += font_height;
}
}

return theme_cache.normal->get_minimum_size() + minsize;
Expand Down Expand Up @@ -556,13 +588,23 @@ HorizontalAlignment Button::get_text_alignment() const {
}

void Button::set_icon_alignment(HorizontalAlignment p_alignment) {
icon_alignment = p_alignment;
horizontal_icon_alignment = p_alignment;
update_minimum_size();
queue_redraw();
}

void Button::set_vertical_icon_alignment(VerticalAlignment p_alignment) {
vertical_icon_alignment = p_alignment;
update_minimum_size();
queue_redraw();
}

HorizontalAlignment Button::get_icon_alignment() const {
return icon_alignment;
return horizontal_icon_alignment;
}

VerticalAlignment Button::get_vertical_icon_alignment() const {
return vertical_icon_alignment;
}

void Button::_bind_methods() {
Expand All @@ -584,6 +626,8 @@ void Button::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_text_alignment"), &Button::get_text_alignment);
ClassDB::bind_method(D_METHOD("set_icon_alignment", "icon_alignment"), &Button::set_icon_alignment);
ClassDB::bind_method(D_METHOD("get_icon_alignment"), &Button::get_icon_alignment);
ClassDB::bind_method(D_METHOD("set_vertical_icon_alignment", "vertical_icon_alignment"), &Button::set_vertical_icon_alignment);
ClassDB::bind_method(D_METHOD("get_vertical_icon_alignment"), &Button::get_vertical_icon_alignment);
ClassDB::bind_method(D_METHOD("set_expand_icon", "enabled"), &Button::set_expand_icon);
ClassDB::bind_method(D_METHOD("is_expand_icon"), &Button::is_expand_icon);

Expand All @@ -598,6 +642,7 @@ void Button::_bind_methods() {

ADD_GROUP("Icon Behavior", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_icon_alignment", "get_icon_alignment");
ADD_PROPERTY(PropertyInfo(Variant::INT, "vertical_icon_alignment", PROPERTY_HINT_ENUM, "Top,Center,Bottom"), "set_vertical_icon_alignment", "get_vertical_icon_alignment");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_icon"), "set_expand_icon", "is_expand_icon");

ADD_GROUP("BiDi", "");
Expand Down
5 changes: 4 additions & 1 deletion scene/gui/button.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,8 @@ class Button : public BaseButton {
bool expand_icon = false;
bool clip_text = false;
HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_CENTER;
HorizontalAlignment icon_alignment = HORIZONTAL_ALIGNMENT_LEFT;
HorizontalAlignment horizontal_icon_alignment = HORIZONTAL_ALIGNMENT_LEFT;
VerticalAlignment vertical_icon_alignment = VERTICAL_ALIGNMENT_CENTER;
float _internal_margin[4] = {};

struct ThemeCache {
Expand Down Expand Up @@ -135,7 +136,9 @@ class Button : public BaseButton {
HorizontalAlignment get_text_alignment() const;

void set_icon_alignment(HorizontalAlignment p_alignment);
void set_vertical_icon_alignment(VerticalAlignment p_alignment);
HorizontalAlignment get_icon_alignment() const;
VerticalAlignment get_vertical_icon_alignment() const;

Button(const String &p_text = String());
~Button();
Expand Down