diff --git a/doc/classes/LineEdit.xml b/doc/classes/LineEdit.xml index 73d4e50dd70..831660fe1f0 100644 --- a/doc/classes/LineEdit.xml +++ b/doc/classes/LineEdit.xml @@ -310,6 +310,9 @@ If [code]true[/code], the [LineEdit] doesn't display decoration. + + Define the scaling behavior of the [member right_icon]. + If [code]true[/code], the [LineEdit] will not exit edit mode when text is submitted by pressing [code]ui_text_submit[/code] action (by default: [kbd]Enter[/kbd] or [kbd]Kp Enter[/kbd]). @@ -352,6 +355,9 @@ Sets the icon that will appear in the right end of the [LineEdit] if there's no [member text], or always, if [member clear_button_enabled] is set to [code]false[/code]. + + Scale ratio of the icon when [member icon_expand_mode] is set to [constant EXPAND_MODE_FIT_TO_LINE_EDIT]. + If [code]true[/code], every character is replaced with the secret character (see [member secret_character]). @@ -539,6 +545,15 @@ Virtual keyboard with additional keys to assist with typing URLs. + + Use the original size for the right icon. + + + Scale the right icon's size to match the size of the text. + + + Scale the right icon to fit the LineEdit. + diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 69ef0bde1e4..332abef942e 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -370,6 +370,40 @@ void LineEdit::_delete(bool p_word, bool p_all_to_right) { } } +Point2 LineEdit::_get_right_icon_size(Ref p_right_icon) const { + Size2 icon_size; + + if (p_right_icon.is_null()) { + return icon_size; + } + + switch (icon_expand_mode) { + default: + case LineEdit::EXPAND_MODE_ORIGINAL_SIZE: + icon_size = p_right_icon->get_size(); + break; + case LineEdit::EXPAND_MODE_FIT_TO_TEXT: { + real_t height = theme_cache.font->get_height(theme_cache.font_size); + icon_size = Size2(height, height); + } break; + case LineEdit::EXPAND_MODE_FIT_TO_LINE_EDIT: { + icon_size = p_right_icon->get_size(); + Point2 size = get_size(); + float icon_width = icon_size.width * size.height / icon_size.height; + float icon_height = size.height; + + if (icon_width > size.width) { + icon_width = size.width; + icon_height = icon_size.height * icon_width / icon_size.width; + } + + icon_size = Size2(icon_width, icon_height) * right_icon_scale; + } break; + } + + return icon_size; +} + void LineEdit::unhandled_key_input(const Ref &p_event) { // Return to prevent editing if just focused. if (!editing) { @@ -1255,20 +1289,21 @@ void LineEdit::_notification(int p_what) { bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { Ref r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; + Point2 right_icon_size = _get_right_icon_size(r_icon); if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { if (Math::is_zero_approx(scroll_offset)) { int total_margin = style->get_margin(SIDE_LEFT) + style->get_margin(SIDE_RIGHT); - int center = int(size.width - total_margin - text_width - r_icon->get_width()) / 2; + int center = int(size.width - total_margin - text_width - right_icon_size.width) / 2; x_ofs = style->get_margin(SIDE_LEFT) + MAX(0, center); } if (rtl) { - x_ofs += r_icon->get_width(); + x_ofs += right_icon_size.width; } } else { if (rtl) { - x_ofs = MAX(style->get_margin(SIDE_LEFT) + r_icon->get_width(), x_ofs); + x_ofs = MAX(style->get_margin(SIDE_LEFT) + right_icon_size.width, x_ofs); } else { - x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT)); + x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - right_icon_size.width - style->get_margin(SIDE_RIGHT)); } } } @@ -1409,6 +1444,7 @@ void LineEdit::_notification(int p_what) { bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { Ref r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; + Point2 right_icon_size = _get_right_icon_size(r_icon); Color color_icon(1, 1, 1, !is_editable() ? .5 * .9 : .9); if (display_clear_icon) { if (clear_button_status.press_attempt && clear_button_status.pressing_inside) { @@ -1418,31 +1454,32 @@ void LineEdit::_notification(int p_what) { } } - Point2 icon_pos = Point2(width - r_icon->get_width() - style->get_margin(SIDE_RIGHT), height / 2 - r_icon->get_height() / 2); + Point2 icon_pos = Point2(width - right_icon_size.width - style->get_margin(SIDE_RIGHT), height / 2 - right_icon_size.height / 2); if (rtl) { icon_pos.x = style->get_margin(SIDE_LEFT); } - r_icon->draw(ci, icon_pos, color_icon); + Rect2 icon_region = Rect2(icon_pos, right_icon_size); + draw_texture_rect(r_icon, icon_region, false, color_icon); if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { if (Math::is_zero_approx(scroll_offset)) { int total_margin = style->get_margin(SIDE_LEFT) + style->get_margin(SIDE_RIGHT); - int center = int(size.width - total_margin - text_width - r_icon->get_width()) / 2; + int center = int(size.width - total_margin - text_width - right_icon_size.width) / 2; x_ofs = style->get_margin(SIDE_LEFT) + MAX(0, center); } if (rtl) { - x_ofs += r_icon->get_width(); + x_ofs += right_icon_size.width; } } else { if (rtl) { - x_ofs = MAX(style->get_margin(SIDE_LEFT) + r_icon->get_width(), x_ofs); + x_ofs = MAX(style->get_margin(SIDE_LEFT) + right_icon_size.width, x_ofs); } else { - x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT)); + x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - right_icon_size.width - style->get_margin(SIDE_RIGHT)); } } if (!rtl) { - ofs_max -= r_icon->get_width(); + ofs_max -= right_icon_size.width; } } @@ -1842,20 +1879,21 @@ void LineEdit::set_caret_at_pixel_pos(int p_x) { bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { Ref r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; + Point2 right_icon_size = _get_right_icon_size(r_icon); if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { if (Math::is_zero_approx(scroll_offset)) { int total_margin = style->get_margin(SIDE_LEFT) + style->get_margin(SIDE_RIGHT); - int center = int(get_size().width - total_margin - text_width - r_icon->get_width()) / 2; + int center = int(get_size().width - total_margin - text_width - right_icon_size.width) / 2; x_ofs = style->get_margin(SIDE_LEFT) + MAX(0, center); } if (rtl) { - x_ofs += r_icon->get_width(); + x_ofs += right_icon_size.width; } } else { if (rtl) { - x_ofs = MAX(style->get_margin(SIDE_LEFT) + r_icon->get_width(), x_ofs); + x_ofs = MAX(style->get_margin(SIDE_LEFT) + right_icon_size.width, x_ofs); } else { - x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT)); + x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - right_icon_size.width - style->get_margin(SIDE_RIGHT)); } } } @@ -1907,20 +1945,21 @@ Vector2 LineEdit::get_caret_pixel_pos() { bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { Ref r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; + Point2 right_icon_size = _get_right_icon_size(r_icon); if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { if (Math::is_zero_approx(scroll_offset)) { int total_margin = style->get_margin(SIDE_LEFT) + style->get_margin(SIDE_RIGHT); - int center = int(get_size().width - total_margin - text_width - r_icon->get_width()) / 2; + int center = int(get_size().width - total_margin - text_width - right_icon_size.width) / 2; x_ofs = style->get_margin(SIDE_LEFT) + MAX(0, center); } if (rtl) { - x_ofs += r_icon->get_width(); + x_ofs += right_icon_size.width; } } else { if (rtl) { - x_ofs = MAX(style->get_margin(SIDE_LEFT) + r_icon->get_width(), x_ofs); + x_ofs = MAX(style->get_margin(SIDE_LEFT) + right_icon_size.width, x_ofs); } else { - x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT)); + x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - right_icon_size.width - style->get_margin(SIDE_RIGHT)); } } } @@ -2270,28 +2309,29 @@ void LineEdit::set_caret_column(int p_column) { bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { Ref r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; + Point2 right_icon_size = _get_right_icon_size(r_icon); if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { if (Math::is_zero_approx(scroll_offset)) { int total_margin = style->get_margin(SIDE_LEFT) + style->get_margin(SIDE_RIGHT); - int center = int(get_size().width - total_margin - text_width - r_icon->get_width()) / 2; + int center = int(get_size().width - total_margin - text_width - right_icon_size.width) / 2; x_ofs = style->get_margin(SIDE_LEFT) + MAX(0, center); } if (rtl) { - x_ofs += r_icon->get_width(); + x_ofs += right_icon_size.width; } } else { if (rtl) { - x_ofs = MAX(style->get_margin(SIDE_LEFT) + r_icon->get_width(), x_ofs); + x_ofs = MAX(style->get_margin(SIDE_LEFT) + right_icon_size.width, x_ofs); } else { if (rtl) { - x_ofs = MAX(style->get_margin(SIDE_LEFT) + r_icon->get_width(), x_ofs); + x_ofs = MAX(style->get_margin(SIDE_LEFT) + right_icon_size.width, x_ofs); } else { - x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT)); + x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - right_icon_size.width - style->get_margin(SIDE_RIGHT)); } } } if (!rtl) { - ofs_max -= r_icon->get_width(); + ofs_max -= right_icon_size.width; } } @@ -2404,12 +2444,14 @@ Size2 LineEdit::get_minimum_size() const { // Take icons into account. int icon_max_width = 0; if (right_icon.is_valid()) { - min_size.height = MAX(min_size.height, right_icon->get_height()); - icon_max_width = right_icon->get_width(); + Point2 right_icon_size = _get_right_icon_size(right_icon); + min_size.height = MAX(min_size.height, right_icon_size.height); + icon_max_width = right_icon_size.width; } if (clear_button_enabled) { - min_size.height = MAX(min_size.height, theme_cache.clear_icon->get_height()); - icon_max_width = MAX(icon_max_width, theme_cache.clear_icon->get_width()); + Point2 right_icon_size = _get_right_icon_size(theme_cache.clear_icon); + min_size.height = MAX(min_size.height, right_icon_size.height); + icon_max_width = MAX(icon_max_width, right_icon_size.width); } min_size.width += icon_max_width; @@ -2942,6 +2984,35 @@ Ref LineEdit::get_right_icon() { return right_icon; } +void LineEdit::set_icon_expand_mode(ExpandMode p_mode) { + if (icon_expand_mode == p_mode) { + return; + } + + icon_expand_mode = p_mode; + queue_redraw(); + update_minimum_size(); + notify_property_list_changed(); +} + +LineEdit::ExpandMode LineEdit::get_icon_expand_mode() const { + return icon_expand_mode; +} + +void LineEdit::set_right_icon_scale(float p_scale) { + if (right_icon_scale == p_scale) { + return; + } + + right_icon_scale = p_scale; + queue_redraw(); + update_minimum_size(); +} + +float LineEdit::get_right_icon_scale() const { + return right_icon_scale; +} + void LineEdit::set_flat(bool p_enabled) { if (flat != p_enabled) { flat = p_enabled; @@ -3042,7 +3113,8 @@ void LineEdit::_fit_to_width() { bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { Ref r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; - t_width -= r_icon->get_width(); + Point2 right_icon_size = _get_right_icon_size(r_icon); + t_width -= right_icon_size.width; } TS->shaped_text_fit_to_width(text_rid, MAX(t_width, full_width)); } @@ -3221,6 +3293,8 @@ void LineEdit::_validate_property(PropertyInfo &p_property) const { } if (!caret_blink_enabled && p_property.name == "caret_blink_interval") { p_property.usage = PROPERTY_USAGE_NO_EDITOR; + } else if (icon_expand_mode != EXPAND_MODE_FIT_TO_LINE_EDIT && p_property.name == "right_icon_scale") { + p_property.usage = PROPERTY_USAGE_NO_EDITOR; } } @@ -3319,6 +3393,10 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("is_drag_and_drop_selection_enabled"), &LineEdit::is_drag_and_drop_selection_enabled); ClassDB::bind_method(D_METHOD("set_right_icon", "icon"), &LineEdit::set_right_icon); ClassDB::bind_method(D_METHOD("get_right_icon"), &LineEdit::get_right_icon); + ClassDB::bind_method(D_METHOD("set_icon_expand_mode", "mode"), &LineEdit::set_icon_expand_mode); + ClassDB::bind_method(D_METHOD("get_icon_expand_mode"), &LineEdit::get_icon_expand_mode); + ClassDB::bind_method(D_METHOD("set_right_icon_scale", "scale"), &LineEdit::set_right_icon_scale); + ClassDB::bind_method(D_METHOD("get_right_icon_scale"), &LineEdit::get_right_icon_scale); ClassDB::bind_method(D_METHOD("set_flat", "enabled"), &LineEdit::set_flat); ClassDB::bind_method(D_METHOD("is_flat"), &LineEdit::is_flat); ClassDB::bind_method(D_METHOD("set_select_all_on_focus", "enabled"), &LineEdit::set_select_all_on_focus); @@ -3371,6 +3449,10 @@ void LineEdit::_bind_methods() { BIND_ENUM_CONSTANT(KEYBOARD_TYPE_PASSWORD); BIND_ENUM_CONSTANT(KEYBOARD_TYPE_URL); + BIND_ENUM_CONSTANT(EXPAND_MODE_ORIGINAL_SIZE); + BIND_ENUM_CONSTANT(EXPAND_MODE_FIT_TO_TEXT); + BIND_ENUM_CONSTANT(EXPAND_MODE_FIT_TO_LINE_EDIT); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "text"), "set_text", "get_text"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "placeholder_text"), "set_placeholder", "get_placeholder"); ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Left,Center,Right,Fill"), "set_horizontal_alignment", "get_horizontal_alignment"); @@ -3387,7 +3469,6 @@ void LineEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_on_focus_loss_enabled"), "set_deselect_on_focus_loss_enabled", "is_deselect_on_focus_loss_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_and_drop_selection_enabled"), "set_drag_and_drop_selection_enabled", "is_drag_and_drop_selection_enabled"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "right_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_right_icon", "get_right_icon"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat"), "set_flat", "is_flat"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_control_chars"), "set_draw_control_chars", "get_draw_control_chars"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_all_on_focus"), "set_select_all_on_focus", "is_select_all_on_focus"); @@ -3414,6 +3495,11 @@ void LineEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override"); ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options"); + ADD_GROUP("Icon", ""); + ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "right_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_right_icon", "get_right_icon"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "icon_expand_mode", PROPERTY_HINT_ENUM, "Original,Fit to Text,Fit to LineEdit"), "set_icon_expand_mode", "get_icon_expand_mode"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "right_icon_scale", PROPERTY_HINT_RANGE, "0.1,1.0,0.01"), "set_right_icon_scale", "get_right_icon_scale"); + BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, LineEdit, normal); BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, LineEdit, read_only); BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, LineEdit, focus); diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h index c8ca6c7e3bb..b02fc7dea79 100644 --- a/scene/gui/line_edit.h +++ b/scene/gui/line_edit.h @@ -83,6 +83,12 @@ public: KEYBOARD_TYPE_URL }; + enum ExpandMode { + EXPAND_MODE_ORIGINAL_SIZE, + EXPAND_MODE_FIT_TO_TEXT, + EXPAND_MODE_FIT_TO_LINE_EDIT, + }; + private: HorizontalAlignment alignment = HORIZONTAL_ALIGNMENT_LEFT; @@ -91,6 +97,7 @@ private: bool editable = false; bool pass = false; bool text_changed_dirty = false; + ExpandMode icon_expand_mode = EXPAND_MODE_ORIGINAL_SIZE; enum AltInputMode { ALT_INPUT_NONE, @@ -158,6 +165,7 @@ private: Ref right_icon; bool flat = false; + float right_icon_scale = 1.0; struct Selection { int begin = 0; @@ -264,6 +272,7 @@ private: void _texture_changed(); void _edit(bool p_show_virtual_keyboard = true, bool p_hide_focus = false); + Point2 _get_right_icon_size(Ref p_right_icon) const; protected: bool _is_over_clear_button(const Point2 &p_pos) const; @@ -430,6 +439,12 @@ public: void set_right_icon(const Ref &p_icon); Ref get_right_icon(); + void set_icon_expand_mode(ExpandMode p_mode); + ExpandMode get_icon_expand_mode() const; + + void set_right_icon_scale(float p_scale); + float get_right_icon_scale() const; + void set_flat(bool p_enabled); bool is_flat() const; @@ -449,3 +464,4 @@ public: VARIANT_ENUM_CAST(LineEdit::MenuItems); VARIANT_ENUM_CAST(LineEdit::VirtualKeyboardType); +VARIANT_ENUM_CAST(LineEdit::ExpandMode);