2014-02-10 02:10:30 +01:00
/*************************************************************************/
/* line_edit.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
2017-08-27 14:16:55 +02:00
/* https://godotengine.org */
2014-02-10 02:10:30 +01:00
/*************************************************************************/
2019-01-01 12:53:14 +01:00
/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2019 Godot Engine contributors (cf. AUTHORS.md) */
2014-02-10 02:10:30 +01:00
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
2018-01-05 00:50:27 +01:00
2014-02-10 02:10:30 +01:00
# include "line_edit.h"
2019-04-05 14:06:16 +02:00
2018-09-11 18:13:45 +02:00
# include "core/message_queue.h"
# include "core/os/keyboard.h"
# include "core/os/os.h"
# include "core/print_string.h"
# include "core/translation.h"
2017-03-05 16:44:50 +01:00
# include "label.h"
2018-07-26 23:41:47 +02:00
2016-06-21 15:38:35 +02:00
# ifdef TOOLS_ENABLED
2018-07-26 23:41:47 +02:00
# include "editor/editor_scale.h"
2017-03-05 14:21:25 +01:00
# include "editor/editor_settings.h"
2016-06-21 15:38:35 +02:00
# endif
2014-02-10 02:10:30 +01:00
2016-06-18 16:15:26 +02:00
static bool _is_text_char ( CharType c ) {
2019-03-09 19:45:06 +01:00
return ! is_symbol ( c ) ;
2016-06-18 16:15:26 +02:00
}
2017-05-20 17:38:03 +02:00
void LineEdit : : _gui_input ( Ref < InputEvent > p_event ) {
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
Ref < InputEventMouseButton > b = p_event ;
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
if ( b . is_valid ( ) ) {
2016-03-09 00:00:52 +01:00
2017-11-09 21:46:29 +01:00
if ( b - > is_pressed ( ) & & b - > get_button_index ( ) = = BUTTON_RIGHT & & context_menu_enabled ) {
2017-09-10 15:37:49 +02:00
menu - > set_position ( get_global_transform ( ) . xform ( get_local_mouse_position ( ) ) ) ;
2017-05-20 17:38:03 +02:00
menu - > set_size ( Vector2 ( 1 , 1 ) ) ;
2019-04-23 03:28:38 +02:00
menu - > set_scale ( get_global_transform ( ) . get_scale ( ) ) ;
2017-05-20 17:38:03 +02:00
menu - > popup ( ) ;
grab_focus ( ) ;
2019-08-04 15:35:50 +02:00
accept_event ( ) ;
2017-05-20 17:38:03 +02:00
return ;
}
2016-05-17 01:25:17 +02:00
2017-05-20 17:38:03 +02:00
if ( b - > get_button_index ( ) ! = BUTTON_LEFT )
return ;
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
_reset_caret_blink_timer ( ) ;
if ( b - > is_pressed ( ) ) {
2016-03-09 00:00:52 +01:00
2019-05-21 14:49:53 +02:00
accept_event ( ) ; //don't pass event further when clicked on text field
2018-07-26 13:45:38 +02:00
if ( ! text . empty ( ) & & is_editable ( ) & & _is_over_clear_button ( b - > get_position ( ) ) ) {
clear_button_status . press_attempt = true ;
clear_button_status . pressing_inside = true ;
return ;
}
2017-05-20 17:38:03 +02:00
shift_selection_check_pre ( b - > get_shift ( ) ) ;
2016-06-18 16:14:43 +02:00
2017-06-03 10:54:24 +02:00
set_cursor_at_pixel_pos ( b - > get_position ( ) . x ) ;
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
if ( b - > get_shift ( ) ) {
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
selection_fill_at_cursor ( ) ;
selection . creating = true ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
} else {
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
if ( b - > is_doubleclick ( ) ) {
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
selection . enabled = true ;
selection . begin = 0 ;
selection . end = text . length ( ) ;
selection . doubleclick = true ;
}
2016-06-18 16:14:43 +02:00
2017-05-20 17:38:03 +02:00
selection . drag_attempt = false ;
2016-06-18 16:14:43 +02:00
2017-05-20 17:38:03 +02:00
if ( ( cursor_pos < selection . begin ) | | ( cursor_pos > selection . end ) | | ! selection . enabled ) {
2014-02-10 02:10:30 +01:00
2017-12-17 18:40:44 +01:00
deselect ( ) ;
2017-05-20 17:38:03 +02:00
selection . cursor_start = cursor_pos ;
selection . creating = true ;
} else if ( selection . enabled ) {
2016-06-18 16:14:43 +02:00
2017-05-20 17:38:03 +02:00
selection . drag_attempt = true ;
2014-02-10 02:10:30 +01:00
}
2017-05-20 17:38:03 +02:00
}
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
update ( ) ;
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
} else {
2016-03-09 00:00:52 +01:00
2018-07-26 13:45:38 +02:00
if ( ! text . empty ( ) & & is_editable ( ) & & clear_button_enabled ) {
bool press_attempt = clear_button_status . press_attempt ;
clear_button_status . press_attempt = false ;
if ( press_attempt & & clear_button_status . pressing_inside & & _is_over_clear_button ( b - > get_position ( ) ) ) {
clear ( ) ;
return ;
}
}
2017-05-20 17:38:03 +02:00
if ( ( ! selection . creating ) & & ( ! selection . doubleclick ) ) {
2017-12-17 18:40:44 +01:00
deselect ( ) ;
2014-02-10 02:10:30 +01:00
}
2017-05-20 17:38:03 +02:00
selection . creating = false ;
selection . doubleclick = false ;
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
if ( OS : : get_singleton ( ) - > has_virtual_keyboard ( ) )
OS : : get_singleton ( ) - > show_virtual_keyboard ( text , get_global_rect ( ) ) ;
}
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
update ( ) ;
}
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
Ref < InputEventMouseMotion > m = p_event ;
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
if ( m . is_valid ( ) ) {
2016-03-09 00:00:52 +01:00
2018-07-26 13:45:38 +02:00
if ( ! text . empty ( ) & & is_editable ( ) & & clear_button_enabled ) {
bool last_press_inside = clear_button_status . pressing_inside ;
clear_button_status . pressing_inside = clear_button_status . press_attempt & & _is_over_clear_button ( m - > get_position ( ) ) ;
if ( last_press_inside ! = clear_button_status . pressing_inside ) {
update ( ) ;
}
}
2017-05-20 17:38:03 +02:00
if ( m - > get_button_mask ( ) & BUTTON_LEFT ) {
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
if ( selection . creating ) {
2017-06-03 10:54:24 +02:00
set_cursor_at_pixel_pos ( m - > get_position ( ) . x ) ;
2017-05-20 17:38:03 +02:00
selection_fill_at_cursor ( ) ;
}
}
}
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
Ref < InputEventKey > k = p_event ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
if ( k . is_valid ( ) ) {
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
if ( ! k - > is_pressed ( ) )
return ;
2019-05-06 21:59:34 +02:00
# ifdef APPLE_STYLE_KEYS
if ( k - > get_control ( ) & & ! k - > get_shift ( ) & & ! k - > get_alt ( ) & & ! k - > get_command ( ) ) {
uint32_t remap_key = KEY_UNKNOWN ;
switch ( k - > get_scancode ( ) ) {
case KEY_F : {
remap_key = KEY_RIGHT ;
} break ;
case KEY_B : {
remap_key = KEY_LEFT ;
} break ;
case KEY_P : {
remap_key = KEY_UP ;
} break ;
case KEY_N : {
remap_key = KEY_DOWN ;
} break ;
case KEY_D : {
remap_key = KEY_DELETE ;
} break ;
case KEY_H : {
remap_key = KEY_BACKSPACE ;
} break ;
}
if ( remap_key ! = KEY_UNKNOWN ) {
k - > set_scancode ( remap_key ) ;
k - > set_control ( false ) ;
}
}
# endif
2017-05-20 17:38:03 +02:00
unsigned int code = k - > get_scancode ( ) ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
if ( k - > get_command ( ) ) {
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
bool handled = true ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
switch ( code ) {
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
case ( KEY_X ) : { // CUT
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
if ( editable ) {
cut_text ( ) ;
}
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
} break ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
case ( KEY_C ) : { // COPY
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
copy_text ( ) ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
} break ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
case ( KEY_V ) : { // PASTE
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
if ( editable ) {
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
paste_text ( ) ;
}
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
} break ;
2014-02-10 02:10:30 +01:00
2017-10-30 00:14:33 +01:00
case ( KEY_Z ) : { // undo / redo
2017-05-20 17:38:03 +02:00
if ( editable ) {
2017-10-30 00:14:33 +01:00
if ( k - > get_shift ( ) ) {
redo ( ) ;
} else {
undo ( ) ;
}
2017-05-20 17:38:03 +02:00
}
} break ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
case ( KEY_U ) : { // Delete from start to cursor
2015-08-15 08:47:22 +02:00
2017-05-20 17:38:03 +02:00
if ( editable ) {
2015-08-15 08:47:22 +02:00
2017-12-17 18:40:44 +01:00
deselect ( ) ;
2017-05-20 17:38:03 +02:00
text = text . substr ( cursor_pos , text . length ( ) - cursor_pos ) ;
Ref < Font > font = get_font ( " font " ) ;
2015-08-15 08:47:22 +02:00
2017-05-20 17:38:03 +02:00
cached_width = 0 ;
if ( font ! = NULL ) {
for ( int i = 0 ; i < text . length ( ) ; i + + )
cached_width + = font - > get_char_size ( text [ i ] ) . width ;
2014-02-10 02:10:30 +01:00
}
2017-09-10 15:37:49 +02:00
set_cursor_position ( 0 ) ;
2017-05-20 17:38:03 +02:00
_text_changed ( ) ;
}
} break ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
case ( KEY_Y ) : { // PASTE (Yank for unix users)
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
if ( editable ) {
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
paste_text ( ) ;
}
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
} break ;
case ( KEY_K ) : { // Delete from cursor_pos to end
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
if ( editable ) {
2014-02-10 02:10:30 +01:00
2017-12-17 18:40:44 +01:00
deselect ( ) ;
2017-05-20 17:38:03 +02:00
text = text . substr ( 0 , cursor_pos ) ;
_text_changed ( ) ;
}
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
} break ;
case ( KEY_A ) : { //Select All
select ( ) ;
} break ;
2018-05-24 11:34:22 +02:00
# ifdef APPLE_STYLE_KEYS
2018-04-23 12:33:08 +02:00
case ( KEY_LEFT ) : { // Go to start of text - like HOME key
set_cursor_position ( 0 ) ;
} break ;
case ( KEY_RIGHT ) : { // Go to end of text - like END key
set_cursor_position ( text . length ( ) ) ;
} break ;
2018-05-24 11:34:22 +02:00
# endif
2019-01-08 21:52:56 +01:00
default : {
handled = false ;
}
2017-05-20 17:38:03 +02:00
}
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
if ( handled ) {
accept_event ( ) ;
return ;
2014-02-10 02:10:30 +01:00
}
2017-05-20 17:38:03 +02:00
}
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
_reset_caret_blink_timer ( ) ;
if ( ! k - > get_metakey ( ) ) {
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
bool handled = true ;
switch ( code ) {
2014-02-10 02:10:30 +01:00
2017-08-06 15:26:07 +02:00
case KEY_KP_ENTER :
case KEY_ENTER : {
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
emit_signal ( " text_entered " , text ) ;
if ( OS : : get_singleton ( ) - > has_virtual_keyboard ( ) )
OS : : get_singleton ( ) - > hide_virtual_keyboard ( ) ;
2016-01-31 22:09:45 +01:00
2017-05-20 17:38:03 +02:00
return ;
} break ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
case KEY_BACKSPACE : {
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
if ( ! editable )
break ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
if ( selection . enabled ) {
selection_delete ( ) ;
break ;
}
2016-06-18 16:15:26 +02:00
# ifdef APPLE_STYLE_KEYS
2017-05-20 17:38:03 +02:00
if ( k - > get_alt ( ) ) {
2016-06-18 16:15:26 +02:00
# else
2017-05-20 17:38:03 +02:00
if ( k - > get_alt ( ) ) {
handled = false ;
break ;
} else if ( k - > get_command ( ) ) {
2016-06-18 16:15:26 +02:00
# endif
2017-05-20 17:38:03 +02:00
int cc = cursor_pos ;
bool prev_char = false ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
while ( cc > 0 ) {
bool ischar = _is_text_char ( text [ cc - 1 ] ) ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
if ( prev_char & & ! ischar )
break ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
prev_char = ischar ;
cc - - ;
}
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
delete_text ( cc , cursor_pos ) ;
2016-06-18 16:15:26 +02:00
2017-09-10 15:37:49 +02:00
set_cursor_position ( cc ) ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
} else {
delete_char ( ) ;
}
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
} break ;
case KEY_KP_4 : {
if ( k - > get_unicode ( ) ! = 0 ) {
handled = false ;
break ;
2016-01-07 21:38:38 +01:00
}
2019-04-05 14:06:16 +02:00
FALLTHROUGH ;
2017-05-20 17:38:03 +02:00
}
case KEY_LEFT : {
2016-06-18 16:15:26 +02:00
2016-06-23 23:03:32 +02:00
# ifndef APPLE_STYLE_KEYS
2017-05-20 17:38:03 +02:00
if ( ! k - > get_alt ( ) )
2016-06-23 23:03:32 +02:00
# endif
2017-05-20 17:38:03 +02:00
shift_selection_check_pre ( k - > get_shift ( ) ) ;
2016-06-18 16:15:26 +02:00
# ifdef APPLE_STYLE_KEYS
2017-05-20 17:38:03 +02:00
if ( k - > get_command ( ) ) {
2017-09-10 15:37:49 +02:00
set_cursor_position ( 0 ) ;
2017-05-20 17:38:03 +02:00
} else if ( k - > get_alt ( ) ) {
2016-06-18 16:15:26 +02:00
# else
2017-05-20 17:38:03 +02:00
if ( k - > get_alt ( ) ) {
handled = false ;
break ;
} else if ( k - > get_command ( ) ) {
2016-06-18 16:15:26 +02:00
# endif
2017-05-20 17:38:03 +02:00
bool prev_char = false ;
int cc = cursor_pos ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
while ( cc > 0 ) {
bool ischar = _is_text_char ( text [ cc - 1 ] ) ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
if ( prev_char & & ! ischar )
break ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
prev_char = ischar ;
cc - - ;
}
2016-06-18 16:15:26 +02:00
2017-09-10 15:37:49 +02:00
set_cursor_position ( cc ) ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
} else {
2017-09-10 15:37:49 +02:00
set_cursor_position ( get_cursor_position ( ) - 1 ) ;
2017-05-20 17:38:03 +02:00
}
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
shift_selection_check_post ( k - > get_shift ( ) ) ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
} break ;
case KEY_KP_6 : {
if ( k - > get_unicode ( ) ! = 0 ) {
handled = false ;
break ;
2016-01-07 21:38:38 +01:00
}
2019-04-05 14:06:16 +02:00
FALLTHROUGH ;
2017-05-20 17:38:03 +02:00
}
case KEY_RIGHT : {
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
shift_selection_check_pre ( k - > get_shift ( ) ) ;
2016-06-18 16:15:26 +02:00
# ifdef APPLE_STYLE_KEYS
2017-05-20 17:38:03 +02:00
if ( k - > get_command ( ) ) {
2017-09-10 15:37:49 +02:00
set_cursor_position ( text . length ( ) ) ;
2017-05-20 17:38:03 +02:00
} else if ( k - > get_alt ( ) ) {
2016-06-18 16:15:26 +02:00
# else
2017-05-20 17:38:03 +02:00
if ( k - > get_alt ( ) ) {
handled = false ;
break ;
} else if ( k - > get_command ( ) ) {
2016-06-18 16:15:26 +02:00
# endif
2017-05-20 17:38:03 +02:00
bool prev_char = false ;
int cc = cursor_pos ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
while ( cc < text . length ( ) ) {
bool ischar = _is_text_char ( text [ cc ] ) ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
if ( prev_char & & ! ischar )
break ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
prev_char = ischar ;
cc + + ;
}
2016-06-18 16:15:26 +02:00
2017-09-10 15:37:49 +02:00
set_cursor_position ( cc ) ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
} else {
2017-09-10 15:37:49 +02:00
set_cursor_position ( get_cursor_position ( ) + 1 ) ;
2017-05-20 17:38:03 +02:00
}
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
shift_selection_check_post ( k - > get_shift ( ) ) ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
} break ;
2017-12-27 17:04:07 +01:00
case KEY_UP : {
shift_selection_check_pre ( k - > get_shift ( ) ) ;
2018-01-12 02:53:03 +01:00
if ( get_cursor_position ( ) = = 0 ) handled = false ;
2017-12-27 17:04:07 +01:00
set_cursor_position ( 0 ) ;
shift_selection_check_post ( k - > get_shift ( ) ) ;
} break ;
case KEY_DOWN : {
shift_selection_check_pre ( k - > get_shift ( ) ) ;
2018-01-12 02:53:03 +01:00
if ( get_cursor_position ( ) = = text . length ( ) ) handled = false ;
2017-12-27 17:04:07 +01:00
set_cursor_position ( text . length ( ) ) ;
shift_selection_check_post ( k - > get_shift ( ) ) ;
} break ;
2017-05-20 17:38:03 +02:00
case KEY_DELETE : {
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
if ( ! editable )
break ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
if ( k - > get_shift ( ) & & ! k - > get_command ( ) & & ! k - > get_alt ( ) ) {
cut_text ( ) ;
break ;
}
2016-03-15 13:03:38 +01:00
2017-05-20 17:38:03 +02:00
if ( selection . enabled ) {
selection_delete ( ) ;
break ;
}
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
int text_len = text . length ( ) ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
if ( cursor_pos = = text_len )
break ; // nothing to do
2016-06-18 16:15:26 +02:00
# ifdef APPLE_STYLE_KEYS
2017-05-20 17:38:03 +02:00
if ( k - > get_alt ( ) ) {
2016-06-18 16:15:26 +02:00
# else
2017-05-20 17:38:03 +02:00
if ( k - > get_alt ( ) ) {
handled = false ;
break ;
} else if ( k - > get_command ( ) ) {
2016-06-18 16:15:26 +02:00
# endif
2017-05-20 17:38:03 +02:00
int cc = cursor_pos ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
bool prev_char = false ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
while ( cc < text . length ( ) ) {
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
bool ischar = _is_text_char ( text [ cc ] ) ;
2016-06-18 16:15:26 +02:00
2017-05-20 17:38:03 +02:00
if ( prev_char & & ! ischar )
break ;
prev_char = ischar ;
cc + + ;
2014-02-10 02:10:30 +01:00
}
2017-05-20 17:38:03 +02:00
delete_text ( cursor_pos , cc ) ;
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
} else {
2017-09-10 15:37:49 +02:00
set_cursor_position ( cursor_pos + 1 ) ;
2017-05-20 17:38:03 +02:00
delete_char ( ) ;
2016-01-07 22:45:28 +01:00
}
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
} break ;
case KEY_KP_7 : {
if ( k - > get_unicode ( ) ! = 0 ) {
handled = false ;
break ;
}
2019-04-05 14:06:16 +02:00
FALLTHROUGH ;
2017-05-20 17:38:03 +02:00
}
case KEY_HOME : {
shift_selection_check_pre ( k - > get_shift ( ) ) ;
2017-09-10 15:37:49 +02:00
set_cursor_position ( 0 ) ;
2017-05-20 17:38:03 +02:00
shift_selection_check_post ( k - > get_shift ( ) ) ;
} break ;
case KEY_KP_1 : {
if ( k - > get_unicode ( ) ! = 0 ) {
2017-03-05 16:44:50 +01:00
handled = false ;
2017-05-20 17:38:03 +02:00
break ;
}
2019-04-05 14:06:16 +02:00
FALLTHROUGH ;
2014-02-10 02:10:30 +01:00
}
2017-05-20 17:38:03 +02:00
case KEY_END : {
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
shift_selection_check_pre ( k - > get_shift ( ) ) ;
2017-09-10 15:37:49 +02:00
set_cursor_position ( text . length ( ) ) ;
2017-05-20 17:38:03 +02:00
shift_selection_check_post ( k - > get_shift ( ) ) ;
} break ;
2016-01-07 21:38:38 +01:00
2017-05-20 17:38:03 +02:00
default : {
handled = false ;
} break ;
}
if ( handled ) {
accept_event ( ) ;
2019-06-05 10:43:32 +02:00
} else if ( ! k - > get_command ( ) ) {
2017-05-20 17:38:03 +02:00
if ( k - > get_unicode ( ) > = 32 & & k - > get_scancode ( ) ! = KEY_DELETE ) {
if ( editable ) {
selection_delete ( ) ;
CharType ucodestr [ 2 ] = { ( CharType ) k - > get_unicode ( ) , 0 } ;
append_at_cursor ( ucodestr ) ;
_text_changed ( ) ;
accept_event ( ) ;
2016-01-07 21:38:38 +01:00
}
2014-02-10 02:10:30 +01:00
2017-05-20 17:38:03 +02:00
} else {
return ;
}
2014-02-10 02:10:30 +01:00
}
2017-05-20 17:38:03 +02:00
update ( ) ;
}
2016-03-09 00:00:52 +01:00
2017-05-20 17:38:03 +02:00
return ;
2014-02-10 02:10:30 +01:00
}
}
2015-08-15 08:47:22 +02:00
void LineEdit : : set_align ( Align p_align ) {
2018-10-04 09:17:59 +02:00
ERR_FAIL_INDEX ( ( int ) p_align , 4 ) ;
2015-08-15 08:47:22 +02:00
align = p_align ;
update ( ) ;
}
2017-03-05 16:44:50 +01:00
LineEdit : : Align LineEdit : : get_align ( ) const {
2015-08-15 08:47:22 +02:00
return align ;
}
2017-03-05 16:44:50 +01:00
Variant LineEdit : : get_drag_data ( const Point2 & p_point ) {
2014-02-10 02:10:30 +01:00
if ( selection . drag_attempt & & selection . enabled ) {
String t = text . substr ( selection . begin , selection . end - selection . begin ) ;
2017-03-05 16:44:50 +01:00
Label * l = memnew ( Label ) ;
2014-02-10 02:10:30 +01:00
l - > set_text ( t ) ;
set_drag_preview ( l ) ;
2017-03-05 16:44:50 +01:00
return t ;
2014-02-10 02:10:30 +01:00
}
return Variant ( ) ;
}
2017-03-05 16:44:50 +01:00
bool LineEdit : : can_drop_data ( const Point2 & p_point , const Variant & p_data ) const {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
return p_data . get_type ( ) = = Variant : : STRING ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
void LineEdit : : drop_data ( const Point2 & p_point , const Variant & p_data ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( p_data . get_type ( ) = = Variant : : STRING ) {
2014-02-10 02:10:30 +01:00
set_cursor_at_pixel_pos ( p_point . x ) ;
2014-05-11 06:14:33 +02:00
int selected = selection . end - selection . begin ;
2015-08-15 08:47:22 +02:00
Ref < Font > font = get_font ( " font " ) ;
2015-09-02 13:36:52 +02:00
if ( font ! = NULL ) {
for ( int i = selection . begin ; i < selection . end ; i + + )
cached_width - = font - > get_char_size ( text [ i ] ) . width ;
}
2015-08-15 08:47:22 +02:00
2014-05-11 06:14:33 +02:00
text . erase ( selection . begin , selected ) ;
2015-08-15 08:47:22 +02:00
2014-02-10 02:10:30 +01:00
append_at_cursor ( p_data ) ;
2017-03-05 16:44:50 +01:00
selection . begin = cursor_pos - selected ;
2014-05-11 06:14:33 +02:00
selection . end = cursor_pos ;
2014-02-10 02:10:30 +01:00
}
}
2018-07-26 13:45:38 +02:00
Control : : CursorShape LineEdit : : get_cursor_shape ( const Point2 & p_pos ) const {
if ( ! text . empty ( ) & & is_editable ( ) & & _is_over_clear_button ( p_pos ) ) {
return CURSOR_ARROW ;
}
return Control : : get_cursor_shape ( p_pos ) ;
}
bool LineEdit : : _is_over_clear_button ( const Point2 & p_pos ) const {
if ( ! clear_button_enabled | | ! has_point ( p_pos ) ) {
return false ;
}
Ref < Texture > icon = Control : : get_icon ( " clear " ) ;
int x_ofs = get_stylebox ( " normal " ) - > get_offset ( ) . x ;
2019-06-26 15:08:25 +02:00
return p_pos . x > get_size ( ) . width - icon - > get_width ( ) - x_ofs ;
2018-07-26 13:45:38 +02:00
}
2014-02-10 02:10:30 +01:00
void LineEdit : : _notification ( int p_what ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
switch ( p_what ) {
2016-06-21 15:38:35 +02:00
# ifdef TOOLS_ENABLED
case NOTIFICATION_ENTER_TREE : {
2017-09-26 09:19:02 +02:00
if ( Engine : : get_singleton ( ) - > is_editor_hint ( ) & & ! get_tree ( ) - > is_node_being_edited ( this ) ) {
2017-01-05 23:41:36 +01:00
cursor_set_blink_enabled ( EDITOR_DEF ( " text_editor/cursor/caret_blink " , false ) ) ;
cursor_set_blink_speed ( EDITOR_DEF ( " text_editor/cursor/caret_blink_speed " , 0.65 ) ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( ! EditorSettings : : get_singleton ( ) - > is_connected ( " settings_changed " , this , " _editor_settings_changed " ) ) {
EditorSettings : : get_singleton ( ) - > connect ( " settings_changed " , this , " _editor_settings_changed " ) ;
2016-06-30 16:12:14 +02:00
}
2016-06-21 15:38:35 +02:00
}
} break ;
# endif
2014-02-10 02:10:30 +01:00
case NOTIFICATION_RESIZED : {
2016-03-09 00:00:52 +01:00
2019-05-15 16:09:44 +02:00
window_pos = 0 ;
2017-09-10 15:37:49 +02:00
set_cursor_position ( get_cursor_position ( ) ) ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
} break ;
2019-06-22 14:42:36 +02:00
case NOTIFICATION_TRANSLATION_CHANGED : {
placeholder_translated = tr ( placeholder ) ;
update_placeholder_width ( ) ;
update ( ) ;
} break ;
2016-06-21 01:16:18 +02:00
case MainLoop : : NOTIFICATION_WM_FOCUS_IN : {
window_has_focus = true ;
draw_caret = true ;
update ( ) ;
} break ;
case MainLoop : : NOTIFICATION_WM_FOCUS_OUT : {
window_has_focus = false ;
draw_caret = false ;
update ( ) ;
} break ;
2014-02-10 02:10:30 +01:00
case NOTIFICATION_DRAW : {
2016-03-09 00:00:52 +01:00
2016-06-21 01:16:18 +02:00
if ( ( ! has_focus ( ) & & ! menu - > has_focus ( ) ) | | ! window_has_focus ) {
draw_caret = false ;
}
2017-03-05 16:44:50 +01:00
int width , height ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
Size2 size = get_size ( ) ;
width = size . width ;
height = size . height ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
RID ci = get_canvas_item ( ) ;
2016-03-09 00:00:52 +01:00
2017-05-02 23:02:06 +02:00
Ref < StyleBox > style = get_stylebox ( " normal " ) ;
2017-07-15 06:40:17 +02:00
if ( ! is_editable ( ) ) {
2017-03-05 16:44:50 +01:00
style = get_stylebox ( " read_only " ) ;
2017-07-15 06:40:17 +02:00
draw_caret = false ;
}
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
Ref < Font > font = get_font ( " font " ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
style - > draw ( ci , Rect2 ( Point2 ( ) , size ) ) ;
2014-02-10 02:10:30 +01:00
if ( has_focus ( ) ) {
2017-03-05 16:44:50 +01:00
get_stylebox ( " focus " ) - > draw ( ci , Rect2 ( Point2 ( ) , size ) ) ;
2014-02-10 02:10:30 +01:00
}
2017-03-05 16:44:50 +01:00
int x_ofs = 0 ;
2018-06-13 17:33:37 +02:00
bool using_placeholder = text . empty ( ) ;
int cached_text_width = using_placeholder ? cached_placeholder_width : cached_width ;
2015-08-15 08:47:22 +02:00
switch ( align ) {
2016-03-09 00:00:52 +01:00
2015-08-15 08:47:22 +02:00
case ALIGN_FILL :
case ALIGN_LEFT : {
2017-03-05 16:44:50 +01:00
x_ofs = style - > get_offset ( ) . x ;
2015-08-15 08:47:22 +02:00
} break ;
case ALIGN_CENTER : {
2017-10-01 20:11:46 +02:00
if ( window_pos ! = 0 )
x_ofs = style - > get_offset ( ) . x ;
else
2018-04-09 22:08:53 +02:00
x_ofs = MAX ( style - > get_margin ( MARGIN_LEFT ) , int ( size . width - ( cached_text_width ) ) / 2 ) ;
2015-08-15 08:47:22 +02:00
} break ;
case ALIGN_RIGHT : {
2018-04-09 22:08:53 +02:00
x_ofs = MAX ( style - > get_margin ( MARGIN_LEFT ) , int ( size . width - style - > get_margin ( MARGIN_RIGHT ) - ( cached_text_width ) ) ) ;
2015-08-15 08:47:22 +02:00
} break ;
}
2018-04-09 22:08:53 +02:00
int ofs_max = width - style - > get_margin ( MARGIN_RIGHT ) ;
2017-03-05 16:44:50 +01:00
int char_ofs = window_pos ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
int y_area = height - style - > get_minimum_size ( ) . height ;
2018-08-10 18:15:26 +02:00
int y_ofs = style - > get_offset ( ) . y + ( y_area - font - > get_height ( ) ) / 2 ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
int font_ascent = font - > get_ascent ( ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
Color selection_color = get_color ( " selection_color " ) ;
2019-06-22 01:16:38 +02:00
Color font_color = is_editable ( ) ? get_color ( " font_color " ) : get_color ( " font_color_uneditable " ) ;
2017-03-05 16:44:50 +01:00
Color font_color_selected = get_color ( " font_color_selected " ) ;
Color cursor_color = get_color ( " cursor_color " ) ;
2016-03-09 00:00:52 +01:00
2019-06-22 14:42:36 +02:00
const String & t = using_placeholder ? placeholder_translated : text ;
2016-06-27 13:47:40 +02:00
// draw placeholder color
2018-06-13 17:33:37 +02:00
if ( using_placeholder )
2016-06-28 05:45:17 +02:00
font_color . a * = placeholder_alpha ;
2016-06-27 13:47:40 +02:00
2018-07-26 13:45:38 +02:00
bool display_clear_icon = ! using_placeholder & & is_editable ( ) & & clear_button_enabled ;
2018-08-11 12:04:19 +02:00
if ( right_icon . is_valid ( ) | | display_clear_icon ) {
Ref < Texture > r_icon = display_clear_icon ? Control : : get_icon ( " clear " ) : right_icon ;
2019-06-22 01:16:38 +02:00
Color color_icon ( 1 , 1 , 1 , ! is_editable ( ) ? .5 * .9 : .9 ) ;
2018-07-26 13:45:38 +02:00
if ( display_clear_icon ) {
if ( clear_button_status . press_attempt & & clear_button_status . pressing_inside ) {
color_icon = get_color ( " clear_button_color_pressed " ) ;
} else {
color_icon = get_color ( " clear_button_color " ) ;
}
}
r_icon - > draw ( ci , Point2 ( width - r_icon - > get_width ( ) - style - > get_margin ( MARGIN_RIGHT ) , height / 2 - r_icon - > get_height ( ) / 2 ) , color_icon ) ;
if ( align = = ALIGN_CENTER ) {
if ( window_pos = = 0 ) {
x_ofs = MAX ( style - > get_margin ( MARGIN_LEFT ) , int ( size . width - cached_text_width - r_icon - > get_width ( ) - style - > get_margin ( MARGIN_RIGHT ) * 2 ) / 2 ) ;
}
} else {
x_ofs = MAX ( style - > get_margin ( MARGIN_LEFT ) , x_ofs - r_icon - > get_width ( ) - style - > get_margin ( MARGIN_RIGHT ) ) ;
}
2019-04-21 18:55:40 +02:00
ofs_max - = r_icon - > get_width ( ) ;
2017-07-18 21:35:37 +02:00
}
2016-09-28 22:05:34 +02:00
int caret_height = font - > get_height ( ) > y_area ? y_area : font - > get_height ( ) ;
2018-03-17 09:44:34 +01:00
FontDrawer drawer ( font , Color ( 1 , 1 , 1 ) ) ;
2017-03-05 16:44:50 +01:00
while ( true ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
//end of string, break!
if ( char_ofs > = t . length ( ) )
2014-02-10 02:10:30 +01:00
break ;
2017-08-07 13:09:56 +02:00
if ( char_ofs = = cursor_pos ) {
if ( ime_text . length ( ) > 0 ) {
int ofs = 0 ;
while ( true ) {
if ( ofs > = ime_text . length ( ) )
break ;
2018-04-28 20:24:48 +02:00
CharType cchar = ( pass & & ! text . empty ( ) ) ? secret_character [ 0 ] : ime_text [ ofs ] ;
CharType next = ( pass & & ! text . empty ( ) ) ? secret_character [ 0 ] : ime_text [ ofs + 1 ] ;
2017-08-07 13:09:56 +02:00
int im_char_width = font - > get_char_size ( cchar , next ) . width ;
if ( ( x_ofs + im_char_width ) > ofs_max )
break ;
bool selected = ofs > = ime_selection . x & & ofs < ime_selection . x + ime_selection . y ;
if ( selected ) {
VisualServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( Point2 ( x_ofs , y_ofs + caret_height ) , Size2 ( im_char_width , 3 ) ) , font_color ) ;
} else {
VisualServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( Point2 ( x_ofs , y_ofs + caret_height ) , Size2 ( im_char_width , 1 ) ) , font_color ) ;
}
2018-03-17 09:44:34 +01:00
drawer . draw_char ( ci , Point2 ( x_ofs , y_ofs + font_ascent ) , cchar , next , font_color ) ;
2017-08-07 13:09:56 +02:00
x_ofs + = im_char_width ;
ofs + + ;
}
}
}
2018-04-28 20:24:48 +02:00
CharType cchar = ( pass & & ! text . empty ( ) ) ? secret_character [ 0 ] : t [ char_ofs ] ;
CharType next = ( pass & & ! text . empty ( ) ) ? secret_character [ 0 ] : t [ char_ofs + 1 ] ;
2017-03-05 16:44:50 +01:00
int char_width = font - > get_char_size ( cchar , next ) . width ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
// end of widget, break!
2015-08-15 08:47:22 +02:00
if ( ( x_ofs + char_width ) > ofs_max )
2014-02-10 02:10:30 +01:00
break ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
bool selected = selection . enabled & & char_ofs > = selection . begin & & char_ofs < selection . end ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( selected )
2016-09-28 22:05:34 +02:00
VisualServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( Point2 ( x_ofs , y_ofs ) , Size2 ( char_width , caret_height ) ) , selection_color ) ;
2016-03-09 00:00:52 +01:00
2018-07-01 16:46:33 +02:00
int yofs = y_ofs + ( caret_height - font - > get_height ( ) ) / 2 ;
drawer . draw_char ( ci , Point2 ( x_ofs , yofs + font_ascent ) , cchar , next , selected ? font_color_selected : font_color ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( char_ofs = = cursor_pos & & draw_caret ) {
2017-08-07 13:09:56 +02:00
if ( ime_text . length ( ) = = 0 ) {
2018-07-26 23:41:47 +02:00
# ifdef TOOLS_ENABLED
VisualServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( Point2 ( x_ofs , y_ofs ) , Size2 ( Math : : round ( EDSCALE ) , caret_height ) ) , cursor_color ) ;
# else
2017-08-07 13:09:56 +02:00
VisualServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( Point2 ( x_ofs , y_ofs ) , Size2 ( 1 , caret_height ) ) , cursor_color ) ;
2018-07-26 23:41:47 +02:00
# endif
2017-08-07 13:09:56 +02:00
}
2016-06-21 01:05:52 +02:00
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
x_ofs + = char_width ;
2014-02-10 02:10:30 +01:00
char_ofs + + ;
}
2017-08-07 13:09:56 +02:00
if ( char_ofs = = cursor_pos ) {
if ( ime_text . length ( ) > 0 ) {
int ofs = 0 ;
while ( true ) {
if ( ofs > = ime_text . length ( ) )
break ;
2018-04-28 20:24:48 +02:00
CharType cchar = ( pass & & ! text . empty ( ) ) ? secret_character [ 0 ] : ime_text [ ofs ] ;
CharType next = ( pass & & ! text . empty ( ) ) ? secret_character [ 0 ] : ime_text [ ofs + 1 ] ;
2017-08-07 13:09:56 +02:00
int im_char_width = font - > get_char_size ( cchar , next ) . width ;
if ( ( x_ofs + im_char_width ) > ofs_max )
break ;
bool selected = ofs > = ime_selection . x & & ofs < ime_selection . x + ime_selection . y ;
if ( selected ) {
VisualServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( Point2 ( x_ofs , y_ofs + caret_height ) , Size2 ( im_char_width , 3 ) ) , font_color ) ;
} else {
VisualServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( Point2 ( x_ofs , y_ofs + caret_height ) , Size2 ( im_char_width , 1 ) ) , font_color ) ;
}
2018-03-17 09:44:34 +01:00
drawer . draw_char ( ci , Point2 ( x_ofs , y_ofs + font_ascent ) , cchar , next , font_color ) ;
2017-08-07 13:09:56 +02:00
x_ofs + = im_char_width ;
ofs + + ;
}
}
}
2017-03-05 16:44:50 +01:00
if ( char_ofs = = cursor_pos & & draw_caret ) { //may be at the end
2017-08-07 13:09:56 +02:00
if ( ime_text . length ( ) = = 0 ) {
2018-07-26 23:41:47 +02:00
# ifdef TOOLS_ENABLED
VisualServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( Point2 ( x_ofs , y_ofs ) , Size2 ( Math : : round ( EDSCALE ) , caret_height ) ) , cursor_color ) ;
# else
2017-08-07 13:09:56 +02:00
VisualServer : : get_singleton ( ) - > canvas_item_add_rect ( ci , Rect2 ( Point2 ( x_ofs , y_ofs ) , Size2 ( 1 , caret_height ) ) , cursor_color ) ;
2018-07-26 23:41:47 +02:00
# endif
2017-08-07 13:09:56 +02:00
}
2016-06-21 01:05:52 +02:00
}
2017-06-25 17:50:45 +02:00
if ( has_focus ( ) ) {
2018-06-07 22:16:57 +02:00
OS : : get_singleton ( ) - > set_ime_active ( true ) ;
2018-06-13 17:33:37 +02:00
OS : : get_singleton ( ) - > set_ime_position ( get_global_position ( ) + Point2 ( using_placeholder ? 0 : x_ofs , y_ofs + caret_height ) ) ;
2017-06-25 17:50:45 +02:00
}
2014-02-10 02:10:30 +01:00
} break ;
case NOTIFICATION_FOCUS_ENTER : {
2016-06-21 01:16:18 +02:00
if ( ! caret_blink_enabled ) {
draw_caret = true ;
}
2018-06-07 22:16:57 +02:00
OS : : get_singleton ( ) - > set_ime_active ( true ) ;
2017-09-10 15:37:49 +02:00
Point2 cursor_pos = Point2 ( get_cursor_position ( ) , 1 ) * get_minimum_size ( ) . height ;
2017-06-25 17:50:45 +02:00
OS : : get_singleton ( ) - > set_ime_position ( get_global_position ( ) + cursor_pos ) ;
2014-02-10 02:10:30 +01:00
if ( OS : : get_singleton ( ) - > has_virtual_keyboard ( ) )
2017-03-05 16:44:50 +01:00
OS : : get_singleton ( ) - > show_virtual_keyboard ( text , get_global_rect ( ) ) ;
2014-02-10 02:10:30 +01:00
} break ;
case NOTIFICATION_FOCUS_EXIT : {
2017-06-25 17:50:45 +02:00
OS : : get_singleton ( ) - > set_ime_position ( Point2 ( ) ) ;
2018-06-07 22:16:57 +02:00
OS : : get_singleton ( ) - > set_ime_active ( false ) ;
2017-08-07 13:09:56 +02:00
ime_text = " " ;
ime_selection = Point2 ( ) ;
2017-06-25 17:50:45 +02:00
2014-02-10 02:10:30 +01:00
if ( OS : : get_singleton ( ) - > has_virtual_keyboard ( ) )
OS : : get_singleton ( ) - > hide_virtual_keyboard ( ) ;
} break ;
2018-11-23 13:07:48 +01:00
case MainLoop : : NOTIFICATION_OS_IME_UPDATE : {
2019-01-08 21:52:56 +01:00
if ( has_focus ( ) ) {
ime_text = OS : : get_singleton ( ) - > get_ime_text ( ) ;
ime_selection = OS : : get_singleton ( ) - > get_ime_selection ( ) ;
update ( ) ;
}
2018-11-23 13:07:48 +01:00
} break ;
2014-02-10 02:10:30 +01:00
}
}
void LineEdit : : copy_text ( ) {
2016-03-09 00:00:52 +01:00
2018-08-24 11:35:46 +02:00
if ( selection . enabled & & ! pass ) {
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > set_clipboard ( text . substr ( selection . begin , selection . end - selection . begin ) ) ;
}
}
void LineEdit : : cut_text ( ) {
2016-03-09 00:00:52 +01:00
2018-08-24 11:35:46 +02:00
if ( selection . enabled & & ! pass ) {
2014-02-10 02:10:30 +01:00
OS : : get_singleton ( ) - > set_clipboard ( text . substr ( selection . begin , selection . end - selection . begin ) ) ;
selection_delete ( ) ;
}
}
void LineEdit : : paste_text ( ) {
2016-03-09 00:00:52 +01:00
2019-05-31 15:27:53 +02:00
// Strip escape characters like \n and \t as they can't be displayed on LineEdit.
String paste_buffer = OS : : get_singleton ( ) - > get_clipboard ( ) . strip_escapes ( ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( paste_buffer ! = " " ) {
2014-02-10 02:10:30 +01:00
2017-03-05 16:44:50 +01:00
if ( selection . enabled ) selection_delete ( ) ;
2014-02-10 02:10:30 +01:00
append_at_cursor ( paste_buffer ) ;
2018-02-05 16:22:34 +01:00
if ( ! text_changed_dirty ) {
if ( is_inside_tree ( ) ) {
MessageQueue : : get_singleton ( ) - > push_call ( this , " _text_changed " ) ;
}
text_changed_dirty = true ;
}
2014-02-10 02:10:30 +01:00
}
2016-05-17 01:25:17 +02:00
}
void LineEdit : : undo ( ) {
2017-10-30 00:14:33 +01:00
if ( undo_stack_pos = = NULL ) {
if ( undo_stack . size ( ) < = 1 ) {
return ;
}
undo_stack_pos = undo_stack . back ( ) ;
} else if ( undo_stack_pos = = undo_stack . front ( ) ) {
return ;
2016-05-17 01:25:17 +02:00
}
2017-10-30 00:14:33 +01:00
undo_stack_pos = undo_stack_pos - > prev ( ) ;
TextOperation op = undo_stack_pos - > get ( ) ;
text = op . text ;
set_cursor_position ( op . cursor_pos ) ;
2019-04-21 10:51:10 +02:00
if ( expand_to_text_length )
minimum_size_changed ( ) ;
2017-10-30 00:14:33 +01:00
_emit_text_change ( ) ;
}
2016-05-17 01:25:17 +02:00
2017-10-30 00:14:33 +01:00
void LineEdit : : redo ( ) {
if ( undo_stack_pos = = NULL ) {
return ;
}
if ( undo_stack_pos = = undo_stack . back ( ) ) {
return ;
}
undo_stack_pos = undo_stack_pos - > next ( ) ;
TextOperation op = undo_stack_pos - > get ( ) ;
text = op . text ;
set_cursor_position ( op . cursor_pos ) ;
2019-04-21 10:51:10 +02:00
if ( expand_to_text_length )
minimum_size_changed ( ) ;
2017-10-30 00:14:33 +01:00
_emit_text_change ( ) ;
2014-02-10 02:10:30 +01:00
}
void LineEdit : : shift_selection_check_pre ( bool p_shift ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( ! selection . enabled & & p_shift ) {
selection . cursor_start = cursor_pos ;
2014-02-10 02:10:30 +01:00
}
if ( ! p_shift )
2017-12-17 18:40:44 +01:00
deselect ( ) ;
2014-02-10 02:10:30 +01:00
}
void LineEdit : : shift_selection_check_post ( bool p_shift ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( p_shift )
selection_fill_at_cursor ( ) ;
}
void LineEdit : : set_cursor_at_pixel_pos ( int p_x ) {
2016-03-09 00:00:52 +01:00
2015-08-15 08:47:22 +02:00
Ref < Font > font = get_font ( " font " ) ;
int ofs = window_pos ;
Ref < StyleBox > style = get_stylebox ( " normal " ) ;
int pixel_ofs = 0 ;
Size2 size = get_size ( ) ;
2019-07-16 00:32:41 +02:00
bool display_clear_icon = ! text . empty ( ) & & is_editable ( ) & & clear_button_enabled ;
int r_icon_width = Control : : get_icon ( " clear " ) - > get_width ( ) ;
2015-08-15 08:47:22 +02:00
switch ( align ) {
2016-03-09 00:00:52 +01:00
2015-08-15 08:47:22 +02:00
case ALIGN_FILL :
case ALIGN_LEFT : {
2016-03-09 00:00:52 +01:00
2015-08-15 08:47:22 +02:00
pixel_ofs = int ( style - > get_offset ( ) . x ) ;
} break ;
case ALIGN_CENTER : {
2017-10-01 20:11:46 +02:00
if ( window_pos ! = 0 )
pixel_ofs = int ( style - > get_offset ( ) . x ) ;
else
pixel_ofs = int ( size . width - ( cached_width ) ) / 2 ;
2019-07-16 00:32:41 +02:00
if ( display_clear_icon )
pixel_ofs - = int ( r_icon_width / 2 + style - > get_margin ( MARGIN_RIGHT ) ) ;
2015-08-15 08:47:22 +02:00
} break ;
case ALIGN_RIGHT : {
2018-04-09 22:08:53 +02:00
pixel_ofs = int ( size . width - style - > get_margin ( MARGIN_RIGHT ) - ( cached_width ) ) ;
2019-07-16 00:32:41 +02:00
if ( display_clear_icon )
pixel_ofs - = int ( r_icon_width + style - > get_margin ( MARGIN_RIGHT ) ) ;
2015-08-15 08:47:22 +02:00
} break ;
}
2017-03-05 16:44:50 +01:00
while ( ofs < text . length ( ) ) {
2016-03-09 00:00:52 +01:00
2015-09-02 13:36:52 +02:00
int char_w = 0 ;
if ( font ! = NULL ) {
2015-12-07 20:31:21 +01:00
char_w = font - > get_char_size ( text [ ofs ] ) . width ;
2015-09-02 13:36:52 +02:00
}
2017-03-05 16:44:50 +01:00
pixel_ofs + = char_w ;
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( pixel_ofs > p_x ) { //found what we look for
break ;
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
ofs + + ;
}
2016-03-09 00:00:52 +01:00
2017-09-10 15:37:49 +02:00
set_cursor_position ( ofs ) ;
2014-02-10 02:10:30 +01:00
}
2016-06-21 01:05:52 +02:00
bool LineEdit : : cursor_get_blink_enabled ( ) const {
return caret_blink_enabled ;
}
void LineEdit : : cursor_set_blink_enabled ( const bool p_enabled ) {
caret_blink_enabled = p_enabled ;
if ( p_enabled ) {
caret_blink_timer - > start ( ) ;
} else {
caret_blink_timer - > stop ( ) ;
}
draw_caret = true ;
}
float LineEdit : : cursor_get_blink_speed ( ) const {
return caret_blink_timer - > get_wait_time ( ) ;
}
void LineEdit : : cursor_set_blink_speed ( const float p_speed ) {
ERR_FAIL_COND ( p_speed < = 0 ) ;
caret_blink_timer - > set_wait_time ( p_speed ) ;
}
void LineEdit : : _reset_caret_blink_timer ( ) {
if ( caret_blink_enabled ) {
caret_blink_timer - > stop ( ) ;
caret_blink_timer - > start ( ) ;
draw_caret = true ;
update ( ) ;
}
2017-03-05 16:44:50 +01:00
}
2016-06-21 01:05:52 +02:00
void LineEdit : : _toggle_draw_caret ( ) {
draw_caret = ! draw_caret ;
2017-01-13 14:45:50 +01:00
if ( is_visible_in_tree ( ) & & has_focus ( ) & & window_has_focus ) {
2016-06-21 01:05:52 +02:00
update ( ) ;
}
}
2014-02-10 02:10:30 +01:00
void LineEdit : : delete_char ( ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( ( text . length ( ) < = 0 ) | | ( cursor_pos = = 0 ) ) return ;
2016-03-09 00:00:52 +01:00
2015-08-15 08:47:22 +02:00
Ref < Font > font = get_font ( " font " ) ;
2015-09-02 13:36:52 +02:00
if ( font ! = NULL ) {
cached_width - = font - > get_char_size ( text [ cursor_pos - 1 ] ) . width ;
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
text . erase ( cursor_pos - 1 , 1 ) ;
2016-03-09 00:00:52 +01:00
2017-09-10 15:37:49 +02:00
set_cursor_position ( get_cursor_position ( ) - 1 ) ;
2016-03-09 00:00:52 +01:00
2016-09-07 01:34:24 +02:00
_text_changed ( ) ;
2014-02-10 02:10:30 +01:00
}
2016-06-18 16:15:26 +02:00
void LineEdit : : delete_text ( int p_from_column , int p_to_column ) {
2017-03-05 16:44:50 +01:00
if ( text . size ( ) > 0 ) {
2016-06-18 16:15:26 +02:00
Ref < Font > font = get_font ( " font " ) ;
if ( font ! = NULL ) {
for ( int i = p_from_column ; i < p_to_column ; i + + )
cached_width - = font - > get_char_size ( text [ i ] ) . width ;
}
2017-03-05 16:44:50 +01:00
} else {
2016-06-18 16:15:26 +02:00
cached_width = 0 ;
}
2017-03-05 16:44:50 +01:00
text . erase ( p_from_column , p_to_column - p_from_column ) ;
cursor_pos - = CLAMP ( cursor_pos - p_from_column , 0 , p_to_column - p_from_column ) ;
2016-06-18 16:15:26 +02:00
2017-03-05 16:44:50 +01:00
if ( cursor_pos > = text . length ( ) ) {
2016-06-18 16:15:26 +02:00
2017-03-05 16:44:50 +01:00
cursor_pos = text . length ( ) ;
2016-06-18 16:15:26 +02:00
}
2017-03-05 16:44:50 +01:00
if ( window_pos > cursor_pos ) {
2016-06-18 16:15:26 +02:00
2017-03-05 16:44:50 +01:00
window_pos = cursor_pos ;
2016-06-18 16:15:26 +02:00
}
2018-02-05 16:22:34 +01:00
if ( ! text_changed_dirty ) {
if ( is_inside_tree ( ) ) {
MessageQueue : : get_singleton ( ) - > push_call ( this , " _text_changed " ) ;
}
text_changed_dirty = true ;
}
2016-06-18 16:15:26 +02:00
}
2014-02-10 02:10:30 +01:00
void LineEdit : : set_text ( String p_text ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
clear_internal ( ) ;
append_at_cursor ( p_text ) ;
update ( ) ;
2017-03-05 16:44:50 +01:00
cursor_pos = 0 ;
window_pos = 0 ;
2014-02-10 02:10:30 +01:00
}
void LineEdit : : clear ( ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
clear_internal ( ) ;
2016-09-07 01:34:24 +02:00
_text_changed ( ) ;
2014-02-10 02:10:30 +01:00
}
String LineEdit : : get_text ( ) const {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
return text ;
}
2016-06-27 13:47:40 +02:00
void LineEdit : : set_placeholder ( String p_text ) {
2019-06-22 14:42:36 +02:00
placeholder = p_text ;
placeholder_translated = tr ( placeholder ) ;
update_placeholder_width ( ) ;
2016-06-27 13:47:40 +02:00
update ( ) ;
}
String LineEdit : : get_placeholder ( ) const {
return placeholder ;
}
2016-06-28 05:45:17 +02:00
void LineEdit : : set_placeholder_alpha ( float p_alpha ) {
placeholder_alpha = p_alpha ;
update ( ) ;
}
float LineEdit : : get_placeholder_alpha ( ) const {
return placeholder_alpha ;
}
2017-09-10 15:37:49 +02:00
void LineEdit : : set_cursor_position ( int p_pos ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( p_pos > ( int ) text . length ( ) )
p_pos = text . length ( ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( p_pos < 0 )
p_pos = 0 ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
cursor_pos = p_pos ;
2016-03-09 00:00:52 +01:00
2014-11-06 01:20:42 +01:00
if ( ! is_inside_tree ( ) ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
window_pos = cursor_pos ;
2014-02-10 02:10:30 +01:00
return ;
}
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
Ref < StyleBox > style = get_stylebox ( " normal " ) ;
2017-03-05 16:44:50 +01:00
Ref < Font > font = get_font ( " font " ) ;
2016-03-09 00:00:52 +01:00
2017-10-20 21:24:41 +02:00
if ( cursor_pos < = window_pos ) {
2014-02-10 02:10:30 +01:00
/* Adjust window if cursor goes too much to the left */
2019-02-19 22:59:09 +01:00
set_window_pos ( MAX ( 0 , cursor_pos - 1 ) ) ;
2019-07-07 23:08:51 +02:00
} else {
2014-02-10 02:10:30 +01:00
/* Adjust window if cursor goes too much to the right */
2017-03-05 16:44:50 +01:00
int window_width = get_size ( ) . width - style - > get_minimum_size ( ) . width ;
2019-04-20 23:22:37 +02:00
bool display_clear_icon = ! text . empty ( ) & & is_editable ( ) & & clear_button_enabled ;
if ( right_icon . is_valid ( ) | | display_clear_icon ) {
Ref < Texture > r_icon = display_clear_icon ? Control : : get_icon ( " clear " ) : right_icon ;
window_width - = r_icon - > get_width ( ) ;
2017-12-07 01:13:34 +01:00
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( window_width < 0 )
2014-02-10 02:10:30 +01:00
return ;
2017-03-05 16:44:50 +01:00
int wp = window_pos ;
2016-03-09 00:00:52 +01:00
2016-06-12 17:05:21 +02:00
if ( font . is_valid ( ) ) {
2017-03-05 16:44:50 +01:00
int accum_width = 0 ;
2016-06-12 17:05:21 +02:00
2017-03-05 16:44:50 +01:00
for ( int i = cursor_pos ; i > = window_pos ; i - - ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( i > = text . length ( ) ) {
2018-06-19 03:10:48 +02:00
//do not do this, because if the cursor is at the end, its just fine that it takes no space
//accum_width = font->get_char_size(' ').width; //anything should do
2016-06-12 17:05:21 +02:00
} else {
2017-03-05 16:44:50 +01:00
accum_width + = font - > get_char_size ( text [ i ] , i + 1 < text . length ( ) ? text [ i + 1 ] : 0 ) . width ; //anything should do
2016-06-12 17:05:21 +02:00
}
2018-06-19 03:10:48 +02:00
if ( accum_width > window_width )
2016-06-12 17:05:21 +02:00
break ;
2015-09-02 13:36:52 +02:00
2017-03-05 16:44:50 +01:00
wp = i ;
2015-09-02 13:36:52 +02:00
}
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( wp ! = window_pos )
set_window_pos ( wp ) ;
2014-02-10 02:10:30 +01:00
}
update ( ) ;
}
2017-09-10 15:37:49 +02:00
int LineEdit : : get_cursor_position ( ) const {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
return cursor_pos ;
}
void LineEdit : : set_window_pos ( int p_pos ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
window_pos = p_pos ;
if ( window_pos < 0 ) window_pos = 0 ;
2014-02-10 02:10:30 +01:00
}
void LineEdit : : append_at_cursor ( String p_text ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( ( max_length < = 0 ) | | ( text . length ( ) + p_text . length ( ) < = max_length ) ) {
2016-03-09 00:00:52 +01:00
2015-08-15 08:47:22 +02:00
Ref < Font > font = get_font ( " font " ) ;
2015-09-02 13:36:52 +02:00
if ( font ! = NULL ) {
for ( int i = 0 ; i < p_text . length ( ) ; i + + )
cached_width + = font - > get_char_size ( p_text [ i ] ) . width ;
2017-03-05 16:44:50 +01:00
} else {
2015-09-02 13:36:52 +02:00
cached_width = 0 ;
}
2015-08-15 08:47:22 +02:00
2017-03-05 16:44:50 +01:00
String pre = text . substr ( 0 , cursor_pos ) ;
String post = text . substr ( cursor_pos , text . length ( ) - cursor_pos ) ;
text = pre + p_text + post ;
2017-09-10 15:37:49 +02:00
set_cursor_position ( cursor_pos + p_text . length ( ) ) ;
2014-02-10 02:10:30 +01:00
}
}
void LineEdit : : clear_internal ( ) {
2016-03-09 00:00:52 +01:00
2019-03-31 17:32:24 +02:00
deselect ( ) ;
2017-10-30 00:14:33 +01:00
_clear_undo_stack ( ) ;
2015-08-15 08:47:22 +02:00
cached_width = 0 ;
2017-03-05 16:44:50 +01:00
cursor_pos = 0 ;
window_pos = 0 ;
undo_text = " " ;
text = " " ;
2014-02-10 02:10:30 +01:00
update ( ) ;
}
Size2 LineEdit : : get_minimum_size ( ) const {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
Ref < StyleBox > style = get_stylebox ( " normal " ) ;
2017-03-05 16:44:50 +01:00
Ref < Font > font = get_font ( " font " ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
Size2 min = style - > get_minimum_size ( ) ;
min . height + = font - > get_height ( ) ;
2016-09-07 01:34:24 +02:00
//minimum size of text
int space_size = font - > get_char_size ( ' ' ) . x ;
2017-03-05 16:44:50 +01:00
int mstext = get_constant ( " minimum_spaces " ) * space_size ;
2016-09-07 01:34:24 +02:00
if ( expand_to_text_length ) {
2018-06-19 03:10:48 +02:00
mstext = MAX ( mstext , font - > get_string_size ( text ) . x + space_size ) ; //add a spce because some fonts are too exact, and because cursor needs a bit more when at the end
2016-09-07 01:34:24 +02:00
}
2017-03-05 16:44:50 +01:00
min . width + = mstext ;
2016-09-07 01:34:24 +02:00
2014-02-10 02:10:30 +01:00
return min ;
}
/* selection */
2017-12-17 18:40:44 +01:00
void LineEdit : : deselect ( ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
selection . begin = 0 ;
selection . end = 0 ;
selection . cursor_start = 0 ;
selection . enabled = false ;
selection . creating = false ;
selection . doubleclick = false ;
2014-02-10 02:10:30 +01:00
update ( ) ;
}
void LineEdit : : selection_delete ( ) {
2016-03-09 00:00:52 +01:00
2016-06-18 16:15:26 +02:00
if ( selection . enabled )
2017-03-05 16:44:50 +01:00
delete_text ( selection . begin , selection . end ) ;
2016-03-09 00:00:52 +01:00
2017-12-17 18:40:44 +01:00
deselect ( ) ;
2014-02-10 02:10:30 +01:00
}
void LineEdit : : set_max_length ( int p_max_length ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
ERR_FAIL_COND ( p_max_length < 0 ) ;
2014-02-10 02:10:30 +01:00
max_length = p_max_length ;
set_text ( text ) ;
}
int LineEdit : : get_max_length ( ) const {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
return max_length ;
}
void LineEdit : : selection_fill_at_cursor ( ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
selection . begin = cursor_pos ;
selection . end = selection . cursor_start ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
if ( selection . end < selection . begin ) {
2019-01-14 23:04:47 +01:00
int aux = selection . end ;
2017-03-05 16:44:50 +01:00
selection . end = selection . begin ;
selection . begin = aux ;
2014-02-10 02:10:30 +01:00
}
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
selection . enabled = ( selection . begin ! = selection . end ) ;
2014-02-10 02:10:30 +01:00
}
void LineEdit : : select_all ( ) {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
if ( ! text . length ( ) )
return ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
selection . begin = 0 ;
selection . end = text . length ( ) ;
selection . enabled = true ;
2014-02-10 02:10:30 +01:00
update ( ) ;
}
2018-04-28 20:24:48 +02:00
2014-02-10 02:10:30 +01:00
void LineEdit : : set_editable ( bool p_editable ) {
2016-03-09 00:00:52 +01:00
2019-04-22 01:09:52 +02:00
if ( editable = = p_editable )
return ;
2017-03-05 16:44:50 +01:00
editable = p_editable ;
2019-04-22 01:09:52 +02:00
// Reorganize context menu.
menu - > clear ( ) ;
if ( editable )
menu - > add_item ( RTR ( " Cut " ) , MENU_CUT , KEY_MASK_CMD | KEY_X ) ;
menu - > add_item ( RTR ( " Copy " ) , MENU_COPY , KEY_MASK_CMD | KEY_C ) ;
if ( editable )
menu - > add_item ( RTR ( " Paste " ) , MENU_PASTE , KEY_MASK_CMD | KEY_V ) ;
menu - > add_separator ( ) ;
menu - > add_item ( RTR ( " Select All " ) , MENU_SELECT_ALL , KEY_MASK_CMD | KEY_A ) ;
if ( editable ) {
menu - > add_item ( RTR ( " Clear " ) , MENU_CLEAR ) ;
menu - > add_separator ( ) ;
menu - > add_item ( RTR ( " Undo " ) , MENU_UNDO , KEY_MASK_CMD | KEY_Z ) ;
menu - > add_item ( RTR ( " Redo " ) , MENU_REDO , KEY_MASK_CMD | KEY_MASK_SHIFT | KEY_Z ) ;
}
2014-02-10 02:10:30 +01:00
update ( ) ;
}
bool LineEdit : : is_editable ( ) const {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
return editable ;
}
void LineEdit : : set_secret ( bool p_secret ) {
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
pass = p_secret ;
2014-02-10 02:10:30 +01:00
update ( ) ;
}
2018-04-28 20:24:48 +02:00
2014-02-10 02:10:30 +01:00
bool LineEdit : : is_secret ( ) const {
2016-03-09 00:00:52 +01:00
2014-02-10 02:10:30 +01:00
return pass ;
}
2018-04-28 20:24:48 +02:00
void LineEdit : : set_secret_character ( const String & p_string ) {
// An empty string as the secret character would crash the engine
// It also wouldn't make sense to use multiple characters as the secret character
2019-08-08 22:11:48 +02:00
ERR_FAIL_COND_MSG ( p_string . length ( ) ! = 1 , " Secret character must be exactly one character long ( " + itos ( p_string . length ( ) ) + " characters given). " ) ;
2018-04-28 20:24:48 +02:00
secret_character = p_string ;
update ( ) ;
}
String LineEdit : : get_secret_character ( ) const {
return secret_character ;
}
2014-02-10 02:10:30 +01:00
void LineEdit : : select ( int p_from , int p_to ) {
2017-03-05 16:44:50 +01:00
if ( p_from = = 0 & & p_to = = 0 ) {
2017-12-17 18:40:44 +01:00
deselect ( ) ;
2014-02-27 15:16:00 +01:00
return ;
}
2014-02-10 02:10:30 +01:00
int len = text . length ( ) ;
2017-03-05 16:44:50 +01:00
if ( p_from < 0 )
p_from = 0 ;
if ( p_from > len )
p_from = len ;
if ( p_to < 0 | | p_to > len )
p_to = len ;
if ( p_from > = p_to )
2014-02-10 02:10:30 +01:00
return ;
2017-03-05 16:44:50 +01:00
selection . enabled = true ;
selection . begin = p_from ;
selection . end = p_to ;
selection . creating = false ;
selection . doubleclick = false ;
2014-02-10 02:10:30 +01:00
update ( ) ;
}
2015-10-17 15:29:54 +02:00
bool LineEdit : : is_text_field ( ) const {
2017-03-05 16:44:50 +01:00
return true ;
2015-10-17 15:29:54 +02:00
}
2014-02-10 02:10:30 +01:00
2016-05-17 01:25:17 +02:00
void LineEdit : : menu_option ( int p_option ) {
2017-03-05 16:44:50 +01:00
switch ( p_option ) {
2016-05-17 01:25:17 +02:00
case MENU_CUT : {
2016-09-19 14:17:48 +02:00
if ( editable ) {
cut_text ( ) ;
}
2016-05-17 01:25:17 +02:00
} break ;
case MENU_COPY : {
copy_text ( ) ;
} break ;
case MENU_PASTE : {
2016-09-19 14:17:48 +02:00
if ( editable ) {
paste_text ( ) ;
}
2016-05-17 01:25:17 +02:00
} break ;
case MENU_CLEAR : {
2016-09-19 14:17:48 +02:00
if ( editable ) {
clear ( ) ;
}
2016-05-17 01:25:17 +02:00
} break ;
case MENU_SELECT_ALL : {
select_all ( ) ;
} break ;
case MENU_UNDO : {
2017-07-17 15:00:01 +02:00
if ( editable ) {
undo ( ) ;
}
2016-05-17 01:25:17 +02:00
} break ;
2017-10-30 00:14:33 +01:00
case MENU_REDO : {
if ( editable ) {
redo ( ) ;
}
}
2016-05-17 01:25:17 +02:00
}
}
2017-11-09 21:46:29 +01:00
void LineEdit : : set_context_menu_enabled ( bool p_enable ) {
context_menu_enabled = p_enable ;
}
bool LineEdit : : is_context_menu_enabled ( ) {
return context_menu_enabled ;
}
2016-05-17 01:25:17 +02:00
PopupMenu * LineEdit : : get_menu ( ) const {
return menu ;
}
2017-03-05 16:44:50 +01:00
void LineEdit : : _editor_settings_changed ( ) {
2018-04-29 19:49:26 +02:00
# ifdef TOOLS_ENABLED
2017-03-05 16:44:50 +01:00
cursor_set_blink_enabled ( EDITOR_DEF ( " text_editor/cursor/caret_blink " , false ) ) ;
cursor_set_blink_speed ( EDITOR_DEF ( " text_editor/cursor/caret_blink_speed " , 0.65 ) ) ;
2016-06-21 15:38:35 +02:00
# endif
2018-04-29 19:49:26 +02:00
}
2016-06-21 15:38:35 +02:00
2016-09-07 08:52:42 +02:00
void LineEdit : : set_expand_to_text_length ( bool p_enabled ) {
2016-09-07 01:34:24 +02:00
2016-09-07 08:52:42 +02:00
expand_to_text_length = p_enabled ;
2016-09-07 01:34:24 +02:00
minimum_size_changed ( ) ;
2017-11-17 08:22:20 +01:00
set_window_pos ( 0 ) ;
2016-09-07 01:34:24 +02:00
}
2017-03-05 16:44:50 +01:00
bool LineEdit : : get_expand_to_text_length ( ) const {
2016-09-07 01:34:24 +02:00
return expand_to_text_length ;
}
2018-07-26 13:45:38 +02:00
void LineEdit : : set_clear_button_enabled ( bool p_enabled ) {
clear_button_enabled = p_enabled ;
update ( ) ;
}
bool LineEdit : : is_clear_button_enabled ( ) const {
return clear_button_enabled ;
}
2018-08-11 12:04:19 +02:00
void LineEdit : : set_right_icon ( const Ref < Texture > & p_icon ) {
if ( right_icon = = p_icon ) {
return ;
}
right_icon = p_icon ;
update ( ) ;
}
2016-09-07 01:34:24 +02:00
void LineEdit : : _text_changed ( ) {
if ( expand_to_text_length )
minimum_size_changed ( ) ;
2017-10-30 00:14:33 +01:00
_emit_text_change ( ) ;
_clear_redo ( ) ;
}
void LineEdit : : _emit_text_change ( ) {
2017-03-05 16:44:50 +01:00
emit_signal ( " text_changed " , text ) ;
2016-09-07 01:34:24 +02:00
_change_notify ( " text " ) ;
2018-02-05 16:22:34 +01:00
text_changed_dirty = false ;
2016-09-07 01:34:24 +02:00
}
2019-06-22 14:42:36 +02:00
void LineEdit : : update_placeholder_width ( ) {
if ( ( max_length < = 0 ) | | ( placeholder_translated . length ( ) < = max_length ) ) {
Ref < Font > font = get_font ( " font " ) ;
cached_placeholder_width = 0 ;
if ( font ! = NULL ) {
for ( int i = 0 ; i < placeholder_translated . length ( ) ; i + + ) {
cached_placeholder_width + = font - > get_char_size ( placeholder_translated [ i ] ) . width ;
}
}
}
}
2017-10-30 00:14:33 +01:00
void LineEdit : : _clear_redo ( ) {
_create_undo_state ( ) ;
if ( undo_stack_pos = = NULL ) {
return ;
}
undo_stack_pos = undo_stack_pos - > next ( ) ;
while ( undo_stack_pos ) {
List < TextOperation > : : Element * elem = undo_stack_pos ;
undo_stack_pos = undo_stack_pos - > next ( ) ;
undo_stack . erase ( elem ) ;
}
_create_undo_state ( ) ;
}
void LineEdit : : _clear_undo_stack ( ) {
undo_stack . clear ( ) ;
undo_stack_pos = NULL ;
_create_undo_state ( ) ;
}
void LineEdit : : _create_undo_state ( ) {
TextOperation op ;
op . text = text ;
op . cursor_pos = cursor_pos ;
undo_stack . push_back ( op ) ;
}
2014-02-10 02:10:30 +01:00
void LineEdit : : _bind_methods ( ) {
2016-03-09 00:00:52 +01:00
2018-02-05 16:22:34 +01:00
ClassDB : : bind_method ( D_METHOD ( " _text_changed " ) , & LineEdit : : _text_changed ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " _toggle_draw_caret " ) , & LineEdit : : _toggle_draw_caret ) ;
2016-06-21 01:05:52 +02:00
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( " _editor_settings_changed " , & LineEdit : : _editor_settings_changed ) ;
2016-06-21 15:38:35 +02:00
2017-02-13 12:47:24 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_align " , " align " ) , & LineEdit : : set_align ) ;
ClassDB : : bind_method ( D_METHOD ( " get_align " ) , & LineEdit : : get_align ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " _gui_input " ) , & LineEdit : : _gui_input ) ;
ClassDB : : bind_method ( D_METHOD ( " clear " ) , & LineEdit : : clear ) ;
2017-12-17 18:40:44 +01:00
ClassDB : : bind_method ( D_METHOD ( " select " , " from " , " to " ) , & LineEdit : : select , DEFVAL ( 0 ) , DEFVAL ( - 1 ) ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " select_all " ) , & LineEdit : : select_all ) ;
2017-12-17 18:40:44 +01:00
ClassDB : : bind_method ( D_METHOD ( " deselect " ) , & LineEdit : : deselect ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_text " , " text " ) , & LineEdit : : set_text ) ;
ClassDB : : bind_method ( D_METHOD ( " get_text " ) , & LineEdit : : get_text ) ;
ClassDB : : bind_method ( D_METHOD ( " set_placeholder " , " text " ) , & LineEdit : : set_placeholder ) ;
ClassDB : : bind_method ( D_METHOD ( " get_placeholder " ) , & LineEdit : : get_placeholder ) ;
ClassDB : : bind_method ( D_METHOD ( " set_placeholder_alpha " , " alpha " ) , & LineEdit : : set_placeholder_alpha ) ;
ClassDB : : bind_method ( D_METHOD ( " get_placeholder_alpha " ) , & LineEdit : : get_placeholder_alpha ) ;
2017-09-10 15:37:49 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_cursor_position " , " position " ) , & LineEdit : : set_cursor_position ) ;
ClassDB : : bind_method ( D_METHOD ( " get_cursor_position " ) , & LineEdit : : get_cursor_position ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_expand_to_text_length " , " enabled " ) , & LineEdit : : set_expand_to_text_length ) ;
ClassDB : : bind_method ( D_METHOD ( " get_expand_to_text_length " ) , & LineEdit : : get_expand_to_text_length ) ;
ClassDB : : bind_method ( D_METHOD ( " cursor_set_blink_enabled " , " enabled " ) , & LineEdit : : cursor_set_blink_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " cursor_get_blink_enabled " ) , & LineEdit : : cursor_get_blink_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " cursor_set_blink_speed " , " blink_speed " ) , & LineEdit : : cursor_set_blink_speed ) ;
ClassDB : : bind_method ( D_METHOD ( " cursor_get_blink_speed " ) , & LineEdit : : cursor_get_blink_speed ) ;
ClassDB : : bind_method ( D_METHOD ( " set_max_length " , " chars " ) , & LineEdit : : set_max_length ) ;
ClassDB : : bind_method ( D_METHOD ( " get_max_length " ) , & LineEdit : : get_max_length ) ;
ClassDB : : bind_method ( D_METHOD ( " append_at_cursor " , " text " ) , & LineEdit : : append_at_cursor ) ;
ClassDB : : bind_method ( D_METHOD ( " set_editable " , " enabled " ) , & LineEdit : : set_editable ) ;
ClassDB : : bind_method ( D_METHOD ( " is_editable " ) , & LineEdit : : is_editable ) ;
ClassDB : : bind_method ( D_METHOD ( " set_secret " , " enabled " ) , & LineEdit : : set_secret ) ;
ClassDB : : bind_method ( D_METHOD ( " is_secret " ) , & LineEdit : : is_secret ) ;
2018-04-28 20:24:48 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_secret_character " , " character " ) , & LineEdit : : set_secret_character ) ;
ClassDB : : bind_method ( D_METHOD ( " get_secret_character " ) , & LineEdit : : get_secret_character ) ;
2017-03-05 16:44:50 +01:00
ClassDB : : bind_method ( D_METHOD ( " menu_option " , " option " ) , & LineEdit : : menu_option ) ;
2017-08-09 13:19:41 +02:00
ClassDB : : bind_method ( D_METHOD ( " get_menu " ) , & LineEdit : : get_menu ) ;
2017-11-09 21:46:29 +01:00
ClassDB : : bind_method ( D_METHOD ( " set_context_menu_enabled " , " enable " ) , & LineEdit : : set_context_menu_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_context_menu_enabled " ) , & LineEdit : : is_context_menu_enabled ) ;
2018-07-26 13:45:38 +02:00
ClassDB : : bind_method ( D_METHOD ( " set_clear_button_enabled " , " enable " ) , & LineEdit : : set_clear_button_enabled ) ;
ClassDB : : bind_method ( D_METHOD ( " is_clear_button_enabled " ) , & LineEdit : : is_clear_button_enabled ) ;
2017-03-05 16:44:50 +01:00
2018-01-09 16:39:43 +01:00
ADD_SIGNAL ( MethodInfo ( " text_changed " , PropertyInfo ( Variant : : STRING , " new_text " ) ) ) ;
ADD_SIGNAL ( MethodInfo ( " text_entered " , PropertyInfo ( Variant : : STRING , " new_text " ) ) ) ;
2014-02-10 02:10:30 +01:00
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( ALIGN_LEFT ) ;
BIND_ENUM_CONSTANT ( ALIGN_CENTER ) ;
BIND_ENUM_CONSTANT ( ALIGN_RIGHT ) ;
BIND_ENUM_CONSTANT ( ALIGN_FILL ) ;
BIND_ENUM_CONSTANT ( MENU_CUT ) ;
BIND_ENUM_CONSTANT ( MENU_COPY ) ;
BIND_ENUM_CONSTANT ( MENU_PASTE ) ;
BIND_ENUM_CONSTANT ( MENU_CLEAR ) ;
BIND_ENUM_CONSTANT ( MENU_SELECT_ALL ) ;
BIND_ENUM_CONSTANT ( MENU_UNDO ) ;
2017-10-30 00:14:33 +01:00
BIND_ENUM_CONSTANT ( MENU_REDO ) ;
2017-08-20 17:45:01 +02:00
BIND_ENUM_CONSTANT ( MENU_MAX ) ;
2016-05-17 01:25:17 +02:00
2018-11-08 15:30:02 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " text " ) , " set_text " , " get_text " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " align " , PROPERTY_HINT_ENUM , " Left,Center,Right,Fill " ) , " set_align " , " get_align " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " max_length " ) , " set_max_length " , " get_max_length " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " editable " ) , " set_editable " , " is_editable " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " secret " ) , " set_secret " , " is_secret " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " secret_character " ) , " set_secret_character " , " get_secret_character " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " expand_to_text_length " ) , " set_expand_to_text_length " , " get_expand_to_text_length " ) ;
2017-03-05 16:44:50 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " focus_mode " , PROPERTY_HINT_ENUM , " None,Click,All " ) , " set_focus_mode " , " get_focus_mode " ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " context_menu_enabled " ) , " set_context_menu_enabled " , " is_context_menu_enabled " ) ;
2018-07-26 13:45:38 +02:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " clear_button_enabled " ) , " set_clear_button_enabled " , " is_clear_button_enabled " ) ;
2017-03-05 16:44:50 +01:00
ADD_GROUP ( " Placeholder " , " placeholder_ " ) ;
2018-11-08 15:30:02 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : STRING , " placeholder_text " ) , " set_placeholder " , " get_placeholder " ) ;
ADD_PROPERTY ( PropertyInfo ( Variant : : REAL , " placeholder_alpha " , PROPERTY_HINT_RANGE , " 0,1,0.001 " ) , " set_placeholder_alpha " , " get_placeholder_alpha " ) ;
2017-03-05 16:44:50 +01:00
ADD_GROUP ( " Caret " , " caret_ " ) ;
2017-02-12 01:11:37 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : BOOL , " caret_blink " ) , " cursor_set_blink_enabled " , " cursor_get_blink_enabled " ) ;
2018-11-08 15:30:02 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : REAL , " caret_blink_speed " , PROPERTY_HINT_RANGE , " 0.1,10,0.01 " ) , " cursor_set_blink_speed " , " cursor_get_blink_speed " ) ;
2018-01-11 23:35:12 +01:00
ADD_PROPERTY ( PropertyInfo ( Variant : : INT , " caret_position " ) , " set_cursor_position " , " get_cursor_position " ) ;
2014-02-10 02:10:30 +01:00
}
LineEdit : : LineEdit ( ) {
2016-03-09 00:00:52 +01:00
2017-10-30 00:14:33 +01:00
undo_stack_pos = NULL ;
_create_undo_state ( ) ;
2015-08-15 08:47:22 +02:00
align = ALIGN_LEFT ;
cached_width = 0 ;
2018-04-09 22:08:53 +02:00
cached_placeholder_width = 0 ;
2017-03-05 16:44:50 +01:00
cursor_pos = 0 ;
window_pos = 0 ;
window_has_focus = true ;
2014-02-10 02:10:30 +01:00
max_length = 0 ;
2017-03-05 16:44:50 +01:00
pass = false ;
2018-04-28 20:24:48 +02:00
secret_character = " * " ;
2018-02-05 16:22:34 +01:00
text_changed_dirty = false ;
2017-03-05 16:44:50 +01:00
placeholder_alpha = 0.6 ;
2018-07-26 13:45:38 +02:00
clear_button_enabled = false ;
2018-10-20 11:48:14 +02:00
clear_button_status . press_attempt = false ;
clear_button_status . pressing_inside = false ;
2016-03-09 00:00:52 +01:00
2017-12-17 18:40:44 +01:00
deselect ( ) ;
2017-03-05 16:44:50 +01:00
set_focus_mode ( FOCUS_ALL ) ;
2014-02-10 02:10:30 +01:00
set_default_cursor_shape ( CURSOR_IBEAM ) ;
2017-01-08 23:54:19 +01:00
set_mouse_filter ( MOUSE_FILTER_STOP ) ;
2016-03-09 00:00:52 +01:00
2017-03-05 16:44:50 +01:00
draw_caret = true ;
caret_blink_enabled = false ;
2016-06-21 01:05:52 +02:00
caret_blink_timer = memnew ( Timer ) ;
add_child ( caret_blink_timer ) ;
caret_blink_timer - > set_wait_time ( 0.65 ) ;
2017-03-05 16:44:50 +01:00
caret_blink_timer - > connect ( " timeout " , this , " _toggle_draw_caret " ) ;
2016-06-21 01:05:52 +02:00
cursor_set_blink_enabled ( false ) ;
2016-03-09 00:00:52 +01:00
2017-11-09 21:46:29 +01:00
context_menu_enabled = true ;
2017-03-05 16:44:50 +01:00
menu = memnew ( PopupMenu ) ;
2016-05-17 01:25:17 +02:00
add_child ( menu ) ;
2019-05-21 22:50:02 +02:00
editable = false ; // initialise to opposite first, so we get past the early-out in set_editable
2019-04-22 01:09:52 +02:00
set_editable ( true ) ;
2017-03-05 16:44:50 +01:00
menu - > connect ( " id_pressed " , this , " menu_option " ) ;
expand_to_text_length = false ;
2014-02-10 02:10:30 +01:00
}
LineEdit : : ~ LineEdit ( ) {
}