From 00480fc8180053fa2d2ca42039756c1f619245c4 Mon Sep 17 00:00:00 2001 From: bruvzg <7645683+bruvzg@users.noreply.github.com> Date: Tue, 9 Jan 2024 22:12:26 +0200 Subject: [PATCH] [Button] Add autowrap feature. --- doc/classes/Button.xml | 3 +++ scene/gui/button.cpp | 46 ++++++++++++++++++++++++++++++++++++++++-- scene/gui/button.h | 4 ++++ 3 files changed, 51 insertions(+), 2 deletions(-) diff --git a/doc/classes/Button.xml b/doc/classes/Button.xml index d7782a816dc..36fb818f9b3 100644 --- a/doc/classes/Button.xml +++ b/doc/classes/Button.xml @@ -43,6 +43,9 @@ Text alignment policy for the button's text, use one of the [enum HorizontalAlignment] constants. + + If set to something other than [constant TextServer.AUTOWRAP_OFF], the text gets wrapped inside the node's bounding rectangle. + 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. diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp index a4eddb832d3..978fb56f786 100644 --- a/scene/gui/button.cpp +++ b/scene/gui/button.cpp @@ -128,6 +128,15 @@ void Button::_notification(int p_what) { queue_redraw(); } break; + case NOTIFICATION_RESIZED: { + if (autowrap_mode != TextServer::AUTOWRAP_OFF) { + _shape(); + + update_minimum_size(); + queue_redraw(); + } + } break; + case NOTIFICATION_DRAW: { const RID ci = get_canvas_item(); const Size2 size = get_size(); @@ -261,7 +270,7 @@ void Button::_notification(int p_what) { } break; } - const bool is_clipped = clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING; + const bool is_clipped = clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING || autowrap_mode != TextServer::AUTOWRAP_OFF; const Size2 custom_element_size = drawable_size_remained; // Draw the icon. @@ -415,7 +424,7 @@ Size2 Button::get_minimum_size_for_text_and_icon(const String &p_text, Refget_size(); - if (clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) { + if (clip_text || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING || autowrap_mode != TextServer::AUTOWRAP_OFF) { minsize.width = 0; } @@ -468,6 +477,23 @@ void Button::_shape(Ref p_paragraph, String p_text) { return; } + BitField autowrap_flags = TextServer::BREAK_MANDATORY; + switch (autowrap_mode) { + case TextServer::AUTOWRAP_WORD_SMART: + autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_ADAPTIVE | TextServer::BREAK_MANDATORY; + break; + case TextServer::AUTOWRAP_WORD: + autowrap_flags = TextServer::BREAK_WORD_BOUND | TextServer::BREAK_MANDATORY; + break; + case TextServer::AUTOWRAP_ARBITRARY: + autowrap_flags = TextServer::BREAK_GRAPHEME_BOUND | TextServer::BREAK_MANDATORY; + break; + case TextServer::AUTOWRAP_OFF: + break; + } + autowrap_flags = autowrap_flags | TextServer::BREAK_TRIM_EDGE_SPACES; + p_paragraph->set_break_flags(autowrap_flags); + if (text_direction == Control::TEXT_DIRECTION_INHERITED) { p_paragraph->set_direction(is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); } else { @@ -510,6 +536,19 @@ String Button::get_text() const { return text; } +void Button::set_autowrap_mode(TextServer::AutowrapMode p_mode) { + if (autowrap_mode != p_mode) { + autowrap_mode = p_mode; + _shape(); + queue_redraw(); + update_minimum_size(); + } +} + +TextServer::AutowrapMode Button::get_autowrap_mode() const { + return autowrap_mode; +} + 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) { @@ -649,6 +688,8 @@ void Button::_bind_methods() { ClassDB::bind_method(D_METHOD("get_text"), &Button::get_text); ClassDB::bind_method(D_METHOD("set_text_overrun_behavior", "overrun_behavior"), &Button::set_text_overrun_behavior); ClassDB::bind_method(D_METHOD("get_text_overrun_behavior"), &Button::get_text_overrun_behavior); + ClassDB::bind_method(D_METHOD("set_autowrap_mode", "autowrap_mode"), &Button::set_autowrap_mode); + ClassDB::bind_method(D_METHOD("get_autowrap_mode"), &Button::get_autowrap_mode); 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_language", "language"), &Button::set_language); @@ -675,6 +716,7 @@ void Button::_bind_methods() { ADD_GROUP("Text Behavior", ""); ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Left,Center,Right"), "set_text_alignment", "get_text_alignment"); ADD_PROPERTY(PropertyInfo(Variant::INT, "text_overrun_behavior", PROPERTY_HINT_ENUM, "Trim Nothing,Trim Characters,Trim Words,Ellipsis,Word Ellipsis"), "set_text_overrun_behavior", "get_text_overrun_behavior"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "autowrap_mode", PROPERTY_HINT_ENUM, "Off,Arbitrary,Word,Word (Smart)"), "set_autowrap_mode", "get_autowrap_mode"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clip_text"), "set_clip_text", "get_clip_text"); ADD_GROUP("Icon Behavior", ""); diff --git a/scene/gui/button.h b/scene/gui/button.h index d0243a9eeb2..6efbafe0ad4 100644 --- a/scene/gui/button.h +++ b/scene/gui/button.h @@ -45,6 +45,7 @@ private: String language; TextDirection text_direction = TEXT_DIRECTION_AUTO; + TextServer::AutowrapMode autowrap_mode = TextServer::AUTOWRAP_OFF; TextServer::OverrunBehavior overrun_behavior = TextServer::OVERRUN_NO_TRIMMING; Ref icon; @@ -120,6 +121,9 @@ public: void set_text_overrun_behavior(TextServer::OverrunBehavior p_behavior); TextServer::OverrunBehavior get_text_overrun_behavior() const; + void set_autowrap_mode(TextServer::AutowrapMode p_mode); + TextServer::AutowrapMode get_autowrap_mode() const; + void set_text_direction(TextDirection p_text_direction); TextDirection get_text_direction() const;