diff options
Diffstat (limited to 'scene/gui/button.cpp')
-rw-r--r-- | scene/gui/button.cpp | 316 |
1 files changed, 263 insertions, 53 deletions
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index e400801b66..0cdfa9457e 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -30,11 +30,11 @@ #include "button.h" -#include "core/translation.h" +#include "core/string/translation.h" #include "servers/rendering_server.h" Size2 Button::get_minimum_size() const { - Size2 minsize = get_theme_font("font")->get_string_size(xl_text); + Size2 minsize = text_buf->get_size(); if (clip_text) { minsize.width = 0; } @@ -59,14 +59,25 @@ Size2 Button::get_minimum_size() const { return get_theme_stylebox("normal")->get_minimum_size() + minsize; } -void Button::_set_internal_margin(Margin p_margin, float p_value) { - _internal_margin[p_margin] = p_value; +void Button::_set_internal_margin(Side p_side, float p_value) { + _internal_margin[p_side] = p_value; } void Button::_notification(int p_what) { switch (p_what) { + case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: { + update(); + } break; case NOTIFICATION_TRANSLATION_CHANGED: { xl_text = tr(text); + _shape(); + + minimum_size_changed(); + update(); + } break; + case NOTIFICATION_THEME_CHANGED: { + _shape(); + minimum_size_changed(); update(); } break; @@ -77,10 +88,16 @@ void Button::_notification(int p_what) { Color color_icon(1, 1, 1, 1); Ref<StyleBox> style = get_theme_stylebox("normal"); + bool rtl = is_layout_rtl(); switch (get_draw_mode()) { case DRAW_NORMAL: { - style = get_theme_stylebox("normal"); + if (rtl && has_theme_stylebox("normal_mirrored")) { + style = get_theme_stylebox("normal_mirrored"); + } else { + style = get_theme_stylebox("normal"); + } + if (!flat) { style->draw(ci, Rect2(Point2(0, 0), size)); } @@ -91,7 +108,12 @@ void Button::_notification(int p_what) { } break; case DRAW_HOVER_PRESSED: { if (has_theme_stylebox("hover_pressed") && has_theme_stylebox_override("hover_pressed")) { - style = get_theme_stylebox("hover_pressed"); + if (rtl && has_theme_stylebox("hover_pressed_mirrored")) { + style = get_theme_stylebox("hover_pressed_mirrored"); + } else { + style = get_theme_stylebox("hover_pressed"); + } + if (!flat) { style->draw(ci, Rect2(Point2(0, 0), size)); } @@ -109,7 +131,12 @@ void Button::_notification(int p_what) { [[fallthrough]]; } case DRAW_PRESSED: { - style = get_theme_stylebox("pressed"); + if (rtl && has_theme_stylebox("pressed_mirrored")) { + style = get_theme_stylebox("pressed_mirrored"); + } else { + style = get_theme_stylebox("pressed"); + } + if (!flat) { style->draw(ci, Rect2(Point2(0, 0), size)); } @@ -124,7 +151,12 @@ void Button::_notification(int p_what) { } break; case DRAW_HOVER: { - style = get_theme_stylebox("hover"); + if (rtl && has_theme_stylebox("hover_mirrored")) { + style = get_theme_stylebox("hover_mirrored"); + } else { + style = get_theme_stylebox("hover"); + } + if (!flat) { style->draw(ci, Rect2(Point2(0, 0), size)); } @@ -135,7 +167,12 @@ void Button::_notification(int p_what) { } break; case DRAW_DISABLED: { - style = get_theme_stylebox("disabled"); + if (rtl && has_theme_stylebox("disabled_mirrored")) { + style = get_theme_stylebox("disabled_mirrored"); + } else { + style = get_theme_stylebox("disabled"); + } + if (!flat) { style->draw(ci, Rect2(Point2(0, 0), size)); } @@ -152,7 +189,6 @@ void Button::_notification(int p_what) { style2->draw(ci, Rect2(Point2(), size)); } - Ref<Font> font = get_theme_font("font"); Ref<Texture2D> _icon; if (icon.is_null() && has_theme_icon("icon")) { _icon = Control::get_theme_icon("icon"); @@ -168,15 +204,21 @@ void Button::_notification(int p_what) { } float icon_ofs_region = 0; - if (_internal_margin[MARGIN_LEFT] > 0) { - icon_ofs_region = _internal_margin[MARGIN_LEFT] + get_theme_constant("hseparation"); + if (rtl) { + if (_internal_margin[SIDE_RIGHT] > 0) { + icon_ofs_region = _internal_margin[SIDE_RIGHT] + get_theme_constant("hseparation"); + } + } else { + if (_internal_margin[SIDE_LEFT] > 0) { + icon_ofs_region = _internal_margin[SIDE_LEFT] + get_theme_constant("hseparation"); + } } if (expand_icon) { Size2 _size = get_size() - style->get_offset() * 2; _size.width -= get_theme_constant("hseparation") + icon_ofs_region; if (!clip_text) { - _size.width -= get_theme_font("font")->get_string_size(xl_text).width; + _size.width -= text_buf->get_size().width; } float icon_width = _icon->get_width() * _size.height / _icon->get_height(); float icon_height = _size.height; @@ -186,29 +228,49 @@ void Button::_notification(int p_what) { 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)); + if (rtl) { + icon_region = Rect2(Point2(size.width - (icon_ofs_region + icon_width + style->get_margin(SIDE_RIGHT)), style->get_margin(SIDE_TOP) + (_size.height - icon_height) / 2), Size2(icon_width, icon_height)); + } else { + 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()); + if (rtl) { + icon_region = Rect2(Point2(size.width - (icon_ofs_region + _icon->get_size().width + style->get_margin(SIDE_RIGHT)), style->get_margin(SIDE_TOP) + Math::floor((valign - _icon->get_height()) / 2.0)), _icon->get_size()); + } 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_theme_constant("hseparation"), 0) : Point2(); int text_clip = size.width - style->get_minimum_size().width - icon_ofs.width; - if (_internal_margin[MARGIN_LEFT] > 0) { - text_clip -= _internal_margin[MARGIN_LEFT] + get_theme_constant("hseparation"); + text_buf->set_width(clip_text ? text_clip : -1); + + int text_width = clip_text ? MIN(text_clip, text_buf->get_size().x) : text_buf->get_size().x; + + if (_internal_margin[SIDE_LEFT] > 0) { + text_clip -= _internal_margin[SIDE_LEFT] + get_theme_constant("hseparation"); } - if (_internal_margin[MARGIN_RIGHT] > 0) { - text_clip -= _internal_margin[MARGIN_RIGHT] + get_theme_constant("hseparation"); + if (_internal_margin[SIDE_RIGHT] > 0) { + text_clip -= _internal_margin[SIDE_RIGHT] + get_theme_constant("hseparation"); } - 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 - text_buf->get_size() - Point2(_internal_margin[SIDE_RIGHT] - _internal_margin[SIDE_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_theme_constant("hseparation"); + if (rtl) { + if (_internal_margin[SIDE_RIGHT] > 0) { + text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width - _internal_margin[SIDE_RIGHT] - get_theme_constant("hseparation"); + } else { + text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width; + } } else { - text_ofs.x = style->get_margin(MARGIN_LEFT) + icon_ofs.x; + if (_internal_margin[SIDE_LEFT] > 0) { + text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x + _internal_margin[SIDE_LEFT] + get_theme_constant("hseparation"); + } else { + text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x; + } } text_ofs.y += style->get_offset().y; } break; @@ -220,17 +282,34 @@ void Button::_notification(int p_what) { 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_theme_constant("hseparation"); + if (rtl) { + if (_internal_margin[SIDE_LEFT] > 0) { + text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x + _internal_margin[SIDE_LEFT] + get_theme_constant("hseparation"); + } else { + text_ofs.x = style->get_margin(SIDE_LEFT) + icon_ofs.x; + } } else { - text_ofs.x = size.x - style->get_margin(MARGIN_RIGHT) - font->get_string_size(xl_text).x; + if (_internal_margin[SIDE_RIGHT] > 0) { + text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width - _internal_margin[SIDE_RIGHT] - get_theme_constant("hseparation"); + } else { + text_ofs.x = size.x - style->get_margin(SIDE_RIGHT) - text_width; + } } 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 (rtl) { + text_ofs.x -= icon_ofs.x; + } + + Color font_outline_modulate = get_theme_color("font_outline_modulate"); + int outline_size = get_theme_constant("outline_size"); + if (outline_size > 0 && font_outline_modulate.a > 0) { + text_buf->draw_outline(ci, text_ofs.floor(), outline_size, font_outline_modulate); + } + + text_buf->draw(ci, text_ofs.floor(), color); if (!_icon.is_null() && icon_region.size.width > 0) { draw_texture_rect_region(_icon, icon_region, Rect2(Point2(), _icon->get_size()), color_icon); @@ -239,29 +318,90 @@ void Button::_notification(int p_what) { } } +void Button::_shape() { + Ref<Font> font = get_theme_font("font"); + int font_size = get_theme_font_size("font_size"); + + text_buf->clear(); + if (text_direction == Control::TEXT_DIRECTION_INHERITED) { + text_buf->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); + } else { + text_buf->set_direction((TextServer::Direction)text_direction); + } + text_buf->add_string(xl_text, font, font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale()); +} + void Button::set_text(const String &p_text) { - if (text == p_text) { - return; + if (text != p_text) { + text = p_text; + xl_text = tr(text); + _shape(); + + update(); + _change_notify("text"); + minimum_size_changed(); } - text = p_text; - xl_text = tr(p_text); - update(); - _change_notify("text"); - minimum_size_changed(); } String Button::get_text() const { return text; } -void Button::set_icon(const Ref<Texture2D> &p_icon) { - if (icon == p_icon) { - return; +void Button::set_text_direction(Control::TextDirection p_text_direction) { + ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3); + if (text_direction != p_text_direction) { + text_direction = p_text_direction; + _shape(); + update(); } - icon = p_icon; +} + +Control::TextDirection Button::get_text_direction() const { + return text_direction; +} + +void Button::clear_opentype_features() { + opentype_features.clear(); + _shape(); update(); - _change_notify("icon"); - minimum_size_changed(); +} + +void Button::set_opentype_feature(const String &p_name, int p_value) { + int32_t tag = TS->name_to_tag(p_name); + if (!opentype_features.has(tag) || (int)opentype_features[tag] != p_value) { + opentype_features[tag] = p_value; + _shape(); + update(); + } +} + +int Button::get_opentype_feature(const String &p_name) const { + int32_t tag = TS->name_to_tag(p_name); + if (!opentype_features.has(tag)) { + return -1; + } + return opentype_features[tag]; +} + +void Button::set_language(const String &p_language) { + if (language != p_language) { + language = p_language; + _shape(); + update(); + } +} + +String Button::get_language() const { + return language; +} + +void Button::set_icon(const Ref<Texture2D> &p_icon) { + if (icon != p_icon) { + icon = p_icon; + update(); + _change_notify("icon"); + minimum_size_changed(); + } } Ref<Texture2D> Button::get_icon() const { @@ -269,9 +409,11 @@ Ref<Texture2D> Button::get_icon() const { } void Button::set_expand_icon(bool p_expand_icon) { - expand_icon = p_expand_icon; - update(); - minimum_size_changed(); + if (expand_icon != p_expand_icon) { + expand_icon = p_expand_icon; + update(); + minimum_size_changed(); + } } bool Button::is_expand_icon() const { @@ -279,9 +421,11 @@ bool Button::is_expand_icon() const { } void Button::set_flat(bool p_flat) { - flat = p_flat; - update(); - _change_notify("flat"); + if (flat != p_flat) { + flat = p_flat; + update(); + _change_notify("flat"); + } } bool Button::is_flat() const { @@ -289,9 +433,11 @@ bool Button::is_flat() const { } void Button::set_clip_text(bool p_clip_text) { - clip_text = p_clip_text; - update(); - minimum_size_changed(); + if (clip_text != p_clip_text) { + clip_text = p_clip_text; + update(); + minimum_size_changed(); + } } bool Button::get_clip_text() const { @@ -299,17 +445,76 @@ bool Button::get_clip_text() const { } void Button::set_text_align(TextAlign p_align) { - align = p_align; - update(); + if (align != p_align) { + align = p_align; + update(); + } } Button::TextAlign Button::get_text_align() const { return align; } +bool Button::_set(const StringName &p_name, const Variant &p_value) { + String str = p_name; + if (str.begins_with("opentype_features/")) { + String name = str.get_slicec('/', 1); + int32_t tag = TS->name_to_tag(name); + double value = p_value; + if (value == -1) { + if (opentype_features.has(tag)) { + opentype_features.erase(tag); + _shape(); + update(); + } + } else { + if ((double)opentype_features[tag] != value) { + opentype_features[tag] = value; + _shape(); + update(); + } + } + _change_notify(); + return true; + } + + return false; +} + +bool Button::_get(const StringName &p_name, Variant &r_ret) const { + String str = p_name; + if (str.begins_with("opentype_features/")) { + String name = str.get_slicec('/', 1); + int32_t tag = TS->name_to_tag(name); + if (opentype_features.has(tag)) { + r_ret = opentype_features[tag]; + return true; + } else { + r_ret = -1; + return true; + } + } + return false; +} + +void Button::_get_property_list(List<PropertyInfo> *p_list) const { + for (const Variant *ftr = opentype_features.next(nullptr); ftr != nullptr; ftr = opentype_features.next(ftr)) { + String name = TS->tag_to_name(*ftr); + p_list->push_back(PropertyInfo(Variant::FLOAT, "opentype_features/" + name)); + } + p_list->push_back(PropertyInfo(Variant::NIL, "opentype_features/_new", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR)); +} + void Button::_bind_methods() { ClassDB::bind_method(D_METHOD("set_text", "text"), &Button::set_text); ClassDB::bind_method(D_METHOD("get_text"), &Button::get_text); + ClassDB::bind_method(D_METHOD("set_text_direction", "direction"), &Button::set_text_direction); + ClassDB::bind_method(D_METHOD("get_text_direction"), &Button::get_text_direction); + ClassDB::bind_method(D_METHOD("set_opentype_feature", "tag", "value"), &Button::set_opentype_feature); + ClassDB::bind_method(D_METHOD("get_opentype_feature", "tag"), &Button::get_opentype_feature); + ClassDB::bind_method(D_METHOD("clear_opentype_features"), &Button::clear_opentype_features); + ClassDB::bind_method(D_METHOD("set_language", "language"), &Button::set_language); + ClassDB::bind_method(D_METHOD("get_language"), &Button::get_language); 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("set_expand_icon"), &Button::set_expand_icon); @@ -325,7 +530,9 @@ void Button::_bind_methods() { BIND_ENUM_CONSTANT(ALIGN_CENTER); BIND_ENUM_CONSTANT(ALIGN_RIGHT); - ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "text", PROPERTY_HINT_MULTILINE_TEXT, "", PROPERTY_USAGE_DEFAULT_INTL), "set_text", "get_text"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,LTR,RTL,Inherited"), "set_text_direction", "get_text_direction"); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_button_icon", "get_button_icon"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "get_clip_text"); @@ -334,6 +541,9 @@ void Button::_bind_methods() { } Button::Button(const String &p_text) { + text_buf.instance(); + text_buf->set_flags(TextServer::BREAK_MANDATORY); + flat = false; clip_text = false; expand_icon = false; |