diff options
Diffstat (limited to 'scene/gui/line_edit.cpp')
-rw-r--r-- | scene/gui/line_edit.cpp | 383 |
1 files changed, 206 insertions, 177 deletions
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp index 283f9af757..14167531a5 100644 --- a/scene/gui/line_edit.cpp +++ b/scene/gui/line_edit.cpp @@ -43,18 +43,15 @@ #endif #include "scene/main/window.h" static bool _is_text_char(CharType c) { - return !is_symbol(c); } void LineEdit::_gui_input(Ref<InputEvent> p_event) { - Ref<InputEventMouseButton> b = p_event; if (b.is_valid()) { - if (b->is_pressed() && b->get_button_index() == BUTTON_RIGHT && context_menu_enabled) { - menu->set_position(get_global_transform().xform(get_local_mouse_position())); + menu->set_position(get_screen_transform().xform(get_local_mouse_position())); menu->set_size(Vector2(1, 1)); //menu->set_scale(get_global_transform().get_scale()); menu->popup(); @@ -63,12 +60,12 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { return; } - if (b->get_button_index() != BUTTON_LEFT) + if (b->get_button_index() != BUTTON_LEFT) { return; + } _reset_caret_blink_timer(); if (b->is_pressed()) { - accept_event(); //don't pass event further when clicked on text field if (!text.empty() && is_editable() && _is_over_clear_button(b->get_position())) { clear_button_status.press_attempt = true; @@ -81,14 +78,11 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { set_cursor_at_pixel_pos(b->get_position().x); if (b->get_shift()) { - selection_fill_at_cursor(); selection.creating = true; } else { - if (b->is_doubleclick() && selecting_enabled) { - selection.enabled = true; selection.begin = 0; selection.end = text.length(); @@ -98,12 +92,10 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { selection.drag_attempt = false; if ((cursor_pos < selection.begin) || (cursor_pos > selection.end) || !selection.enabled) { - deselect(); selection.cursor_start = cursor_pos; selection.creating = true; } else if (selection.enabled) { - selection.drag_attempt = true; } } @@ -111,7 +103,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { update(); } else { - if (!text.empty() && is_editable() && clear_button_enabled) { bool press_attempt = clear_button_status.press_attempt; clear_button_status.press_attempt = false; @@ -127,8 +118,13 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { selection.creating = false; selection.doubleclick = false; - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) - DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { + if (selection.enabled) { + DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end); + } else { + DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, cursor_pos); + } + } } update(); @@ -137,7 +133,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { Ref<InputEventMouseMotion> m = p_event; if (m.is_valid()) { - if (!text.empty() && is_editable() && clear_button_enabled) { bool last_press_inside = clear_button_status.pressing_inside; clear_button_status.pressing_inside = clear_button_status.press_attempt && _is_over_clear_button(m->get_position()); @@ -147,7 +142,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } if (m->get_button_mask() & BUTTON_LEFT) { - if (selection.creating) { set_cursor_at_pixel_pos(m->get_position().x); selection_fill_at_cursor(); @@ -158,9 +152,9 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { Ref<InputEventKey> k = p_event; if (k.is_valid()) { - - if (!k->is_pressed()) + if (!k->is_pressed()) { return; + } #ifdef APPLE_STYLE_KEYS if (k->get_control() && !k->get_shift() && !k->get_alt() && !k->get_command()) { @@ -202,11 +196,9 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { unsigned int code = k->get_keycode(); if (k->get_command() && is_shortcut_keys_enabled()) { - bool handled = true; switch (code) { - case (KEY_X): { // CUT. if (editable) { @@ -224,7 +216,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { case (KEY_V): { // PASTE. if (editable) { - paste_text(); } @@ -243,7 +234,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { case (KEY_U): { // Delete from start to cursor. if (editable) { - deselect(); text = text.substr(cursor_pos, text.length() - cursor_pos); update_cached_width(); @@ -256,7 +246,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { case (KEY_Y): { // PASTE (Yank for unix users). if (editable) { - paste_text(); } @@ -264,7 +253,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { case (KEY_K): { // Delete from cursor_pos to end. if (editable) { - deselect(); text = text.substr(0, cursor_pos); _text_changed(); @@ -277,10 +265,30 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } break; #ifdef APPLE_STYLE_KEYS case (KEY_LEFT): { // Go to start of text - like HOME key. + shift_selection_check_pre(k->get_shift()); set_cursor_position(0); + shift_selection_check_post(k->get_shift()); } break; case (KEY_RIGHT): { // Go to end of text - like END key. + shift_selection_check_pre(k->get_shift()); set_cursor_position(text.length()); + shift_selection_check_post(k->get_shift()); + } break; + case (KEY_BACKSPACE): { + if (!editable) + break; + + // If selected, delete the selection + if (selection.enabled) { + selection_delete(); + break; + } + + // Otherwise delete from cursor to beginning of text edit + int current_pos = get_cursor_position(); + if (current_pos != 0) { + delete_text(0, current_pos); + } } break; #endif default: { @@ -296,23 +304,22 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { _reset_caret_blink_timer(); if (!k->get_metakey()) { - bool handled = true; switch (code) { - case KEY_KP_ENTER: case KEY_ENTER: { - emit_signal("text_entered", text); - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { DisplayServer::get_singleton()->virtual_keyboard_hide(); + } + return; } break; case KEY_BACKSPACE: { - - if (!editable) + if (!editable) { break; + } if (selection.enabled) { selection_delete(); @@ -333,8 +340,9 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { while (cc > 0) { bool ischar = _is_text_char(text[cc - 1]); - if (prev_char && !ischar) + if (prev_char && !ischar) { break; + } prev_char = ischar; cc--; @@ -376,7 +384,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { if (k->get_command()) { set_cursor_position(0); } else if (k->get_alt()) { - #else if (k->get_alt()) { handled = false; @@ -389,8 +396,9 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { while (cc > 0) { bool ischar = _is_text_char(text[cc - 1]); - if (prev_char && !ischar) + if (prev_char && !ischar) { break; + } prev_char = ischar; cc--; @@ -444,8 +452,9 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { while (cc < text.length()) { bool ischar = _is_text_char(text[cc]); - if (prev_char && !ischar) + if (prev_char && !ischar) { break; + } prev_char = ischar; cc++; @@ -461,23 +470,25 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } break; case KEY_UP: { - shift_selection_check_pre(k->get_shift()); - if (get_cursor_position() == 0) handled = false; + if (get_cursor_position() == 0) { + handled = false; + } set_cursor_position(0); shift_selection_check_post(k->get_shift()); } break; case KEY_DOWN: { - shift_selection_check_pre(k->get_shift()); - if (get_cursor_position() == text.length()) handled = false; + if (get_cursor_position() == text.length()) { + handled = false; + } set_cursor_position(text.length()); shift_selection_check_post(k->get_shift()); } break; case KEY_DELETE: { - - if (!editable) + if (!editable) { break; + } if (k->get_shift() && !k->get_command() && !k->get_alt()) { cut_text(); @@ -491,8 +502,9 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { int text_len = text.length(); - if (cursor_pos == text_len) + if (cursor_pos == text_len) { break; // Nothing to do. + } #ifdef APPLE_STYLE_KEYS if (k->get_alt()) { @@ -507,11 +519,11 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { bool prev_char = false; while (cc < text.length()) { - bool ischar = _is_text_char(text[cc]); - if (prev_char && !ischar) + if (prev_char && !ischar) { break; + } prev_char = ischar; cc++; } @@ -532,7 +544,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { [[fallthrough]]; } case KEY_HOME: { - shift_selection_check_pre(k->get_shift()); set_cursor_position(0); shift_selection_check_post(k->get_shift()); @@ -545,7 +556,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { [[fallthrough]]; } case KEY_END: { - shift_selection_check_pre(k->get_shift()); set_cursor_position(text.length()); shift_selection_check_post(k->get_shift()); @@ -562,7 +572,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } break; default: { - handled = false; } break; } @@ -571,7 +580,6 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { accept_event(); } else if (!k->get_command() || (k->get_command() && k->get_alt())) { if (k->get_unicode() >= 32 && k->get_keycode() != KEY_DELETE) { - if (editable) { selection_delete(); CharType ucodestr[2] = { (CharType)k->get_unicode(), 0 }; @@ -596,19 +604,16 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) { } void LineEdit::set_align(Align p_align) { - ERR_FAIL_INDEX((int)p_align, 4); align = p_align; update(); } LineEdit::Align LineEdit::get_align() const { - return align; } Variant LineEdit::get_drag_data(const Point2 &p_point) { - if (selection.drag_attempt && selection.enabled) { String t = text.substr(selection.begin, selection.end - selection.begin); Label *l = memnew(Label); @@ -619,20 +624,21 @@ Variant LineEdit::get_drag_data(const Point2 &p_point) { return Variant(); } -bool LineEdit::can_drop_data(const Point2 &p_point, const Variant &p_data) const { +bool LineEdit::can_drop_data(const Point2 &p_point, const Variant &p_data) const { return p_data.get_type() == Variant::STRING; } -void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) { +void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) { if (p_data.get_type() == Variant::STRING) { set_cursor_at_pixel_pos(p_point.x); int selected = selection.end - selection.begin; Ref<Font> font = get_theme_font("font"); if (font != nullptr) { - for (int i = selection.begin; i < selection.end; i++) + for (int i = selection.begin; i < selection.end; i++) { cached_width -= font->get_char_size(pass ? secret_character[0] : text[i]).width; + } } text.erase(selection.begin, selected); @@ -660,7 +666,6 @@ bool LineEdit::_is_over_clear_button(const Point2 &p_pos) const { } void LineEdit::_notification(int p_what) { - switch (p_what) { #ifdef TOOLS_ENABLED case NOTIFICATION_ENTER_TREE: { @@ -675,7 +680,6 @@ void LineEdit::_notification(int p_what) { } break; #endif case NOTIFICATION_RESIZED: { - window_pos = 0; set_cursor_position(get_cursor_position()); @@ -685,19 +689,18 @@ void LineEdit::_notification(int p_what) { update_placeholder_width(); update(); } break; - case NOTIFICATION_WM_FOCUS_IN: { + case NOTIFICATION_WM_WINDOW_FOCUS_IN: { window_has_focus = true; draw_caret = true; update(); } break; - case NOTIFICATION_WM_FOCUS_OUT: { + case NOTIFICATION_WM_WINDOW_FOCUS_OUT: { window_has_focus = false; draw_caret = false; update(); } break; case NOTIFICATION_DRAW: { - - if ((!has_focus() && !menu->has_focus()) || !window_has_focus) { + if ((!has_focus() && !menu->has_focus() && !caret_force_displayed) || !window_has_focus) { draw_caret = false; } @@ -720,7 +723,6 @@ void LineEdit::_notification(int p_what) { style->draw(ci, Rect2(Point2(), size)); if (has_focus()) { - get_theme_stylebox("focus")->draw(ci, Rect2(Point2(), size)); } @@ -729,21 +731,18 @@ void LineEdit::_notification(int p_what) { int cached_text_width = using_placeholder ? cached_placeholder_width : cached_width; switch (align) { - case ALIGN_FILL: case ALIGN_LEFT: { - x_ofs = style->get_offset().x; } break; case ALIGN_CENTER: { - - if (window_pos != 0) + if (window_pos != 0) { x_ofs = style->get_offset().x; - else + } else { x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - (cached_text_width)) / 2); + } } break; case ALIGN_RIGHT: { - x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - style->get_margin(MARGIN_RIGHT) - (cached_text_width))); } break; } @@ -763,8 +762,9 @@ void LineEdit::_notification(int p_what) { const String &t = using_placeholder ? placeholder_translated : text; // Draw placeholder color. - if (using_placeholder) + if (using_placeholder) { font_color.a *= placeholder_alpha; + } bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; if (right_icon.is_valid() || display_clear_icon) { @@ -794,24 +794,26 @@ void LineEdit::_notification(int p_what) { int caret_height = font->get_height() > y_area ? y_area : font->get_height(); FontDrawer drawer(font, Color(1, 1, 1)); while (true) { - // End of string, break. - if (char_ofs >= t.length()) + if (char_ofs >= t.length()) { break; + } if (char_ofs == cursor_pos) { if (ime_text.length() > 0) { int ofs = 0; while (true) { - if (ofs >= ime_text.length()) + if (ofs >= ime_text.length()) { break; + } CharType cchar = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs]; CharType next = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs + 1]; int im_char_width = font->get_char_size(cchar, next).width; - if ((x_ofs + im_char_width) > ofs_max) + if ((x_ofs + im_char_width) > ofs_max) { break; + } bool selected = ofs >= ime_selection.x && ofs < ime_selection.x + ime_selection.y; if (selected) { @@ -833,13 +835,15 @@ void LineEdit::_notification(int p_what) { int char_width = font->get_char_size(cchar, next).width; // End of widget, break. - if ((x_ofs + char_width) > ofs_max) + if ((x_ofs + char_width) > ofs_max) { break; + } bool selected = selection.enabled && char_ofs >= selection.begin && char_ofs < selection.end; - if (selected) + if (selected) { RenderingServer::get_singleton()->canvas_item_add_rect(ci, Rect2(Point2(x_ofs, y_ofs), Size2(char_width, caret_height)), selection_color); + } int yofs = y_ofs + (caret_height - font->get_height()) / 2; drawer.draw_char(ci, Point2(x_ofs, yofs + font_ascent), cchar, next, selected ? font_color_selected : font_color); @@ -862,15 +866,17 @@ void LineEdit::_notification(int p_what) { if (ime_text.length() > 0) { int ofs = 0; while (true) { - if (ofs >= ime_text.length()) + if (ofs >= ime_text.length()) { break; + } CharType cchar = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs]; CharType next = (pass && !text.empty()) ? secret_character[0] : ime_text[ofs + 1]; int im_char_width = font->get_char_size(cchar, next).width; - if ((x_ofs + im_char_width) > ofs_max) + if ((x_ofs + im_char_width) > ofs_max) { break; + } bool selected = ofs >= ime_selection.x && ofs < ime_selection.x + ime_selection.y; if (selected) { @@ -920,11 +926,14 @@ void LineEdit::_notification(int p_what) { } } break; case NOTIFICATION_FOCUS_ENTER: { - - if (caret_blink_enabled) { - caret_blink_timer->start(); - } else { - draw_caret = true; + if (!caret_force_displayed) { + if (caret_blink_enabled) { + if (caret_blink_timer->is_stopped()) { + caret_blink_timer->start(); + } + } else { + draw_caret = true; + } } if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) { @@ -933,13 +942,17 @@ void LineEdit::_notification(int p_what) { DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + cursor_pos, get_viewport()->get_window_id()); } - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) - DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), max_length); + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { + if (selection.enabled) { + DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, selection.begin, selection.end); + } else { + DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), false, max_length, cursor_pos); + } + } } break; case NOTIFICATION_FOCUS_EXIT: { - - if (caret_blink_enabled) { + if (caret_blink_enabled && !caret_force_displayed) { caret_blink_timer->stop(); } @@ -950,12 +963,12 @@ void LineEdit::_notification(int p_what) { ime_text = ""; ime_selection = Point2(); - if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD)) + if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { DisplayServer::get_singleton()->virtual_keyboard_hide(); + } } break; case MainLoop::NOTIFICATION_OS_IME_UPDATE: { - if (has_focus()) { ime_text = DisplayServer::get_singleton()->ime_get_text(); ime_selection = DisplayServer::get_singleton()->ime_get_selection(); @@ -966,14 +979,12 @@ void LineEdit::_notification(int p_what) { } void LineEdit::copy_text() { - if (selection.enabled && !pass) { DisplayServer::get_singleton()->clipboard_set(text.substr(selection.begin, selection.end - selection.begin)); } } void LineEdit::cut_text() { - if (selection.enabled && !pass) { DisplayServer::get_singleton()->clipboard_set(text.substr(selection.begin, selection.end - selection.begin)); selection_delete(); @@ -981,14 +992,14 @@ void LineEdit::cut_text() { } void LineEdit::paste_text() { - // Strip escape characters like \n and \t as they can't be displayed on LineEdit. String paste_buffer = DisplayServer::get_singleton()->clipboard_get().strip_escapes(); if (paste_buffer != "") { - int prev_len = text.length(); - if (selection.enabled) selection_delete(); + if (selection.enabled) { + selection_delete(); + } append_at_cursor(paste_buffer); if (!text_changed_dirty) { @@ -1016,8 +1027,9 @@ void LineEdit::undo() { window_pos = op.window_pos; set_cursor_position(op.cursor_pos); - if (expand_to_text_length) + if (expand_to_text_length) { minimum_size_changed(); + } _emit_text_change(); } @@ -1036,29 +1048,29 @@ void LineEdit::redo() { window_pos = op.window_pos; set_cursor_position(op.cursor_pos); - if (expand_to_text_length) + if (expand_to_text_length) { minimum_size_changed(); + } _emit_text_change(); } void LineEdit::shift_selection_check_pre(bool p_shift) { - if (!selection.enabled && p_shift) { selection.cursor_start = cursor_pos; } - if (!p_shift) + if (!p_shift) { deselect(); + } } void LineEdit::shift_selection_check_post(bool p_shift) { - - if (p_shift) + if (p_shift) { selection_fill_at_cursor(); + } } void LineEdit::set_cursor_at_pixel_pos(int p_x) { - Ref<Font> font = get_theme_font("font"); int ofs = window_pos; Ref<StyleBox> style = get_theme_stylebox("normal"); @@ -1068,33 +1080,31 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) { int r_icon_width = Control::get_theme_icon("clear")->get_width(); switch (align) { - case ALIGN_FILL: case ALIGN_LEFT: { - pixel_ofs = int(style->get_offset().x); } break; case ALIGN_CENTER: { - - if (window_pos != 0) + if (window_pos != 0) { pixel_ofs = int(style->get_offset().x); - else + } else { pixel_ofs = int(size.width - (cached_width)) / 2; + } - if (display_clear_icon) + if (display_clear_icon) { pixel_ofs -= int(r_icon_width / 2 + style->get_margin(MARGIN_RIGHT)); + } } break; case ALIGN_RIGHT: { - pixel_ofs = int(size.width - style->get_margin(MARGIN_RIGHT) - (cached_width)); - if (display_clear_icon) + if (display_clear_icon) { pixel_ofs -= int(r_icon_width + style->get_margin(MARGIN_RIGHT)); + } } break; } while (ofs < text.length()) { - int char_w = 0; if (font != nullptr) { char_w = font->get_char_size(pass ? secret_character[0] : text[ofs]).width; @@ -1112,7 +1122,6 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) { } int LineEdit::get_cursor_pixel_pos() { - Ref<Font> font = get_theme_font("font"); int ofs = window_pos; Ref<StyleBox> style = get_theme_stylebox("normal"); @@ -1122,28 +1131,27 @@ int LineEdit::get_cursor_pixel_pos() { int r_icon_width = Control::get_theme_icon("clear")->get_width(); switch (align) { - case ALIGN_FILL: case ALIGN_LEFT: { - pixel_ofs = int(style->get_offset().x); } break; case ALIGN_CENTER: { - - if (window_pos != 0) + if (window_pos != 0) { pixel_ofs = int(style->get_offset().x); - else + } else { pixel_ofs = int(size.width - (cached_width)) / 2; + } - if (display_clear_icon) + if (display_clear_icon) { pixel_ofs -= int(r_icon_width / 2 + style->get_margin(MARGIN_RIGHT)); + } } break; case ALIGN_RIGHT: { - pixel_ofs = int(size.width - style->get_margin(MARGIN_RIGHT) - (cached_width)); - if (display_clear_icon) + if (display_clear_icon) { pixel_ofs -= int(r_icon_width + style->get_margin(MARGIN_RIGHT)); + } } break; } @@ -1164,9 +1172,11 @@ bool LineEdit::cursor_get_blink_enabled() const { void LineEdit::cursor_set_blink_enabled(const bool p_enabled) { caret_blink_enabled = p_enabled; - if (has_focus()) { + if (has_focus() || caret_force_displayed) { if (p_enabled) { - caret_blink_timer->start(); + if (caret_blink_timer->is_stopped()) { + caret_blink_timer->start(); + } } else { caret_blink_timer->stop(); } @@ -1175,6 +1185,16 @@ void LineEdit::cursor_set_blink_enabled(const bool p_enabled) { draw_caret = true; } +bool LineEdit::cursor_get_force_displayed() const { + return caret_force_displayed; +} + +void LineEdit::cursor_set_force_displayed(const bool p_enabled) { + caret_force_displayed = p_enabled; + cursor_set_blink_enabled(caret_blink_enabled); + update(); +} + float LineEdit::cursor_get_blink_speed() const { return caret_blink_timer->get_wait_time(); } @@ -1197,14 +1217,15 @@ void LineEdit::_reset_caret_blink_timer() { void LineEdit::_toggle_draw_caret() { draw_caret = !draw_caret; - if (is_visible_in_tree() && has_focus() && window_has_focus) { + if (is_visible_in_tree() && ((has_focus() && window_has_focus) || caret_force_displayed)) { update(); } } void LineEdit::delete_char() { - - if ((text.length() <= 0) || (cursor_pos == 0)) return; + if ((text.length() <= 0) || (cursor_pos == 0)) { + return; + } Ref<Font> font = get_theme_font("font"); if (font != nullptr) { @@ -1223,12 +1244,14 @@ void LineEdit::delete_char() { } void LineEdit::delete_text(int p_from_column, int p_to_column) { - + ERR_FAIL_COND_MSG(p_from_column < 0 || p_from_column > p_to_column || p_to_column > text.length(), + vformat("Positional parameters (from: %d, to: %d) are inverted or outside the text length (%d).", p_from_column, p_to_column, text.length())); if (text.size() > 0) { Ref<Font> font = get_theme_font("font"); if (font != nullptr) { - for (int i = p_from_column; i < p_to_column; i++) + for (int i = p_from_column; i < p_to_column; i++) { cached_width -= font->get_char_size(pass ? secret_character[0] : text[i]).width; + } } } else { cached_width = 0; @@ -1238,11 +1261,9 @@ void LineEdit::delete_text(int p_from_column, int p_to_column) { cursor_pos -= CLAMP(cursor_pos - p_from_column, 0, p_to_column - p_from_column); if (cursor_pos >= text.length()) { - cursor_pos = text.length(); } if (window_pos > cursor_pos) { - window_pos = cursor_pos; } @@ -1259,7 +1280,6 @@ void LineEdit::delete_text(int p_from_column, int p_to_column) { } void LineEdit::set_text(String p_text) { - clear_internal(); append_at_cursor(p_text); @@ -1273,18 +1293,15 @@ void LineEdit::set_text(String p_text) { } void LineEdit::clear() { - clear_internal(); _text_changed(); } String LineEdit::get_text() const { - return text; } void LineEdit::set_placeholder(String p_text) { - placeholder = p_text; placeholder_translated = tr(placeholder); update_placeholder_width(); @@ -1292,33 +1309,30 @@ void LineEdit::set_placeholder(String p_text) { } String LineEdit::get_placeholder() const { - return placeholder; } void LineEdit::set_placeholder_alpha(float p_alpha) { - placeholder_alpha = p_alpha; update(); } float LineEdit::get_placeholder_alpha() const { - return placeholder_alpha; } void LineEdit::set_cursor_position(int p_pos) { - - if (p_pos > (int)text.length()) + if (p_pos > (int)text.length()) { p_pos = text.length(); + } - if (p_pos < 0) + if (p_pos < 0) { p_pos = 0; + } cursor_pos = p_pos; if (!is_inside_tree()) { - window_pos = cursor_pos; return; } @@ -1338,16 +1352,15 @@ void LineEdit::set_cursor_position(int p_pos) { window_width -= r_icon->get_width(); } - if (window_width < 0) + if (window_width < 0) { return; + } int wp = window_pos; if (font.is_valid()) { - int accum_width = 0; for (int i = cursor_pos; i >= window_pos; i--) { - if (i >= text.length()) { // Do not do this, because if the cursor is at the end, its just fine that it takes no space. // accum_width = font->get_char_size(' ').width; @@ -1358,32 +1371,33 @@ void LineEdit::set_cursor_position(int p_pos) { accum_width += font->get_char_size(text[i], i + 1 < text.length() ? text[i + 1] : 0).width; // Anything should do. } } - if (accum_width > window_width) + if (accum_width > window_width) { break; + } wp = i; } } - if (wp != window_pos) + if (wp != window_pos) { set_window_pos(wp); + } } update(); } int LineEdit::get_cursor_position() const { - return cursor_pos; } void LineEdit::set_window_pos(int p_pos) { - window_pos = p_pos; - if (window_pos < 0) window_pos = 0; + if (window_pos < 0) { + window_pos = 0; + } } void LineEdit::append_at_cursor(String p_text) { - if ((max_length <= 0) || (text.length() + p_text.length() <= max_length)) { String pre = text.substr(0, cursor_pos); String post = text.substr(cursor_pos, text.length() - cursor_pos); @@ -1396,7 +1410,6 @@ void LineEdit::append_at_cursor(String p_text) { } void LineEdit::clear_internal() { - deselect(); _clear_undo_stack(); cached_width = 0; @@ -1408,7 +1421,6 @@ void LineEdit::clear_internal() { } Size2 LineEdit::get_minimum_size() const { - Ref<StyleBox> style = get_theme_stylebox("normal"); Ref<Font> font = get_theme_font("font"); @@ -1439,7 +1451,6 @@ Size2 LineEdit::get_minimum_size() const { } void LineEdit::deselect() { - selection.begin = 0; selection.end = 0; selection.cursor_start = 0; @@ -1450,28 +1461,27 @@ void LineEdit::deselect() { } void LineEdit::selection_delete() { - - if (selection.enabled) + if (selection.enabled) { delete_text(selection.begin, selection.end); + } deselect(); } void LineEdit::set_max_length(int p_max_length) { - ERR_FAIL_COND(p_max_length < 0); max_length = p_max_length; set_text(text); } int LineEdit::get_max_length() const { - return max_length; } void LineEdit::selection_fill_at_cursor() { - if (!selecting_enabled) + if (!selecting_enabled) { return; + } selection.begin = cursor_pos; selection.end = selection.cursor_start; @@ -1486,11 +1496,13 @@ void LineEdit::selection_fill_at_cursor() { } void LineEdit::select_all() { - if (!selecting_enabled) + if (!selecting_enabled) { return; + } - if (!text.length()) + if (!text.length()) { return; + } selection.begin = 0; selection.end = text.length(); @@ -1499,9 +1511,9 @@ void LineEdit::select_all() { } void LineEdit::set_editable(bool p_editable) { - - if (editable == p_editable) + if (editable == p_editable) { return; + } editable = p_editable; _generate_context_menu(); @@ -1511,24 +1523,20 @@ void LineEdit::set_editable(bool p_editable) { } bool LineEdit::is_editable() const { - return editable; } void LineEdit::set_secret(bool p_secret) { - pass = p_secret; update_cached_width(); update(); } bool LineEdit::is_secret() const { - return pass; } void LineEdit::set_secret_character(const String &p_string) { - // An empty string as the secret character would crash the engine. // It also wouldn't make sense to use multiple characters as the secret character. ERR_FAIL_COND_MSG(p_string.length() != 1, "Secret character must be exactly one character long (" + itos(p_string.length()) + " characters given)."); @@ -1543,8 +1551,9 @@ String LineEdit::get_secret_character() const { } void LineEdit::select(int p_from, int p_to) { - if (!selecting_enabled) + if (!selecting_enabled) { return; + } if (p_from == 0 && p_to == 0) { deselect(); @@ -1552,15 +1561,19 @@ void LineEdit::select(int p_from, int p_to) { } int len = text.length(); - if (p_from < 0) + if (p_from < 0) { p_from = 0; - if (p_from > len) + } + if (p_from > len) { p_from = len; - if (p_to < 0 || p_to > len) + } + if (p_to < 0 || p_to > len) { p_to = len; + } - if (p_from >= p_to) + if (p_from >= p_to) { return; + } selection.enabled = true; selection.begin = p_from; @@ -1571,12 +1584,10 @@ void LineEdit::select(int p_from, int p_to) { } bool LineEdit::is_text_field() const { - return true; } void LineEdit::menu_option(int p_option) { - switch (p_option) { case MENU_CUT: { if (editable) { @@ -1584,7 +1595,6 @@ void LineEdit::menu_option(int p_option) { } } break; case MENU_COPY: { - copy_text(); } break; case MENU_PASTE: { @@ -1633,7 +1643,6 @@ void LineEdit::_editor_settings_changed() { } void LineEdit::set_expand_to_text_length(bool p_enabled) { - expand_to_text_length = p_enabled; minimum_size_changed(); set_window_pos(0); @@ -1666,11 +1675,20 @@ bool LineEdit::is_shortcut_keys_enabled() const { return shortcut_keys_enabled; } +void LineEdit::set_virtual_keyboard_enabled(bool p_enable) { + virtual_keyboard_enabled = p_enable; +} + +bool LineEdit::is_virtual_keyboard_enabled() const { + return virtual_keyboard_enabled; +} + void LineEdit::set_selecting_enabled(bool p_enabled) { selecting_enabled = p_enabled; - if (!selecting_enabled) + if (!selecting_enabled) { deselect(); + } _generate_context_menu(); } @@ -1693,8 +1711,9 @@ Ref<Texture2D> LineEdit::get_right_icon() { } void LineEdit::_text_changed() { - if (expand_to_text_length) + if (expand_to_text_length) { minimum_size_changed(); + } _emit_text_change(); _clear_redo(); @@ -1760,14 +1779,17 @@ void LineEdit::_create_undo_state() { void LineEdit::_generate_context_menu() { // Reorganize context menu. menu->clear(); - if (editable) + if (editable) { menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_X : 0); + } menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_C : 0); - if (editable) + if (editable) { menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_V : 0); + } menu->add_separator(); - if (is_selecting_enabled()) + if (is_selecting_enabled()) { menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_A : 0); + } if (editable) { menu->add_item(RTR("Clear"), MENU_CLEAR); menu->add_separator(); @@ -1777,7 +1799,6 @@ void LineEdit::_generate_context_menu() { } void LineEdit::_bind_methods() { - ClassDB::bind_method(D_METHOD("_text_changed"), &LineEdit::_text_changed); ClassDB::bind_method(D_METHOD("set_align", "align"), &LineEdit::set_align); @@ -1800,11 +1821,15 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_expand_to_text_length"), &LineEdit::get_expand_to_text_length); ClassDB::bind_method(D_METHOD("cursor_set_blink_enabled", "enabled"), &LineEdit::cursor_set_blink_enabled); ClassDB::bind_method(D_METHOD("cursor_get_blink_enabled"), &LineEdit::cursor_get_blink_enabled); + ClassDB::bind_method(D_METHOD("cursor_set_force_displayed", "enabled"), &LineEdit::cursor_set_force_displayed); + ClassDB::bind_method(D_METHOD("cursor_get_force_displayed"), &LineEdit::cursor_get_force_displayed); ClassDB::bind_method(D_METHOD("cursor_set_blink_speed", "blink_speed"), &LineEdit::cursor_set_blink_speed); ClassDB::bind_method(D_METHOD("cursor_get_blink_speed"), &LineEdit::cursor_get_blink_speed); ClassDB::bind_method(D_METHOD("set_max_length", "chars"), &LineEdit::set_max_length); ClassDB::bind_method(D_METHOD("get_max_length"), &LineEdit::get_max_length); ClassDB::bind_method(D_METHOD("append_at_cursor", "text"), &LineEdit::append_at_cursor); + ClassDB::bind_method(D_METHOD("delete_char_at_cursor"), &LineEdit::delete_char); + ClassDB::bind_method(D_METHOD("delete_text", "from_column", "to_column"), &LineEdit::delete_text); ClassDB::bind_method(D_METHOD("set_editable", "enabled"), &LineEdit::set_editable); ClassDB::bind_method(D_METHOD("is_editable"), &LineEdit::is_editable); ClassDB::bind_method(D_METHOD("set_secret", "enabled"), &LineEdit::set_secret); @@ -1815,6 +1840,8 @@ void LineEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("get_menu"), &LineEdit::get_menu); ClassDB::bind_method(D_METHOD("set_context_menu_enabled", "enable"), &LineEdit::set_context_menu_enabled); ClassDB::bind_method(D_METHOD("is_context_menu_enabled"), &LineEdit::is_context_menu_enabled); + ClassDB::bind_method(D_METHOD("set_virtual_keyboard_enabled", "enable"), &LineEdit::set_virtual_keyboard_enabled); + ClassDB::bind_method(D_METHOD("is_virtual_keyboard_enabled"), &LineEdit::is_virtual_keyboard_enabled); ClassDB::bind_method(D_METHOD("set_clear_button_enabled", "enable"), &LineEdit::set_clear_button_enabled); ClassDB::bind_method(D_METHOD("is_clear_button_enabled"), &LineEdit::is_clear_button_enabled); ClassDB::bind_method(D_METHOD("set_shortcut_keys_enabled", "enable"), &LineEdit::set_shortcut_keys_enabled); @@ -1850,6 +1877,7 @@ void LineEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::STRING, "secret_character"), "set_secret_character", "get_secret_character"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_to_text_length"), "set_expand_to_text_length", "get_expand_to_text_length"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled"), "set_context_menu_enabled", "is_context_menu_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled"), "set_virtual_keyboard_enabled", "is_virtual_keyboard_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clear_button_enabled"), "set_clear_button_enabled", "is_clear_button_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled"), "set_shortcut_keys_enabled", "is_shortcut_keys_enabled"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled"), "set_selecting_enabled", "is_selecting_enabled"); @@ -1861,10 +1889,10 @@ void LineEdit::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "cursor_set_blink_enabled", "cursor_get_blink_enabled"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "cursor_set_blink_speed", "cursor_get_blink_speed"); ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_position"), "set_cursor_position", "get_cursor_position"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_force_displayed"), "cursor_set_force_displayed", "cursor_get_force_displayed"); } LineEdit::LineEdit() { - undo_stack_pos = nullptr; _create_undo_state(); align = ALIGN_LEFT; @@ -1891,6 +1919,7 @@ LineEdit::LineEdit() { draw_caret = true; caret_blink_enabled = false; + caret_force_displayed = false; caret_blink_timer = memnew(Timer); add_child(caret_blink_timer); caret_blink_timer->set_wait_time(0.65); |