1 | /**************************************************************************/ |
2 | /* line_edit.cpp */ |
3 | /**************************************************************************/ |
4 | /* This file is part of: */ |
5 | /* GODOT ENGINE */ |
6 | /* https://godotengine.org */ |
7 | /**************************************************************************/ |
8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
10 | /* */ |
11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
12 | /* a copy of this software and associated documentation files (the */ |
13 | /* "Software"), to deal in the Software without restriction, including */ |
14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
17 | /* the following conditions: */ |
18 | /* */ |
19 | /* The above copyright notice and this permission notice shall be */ |
20 | /* included in all copies or substantial portions of the Software. */ |
21 | /* */ |
22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
29 | /**************************************************************************/ |
30 | |
31 | #include "line_edit.h" |
32 | |
33 | #include "core/input/input_map.h" |
34 | #include "core/object/message_queue.h" |
35 | #include "core/os/keyboard.h" |
36 | #include "core/os/os.h" |
37 | #include "core/string/print_string.h" |
38 | #include "core/string/translation.h" |
39 | #include "scene/gui/label.h" |
40 | #include "scene/main/window.h" |
41 | #include "scene/theme/theme_db.h" |
42 | #include "servers/display_server.h" |
43 | #include "servers/text_server.h" |
44 | |
45 | #ifdef TOOLS_ENABLED |
46 | #include "editor/editor_settings.h" |
47 | #endif |
48 | |
49 | void LineEdit::_swap_current_input_direction() { |
50 | if (input_direction == TEXT_DIRECTION_LTR) { |
51 | input_direction = TEXT_DIRECTION_RTL; |
52 | } else { |
53 | input_direction = TEXT_DIRECTION_LTR; |
54 | } |
55 | set_caret_column(get_caret_column()); |
56 | queue_redraw(); |
57 | } |
58 | |
59 | void LineEdit::_move_caret_left(bool p_select, bool p_move_by_word) { |
60 | if (selection.enabled && !p_select) { |
61 | set_caret_column(selection.begin); |
62 | deselect(); |
63 | return; |
64 | } |
65 | |
66 | shift_selection_check_pre(p_select); |
67 | |
68 | if (p_move_by_word) { |
69 | int cc = caret_column; |
70 | |
71 | PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid); |
72 | for (int i = words.size() - 2; i >= 0; i = i - 2) { |
73 | if (words[i] < cc) { |
74 | cc = words[i]; |
75 | break; |
76 | } |
77 | } |
78 | |
79 | set_caret_column(cc); |
80 | } else { |
81 | if (caret_mid_grapheme_enabled) { |
82 | set_caret_column(get_caret_column() - 1); |
83 | } else { |
84 | set_caret_column(TS->shaped_text_prev_character_pos(text_rid, get_caret_column())); |
85 | } |
86 | } |
87 | |
88 | shift_selection_check_post(p_select); |
89 | _reset_caret_blink_timer(); |
90 | } |
91 | |
92 | void LineEdit::_move_caret_right(bool p_select, bool p_move_by_word) { |
93 | if (selection.enabled && !p_select) { |
94 | set_caret_column(selection.end); |
95 | deselect(); |
96 | return; |
97 | } |
98 | |
99 | shift_selection_check_pre(p_select); |
100 | |
101 | if (p_move_by_word) { |
102 | int cc = caret_column; |
103 | |
104 | PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid); |
105 | for (int i = 1; i < words.size(); i = i + 2) { |
106 | if (words[i] > cc) { |
107 | cc = words[i]; |
108 | break; |
109 | } |
110 | } |
111 | |
112 | set_caret_column(cc); |
113 | } else { |
114 | if (caret_mid_grapheme_enabled) { |
115 | set_caret_column(get_caret_column() + 1); |
116 | } else { |
117 | set_caret_column(TS->shaped_text_next_character_pos(text_rid, get_caret_column())); |
118 | } |
119 | } |
120 | |
121 | shift_selection_check_post(p_select); |
122 | _reset_caret_blink_timer(); |
123 | } |
124 | |
125 | void LineEdit::_move_caret_start(bool p_select) { |
126 | shift_selection_check_pre(p_select); |
127 | set_caret_column(0); |
128 | shift_selection_check_post(p_select); |
129 | } |
130 | |
131 | void LineEdit::_move_caret_end(bool p_select) { |
132 | shift_selection_check_pre(p_select); |
133 | set_caret_column(text.length()); |
134 | shift_selection_check_post(p_select); |
135 | } |
136 | |
137 | void LineEdit::_backspace(bool p_word, bool p_all_to_left) { |
138 | if (!editable) { |
139 | return; |
140 | } |
141 | |
142 | if (p_all_to_left) { |
143 | deselect(); |
144 | text = text.substr(0, caret_column); |
145 | _text_changed(); |
146 | return; |
147 | } |
148 | |
149 | if (selection.enabled) { |
150 | selection_delete(); |
151 | return; |
152 | } |
153 | |
154 | if (p_word) { |
155 | int cc = caret_column; |
156 | |
157 | PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid); |
158 | for (int i = words.size() - 2; i >= 0; i = i - 2) { |
159 | if (words[i] < cc) { |
160 | cc = words[i]; |
161 | break; |
162 | } |
163 | } |
164 | |
165 | delete_text(cc, caret_column); |
166 | |
167 | set_caret_column(cc); |
168 | } else { |
169 | delete_char(); |
170 | } |
171 | } |
172 | |
173 | void LineEdit::_delete(bool p_word, bool p_all_to_right) { |
174 | if (!editable) { |
175 | return; |
176 | } |
177 | |
178 | if (p_all_to_right) { |
179 | deselect(); |
180 | text = text.substr(caret_column, text.length() - caret_column); |
181 | _shape(); |
182 | set_caret_column(0); |
183 | _text_changed(); |
184 | return; |
185 | } |
186 | |
187 | if (selection.enabled) { |
188 | selection_delete(); |
189 | return; |
190 | } |
191 | |
192 | int text_len = text.length(); |
193 | |
194 | if (caret_column == text_len) { |
195 | return; // Nothing to do. |
196 | } |
197 | |
198 | if (p_word) { |
199 | int cc = caret_column; |
200 | PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid); |
201 | for (int i = 1; i < words.size(); i = i + 2) { |
202 | if (words[i] > cc) { |
203 | cc = words[i]; |
204 | break; |
205 | } |
206 | } |
207 | |
208 | delete_text(caret_column, cc); |
209 | set_caret_column(caret_column); |
210 | } else { |
211 | if (caret_mid_grapheme_enabled) { |
212 | set_caret_column(caret_column + 1); |
213 | delete_char(); |
214 | } else { |
215 | int cc = caret_column; |
216 | set_caret_column(TS->shaped_text_next_character_pos(text_rid, caret_column)); |
217 | delete_text(cc, caret_column); |
218 | } |
219 | } |
220 | } |
221 | |
222 | void LineEdit::unhandled_key_input(const Ref<InputEvent> &p_event) { |
223 | Ref<InputEventKey> k = p_event; |
224 | |
225 | if (k.is_valid()) { |
226 | if (!k->is_pressed()) { |
227 | return; |
228 | } |
229 | // Handle Unicode (with modifiers active, process after shortcuts). |
230 | if (has_focus() && editable && (k->get_unicode() >= 32)) { |
231 | selection_delete(); |
232 | char32_t ucodestr[2] = { (char32_t)k->get_unicode(), 0 }; |
233 | int prev_len = text.length(); |
234 | insert_text_at_caret(ucodestr); |
235 | if (text.length() != prev_len) { |
236 | _text_changed(); |
237 | } |
238 | accept_event(); |
239 | } |
240 | } |
241 | } |
242 | |
243 | void LineEdit::gui_input(const Ref<InputEvent> &p_event) { |
244 | ERR_FAIL_COND(p_event.is_null()); |
245 | |
246 | Ref<InputEventMouseButton> b = p_event; |
247 | |
248 | if (b.is_valid()) { |
249 | if (ime_text.length() != 0) { |
250 | // Ignore mouse clicks in IME input mode. |
251 | return; |
252 | } |
253 | if (b->is_pressed() && b->get_button_index() == MouseButton::RIGHT && context_menu_enabled) { |
254 | _update_context_menu(); |
255 | menu->set_position(get_screen_position() + get_local_mouse_position()); |
256 | menu->reset_size(); |
257 | menu->popup(); |
258 | grab_focus(); |
259 | accept_event(); |
260 | return; |
261 | } |
262 | |
263 | if (is_middle_mouse_paste_enabled() && b->is_pressed() && b->get_button_index() == MouseButton::MIDDLE && is_editable() && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) { |
264 | String paste_buffer = DisplayServer::get_singleton()->clipboard_get_primary().strip_escapes(); |
265 | |
266 | deselect(); |
267 | set_caret_at_pixel_pos(b->get_position().x); |
268 | if (!paste_buffer.is_empty()) { |
269 | insert_text_at_caret(paste_buffer); |
270 | |
271 | if (!text_changed_dirty) { |
272 | if (is_inside_tree()) { |
273 | MessageQueue::get_singleton()->push_call(this, "_text_changed" ); |
274 | } |
275 | text_changed_dirty = true; |
276 | } |
277 | } |
278 | grab_focus(); |
279 | accept_event(); |
280 | return; |
281 | } |
282 | |
283 | if (b->get_button_index() != MouseButton::LEFT) { |
284 | return; |
285 | } |
286 | |
287 | _reset_caret_blink_timer(); |
288 | if (b->is_pressed()) { |
289 | accept_event(); // Don't pass event further when clicked on text field. |
290 | if (!text.is_empty() && is_editable() && _is_over_clear_button(b->get_position())) { |
291 | clear_button_status.press_attempt = true; |
292 | clear_button_status.pressing_inside = true; |
293 | queue_redraw(); |
294 | return; |
295 | } |
296 | |
297 | if (b->is_shift_pressed()) { |
298 | shift_selection_check_pre(true); |
299 | } |
300 | |
301 | set_caret_at_pixel_pos(b->get_position().x); |
302 | |
303 | if (b->is_shift_pressed()) { |
304 | selection_fill_at_caret(); |
305 | selection.creating = true; |
306 | |
307 | } else { |
308 | if (selecting_enabled) { |
309 | const int triple_click_timeout = 600; |
310 | const int triple_click_tolerance = 5; |
311 | 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; |
312 | |
313 | if (is_triple_click && text.length()) { |
314 | // Triple-click select all. |
315 | selection.enabled = true; |
316 | selection.begin = 0; |
317 | selection.end = text.length(); |
318 | selection.double_click = true; |
319 | last_dblclk = 0; |
320 | set_caret_column(selection.begin); |
321 | if (!pass && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) { |
322 | DisplayServer::get_singleton()->clipboard_set_primary(text); |
323 | } |
324 | } else if (b->is_double_click()) { |
325 | // Double-click select word. |
326 | last_dblclk = OS::get_singleton()->get_ticks_msec(); |
327 | last_dblclk_pos = b->get_position(); |
328 | PackedInt32Array words = TS->shaped_text_get_word_breaks(text_rid); |
329 | for (int i = 0; i < words.size(); i = i + 2) { |
330 | if ((words[i] < caret_column && words[i + 1] > caret_column) || (i == words.size() - 2 && caret_column == words[i + 1])) { |
331 | selection.enabled = true; |
332 | selection.begin = words[i]; |
333 | selection.end = words[i + 1]; |
334 | selection.double_click = true; |
335 | set_caret_column(selection.end); |
336 | break; |
337 | } |
338 | } |
339 | if (!pass && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) { |
340 | DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text()); |
341 | } |
342 | } |
343 | } |
344 | |
345 | selection.drag_attempt = false; |
346 | if (!selection.double_click) { |
347 | bool is_inside_sel = selection.enabled && caret_column >= selection.begin && caret_column <= selection.end; |
348 | if (drag_and_drop_selection_enabled && is_inside_sel) { |
349 | selection.drag_attempt = true; |
350 | } else { |
351 | deselect(); |
352 | selection.start_column = caret_column; |
353 | selection.creating = true; |
354 | } |
355 | } |
356 | } |
357 | |
358 | queue_redraw(); |
359 | |
360 | } else { |
361 | if (selection.enabled && !pass && b->get_button_index() == MouseButton::LEFT && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_CLIPBOARD_PRIMARY)) { |
362 | DisplayServer::get_singleton()->clipboard_set_primary(get_selected_text()); |
363 | } |
364 | if (!text.is_empty() && is_editable() && clear_button_enabled) { |
365 | bool press_attempt = clear_button_status.press_attempt; |
366 | clear_button_status.press_attempt = false; |
367 | if (press_attempt && clear_button_status.pressing_inside && _is_over_clear_button(b->get_position())) { |
368 | clear(); |
369 | return; |
370 | } |
371 | } |
372 | |
373 | if ((!selection.creating) && (!selection.double_click)) { |
374 | deselect(); |
375 | } |
376 | selection.creating = false; |
377 | selection.double_click = false; |
378 | if (!drag_action) { |
379 | selection.drag_attempt = false; |
380 | } |
381 | |
382 | if (pending_select_all_on_focus) { |
383 | select_all(); |
384 | pending_select_all_on_focus = false; |
385 | } |
386 | |
387 | show_virtual_keyboard(); |
388 | } |
389 | |
390 | queue_redraw(); |
391 | return; |
392 | } |
393 | |
394 | Ref<InputEventMouseMotion> m = p_event; |
395 | |
396 | if (m.is_valid()) { |
397 | if (!text.is_empty() && is_editable() && clear_button_enabled) { |
398 | bool last_press_inside = clear_button_status.pressing_inside; |
399 | clear_button_status.pressing_inside = clear_button_status.press_attempt && _is_over_clear_button(m->get_position()); |
400 | if (last_press_inside != clear_button_status.pressing_inside) { |
401 | queue_redraw(); |
402 | } |
403 | } |
404 | |
405 | if (m->get_button_mask().has_flag(MouseButtonMask::LEFT)) { |
406 | if (selection.creating) { |
407 | set_caret_at_pixel_pos(m->get_position().x); |
408 | selection_fill_at_caret(); |
409 | } |
410 | } |
411 | |
412 | if (drag_action && can_drop_data(m->get_position(), get_viewport()->gui_get_drag_data())) { |
413 | drag_caret_force_displayed = true; |
414 | set_caret_at_pixel_pos(m->get_position().x); |
415 | } |
416 | |
417 | return; |
418 | } |
419 | |
420 | Ref<InputEventKey> k = p_event; |
421 | |
422 | if (k.is_valid()) { |
423 | if (!k->is_pressed()) { |
424 | if (alt_start && k->get_keycode() == Key::ALT) { |
425 | alt_start = false; |
426 | if ((alt_code > 0x31 && alt_code < 0xd800) || (alt_code > 0xdfff && alt_code <= 0x10ffff)) { |
427 | char32_t ucodestr[2] = { (char32_t)alt_code, 0 }; |
428 | insert_text_at_caret(ucodestr); |
429 | } |
430 | accept_event(); |
431 | return; |
432 | } |
433 | return; |
434 | } |
435 | |
436 | // Alt + Unicode input: |
437 | if (k->is_alt_pressed()) { |
438 | if (!alt_start) { |
439 | if (k->get_keycode() == Key::KP_ADD) { |
440 | alt_start = true; |
441 | alt_code = 0; |
442 | accept_event(); |
443 | return; |
444 | } |
445 | } else { |
446 | if (k->get_keycode() >= Key::KEY_0 && k->get_keycode() <= Key::KEY_9) { |
447 | alt_code = alt_code << 4; |
448 | alt_code += (uint32_t)(k->get_keycode() - Key::KEY_0); |
449 | } |
450 | if (k->get_keycode() >= Key::KP_0 && k->get_keycode() <= Key::KP_9) { |
451 | alt_code = alt_code << 4; |
452 | alt_code += (uint32_t)(k->get_keycode() - Key::KP_0); |
453 | } |
454 | if (k->get_keycode() >= Key::A && k->get_keycode() <= Key::F) { |
455 | alt_code = alt_code << 4; |
456 | alt_code += (uint32_t)(k->get_keycode() - Key::A) + 10; |
457 | } |
458 | accept_event(); |
459 | return; |
460 | } |
461 | } |
462 | |
463 | if (context_menu_enabled) { |
464 | if (k->is_action("ui_menu" , true)) { |
465 | _update_context_menu(); |
466 | Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + theme_cache.font->get_height(theme_cache.font_size)) / 2); |
467 | menu->set_position(get_screen_position() + pos); |
468 | menu->reset_size(); |
469 | menu->popup(); |
470 | menu->grab_focus(); |
471 | |
472 | accept_event(); |
473 | return; |
474 | } |
475 | } |
476 | |
477 | // Default is ENTER and KP_ENTER. Cannot use ui_accept as default includes SPACE. |
478 | if (k->is_action("ui_text_submit" , false)) { |
479 | emit_signal(SNAME("text_submitted" ), text); |
480 | if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { |
481 | DisplayServer::get_singleton()->virtual_keyboard_hide(); |
482 | } |
483 | accept_event(); |
484 | return; |
485 | } |
486 | |
487 | if (k->is_action("ui_cancel" )) { |
488 | callable_mp((Control *)this, &Control::release_focus).call_deferred(); |
489 | return; |
490 | } |
491 | |
492 | if (is_shortcut_keys_enabled()) { |
493 | if (k->is_action("ui_copy" , true)) { |
494 | copy_text(); |
495 | accept_event(); |
496 | return; |
497 | } |
498 | |
499 | if (k->is_action("ui_text_select_all" , true)) { |
500 | select(); |
501 | accept_event(); |
502 | return; |
503 | } |
504 | |
505 | // Cut / Paste |
506 | if (k->is_action("ui_cut" , true)) { |
507 | cut_text(); |
508 | accept_event(); |
509 | return; |
510 | } |
511 | |
512 | if (k->is_action("ui_paste" , true)) { |
513 | paste_text(); |
514 | accept_event(); |
515 | return; |
516 | } |
517 | |
518 | // Undo / Redo |
519 | if (k->is_action("ui_undo" , true)) { |
520 | undo(); |
521 | accept_event(); |
522 | return; |
523 | } |
524 | |
525 | if (k->is_action("ui_redo" , true)) { |
526 | redo(); |
527 | accept_event(); |
528 | return; |
529 | } |
530 | } |
531 | |
532 | // BACKSPACE |
533 | if (k->is_action("ui_text_backspace_all_to_left" , true)) { |
534 | _backspace(false, true); |
535 | accept_event(); |
536 | return; |
537 | } |
538 | if (k->is_action("ui_text_backspace_word" , true)) { |
539 | _backspace(true); |
540 | accept_event(); |
541 | return; |
542 | } |
543 | if (k->is_action("ui_text_backspace" , true)) { |
544 | _backspace(); |
545 | accept_event(); |
546 | return; |
547 | } |
548 | |
549 | // DELETE |
550 | if (k->is_action("ui_text_delete_all_to_right" , true)) { |
551 | _delete(false, true); |
552 | accept_event(); |
553 | return; |
554 | } |
555 | if (k->is_action("ui_text_delete_word" , true)) { |
556 | _delete(true); |
557 | accept_event(); |
558 | return; |
559 | } |
560 | if (k->is_action("ui_text_delete" , true)) { |
561 | _delete(); |
562 | accept_event(); |
563 | return; |
564 | } |
565 | |
566 | // Cursor Movement |
567 | |
568 | k = k->duplicate(); |
569 | bool shift_pressed = k->is_shift_pressed(); |
570 | // Remove shift or else actions will not match. Use above variable for selection. |
571 | k->set_shift_pressed(false); |
572 | |
573 | if (k->is_action("ui_text_caret_word_left" , true)) { |
574 | _move_caret_left(shift_pressed, true); |
575 | accept_event(); |
576 | return; |
577 | } |
578 | if (k->is_action("ui_text_caret_left" , true)) { |
579 | _move_caret_left(shift_pressed); |
580 | accept_event(); |
581 | return; |
582 | } |
583 | if (k->is_action("ui_text_caret_word_right" , true)) { |
584 | _move_caret_right(shift_pressed, true); |
585 | accept_event(); |
586 | return; |
587 | } |
588 | if (k->is_action("ui_text_caret_right" , true)) { |
589 | _move_caret_right(shift_pressed, false); |
590 | accept_event(); |
591 | return; |
592 | } |
593 | |
594 | // Up = Home, Down = End |
595 | 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)) { |
596 | _move_caret_start(shift_pressed); |
597 | accept_event(); |
598 | return; |
599 | } |
600 | 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)) { |
601 | _move_caret_end(shift_pressed); |
602 | accept_event(); |
603 | return; |
604 | } |
605 | |
606 | // Misc |
607 | if (k->is_action("ui_swap_input_direction" , true)) { |
608 | _swap_current_input_direction(); |
609 | accept_event(); |
610 | return; |
611 | } |
612 | |
613 | _reset_caret_blink_timer(); |
614 | |
615 | // Allow unicode handling if: |
616 | // * No Modifiers are pressed (except shift) |
617 | bool allow_unicode_handling = !(k->is_command_or_control_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed()); |
618 | |
619 | if (allow_unicode_handling && editable && k->get_unicode() >= 32) { |
620 | // Handle Unicode if no modifiers are active. |
621 | selection_delete(); |
622 | char32_t ucodestr[2] = { (char32_t)k->get_unicode(), 0 }; |
623 | int prev_len = text.length(); |
624 | insert_text_at_caret(ucodestr); |
625 | if (text.length() != prev_len) { |
626 | _text_changed(); |
627 | } |
628 | accept_event(); |
629 | return; |
630 | } |
631 | } |
632 | } |
633 | |
634 | void LineEdit::set_horizontal_alignment(HorizontalAlignment p_alignment) { |
635 | ERR_FAIL_INDEX((int)p_alignment, 4); |
636 | if (alignment == p_alignment) { |
637 | return; |
638 | } |
639 | |
640 | alignment = p_alignment; |
641 | _shape(); |
642 | queue_redraw(); |
643 | } |
644 | |
645 | HorizontalAlignment LineEdit::get_horizontal_alignment() const { |
646 | return alignment; |
647 | } |
648 | |
649 | Variant LineEdit::get_drag_data(const Point2 &p_point) { |
650 | Variant ret = Control::get_drag_data(p_point); |
651 | if (ret != Variant()) { |
652 | return ret; |
653 | } |
654 | |
655 | if (selection.drag_attempt && selection.enabled) { |
656 | String t = get_selected_text(); |
657 | Label *l = memnew(Label); |
658 | l->set_text(t); |
659 | set_drag_preview(l); |
660 | return t; |
661 | } |
662 | |
663 | return Variant(); |
664 | } |
665 | |
666 | bool LineEdit::can_drop_data(const Point2 &p_point, const Variant &p_data) const { |
667 | bool drop_override = Control::can_drop_data(p_point, p_data); // In case user wants to drop custom data. |
668 | if (drop_override) { |
669 | return drop_override; |
670 | } |
671 | |
672 | return is_editable() && p_data.get_type() == Variant::STRING; |
673 | } |
674 | |
675 | void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) { |
676 | Control::drop_data(p_point, p_data); |
677 | |
678 | if (p_data.get_type() == Variant::STRING && is_editable()) { |
679 | set_caret_at_pixel_pos(p_point.x); |
680 | int caret_column_tmp = caret_column; |
681 | bool is_inside_sel = selection.enabled && caret_column >= selection.begin && caret_column <= selection.end; |
682 | if (Input::get_singleton()->is_key_pressed(Key::CTRL)) { |
683 | is_inside_sel = selection.enabled && caret_column > selection.begin && caret_column < selection.end; |
684 | } |
685 | if (selection.drag_attempt) { |
686 | selection.drag_attempt = false; |
687 | if (!is_inside_sel) { |
688 | if (!Input::get_singleton()->is_key_pressed(Key::CTRL)) { |
689 | if (caret_column_tmp > selection.end) { |
690 | caret_column_tmp = caret_column_tmp - (selection.end - selection.begin); |
691 | } |
692 | selection_delete(); |
693 | } |
694 | |
695 | set_caret_column(caret_column_tmp); |
696 | insert_text_at_caret(p_data); |
697 | } |
698 | } else if (selection.enabled && caret_column >= selection.begin && caret_column <= selection.end) { |
699 | caret_column_tmp = selection.begin; |
700 | selection_delete(); |
701 | set_caret_column(caret_column_tmp); |
702 | insert_text_at_caret(p_data); |
703 | grab_focus(); |
704 | } else { |
705 | insert_text_at_caret(p_data); |
706 | grab_focus(); |
707 | } |
708 | select(caret_column_tmp, caret_column); |
709 | if (!text_changed_dirty) { |
710 | if (is_inside_tree()) { |
711 | MessageQueue::get_singleton()->push_call(this, "_text_changed" ); |
712 | } |
713 | text_changed_dirty = true; |
714 | } |
715 | queue_redraw(); |
716 | } |
717 | } |
718 | |
719 | Control::CursorShape LineEdit::get_cursor_shape(const Point2 &p_pos) const { |
720 | if ((!text.is_empty() && is_editable() && _is_over_clear_button(p_pos)) || (!is_editable() && (!is_selecting_enabled() || text.is_empty()))) { |
721 | return CURSOR_ARROW; |
722 | } |
723 | return Control::get_cursor_shape(p_pos); |
724 | } |
725 | |
726 | bool LineEdit::_is_over_clear_button(const Point2 &p_pos) const { |
727 | if (!clear_button_enabled || !has_point(p_pos)) { |
728 | return false; |
729 | } |
730 | Ref<Texture2D> icon = theme_cache.clear_icon; |
731 | int x_ofs = theme_cache.normal->get_margin(SIDE_RIGHT); |
732 | return p_pos.x > get_size().width - icon->get_width() - x_ofs; |
733 | } |
734 | |
735 | void LineEdit::_update_theme_item_cache() { |
736 | Control::_update_theme_item_cache(); |
737 | |
738 | theme_cache.base_scale = get_theme_default_base_scale(); |
739 | } |
740 | |
741 | void LineEdit::_notification(int p_what) { |
742 | switch (p_what) { |
743 | #ifdef TOOLS_ENABLED |
744 | case NOTIFICATION_ENTER_TREE: { |
745 | if (Engine::get_singleton()->is_editor_hint() && !get_tree()->is_node_being_edited(this)) { |
746 | set_caret_blink_enabled(EDITOR_GET("text_editor/appearance/caret/caret_blink" )); |
747 | set_caret_blink_interval(EDITOR_GET("text_editor/appearance/caret/caret_blink_interval" )); |
748 | |
749 | if (!EditorSettings::get_singleton()->is_connected("settings_changed" , callable_mp(this, &LineEdit::_editor_settings_changed))) { |
750 | EditorSettings::get_singleton()->connect("settings_changed" , callable_mp(this, &LineEdit::_editor_settings_changed)); |
751 | } |
752 | } |
753 | } break; |
754 | #endif |
755 | |
756 | case NOTIFICATION_RESIZED: { |
757 | _fit_to_width(); |
758 | scroll_offset = 0.0; |
759 | set_caret_column(get_caret_column()); |
760 | } break; |
761 | |
762 | case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: |
763 | case NOTIFICATION_THEME_CHANGED: { |
764 | _shape(); |
765 | queue_redraw(); |
766 | } break; |
767 | |
768 | case NOTIFICATION_TRANSLATION_CHANGED: { |
769 | placeholder_translated = atr(placeholder); |
770 | _shape(); |
771 | queue_redraw(); |
772 | } break; |
773 | |
774 | case NOTIFICATION_WM_WINDOW_FOCUS_IN: { |
775 | window_has_focus = true; |
776 | _validate_caret_can_draw(); |
777 | queue_redraw(); |
778 | } break; |
779 | |
780 | case NOTIFICATION_WM_WINDOW_FOCUS_OUT: { |
781 | window_has_focus = false; |
782 | _validate_caret_can_draw(); |
783 | queue_redraw(); |
784 | } break; |
785 | |
786 | case NOTIFICATION_INTERNAL_PROCESS: { |
787 | if (caret_blink_enabled && caret_can_draw) { |
788 | caret_blink_timer += get_process_delta_time(); |
789 | |
790 | if (caret_blink_timer >= caret_blink_interval) { |
791 | caret_blink_timer = 0.0; |
792 | _toggle_draw_caret(); |
793 | } |
794 | } |
795 | } break; |
796 | |
797 | case NOTIFICATION_DRAW: { |
798 | int width, height; |
799 | bool rtl = is_layout_rtl(); |
800 | |
801 | Size2 size = get_size(); |
802 | width = size.width; |
803 | height = size.height; |
804 | |
805 | RID ci = get_canvas_item(); |
806 | |
807 | Ref<StyleBox> style = theme_cache.normal; |
808 | if (!is_editable()) { |
809 | style = theme_cache.read_only; |
810 | } |
811 | Ref<Font> font = theme_cache.font; |
812 | |
813 | if (!flat) { |
814 | style->draw(ci, Rect2(Point2(), size)); |
815 | } |
816 | |
817 | if (has_focus()) { |
818 | theme_cache.focus->draw(ci, Rect2(Point2(), size)); |
819 | } |
820 | |
821 | int x_ofs = 0; |
822 | bool using_placeholder = text.is_empty() && ime_text.is_empty(); |
823 | float text_width = TS->shaped_text_get_size(text_rid).x; |
824 | float text_height = TS->shaped_text_get_size(text_rid).y; |
825 | |
826 | switch (alignment) { |
827 | case HORIZONTAL_ALIGNMENT_FILL: |
828 | case HORIZONTAL_ALIGNMENT_LEFT: { |
829 | if (rtl) { |
830 | x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - Math::ceil(style->get_margin(SIDE_RIGHT) + (text_width)))); |
831 | } else { |
832 | x_ofs = style->get_offset().x; |
833 | } |
834 | } break; |
835 | case HORIZONTAL_ALIGNMENT_CENTER: { |
836 | if (!Math::is_zero_approx(scroll_offset)) { |
837 | x_ofs = style->get_offset().x; |
838 | } else { |
839 | x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - (text_width)) / 2); |
840 | } |
841 | } break; |
842 | case HORIZONTAL_ALIGNMENT_RIGHT: { |
843 | if (rtl) { |
844 | x_ofs = style->get_offset().x; |
845 | } else { |
846 | x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - Math::ceil(style->get_margin(SIDE_RIGHT) + (text_width)))); |
847 | } |
848 | } break; |
849 | } |
850 | |
851 | int ofs_max = width - style->get_margin(SIDE_RIGHT); |
852 | |
853 | int y_area = height - style->get_minimum_size().height; |
854 | int y_ofs = style->get_offset().y + (y_area - text_height) / 2; |
855 | |
856 | Color selection_color = theme_cache.selection_color; |
857 | Color font_color; |
858 | if (is_editable()) { |
859 | font_color = theme_cache.font_color; |
860 | } else { |
861 | font_color = theme_cache.font_uneditable_color; |
862 | } |
863 | Color font_selected_color = theme_cache.font_selected_color; |
864 | Color caret_color = theme_cache.caret_color; |
865 | |
866 | // Draw placeholder color. |
867 | if (using_placeholder) { |
868 | font_color = theme_cache.font_placeholder_color; |
869 | } |
870 | |
871 | bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; |
872 | if (right_icon.is_valid() || display_clear_icon) { |
873 | Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; |
874 | Color color_icon(1, 1, 1, !is_editable() ? .5 * .9 : .9); |
875 | if (display_clear_icon) { |
876 | if (clear_button_status.press_attempt && clear_button_status.pressing_inside) { |
877 | color_icon = theme_cache.clear_button_color_pressed; |
878 | } else { |
879 | color_icon = theme_cache.clear_button_color; |
880 | } |
881 | } |
882 | |
883 | r_icon->draw(ci, Point2(width - r_icon->get_width() - style->get_margin(SIDE_RIGHT), height / 2 - r_icon->get_height() / 2), color_icon); |
884 | |
885 | if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { |
886 | if (Math::is_zero_approx(scroll_offset)) { |
887 | x_ofs = MAX(style->get_margin(SIDE_LEFT), int(size.width - text_width - r_icon->get_width() - style->get_margin(SIDE_RIGHT) * 2) / 2); |
888 | } |
889 | } else { |
890 | x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT)); |
891 | } |
892 | |
893 | ofs_max -= r_icon->get_width(); |
894 | } |
895 | |
896 | // Draw selections rects. |
897 | Vector2 ofs = Point2(x_ofs + scroll_offset, y_ofs); |
898 | if (selection.enabled) { |
899 | Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, selection.begin, selection.end); |
900 | for (int i = 0; i < sel.size(); i++) { |
901 | Rect2 rect = Rect2(sel[i].x + ofs.x, ofs.y, sel[i].y - sel[i].x, text_height); |
902 | if (rect.position.x + rect.size.x <= x_ofs || rect.position.x > ofs_max) { |
903 | continue; |
904 | } |
905 | if (rect.position.x < x_ofs) { |
906 | rect.size.x -= (x_ofs - rect.position.x); |
907 | rect.position.x = x_ofs; |
908 | } else if (rect.position.x + rect.size.x > ofs_max) { |
909 | rect.size.x = ofs_max - rect.position.x; |
910 | } |
911 | RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, selection_color); |
912 | } |
913 | } |
914 | const Glyph *glyphs = TS->shaped_text_get_glyphs(text_rid); |
915 | int gl_size = TS->shaped_text_get_glyph_count(text_rid); |
916 | |
917 | // Draw text. |
918 | ofs.y += TS->shaped_text_get_ascent(text_rid); |
919 | Color font_outline_color = theme_cache.font_outline_color; |
920 | int outline_size = theme_cache.font_outline_size; |
921 | if (outline_size > 0 && font_outline_color.a > 0) { |
922 | Vector2 oofs = ofs; |
923 | for (int i = 0; i < gl_size; i++) { |
924 | for (int j = 0; j < glyphs[i].repeat; j++) { |
925 | if (ceil(oofs.x) >= x_ofs && (oofs.x + glyphs[i].advance) <= ofs_max) { |
926 | if (glyphs[i].font_rid != RID()) { |
927 | 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); |
928 | } |
929 | } |
930 | oofs.x += glyphs[i].advance; |
931 | } |
932 | if (oofs.x >= ofs_max) { |
933 | break; |
934 | } |
935 | } |
936 | } |
937 | for (int i = 0; i < gl_size; i++) { |
938 | bool selected = selection.enabled && glyphs[i].start >= selection.begin && glyphs[i].end <= selection.end; |
939 | for (int j = 0; j < glyphs[i].repeat; j++) { |
940 | if (ceil(ofs.x) >= x_ofs && (ofs.x + glyphs[i].advance) <= ofs_max) { |
941 | if (glyphs[i].font_rid != RID()) { |
942 | 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); |
943 | } else if (((glyphs[i].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) && ((glyphs[i].flags & TextServer::GRAPHEME_IS_EMBEDDED_OBJECT) != TextServer::GRAPHEME_IS_EMBEDDED_OBJECT)) { |
944 | 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); |
945 | } |
946 | } |
947 | ofs.x += glyphs[i].advance; |
948 | } |
949 | if (ofs.x >= ofs_max) { |
950 | break; |
951 | } |
952 | } |
953 | |
954 | // Draw carets. |
955 | ofs.x = x_ofs + scroll_offset; |
956 | if ((caret_can_draw && draw_caret) || drag_caret_force_displayed) { |
957 | // Prevent carets from disappearing at theme scales below 1.0 (if the caret width is 1). |
958 | const int caret_width = theme_cache.caret_width * MAX(1, theme_cache.base_scale); |
959 | |
960 | if (ime_text.is_empty() || ime_selection.y == 0) { |
961 | // Normal caret. |
962 | CaretInfo caret = TS->shaped_text_get_carets(text_rid, ime_text.is_empty() ? caret_column : caret_column + ime_selection.x); |
963 | if (using_placeholder || (caret.l_caret == Rect2() && caret.t_caret == Rect2())) { |
964 | // No carets, add one at the start. |
965 | int h = theme_cache.font->get_height(theme_cache.font_size); |
966 | int y = style->get_offset().y + (y_area - h) / 2; |
967 | caret.l_dir = (rtl) ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR; |
968 | switch (alignment) { |
969 | case HORIZONTAL_ALIGNMENT_FILL: |
970 | case HORIZONTAL_ALIGNMENT_LEFT: { |
971 | if (rtl) { |
972 | caret.l_caret = Rect2(Vector2(ofs_max, y), Size2(caret_width, h)); |
973 | } else { |
974 | caret.l_caret = Rect2(Vector2(style->get_offset().x, y), Size2(caret_width, h)); |
975 | } |
976 | } break; |
977 | case HORIZONTAL_ALIGNMENT_CENTER: { |
978 | caret.l_caret = Rect2(Vector2(size.x / 2, y), Size2(caret_width, h)); |
979 | } break; |
980 | case HORIZONTAL_ALIGNMENT_RIGHT: { |
981 | if (rtl) { |
982 | caret.l_caret = Rect2(Vector2(style->get_offset().x, y), Size2(caret_width, h)); |
983 | } else { |
984 | caret.l_caret = Rect2(Vector2(ofs_max, y), Size2(caret_width, h)); |
985 | } |
986 | } break; |
987 | } |
988 | |
989 | RenderingServer::get_singleton()->canvas_item_add_rect(ci, caret.l_caret, caret_color); |
990 | } else { |
991 | if (caret.l_caret != Rect2() && caret.l_dir == TextServer::DIRECTION_AUTO) { |
992 | // Draw extra marker on top of mid caret. |
993 | Rect2 trect = Rect2(caret.l_caret.position.x - 2.5 * caret_width, caret.l_caret.position.y, 6 * caret_width, caret_width); |
994 | trect.position += ofs; |
995 | RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color); |
996 | } else if (caret.l_caret != Rect2() && caret.t_caret != Rect2() && caret.l_dir != caret.t_dir) { |
997 | // Draw extra direction marker on top of split caret. |
998 | float d = (caret.l_dir == TextServer::DIRECTION_LTR) ? 0.5 : -3; |
999 | Rect2 trect = Rect2(caret.l_caret.position.x + d * caret_width, caret.l_caret.position.y + caret.l_caret.size.y - caret_width, 3 * caret_width, caret_width); |
1000 | trect.position += ofs; |
1001 | RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color); |
1002 | |
1003 | d = (caret.t_dir == TextServer::DIRECTION_LTR) ? 0.5 : -3; |
1004 | trect = Rect2(caret.t_caret.position.x + d * caret_width, caret.t_caret.position.y, 3 * caret_width, caret_width); |
1005 | trect.position += ofs; |
1006 | RenderingServer::get_singleton()->canvas_item_add_rect(ci, trect, caret_color); |
1007 | } |
1008 | |
1009 | caret.l_caret.position += ofs; |
1010 | caret.l_caret.size.x = caret_width; |
1011 | RenderingServer::get_singleton()->canvas_item_add_rect(ci, caret.l_caret, caret_color); |
1012 | |
1013 | caret.t_caret.position += ofs; |
1014 | caret.t_caret.size.x = caret_width; |
1015 | |
1016 | RenderingServer::get_singleton()->canvas_item_add_rect(ci, caret.t_caret, caret_color); |
1017 | } |
1018 | } |
1019 | if (!ime_text.is_empty()) { |
1020 | { |
1021 | // IME intermediate text range. |
1022 | Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, caret_column, caret_column + ime_text.length()); |
1023 | for (int i = 0; i < sel.size(); i++) { |
1024 | Rect2 rect = Rect2(sel[i].x + ofs.x, ofs.y, sel[i].y - sel[i].x, text_height); |
1025 | if (rect.position.x + rect.size.x <= x_ofs || rect.position.x > ofs_max) { |
1026 | continue; |
1027 | } |
1028 | if (rect.position.x < x_ofs) { |
1029 | rect.size.x -= (x_ofs - rect.position.x); |
1030 | rect.position.x = x_ofs; |
1031 | } else if (rect.position.x + rect.size.x > ofs_max) { |
1032 | rect.size.x = ofs_max - rect.position.x; |
1033 | } |
1034 | rect.size.y = caret_width; |
1035 | RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, caret_color); |
1036 | } |
1037 | } |
1038 | { |
1039 | // IME caret. |
1040 | if (ime_selection.y > 0) { |
1041 | Vector<Vector2> sel = TS->shaped_text_get_selection(text_rid, caret_column + ime_selection.x, caret_column + ime_selection.x + ime_selection.y); |
1042 | for (int i = 0; i < sel.size(); i++) { |
1043 | Rect2 rect = Rect2(sel[i].x + ofs.x, ofs.y, sel[i].y - sel[i].x, text_height); |
1044 | if (rect.position.x + rect.size.x <= x_ofs || rect.position.x > ofs_max) { |
1045 | continue; |
1046 | } |
1047 | if (rect.position.x < x_ofs) { |
1048 | rect.size.x -= (x_ofs - rect.position.x); |
1049 | rect.position.x = x_ofs; |
1050 | } else if (rect.position.x + rect.size.x > ofs_max) { |
1051 | rect.size.x = ofs_max - rect.position.x; |
1052 | } |
1053 | rect.size.y = caret_width * 3; |
1054 | RenderingServer::get_singleton()->canvas_item_add_rect(ci, rect, caret_color); |
1055 | } |
1056 | } |
1057 | } |
1058 | } |
1059 | } |
1060 | |
1061 | if (has_focus()) { |
1062 | if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) { |
1063 | DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id()); |
1064 | Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + theme_cache.font->get_height(theme_cache.font_size)) / 2) + get_global_position(); |
1065 | if (get_window()->get_embedder()) { |
1066 | pos += get_viewport()->get_popup_base_transform().get_origin(); |
1067 | } |
1068 | DisplayServer::get_singleton()->window_set_ime_position(pos, get_viewport()->get_window_id()); |
1069 | } |
1070 | } |
1071 | } break; |
1072 | |
1073 | case NOTIFICATION_FOCUS_ENTER: { |
1074 | _validate_caret_can_draw(); |
1075 | |
1076 | if (select_all_on_focus) { |
1077 | if (Input::get_singleton()->is_mouse_button_pressed(MouseButton::LEFT)) { |
1078 | // Select all when the mouse button is up. |
1079 | pending_select_all_on_focus = true; |
1080 | } else { |
1081 | select_all(); |
1082 | } |
1083 | } |
1084 | |
1085 | if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) { |
1086 | DisplayServer::get_singleton()->window_set_ime_active(true, get_viewport()->get_window_id()); |
1087 | Point2 pos = Point2(get_caret_pixel_pos().x, (get_size().y + theme_cache.font->get_height(theme_cache.font_size)) / 2) + get_global_position(); |
1088 | if (get_window()->get_embedder()) { |
1089 | pos += get_viewport()->get_popup_base_transform().get_origin(); |
1090 | } |
1091 | DisplayServer::get_singleton()->window_set_ime_position(pos, get_viewport()->get_window_id()); |
1092 | } |
1093 | |
1094 | show_virtual_keyboard(); |
1095 | } break; |
1096 | |
1097 | case NOTIFICATION_FOCUS_EXIT: { |
1098 | _validate_caret_can_draw(); |
1099 | |
1100 | if (get_viewport()->get_window_id() != DisplayServer::INVALID_WINDOW_ID && DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_IME)) { |
1101 | DisplayServer::get_singleton()->window_set_ime_position(Point2(), get_viewport()->get_window_id()); |
1102 | DisplayServer::get_singleton()->window_set_ime_active(false, get_viewport()->get_window_id()); |
1103 | } |
1104 | ime_text = "" ; |
1105 | ime_selection = Point2(); |
1106 | _shape(); |
1107 | set_caret_column(caret_column); // Update scroll_offset. |
1108 | |
1109 | if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { |
1110 | DisplayServer::get_singleton()->virtual_keyboard_hide(); |
1111 | } |
1112 | |
1113 | if (deselect_on_focus_loss_enabled && !selection.drag_attempt) { |
1114 | deselect(); |
1115 | } |
1116 | } break; |
1117 | |
1118 | case MainLoop::NOTIFICATION_OS_IME_UPDATE: { |
1119 | if (has_focus()) { |
1120 | ime_text = DisplayServer::get_singleton()->ime_get_text(); |
1121 | ime_selection = DisplayServer::get_singleton()->ime_get_selection(); |
1122 | |
1123 | if (!ime_text.is_empty()) { |
1124 | selection_delete(); |
1125 | } |
1126 | |
1127 | _shape(); |
1128 | set_caret_column(caret_column); // Update scroll_offset. |
1129 | |
1130 | queue_redraw(); |
1131 | } |
1132 | } break; |
1133 | |
1134 | case NOTIFICATION_DRAG_BEGIN: { |
1135 | drag_action = true; |
1136 | } break; |
1137 | |
1138 | case NOTIFICATION_DRAG_END: { |
1139 | if (is_drag_successful()) { |
1140 | if (selection.drag_attempt) { |
1141 | selection.drag_attempt = false; |
1142 | if (is_editable() && !Input::get_singleton()->is_key_pressed(Key::CTRL)) { |
1143 | selection_delete(); |
1144 | } else if (deselect_on_focus_loss_enabled) { |
1145 | deselect(); |
1146 | } |
1147 | } |
1148 | } else { |
1149 | selection.drag_attempt = false; |
1150 | } |
1151 | drag_action = false; |
1152 | drag_caret_force_displayed = false; |
1153 | } break; |
1154 | } |
1155 | } |
1156 | |
1157 | void LineEdit::copy_text() { |
1158 | if (selection.enabled && !pass) { |
1159 | DisplayServer::get_singleton()->clipboard_set(get_selected_text()); |
1160 | } |
1161 | } |
1162 | |
1163 | void LineEdit::cut_text() { |
1164 | if (editable && selection.enabled && !pass) { |
1165 | DisplayServer::get_singleton()->clipboard_set(get_selected_text()); |
1166 | selection_delete(); |
1167 | } |
1168 | } |
1169 | |
1170 | void LineEdit::paste_text() { |
1171 | if (!editable) { |
1172 | return; |
1173 | } |
1174 | |
1175 | // Strip escape characters like \n and \t as they can't be displayed on LineEdit. |
1176 | String paste_buffer = DisplayServer::get_singleton()->clipboard_get().strip_escapes(); |
1177 | |
1178 | if (!paste_buffer.is_empty()) { |
1179 | int prev_len = text.length(); |
1180 | if (selection.enabled) { |
1181 | selection_delete(); |
1182 | } |
1183 | insert_text_at_caret(paste_buffer); |
1184 | |
1185 | if (!text_changed_dirty) { |
1186 | if (is_inside_tree() && text.length() != prev_len) { |
1187 | MessageQueue::get_singleton()->push_call(this, "_text_changed" ); |
1188 | } |
1189 | text_changed_dirty = true; |
1190 | } |
1191 | } |
1192 | } |
1193 | |
1194 | bool LineEdit::has_undo() const { |
1195 | if (undo_stack_pos == nullptr) { |
1196 | return undo_stack.size() > 1; |
1197 | } |
1198 | return undo_stack_pos != undo_stack.front(); |
1199 | } |
1200 | |
1201 | bool LineEdit::has_redo() const { |
1202 | return undo_stack_pos != nullptr && undo_stack_pos != undo_stack.back(); |
1203 | } |
1204 | |
1205 | void LineEdit::undo() { |
1206 | if (!editable) { |
1207 | return; |
1208 | } |
1209 | |
1210 | if (undo_stack_pos == nullptr) { |
1211 | if (undo_stack.size() <= 1) { |
1212 | return; |
1213 | } |
1214 | undo_stack_pos = undo_stack.back(); |
1215 | } else if (undo_stack_pos == undo_stack.front()) { |
1216 | return; |
1217 | } |
1218 | |
1219 | deselect(); |
1220 | |
1221 | undo_stack_pos = undo_stack_pos->prev(); |
1222 | TextOperation op = undo_stack_pos->get(); |
1223 | text = op.text; |
1224 | scroll_offset = op.scroll_offset; |
1225 | set_caret_column(op.caret_column); |
1226 | |
1227 | _shape(); |
1228 | _emit_text_change(); |
1229 | } |
1230 | |
1231 | void LineEdit::redo() { |
1232 | if (!editable) { |
1233 | return; |
1234 | } |
1235 | |
1236 | if (undo_stack_pos == nullptr) { |
1237 | return; |
1238 | } |
1239 | if (undo_stack_pos == undo_stack.back()) { |
1240 | return; |
1241 | } |
1242 | |
1243 | deselect(); |
1244 | |
1245 | undo_stack_pos = undo_stack_pos->next(); |
1246 | TextOperation op = undo_stack_pos->get(); |
1247 | text = op.text; |
1248 | scroll_offset = op.scroll_offset; |
1249 | set_caret_column(op.caret_column); |
1250 | |
1251 | _shape(); |
1252 | _emit_text_change(); |
1253 | } |
1254 | |
1255 | void LineEdit::shift_selection_check_pre(bool p_shift) { |
1256 | if (!selection.enabled && p_shift) { |
1257 | selection.start_column = caret_column; |
1258 | } |
1259 | if (!p_shift) { |
1260 | deselect(); |
1261 | } |
1262 | } |
1263 | |
1264 | void LineEdit::shift_selection_check_post(bool p_shift) { |
1265 | if (p_shift) { |
1266 | selection_fill_at_caret(); |
1267 | } |
1268 | } |
1269 | |
1270 | void LineEdit::set_caret_at_pixel_pos(int p_x) { |
1271 | Ref<StyleBox> style = theme_cache.normal; |
1272 | bool rtl = is_layout_rtl(); |
1273 | |
1274 | int x_ofs = 0; |
1275 | float text_width = TS->shaped_text_get_size(text_rid).x; |
1276 | switch (alignment) { |
1277 | case HORIZONTAL_ALIGNMENT_FILL: |
1278 | case HORIZONTAL_ALIGNMENT_LEFT: { |
1279 | if (rtl) { |
1280 | x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width))); |
1281 | } else { |
1282 | x_ofs = style->get_offset().x; |
1283 | } |
1284 | } break; |
1285 | case HORIZONTAL_ALIGNMENT_CENTER: { |
1286 | if (!Math::is_zero_approx(scroll_offset)) { |
1287 | x_ofs = style->get_offset().x; |
1288 | } else { |
1289 | x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2); |
1290 | } |
1291 | } break; |
1292 | case HORIZONTAL_ALIGNMENT_RIGHT: { |
1293 | if (rtl) { |
1294 | x_ofs = style->get_offset().x; |
1295 | } else { |
1296 | x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width))); |
1297 | } |
1298 | } break; |
1299 | } |
1300 | |
1301 | bool using_placeholder = text.is_empty() && ime_text.is_empty(); |
1302 | bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; |
1303 | if (right_icon.is_valid() || display_clear_icon) { |
1304 | Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; |
1305 | if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { |
1306 | if (Math::is_zero_approx(scroll_offset)) { |
1307 | 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); |
1308 | } |
1309 | } else { |
1310 | x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT)); |
1311 | } |
1312 | } |
1313 | |
1314 | int ofs = ceil(TS->shaped_text_hit_test_position(text_rid, p_x - x_ofs - scroll_offset)); |
1315 | if (!caret_mid_grapheme_enabled) { |
1316 | ofs = TS->shaped_text_closest_character_pos(text_rid, ofs); |
1317 | } |
1318 | set_caret_column(ofs); |
1319 | } |
1320 | |
1321 | Vector2 LineEdit::get_caret_pixel_pos() { |
1322 | Ref<StyleBox> style = theme_cache.normal; |
1323 | bool rtl = is_layout_rtl(); |
1324 | |
1325 | int x_ofs = 0; |
1326 | float text_width = TS->shaped_text_get_size(text_rid).x; |
1327 | switch (alignment) { |
1328 | case HORIZONTAL_ALIGNMENT_FILL: |
1329 | case HORIZONTAL_ALIGNMENT_LEFT: { |
1330 | if (rtl) { |
1331 | x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width))); |
1332 | } else { |
1333 | x_ofs = style->get_offset().x; |
1334 | } |
1335 | } break; |
1336 | case HORIZONTAL_ALIGNMENT_CENTER: { |
1337 | if (!Math::is_zero_approx(scroll_offset)) { |
1338 | x_ofs = style->get_offset().x; |
1339 | } else { |
1340 | x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2); |
1341 | } |
1342 | } break; |
1343 | case HORIZONTAL_ALIGNMENT_RIGHT: { |
1344 | if (rtl) { |
1345 | x_ofs = style->get_offset().x; |
1346 | } else { |
1347 | x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width))); |
1348 | } |
1349 | } break; |
1350 | } |
1351 | |
1352 | bool using_placeholder = text.is_empty() && ime_text.is_empty(); |
1353 | bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; |
1354 | if (right_icon.is_valid() || display_clear_icon) { |
1355 | Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; |
1356 | if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { |
1357 | if (Math::is_zero_approx(scroll_offset)) { |
1358 | 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); |
1359 | } |
1360 | } else { |
1361 | x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT)); |
1362 | } |
1363 | } |
1364 | |
1365 | Vector2 ret; |
1366 | CaretInfo caret; |
1367 | // Get position of the start of caret. |
1368 | if (ime_text.length() != 0 && ime_selection.x != 0) { |
1369 | caret = TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x); |
1370 | } else { |
1371 | caret = TS->shaped_text_get_carets(text_rid, caret_column); |
1372 | } |
1373 | |
1374 | if ((caret.l_caret != Rect2() && (caret.l_dir == TextServer::DIRECTION_AUTO || caret.l_dir == (TextServer::Direction)input_direction)) || (caret.t_caret == Rect2())) { |
1375 | ret.x = x_ofs + caret.l_caret.position.x + scroll_offset; |
1376 | } else { |
1377 | ret.x = x_ofs + caret.t_caret.position.x + scroll_offset; |
1378 | } |
1379 | |
1380 | // Get position of the end of caret. |
1381 | if (ime_text.length() != 0) { |
1382 | if (ime_selection.y != 0) { |
1383 | caret = TS->shaped_text_get_carets(text_rid, caret_column + ime_selection.x + ime_selection.y); |
1384 | } else { |
1385 | caret = TS->shaped_text_get_carets(text_rid, caret_column + ime_text.size()); |
1386 | } |
1387 | if ((caret.l_caret != Rect2() && (caret.l_dir == TextServer::DIRECTION_AUTO || caret.l_dir == (TextServer::Direction)input_direction)) || (caret.t_caret == Rect2())) { |
1388 | ret.y = x_ofs + caret.l_caret.position.x + scroll_offset; |
1389 | } else { |
1390 | ret.y = x_ofs + caret.t_caret.position.x + scroll_offset; |
1391 | } |
1392 | } else { |
1393 | ret.y = ret.x; |
1394 | } |
1395 | |
1396 | return ret; |
1397 | } |
1398 | |
1399 | void LineEdit::set_caret_mid_grapheme_enabled(const bool p_enabled) { |
1400 | caret_mid_grapheme_enabled = p_enabled; |
1401 | } |
1402 | |
1403 | bool LineEdit::is_caret_mid_grapheme_enabled() const { |
1404 | return caret_mid_grapheme_enabled; |
1405 | } |
1406 | |
1407 | bool LineEdit::is_caret_blink_enabled() const { |
1408 | return caret_blink_enabled; |
1409 | } |
1410 | |
1411 | void LineEdit::set_caret_blink_enabled(const bool p_enabled) { |
1412 | if (caret_blink_enabled == p_enabled) { |
1413 | return; |
1414 | } |
1415 | |
1416 | caret_blink_enabled = p_enabled; |
1417 | set_process_internal(p_enabled); |
1418 | |
1419 | draw_caret = !caret_blink_enabled; |
1420 | if (caret_blink_enabled) { |
1421 | caret_blink_timer = 0.0; |
1422 | } |
1423 | queue_redraw(); |
1424 | |
1425 | notify_property_list_changed(); |
1426 | } |
1427 | |
1428 | bool LineEdit::is_caret_force_displayed() const { |
1429 | return caret_force_displayed; |
1430 | } |
1431 | |
1432 | void LineEdit::set_caret_force_displayed(const bool p_enabled) { |
1433 | if (caret_force_displayed == p_enabled) { |
1434 | return; |
1435 | } |
1436 | |
1437 | caret_force_displayed = p_enabled; |
1438 | _validate_caret_can_draw(); |
1439 | |
1440 | queue_redraw(); |
1441 | } |
1442 | |
1443 | float LineEdit::get_caret_blink_interval() const { |
1444 | return caret_blink_interval; |
1445 | } |
1446 | |
1447 | void LineEdit::set_caret_blink_interval(const float p_interval) { |
1448 | ERR_FAIL_COND(p_interval <= 0); |
1449 | caret_blink_interval = p_interval; |
1450 | } |
1451 | |
1452 | void LineEdit::_reset_caret_blink_timer() { |
1453 | if (caret_blink_enabled) { |
1454 | draw_caret = true; |
1455 | if (caret_can_draw) { |
1456 | caret_blink_timer = 0.0; |
1457 | queue_redraw(); |
1458 | } |
1459 | } |
1460 | } |
1461 | |
1462 | void LineEdit::_toggle_draw_caret() { |
1463 | draw_caret = !draw_caret; |
1464 | if (is_visible_in_tree() && caret_can_draw) { |
1465 | queue_redraw(); |
1466 | } |
1467 | } |
1468 | |
1469 | void LineEdit::_validate_caret_can_draw() { |
1470 | if (caret_blink_enabled) { |
1471 | draw_caret = true; |
1472 | caret_blink_timer = 0.0; |
1473 | } |
1474 | caret_can_draw = editable && (window_has_focus || (menu && menu->has_focus())) && (has_focus() || caret_force_displayed); |
1475 | } |
1476 | |
1477 | void LineEdit::delete_char() { |
1478 | if ((text.length() <= 0) || (caret_column == 0)) { |
1479 | return; |
1480 | } |
1481 | |
1482 | text = text.left(caret_column - 1) + text.substr(caret_column); |
1483 | _shape(); |
1484 | |
1485 | set_caret_column(get_caret_column() - 1); |
1486 | |
1487 | _text_changed(); |
1488 | } |
1489 | |
1490 | void LineEdit::delete_text(int p_from_column, int p_to_column) { |
1491 | ERR_FAIL_COND_MSG(p_from_column < 0 || p_from_column > p_to_column || p_to_column > text.length(), |
1492 | vformat("Positional parameters (from: %d, to: %d) are inverted or outside the text length (%d)." , p_from_column, p_to_column, text.length())); |
1493 | |
1494 | text = text.left(p_from_column) + text.substr(p_to_column); |
1495 | _shape(); |
1496 | |
1497 | set_caret_column(caret_column - CLAMP(caret_column - p_from_column, 0, p_to_column - p_from_column)); |
1498 | |
1499 | if (!text_changed_dirty) { |
1500 | if (is_inside_tree()) { |
1501 | MessageQueue::get_singleton()->push_call(this, "_text_changed" ); |
1502 | } |
1503 | text_changed_dirty = true; |
1504 | } |
1505 | } |
1506 | |
1507 | void LineEdit::set_text(String p_text) { |
1508 | clear_internal(); |
1509 | insert_text_at_caret(p_text); |
1510 | _create_undo_state(); |
1511 | |
1512 | queue_redraw(); |
1513 | caret_column = 0; |
1514 | scroll_offset = 0.0; |
1515 | } |
1516 | |
1517 | void LineEdit::set_text_with_selection(const String &p_text) { |
1518 | Selection selection_copy = selection; |
1519 | |
1520 | clear_internal(); |
1521 | insert_text_at_caret(p_text); |
1522 | _create_undo_state(); |
1523 | |
1524 | int tlen = text.length(); |
1525 | selection = selection_copy; |
1526 | selection.begin = MIN(selection.begin, tlen); |
1527 | selection.end = MIN(selection.end, tlen); |
1528 | selection.start_column = MIN(selection.start_column, tlen); |
1529 | |
1530 | queue_redraw(); |
1531 | } |
1532 | |
1533 | void LineEdit::set_text_direction(Control::TextDirection p_text_direction) { |
1534 | ERR_FAIL_COND((int)p_text_direction < -1 || (int)p_text_direction > 3); |
1535 | if (text_direction != p_text_direction) { |
1536 | text_direction = p_text_direction; |
1537 | if (text_direction != TEXT_DIRECTION_AUTO && text_direction != TEXT_DIRECTION_INHERITED) { |
1538 | input_direction = text_direction; |
1539 | } |
1540 | _shape(); |
1541 | |
1542 | if (menu_dir) { |
1543 | menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_INHERITED), text_direction == TEXT_DIRECTION_INHERITED); |
1544 | menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_AUTO), text_direction == TEXT_DIRECTION_AUTO); |
1545 | menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_LTR), text_direction == TEXT_DIRECTION_LTR); |
1546 | menu_dir->set_item_checked(menu_dir->get_item_index(MENU_DIR_RTL), text_direction == TEXT_DIRECTION_RTL); |
1547 | } |
1548 | queue_redraw(); |
1549 | } |
1550 | } |
1551 | |
1552 | Control::TextDirection LineEdit::get_text_direction() const { |
1553 | return text_direction; |
1554 | } |
1555 | |
1556 | void LineEdit::set_language(const String &p_language) { |
1557 | if (language != p_language) { |
1558 | language = p_language; |
1559 | _shape(); |
1560 | queue_redraw(); |
1561 | } |
1562 | } |
1563 | |
1564 | String LineEdit::get_language() const { |
1565 | return language; |
1566 | } |
1567 | |
1568 | void LineEdit::set_draw_control_chars(bool p_draw_control_chars) { |
1569 | if (draw_control_chars != p_draw_control_chars) { |
1570 | draw_control_chars = p_draw_control_chars; |
1571 | if (menu && menu->get_item_index(MENU_DISPLAY_UCC) >= 0) { |
1572 | menu->set_item_checked(menu->get_item_index(MENU_DISPLAY_UCC), draw_control_chars); |
1573 | } |
1574 | _shape(); |
1575 | queue_redraw(); |
1576 | } |
1577 | } |
1578 | |
1579 | bool LineEdit::get_draw_control_chars() const { |
1580 | return draw_control_chars; |
1581 | } |
1582 | |
1583 | void LineEdit::set_structured_text_bidi_override(TextServer::StructuredTextParser p_parser) { |
1584 | if (st_parser != p_parser) { |
1585 | st_parser = p_parser; |
1586 | _shape(); |
1587 | queue_redraw(); |
1588 | } |
1589 | } |
1590 | |
1591 | TextServer::StructuredTextParser LineEdit::get_structured_text_bidi_override() const { |
1592 | return st_parser; |
1593 | } |
1594 | |
1595 | void LineEdit::set_structured_text_bidi_override_options(Array p_args) { |
1596 | st_args = p_args; |
1597 | _shape(); |
1598 | queue_redraw(); |
1599 | } |
1600 | |
1601 | Array LineEdit::get_structured_text_bidi_override_options() const { |
1602 | return st_args; |
1603 | } |
1604 | |
1605 | void LineEdit::clear() { |
1606 | clear_internal(); |
1607 | _text_changed(); |
1608 | |
1609 | // This should reset virtual keyboard state if needed. |
1610 | if (has_focus()) { |
1611 | show_virtual_keyboard(); |
1612 | } |
1613 | } |
1614 | |
1615 | void LineEdit::show_virtual_keyboard() { |
1616 | if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_VIRTUAL_KEYBOARD) && virtual_keyboard_enabled) { |
1617 | if (selection.enabled) { |
1618 | DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), DisplayServer::VirtualKeyboardType(virtual_keyboard_type), max_length, selection.begin, selection.end); |
1619 | } else { |
1620 | DisplayServer::get_singleton()->virtual_keyboard_show(text, get_global_rect(), DisplayServer::VirtualKeyboardType(virtual_keyboard_type), max_length, caret_column); |
1621 | } |
1622 | } |
1623 | } |
1624 | |
1625 | String LineEdit::get_text() const { |
1626 | return text; |
1627 | } |
1628 | |
1629 | void LineEdit::set_placeholder(String p_text) { |
1630 | if (placeholder == p_text) { |
1631 | return; |
1632 | } |
1633 | |
1634 | placeholder = p_text; |
1635 | placeholder_translated = atr(placeholder); |
1636 | _shape(); |
1637 | queue_redraw(); |
1638 | } |
1639 | |
1640 | String LineEdit::get_placeholder() const { |
1641 | return placeholder; |
1642 | } |
1643 | |
1644 | void LineEdit::set_caret_column(int p_column) { |
1645 | if (p_column > (int)text.length()) { |
1646 | p_column = text.length(); |
1647 | } |
1648 | |
1649 | if (p_column < 0) { |
1650 | p_column = 0; |
1651 | } |
1652 | |
1653 | caret_column = p_column; |
1654 | |
1655 | // Fit to window. |
1656 | |
1657 | if (!is_inside_tree()) { |
1658 | scroll_offset = 0.0; |
1659 | return; |
1660 | } |
1661 | |
1662 | Ref<StyleBox> style = theme_cache.normal; |
1663 | bool rtl = is_layout_rtl(); |
1664 | |
1665 | int x_ofs = 0; |
1666 | float text_width = TS->shaped_text_get_size(text_rid).x; |
1667 | switch (alignment) { |
1668 | case HORIZONTAL_ALIGNMENT_FILL: |
1669 | case HORIZONTAL_ALIGNMENT_LEFT: { |
1670 | if (rtl) { |
1671 | x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width))); |
1672 | } else { |
1673 | x_ofs = style->get_offset().x; |
1674 | } |
1675 | } break; |
1676 | case HORIZONTAL_ALIGNMENT_CENTER: { |
1677 | if (!Math::is_zero_approx(scroll_offset)) { |
1678 | x_ofs = style->get_offset().x; |
1679 | } else { |
1680 | x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - (text_width)) / 2); |
1681 | } |
1682 | } break; |
1683 | case HORIZONTAL_ALIGNMENT_RIGHT: { |
1684 | if (rtl) { |
1685 | x_ofs = style->get_offset().x; |
1686 | } else { |
1687 | x_ofs = MAX(style->get_margin(SIDE_LEFT), int(get_size().width - style->get_margin(SIDE_RIGHT) - (text_width))); |
1688 | } |
1689 | } break; |
1690 | } |
1691 | |
1692 | int ofs_max = get_size().width - style->get_margin(SIDE_RIGHT); |
1693 | bool using_placeholder = text.is_empty() && ime_text.is_empty(); |
1694 | bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; |
1695 | if (right_icon.is_valid() || display_clear_icon) { |
1696 | Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; |
1697 | if (alignment == HORIZONTAL_ALIGNMENT_CENTER) { |
1698 | if (Math::is_zero_approx(scroll_offset)) { |
1699 | 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); |
1700 | } |
1701 | } else { |
1702 | x_ofs = MAX(style->get_margin(SIDE_LEFT), x_ofs - r_icon->get_width() - style->get_margin(SIDE_RIGHT)); |
1703 | } |
1704 | ofs_max -= r_icon->get_width(); |
1705 | } |
1706 | |
1707 | // Note: Use two coordinates to fit IME input range. |
1708 | Vector2 primary_caret_offset = get_caret_pixel_pos(); |
1709 | |
1710 | if (MIN(primary_caret_offset.x, primary_caret_offset.y) <= x_ofs) { |
1711 | scroll_offset += x_ofs - MIN(primary_caret_offset.x, primary_caret_offset.y); |
1712 | } else if (MAX(primary_caret_offset.x, primary_caret_offset.y) >= ofs_max) { |
1713 | scroll_offset += ofs_max - MAX(primary_caret_offset.x, primary_caret_offset.y); |
1714 | } |
1715 | scroll_offset = MIN(0, scroll_offset); |
1716 | |
1717 | queue_redraw(); |
1718 | } |
1719 | |
1720 | int LineEdit::get_caret_column() const { |
1721 | return caret_column; |
1722 | } |
1723 | |
1724 | void LineEdit::set_scroll_offset(float p_pos) { |
1725 | scroll_offset = p_pos; |
1726 | if (scroll_offset < 0.0) { |
1727 | scroll_offset = 0.0; |
1728 | } |
1729 | } |
1730 | |
1731 | float LineEdit::get_scroll_offset() const { |
1732 | return scroll_offset; |
1733 | } |
1734 | |
1735 | void LineEdit::insert_text_at_caret(String p_text) { |
1736 | if (max_length > 0) { |
1737 | // Truncate text to append to fit in max_length, if needed. |
1738 | int available_chars = max_length - text.length(); |
1739 | if (p_text.length() > available_chars) { |
1740 | emit_signal(SNAME("text_change_rejected" ), p_text.substr(available_chars)); |
1741 | p_text = p_text.substr(0, available_chars); |
1742 | } |
1743 | } |
1744 | String pre = text.substr(0, caret_column); |
1745 | String post = text.substr(caret_column, text.length() - caret_column); |
1746 | text = pre + p_text + post; |
1747 | _shape(); |
1748 | TextServer::Direction dir = TS->shaped_text_get_dominant_direction_in_range(text_rid, caret_column, caret_column + p_text.length()); |
1749 | if (dir != TextServer::DIRECTION_AUTO) { |
1750 | input_direction = (TextDirection)dir; |
1751 | } |
1752 | set_caret_column(caret_column + p_text.length()); |
1753 | |
1754 | if (!ime_text.is_empty()) { |
1755 | _shape(); |
1756 | } |
1757 | } |
1758 | |
1759 | void LineEdit::clear_internal() { |
1760 | deselect(); |
1761 | _clear_undo_stack(); |
1762 | caret_column = 0; |
1763 | scroll_offset = 0.0; |
1764 | undo_text = "" ; |
1765 | text = "" ; |
1766 | _shape(); |
1767 | queue_redraw(); |
1768 | } |
1769 | |
1770 | Size2 LineEdit::get_minimum_size() const { |
1771 | Ref<StyleBox> style = theme_cache.normal; |
1772 | Ref<Font> font = theme_cache.font; |
1773 | int font_size = theme_cache.font_size; |
1774 | |
1775 | Size2 min_size; |
1776 | |
1777 | // Minimum size of text. |
1778 | float em_space_size = font->get_char_size('M', font_size).x; |
1779 | min_size.width = theme_cache.minimum_character_width * em_space_size; |
1780 | |
1781 | if (expand_to_text_length) { |
1782 | // Ensure some space for the caret when placed at the end. |
1783 | min_size.width = MAX(min_size.width, full_width + theme_cache.caret_width); |
1784 | } |
1785 | |
1786 | min_size.height = MAX(TS->shaped_text_get_size(text_rid).y, font->get_height(font_size)); |
1787 | |
1788 | // Take icons into account. |
1789 | int icon_max_width = 0; |
1790 | if (right_icon.is_valid()) { |
1791 | min_size.height = MAX(min_size.height, right_icon->get_height()); |
1792 | icon_max_width = right_icon->get_width(); |
1793 | } |
1794 | if (clear_button_enabled) { |
1795 | min_size.height = MAX(min_size.height, theme_cache.clear_icon->get_height()); |
1796 | icon_max_width = MAX(icon_max_width, theme_cache.clear_icon->get_width()); |
1797 | } |
1798 | min_size.width += icon_max_width; |
1799 | |
1800 | return style->get_minimum_size() + min_size; |
1801 | } |
1802 | |
1803 | void LineEdit::deselect() { |
1804 | selection.begin = 0; |
1805 | selection.end = 0; |
1806 | selection.start_column = 0; |
1807 | selection.enabled = false; |
1808 | selection.creating = false; |
1809 | selection.double_click = false; |
1810 | queue_redraw(); |
1811 | } |
1812 | |
1813 | bool LineEdit::has_selection() const { |
1814 | return selection.enabled; |
1815 | } |
1816 | |
1817 | String LineEdit::get_selected_text() { |
1818 | if (selection.enabled) { |
1819 | return text.substr(selection.begin, selection.end - selection.begin); |
1820 | } else { |
1821 | return String(); |
1822 | } |
1823 | } |
1824 | |
1825 | int LineEdit::get_selection_from_column() const { |
1826 | ERR_FAIL_COND_V(!selection.enabled, -1); |
1827 | return selection.begin; |
1828 | } |
1829 | |
1830 | int LineEdit::get_selection_to_column() const { |
1831 | ERR_FAIL_COND_V(!selection.enabled, -1); |
1832 | return selection.end; |
1833 | } |
1834 | |
1835 | void LineEdit::selection_delete() { |
1836 | if (selection.enabled) { |
1837 | delete_text(selection.begin, selection.end); |
1838 | } |
1839 | |
1840 | deselect(); |
1841 | } |
1842 | |
1843 | void LineEdit::set_max_length(int p_max_length) { |
1844 | ERR_FAIL_COND(p_max_length < 0); |
1845 | max_length = p_max_length; |
1846 | set_text(text); |
1847 | } |
1848 | |
1849 | int LineEdit::get_max_length() const { |
1850 | return max_length; |
1851 | } |
1852 | |
1853 | void LineEdit::selection_fill_at_caret() { |
1854 | if (!selecting_enabled) { |
1855 | return; |
1856 | } |
1857 | |
1858 | selection.begin = caret_column; |
1859 | selection.end = selection.start_column; |
1860 | |
1861 | if (selection.end < selection.begin) { |
1862 | int aux = selection.end; |
1863 | selection.end = selection.begin; |
1864 | selection.begin = aux; |
1865 | } |
1866 | |
1867 | selection.enabled = (selection.begin != selection.end); |
1868 | } |
1869 | |
1870 | void LineEdit::select_all() { |
1871 | if (!selecting_enabled) { |
1872 | return; |
1873 | } |
1874 | |
1875 | if (!text.length()) { |
1876 | return; |
1877 | } |
1878 | |
1879 | selection.begin = 0; |
1880 | selection.end = text.length(); |
1881 | selection.enabled = true; |
1882 | queue_redraw(); |
1883 | } |
1884 | |
1885 | void LineEdit::set_editable(bool p_editable) { |
1886 | if (editable == p_editable) { |
1887 | return; |
1888 | } |
1889 | |
1890 | editable = p_editable; |
1891 | _validate_caret_can_draw(); |
1892 | |
1893 | update_minimum_size(); |
1894 | queue_redraw(); |
1895 | } |
1896 | |
1897 | bool LineEdit::is_editable() const { |
1898 | return editable; |
1899 | } |
1900 | |
1901 | void LineEdit::set_secret(bool p_secret) { |
1902 | if (pass == p_secret) { |
1903 | return; |
1904 | } |
1905 | |
1906 | pass = p_secret; |
1907 | _shape(); |
1908 | queue_redraw(); |
1909 | } |
1910 | |
1911 | bool LineEdit::is_secret() const { |
1912 | return pass; |
1913 | } |
1914 | |
1915 | void LineEdit::set_secret_character(const String &p_string) { |
1916 | // An empty string as the secret character would crash the engine. |
1917 | // It also wouldn't make sense to use multiple characters as the secret character. |
1918 | ERR_FAIL_COND_MSG(p_string.length() != 1, "Secret character must be exactly one character long (" + itos(p_string.length()) + " characters given)." ); |
1919 | |
1920 | if (secret_character == p_string) { |
1921 | return; |
1922 | } |
1923 | |
1924 | secret_character = p_string; |
1925 | _shape(); |
1926 | queue_redraw(); |
1927 | } |
1928 | |
1929 | String LineEdit::get_secret_character() const { |
1930 | return secret_character; |
1931 | } |
1932 | |
1933 | void LineEdit::select(int p_from, int p_to) { |
1934 | if (!selecting_enabled) { |
1935 | return; |
1936 | } |
1937 | |
1938 | if (p_from == 0 && p_to == 0) { |
1939 | deselect(); |
1940 | return; |
1941 | } |
1942 | |
1943 | int len = text.length(); |
1944 | if (p_from < 0) { |
1945 | p_from = 0; |
1946 | } |
1947 | if (p_from > len) { |
1948 | p_from = len; |
1949 | } |
1950 | if (p_to < 0 || p_to > len) { |
1951 | p_to = len; |
1952 | } |
1953 | |
1954 | if (p_from >= p_to) { |
1955 | return; |
1956 | } |
1957 | |
1958 | selection.enabled = true; |
1959 | selection.begin = p_from; |
1960 | selection.end = p_to; |
1961 | selection.creating = false; |
1962 | selection.double_click = false; |
1963 | queue_redraw(); |
1964 | } |
1965 | |
1966 | bool LineEdit::is_text_field() const { |
1967 | return true; |
1968 | } |
1969 | |
1970 | void LineEdit::(int p_option) { |
1971 | switch (p_option) { |
1972 | case MENU_CUT: { |
1973 | if (editable) { |
1974 | cut_text(); |
1975 | } |
1976 | } break; |
1977 | case MENU_COPY: { |
1978 | copy_text(); |
1979 | } break; |
1980 | case MENU_PASTE: { |
1981 | if (editable) { |
1982 | paste_text(); |
1983 | } |
1984 | } break; |
1985 | case MENU_CLEAR: { |
1986 | if (editable) { |
1987 | clear(); |
1988 | } |
1989 | } break; |
1990 | case MENU_SELECT_ALL: { |
1991 | select_all(); |
1992 | } break; |
1993 | case MENU_UNDO: { |
1994 | if (editable) { |
1995 | undo(); |
1996 | } |
1997 | } break; |
1998 | case MENU_REDO: { |
1999 | if (editable) { |
2000 | redo(); |
2001 | } |
2002 | } break; |
2003 | case MENU_DIR_INHERITED: { |
2004 | set_text_direction(TEXT_DIRECTION_INHERITED); |
2005 | } break; |
2006 | case MENU_DIR_AUTO: { |
2007 | set_text_direction(TEXT_DIRECTION_AUTO); |
2008 | } break; |
2009 | case MENU_DIR_LTR: { |
2010 | set_text_direction(TEXT_DIRECTION_LTR); |
2011 | } break; |
2012 | case MENU_DIR_RTL: { |
2013 | set_text_direction(TEXT_DIRECTION_RTL); |
2014 | } break; |
2015 | case MENU_DISPLAY_UCC: { |
2016 | set_draw_control_chars(!get_draw_control_chars()); |
2017 | } break; |
2018 | case MENU_INSERT_LRM: { |
2019 | if (editable) { |
2020 | insert_text_at_caret(String::chr(0x200E)); |
2021 | } |
2022 | } break; |
2023 | case MENU_INSERT_RLM: { |
2024 | if (editable) { |
2025 | insert_text_at_caret(String::chr(0x200F)); |
2026 | } |
2027 | } break; |
2028 | case MENU_INSERT_LRE: { |
2029 | if (editable) { |
2030 | insert_text_at_caret(String::chr(0x202A)); |
2031 | } |
2032 | } break; |
2033 | case MENU_INSERT_RLE: { |
2034 | if (editable) { |
2035 | insert_text_at_caret(String::chr(0x202B)); |
2036 | } |
2037 | } break; |
2038 | case MENU_INSERT_LRO: { |
2039 | if (editable) { |
2040 | insert_text_at_caret(String::chr(0x202D)); |
2041 | } |
2042 | } break; |
2043 | case MENU_INSERT_RLO: { |
2044 | if (editable) { |
2045 | insert_text_at_caret(String::chr(0x202E)); |
2046 | } |
2047 | } break; |
2048 | case MENU_INSERT_PDF: { |
2049 | if (editable) { |
2050 | insert_text_at_caret(String::chr(0x202C)); |
2051 | } |
2052 | } break; |
2053 | case MENU_INSERT_ALM: { |
2054 | if (editable) { |
2055 | insert_text_at_caret(String::chr(0x061C)); |
2056 | } |
2057 | } break; |
2058 | case MENU_INSERT_LRI: { |
2059 | if (editable) { |
2060 | insert_text_at_caret(String::chr(0x2066)); |
2061 | } |
2062 | } break; |
2063 | case MENU_INSERT_RLI: { |
2064 | if (editable) { |
2065 | insert_text_at_caret(String::chr(0x2067)); |
2066 | } |
2067 | } break; |
2068 | case MENU_INSERT_FSI: { |
2069 | if (editable) { |
2070 | insert_text_at_caret(String::chr(0x2068)); |
2071 | } |
2072 | } break; |
2073 | case MENU_INSERT_PDI: { |
2074 | if (editable) { |
2075 | insert_text_at_caret(String::chr(0x2069)); |
2076 | } |
2077 | } break; |
2078 | case MENU_INSERT_ZWJ: { |
2079 | if (editable) { |
2080 | insert_text_at_caret(String::chr(0x200D)); |
2081 | } |
2082 | } break; |
2083 | case MENU_INSERT_ZWNJ: { |
2084 | if (editable) { |
2085 | insert_text_at_caret(String::chr(0x200C)); |
2086 | } |
2087 | } break; |
2088 | case MENU_INSERT_WJ: { |
2089 | if (editable) { |
2090 | insert_text_at_caret(String::chr(0x2060)); |
2091 | } |
2092 | } break; |
2093 | case MENU_INSERT_SHY: { |
2094 | if (editable) { |
2095 | insert_text_at_caret(String::chr(0x00AD)); |
2096 | } |
2097 | } |
2098 | } |
2099 | } |
2100 | |
2101 | void LineEdit::(bool p_enable) { |
2102 | context_menu_enabled = p_enable; |
2103 | } |
2104 | |
2105 | bool LineEdit::() { |
2106 | return context_menu_enabled; |
2107 | } |
2108 | |
2109 | bool LineEdit::() const { |
2110 | return menu && menu->is_visible(); |
2111 | } |
2112 | |
2113 | PopupMenu *LineEdit::() const { |
2114 | if (!menu) { |
2115 | const_cast<LineEdit *>(this)->_generate_context_menu(); |
2116 | } |
2117 | return menu; |
2118 | } |
2119 | |
2120 | void LineEdit::_editor_settings_changed() { |
2121 | #ifdef TOOLS_ENABLED |
2122 | set_caret_blink_enabled(EDITOR_GET("text_editor/appearance/caret/caret_blink" )); |
2123 | set_caret_blink_interval(EDITOR_GET("text_editor/appearance/caret/caret_blink_interval" )); |
2124 | #endif |
2125 | } |
2126 | |
2127 | void LineEdit::set_expand_to_text_length_enabled(bool p_enabled) { |
2128 | expand_to_text_length = p_enabled; |
2129 | update_minimum_size(); |
2130 | set_caret_column(caret_column); |
2131 | } |
2132 | |
2133 | bool LineEdit::is_expand_to_text_length_enabled() const { |
2134 | return expand_to_text_length; |
2135 | } |
2136 | |
2137 | void LineEdit::set_clear_button_enabled(bool p_enabled) { |
2138 | if (clear_button_enabled == p_enabled) { |
2139 | return; |
2140 | } |
2141 | clear_button_enabled = p_enabled; |
2142 | _fit_to_width(); |
2143 | update_minimum_size(); |
2144 | queue_redraw(); |
2145 | } |
2146 | |
2147 | bool LineEdit::is_clear_button_enabled() const { |
2148 | return clear_button_enabled; |
2149 | } |
2150 | |
2151 | void LineEdit::set_shortcut_keys_enabled(bool p_enabled) { |
2152 | shortcut_keys_enabled = p_enabled; |
2153 | } |
2154 | |
2155 | bool LineEdit::is_shortcut_keys_enabled() const { |
2156 | return shortcut_keys_enabled; |
2157 | } |
2158 | |
2159 | void LineEdit::set_virtual_keyboard_enabled(bool p_enable) { |
2160 | virtual_keyboard_enabled = p_enable; |
2161 | } |
2162 | |
2163 | bool LineEdit::is_virtual_keyboard_enabled() const { |
2164 | return virtual_keyboard_enabled; |
2165 | } |
2166 | |
2167 | void LineEdit::set_virtual_keyboard_type(VirtualKeyboardType p_type) { |
2168 | virtual_keyboard_type = p_type; |
2169 | } |
2170 | |
2171 | LineEdit::VirtualKeyboardType LineEdit::get_virtual_keyboard_type() const { |
2172 | return virtual_keyboard_type; |
2173 | } |
2174 | |
2175 | void LineEdit::set_middle_mouse_paste_enabled(bool p_enabled) { |
2176 | middle_mouse_paste_enabled = p_enabled; |
2177 | } |
2178 | |
2179 | bool LineEdit::is_middle_mouse_paste_enabled() const { |
2180 | return middle_mouse_paste_enabled; |
2181 | } |
2182 | |
2183 | void LineEdit::set_selecting_enabled(bool p_enabled) { |
2184 | if (selecting_enabled == p_enabled) { |
2185 | return; |
2186 | } |
2187 | |
2188 | selecting_enabled = p_enabled; |
2189 | |
2190 | if (!selecting_enabled) { |
2191 | deselect(); |
2192 | } |
2193 | } |
2194 | |
2195 | bool LineEdit::is_selecting_enabled() const { |
2196 | return selecting_enabled; |
2197 | } |
2198 | |
2199 | void LineEdit::set_deselect_on_focus_loss_enabled(const bool p_enabled) { |
2200 | if (deselect_on_focus_loss_enabled == p_enabled) { |
2201 | return; |
2202 | } |
2203 | |
2204 | deselect_on_focus_loss_enabled = p_enabled; |
2205 | if (p_enabled && selection.enabled && !has_focus()) { |
2206 | deselect(); |
2207 | } |
2208 | } |
2209 | |
2210 | bool LineEdit::is_deselect_on_focus_loss_enabled() const { |
2211 | return deselect_on_focus_loss_enabled; |
2212 | } |
2213 | |
2214 | void LineEdit::set_drag_and_drop_selection_enabled(const bool p_enabled) { |
2215 | drag_and_drop_selection_enabled = p_enabled; |
2216 | } |
2217 | |
2218 | bool LineEdit::is_drag_and_drop_selection_enabled() const { |
2219 | return drag_and_drop_selection_enabled; |
2220 | } |
2221 | |
2222 | void LineEdit::set_right_icon(const Ref<Texture2D> &p_icon) { |
2223 | if (right_icon == p_icon) { |
2224 | return; |
2225 | } |
2226 | right_icon = p_icon; |
2227 | _fit_to_width(); |
2228 | update_minimum_size(); |
2229 | queue_redraw(); |
2230 | } |
2231 | |
2232 | Ref<Texture2D> LineEdit::get_right_icon() { |
2233 | return right_icon; |
2234 | } |
2235 | |
2236 | void LineEdit::set_flat(bool p_enabled) { |
2237 | if (flat != p_enabled) { |
2238 | flat = p_enabled; |
2239 | queue_redraw(); |
2240 | } |
2241 | } |
2242 | |
2243 | bool LineEdit::is_flat() const { |
2244 | return flat; |
2245 | } |
2246 | |
2247 | void LineEdit::set_select_all_on_focus(bool p_enabled) { |
2248 | select_all_on_focus = p_enabled; |
2249 | } |
2250 | |
2251 | bool LineEdit::is_select_all_on_focus() const { |
2252 | return select_all_on_focus; |
2253 | } |
2254 | |
2255 | void LineEdit::clear_pending_select_all_on_focus() { |
2256 | pending_select_all_on_focus = false; |
2257 | } |
2258 | |
2259 | void LineEdit::_text_changed() { |
2260 | _emit_text_change(); |
2261 | _clear_redo(); |
2262 | } |
2263 | |
2264 | void LineEdit::_emit_text_change() { |
2265 | emit_signal(SNAME("text_changed" ), text); |
2266 | text_changed_dirty = false; |
2267 | } |
2268 | |
2269 | void LineEdit::_shape() { |
2270 | const Ref<Font> &font = theme_cache.font; |
2271 | int font_size = theme_cache.font_size; |
2272 | if (font.is_null()) { |
2273 | return; |
2274 | } |
2275 | |
2276 | Size2 old_size = TS->shaped_text_get_size(text_rid); |
2277 | TS->shaped_text_clear(text_rid); |
2278 | |
2279 | String t; |
2280 | if (text.length() == 0 && ime_text.length() == 0) { |
2281 | t = placeholder_translated; |
2282 | } else if (pass) { |
2283 | t = secret_character.repeat(text.length() + ime_text.length()); |
2284 | } else { |
2285 | if (ime_text.length() > 0) { |
2286 | t = text.substr(0, caret_column) + ime_text + text.substr(caret_column, text.length()); |
2287 | } else { |
2288 | t = text; |
2289 | } |
2290 | } |
2291 | if (text_direction == Control::TEXT_DIRECTION_INHERITED) { |
2292 | TS->shaped_text_set_direction(text_rid, is_layout_rtl() ? TextServer::DIRECTION_RTL : TextServer::DIRECTION_LTR); |
2293 | } else { |
2294 | TS->shaped_text_set_direction(text_rid, (TextServer::Direction)text_direction); |
2295 | } |
2296 | TS->shaped_text_set_preserve_control(text_rid, draw_control_chars); |
2297 | |
2298 | TS->shaped_text_add_string(text_rid, t, font->get_rids(), font_size, font->get_opentype_features(), language); |
2299 | TS->shaped_text_set_bidi_override(text_rid, structured_text_parser(st_parser, st_args, t)); |
2300 | |
2301 | full_width = TS->shaped_text_get_size(text_rid).x; |
2302 | _fit_to_width(); |
2303 | |
2304 | Size2 size = TS->shaped_text_get_size(text_rid); |
2305 | |
2306 | if ((expand_to_text_length && old_size.x != size.x) || (old_size.y != size.y)) { |
2307 | update_minimum_size(); |
2308 | } |
2309 | } |
2310 | |
2311 | void LineEdit::_fit_to_width() { |
2312 | if (alignment == HORIZONTAL_ALIGNMENT_FILL) { |
2313 | Ref<StyleBox> style = theme_cache.normal; |
2314 | int t_width = get_size().width - style->get_margin(SIDE_RIGHT) - style->get_margin(SIDE_LEFT); |
2315 | bool using_placeholder = text.is_empty() && ime_text.is_empty(); |
2316 | bool display_clear_icon = !using_placeholder && is_editable() && clear_button_enabled; |
2317 | if (right_icon.is_valid() || display_clear_icon) { |
2318 | Ref<Texture2D> r_icon = display_clear_icon ? theme_cache.clear_icon : right_icon; |
2319 | t_width -= r_icon->get_width(); |
2320 | } |
2321 | TS->shaped_text_fit_to_width(text_rid, MAX(t_width, full_width)); |
2322 | } |
2323 | } |
2324 | |
2325 | void LineEdit::_clear_redo() { |
2326 | _create_undo_state(); |
2327 | if (undo_stack_pos == nullptr) { |
2328 | return; |
2329 | } |
2330 | |
2331 | undo_stack_pos = undo_stack_pos->next(); |
2332 | while (undo_stack_pos) { |
2333 | List<TextOperation>::Element *elem = undo_stack_pos; |
2334 | undo_stack_pos = undo_stack_pos->next(); |
2335 | undo_stack.erase(elem); |
2336 | } |
2337 | _create_undo_state(); |
2338 | } |
2339 | |
2340 | void LineEdit::_clear_undo_stack() { |
2341 | undo_stack.clear(); |
2342 | undo_stack_pos = nullptr; |
2343 | _create_undo_state(); |
2344 | } |
2345 | |
2346 | void LineEdit::_create_undo_state() { |
2347 | TextOperation op; |
2348 | op.text = text; |
2349 | op.caret_column = caret_column; |
2350 | op.scroll_offset = scroll_offset; |
2351 | undo_stack.push_back(op); |
2352 | } |
2353 | |
2354 | Key LineEdit::(const String &p_action) { |
2355 | const List<Ref<InputEvent>> *events = InputMap::get_singleton()->action_get_events(p_action); |
2356 | if (!events) { |
2357 | return Key::NONE; |
2358 | } |
2359 | |
2360 | // Use first event in the list for the accelerator. |
2361 | const List<Ref<InputEvent>>::Element *first_event = events->front(); |
2362 | if (!first_event) { |
2363 | return Key::NONE; |
2364 | } |
2365 | |
2366 | const Ref<InputEventKey> event = first_event->get(); |
2367 | if (event.is_null()) { |
2368 | return Key::NONE; |
2369 | } |
2370 | |
2371 | // Use physical keycode if non-zero. |
2372 | if (event->get_physical_keycode() != Key::NONE) { |
2373 | return event->get_physical_keycode_with_modifiers(); |
2374 | } else { |
2375 | return event->get_keycode_with_modifiers(); |
2376 | } |
2377 | } |
2378 | |
2379 | void LineEdit::() { |
2380 | menu = memnew(PopupMenu); |
2381 | add_child(menu, false, INTERNAL_MODE_FRONT); |
2382 | |
2383 | menu_dir = memnew(PopupMenu); |
2384 | menu_dir->set_name("DirMenu" ); |
2385 | menu_dir->add_radio_check_item(RTR("Same as Layout Direction" ), MENU_DIR_INHERITED); |
2386 | menu_dir->add_radio_check_item(RTR("Auto-Detect Direction" ), MENU_DIR_AUTO); |
2387 | menu_dir->add_radio_check_item(RTR("Left-to-Right" ), MENU_DIR_LTR); |
2388 | menu_dir->add_radio_check_item(RTR("Right-to-Left" ), MENU_DIR_RTL); |
2389 | menu->add_child(menu_dir, false, INTERNAL_MODE_FRONT); |
2390 | |
2391 | menu_ctl = memnew(PopupMenu); |
2392 | menu_ctl->set_name("CTLMenu" ); |
2393 | menu_ctl->add_item(RTR("Left-to-Right Mark (LRM)" ), MENU_INSERT_LRM); |
2394 | menu_ctl->add_item(RTR("Right-to-Left Mark (RLM)" ), MENU_INSERT_RLM); |
2395 | menu_ctl->add_item(RTR("Start of Left-to-Right Embedding (LRE)" ), MENU_INSERT_LRE); |
2396 | menu_ctl->add_item(RTR("Start of Right-to-Left Embedding (RLE)" ), MENU_INSERT_RLE); |
2397 | menu_ctl->add_item(RTR("Start of Left-to-Right Override (LRO)" ), MENU_INSERT_LRO); |
2398 | menu_ctl->add_item(RTR("Start of Right-to-Left Override (RLO)" ), MENU_INSERT_RLO); |
2399 | menu_ctl->add_item(RTR("Pop Direction Formatting (PDF)" ), MENU_INSERT_PDF); |
2400 | menu_ctl->add_separator(); |
2401 | menu_ctl->add_item(RTR("Arabic Letter Mark (ALM)" ), MENU_INSERT_ALM); |
2402 | menu_ctl->add_item(RTR("Left-to-Right Isolate (LRI)" ), MENU_INSERT_LRI); |
2403 | menu_ctl->add_item(RTR("Right-to-Left Isolate (RLI)" ), MENU_INSERT_RLI); |
2404 | menu_ctl->add_item(RTR("First Strong Isolate (FSI)" ), MENU_INSERT_FSI); |
2405 | menu_ctl->add_item(RTR("Pop Direction Isolate (PDI)" ), MENU_INSERT_PDI); |
2406 | menu_ctl->add_separator(); |
2407 | menu_ctl->add_item(RTR("Zero-Width Joiner (ZWJ)" ), MENU_INSERT_ZWJ); |
2408 | menu_ctl->add_item(RTR("Zero-Width Non-Joiner (ZWNJ)" ), MENU_INSERT_ZWNJ); |
2409 | menu_ctl->add_item(RTR("Word Joiner (WJ)" ), MENU_INSERT_WJ); |
2410 | menu_ctl->add_item(RTR("Soft Hyphen (SHY)" ), MENU_INSERT_SHY); |
2411 | menu->add_child(menu_ctl, false, INTERNAL_MODE_FRONT); |
2412 | |
2413 | menu->add_item(RTR("Cut" ), MENU_CUT); |
2414 | menu->add_item(RTR("Copy" ), MENU_COPY); |
2415 | menu->add_item(RTR("Paste" ), MENU_PASTE); |
2416 | menu->add_separator(); |
2417 | menu->add_item(RTR("Select All" ), MENU_SELECT_ALL); |
2418 | menu->add_item(RTR("Clear" ), MENU_CLEAR); |
2419 | menu->add_separator(); |
2420 | menu->add_item(RTR("Undo" ), MENU_UNDO); |
2421 | menu->add_item(RTR("Redo" ), MENU_REDO); |
2422 | menu->add_separator(); |
2423 | menu->add_submenu_item(RTR("Text Writing Direction" ), "DirMenu" , MENU_SUBMENU_TEXT_DIR); |
2424 | menu->add_separator(); |
2425 | menu->add_check_item(RTR("Display Control Characters" ), MENU_DISPLAY_UCC); |
2426 | menu->add_submenu_item(RTR("Insert Control Character" ), "CTLMenu" , MENU_SUBMENU_INSERT_UCC); |
2427 | |
2428 | menu->connect("id_pressed" , callable_mp(this, &LineEdit::menu_option)); |
2429 | menu_dir->connect("id_pressed" , callable_mp(this, &LineEdit::menu_option)); |
2430 | menu_ctl->connect("id_pressed" , callable_mp(this, &LineEdit::menu_option)); |
2431 | |
2432 | menu->connect(SNAME("focus_entered" ), callable_mp(this, &LineEdit::_validate_caret_can_draw)); |
2433 | menu->connect(SNAME("focus_exited" ), callable_mp(this, &LineEdit::_validate_caret_can_draw)); |
2434 | } |
2435 | |
2436 | void LineEdit::() { |
2437 | if (!menu) { |
2438 | _generate_context_menu(); |
2439 | } |
2440 | |
2441 | int idx = -1; |
2442 | |
2443 | #define (m_menu, m_id, m_action, m_disabled) \ |
2444 | idx = m_menu->get_item_index(m_id); \ |
2445 | if (idx >= 0) { \ |
2446 | m_menu->set_item_accelerator(idx, shortcut_keys_enabled ? _get_menu_action_accelerator(m_action) : Key::NONE); \ |
2447 | m_menu->set_item_disabled(idx, m_disabled); \ |
2448 | } |
2449 | |
2450 | #define (m_menu, m_id, m_action) \ |
2451 | idx = m_menu->get_item_index(m_id); \ |
2452 | if (idx >= 0) { \ |
2453 | m_menu->set_item_accelerator(idx, shortcut_keys_enabled ? _get_menu_action_accelerator(m_action) : Key::NONE); \ |
2454 | } |
2455 | |
2456 | #define (m_menu, m_id, m_disabled) \ |
2457 | idx = m_menu->get_item_index(m_id); \ |
2458 | if (idx >= 0) { \ |
2459 | m_menu->set_item_disabled(idx, m_disabled); \ |
2460 | } |
2461 | |
2462 | #define (m_menu, m_id, m_checked) \ |
2463 | idx = m_menu->get_item_index(m_id); \ |
2464 | if (idx >= 0) { \ |
2465 | m_menu->set_item_checked(idx, m_checked); \ |
2466 | } |
2467 | |
2468 | MENU_ITEM_ACTION_DISABLED(menu, MENU_CUT, "ui_cut" , !editable) |
2469 | MENU_ITEM_ACTION(menu, MENU_COPY, "ui_copy" ) |
2470 | MENU_ITEM_ACTION_DISABLED(menu, MENU_PASTE, "ui_paste" , !editable) |
2471 | MENU_ITEM_ACTION_DISABLED(menu, MENU_SELECT_ALL, "ui_text_select_all" , !selecting_enabled) |
2472 | MENU_ITEM_DISABLED(menu, MENU_CLEAR, !editable) |
2473 | MENU_ITEM_ACTION_DISABLED(menu, MENU_UNDO, "ui_undo" , !editable || !has_undo()) |
2474 | MENU_ITEM_ACTION_DISABLED(menu, MENU_REDO, "ui_redo" , !editable || !has_redo()) |
2475 | MENU_ITEM_CHECKED(menu_dir, MENU_DIR_INHERITED, text_direction == TEXT_DIRECTION_INHERITED) |
2476 | MENU_ITEM_CHECKED(menu_dir, MENU_DIR_AUTO, text_direction == TEXT_DIRECTION_AUTO) |
2477 | MENU_ITEM_CHECKED(menu_dir, MENU_DIR_LTR, text_direction == TEXT_DIRECTION_LTR) |
2478 | MENU_ITEM_CHECKED(menu_dir, MENU_DIR_RTL, text_direction == TEXT_DIRECTION_RTL) |
2479 | MENU_ITEM_CHECKED(menu, MENU_DISPLAY_UCC, draw_control_chars) |
2480 | MENU_ITEM_DISABLED(menu, MENU_SUBMENU_INSERT_UCC, !editable) |
2481 | |
2482 | #undef MENU_ITEM_ACTION_DISABLED |
2483 | #undef MENU_ITEM_ACTION |
2484 | #undef MENU_ITEM_DISABLED |
2485 | #undef MENU_ITEM_CHECKED |
2486 | } |
2487 | |
2488 | void LineEdit::_validate_property(PropertyInfo &p_property) const { |
2489 | if (!caret_blink_enabled && p_property.name == "caret_blink_interval" ) { |
2490 | p_property.usage = PROPERTY_USAGE_NO_EDITOR; |
2491 | } |
2492 | } |
2493 | |
2494 | void LineEdit::_bind_methods() { |
2495 | ClassDB::bind_method(D_METHOD("_text_changed" ), &LineEdit::_text_changed); |
2496 | |
2497 | ClassDB::bind_method(D_METHOD("set_horizontal_alignment" , "alignment" ), &LineEdit::set_horizontal_alignment); |
2498 | ClassDB::bind_method(D_METHOD("get_horizontal_alignment" ), &LineEdit::get_horizontal_alignment); |
2499 | |
2500 | ClassDB::bind_method(D_METHOD("clear" ), &LineEdit::clear); |
2501 | ClassDB::bind_method(D_METHOD("select" , "from" , "to" ), &LineEdit::select, DEFVAL(0), DEFVAL(-1)); |
2502 | ClassDB::bind_method(D_METHOD("select_all" ), &LineEdit::select_all); |
2503 | ClassDB::bind_method(D_METHOD("deselect" ), &LineEdit::deselect); |
2504 | ClassDB::bind_method(D_METHOD("has_selection" ), &LineEdit::has_selection); |
2505 | ClassDB::bind_method(D_METHOD("get_selected_text" ), &LineEdit::get_selected_text); |
2506 | ClassDB::bind_method(D_METHOD("get_selection_from_column" ), &LineEdit::get_selection_from_column); |
2507 | ClassDB::bind_method(D_METHOD("get_selection_to_column" ), &LineEdit::get_selection_to_column); |
2508 | ClassDB::bind_method(D_METHOD("set_text" , "text" ), &LineEdit::set_text); |
2509 | ClassDB::bind_method(D_METHOD("get_text" ), &LineEdit::get_text); |
2510 | ClassDB::bind_method(D_METHOD("get_draw_control_chars" ), &LineEdit::get_draw_control_chars); |
2511 | ClassDB::bind_method(D_METHOD("set_draw_control_chars" , "enable" ), &LineEdit::set_draw_control_chars); |
2512 | ClassDB::bind_method(D_METHOD("set_text_direction" , "direction" ), &LineEdit::set_text_direction); |
2513 | ClassDB::bind_method(D_METHOD("get_text_direction" ), &LineEdit::get_text_direction); |
2514 | ClassDB::bind_method(D_METHOD("set_language" , "language" ), &LineEdit::set_language); |
2515 | ClassDB::bind_method(D_METHOD("get_language" ), &LineEdit::get_language); |
2516 | ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override" , "parser" ), &LineEdit::set_structured_text_bidi_override); |
2517 | ClassDB::bind_method(D_METHOD("get_structured_text_bidi_override" ), &LineEdit::get_structured_text_bidi_override); |
2518 | ClassDB::bind_method(D_METHOD("set_structured_text_bidi_override_options" , "args" ), &LineEdit::set_structured_text_bidi_override_options); |
2519 | ClassDB::bind_method(D_METHOD("get_structured_text_bidi_override_options" ), &LineEdit::get_structured_text_bidi_override_options); |
2520 | ClassDB::bind_method(D_METHOD("set_placeholder" , "text" ), &LineEdit::set_placeholder); |
2521 | ClassDB::bind_method(D_METHOD("get_placeholder" ), &LineEdit::get_placeholder); |
2522 | ClassDB::bind_method(D_METHOD("set_caret_column" , "position" ), &LineEdit::set_caret_column); |
2523 | ClassDB::bind_method(D_METHOD("get_caret_column" ), &LineEdit::get_caret_column); |
2524 | ClassDB::bind_method(D_METHOD("get_scroll_offset" ), &LineEdit::get_scroll_offset); |
2525 | ClassDB::bind_method(D_METHOD("set_expand_to_text_length_enabled" , "enabled" ), &LineEdit::set_expand_to_text_length_enabled); |
2526 | ClassDB::bind_method(D_METHOD("is_expand_to_text_length_enabled" ), &LineEdit::is_expand_to_text_length_enabled); |
2527 | ClassDB::bind_method(D_METHOD("set_caret_blink_enabled" , "enabled" ), &LineEdit::set_caret_blink_enabled); |
2528 | ClassDB::bind_method(D_METHOD("is_caret_blink_enabled" ), &LineEdit::is_caret_blink_enabled); |
2529 | ClassDB::bind_method(D_METHOD("set_caret_mid_grapheme_enabled" , "enabled" ), &LineEdit::set_caret_mid_grapheme_enabled); |
2530 | ClassDB::bind_method(D_METHOD("is_caret_mid_grapheme_enabled" ), &LineEdit::is_caret_mid_grapheme_enabled); |
2531 | ClassDB::bind_method(D_METHOD("set_caret_force_displayed" , "enabled" ), &LineEdit::set_caret_force_displayed); |
2532 | ClassDB::bind_method(D_METHOD("is_caret_force_displayed" ), &LineEdit::is_caret_force_displayed); |
2533 | ClassDB::bind_method(D_METHOD("set_caret_blink_interval" , "interval" ), &LineEdit::set_caret_blink_interval); |
2534 | ClassDB::bind_method(D_METHOD("get_caret_blink_interval" ), &LineEdit::get_caret_blink_interval); |
2535 | ClassDB::bind_method(D_METHOD("set_max_length" , "chars" ), &LineEdit::set_max_length); |
2536 | ClassDB::bind_method(D_METHOD("get_max_length" ), &LineEdit::get_max_length); |
2537 | ClassDB::bind_method(D_METHOD("insert_text_at_caret" , "text" ), &LineEdit::insert_text_at_caret); |
2538 | ClassDB::bind_method(D_METHOD("delete_char_at_caret" ), &LineEdit::delete_char); |
2539 | ClassDB::bind_method(D_METHOD("delete_text" , "from_column" , "to_column" ), &LineEdit::delete_text); |
2540 | ClassDB::bind_method(D_METHOD("set_editable" , "enabled" ), &LineEdit::set_editable); |
2541 | ClassDB::bind_method(D_METHOD("is_editable" ), &LineEdit::is_editable); |
2542 | ClassDB::bind_method(D_METHOD("set_secret" , "enabled" ), &LineEdit::set_secret); |
2543 | ClassDB::bind_method(D_METHOD("is_secret" ), &LineEdit::is_secret); |
2544 | ClassDB::bind_method(D_METHOD("set_secret_character" , "character" ), &LineEdit::set_secret_character); |
2545 | ClassDB::bind_method(D_METHOD("get_secret_character" ), &LineEdit::get_secret_character); |
2546 | ClassDB::bind_method(D_METHOD("menu_option" , "option" ), &LineEdit::menu_option); |
2547 | ClassDB::bind_method(D_METHOD("get_menu" ), &LineEdit::get_menu); |
2548 | ClassDB::bind_method(D_METHOD("is_menu_visible" ), &LineEdit::is_menu_visible); |
2549 | ClassDB::bind_method(D_METHOD("set_context_menu_enabled" , "enable" ), &LineEdit::set_context_menu_enabled); |
2550 | ClassDB::bind_method(D_METHOD("is_context_menu_enabled" ), &LineEdit::is_context_menu_enabled); |
2551 | ClassDB::bind_method(D_METHOD("set_virtual_keyboard_enabled" , "enable" ), &LineEdit::set_virtual_keyboard_enabled); |
2552 | ClassDB::bind_method(D_METHOD("is_virtual_keyboard_enabled" ), &LineEdit::is_virtual_keyboard_enabled); |
2553 | ClassDB::bind_method(D_METHOD("set_virtual_keyboard_type" , "type" ), &LineEdit::set_virtual_keyboard_type); |
2554 | ClassDB::bind_method(D_METHOD("get_virtual_keyboard_type" ), &LineEdit::get_virtual_keyboard_type); |
2555 | ClassDB::bind_method(D_METHOD("set_clear_button_enabled" , "enable" ), &LineEdit::set_clear_button_enabled); |
2556 | ClassDB::bind_method(D_METHOD("is_clear_button_enabled" ), &LineEdit::is_clear_button_enabled); |
2557 | ClassDB::bind_method(D_METHOD("set_shortcut_keys_enabled" , "enable" ), &LineEdit::set_shortcut_keys_enabled); |
2558 | ClassDB::bind_method(D_METHOD("is_shortcut_keys_enabled" ), &LineEdit::is_shortcut_keys_enabled); |
2559 | ClassDB::bind_method(D_METHOD("set_middle_mouse_paste_enabled" , "enable" ), &LineEdit::set_middle_mouse_paste_enabled); |
2560 | ClassDB::bind_method(D_METHOD("is_middle_mouse_paste_enabled" ), &LineEdit::is_middle_mouse_paste_enabled); |
2561 | ClassDB::bind_method(D_METHOD("set_selecting_enabled" , "enable" ), &LineEdit::set_selecting_enabled); |
2562 | ClassDB::bind_method(D_METHOD("is_selecting_enabled" ), &LineEdit::is_selecting_enabled); |
2563 | ClassDB::bind_method(D_METHOD("set_deselect_on_focus_loss_enabled" , "enable" ), &LineEdit::set_deselect_on_focus_loss_enabled); |
2564 | ClassDB::bind_method(D_METHOD("is_deselect_on_focus_loss_enabled" ), &LineEdit::is_deselect_on_focus_loss_enabled); |
2565 | ClassDB::bind_method(D_METHOD("set_drag_and_drop_selection_enabled" , "enable" ), &LineEdit::set_drag_and_drop_selection_enabled); |
2566 | ClassDB::bind_method(D_METHOD("is_drag_and_drop_selection_enabled" ), &LineEdit::is_drag_and_drop_selection_enabled); |
2567 | ClassDB::bind_method(D_METHOD("set_right_icon" , "icon" ), &LineEdit::set_right_icon); |
2568 | ClassDB::bind_method(D_METHOD("get_right_icon" ), &LineEdit::get_right_icon); |
2569 | ClassDB::bind_method(D_METHOD("set_flat" , "enabled" ), &LineEdit::set_flat); |
2570 | ClassDB::bind_method(D_METHOD("is_flat" ), &LineEdit::is_flat); |
2571 | ClassDB::bind_method(D_METHOD("set_select_all_on_focus" , "enabled" ), &LineEdit::set_select_all_on_focus); |
2572 | ClassDB::bind_method(D_METHOD("is_select_all_on_focus" ), &LineEdit::is_select_all_on_focus); |
2573 | |
2574 | ADD_SIGNAL(MethodInfo("text_changed" , PropertyInfo(Variant::STRING, "new_text" ))); |
2575 | ADD_SIGNAL(MethodInfo("text_change_rejected" , PropertyInfo(Variant::STRING, "rejected_substring" ))); |
2576 | ADD_SIGNAL(MethodInfo("text_submitted" , PropertyInfo(Variant::STRING, "new_text" ))); |
2577 | |
2578 | BIND_ENUM_CONSTANT(MENU_CUT); |
2579 | BIND_ENUM_CONSTANT(MENU_COPY); |
2580 | BIND_ENUM_CONSTANT(MENU_PASTE); |
2581 | BIND_ENUM_CONSTANT(MENU_CLEAR); |
2582 | BIND_ENUM_CONSTANT(MENU_SELECT_ALL); |
2583 | BIND_ENUM_CONSTANT(MENU_UNDO); |
2584 | BIND_ENUM_CONSTANT(MENU_REDO); |
2585 | BIND_ENUM_CONSTANT(MENU_SUBMENU_TEXT_DIR); |
2586 | BIND_ENUM_CONSTANT(MENU_DIR_INHERITED); |
2587 | BIND_ENUM_CONSTANT(MENU_DIR_AUTO); |
2588 | BIND_ENUM_CONSTANT(MENU_DIR_LTR); |
2589 | BIND_ENUM_CONSTANT(MENU_DIR_RTL); |
2590 | BIND_ENUM_CONSTANT(MENU_DISPLAY_UCC); |
2591 | BIND_ENUM_CONSTANT(MENU_SUBMENU_INSERT_UCC); |
2592 | BIND_ENUM_CONSTANT(MENU_INSERT_LRM); |
2593 | BIND_ENUM_CONSTANT(MENU_INSERT_RLM); |
2594 | BIND_ENUM_CONSTANT(MENU_INSERT_LRE); |
2595 | BIND_ENUM_CONSTANT(MENU_INSERT_RLE); |
2596 | BIND_ENUM_CONSTANT(MENU_INSERT_LRO); |
2597 | BIND_ENUM_CONSTANT(MENU_INSERT_RLO); |
2598 | BIND_ENUM_CONSTANT(MENU_INSERT_PDF); |
2599 | BIND_ENUM_CONSTANT(MENU_INSERT_ALM); |
2600 | BIND_ENUM_CONSTANT(MENU_INSERT_LRI); |
2601 | BIND_ENUM_CONSTANT(MENU_INSERT_RLI); |
2602 | BIND_ENUM_CONSTANT(MENU_INSERT_FSI); |
2603 | BIND_ENUM_CONSTANT(MENU_INSERT_PDI); |
2604 | BIND_ENUM_CONSTANT(MENU_INSERT_ZWJ); |
2605 | BIND_ENUM_CONSTANT(MENU_INSERT_ZWNJ); |
2606 | BIND_ENUM_CONSTANT(MENU_INSERT_WJ); |
2607 | BIND_ENUM_CONSTANT(MENU_INSERT_SHY); |
2608 | BIND_ENUM_CONSTANT(MENU_MAX); |
2609 | |
2610 | BIND_ENUM_CONSTANT(KEYBOARD_TYPE_DEFAULT); |
2611 | BIND_ENUM_CONSTANT(KEYBOARD_TYPE_MULTILINE); |
2612 | BIND_ENUM_CONSTANT(KEYBOARD_TYPE_NUMBER); |
2613 | BIND_ENUM_CONSTANT(KEYBOARD_TYPE_NUMBER_DECIMAL); |
2614 | BIND_ENUM_CONSTANT(KEYBOARD_TYPE_PHONE); |
2615 | BIND_ENUM_CONSTANT(KEYBOARD_TYPE_EMAIL_ADDRESS); |
2616 | BIND_ENUM_CONSTANT(KEYBOARD_TYPE_PASSWORD); |
2617 | BIND_ENUM_CONSTANT(KEYBOARD_TYPE_URL); |
2618 | |
2619 | ADD_PROPERTY(PropertyInfo(Variant::STRING, "text" ), "set_text" , "get_text" ); |
2620 | ADD_PROPERTY(PropertyInfo(Variant::STRING, "placeholder_text" ), "set_placeholder" , "get_placeholder" ); |
2621 | ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment" , PROPERTY_HINT_ENUM, "Left,Center,Right,Fill" ), "set_horizontal_alignment" , "get_horizontal_alignment" ); |
2622 | ADD_PROPERTY(PropertyInfo(Variant::INT, "max_length" , PROPERTY_HINT_RANGE, "0,1000,1,or_greater" ), "set_max_length" , "get_max_length" ); |
2623 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "editable" ), "set_editable" , "is_editable" ); |
2624 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "secret" ), "set_secret" , "is_secret" ); |
2625 | ADD_PROPERTY(PropertyInfo(Variant::STRING, "secret_character" ), "set_secret_character" , "get_secret_character" ); |
2626 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "expand_to_text_length" ), "set_expand_to_text_length_enabled" , "is_expand_to_text_length_enabled" ); |
2627 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "context_menu_enabled" ), "set_context_menu_enabled" , "is_context_menu_enabled" ); |
2628 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "virtual_keyboard_enabled" ), "set_virtual_keyboard_enabled" , "is_virtual_keyboard_enabled" ); |
2629 | ADD_PROPERTY(PropertyInfo(Variant::INT, "virtual_keyboard_type" , PROPERTY_HINT_ENUM, "Default,Multiline,Number,Decimal,Phone,Email,Password,URL" ), "set_virtual_keyboard_type" , "get_virtual_keyboard_type" ); |
2630 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "clear_button_enabled" ), "set_clear_button_enabled" , "is_clear_button_enabled" ); |
2631 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "shortcut_keys_enabled" ), "set_shortcut_keys_enabled" , "is_shortcut_keys_enabled" ); |
2632 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "middle_mouse_paste_enabled" ), "set_middle_mouse_paste_enabled" , "is_middle_mouse_paste_enabled" ); |
2633 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "selecting_enabled" ), "set_selecting_enabled" , "is_selecting_enabled" ); |
2634 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "deselect_on_focus_loss_enabled" ), "set_deselect_on_focus_loss_enabled" , "is_deselect_on_focus_loss_enabled" ); |
2635 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_and_drop_selection_enabled" ), "set_drag_and_drop_selection_enabled" , "is_drag_and_drop_selection_enabled" ); |
2636 | ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "right_icon" , PROPERTY_HINT_RESOURCE_TYPE, "Texture" ), "set_right_icon" , "get_right_icon" ); |
2637 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "flat" ), "set_flat" , "is_flat" ); |
2638 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "draw_control_chars" ), "set_draw_control_chars" , "get_draw_control_chars" ); |
2639 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_all_on_focus" ), "set_select_all_on_focus" , "is_select_all_on_focus" ); |
2640 | |
2641 | ADD_GROUP("Caret" , "caret_" ); |
2642 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_blink" ), "set_caret_blink_enabled" , "is_caret_blink_enabled" ); |
2643 | ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "caret_blink_interval" , PROPERTY_HINT_RANGE, "0.1,10,0.01" ), "set_caret_blink_interval" , "get_caret_blink_interval" ); |
2644 | ADD_PROPERTY(PropertyInfo(Variant::INT, "caret_column" , PROPERTY_HINT_RANGE, "0,1000,1,or_greater" ), "set_caret_column" , "get_caret_column" ); |
2645 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_force_displayed" ), "set_caret_force_displayed" , "is_caret_force_displayed" ); |
2646 | ADD_PROPERTY(PropertyInfo(Variant::BOOL, "caret_mid_grapheme" ), "set_caret_mid_grapheme_enabled" , "is_caret_mid_grapheme_enabled" ); |
2647 | |
2648 | ADD_GROUP("BiDi" , "" ); |
2649 | ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction" , PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited" ), "set_text_direction" , "get_text_direction" ); |
2650 | ADD_PROPERTY(PropertyInfo(Variant::STRING, "language" , PROPERTY_HINT_LOCALE_ID, "" ), "set_language" , "get_language" ); |
2651 | ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override" , PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom" ), "set_structured_text_bidi_override" , "get_structured_text_bidi_override" ); |
2652 | ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options" ), "set_structured_text_bidi_override_options" , "get_structured_text_bidi_override_options" ); |
2653 | |
2654 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, LineEdit, normal); |
2655 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, LineEdit, read_only); |
2656 | BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, LineEdit, focus); |
2657 | |
2658 | BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, LineEdit, font); |
2659 | BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, LineEdit, font_size); |
2660 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, font_color); |
2661 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, font_uneditable_color); |
2662 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, font_selected_color); |
2663 | BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, LineEdit, font_outline_size, "outline_size" ); |
2664 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, font_outline_color); |
2665 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, font_placeholder_color); |
2666 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, LineEdit, caret_width); |
2667 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, caret_color); |
2668 | BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, LineEdit, minimum_character_width); |
2669 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, selection_color); |
2670 | |
2671 | BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, LineEdit, clear_icon, "clear" ); |
2672 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, clear_button_color); |
2673 | BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, clear_button_color_pressed); |
2674 | } |
2675 | |
2676 | LineEdit::LineEdit(const String &p_placeholder) { |
2677 | text_rid = TS->create_shaped_text(); |
2678 | _create_undo_state(); |
2679 | |
2680 | deselect(); |
2681 | set_focus_mode(FOCUS_ALL); |
2682 | set_default_cursor_shape(CURSOR_IBEAM); |
2683 | set_mouse_filter(MOUSE_FILTER_STOP); |
2684 | set_process_unhandled_key_input(true); |
2685 | |
2686 | set_caret_blink_enabled(false); |
2687 | |
2688 | set_placeholder(p_placeholder); |
2689 | |
2690 | set_editable(true); // Initialize to opposite first, so we get past the early-out in set_editable. |
2691 | } |
2692 | |
2693 | LineEdit::~LineEdit() { |
2694 | TS->free_rid(text_rid); |
2695 | } |
2696 | |