summaryrefslogtreecommitdiff
path: root/scene/gui/line_edit.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'scene/gui/line_edit.cpp')
-rw-r--r--scene/gui/line_edit.cpp1238
1 files changed, 605 insertions, 633 deletions
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 9f8b944f4c..c2ed9c1a3c 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2020 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2020 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -30,6 +30,7 @@
#include "line_edit.h"
+#include "core/input/input_map.h"
#include "core/object/message_queue.h"
#include "core/os/keyboard.h"
#include "core/os/os.h"
@@ -44,7 +45,180 @@
#endif
#include "scene/main/window.h"
+void LineEdit::_swap_current_input_direction() {
+ if (input_direction == TEXT_DIRECTION_LTR) {
+ input_direction = TEXT_DIRECTION_RTL;
+ } else {
+ input_direction = TEXT_DIRECTION_LTR;
+ }
+ set_caret_column(get_caret_column());
+ update();
+}
+
+void LineEdit::_move_caret_left(bool p_select, bool p_move_by_word) {
+ if (selection.enabled && !p_select) {
+ set_caret_column(selection.begin);
+ deselect();
+ return;
+ }
+
+ shift_selection_check_pre(p_select);
+
+ if (p_move_by_word) {
+ int cc = caret_column;
+
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = words.size() - 1; i >= 0; i--) {
+ if (words[i].x < cc) {
+ cc = words[i].x;
+ break;
+ }
+ }
+
+ set_caret_column(cc);
+ } else {
+ if (caret_mid_grapheme_enabled) {
+ set_caret_column(get_caret_column() - 1);
+ } else {
+ set_caret_column(TS->shaped_text_prev_grapheme_pos(text_rid, get_caret_column()));
+ }
+ }
+
+ shift_selection_check_post(p_select);
+}
+
+void LineEdit::_move_caret_right(bool p_select, bool p_move_by_word) {
+ if (selection.enabled && !p_select) {
+ set_caret_column(selection.end);
+ deselect();
+ return;
+ }
+
+ shift_selection_check_pre(p_select);
+
+ if (p_move_by_word) {
+ int cc = caret_column;
+
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = 0; i < words.size(); i++) {
+ if (words[i].y > cc) {
+ cc = words[i].y;
+ break;
+ }
+ }
+
+ set_caret_column(cc);
+ } else {
+ if (caret_mid_grapheme_enabled) {
+ set_caret_column(get_caret_column() + 1);
+ } else {
+ set_caret_column(TS->shaped_text_next_grapheme_pos(text_rid, get_caret_column()));
+ }
+ }
+
+ shift_selection_check_post(p_select);
+}
+
+void LineEdit::_move_caret_start(bool p_select) {
+ shift_selection_check_pre(p_select);
+ set_caret_column(0);
+ shift_selection_check_post(p_select);
+}
+
+void LineEdit::_move_caret_end(bool p_select) {
+ shift_selection_check_pre(p_select);
+ set_caret_column(text.length());
+ shift_selection_check_post(p_select);
+}
+
+void LineEdit::_backspace(bool p_word, bool p_all_to_left) {
+ if (!editable) {
+ return;
+ }
+
+ if (p_all_to_left) {
+ deselect();
+ text = text.substr(0, caret_column);
+ _text_changed();
+ return;
+ }
+
+ if (selection.enabled) {
+ selection_delete();
+ return;
+ }
+
+ if (p_word) {
+ int cc = caret_column;
+
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = words.size() - 1; i >= 0; i--) {
+ if (words[i].x < cc) {
+ cc = words[i].x;
+ break;
+ }
+ }
+
+ delete_text(cc, caret_column);
+
+ set_caret_column(cc);
+ } else {
+ delete_char();
+ }
+}
+
+void LineEdit::_delete(bool p_word, bool p_all_to_right) {
+ if (!editable) {
+ return;
+ }
+
+ if (p_all_to_right) {
+ deselect();
+ text = text.substr(caret_column, text.length() - caret_column);
+ _shape();
+ set_caret_column(0);
+ _text_changed();
+ return;
+ }
+
+ if (selection.enabled) {
+ selection_delete();
+ return;
+ }
+
+ int text_len = text.length();
+
+ if (caret_column == text_len) {
+ return; // Nothing to do.
+ }
+
+ if (p_word) {
+ int cc = caret_column;
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = 0; i < words.size(); i++) {
+ if (words[i].y > cc) {
+ cc = words[i].y;
+ break;
+ }
+ }
+
+ delete_text(caret_column, cc);
+ set_caret_column(caret_column);
+ } else {
+ if (caret_mid_grapheme_enabled) {
+ set_caret_column(caret_column + 1);
+ delete_char();
+ } else {
+ int cc = caret_column;
+ set_caret_column(TS->shaped_text_next_grapheme_pos(text_rid, caret_column));
+ delete_text(cc, caret_column);
+ }
+ }
+}
+
void LineEdit::_gui_input(Ref<InputEvent> p_event) {
+ ERR_FAIL_COND(p_event.is_null());
+
Ref<InputEventMouseButton> b = p_event;
if (b.is_valid()) {
@@ -52,51 +226,70 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
// Ignore mouse clicks in IME input mode.
return;
}
- if (b->is_pressed() && b->get_button_index() == BUTTON_RIGHT && context_menu_enabled) {
+ if (b->is_pressed() && b->get_button_index() == MOUSE_BUTTON_RIGHT && context_menu_enabled) {
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());
+ _generate_context_menu();
menu->popup();
grab_focus();
accept_event();
return;
}
- if (b->get_button_index() != BUTTON_LEFT) {
+ if (b->get_button_index() != MOUSE_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())) {
+ if (!text.is_empty() && is_editable() && _is_over_clear_button(b->get_position())) {
clear_button_status.press_attempt = true;
clear_button_status.pressing_inside = true;
update();
return;
}
- shift_selection_check_pre(b->get_shift());
+ shift_selection_check_pre(b->is_shift_pressed());
- set_cursor_at_pixel_pos(b->get_position().x);
+ set_caret_at_pixel_pos(b->get_position().x);
- if (b->get_shift()) {
- selection_fill_at_cursor();
+ if (b->is_shift_pressed()) {
+ selection_fill_at_caret();
selection.creating = true;
} else {
- if (b->is_doubleclick() && selecting_enabled) {
- selection.enabled = true;
- selection.begin = 0;
- selection.end = text.length();
- selection.doubleclick = true;
+ if (selecting_enabled) {
+ if (!b->is_double_click() && (OS::get_singleton()->get_ticks_msec() - selection.last_dblclk) < 600) {
+ // Triple-click select all.
+ selection.enabled = true;
+ selection.begin = 0;
+ selection.end = text.length();
+ selection.double_click = true;
+ selection.last_dblclk = 0;
+ caret_column = selection.begin;
+ } else if (b->is_double_click()) {
+ // Double-click select word.
+ Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = 0; i < words.size(); i++) {
+ if (words[i].x < caret_column && words[i].y > caret_column) {
+ selection.enabled = true;
+ selection.begin = words[i].x;
+ selection.end = words[i].y;
+ selection.double_click = true;
+ selection.last_dblclk = OS::get_singleton()->get_ticks_msec();
+ caret_column = selection.end;
+ break;
+ }
+ }
+ }
}
selection.drag_attempt = false;
- if ((cursor_pos < selection.begin) || (cursor_pos > selection.end) || !selection.enabled) {
+ if ((caret_column < selection.begin) || (caret_column > selection.end) || !selection.enabled) {
deselect();
- selection.cursor_start = cursor_pos;
+ selection.start_column = caret_column;
selection.creating = true;
} else if (selection.enabled) {
selection.drag_attempt = true;
@@ -106,7 +299,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
update();
} else {
- if (!text.empty() && is_editable() && clear_button_enabled) {
+ if (!text.is_empty() && is_editable() && clear_button_enabled) {
bool press_attempt = clear_button_status.press_attempt;
clear_button_status.press_attempt = false;
if (press_attempt && clear_button_status.pressing_inside && _is_over_clear_button(b->get_position())) {
@@ -115,19 +308,13 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
}
}
- if ((!selection.creating) && (!selection.doubleclick)) {
+ if ((!selection.creating) && (!selection.double_click)) {
deselect();
}
selection.creating = false;
- selection.doubleclick = false;
+ selection.double_click = false;
- 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);
- }
- }
+ show_virtual_keyboard();
}
update();
@@ -136,7 +323,7 @@ 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) {
+ if (!text.is_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());
if (last_press_inside != clear_button_status.pressing_inside) {
@@ -144,10 +331,10 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
}
}
- if (m->get_button_mask() & BUTTON_LEFT) {
+ if (m->get_button_mask() & MOUSE_BUTTON_LEFT) {
if (selection.creating) {
- set_cursor_at_pixel_pos(m->get_position().x);
- selection_fill_at_cursor();
+ set_caret_at_pixel_pos(m->get_position().x);
+ selection_fill_at_caret();
}
}
}
@@ -159,453 +346,163 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
return;
}
-#ifdef APPLE_STYLE_KEYS
- if (k->get_control() && !k->get_shift() && !k->get_alt() && !k->get_command()) {
- uint32_t remap_key = KEY_UNKNOWN;
- switch (k->get_keycode()) {
- case KEY_F: {
- remap_key = KEY_RIGHT;
- } break;
- case KEY_B: {
- remap_key = KEY_LEFT;
- } break;
- case KEY_P: {
- remap_key = KEY_UP;
- } break;
- case KEY_N: {
- remap_key = KEY_DOWN;
- } break;
- case KEY_D: {
- remap_key = KEY_DELETE;
- } break;
- case KEY_H: {
- remap_key = KEY_BACKSPACE;
- } break;
- case KEY_A: {
- remap_key = KEY_HOME;
- } break;
- case KEY_E: {
- remap_key = KEY_END;
- } break;
+ if (context_menu_enabled) {
+ if (k->is_action("ui_menu", true)) {
+ Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + get_theme_font("font")->get_height(get_theme_font_size("font_size"))) / 2);
+ menu->set_position(get_global_transform().xform(pos));
+ menu->set_size(Vector2(1, 1));
+ _generate_context_menu();
+ menu->popup();
+ menu->grab_focus();
}
+ }
- if (remap_key != KEY_UNKNOWN) {
- k->set_keycode(remap_key);
- k->set_control(false);
+ // Default is ENTER, KP_ENTER. Cannot use ui_accept as default includes SPACE
+ if (k->is_action("ui_text_newline", true)) {
+ emit_signal("text_entered", text);
+ if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
+ DisplayServer::get_singleton()->virtual_keyboard_hide();
}
}
-#endif
-
- unsigned int code = k->get_keycode();
-
- if (k->get_command() && is_shortcut_keys_enabled()) {
- bool handled = true;
-
- switch (code) {
- case (KEY_QUOTELEFT): { // Swap current input direction (primary cursor)
-
- if (input_direction == TEXT_DIRECTION_LTR) {
- input_direction = TEXT_DIRECTION_RTL;
- } else {
- input_direction = TEXT_DIRECTION_LTR;
- }
- set_cursor_position(get_cursor_position());
- update();
-
- } break;
-
- case (KEY_X): { // CUT.
-
- if (editable) {
- cut_text();
- }
-
- } break;
- case (KEY_C): { // COPY.
-
- copy_text();
-
- } break;
-
- case (KEY_Y): // PASTE (Yank for unix users).
- case (KEY_V): { // PASTE.
-
- if (editable) {
- paste_text();
- }
-
- } break;
-
- case (KEY_Z): { // Undo/redo.
- if (editable) {
- if (k->get_shift()) {
- redo();
- } else {
- undo();
- }
- }
- } break;
-
- case (KEY_U): { // Delete from start to cursor.
-
- if (editable) {
- deselect();
- text = text.substr(cursor_pos, text.length() - cursor_pos);
- _shape();
- set_cursor_position(0);
- _text_changed();
- }
-
- } break;
-
- case (KEY_K): { // Delete from cursor_pos to end.
-
- if (editable) {
- deselect();
- text = text.substr(0, cursor_pos);
- _text_changed();
- }
+ if (is_shortcut_keys_enabled()) {
+ if (k->is_action("ui_copy", true)) {
+ copy_text();
+ accept_event();
+ return;
+ }
- } break;
- case (KEY_A): { // Select all.
- select();
+ if (k->is_action("ui_text_select_all", true)) {
+ select();
+ accept_event();
+ return;
+ }
- } 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;
+ // Cut / Paste
+ if (k->is_action("ui_cut", true)) {
+ cut_text();
+ accept_event();
+ return;
+ }
- // If selected, delete the selection
- if (selection.enabled) {
- selection_delete();
- break;
- }
+ if (k->is_action("ui_paste", true)) {
+ paste_text();
+ accept_event();
+ return;
+ }
- // 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: {
- handled = false;
- }
+ // Undo / Redo
+ if (k->is_action("ui_undo", true)) {
+ undo();
+ accept_event();
+ return;
}
- if (handled) {
+ if (k->is_action("ui_redo", true)) {
+ redo();
accept_event();
return;
}
}
- _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) && virtual_keyboard_enabled) {
- DisplayServer::get_singleton()->virtual_keyboard_hide();
- }
-
- } break;
-
- case KEY_BACKSPACE: {
- if (!editable) {
- break;
- }
-
- if (selection.enabled) {
- selection_delete();
- break;
- }
-
-#ifdef APPLE_STYLE_KEYS
- if (k->get_alt()) {
-#else
- if (k->get_alt()) {
- handled = false;
- break;
- } else if (k->get_command()) {
-#endif
- int cc = cursor_pos;
-
- Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
- for (int i = words.size() - 1; i >= 0; i--) {
- if (words[i].x < cc) {
- cc = words[i].x;
- break;
- }
- }
-
- delete_text(cc, cursor_pos);
-
- set_cursor_position(cc);
-
- } else {
- delete_char();
- }
-
- } break;
- case KEY_KP_4: {
- if (k->get_unicode() != 0) {
- handled = false;
- break;
- }
- [[fallthrough]];
- }
- case KEY_LEFT: {
-#ifndef APPLE_STYLE_KEYS
- if (!k->get_alt()) {
-#endif
- if (selection.enabled && !k->get_shift()) {
- set_cursor_position(selection.begin);
- deselect();
- handled = true;
- break;
- }
-
- shift_selection_check_pre(k->get_shift());
-#ifndef APPLE_STYLE_KEYS
- }
-#endif
-
-#ifdef APPLE_STYLE_KEYS
- if (k->get_command()) {
- set_cursor_position(0);
- } else if (k->get_alt()) {
-#else
- if (k->get_alt()) {
- handled = false;
- break;
- } else if (k->get_command()) {
-#endif
- int cc = cursor_pos;
-
- Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
- for (int i = words.size() - 1; i >= 0; i--) {
- if (words[i].x < cc) {
- cc = words[i].x;
- break;
- }
- }
-
- set_cursor_position(cc);
-
- } else {
- if (mid_grapheme_caret_enabled) {
- set_cursor_position(get_cursor_position() - 1);
- } else {
- set_cursor_position(TS->shaped_text_prev_grapheme_pos(text_rid, get_cursor_position()));
- }
- }
-
- shift_selection_check_post(k->get_shift());
-
- } break;
- case KEY_KP_6: {
- if (k->get_unicode() != 0) {
- handled = false;
- break;
- }
- [[fallthrough]];
- }
- case KEY_RIGHT: {
-#ifndef APPLE_STYLE_KEYS
- if (!k->get_alt()) {
-#endif
- if (selection.enabled && !k->get_shift()) {
- set_cursor_position(selection.end);
- deselect();
- handled = true;
- break;
- }
-
- shift_selection_check_pre(k->get_shift());
-#ifndef APPLE_STYLE_KEYS
- }
-#endif
-
-#ifdef APPLE_STYLE_KEYS
- if (k->get_command()) {
- set_cursor_position(text.length());
- } else if (k->get_alt()) {
-#else
- if (k->get_alt()) {
- handled = false;
- break;
- } else if (k->get_command()) {
-#endif
- int cc = cursor_pos;
-
- Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
- for (int i = 0; i < words.size(); i++) {
- if (words[i].y > cc) {
- cc = words[i].y;
- break;
- }
- }
-
- set_cursor_position(cc);
-
- } else {
- if (mid_grapheme_caret_enabled) {
- set_cursor_position(get_cursor_position() + 1);
- } else {
- set_cursor_position(TS->shaped_text_next_grapheme_pos(text_rid, get_cursor_position()));
- }
- }
-
- shift_selection_check_post(k->get_shift());
-
- } break;
- case KEY_UP: {
- shift_selection_check_pre(k->get_shift());
- 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;
- }
- set_cursor_position(text.length());
- shift_selection_check_post(k->get_shift());
- } break;
- case KEY_DELETE: {
- if (!editable) {
- break;
- }
-
- if (k->get_shift() && !k->get_command() && !k->get_alt()) {
- cut_text();
- break;
- }
-
- if (selection.enabled) {
- selection_delete();
- break;
- }
-
- int text_len = text.length();
+ // BACKSPACE
+ if (k->is_action("ui_text_backspace_all_to_left", true)) {
+ _backspace(false, true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_backspace_word", true)) {
+ _backspace(true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_backspace", true)) {
+ _backspace();
+ accept_event();
+ return;
+ }
- if (cursor_pos == text_len) {
- break; // Nothing to do.
- }
+ // DELETE
+ if (k->is_action("ui_text_delete_all_to_right", true)) {
+ _delete(false, true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_delete_word", true)) {
+ _delete(true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_delete", true)) {
+ _delete();
+ accept_event();
+ return;
+ }
-#ifdef APPLE_STYLE_KEYS
- if (k->get_alt()) {
-#else
- if (k->get_alt()) {
- handled = false;
- break;
- } else if (k->get_command()) {
-#endif
- int cc = cursor_pos;
+ // Cursor Movement
- Vector<Vector2i> words = TS->shaped_text_get_word_breaks(text_rid);
- for (int i = 0; i < words.size(); i++) {
- if (words[i].y > cc) {
- cc = words[i].y;
- break;
- }
- }
+ k = k->duplicate();
+ bool shift_pressed = k->is_shift_pressed();
+ // Remove shift or else actions will not match. Use above variable for selection.
+ k->set_shift_pressed(false);
- delete_text(cursor_pos, cc);
+ if (k->is_action("ui_text_caret_word_left", true)) {
+ _move_caret_left(shift_pressed, true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_left", true)) {
+ _move_caret_left(shift_pressed);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_word_right", true)) {
+ _move_caret_right(shift_pressed, true);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_right", true)) {
+ _move_caret_right(shift_pressed, false);
+ accept_event();
+ return;
+ }
- } else {
- if (mid_grapheme_caret_enabled) {
- set_cursor_position(cursor_pos + 1);
- delete_char();
- } else {
- int cc = cursor_pos;
- set_cursor_position(TS->shaped_text_next_grapheme_pos(text_rid, cursor_pos));
- delete_text(cc, cursor_pos);
- }
- }
+ // Up = Home, Down = End
+ if (k->is_action("ui_text_caret_up", true) || k->is_action("ui_text_caret_line_start", true) || k->is_action("ui_text_caret_page_up", true)) {
+ _move_caret_start(shift_pressed);
+ accept_event();
+ return;
+ }
+ if (k->is_action("ui_text_caret_down", true) || k->is_action("ui_text_caret_line_end", true) || k->is_action("ui_text_caret_page_down", true)) {
+ _move_caret_end(shift_pressed);
+ accept_event();
+ return;
+ }
- } break;
- case KEY_KP_7: {
- if (k->get_unicode() != 0) {
- handled = false;
- break;
- }
- [[fallthrough]];
- }
- case KEY_HOME: {
- shift_selection_check_pre(k->get_shift());
- set_cursor_position(0);
- shift_selection_check_post(k->get_shift());
- } break;
- case KEY_KP_1: {
- if (k->get_unicode() != 0) {
- handled = false;
- break;
- }
- [[fallthrough]];
- }
- case KEY_END: {
- shift_selection_check_pre(k->get_shift());
- set_cursor_position(text.length());
- shift_selection_check_post(k->get_shift());
- } break;
- case KEY_MENU: {
- if (context_menu_enabled) {
- Point2 pos = Point2(get_cursor_pixel_pos().x, (get_size().y + get_theme_font("font")->get_height(get_theme_font_size("font_size"))) / 2);
- menu->set_position(get_global_transform().xform(pos));
- menu->set_size(Vector2(1, 1));
- //menu->set_scale(get_global_transform().get_scale());
- menu->popup();
- menu->grab_focus();
- }
- } break;
+ // Misc
+ if (k->is_action("ui_swap_input_direction", true)) {
+ _swap_current_input_direction();
+ accept_event();
+ return;
+ }
- default: {
- handled = false;
- } break;
- }
+ _reset_caret_blink_timer();
- if (handled) {
- 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();
- char32_t ucodestr[2] = { (char32_t)k->get_unicode(), 0 };
- int prev_len = text.length();
- append_at_cursor(ucodestr);
- if (text.length() != prev_len) {
- _text_changed();
- }
- accept_event();
- }
+ // Allow unicode handling if:
+ // * No Modifiers are pressed (except shift)
+ bool allow_unicode_handling = !(k->is_command_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
- } else {
- return;
- }
+ if (allow_unicode_handling && editable && k->get_unicode() >= 32) {
+ // Handle Unicode (if no modifiers active)
+ selection_delete();
+ char32_t ucodestr[2] = { (char32_t)k->get_unicode(), 0 };
+ int prev_len = text.length();
+ insert_text_at_caret(ucodestr);
+ if (text.length() != prev_len) {
+ _text_changed();
}
-
- update();
+ accept_event();
}
-
- return;
}
}
@@ -635,25 +532,32 @@ Variant LineEdit::get_drag_data(const Point2 &p_point) {
}
bool LineEdit::can_drop_data(const Point2 &p_point, const Variant &p_data) const {
+ bool drop_override = Control::can_drop_data(p_point, p_data); // In case user wants to drop custom data.
+ if (drop_override) {
+ return drop_override;
+ }
+
return p_data.get_type() == Variant::STRING;
}
void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
+ Control::drop_data(p_point, p_data);
+
if (p_data.get_type() == Variant::STRING) {
- set_cursor_at_pixel_pos(p_point.x);
+ set_caret_at_pixel_pos(p_point.x);
int selected = selection.end - selection.begin;
text.erase(selection.begin, selected);
_shape();
- append_at_cursor(p_data);
- selection.begin = cursor_pos - selected;
- selection.end = cursor_pos;
+ insert_text_at_caret(p_data);
+ selection.begin = caret_column - selected;
+ selection.end = caret_column;
}
}
Control::CursorShape LineEdit::get_cursor_shape(const Point2 &p_pos) const {
- if (!text.empty() && is_editable() && _is_over_clear_button(p_pos)) {
+ if ((!text.is_empty() && is_editable() && _is_over_clear_button(p_pos)) || (!is_editable() && (!is_selecting_enabled() || text.is_empty()))) {
return CURSOR_ARROW;
}
return Control::get_cursor_shape(p_pos);
@@ -673,8 +577,8 @@ void LineEdit::_notification(int p_what) {
#ifdef TOOLS_ENABLED
case NOTIFICATION_ENTER_TREE: {
if (Engine::get_singleton()->is_editor_hint() && !get_tree()->is_node_being_edited(this)) {
- cursor_set_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false));
- cursor_set_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65));
+ set_caret_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false));
+ set_caret_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65));
if (!EditorSettings::get_singleton()->is_connected("settings_changed", callable_mp(this, &LineEdit::_editor_settings_changed))) {
EditorSettings::get_singleton()->connect("settings_changed", callable_mp(this, &LineEdit::_editor_settings_changed));
@@ -685,7 +589,7 @@ void LineEdit::_notification(int p_what) {
case NOTIFICATION_RESIZED: {
_fit_to_width();
scroll_offset = 0;
- set_cursor_position(get_cursor_position());
+ set_caret_column(get_caret_column());
} break;
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
@@ -735,7 +639,7 @@ void LineEdit::_notification(int p_what) {
}
int x_ofs = 0;
- bool using_placeholder = text.empty() && ime_text.empty();
+ bool using_placeholder = text.is_empty() && ime_text.is_empty();
float text_width = TS->shaped_text_get_size(text_rid).x;
float text_height = TS->shaped_text_get_size(text_rid).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM);
@@ -743,7 +647,7 @@ void LineEdit::_notification(int p_what) {
case ALIGN_FILL:
case ALIGN_LEFT: {
if (rtl) {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - style->get_margin(MARGIN_RIGHT) - (text_width)));
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - style->get_margin(SIDE_RIGHT) - (text_width)));
} else {
x_ofs = style->get_offset().x;
}
@@ -752,27 +656,27 @@ void LineEdit::_notification(int p_what) {
if (scroll_offset != 0) {
x_ofs = style->get_offset().x;
} else {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - (text_width)) / 2);
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - (text_width)) / 2);
}
} break;
case ALIGN_RIGHT: {
if (rtl) {
x_ofs = style->get_offset().x;
} else {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - style->get_margin(MARGIN_RIGHT) - (text_width)));
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - style->get_margin(SIDE_RIGHT) - (text_width)));
}
} break;
}
- int ofs_max = width - style->get_margin(MARGIN_RIGHT);
+ int ofs_max = width - style->get_margin(SIDE_RIGHT);
int y_area = height - style->get_minimum_size().height;
int y_ofs = style->get_offset().y + (y_area - text_height) / 2;
Color selection_color = get_theme_color("selection_color");
- Color font_color = is_editable() ? get_theme_color("font_color") : get_theme_color("font_color_uneditable");
- Color font_color_selected = get_theme_color("font_color_selected");
- Color cursor_color = get_theme_color("cursor_color");
+ Color font_color = is_editable() ? get_theme_color("font_color") : get_theme_color("font_uneditable_color");
+ Color font_selected_color = get_theme_color("font_selected_color");
+ Color caret_color = get_theme_color("caret_color");
// Draw placeholder color.
if (using_placeholder) {
@@ -791,14 +695,14 @@ void LineEdit::_notification(int p_what) {
}
}
- r_icon->draw(ci, Point2(width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT), height / 2 - r_icon->get_height() / 2), color_icon);
+ r_icon->draw(ci, Point2(width - r_icon->get_width() - style->get_margin(SIDE_RIGHT), height / 2 - r_icon->get_height() / 2), color_icon);
if (align == ALIGN_CENTER) {
if (scroll_offset == 0) {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(size.width - text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2);
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2);
}
} else {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - r_icon->get_width() - style->get_margin(MARGIN_RIGHT));
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT));
}
ofs_max -= r_icon->get_width();
@@ -834,14 +738,32 @@ void LineEdit::_notification(int p_what) {
// Draw text.
ofs.y += TS->shaped_text_get_ascent(text_rid);
+ Color font_outline_color = get_theme_color("font_outline_color");
+ int outline_size = get_theme_constant("outline_size");
+ if (outline_size > 0 && font_outline_color.a > 0) {
+ Vector2 oofs = ofs;
+ for (int i = 0; i < gl_size; i++) {
+ for (int j = 0; j < glyphs[i].repeat; j++) {
+ if (ceil(oofs.x) >= x_ofs && (oofs.x + glyphs[i].advance) <= ofs_max) {
+ if (glyphs[i].font_rid != RID()) {
+ TS->font_draw_glyph_outline(glyphs[i].font_rid, ci, glyphs[i].font_size, outline_size, oofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, font_outline_color);
+ }
+ }
+ oofs.x += glyphs[i].advance;
+ }
+ if (oofs.x >= ofs_max) {
+ break;
+ }
+ }
+ }
for (int i = 0; i < gl_size; i++) {
bool selected = selection.enabled && glyphs[i].start >= selection.begin && glyphs[i].end <= selection.end;
for (int j = 0; j < glyphs[i].repeat; j++) {
if (ceil(ofs.x) >= x_ofs && (ofs.x + glyphs[i].advance) <= ofs_max) {
if (glyphs[i].font_rid != RID()) {
- TS->font_draw_glyph(glyphs[i].font_rid, ci, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_color_selected : font_color);
+ TS->font_draw_glyph(glyphs[i].font_rid, ci, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_selected_color : font_color);
} else if ((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) {
- TS->draw_hex_code_box(ci, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_color_selected : font_color);
+ TS->draw_hex_code_box(ci, glyphs[i].font_size, ofs + Vector2(glyphs[i].x_off, glyphs[i].y_off), glyphs[i].index, selected ? font_selected_color : font_color);
}
}
ofs.x += glyphs[i].advance;
@@ -858,7 +780,7 @@ void LineEdit::_notification(int p_what) {
// Normal caret.
Rect2 l_caret, t_caret;
TextServer::Direction l_dir, t_dir;
- TS->shaped_text_get_carets(text_rid, cursor_pos, l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column, l_caret, l_dir, t_caret, t_dir);
if (l_caret == Rect2() && t_caret == Rect2()) {
// No carets, add one at the start.
@@ -871,28 +793,28 @@ void LineEdit::_notification(int p_what) {
l_dir = TextServer::DIRECTION_LTR;
l_caret = Rect2(Vector2(x_ofs, y), Size2(caret_width, h));
}
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, caret_color);
} else {
if (l_caret != Rect2() && l_dir == TextServer::DIRECTION_AUTO) {
// Draw extra marker on top of mid caret.
Rect2 trect = Rect2(l_caret.position.x - 3 * caret_width, l_caret.position.y, 6 * caret_width, caret_width);
trect.position += ofs;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color);
}
l_caret.position += ofs;
l_caret.size.x = caret_width;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, caret_color);
t_caret.position += ofs;
t_caret.size.x = caret_width;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, t_caret, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, t_caret, caret_color);
}
} else {
{
- // IME intermidiet text range.
- Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, cursor_pos, cursor_pos + ime_text.length());
+ // IME intermediate text range.
+ Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, caret_column, caret_column + ime_text.length());
for (int i = 0; i < sel.size(); i++) {
Rect2 rect = Rect2(sel[i].x + ofs.x, ofs.y, sel[i].y - sel[i].x, text_height);
if (rect.position.x + rect.size.x <= x_ofs || rect.position.x > ofs_max) {
@@ -905,12 +827,12 @@ void LineEdit::_notification(int p_what) {
rect.size.x = ofs_max - rect.position.x;
}
rect.size.y = caret_width;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, caret_color);
}
}
{
// IME caret.
- Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, cursor_pos + ime_selection.x, cursor_pos + ime_selection.x + ime_selection.y);
+ Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, caret_column + ime_selection.x, caret_column + ime_selection.x + ime_selection.y);
for (int i = 0; i < sel.size(); i++) {
Rect2 rect = Rect2(sel[i].x + ofs.x, ofs.y, sel[i].y - sel[i].x, text_height);
if (rect.position.x + rect.size.x <= x_ofs || rect.position.x > ofs_max) {
@@ -923,14 +845,14 @@ void LineEdit::_notification(int p_what) {
rect.size.x = ofs_max - rect.position.x;
}
rect.size.y = caret_width * 3;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, cursor_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, caret_color);
}
}
}
}
if (has_focus()) {
- if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + Point2(using_placeholder ? 0 : x_ofs, y_ofs + TS->shaped_text_get_size(text_rid).y), get_viewport()->get_window_id());
}
@@ -947,34 +869,27 @@ void LineEdit::_notification(int p_what) {
}
}
- if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id());
- Point2 cursor_pos = Point2(get_cursor_position(), 1) * get_minimum_size().height;
- 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) && 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);
- }
+ Point2 caret_column = Point2(get_caret_column(), 1) * get_minimum_size().height;
+ DisplayServer::get_singleton()->window_set_ime_position(get_global_position() + caret_column, get_viewport()->get_window_id());
}
+ show_virtual_keyboard();
} break;
case NOTIFICATION_FOCUS_EXIT: {
if (caret_blink_enabled && !caret_force_displayed) {
caret_blink_timer->stop();
}
- if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID) {
+ if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) {
DisplayServer::get_singleton()->window_set_ime_position(Point2(), get_viewport()->get_window_id());
DisplayServer::get_singleton()->window_set_ime_active(false, get_viewport()->get_window_id());
}
ime_text = "";
ime_selection = Point2();
_shape();
- set_cursor_position(cursor_pos); // Update scroll_offset
+ set_caret_column(caret_column); // Update scroll_offset
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) {
DisplayServer::get_singleton()->virtual_keyboard_hide();
@@ -986,7 +901,7 @@ void LineEdit::_notification(int p_what) {
ime_text = DisplayServer::get_singleton()->ime_get_text();
ime_selection = DisplayServer::get_singleton()->ime_get_selection();
_shape();
- set_cursor_position(cursor_pos); // Update scroll_offset
+ set_caret_column(caret_column); // Update scroll_offset
update();
}
@@ -1001,13 +916,17 @@ void LineEdit::copy_text() {
}
void LineEdit::cut_text() {
- if (selection.enabled && !pass) {
+ if (editable && selection.enabled && !pass) {
DisplayServer::get_singleton()->clipboard_set(text.substr(selection.begin, selection.end - selection.begin));
selection_delete();
}
}
void LineEdit::paste_text() {
+ if (!editable) {
+ return;
+ }
+
// 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();
@@ -1016,7 +935,7 @@ void LineEdit::paste_text() {
if (selection.enabled) {
selection_delete();
}
- append_at_cursor(paste_buffer);
+ insert_text_at_caret(paste_buffer);
if (!text_changed_dirty) {
if (is_inside_tree() && text.length() != prev_len) {
@@ -1028,6 +947,10 @@ void LineEdit::paste_text() {
}
void LineEdit::undo() {
+ if (!editable) {
+ return;
+ }
+
if (undo_stack_pos == nullptr) {
if (undo_stack.size() <= 1) {
return;
@@ -1040,13 +963,17 @@ void LineEdit::undo() {
TextOperation op = undo_stack_pos->get();
text = op.text;
scroll_offset = op.scroll_offset;
- set_cursor_position(op.cursor_pos);
+ set_caret_column(op.caret_column);
_shape();
_emit_text_change();
}
void LineEdit::redo() {
+ if (!editable) {
+ return;
+ }
+
if (undo_stack_pos == nullptr) {
return;
}
@@ -1057,7 +984,7 @@ void LineEdit::redo() {
TextOperation op = undo_stack_pos->get();
text = op.text;
scroll_offset = op.scroll_offset;
- set_cursor_position(op.cursor_pos);
+ set_caret_column(op.caret_column);
_shape();
_emit_text_change();
@@ -1065,7 +992,7 @@ void LineEdit::redo() {
void LineEdit::shift_selection_check_pre(bool p_shift) {
if (!selection.enabled && p_shift) {
- selection.cursor_start = cursor_pos;
+ selection.start_column = caret_column;
}
if (!p_shift) {
deselect();
@@ -1074,11 +1001,11 @@ void LineEdit::shift_selection_check_pre(bool p_shift) {
void LineEdit::shift_selection_check_post(bool p_shift) {
if (p_shift) {
- selection_fill_at_cursor();
+ selection_fill_at_caret();
}
}
-void LineEdit::set_cursor_at_pixel_pos(int p_x) {
+void LineEdit::set_caret_at_pixel_pos(int p_x) {
Ref<StyleBox> style = get_theme_stylebox("normal");
bool rtl = is_layout_rtl();
@@ -1088,7 +1015,7 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) {
case ALIGN_FILL:
case ALIGN_LEFT: {
if (rtl) {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - style->get_margin(MARGIN_RIGHT) - (text_width)));
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width)));
} else {
x_ofs = style->get_offset().x;
}
@@ -1097,36 +1024,36 @@ void LineEdit::set_cursor_at_pixel_pos(int p_x) {
if (scroll_offset != 0) {
x_ofs = style->get_offset().x;
} else {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - (text_width)) / 2);
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2);
}
} break;
case ALIGN_RIGHT: {
if (rtl) {
x_ofs = style->get_offset().x;
} else {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - style->get_margin(MARGIN_RIGHT) - (text_width)));
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width)));
}
} break;
}
- bool using_placeholder = text.empty() && ime_text.empty();
+ bool using_placeholder = text.is_empty() && ime_text.is_empty();
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon("clear") : right_icon;
if (align == ALIGN_CENTER) {
if (scroll_offset == 0) {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2);
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2);
}
} else {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - r_icon->get_width() - style->get_margin(MARGIN_RIGHT));
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT));
}
}
int ofs = TS->shaped_text_hit_test_position(text_rid, p_x - x_ofs - scroll_offset);
- set_cursor_position(ofs);
+ set_caret_column(ofs);
}
-Vector2i LineEdit::get_cursor_pixel_pos() {
+Vector2i LineEdit::get_caret_pixel_pos() {
Ref<StyleBox> style = get_theme_stylebox("normal");
bool rtl = is_layout_rtl();
@@ -1136,7 +1063,7 @@ Vector2i LineEdit::get_cursor_pixel_pos() {
case ALIGN_FILL:
case ALIGN_LEFT: {
if (rtl) {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - style->get_margin(MARGIN_RIGHT) - (text_width)));
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width)));
} else {
x_ofs = style->get_offset().x;
}
@@ -1145,28 +1072,28 @@ Vector2i LineEdit::get_cursor_pixel_pos() {
if (scroll_offset != 0) {
x_ofs = style->get_offset().x;
} else {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - (text_width)) / 2);
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2);
}
} break;
case ALIGN_RIGHT: {
if (rtl) {
x_ofs = style->get_offset().x;
} else {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - style->get_margin(MARGIN_RIGHT) - (text_width)));
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width)));
}
} break;
}
- bool using_placeholder = text.empty() && ime_text.empty();
+ bool using_placeholder = text.is_empty() && ime_text.is_empty();
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon("clear") : right_icon;
if (align == ALIGN_CENTER) {
if (scroll_offset == 0) {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2);
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2);
}
} else {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - r_icon->get_width() - style->get_margin(MARGIN_RIGHT));
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT));
}
}
@@ -1175,9 +1102,9 @@ Vector2i LineEdit::get_cursor_pixel_pos() {
TextServer::Direction l_dir, t_dir;
// Get position of the start of caret.
if (ime_text.length() != 0 && ime_selection.x != 0) {
- TS->shaped_text_get_carets(text_rid, cursor_pos + ime_selection.x, l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x, l_caret, l_dir, t_caret, t_dir);
} else {
- TS->shaped_text_get_carets(text_rid, cursor_pos, l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column, l_caret, l_dir, t_caret, t_dir);
}
if ((l_caret != Rect2() && (l_dir == TextServer::DIRECTION_AUTO || l_dir == (TextServer::Direction)input_direction)) || (t_caret == Rect2())) {
@@ -1189,9 +1116,9 @@ Vector2i LineEdit::get_cursor_pixel_pos() {
// Get position of the end of caret.
if (ime_text.length() != 0) {
if (ime_selection.y != 0) {
- TS->shaped_text_get_carets(text_rid, cursor_pos + ime_selection.x + ime_selection.y, l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x + ime_selection.y, l_caret, l_dir, t_caret, t_dir);
} else {
- TS->shaped_text_get_carets(text_rid, cursor_pos + ime_text.size(), l_caret, l_dir, t_caret, t_dir);
+ TS->shaped_text_get_carets(text_rid, caret_column + ime_text.size(), l_caret, l_dir, t_caret, t_dir);
}
if ((l_caret != Rect2() && (l_dir == TextServer::DIRECTION_AUTO || l_dir == (TextServer::Direction)input_direction)) || (t_caret == Rect2())) {
ret.y = x_ofs + l_caret.position.x + scroll_offset;
@@ -1205,19 +1132,19 @@ Vector2i LineEdit::get_cursor_pixel_pos() {
return ret;
}
-void LineEdit::set_mid_grapheme_caret_enabled(const bool p_enabled) {
- mid_grapheme_caret_enabled = p_enabled;
+void LineEdit::set_caret_mid_grapheme_enabled(const bool p_enabled) {
+ caret_mid_grapheme_enabled = p_enabled;
}
-bool LineEdit::get_mid_grapheme_caret_enabled() const {
- return mid_grapheme_caret_enabled;
+bool LineEdit::is_caret_mid_grapheme_enabled() const {
+ return caret_mid_grapheme_enabled;
}
-bool LineEdit::cursor_get_blink_enabled() const {
+bool LineEdit::is_caret_blink_enabled() const {
return caret_blink_enabled;
}
-void LineEdit::cursor_set_blink_enabled(const bool p_enabled) {
+void LineEdit::set_caret_blink_enabled(const bool p_enabled) {
caret_blink_enabled = p_enabled;
if (has_focus() || caret_force_displayed) {
@@ -1231,23 +1158,25 @@ void LineEdit::cursor_set_blink_enabled(const bool p_enabled) {
}
draw_caret = true;
+
+ notify_property_list_changed();
}
-bool LineEdit::cursor_get_force_displayed() const {
+bool LineEdit::is_caret_force_displayed() const {
return caret_force_displayed;
}
-void LineEdit::cursor_set_force_displayed(const bool p_enabled) {
+void LineEdit::set_caret_force_displayed(const bool p_enabled) {
caret_force_displayed = p_enabled;
- cursor_set_blink_enabled(caret_blink_enabled);
+ set_caret_blink_enabled(caret_blink_enabled);
update();
}
-float LineEdit::cursor_get_blink_speed() const {
+float LineEdit::get_caret_blink_speed() const {
return caret_blink_timer->get_wait_time();
}
-void LineEdit::cursor_set_blink_speed(const float p_speed) {
+void LineEdit::set_caret_blink_speed(const float p_speed) {
ERR_FAIL_COND(p_speed <= 0);
caret_blink_timer->set_wait_time(p_speed);
}
@@ -1271,14 +1200,14 @@ void LineEdit::_toggle_draw_caret() {
}
void LineEdit::delete_char() {
- if ((text.length() <= 0) || (cursor_pos == 0)) {
+ if ((text.length() <= 0) || (caret_column == 0)) {
return;
}
- text.erase(cursor_pos - 1, 1);
+ text.erase(caret_column - 1, 1);
_shape();
- set_cursor_position(get_cursor_position() - 1);
+ set_caret_column(get_caret_column() - 1);
_text_changed();
}
@@ -1290,10 +1219,10 @@ void LineEdit::delete_text(int p_from_column, int p_to_column) {
text.erase(p_from_column, p_to_column - p_from_column);
_shape();
- cursor_pos -= CLAMP(cursor_pos - p_from_column, 0, p_to_column - p_from_column);
+ caret_column -= CLAMP(caret_column - p_from_column, 0, p_to_column - p_from_column);
- if (cursor_pos >= text.length()) {
- cursor_pos = text.length();
+ if (caret_column >= text.length()) {
+ caret_column = text.length();
}
if (!text_changed_dirty) {
@@ -1306,10 +1235,11 @@ 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);
+ insert_text_at_caret(p_text);
+ _create_undo_state();
update();
- cursor_pos = 0;
+ caret_column = 0;
scroll_offset = 0;
}
@@ -1407,6 +1337,21 @@ Array LineEdit::get_structured_text_bidi_override_options() const {
void LineEdit::clear() {
clear_internal();
_text_changed();
+
+ // This should reset virtual keyboard state if needed.
+ if (has_focus()) {
+ show_virtual_keyboard();
+ }
+}
+
+void LineEdit::show_virtual_keyboard() {
+ 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, caret_column);
+ }
+ }
}
String LineEdit::get_text() const {
@@ -1433,16 +1378,16 @@ float LineEdit::get_placeholder_alpha() const {
return placeholder_alpha;
}
-void LineEdit::set_cursor_position(int p_pos) {
- if (p_pos > (int)text.length()) {
- p_pos = text.length();
+void LineEdit::set_caret_column(int p_column) {
+ if (p_column > (int)text.length()) {
+ p_column = text.length();
}
- if (p_pos < 0) {
- p_pos = 0;
+ if (p_column < 0) {
+ p_column = 0;
}
- cursor_pos = p_pos;
+ caret_column = p_column;
// Fit to window.
@@ -1460,7 +1405,7 @@ void LineEdit::set_cursor_position(int p_pos) {
case ALIGN_FILL:
case ALIGN_LEFT: {
if (rtl) {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - style->get_margin(MARGIN_RIGHT) - (text_width)));
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width)));
} else {
x_ofs = style->get_offset().x;
}
@@ -1469,35 +1414,35 @@ void LineEdit::set_cursor_position(int p_pos) {
if (scroll_offset != 0) {
x_ofs = style->get_offset().x;
} else {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - (text_width)) / 2);
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2);
}
} break;
case ALIGN_RIGHT: {
if (rtl) {
x_ofs = style->get_offset().x;
} else {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - style->get_margin(MARGIN_RIGHT) - (text_width)));
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width)));
}
} break;
}
- int ofs_max = get_size().width - style->get_margin(MARGIN_RIGHT);
- bool using_placeholder = text.empty() && ime_text.empty();
+ int ofs_max = get_size().width - style->get_margin(SIDE_RIGHT);
+ bool using_placeholder = text.is_empty() && ime_text.is_empty();
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon("clear") : right_icon;
if (align == ALIGN_CENTER) {
if (scroll_offset == 0) {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(MARGIN_RIGHT) * 2) / 2);
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2);
}
} else {
- x_ofs = MAX(style->get_margin(MARGIN_LEFT), x_ofs - r_icon->get_width() - style->get_margin(MARGIN_RIGHT));
+ x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT));
}
ofs_max -= r_icon->get_width();
}
- // Note: Use too coordinates to fit IME input range.
- Vector2i primary_catret_offset = get_cursor_pixel_pos();
+ // Note: Use two coordinates to fit IME input range.
+ Vector2i primary_catret_offset = get_caret_pixel_pos();
if (MIN(primary_catret_offset.x, primary_catret_offset.y) <= x_ofs) {
scroll_offset += (x_ofs - MIN(primary_catret_offset.x, primary_catret_offset.y));
@@ -1509,8 +1454,8 @@ void LineEdit::set_cursor_position(int p_pos) {
update();
}
-int LineEdit::get_cursor_position() const {
- return cursor_pos;
+int LineEdit::get_caret_column() const {
+ return caret_column;
}
void LineEdit::set_scroll_offset(int p_pos) {
@@ -1524,17 +1469,17 @@ int LineEdit::get_scroll_offset() const {
return scroll_offset;
}
-void LineEdit::append_at_cursor(String p_text) {
+void LineEdit::insert_text_at_caret(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);
+ String pre = text.substr(0, caret_column);
+ String post = text.substr(caret_column, text.length() - caret_column);
text = pre + p_text + post;
_shape();
- TextServer::Direction dir = TS->shaped_text_get_dominant_direciton_in_range(text_rid, cursor_pos, cursor_pos + p_text.length());
+ TextServer::Direction dir = TS->shaped_text_get_dominant_direciton_in_range(text_rid, caret_column, caret_column + p_text.length());
if (dir != TextServer::DIRECTION_AUTO) {
input_direction = (TextDirection)dir;
}
- set_cursor_position(cursor_pos + p_text.length());
+ set_caret_column(caret_column + p_text.length());
} else {
emit_signal("text_change_rejected");
}
@@ -1543,7 +1488,7 @@ void LineEdit::append_at_cursor(String p_text) {
void LineEdit::clear_internal() {
deselect();
_clear_undo_stack();
- cursor_pos = 0;
+ caret_column = 0;
scroll_offset = 0;
undo_text = "";
text = "";
@@ -1559,18 +1504,18 @@ Size2 LineEdit::get_minimum_size() const {
Size2 min_size;
// Minimum size of text.
- int space_size = font->get_char_size('m', 0, font_size).x;
- min_size.width = get_theme_constant("minimum_spaces") * space_size;
+ int em_space_size = font->get_char_size('M', 0, font_size).x;
+ min_size.width = get_theme_constant("minimum_character_width") * em_space_size;
if (expand_to_text_length) {
- // Add a space because some fonts are too exact, and because cursor needs a bit more when at the end.
- min_size.width = MAX(min_size.width, full_width + space_size);
+ // Add a space because some fonts are too exact, and because caret needs a bit more when at the end.
+ min_size.width = MAX(min_size.width, full_width + em_space_size);
}
min_size.height = MAX(TS->shaped_text_get_size(text_rid).y + font->get_spacing(Font::SPACING_TOP) + font->get_spacing(Font::SPACING_BOTTOM), font->get_height(font_size));
// Take icons into account.
- bool using_placeholder = text.empty() && ime_text.empty();
+ bool using_placeholder = text.is_empty() && ime_text.is_empty();
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon("clear") : right_icon;
@@ -1584,10 +1529,10 @@ Size2 LineEdit::get_minimum_size() const {
void LineEdit::deselect() {
selection.begin = 0;
selection.end = 0;
- selection.cursor_start = 0;
+ selection.start_column = 0;
selection.enabled = false;
selection.creating = false;
- selection.doubleclick = false;
+ selection.double_click = false;
update();
}
@@ -1609,13 +1554,13 @@ int LineEdit::get_max_length() const {
return max_length;
}
-void LineEdit::selection_fill_at_cursor() {
+void LineEdit::selection_fill_at_caret() {
if (!selecting_enabled) {
return;
}
- selection.begin = cursor_pos;
- selection.end = selection.cursor_start;
+ selection.begin = caret_column;
+ selection.end = selection.start_column;
if (selection.end < selection.begin) {
int aux = selection.end;
@@ -1714,7 +1659,7 @@ void LineEdit::select(int p_from, int p_to) {
selection.begin = p_from;
selection.end = p_to;
selection.creating = false;
- selection.doubleclick = false;
+ selection.double_click = false;
update();
}
@@ -1772,82 +1717,82 @@ void LineEdit::menu_option(int p_option) {
} break;
case MENU_INSERT_LRM: {
if (editable) {
- append_at_cursor(String::chr(0x200E));
+ insert_text_at_caret(String::chr(0x200E));
}
} break;
case MENU_INSERT_RLM: {
if (editable) {
- append_at_cursor(String::chr(0x200F));
+ insert_text_at_caret(String::chr(0x200F));
}
} break;
case MENU_INSERT_LRE: {
if (editable) {
- append_at_cursor(String::chr(0x202A));
+ insert_text_at_caret(String::chr(0x202A));
}
} break;
case MENU_INSERT_RLE: {
if (editable) {
- append_at_cursor(String::chr(0x202B));
+ insert_text_at_caret(String::chr(0x202B));
}
} break;
case MENU_INSERT_LRO: {
if (editable) {
- append_at_cursor(String::chr(0x202D));
+ insert_text_at_caret(String::chr(0x202D));
}
} break;
case MENU_INSERT_RLO: {
if (editable) {
- append_at_cursor(String::chr(0x202E));
+ insert_text_at_caret(String::chr(0x202E));
}
} break;
case MENU_INSERT_PDF: {
if (editable) {
- append_at_cursor(String::chr(0x202C));
+ insert_text_at_caret(String::chr(0x202C));
}
} break;
case MENU_INSERT_ALM: {
if (editable) {
- append_at_cursor(String::chr(0x061C));
+ insert_text_at_caret(String::chr(0x061C));
}
} break;
case MENU_INSERT_LRI: {
if (editable) {
- append_at_cursor(String::chr(0x2066));
+ insert_text_at_caret(String::chr(0x2066));
}
} break;
case MENU_INSERT_RLI: {
if (editable) {
- append_at_cursor(String::chr(0x2067));
+ insert_text_at_caret(String::chr(0x2067));
}
} break;
case MENU_INSERT_FSI: {
if (editable) {
- append_at_cursor(String::chr(0x2068));
+ insert_text_at_caret(String::chr(0x2068));
}
} break;
case MENU_INSERT_PDI: {
if (editable) {
- append_at_cursor(String::chr(0x2069));
+ insert_text_at_caret(String::chr(0x2069));
}
} break;
case MENU_INSERT_ZWJ: {
if (editable) {
- append_at_cursor(String::chr(0x200D));
+ insert_text_at_caret(String::chr(0x200D));
}
} break;
case MENU_INSERT_ZWNJ: {
if (editable) {
- append_at_cursor(String::chr(0x200C));
+ insert_text_at_caret(String::chr(0x200C));
}
} break;
case MENU_INSERT_WJ: {
if (editable) {
- append_at_cursor(String::chr(0x2060));
+ insert_text_at_caret(String::chr(0x2060));
}
} break;
case MENU_INSERT_SHY: {
if (editable) {
- append_at_cursor(String::chr(0x00AD));
+ insert_text_at_caret(String::chr(0x00AD));
}
}
}
@@ -1867,18 +1812,18 @@ PopupMenu *LineEdit::get_menu() const {
void LineEdit::_editor_settings_changed() {
#ifdef TOOLS_ENABLED
- cursor_set_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false));
- cursor_set_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65));
+ set_caret_blink_enabled(EDITOR_DEF("text_editor/cursor/caret_blink", false));
+ set_caret_blink_speed(EDITOR_DEF("text_editor/cursor/caret_blink_speed", 0.65));
#endif
}
-void LineEdit::set_expand_to_text_length(bool p_enabled) {
+void LineEdit::set_expand_to_text_length_enabled(bool p_enabled) {
expand_to_text_length = p_enabled;
minimum_size_changed();
- set_cursor_position(cursor_pos);
+ set_caret_column(caret_column);
}
-bool LineEdit::get_expand_to_text_length() const {
+bool LineEdit::is_expand_to_text_length_enabled() const {
return expand_to_text_length;
}
@@ -1949,7 +1894,6 @@ void LineEdit::_text_changed() {
void LineEdit::_emit_text_change() {
emit_signal("text_changed", text);
- _change_notify("text");
text_changed_dirty = false;
}
@@ -1964,7 +1908,7 @@ void LineEdit::_shape() {
t = secret_character.repeat(text.length() + ime_text.length());
} else {
if (ime_text.length() > 0) {
- t = text.substr(0, cursor_pos) + ime_text + text.substr(cursor_pos, text.length());
+ t = text.substr(0, caret_column) + ime_text + text.substr(caret_column, text.length());
} else {
t = text;
}
@@ -1994,8 +1938,8 @@ void LineEdit::_shape() {
void LineEdit::_fit_to_width() {
if (align == ALIGN_FILL) {
Ref<StyleBox> style = get_theme_stylebox("normal");
- int t_width = get_size().width - style->get_margin(MARGIN_RIGHT) - style->get_margin(MARGIN_LEFT);
- bool using_placeholder = text.empty() && ime_text.empty();
+ int t_width = get_size().width - style->get_margin(SIDE_RIGHT) - style->get_margin(SIDE_LEFT);
+ bool using_placeholder = text.is_empty() && ime_text.is_empty();
bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled;
if (right_icon.is_valid() || display_clear_icon) {
Ref<Texture2D> r_icon = display_clear_icon ? Control::get_theme_icon("clear") : right_icon;
@@ -2029,30 +1973,55 @@ void LineEdit::_clear_undo_stack() {
void LineEdit::_create_undo_state() {
TextOperation op;
op.text = text;
- op.cursor_pos = cursor_pos;
+ op.caret_column = caret_column;
op.scroll_offset = scroll_offset;
undo_stack.push_back(op);
}
+int LineEdit::_get_menu_action_accelerator(const String &p_action) {
+ const List<Ref<InputEvent>> *events = InputMap::get_singleton()->action_get_events(p_action);
+ if (!events) {
+ return 0;
+ }
+
+ // Use first event in the list for the accelerator.
+ const List<Ref<InputEvent>>::Element *first_event = events->front();
+ if (!first_event) {
+ return 0;
+ }
+
+ const Ref<InputEventKey> event = first_event->get();
+ if (event.is_null()) {
+ return 0;
+ }
+
+ // Use physical keycode if non-zero
+ if (event->get_physical_keycode() != 0) {
+ return event->get_physical_keycode_with_modifiers();
+ } else {
+ return event->get_keycode_with_modifiers();
+ }
+}
+
void LineEdit::_generate_context_menu() {
// Reorganize context menu.
menu->clear();
if (editable) {
- menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_X : 0);
+ menu->add_item(RTR("Cut"), MENU_CUT, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_cut") : 0);
}
- menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_C : 0);
+ menu->add_item(RTR("Copy"), MENU_COPY, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_copy") : 0);
if (editable) {
- menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_V : 0);
+ menu->add_item(RTR("Paste"), MENU_PASTE, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_paste") : 0);
}
menu->add_separator();
if (is_selecting_enabled()) {
- menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_A : 0);
+ menu->add_item(RTR("Select All"), MENU_SELECT_ALL, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_text_select_all") : 0);
}
if (editable) {
menu->add_item(RTR("Clear"), MENU_CLEAR);
menu->add_separator();
- menu->add_item(RTR("Undo"), MENU_UNDO, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_Z : 0);
- menu->add_item(RTR("Redo"), MENU_REDO, is_shortcut_keys_enabled() ? KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z : 0);
+ menu->add_item(RTR("Undo"), MENU_UNDO, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_undo") : 0);
+ menu->add_item(RTR("Redo"), MENU_REDO, is_shortcut_keys_enabled() ? _get_menu_action_accelerator("ui_redo") : 0);
}
menu->add_separator();
menu->add_submenu_item(RTR("Text writing direction"), "DirMenu");
@@ -2082,7 +2051,7 @@ bool LineEdit::_set(const StringName &p_name, const Variant &p_value) {
update();
}
}
- _change_notify();
+ notify_property_list_changed();
return true;
}
@@ -2113,6 +2082,12 @@ void LineEdit::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::NIL, "opentype_features/_new", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR));
}
+void LineEdit::_validate_property(PropertyInfo &property) const {
+ if (!caret_blink_enabled && property.name == "caret_blink_speed") {
+ property.usage = PROPERTY_USAGE_NOEDITOR;
+ }
+}
+
void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("_text_changed"), &LineEdit::_text_changed);
@@ -2143,23 +2118,23 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_placeholder"), &LineEdit::get_placeholder);
ClassDB::bind_method(D_METHOD("set_placeholder_alpha", "alpha"), &LineEdit::set_placeholder_alpha);
ClassDB::bind_method(D_METHOD("get_placeholder_alpha"), &LineEdit::get_placeholder_alpha);
- ClassDB::bind_method(D_METHOD("set_cursor_position", "position"), &LineEdit::set_cursor_position);
- ClassDB::bind_method(D_METHOD("get_cursor_position"), &LineEdit::get_cursor_position);
+ ClassDB::bind_method(D_METHOD("set_caret_column", "position"), &LineEdit::set_caret_column);
+ ClassDB::bind_method(D_METHOD("get_caret_column"), &LineEdit::get_caret_column);
ClassDB::bind_method(D_METHOD("get_scroll_offset"), &LineEdit::get_scroll_offset);
- ClassDB::bind_method(D_METHOD("set_expand_to_text_length", "enabled"), &LineEdit::set_expand_to_text_length);
- 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("set_mid_grapheme_caret_enabled", "enabled"), &LineEdit::set_mid_grapheme_caret_enabled);
- ClassDB::bind_method(D_METHOD("get_mid_grapheme_caret_enabled"), &LineEdit::get_mid_grapheme_caret_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_expand_to_text_length_enabled", "enabled"), &LineEdit::set_expand_to_text_length_enabled);
+ ClassDB::bind_method(D_METHOD("is_expand_to_text_length_enabled"), &LineEdit::is_expand_to_text_length_enabled);
+ ClassDB::bind_method(D_METHOD("set_caret_blink_enabled", "enabled"), &LineEdit::set_caret_blink_enabled);
+ ClassDB::bind_method(D_METHOD("is_caret_blink_enabled"), &LineEdit::is_caret_blink_enabled);
+ ClassDB::bind_method(D_METHOD("set_caret_mid_grapheme_enabled", "enabled"), &LineEdit::set_caret_mid_grapheme_enabled);
+ ClassDB::bind_method(D_METHOD("is_caret_mid_grapheme_enabled"), &LineEdit::is_caret_mid_grapheme_enabled);
+ ClassDB::bind_method(D_METHOD("set_caret_force_displayed", "enabled"), &LineEdit::set_caret_force_displayed);
+ ClassDB::bind_method(D_METHOD("is_caret_force_displayed"), &LineEdit::is_caret_force_displayed);
+ ClassDB::bind_method(D_METHOD("set_caret_blink_speed", "blink_speed"), &LineEdit::set_caret_blink_speed);
+ ClassDB::bind_method(D_METHOD("get_caret_blink_speed"), &LineEdit::get_caret_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("insert_text_at_caret", "text"), &LineEdit::insert_text_at_caret);
+ ClassDB::bind_method(D_METHOD("delete_char_at_caret"), &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);
@@ -2227,14 +2202,14 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable"), "set_editable", "is_editable");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "secret"), "set_secret", "is_secret");
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, "expand_to_text_length"), "set_expand_to_text_length_enabled", "is_expand_to_text_length_enabled");
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");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "right_icon", PROPERTY_HINT_RESOURCE_TYPE, "Texture"), "set_right_icon", "get_right_icon");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,LTR,RTL,Inherited"), "set_text_direction", "get_text_direction");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language"), "set_language", "get_language");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_control_chars"), "set_draw_control_chars", "get_draw_control_chars");
ADD_GROUP("Structured Text", "structured_text_");
@@ -2244,20 +2219,17 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "placeholder_text"), "set_placeholder", "get_placeholder");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "placeholder_alpha", PROPERTY_HINT_RANGE, "0,1,0.001"), "set_placeholder_alpha", "get_placeholder_alpha");
ADD_GROUP("Caret", "caret_");
- 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");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_mid_grapheme_caret_enabled", "get_mid_grapheme_caret_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink"), "set_caret_blink_enabled", "is_caret_blink_enabled");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_speed", PROPERTY_HINT_RANGE, "0.1,10,0.01"), "set_caret_blink_speed", "get_caret_blink_speed");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_column"), "set_caret_column", "get_caret_column");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_force_displayed"), "set_caret_force_displayed", "is_caret_force_displayed");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme"), "set_caret_mid_grapheme_enabled", "is_caret_mid_grapheme_enabled");
}
LineEdit::LineEdit() {
text_rid = TS->create_shaped_text();
_create_undo_state();
- clear_button_status.press_attempt = false;
- clear_button_status.pressing_inside = false;
-
deselect();
set_focus_mode(FOCUS_ALL);
set_default_cursor_shape(CURSOR_IBEAM);
@@ -2267,7 +2239,7 @@ LineEdit::LineEdit() {
add_child(caret_blink_timer);
caret_blink_timer->set_wait_time(0.65);
caret_blink_timer->connect("timeout", callable_mp(this, &LineEdit::_toggle_draw_caret));
- cursor_set_blink_enabled(false);
+ set_caret_blink_enabled(false);
menu = memnew(PopupMenu);
add_child(menu);