diff options
Diffstat (limited to 'scene/gui/text_edit.cpp')
-rw-r--r-- | scene/gui/text_edit.cpp | 374 |
1 files changed, 330 insertions, 44 deletions
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index d84e9956ba..0b797e7df3 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -46,7 +46,6 @@ #define TAB_PIXELS - static bool _is_text_char(CharType c) { return (c>='a' && c<='z') || (c>='A' && c<='Z') || (c>='0' && c<='9') || c=='_'; @@ -57,6 +56,42 @@ static bool _is_symbol(CharType c) { return c!='_' && ((c>='!' && c<='/') || (c>=':' && c<='@') || (c>='[' && c<='`') || (c>='{' && c<='~') || c=='\t'); } +static bool _is_pair_right_symbol(CharType c) { + return + c == '"' || + c == '\'' || + c == ')' || + c == ']' || + c == '}'; +} + +static bool _is_pair_left_symbol(CharType c) { + return + c == '"' || + c == '\'' || + c == '(' || + c == '[' || + c == '{'; +} + +static bool _is_pair_symbol(CharType c) { + return _is_pair_left_symbol(c) || _is_pair_right_symbol(c); +} + +static CharType _get_right_pair_symbol(CharType c) { + if(c == '"') + return '"'; + if(c == '\'') + return '\''; + if(c == '(') + return ')'; + if(c == '[') + return ']'; + if(c == '{') + return '}'; + return 0; +} + void TextEdit::Text::set_font(const Ref<Font>& p_font) { font=p_font; @@ -301,7 +336,7 @@ void TextEdit::_update_scrollbars() { v_scroll->set_val(cursor.line_ofs); } else { - + cursor.line_ofs = 0; v_scroll->hide(); } @@ -707,6 +742,93 @@ void TextEdit::_notification(int p_what) { } } +void TextEdit::_consume_pair_symbol(CharType ch) { + + int cursor_position_to_move = cursor_get_column() + 1; + + CharType ch_single[2] = {ch, 0}; + CharType ch_single_pair[2] = {_get_right_pair_symbol(ch), 0}; + CharType ch_pair[3] = {ch, _get_right_pair_symbol(ch), 0}; + + if(is_selection_active()) { + + int new_column,new_line; + + _begin_compex_operation(); + _insert_text(get_selection_from_line(), get_selection_from_column(), + ch_single, + &new_line, &new_column); + + int to_col_offset = 0; + if(get_selection_from_line() == get_selection_to_line()) + to_col_offset = 1; + + _insert_text(get_selection_to_line(), + get_selection_to_column() + to_col_offset, + ch_single_pair, + &new_line,&new_column); + _end_compex_operation(); + + cursor_set_line(get_selection_to_line()); + cursor_set_column(get_selection_to_column() + to_col_offset); + + deselect(); + update(); + return; + } + + if( (ch == '\'' || ch == '"') && + cursor_get_column() > 0 && + _is_text_char(text[cursor.line][cursor_get_column() - 1]) + ) { + insert_text_at_cursor(ch_single); + cursor_set_column(cursor_position_to_move); + return; + } + + if(cursor_get_column() < text[cursor.line].length()) { + if(_is_text_char(text[cursor.line][cursor_get_column()])) { + insert_text_at_cursor(ch_single); + cursor_set_column(cursor_position_to_move); + return; + } + if( _is_pair_right_symbol(ch) && + text[cursor.line][cursor_get_column()] == ch + ) { + cursor_set_column(cursor_position_to_move); + return; + } + } + + + insert_text_at_cursor(ch_pair); + cursor_set_column(cursor_position_to_move); + return; + +} + +void TextEdit::_consume_backspace_for_pair_symbol(int prev_line, int prev_column) { + + bool remove_right_symbol = false; + + if(cursor.column < text[cursor.line].length() && cursor.column > 0) { + + CharType left_char = text[cursor.line][cursor.column - 1]; + CharType right_char = text[cursor.line][cursor.column]; + + if(right_char == _get_right_pair_symbol(left_char)) { + remove_right_symbol = true; + } + + } + if(remove_right_symbol) { + _remove_text(prev_line,prev_column,cursor.line,cursor.column + 1); + } else { + _remove_text(prev_line,prev_column,cursor.line,cursor.column); + } + +} + void TextEdit::backspace_at_cursor() { if (cursor.column==0 && cursor.line==0) @@ -714,7 +836,14 @@ void TextEdit::backspace_at_cursor() { int prev_line = cursor.column?cursor.line:cursor.line-1; int prev_column = cursor.column?(cursor.column-1):(text[cursor.line-1].length()); - _remove_text(prev_line,prev_column,cursor.line,cursor.column); + if(auto_brace_completion_enabled && + cursor.column > 0 && + _is_pair_left_symbol(text[cursor.line][cursor.column - 1])) { + _consume_backspace_for_pair_symbol(prev_line, prev_column); + } else { + _remove_text(prev_line,prev_column,cursor.line,cursor.column); + } + cursor_set_line(prev_line); cursor_set_column(prev_column); @@ -976,7 +1105,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { return; } - if (k.scancode==KEY_RETURN) { + if (k.scancode==KEY_RETURN || k.scancode==KEY_TAB) { _confirm_completion(); accept_event(); @@ -1002,11 +1131,17 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (cursor.column<text[cursor.line].length() && text[cursor.line][cursor.column]==k.unicode) { //same char, move ahead cursor_set_column(cursor.column+1); + } else { //different char, go back const CharType chr[2] = {k.unicode, 0}; - _insert_text_at_cursor(chr); + if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { + _consume_pair_symbol(chr[0]); + } else { + _insert_text_at_cursor(chr); + } } + _update_completion_candidates(); accept_event(); @@ -1072,8 +1207,10 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { cursor_set_line(selection.from_line); cursor_set_column(selection.from_column); + _begin_compex_operation(); _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); _insert_text_at_cursor(txt); + _end_compex_operation(); selection.active=true; selection.from_column=sel_column; selection.from_line=sel_line; @@ -1111,7 +1248,8 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { default: if (k.unicode>=32 && !k.mod.command && !k.mod.alt && !k.mod.meta) clear=true; - + if (auto_brace_completion_enabled && _is_pair_left_symbol(k.unicode)) + clear=false; } if (unselect) { @@ -1216,13 +1354,13 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { cursor_set_column(cc); - } else if (cursor.column==0) { + } else if (cursor.column==0) { if (cursor.line>0) { cursor_set_line(cursor.line-1); cursor_set_column(text[cursor.line].length()); } - } else { + } else { cursor_set_column(cursor_get_column()-1); } @@ -1256,13 +1394,13 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { cursor_set_column(cc); - } else if (cursor.column==text[cursor.line].length()) { + } else if (cursor.column==text[cursor.line].length()) { if (cursor.line<text.size()-1) { cursor_set_line(cursor.line+1); cursor_set_column(0); } - } else { + } else { cursor_set_column(cursor_get_column()+1); } @@ -1431,19 +1569,35 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { break; } - if (!selection.active) - break; + if (!selection.active){ - String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - OS::get_singleton()->set_clipboard(clipboard); + String clipboard = text[cursor.line]; + OS::get_singleton()->set_clipboard(clipboard); + cursor_set_line(cursor.line); + cursor_set_column(0); + _remove_text(cursor.line,0,cursor.line,text[cursor.line].length()); - cursor_set_line(selection.from_line); - cursor_set_column(selection.from_column); + backspace_at_cursor(); + update(); + cursor_set_line(cursor.line+1); + cut_copy_line = true; - _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - selection.active=false; - selection.selecting_mode=Selection::MODE_NONE; - update(); + } + else + { + + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + OS::get_singleton()->set_clipboard(clipboard); + + cursor_set_line(selection.from_line); + cursor_set_column(selection.from_column); + + _remove_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + selection.active=false; + selection.selecting_mode=Selection::MODE_NONE; + update(); + cut_copy_line = false; + } } break; case KEY_C: { @@ -1453,11 +1607,16 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { break; } - if (!selection.active) - break; - - String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); - OS::get_singleton()->set_clipboard(clipboard); + if (!selection.active){ + String clipboard = _base_get_text(cursor.line,0,cursor.line,text[cursor.line].length()); + OS::get_singleton()->set_clipboard(clipboard); + cut_copy_line = true; + } + else{ + String clipboard = _base_get_text(selection.from_line,selection.from_column,selection.to_line,selection.to_column); + OS::get_singleton()->set_clipboard(clipboard); + cut_copy_line = false; + } } break; case KEY_Z: { @@ -1487,6 +1646,12 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { cursor_set_column(selection.from_column); } + else if (cut_copy_line) + { + cursor_set_column(0); + String ins="\n"; + clipboard += ins; + } _insert_text_at_cursor(clipboard); @@ -1503,10 +1668,54 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { } break; - default: { - - scancode_handled=false; - } break; + case KEY_K:{ + if (!k.mod.command || k.mod.shift || k.mod.alt) { + scancode_handled=false; + break; + } + else { + if (selection.active) { + int ini = selection.from_line; + int end = selection.to_line; + for (int i=ini; i<= end; i++) + { + _insert_text(i,0,"#"); + } + } + else{ + _insert_text(cursor.line,0,"#"); + } + update(); + } + break;} + + case KEY_U:{ + if (!k.mod.command || k.mod.shift || k.mod.alt) { + scancode_handled=false; + break; + } + else { + if (selection.active) { + int ini = selection.from_line; + int end = selection.to_line; + for (int i=ini; i<= end; i++) + { + if (text[i][0] == '#') + _remove_text(i,0,i,1); + } + } + else{ + if (text[cursor.line][0] == '#') + _remove_text(cursor.line,0,cursor.line,1); + } + update(); + } + break;} + + default: { + + scancode_handled=false; + } break; } @@ -1520,14 +1729,35 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (readonly) break; + accept_event(); + } else { + + break; + } + } + + if (!scancode_handled && !k.mod.command && !k.mod.alt) { + + if (k.unicode>=32) { + + if (readonly) + break; + const CharType chr[2] = {k.unicode, 0}; - _insert_text_at_cursor(chr); + + if(auto_brace_completion_enabled && _is_pair_symbol(chr[0])) { + _consume_pair_symbol(chr[0]); + } else { + _insert_text_at_cursor(chr); + } + accept_event(); } else { break; } } + if (!selection.selecting_test) { @@ -1569,8 +1799,6 @@ void TextEdit::_post_shift_selection() { /**** TEXT EDIT CORE API ****/ - - void TextEdit::_base_insert_text(int p_line, int p_char,const String& p_text,int &r_end_line,int &r_end_column) { //save for undo... @@ -1677,14 +1905,12 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column,int p_to_lin - void TextEdit::_insert_text(int p_line, int p_char,const String& p_text,int *r_end_line,int *r_end_column) { if (!setting_text) idle_detect->start(); if (undo_enabled) { - _clear_redo(); } @@ -1868,7 +2094,6 @@ void TextEdit::adjust_viewport_to_cursor() { } - void TextEdit::cursor_set_column(int p_col) { if (p_col<0) @@ -2336,6 +2561,27 @@ String TextEdit::get_selection_text() const { } +String TextEdit::get_word_under_cursor() const { + + int prev_cc = cursor.column; + while(prev_cc >0) { + bool is_char = _is_text_char(text[cursor.line][prev_cc-1]); + if (!is_char) + break; + --prev_cc; + } + + int next_cc = cursor.column; + while(next_cc<text[cursor.line].length()) { + bool is_char = _is_text_char(text[cursor.line][next_cc]); + if(!is_char) + break; + ++ next_cc; + } + if (prev_cc == cursor.column || next_cc == cursor.column) + return ""; + return text[cursor.line].substr(prev_cc, next_cc-prev_cc); +} DVector<int> TextEdit::_search_bind(const String &p_key,uint32_t p_search_flags, int p_from_line,int p_from_column) const { @@ -2496,7 +2742,7 @@ void TextEdit::_clear_redo() { void TextEdit::undo() { - + _push_current_op(); if (undo_stack_pos==NULL) { @@ -2511,8 +2757,13 @@ void TextEdit::undo() { else undo_stack_pos=undo_stack_pos->prev(); - _do_text_op( undo_stack_pos->get(),true); + if(undo_stack_pos->get().chain_backward) { + do { + undo_stack_pos = undo_stack_pos->prev(); + _do_text_op(undo_stack_pos->get(), true); + } while(!undo_stack_pos->get().chain_forward); + } cursor_set_line(undo_stack_pos->get().from_line); cursor_set_column(undo_stack_pos->get().from_column); @@ -2526,8 +2777,13 @@ void TextEdit::redo() { if (undo_stack_pos==NULL) return; //nothing to do. - - _do_text_op( undo_stack_pos->get(),false); + _do_text_op(undo_stack_pos->get(), false); + if(undo_stack_pos->get().chain_forward) { + do { + undo_stack_pos=undo_stack_pos->next(); + _do_text_op(undo_stack_pos->get(), false); + } while(!undo_stack_pos->get().chain_backward); + } cursor_set_line(undo_stack_pos->get().from_line); cursor_set_column(undo_stack_pos->get().from_column); undo_stack_pos=undo_stack_pos->next(); @@ -2539,20 +2795,43 @@ void TextEdit::clear_undo_history() { saved_version=0; current_op.type=TextOperation::TYPE_NONE; undo_stack_pos=NULL; - undo_stack.clear();; + undo_stack.clear(); } +void TextEdit::_begin_compex_operation() { + _push_current_op(); + next_operation_is_complex=true; +} -void TextEdit::_push_current_op() { +void TextEdit::_end_compex_operation() { + + _push_current_op(); + ERR_FAIL_COND(undo_stack.size() == 0); + + if(undo_stack.back()->get().chain_forward) { + undo_stack.back()->get().chain_forward=false; + return; + } + + undo_stack.back()->get().chain_backward=true; +} +void TextEdit::_push_current_op() { + if (current_op.type==TextOperation::TYPE_NONE) return; // do nothing - + + if(next_operation_is_complex) { + current_op.chain_forward=true; + next_operation_is_complex=false; + } + undo_stack.push_back(current_op); current_op.type=TextOperation::TYPE_NONE; current_op.text=""; - + current_op.chain_forward=false; + } void TextEdit::set_draw_tabs(bool p_draw) { @@ -2693,6 +2972,7 @@ void TextEdit::_update_completion_candidates() { completion_current=completion_options[completion_index]; +#if 0 // even there's only one option, user still get the chance to choose using it or not if (completion_options.size()==1) { //one option to complete, just complete it automagically _confirm_completion(); @@ -2701,6 +2981,9 @@ void TextEdit::_update_completion_candidates() { return; } +#endif + if (completion_options.size()==1 && s==completion_options[0]) + _cancel_completion(); completion_enabled=true; @@ -2855,6 +3138,7 @@ void TextEdit::_bind_methods() { ObjectTypeDB::bind_method(_MD("get_selection_to_line"),&TextEdit::get_selection_to_line); ObjectTypeDB::bind_method(_MD("get_selection_to_column"),&TextEdit::get_selection_to_column); ObjectTypeDB::bind_method(_MD("get_selection_text"),&TextEdit::get_selection_text); + ObjectTypeDB::bind_method(_MD("get_word_under_cursor"),&TextEdit::get_word_under_cursor); ObjectTypeDB::bind_method(_MD("search","flags","from_line","from_column","to_line","to_column"),&TextEdit::_search_bind); ObjectTypeDB::bind_method(_MD("undo"),&TextEdit::undo); @@ -2945,7 +3229,7 @@ TextEdit::TextEdit() { current_op.type=TextOperation::TYPE_NONE; undo_enabled=true; - undo_stack_pos=NULL; + undo_stack_pos=NULL; setting_text=false; last_dblclk=0; current_op.version=0; @@ -2957,6 +3241,8 @@ TextEdit::TextEdit() { completion_line_ofs=0; tooltip_obj=NULL; line_numbers=false; + next_operation_is_complex=false; + auto_brace_completion_enabled=false; } TextEdit::~TextEdit(){ |