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.cpp157
1 files changed, 85 insertions, 72 deletions
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index 11e08b231e..54e7d8f960 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -40,7 +40,6 @@
#include "servers/display_server.h"
#include "servers/text_server.h"
#ifdef TOOLS_ENABLED
-#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#endif
#include "scene/main/window.h"
@@ -67,10 +66,10 @@ void LineEdit::_move_caret_left(bool p_select, bool p_move_by_word) {
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;
+ PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = words.size() - 2; i >= 0; i = i - 2) {
+ if (words[i] < cc) {
+ cc = words[i];
break;
}
}
@@ -99,10 +98,10 @@ void LineEdit::_move_caret_right(bool p_select, bool p_move_by_word) {
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;
+ PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = 1; i < words.size(); i = i + 2) {
+ if (words[i] > cc) {
+ cc = words[i];
break;
}
}
@@ -151,10 +150,10 @@ void LineEdit::_backspace(bool p_word, bool p_all_to_left) {
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;
+ PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = words.size() - 2; i >= 0; i = i - 2) {
+ if (words[i] < cc) {
+ cc = words[i];
break;
}
}
@@ -194,10 +193,10 @@ void LineEdit::_delete(bool p_word, bool p_all_to_right) {
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;
+ PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = 1; i < words.size(); i = i + 2) {
+ if (words[i] > cc) {
+ cc = words[i];
break;
}
}
@@ -216,7 +215,7 @@ void LineEdit::_delete(bool p_word, bool p_all_to_right) {
}
}
-void LineEdit::_gui_input(Ref<InputEvent> p_event) {
+void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
Ref<InputEventMouseButton> b = p_event;
@@ -242,7 +241,7 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
_reset_caret_blink_timer();
if (b->is_pressed()) {
- accept_event(); //don't pass event further when clicked on text field
+ accept_event(); // don't pass event further when clicked on text field
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;
@@ -260,24 +259,29 @@ void LineEdit::_gui_input(Ref<InputEvent> p_event) {
} else {
if (selecting_enabled) {
- if (!b->is_double_click() && (OS::get_singleton()->get_ticks_msec() - selection.last_dblclk) < 600) {
+ const int triple_click_timeout = 600;
+ const int triple_click_tolerance = 5;
+ const bool is_triple_click = !b->is_double_click() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < triple_click_timeout && b->get_position().distance_to(last_dblclk_pos) < triple_click_tolerance;
+
+ if (is_triple_click && text.length()) {
// Triple-click select all.
selection.enabled = true;
selection.begin = 0;
selection.end = text.length();
selection.double_click = true;
- selection.last_dblclk = 0;
+ 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) {
+ last_dblclk = OS::get_singleton()->get_ticks_msec();
+ last_dblclk_pos = b->get_position();
+ PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid);
+ for (int i = 0; i < words.size(); i = i + 2) {
+ if ((words[i] < caret_column && words[i + 1] > caret_column) || (i == words.size() - 2 && caret_column == words[i + 1])) {
selection.enabled = true;
- selection.begin = words[i].x;
- selection.end = words[i].y;
+ selection.begin = words[i];
+ selection.end = words[i + 1];
selection.double_click = true;
- selection.last_dblclk = OS::get_singleton()->get_ticks_msec();
caret_column = selection.end;
break;
}
@@ -641,7 +645,7 @@ void LineEdit::_notification(int p_what) {
int x_ofs = 0;
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);
+ float text_height = TS->shaped_text_get_size(text_rid).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM);
switch (align) {
case ALIGN_FILL:
@@ -674,7 +678,7 @@ void LineEdit::_notification(int p_what) {
int y_ofs = style->get_offset().y + (y_area - text_height) / 2;
Color selection_color = get_theme_color(SNAME("selection_color"));
- Color font_color = is_editable() ? get_theme_color(SNAME("font_color")) : get_theme_color(SNAME("font_uneditable_color"));
+ Color font_color = get_theme_color(is_editable() ? SNAME("font_color") : SNAME("font_uneditable_color"));
Color font_selected_color = get_theme_color(SNAME("font_selected_color"));
Color caret_color = get_theme_color(SNAME("caret_color"));
@@ -708,11 +712,7 @@ void LineEdit::_notification(int p_what) {
ofs_max -= r_icon->get_width();
}
-#ifdef TOOLS_ENABLED
- int caret_width = Math::round(EDSCALE);
-#else
- int caret_width = 1;
-#endif
+ int caret_width = Math::round(1 * get_theme_default_base_scale());
// Draw selections rects.
Vector2 ofs = Point2(x_ofs + scroll_offset, y_ofs);
@@ -732,9 +732,8 @@ void LineEdit::_notification(int p_what) {
RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, selection_color);
}
}
- const Vector<TextServer::Glyph> visual = TS->shaped_text_get_glyphs(text_rid);
- const TextServer::Glyph *glyphs = visual.ptr();
- int gl_size = visual.size();
+ const Glyph *glyphs = TS->shaped_text_get_glyphs(text_rid);
+ int gl_size = TS->shaped_text_get_glyph_count(text_rid);
// Draw text.
ofs.y += TS->shaped_text_get_ascent(text_rid);
@@ -778,38 +777,36 @@ void LineEdit::_notification(int p_what) {
if (draw_caret) {
if (ime_text.length() == 0) {
// Normal caret.
- Rect2 l_caret, t_caret;
- TextServer::Direction l_dir, t_dir;
- TS->shaped_text_get_carets(text_rid, caret_column, l_caret, l_dir, t_caret, t_dir);
+ CaretInfo caret = TS->shaped_text_get_carets(text_rid, caret_column);
- if (l_caret == Rect2() && t_caret == Rect2()) {
+ if (caret.l_caret == Rect2() && caret.t_caret == Rect2()) {
// No carets, add one at the start.
int h = get_theme_font(SNAME("font"))->get_height(get_theme_font_size(SNAME("font_size")));
int y = style->get_offset().y + (y_area - h) / 2;
if (rtl) {
- l_dir = TextServer::DIRECTION_RTL;
- l_caret = Rect2(Vector2(ofs_max, y), Size2(caret_width, h));
+ caret.l_dir = TextServer::DIRECTION_RTL;
+ caret.l_caret = Rect2(Vector2(ofs_max, y), Size2(caret_width, h));
} else {
- l_dir = TextServer::DIRECTION_LTR;
- l_caret = Rect2(Vector2(x_ofs, y), Size2(caret_width, h));
+ caret.l_dir = TextServer::DIRECTION_LTR;
+ caret.l_caret = Rect2(Vector2(x_ofs, y), Size2(caret_width, h));
}
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, l_caret, caret_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, caret.l_caret, caret_color);
} else {
- if (l_caret != Rect2() && l_dir == TextServer::DIRECTION_AUTO) {
+ if (caret.l_caret != Rect2() && caret.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);
+ Rect2 trect = Rect2(caret.l_caret.position.x - 3 * caret_width, caret.l_caret.position.y, 6 * caret_width, caret_width);
trect.position += ofs;
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, caret_color);
+ caret.l_caret.position += ofs;
+ caret.l_caret.size.x = caret_width;
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, caret.l_caret, caret_color);
- t_caret.position += ofs;
- t_caret.size.x = caret_width;
+ caret.t_caret.position += ofs;
+ caret.t_caret.size.x = caret_width;
- RenderingServer::get_singleton()->canvas_item_add_rect(ci, t_caret, caret_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(ci, caret.t_caret, caret_color);
}
} else {
{
@@ -1109,32 +1106,31 @@ Vector2i LineEdit::get_caret_pixel_pos() {
}
Vector2i ret;
- Rect2 l_caret, t_caret;
- TextServer::Direction l_dir, t_dir;
+ CaretInfo caret;
// Get position of the start of caret.
if (ime_text.length() != 0 && ime_selection.x != 0) {
- TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x, l_caret, l_dir, t_caret, t_dir);
+ caret = TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x);
} else {
- TS->shaped_text_get_carets(text_rid, caret_column, l_caret, l_dir, t_caret, t_dir);
+ caret = TS->shaped_text_get_carets(text_rid, caret_column);
}
- if ((l_caret != Rect2() && (l_dir == TextServer::DIRECTION_AUTO || l_dir == (TextServer::Direction)input_direction)) || (t_caret == Rect2())) {
- ret.x = x_ofs + l_caret.position.x + scroll_offset;
+ if ((caret.l_caret != Rect2() && (caret.l_dir == TextServer::DIRECTION_AUTO || caret.l_dir == (TextServer::Direction)input_direction)) || (caret.t_caret == Rect2())) {
+ ret.x = x_ofs + caret.l_caret.position.x + scroll_offset;
} else {
- ret.x = x_ofs + t_caret.position.x + scroll_offset;
+ ret.x = x_ofs + caret.t_caret.position.x + scroll_offset;
}
// Get position of the end of caret.
if (ime_text.length() != 0) {
if (ime_selection.y != 0) {
- TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x + ime_selection.y, l_caret, l_dir, t_caret, t_dir);
+ caret = TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x + ime_selection.y);
} else {
- TS->shaped_text_get_carets(text_rid, caret_column + ime_text.size(), l_caret, l_dir, t_caret, t_dir);
+ caret = TS->shaped_text_get_carets(text_rid, caret_column + ime_text.size());
}
- 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;
+ if ((caret.l_caret != Rect2() && (caret.l_dir == TextServer::DIRECTION_AUTO || caret.l_dir == (TextServer::Direction)input_direction)) || (caret.t_caret == Rect2())) {
+ ret.y = x_ofs + caret.l_caret.position.x + scroll_offset;
} else {
- ret.y = x_ofs + t_caret.position.x + scroll_offset;
+ ret.y = x_ofs + caret.t_caret.position.x + scroll_offset;
}
} else {
ret.y = ret.x;
@@ -1497,7 +1493,7 @@ void LineEdit::insert_text_at_caret(String p_text) {
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, caret_column, caret_column + p_text.length());
+ TextServer::Direction dir = TS->shaped_text_get_dominant_direction_in_range(text_rid, caret_column, caret_column + p_text.length());
if (dir != TextServer::DIRECTION_AUTO) {
input_direction = (TextDirection)dir;
}
@@ -1531,7 +1527,7 @@ Size2 LineEdit::get_minimum_size() const {
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));
+ min_size.height = MAX(TS->shaped_text_get_size(text_rid).y + font->get_spacing(TextServer::SPACING_TOP) + font->get_spacing(TextServer::SPACING_BOTTOM), font->get_height(font_size));
// Take icons into account.
bool using_placeholder = text.is_empty() && ime_text.is_empty();
@@ -1555,6 +1551,20 @@ void LineEdit::deselect() {
update();
}
+bool LineEdit::has_selection() const {
+ return selection.enabled;
+}
+
+int LineEdit::get_selection_from_column() const {
+ ERR_FAIL_COND_V(!selection.enabled, -1);
+ return selection.begin;
+}
+
+int LineEdit::get_selection_to_column() const {
+ ERR_FAIL_COND_V(!selection.enabled, -1);
+ return selection.end;
+}
+
void LineEdit::selection_delete() {
if (selection.enabled) {
delete_text(selection.begin, selection.end);
@@ -1921,7 +1931,7 @@ void LineEdit::_shape() {
TS->shaped_text_clear(text_rid);
String t;
- if (text.length() == 0) {
+ if (text.length() == 0 && ime_text.length() == 0) {
t = placeholder_translated;
} else if (pass) {
t = secret_character.repeat(text.length() + ime_text.length());
@@ -1941,6 +1951,7 @@ void LineEdit::_shape() {
const Ref<Font> &font = get_theme_font(SNAME("font"));
int font_size = get_theme_font_size(SNAME("font_size"));
+ ERR_FAIL_COND(font.is_null());
TS->shaped_text_add_string(text_rid, t, font->get_rids(), font_size, opentype_features, (language != "") ? language : TranslationServer::get_singleton()->get_tool_locale());
TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, t));
@@ -2084,11 +2095,13 @@ void LineEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_align", "align"), &LineEdit::set_align);
ClassDB::bind_method(D_METHOD("get_align"), &LineEdit::get_align);
- ClassDB::bind_method(D_METHOD("_gui_input"), &LineEdit::_gui_input);
ClassDB::bind_method(D_METHOD("clear"), &LineEdit::clear);
ClassDB::bind_method(D_METHOD("select", "from", "to"), &LineEdit::select, DEFVAL(0), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("select_all"), &LineEdit::select_all);
ClassDB::bind_method(D_METHOD("deselect"), &LineEdit::deselect);
+ ClassDB::bind_method(D_METHOD("has_selection"), &LineEdit::has_selection);
+ ClassDB::bind_method(D_METHOD("get_selection_from_column"), &LineEdit::get_selection_from_column);
+ ClassDB::bind_method(D_METHOD("get_selection_to_column"), &LineEdit::get_selection_to_column);
ClassDB::bind_method(D_METHOD("set_text", "text"), &LineEdit::set_text);
ClassDB::bind_method(D_METHOD("get_text"), &LineEdit::get_text);
ClassDB::bind_method(D_METHOD("get_draw_control_chars"), &LineEdit::get_draw_control_chars);
@@ -2220,7 +2233,7 @@ void LineEdit::_bind_methods() {
void LineEdit::_ensure_menu() {
if (!menu) {
menu = memnew(PopupMenu);
- add_child(menu);
+ add_child(menu, false, INTERNAL_MODE_FRONT);
menu_dir = memnew(PopupMenu);
menu_dir->set_name("DirMenu");
@@ -2305,7 +2318,7 @@ LineEdit::LineEdit() {
set_mouse_filter(MOUSE_FILTER_STOP);
caret_blink_timer = memnew(Timer);
- add_child(caret_blink_timer);
+ add_child(caret_blink_timer, false, INTERNAL_MODE_FRONT);
caret_blink_timer->set_wait_time(0.65);
caret_blink_timer->connect("timeout", callable_mp(this, &LineEdit::_toggle_draw_caret));
set_caret_blink_enabled(false);