Allow Label and RichTextLabel to use the new custom_maximum_size
These will be able to use `custom_maximum_size` for autowrapping and trimming, reflecting expected behavior.
This commit is contained in:
@@ -49,6 +49,7 @@
|
||||
<members>
|
||||
<member name="autowrap_mode" type="int" setter="set_autowrap_mode" getter="get_autowrap_mode" enum="TextServer.AutowrapMode" default="0">
|
||||
If set to something other than [constant TextServer.AUTOWRAP_OFF], the text gets wrapped inside the node's bounding rectangle. If you resize the node, it will change its height automatically to show all the text.
|
||||
[b]Note:[/b] Labels with autowrapping enabled must have a custom maximum width configured to work correctly, either through the Label's own [member Control.custom_maximum_size] or as a result of a propagated maximum size from a parent Control with [member Control.propagate_maximum_size] enabled.
|
||||
</member>
|
||||
<member name="autowrap_trim_flags" type="int" setter="set_autowrap_trim_flags" getter="get_autowrap_trim_flags" enum="TextServer.LineBreakFlag" is_bitfield="true" default="192">
|
||||
Autowrap space trimming flags. See [constant TextServer.BREAK_TRIM_START_EDGE_SPACES] and [constant TextServer.BREAK_TRIM_END_EDGE_SPACES] for more info.
|
||||
|
||||
@@ -715,6 +715,7 @@
|
||||
<members>
|
||||
<member name="autowrap_mode" type="int" setter="set_autowrap_mode" getter="get_autowrap_mode" enum="TextServer.AutowrapMode" default="3">
|
||||
If set to something other than [constant TextServer.AUTOWRAP_OFF], the text gets wrapped inside the node's bounding rectangle.
|
||||
[b]Note:[/b] RichTextLabels with autowrapping and [member fit_content] enabled must have a custom maximum width configured to work correctly, either through the RichTextLabel's own [member Control.custom_maximum_size] or as a result of a propagated maximum size from a parent Control with [member Control.propagate_maximum_size] enabled.
|
||||
</member>
|
||||
<member name="autowrap_trim_flags" type="int" setter="set_autowrap_trim_flags" getter="get_autowrap_trim_flags" enum="TextServer.LineBreakFlag" is_bitfield="true" default="192">
|
||||
Autowrap space trimming flags. See [constant TextServer.BREAK_TRIM_START_EDGE_SPACES] and [constant TextServer.BREAK_TRIM_END_EDGE_SPACES] for more info.
|
||||
@@ -739,6 +740,7 @@
|
||||
</member>
|
||||
<member name="fit_content" type="bool" setter="set_fit_content" getter="is_fit_content_enabled" default="false">
|
||||
If [code]true[/code], the label's minimum size will be automatically updated to fit its content, matching the behavior of [Label].
|
||||
[b]Note:[/b] RichTextLabels with autowrapping and [member fit_content] enabled must have a custom maximum width configured to work correctly, either through the RichTextLabel's own [member Control.custom_maximum_size] or as a result of a propagated maximum size from a parent Control with [member Control.propagate_maximum_size] enabled.
|
||||
</member>
|
||||
<member name="focus_mode" type="int" setter="set_focus_mode" getter="get_focus_mode" overrides="Control" enum="Control.FocusMode" default="3" />
|
||||
<member name="hint_underlined" type="bool" setter="set_hint_underline" getter="is_hint_underlined" default="true">
|
||||
|
||||
+56
-11
@@ -32,7 +32,6 @@
|
||||
|
||||
#include "core/object/callable_mp.h"
|
||||
#include "core/object/class_db.h"
|
||||
#include "scene/gui/container.h"
|
||||
#include "scene/main/scene_tree.h"
|
||||
#include "scene/theme/theme_db.h"
|
||||
#include "servers/display/accessibility_server.h"
|
||||
@@ -145,6 +144,20 @@ void Label::_shape() const {
|
||||
|
||||
Ref<StyleBox> style = theme_cache.normal_style;
|
||||
int width = (get_size().width - style->get_minimum_size().width);
|
||||
float combined_maximum_width = get_combined_maximum_size().x;
|
||||
bool wrap_with_max_width = autowrap_mode != TextServer::AUTOWRAP_OFF && combined_maximum_width > 0;
|
||||
int maximum_width = -1;
|
||||
if (wrap_with_max_width) {
|
||||
maximum_width = int(combined_maximum_width - style->get_minimum_size().width);
|
||||
if (maximum_width <= 0) {
|
||||
maximum_width = 1;
|
||||
}
|
||||
if (width > 0) {
|
||||
width = MIN(width, maximum_width);
|
||||
} else {
|
||||
width = maximum_width;
|
||||
}
|
||||
}
|
||||
|
||||
if (text_dirty) {
|
||||
for (Paragraph ¶ : paragraphs) {
|
||||
@@ -250,7 +263,7 @@ void Label::_shape() const {
|
||||
bool lines_hidden = visible_lines > 0 && visible_lines < total_line_count;
|
||||
|
||||
int line_index = 0;
|
||||
if (autowrap_mode == TextServer::AUTOWRAP_OFF) {
|
||||
if (autowrap_mode == TextServer::AUTOWRAP_OFF || wrap_with_max_width) {
|
||||
minsize.width = 0.0f;
|
||||
}
|
||||
for (Paragraph ¶ : paragraphs) {
|
||||
@@ -260,6 +273,8 @@ void Label::_shape() const {
|
||||
minsize.width = TS->shaped_text_get_size(line_rid).x;
|
||||
}
|
||||
}
|
||||
} else if (wrap_with_max_width) {
|
||||
minsize.width = MAX(minsize.width, TS->shaped_text_get_size(para.text_rid).x);
|
||||
}
|
||||
|
||||
if (para.lines_dirty) {
|
||||
@@ -339,6 +354,9 @@ void Label::_shape() const {
|
||||
}
|
||||
line_index += para.lines_rid.size();
|
||||
}
|
||||
if (wrap_with_max_width && maximum_width > 0) {
|
||||
minsize.width = MIN(minsize.width, maximum_width);
|
||||
}
|
||||
|
||||
_update_visible();
|
||||
|
||||
@@ -631,12 +649,8 @@ PackedStringArray Label::get_configuration_warnings() const {
|
||||
// but for now we have to warn about this impossible to resolve combination.
|
||||
// See GH-83546.
|
||||
if (is_inside_tree() && get_tree()->get_edited_scene_root() != this) {
|
||||
// If the Label happens to be the root node of the edited scene, we don't need
|
||||
// to check what its parent is. It's going to be some node from the editor tree
|
||||
// and it can be a container, but that makes no difference to the user.
|
||||
Container *parent_container = Object::cast_to<Container>(get_parent_control());
|
||||
if (parent_container && autowrap_mode != TextServer::AUTOWRAP_OFF && get_custom_minimum_size() == Size2()) {
|
||||
warnings.push_back(RTR("Labels with autowrapping enabled must have a custom minimum size configured to work correctly inside a container."));
|
||||
if (autowrap_mode != TextServer::AUTOWRAP_OFF && get_combined_maximum_size().width <= 0) {
|
||||
warnings.push_back(RTR("Labels with autowrapping enabled must have a positive custom maximum width configured to work correctly."));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -979,6 +993,9 @@ Size2 Label::get_minimum_size() const {
|
||||
_ensure_shaped();
|
||||
|
||||
Size2 min_size = minsize;
|
||||
Size2 combined_maximum_size = get_combined_maximum_size();
|
||||
bool wrap_with_max_width = autowrap_mode != TextServer::AUTOWRAP_OFF && combined_maximum_size.x > 0;
|
||||
bool overrun_with_max_width = autowrap_mode == TextServer::AUTOWRAP_OFF && combined_maximum_size.x > 0 && (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING);
|
||||
|
||||
const Ref<Font> &font = (settings.is_valid() && settings->get_font().is_valid()) ? settings->get_font() : theme_cache.font;
|
||||
int font_size = settings.is_valid() ? settings->get_font_size() : theme_cache.font_size;
|
||||
@@ -993,12 +1010,25 @@ Size2 Label::get_minimum_size() const {
|
||||
} else if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
|
||||
min_size.height = 1;
|
||||
}
|
||||
return Size2(1, min_size.height) + min_style;
|
||||
if (wrap_with_max_width) {
|
||||
min_size.width = MAX(1, min_size.width);
|
||||
return min_size + min_style;
|
||||
} else {
|
||||
return Size2(1, min_size.height) + min_style;
|
||||
}
|
||||
} else {
|
||||
if (clip || overrun_behavior != TextServer::OVERRUN_NO_TRIMMING) {
|
||||
min_size.width = 1;
|
||||
if (overrun_with_max_width) {
|
||||
min_size.width = MAX(1, min_size.width);
|
||||
} else {
|
||||
min_size.width = 1;
|
||||
}
|
||||
}
|
||||
return min_size + min_style;
|
||||
Size2 computed_min_size = min_size + min_style;
|
||||
if (overrun_with_max_width) {
|
||||
computed_min_size.width = MIN(computed_min_size.width, combined_maximum_size.x);
|
||||
}
|
||||
return computed_min_size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1123,6 +1153,19 @@ void Label::_invalidate() {
|
||||
update_configuration_warnings();
|
||||
}
|
||||
|
||||
void Label::_maximum_size_changed() {
|
||||
if (autowrap_mode == TextServer::AUTOWRAP_OFF && overrun_behavior == TextServer::OVERRUN_NO_TRIMMING) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (Paragraph ¶ : paragraphs) {
|
||||
para.lines_dirty = true;
|
||||
}
|
||||
queue_redraw();
|
||||
update_minimum_size();
|
||||
update_configuration_warnings();
|
||||
}
|
||||
|
||||
void Label::set_label_settings(const Ref<LabelSettings> &p_settings) {
|
||||
if (settings != p_settings) {
|
||||
if (settings.is_valid()) {
|
||||
@@ -1479,6 +1522,8 @@ void Label::_bind_methods() {
|
||||
}
|
||||
|
||||
Label::Label(const String &p_text) {
|
||||
connect(SceneStringName(maximum_size_changed), callable_mp(this, &Label::_maximum_size_changed));
|
||||
|
||||
set_mouse_filter(MOUSE_FILTER_IGNORE);
|
||||
set_text(p_text);
|
||||
set_v_size_flags(SIZE_SHRINK_CENTER);
|
||||
|
||||
@@ -101,6 +101,7 @@ private:
|
||||
void _update_visible() const;
|
||||
void _shape() const;
|
||||
void _invalidate();
|
||||
void _maximum_size_changed();
|
||||
|
||||
protected:
|
||||
RID get_line_rid(int p_line) const;
|
||||
|
||||
@@ -206,6 +206,20 @@ Rect2 RichTextLabel::_get_text_rect() {
|
||||
return Rect2(theme_cache.normal_style->get_offset(), get_size() - theme_cache.normal_style->get_minimum_size());
|
||||
}
|
||||
|
||||
int RichTextLabel::_get_wrap_width(const Rect2 &p_text_rect) const {
|
||||
int wrap_width = p_text_rect.get_size().width;
|
||||
float combined_maximum_width = get_combined_maximum_size().x;
|
||||
if (autowrap_mode != TextServer::AUTOWRAP_OFF && combined_maximum_width > 0.0) {
|
||||
int maximum_width = int(combined_maximum_width - theme_cache.normal_style->get_minimum_size().width);
|
||||
if (maximum_width <= 0) {
|
||||
maximum_width = 1;
|
||||
}
|
||||
wrap_width = MIN(wrap_width, maximum_width);
|
||||
wrap_width = MAX(wrap_width, 1);
|
||||
}
|
||||
return wrap_width;
|
||||
}
|
||||
|
||||
RichTextLabel::Item *RichTextLabel::_get_item_at_pos(RichTextLabel::Item *p_item_from, RichTextLabel::Item *p_item_to, int p_position) {
|
||||
int offset = 0;
|
||||
for (Item *it = p_item_from; it && it != p_item_to; it = _get_next_item(it)) {
|
||||
@@ -4015,6 +4029,7 @@ bool RichTextLabel::_validate_line_caches() {
|
||||
if (main->first_invalid_line.load() == (int)main->lines.size()) {
|
||||
MutexLock data_lock(data_mutex);
|
||||
Rect2 text_rect = _get_text_rect();
|
||||
int wrap_width = _get_wrap_width(text_rect);
|
||||
|
||||
float ctrl_height = get_size().height;
|
||||
|
||||
@@ -4043,8 +4058,8 @@ bool RichTextLabel::_validate_line_caches() {
|
||||
|
||||
float total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]);
|
||||
for (int i = fi; i < (int)main->lines.size(); i++) {
|
||||
total_height = _resize_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height);
|
||||
total_height = _update_scroll_exceeds(total_height, ctrl_height, text_rect.get_size().width, i, old_scroll, text_rect.size.height);
|
||||
total_height = _resize_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, wrap_width - scroll_w, total_height);
|
||||
total_height = _update_scroll_exceeds(total_height, ctrl_height, wrap_width, i, old_scroll, text_rect.size.height);
|
||||
main->first_resized_line.store(i);
|
||||
}
|
||||
|
||||
@@ -4091,6 +4106,7 @@ void RichTextLabel::_process_line_caches() {
|
||||
|
||||
MutexLock data_lock(data_mutex);
|
||||
Rect2 text_rect = _get_text_rect();
|
||||
int wrap_width = _get_wrap_width(text_rect);
|
||||
|
||||
float ctrl_height = get_size().height;
|
||||
int fi = main->first_invalid_line.load();
|
||||
@@ -4119,8 +4135,8 @@ void RichTextLabel::_process_line_caches() {
|
||||
}
|
||||
|
||||
for (int i = sr; i < fi; i++) {
|
||||
total_height = _resize_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height);
|
||||
total_height = _update_scroll_exceeds(total_height, ctrl_height, text_rect.get_size().width, i, old_scroll, text_rect.size.height);
|
||||
total_height = _resize_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, wrap_width - scroll_w, total_height);
|
||||
total_height = _update_scroll_exceeds(total_height, ctrl_height, wrap_width, i, old_scroll, text_rect.size.height);
|
||||
|
||||
main->first_resized_line.store(i);
|
||||
|
||||
@@ -4133,8 +4149,8 @@ void RichTextLabel::_process_line_caches() {
|
||||
|
||||
total_height = (fi == 0) ? 0 : _calculate_line_vertical_offset(main->lines[fi - 1]);
|
||||
for (int i = fi; i < (int)main->lines.size(); i++) {
|
||||
total_height = _shape_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, text_rect.get_size().width - scroll_w, total_height, &total_chars);
|
||||
total_height = _update_scroll_exceeds(total_height, ctrl_height, text_rect.get_size().width, i, old_scroll, text_rect.size.height);
|
||||
total_height = _shape_line(main, i, theme_cache.normal_font, theme_cache.normal_font_size, wrap_width - scroll_w, total_height, &total_chars);
|
||||
total_height = _update_scroll_exceeds(total_height, ctrl_height, wrap_width, i, old_scroll, text_rect.size.height);
|
||||
|
||||
main->first_invalid_line.store(i);
|
||||
main->first_resized_line.store(i);
|
||||
@@ -7571,6 +7587,7 @@ void RichTextLabel::set_autowrap_mode(TextServer::AutowrapMode p_mode) {
|
||||
_invalidate_accessibility();
|
||||
_validate_line_caches();
|
||||
queue_redraw();
|
||||
update_minimum_size();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7586,6 +7603,7 @@ void RichTextLabel::set_autowrap_trim_flags(BitField<TextServer::LineBreakFlag>
|
||||
main->first_invalid_line = 0; // Invalidate all lines.
|
||||
_validate_line_caches();
|
||||
queue_redraw();
|
||||
update_minimum_size();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7763,6 +7781,19 @@ bool RichTextLabel::_set(const StringName &p_name, const Variant &p_value) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void RichTextLabel::_maximum_size_changed() {
|
||||
if (!fit_content || autowrap_mode == TextServer::AUTOWRAP_OFF) {
|
||||
return;
|
||||
}
|
||||
|
||||
_stop_thread();
|
||||
main->first_resized_line.store(0); // Invalidate all lines.
|
||||
_invalidate_accessibility();
|
||||
_validate_line_caches();
|
||||
queue_redraw();
|
||||
update_minimum_size();
|
||||
}
|
||||
|
||||
void RichTextLabel::_bind_methods() {
|
||||
ClassDB::bind_method(D_METHOD("get_parsed_text"), &RichTextLabel::get_parsed_text);
|
||||
ClassDB::bind_method(D_METHOD("add_text", "text"), &RichTextLabel::add_text);
|
||||
@@ -8231,14 +8262,34 @@ int RichTextLabel::get_total_glyph_count() const {
|
||||
Size2 RichTextLabel::get_minimum_size() const {
|
||||
Size2 sb_min_size = theme_cache.normal_style->get_minimum_size();
|
||||
Size2 min_size;
|
||||
bool wrap_with_max_width = autowrap_mode != TextServer::AUTOWRAP_OFF && get_combined_maximum_size().x > 0.0;
|
||||
|
||||
if (fit_content) {
|
||||
min_size.x = get_content_width();
|
||||
if (!wrap_with_max_width) {
|
||||
min_size.x = get_content_width();
|
||||
}
|
||||
min_size.y = get_content_height();
|
||||
}
|
||||
|
||||
if (wrap_with_max_width) {
|
||||
const_cast<RichTextLabel *>(this)->_validate_line_caches();
|
||||
|
||||
int natural_width = 0;
|
||||
int to_line = main->first_invalid_line.load();
|
||||
for (int i = 0; i < to_line; i++) {
|
||||
MutexLock lock(main->lines[i].text_buf->get_mutex());
|
||||
natural_width = MAX(natural_width, int(Math::ceil(main->lines[i].offset.x + main->lines[i].text_buf->get_non_wrapped_size().x)));
|
||||
}
|
||||
|
||||
int maximum_width = int(get_combined_maximum_size().x - sb_min_size.width);
|
||||
if (maximum_width <= 0) {
|
||||
maximum_width = 1;
|
||||
}
|
||||
min_size.x = MIN(natural_width, maximum_width);
|
||||
}
|
||||
|
||||
return sb_min_size +
|
||||
((autowrap_mode != TextServer::AUTOWRAP_OFF) ? Size2(1, min_size.height) : min_size);
|
||||
((autowrap_mode != TextServer::AUTOWRAP_OFF) ? Size2(wrap_with_max_width ? MAX(1, min_size.x) : 1, min_size.height) : min_size);
|
||||
}
|
||||
|
||||
// Context menu.
|
||||
@@ -8387,6 +8438,8 @@ Dictionary RichTextLabel::parse_expressions_for_values(Vector<String> p_expressi
|
||||
}
|
||||
|
||||
RichTextLabel::RichTextLabel(const String &p_text) {
|
||||
connect(SceneStringName(maximum_size_changed), callable_mp(this, &RichTextLabel::_maximum_size_changed));
|
||||
|
||||
main = memnew(ItemFrame);
|
||||
main->owner = get_instance_id();
|
||||
main->rid = items.make_rid(main);
|
||||
|
||||
@@ -716,6 +716,10 @@ private:
|
||||
Item *_get_prev_item(Item *p_item, bool p_free = false) const;
|
||||
|
||||
Rect2 _get_text_rect();
|
||||
int _get_wrap_width(const Rect2 &p_text_rect) const;
|
||||
|
||||
void _maximum_size_changed();
|
||||
|
||||
Ref<RichTextEffect> _get_custom_effect_by_code(String p_bbcode_identifier);
|
||||
virtual Dictionary parse_expressions_for_values(Vector<String> p_expressions);
|
||||
|
||||
|
||||
@@ -0,0 +1,261 @@
|
||||
/**************************************************************************/
|
||||
/* test_label.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "tests/test_macros.h"
|
||||
|
||||
TEST_FORCE_LINK(test_label)
|
||||
|
||||
#if defined(MODULE_TEXT_SERVER_FB_ENABLED) || defined(MODULE_TEXT_SERVER_ADV_ENABLED)
|
||||
|
||||
#include "scene/gui/label.h"
|
||||
#include "scene/main/scene_tree.h"
|
||||
#include "scene/main/window.h"
|
||||
|
||||
namespace TestLabel {
|
||||
|
||||
TEST_CASE("[SceneTree][Label] Custom minimum size") {
|
||||
// This is an anti-regression test case introduced in GH-116640. When the old minimum size behavior is removed, this test case should be removed too.
|
||||
Label *test_label = memnew(Label);
|
||||
Window *root = SceneTree::get_singleton()->get_root();
|
||||
root->add_child(test_label);
|
||||
|
||||
real_t min_width = 50;
|
||||
|
||||
test_label->set_custom_minimum_size(Size2(min_width, 0));
|
||||
test_label->set_text("This is a long text that should be wrapped and exceeds minimum size.");
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase to fit the text with AUTOWRAP_OFF.");
|
||||
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_ARBITRARY);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
Math::is_equal_approx(test_label->get_size().width, min_width),
|
||||
"Label width will be equal to custom minimum width with AUTOWRAP_ARBITRARY.");
|
||||
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
Math::is_equal_approx(test_label->get_size().width, min_width),
|
||||
"Label width will be equal to custom minimum width with AUTOWRAP_WORD.");
|
||||
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
Math::is_equal_approx(test_label->get_size().width, min_width),
|
||||
"Label width will be equal to custom minimum width with AUTOWRAP_WORD_SMART.");
|
||||
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_OFF);
|
||||
test_label->set_clip_text(true);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
Math::is_equal_approx(test_label->get_size().width, min_width),
|
||||
"Label width will be equal to custom minimum width with clip_text.");
|
||||
|
||||
test_label->set_clip_text(false);
|
||||
test_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_CHAR);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
Math::is_equal_approx(test_label->get_size().width, min_width),
|
||||
"Label width will be equal to custom minimum width with OVERRUN_TRIM_CHAR.");
|
||||
|
||||
test_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_WORD);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
Math::is_equal_approx(test_label->get_size().width, min_width),
|
||||
"Label width will be equal to custom minimum width with OVERRUN_TRIM_WORD.");
|
||||
|
||||
test_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
Math::is_equal_approx(test_label->get_size().width, min_width),
|
||||
"Label width will be equal to custom minimum width with OVERRUN_TRIM_ELLIPSIS.");
|
||||
|
||||
test_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_WORD_ELLIPSIS);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
Math::is_equal_approx(test_label->get_size().width, min_width),
|
||||
"Label width will be equal to custom minimum width with OVERRUN_TRIM_WORD_ELLIPSIS.");
|
||||
|
||||
test_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS_FORCE);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
Math::is_equal_approx(test_label->get_size().width, min_width),
|
||||
"Label width will be equal to custom minimum width with OVERRUN_TRIM_ELLIPSIS_FORCE.");
|
||||
|
||||
test_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_WORD_ELLIPSIS_FORCE);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
Math::is_equal_approx(test_label->get_size().width, min_width),
|
||||
"Label width will be equal to custom minimum width with OVERRUN_TRIM_WORD_ELLIPSIS_FORCE.");
|
||||
|
||||
memdelete(test_label);
|
||||
}
|
||||
|
||||
TEST_CASE("[SceneTree][Label] Sizing") {
|
||||
Label *test_label = memnew(Label);
|
||||
Window *root = SceneTree::get_singleton()->get_root();
|
||||
root->add_child(test_label);
|
||||
|
||||
real_t max_width = 50;
|
||||
real_t min_width = 25;
|
||||
|
||||
test_label->set_custom_maximum_size(Size2(max_width, 0));
|
||||
test_label->set_custom_minimum_size(Size2(min_width, 0));
|
||||
test_label->set_text("This is a long text that should be wrapped and exceeds minimum size.");
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with AUTOWRAP_OFF.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with AUTOWRAP_OFF.");
|
||||
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_ARBITRARY);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with AUTOWRAP_ARBITRARY.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with AUTOWRAP_ARBITRARY.");
|
||||
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with AUTOWRAP_WORD.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with AUTOWRAP_WORD.");
|
||||
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with AUTOWRAP_WORD_SMART.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with AUTOWRAP_WORD_SMART.");
|
||||
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_OFF);
|
||||
test_label->set_clip_text(true);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with clip_text.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with clip_text.");
|
||||
|
||||
test_label->set_clip_text(false);
|
||||
test_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_CHAR);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with OVERRUN_TRIM_CHAR.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with OVERRUN_TRIM_CHAR.");
|
||||
|
||||
test_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_WORD);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with OVERRUN_TRIM_WORD.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with OVERRUN_TRIM_WORD.");
|
||||
|
||||
test_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with OVERRUN_TRIM_ELLIPSIS.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with OVERRUN_TRIM_ELLIPSIS.");
|
||||
|
||||
test_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_WORD_ELLIPSIS);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with OVERRUN_TRIM_WORD_ELLIPSIS.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with OVERRUN_TRIM_WORD_ELLIPSIS.");
|
||||
|
||||
test_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS_FORCE);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with OVERRUN_TRIM_ELLIPSIS_FORCE.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with OVERRUN_TRIM_ELLIPSIS_FORCE.");
|
||||
|
||||
test_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_WORD_ELLIPSIS_FORCE);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with OVERRUN_TRIM_WORD_ELLIPSIS_FORCE.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with OVERRUN_TRIM_WORD_ELLIPSIS_FORCE.");
|
||||
|
||||
memdelete(test_label);
|
||||
}
|
||||
|
||||
} // namespace TestLabel
|
||||
|
||||
#endif // MODULE_TEXT_SERVER_FB_ENABLED || MODULE_TEXT_SERVER_ADV_ENABLED
|
||||
@@ -0,0 +1,142 @@
|
||||
/**************************************************************************/
|
||||
/* test_rich_text_label.cpp */
|
||||
/**************************************************************************/
|
||||
/* This file is part of: */
|
||||
/* GODOT ENGINE */
|
||||
/* https://godotengine.org */
|
||||
/**************************************************************************/
|
||||
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
|
||||
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
|
||||
/* */
|
||||
/* Permission is hereby granted, free of charge, to any person obtaining */
|
||||
/* a copy of this software and associated documentation files (the */
|
||||
/* "Software"), to deal in the Software without restriction, including */
|
||||
/* without limitation the rights to use, copy, modify, merge, publish, */
|
||||
/* distribute, sublicense, and/or sell copies of the Software, and to */
|
||||
/* permit persons to whom the Software is furnished to do so, subject to */
|
||||
/* the following conditions: */
|
||||
/* */
|
||||
/* The above copyright notice and this permission notice shall be */
|
||||
/* included in all copies or substantial portions of the Software. */
|
||||
/* */
|
||||
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
|
||||
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
|
||||
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */
|
||||
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
|
||||
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
|
||||
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
|
||||
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
|
||||
/**************************************************************************/
|
||||
|
||||
#include "tests/test_macros.h"
|
||||
|
||||
TEST_FORCE_LINK(test_rich_text_label)
|
||||
|
||||
#ifndef ADVANCED_GUI_DISABLED
|
||||
|
||||
#include "scene/gui/rich_text_label.h"
|
||||
#include "scene/main/scene_tree.h"
|
||||
#include "scene/main/window.h"
|
||||
|
||||
namespace TestRichTextLabel {
|
||||
|
||||
TEST_CASE("[SceneTree][RichTextLabel] Custom minimum size with fit content") {
|
||||
// This is an anti-regression test case introduced in GH-116640. When the old minimum size behavior is removed, this test case should be removed too.
|
||||
RichTextLabel *test_label = memnew(RichTextLabel);
|
||||
Window *root = SceneTree::get_singleton()->get_root();
|
||||
root->add_child(test_label);
|
||||
|
||||
real_t min_width = 50;
|
||||
|
||||
test_label->set_fit_content(true);
|
||||
test_label->set_custom_minimum_size(Size2(min_width, 0));
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_OFF);
|
||||
test_label->set_text("This is a long text that should be wrapped and exceeds minimum size.");
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase to fit the text with AUTOWRAP_OFF.");
|
||||
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_ARBITRARY);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
Math::is_equal_approx(test_label->get_size().width, min_width),
|
||||
"Label width will be equal to custom minimum width with AUTOWRAP_ARBITRARY.");
|
||||
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
Math::is_equal_approx(test_label->get_size().width, min_width),
|
||||
"Label width will be equal to custom minimum width with AUTOWRAP_WORD.");
|
||||
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
Math::is_equal_approx(test_label->get_size().width, min_width),
|
||||
"Label width will be equal to custom minimum width with AUTOWRAP_WORD_SMART.");
|
||||
|
||||
memdelete(test_label);
|
||||
}
|
||||
|
||||
TEST_CASE("[SceneTree][RichTextLabel] Sizing with fit content") {
|
||||
RichTextLabel *test_label = memnew(RichTextLabel);
|
||||
Window *root = SceneTree::get_singleton()->get_root();
|
||||
root->add_child(test_label);
|
||||
|
||||
real_t max_width = 50;
|
||||
real_t min_width = 25;
|
||||
|
||||
test_label->set_fit_content(true);
|
||||
test_label->set_custom_maximum_size(Size2(max_width, 0));
|
||||
test_label->set_custom_minimum_size(Size2(min_width, 0));
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_OFF);
|
||||
test_label->set_text("This is a long text that should be wrapped and exceeds minimum size.");
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with AUTOWRAP_OFF.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with AUTOWRAP_OFF.");
|
||||
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_ARBITRARY);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with AUTOWRAP_ARBITRARY.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with AUTOWRAP_ARBITRARY.");
|
||||
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with AUTOWRAP_WORD.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with AUTOWRAP_WORD.");
|
||||
|
||||
test_label->set_autowrap_mode(TextServer::AUTOWRAP_WORD_SMART);
|
||||
SceneTree::get_singleton()->process(0);
|
||||
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width <= max_width,
|
||||
"Label width will increase up to the custom maximum width with AUTOWRAP_WORD_SMART.");
|
||||
CHECK_MESSAGE(
|
||||
test_label->get_size().width > min_width,
|
||||
"Label width will increase beyond the custom minimum width with AUTOWRAP_WORD_SMART.");
|
||||
|
||||
memdelete(test_label);
|
||||
}
|
||||
|
||||
} // namespace TestRichTextLabel
|
||||
|
||||
#endif // ADVANCED_GUI_DISABLED
|
||||
Reference in New Issue
Block a user