From 65fa8f91ca979d61cebed8eddd4c8a5bc5317ca7 Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Sat, 28 May 2016 18:22:54 +0200 Subject: [PATCH 1/3] TextEdit: Avoid capturing KEY_ESCAPE when there is no completion hint --- scene/gui/text_edit.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 03024daff5b..3199a7f15c6 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -1892,7 +1892,8 @@ void TextEdit::_input_event(const InputEvent& p_input_event) { if (completion_hint!="") { completion_hint=""; update(); - + } else { + scancode_handled=false; } } break; case KEY_TAB: { From aba972238ec23612a9b418c9aa39b903557813ee Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Sat, 28 May 2016 18:23:49 +0200 Subject: [PATCH 2/3] TextEdit: Improve search method to avoid overlapping results --- scene/gui/text_edit.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 3199a7f15c6..72c1da0bc58 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -3566,10 +3566,8 @@ bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_li //wrapped if (p_search_flags&SEARCH_BACKWARDS) { - text_line=text_line.substr(from_column,text_line.length()); from_column=text_line.length(); } else { - text_line=text_line.substr(0,from_column); from_column=0; } @@ -3580,7 +3578,6 @@ bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_li } else { - //text_line=text_line.substr(0,p_from_column); //wrap around for missing begining. if (p_search_flags&SEARCH_BACKWARDS) from_column=text_line.length()-1; else @@ -3589,12 +3586,25 @@ bool TextEdit::search(const String &p_key,uint32_t p_search_flags, int p_from_li pos=-1; - if (!(p_search_flags&SEARCH_BACKWARDS)) { + int pos_from=0; + int last_pos=-1; + while ((last_pos=(p_search_flags&SEARCH_MATCH_CASE)?text_line.find(p_key,pos_from):text_line.findn(p_key,pos_from))!=-1) { - pos = (p_search_flags&SEARCH_MATCH_CASE)?text_line.find(p_key,from_column):text_line.findn(p_key,from_column); - } else { + if (p_search_flags&SEARCH_BACKWARDS) { - pos = (p_search_flags&SEARCH_MATCH_CASE)?text_line.rfind(p_key,from_column):text_line.rfindn(p_key,from_column); + if (last_pos>from_column) + break; + pos=last_pos; + + } else { + + if (last_pos>=from_column) { + pos=last_pos; + break; + } + } + + pos_from=last_pos+p_key.length(); } if (pos!=-1 && (p_search_flags&SEARCH_WHOLE_WORDS)) { From 51be9beec9c38a8cd5a0f9a42a8258484aece9fb Mon Sep 17 00:00:00 2001 From: Ignacio Etcheverry Date: Sat, 28 May 2016 18:25:45 +0200 Subject: [PATCH 3/3] ScriptEditor/ShaderEditor: Replace find/replace dialog with a bar --- scene/gui/text_edit.cpp | 67 ++- scene/gui/text_edit.h | 13 +- tools/editor/code_editor.cpp | 471 +++++++++++++++++- tools/editor/code_editor.h | 71 ++- tools/editor/editor_settings.cpp | 4 + tools/editor/plugins/script_editor_plugin.cpp | 19 +- tools/editor/plugins/script_editor_plugin.h | 2 +- tools/editor/plugins/shader_editor_plugin.cpp | 19 +- tools/editor/plugins/shader_editor_plugin.h | 2 +- 9 files changed, 621 insertions(+), 47 deletions(-) diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp index 72c1da0bc58..2f6fda83506 100644 --- a/scene/gui/text_edit.cpp +++ b/scene/gui/text_edit.cpp @@ -682,9 +682,13 @@ void TextEdit::_notification(int p_what) { // check if line contains highlighted word int highlighted_text_col = -1; - if (highlighted_text.length() != 0) { - highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, 0); - } + int search_text_col = -1; + + if (!search_text.empty()) + search_text_col = _get_column_pos_of_word(search_text, str, search_flags, 0); + + if (highlighted_text.length() != 0 && highlighted_text != search_text) + highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE|SEARCH_WHOLE_WORDS, 0); if (cache.line_number_w) { String fc = String::num(line+1); @@ -879,20 +883,45 @@ void TextEdit::_notification(int p_what) { break; } - bool in_selection = (selection.active && line>=selection.from_line && line<=selection.to_line && (line>selection.from_line || j>=selection.from_column) && (line= search_text_col+search_text.length()) + search_text_col = _get_column_pos_of_word(search_text, str, search_flags, j); + + in_search_result = j >= search_text_col && j < search_text_col+search_text.length(); + + if (in_search_result) { + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w, get_row_height())),cache.search_result_color); + } + } + + bool in_selection = (selection.active && line>=selection.from_line && line<=selection.to_line && (line>selection.from_line || j>=selection.from_column) && (linecanvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w,get_row_height())),cache.selection_color); } + if (in_search_result) { + Color border_color=(line==search_result_line && j>=search_result_col && jcanvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w,1)),border_color); + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y+get_row_height()-1 ), Size2i(char_w,1)),border_color); + + if (j==search_text_col) + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(1,get_row_height())),border_color); + if (j==search_text_col+search_text.length()-1) + VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin+char_w-1, ofs_y ), Size2i(1,get_row_height())),border_color); + } + if (highlight_all_occurrences) { if (highlighted_text_col != -1) { // if we are at the end check for new word on same line if (j > highlighted_text_col+highlighted_text.length()) { - highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, j); + highlighted_text_col = _get_column_pos_of_word(highlighted_text, str, SEARCH_MATCH_CASE|SEARCH_WHOLE_WORDS, j); } bool in_highlighted_word = (j >= highlighted_text_col && j < highlighted_text_col+highlighted_text.length()); @@ -3221,6 +3250,8 @@ void TextEdit::_update_caches() { cache.breakpoint_color=get_color("breakpoint_color"); cache.brace_mismatch_color=get_color("brace_mismatch_color"); cache.word_highlighted_color=get_color("word_highlighted_color"); + cache.search_result_color=get_color("search_result_color"); + cache.search_result_border_color=get_color("search_result_border_color"); cache.line_spacing=get_constant("line_spacing"); cache.row_height = cache.font->get_height() + cache.line_spacing; cache.tab_icon=get_icon("tab"); @@ -3482,12 +3513,25 @@ String TextEdit::get_word_under_cursor() const { return text[cursor.line].substr(prev_cc, next_cc-prev_cc); } +void TextEdit::set_search_text(const String &p_search_text) { + search_text = p_search_text; +} + +void TextEdit::set_search_flags(uint32_t p_flags) { + search_flags = p_flags; +} + +void TextEdit::set_current_search_result(int line, int col) { + search_result_line = line; + search_result_col = col; +} + void TextEdit::set_highlight_all_occurrences(const bool p_enabled) { highlight_all_occurrences = p_enabled; update(); } -int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_search, int p_from_column) { +int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_search, uint32_t p_search_flags, int p_from_column) { int col = -1; if (p_key.length() > 0 && p_search.length() > 0) { @@ -3495,12 +3539,15 @@ int TextEdit::_get_column_pos_of_word(const String &p_key, const String &p_searc p_from_column = 0; } - while (col == -1 && p_from_column <= p_search.length()) { - // match case - col = p_search.findn(p_key, p_from_column); + while (col == -1 && p_from_column <= p_search.length()) { + if (p_search_flags&SEARCH_MATCH_CASE) { + col = p_search.find(p_key,p_from_column); + } else { + col = p_search.findn(p_key,p_from_column); + } // whole words only - if (col != -1) { + if (col != -1 && p_search_flags&SEARCH_WHOLE_WORDS) { p_from_column=col; if (col > 0 && _is_text_char(p_search[col-1])) { diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h index dbe6293240e..f39b898c669 100644 --- a/scene/gui/text_edit.h +++ b/scene/gui/text_edit.h @@ -88,6 +88,8 @@ class TextEdit : public Control { Color current_line_color; Color brace_mismatch_color; Color word_highlighted_color; + Color search_result_color; + Color search_result_border_color; int row_height; int line_spacing; @@ -249,6 +251,11 @@ class TextEdit : public Control { bool callhint_below; Vector2 callhint_offset; + String search_text; + uint32_t search_flags; + int search_result_line; + int search_result_col; + int get_visible_rows() const; int get_char_count(); @@ -287,7 +294,7 @@ class TextEdit : public Control { String _base_get_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column) const; void _base_remove_text(int p_from_line, int p_from_column,int p_to_line,int p_to_column); - int _get_column_pos_of_word(const String &p_key, const String &p_search, int p_from_column); + int _get_column_pos_of_word(const String &p_key, const String &p_search, uint32_t p_search_flags, int p_from_column); DVector _search_bind(const String &p_key,uint32_t p_search_flags, int p_from_line,int p_from_column) const; @@ -408,6 +415,10 @@ public: void select(int p_from_line,int p_from_column,int p_to_line,int p_to_column); void deselect(); + void set_search_text(const String& p_search_text); + void set_search_flags(uint32_t p_flags); + void set_current_search_result(int line, int col); + void set_highlight_all_occurrences(const bool p_enabled); bool is_selection_active() const; int get_selection_from_line() const; diff --git a/tools/editor/code_editor.cpp b/tools/editor/code_editor.cpp index c92b40628c6..0702974051f 100644 --- a/tools/editor/code_editor.cpp +++ b/tools/editor/code_editor.cpp @@ -30,6 +30,7 @@ #include "editor_settings.h" #include "scene/gui/margin_container.h" #include "scene/gui/separator.h" +#include "os/keyboard.h" void GotoLineDialog::popup_find_line(TextEdit *p_edit) { @@ -76,6 +77,436 @@ GotoLineDialog::GotoLineDialog() { } +void FindReplaceBar::_notification(int p_what) { + + if (p_what == NOTIFICATION_READY) { + + find_prev->set_icon(get_icon("MoveUp", "EditorIcons")); + find_next->set_icon(get_icon("MoveDown", "EditorIcons")); + hide_button->set_normal_texture(get_icon("Close","EditorIcons")); + hide_button->set_hover_texture(get_icon("CloseHover","EditorIcons")); + hide_button->set_pressed_texture(get_icon("Close","EditorIcons")); + + } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) { + + set_process_unhandled_input(is_visible()); + } +} + +void FindReplaceBar::_unhandled_input(const InputEvent &p_event) { + + if (p_event.type == InputEvent::KEY) { + + const InputEventKey& k = p_event.key; + + if (k.pressed && (text_edit->has_focus() || text_vbc->is_a_parent_of(get_focus_owner()))) { + + bool accepted = true; + + switch (k.scancode) { + + case KEY_ESCAPE: { + + _hide_bar(); + } break; + default: { + + accepted = false; + } break; + } + + if (accepted) { + accept_event(); + } + } + } +} + +bool FindReplaceBar::_search(bool p_include_current, bool p_backwards) { + + String text=get_search_text(); + uint32_t flags=0; + + if (is_whole_words()) + flags|=TextEdit::SEARCH_WHOLE_WORDS; + if (is_case_sensitive()) + flags|=TextEdit::SEARCH_MATCH_CASE; + if (p_backwards) + flags|=TextEdit::SEARCH_BACKWARDS; + + int line=text_edit->cursor_get_line(); + int col=text_edit->cursor_get_column(); + + if (text_edit->is_selection_active() && !replace_all_mode) { + line = text_edit->get_selection_from_line(); + col = text_edit->get_selection_from_column(); + } + + bool cursor_at_result=false; + + if (line==current_result_line && col>=current_result_col && col<=current_result_col+text.length()) { + col=current_result_col; + cursor_at_result=true; + } + + if (!p_include_current) { + if (p_backwards) { + col-=text.length(); + if (col<0) { + line-=1; + if (line<0) + line=text_edit->get_line_count()-1; + col=text_edit->get_line(line).length(); + } + } else if (cursor_at_result) { + col+=text.length(); + if (col>text_edit->get_line(line).length()) { + line+=1; + if (line>=text_edit->get_line_count()) + line=0; + col=0; + } + } + } + + bool found = text_edit->search(text,flags,line,col,line,col); + + if (!found) { + if (p_backwards) { + line = text_edit->get_line_count()-1; + col = text_edit->get_line(line).length()-1; + } else { + line = 0; + col = 0; + } + + found = text_edit->search(text,flags,line,col,line,col); + } + + if (found) { + text_edit->cursor_set_line(line); + text_edit->cursor_set_column(p_backwards?col:col+text.length()); + text_edit->select(line,col,line,col+text.length()); + text_edit->set_search_text(text); + text_edit->set_search_flags(flags); + text_edit->set_current_search_result(line,col); + + current_result_line = line; + current_result_col = col; + + set_error(""); + } else { + current_result_line = -1; + current_result_col = -1; + text_edit->set_search_text(""); + set_error(text.empty()?"":TTR("No Matches")); + } + + return found; +} + +void FindReplaceBar::_replace() { + + if (text_edit->get_selection_text()==get_search_text()) { + text_edit->insert_text_at_cursor(get_replace_text()); + } + + search_current(); +} + +void FindReplaceBar::_replace_all() { + + // line as x so it gets priority in comparison, column as y + Point2i orig_cursor(text_edit->cursor_get_line(),text_edit->cursor_get_column()); + Point2i prev_match=Point2(-1,-1); + + bool selection_enabled = text_edit->is_selection_active(); + Point2i selection_begin,selection_end; + if (selection_enabled) { + selection_begin=Point2i(text_edit->get_selection_from_line(),text_edit->get_selection_from_column()); + selection_end=Point2i(text_edit->get_selection_to_line(),text_edit->get_selection_to_column()); + } + + int vsval = text_edit->get_v_scroll(); + + text_edit->cursor_set_line(0); + text_edit->cursor_set_column(0); + + int rc=0; + + replace_all_mode = true; + + text_edit->begin_complex_operation(); + + while(_search(false)) { + + if (!text_edit->is_selection_active()) { + // search selects + break; + } + + // replace area + Point2i match_from(text_edit->get_selection_from_line(),text_edit->get_selection_from_column()); + Point2i match_to(text_edit->get_selection_to_line(),text_edit->get_selection_to_column()); + + if (match_from < prev_match) + break; // done + + prev_match=match_to; + + if (selection_enabled && is_selection_only()) { + + if (match_fromselection_end) + continue; + + // replace but adjust selection bounds + text_edit->insert_text_at_cursor(get_replace_text()); + if (match_to.x==selection_end.x) + selection_end.y+=get_replace_text().length() - get_search_text().length(); + } else { + //just replace + text_edit->insert_text_at_cursor(get_replace_text()); + } + + rc++; + } + + text_edit->end_complex_operation(); + + replace_all_mode = false; + + // restore editor state (selection, cursor, scroll) + text_edit->cursor_set_line(orig_cursor.x); + text_edit->cursor_set_column(orig_cursor.y); + + if (selection_enabled && is_selection_only()) { + // reselect + text_edit->select(selection_begin.x,selection_begin.y,selection_end.x,selection_end.y); + } else { + text_edit->deselect(); + } + + text_edit->set_v_scroll(vsval); + set_error(vformat(TTR("Replaced %d Ocurrence(s)."), rc)); +} + +void FindReplaceBar::search_current() { + + _search(true); +} + +void FindReplaceBar::search_prev() { + + _search(false, true); +} + +void FindReplaceBar::search_next() { + + _search(); +} + +void FindReplaceBar::_hide_bar() { + + text_edit->set_search_text(""); + current_result_line = -1; + current_result_col = -1; + replace_hbc->hide(); + replace_options_hbc->hide(); + hide(); +} + +void FindReplaceBar::_show_search() { + + show(); + search_text->grab_focus(); + + if (text_edit->is_selection_active()) { + search_text->set_text(text_edit->get_selection_text()); + } + + if (!get_search_text().empty()) { + search_text->select_all(); + search_text->set_cursor_pos(search_text->get_text().length()); + search_current(); + } +} + +void FindReplaceBar::popup_search() { + + replace_hbc->hide(); + replace_options_hbc->hide(); + _show_search(); +} + +void FindReplaceBar::popup_replace() { + + if (!replace_hbc->is_visible() || !replace_options_hbc->is_visible()) { + replace_text->clear(); + replace_hbc->show(); + replace_options_hbc->show(); + } + + _show_search(); +} + +void FindReplaceBar::_search_options_changed(bool p_pressed) { + + search_current(); +} + +void FindReplaceBar::_search_text_changed(const String& p_text) { + + search_current(); +} + +void FindReplaceBar::_search_text_entered(const String& p_text) { + + search_next(); +} + +String FindReplaceBar::get_search_text() const { + + return search_text->get_text(); +} + +String FindReplaceBar::get_replace_text() const { + + return replace_text->get_text(); +} + +bool FindReplaceBar::is_case_sensitive() const { + + return case_sensitive->is_pressed(); +} + +bool FindReplaceBar::is_whole_words() const { + + return whole_words->is_pressed(); +} + +bool FindReplaceBar::is_selection_only() const { + + return selection_only->is_pressed(); +} + +void FindReplaceBar::set_error(const String &p_label) { + + error_label->set_text(p_label); +} + +void FindReplaceBar::set_text_edit(TextEdit *p_text_edit) { + + text_edit = p_text_edit; + text_edit->connect("_text_changed",this,"_search_text_changed",varray(String())); +} + +void FindReplaceBar::_bind_methods() { + + ObjectTypeDB::bind_method("_unhandled_input",&FindReplaceBar::_unhandled_input); + + ObjectTypeDB::bind_method("_search_text_changed",&FindReplaceBar::_search_text_changed); + ObjectTypeDB::bind_method("_search_text_entered",&FindReplaceBar::_search_text_entered); + ObjectTypeDB::bind_method("_search_current",&FindReplaceBar::search_current); + ObjectTypeDB::bind_method("_search_next",&FindReplaceBar::search_next); + ObjectTypeDB::bind_method("_search_prev",&FindReplaceBar::search_prev); + ObjectTypeDB::bind_method("_replace_pressed",&FindReplaceBar::_replace); + ObjectTypeDB::bind_method("_replace_all_pressed",&FindReplaceBar::_replace_all); + ObjectTypeDB::bind_method("_search_options_changed",&FindReplaceBar::_search_options_changed); + ObjectTypeDB::bind_method("_hide_pressed",&FindReplaceBar::_hide_bar); + + ADD_SIGNAL(MethodInfo("search")); +} + +FindReplaceBar::FindReplaceBar() { + + text_vbc = memnew(VBoxContainer); + add_child(text_vbc); + + HBoxContainer *search_hbc = memnew(HBoxContainer); + text_vbc->add_child(search_hbc); + + search_text = memnew(LineEdit); + search_hbc->add_child(search_text); + search_text->set_custom_minimum_size(Size2(200, 0)); + search_text->connect("text_changed",this,"_search_text_changed"); + search_text->connect("text_entered",this,"_search_text_entered"); + + find_prev = memnew(ToolButton); + search_hbc->add_child(find_prev); + find_prev->set_focus_mode(FOCUS_NONE); + find_prev->connect("pressed",this,"_search_prev"); + + find_next = memnew(ToolButton); + search_hbc->add_child(find_next); + find_next->set_focus_mode(FOCUS_NONE); + find_next->connect("pressed",this,"_search_next"); + + replace_hbc = memnew(HBoxContainer); + text_vbc->add_child(replace_hbc); + replace_hbc->hide(); + + replace_text = memnew(LineEdit); + replace_hbc->add_child(replace_text); + replace_text->set_custom_minimum_size(Size2(200, 0)); + replace_text->connect("text_entered",this,"_search_text_entered"); + + replace = memnew(ToolButton); + replace_hbc->add_child(replace); + replace->set_text(TTR("Replace")); + replace->set_focus_mode(FOCUS_NONE); + replace->connect("pressed",this,"_replace_pressed"); + + replace_all = memnew(ToolButton); + replace_hbc->add_child(replace_all); + replace_all->set_text(TTR("Replace All")); + replace_all->set_focus_mode(FOCUS_NONE); + replace_all->connect("pressed",this,"_replace_all_pressed"); + + Control *spacer_split = memnew( Control ); + spacer_split->set_custom_minimum_size(Size2(0, 1)); + text_vbc->add_child(spacer_split); + + VBoxContainer *options_vbc = memnew(VBoxContainer); + add_child(options_vbc); + options_vbc->set_h_size_flags(SIZE_EXPAND_FILL); + + HBoxContainer *search_options = memnew(HBoxContainer); + options_vbc->add_child(search_options); + + case_sensitive = memnew(CheckBox); + search_options->add_child(case_sensitive); + case_sensitive->set_text(TTR("Match Case")); + case_sensitive->set_focus_mode(FOCUS_NONE); + case_sensitive->connect("toggled",this,"_search_options_changed"); + + whole_words = memnew(CheckBox); + search_options->add_child(whole_words); + whole_words->set_text(TTR("Whole Words")); + whole_words->set_focus_mode(FOCUS_NONE); + whole_words->connect("toggled",this,"_search_options_changed"); + + error_label = memnew(Label); + search_options->add_child(error_label); + + search_options->add_spacer(); + + hide_button = memnew(TextureButton); + search_options->add_child(hide_button); + hide_button->set_focus_mode(FOCUS_NONE); + hide_button->connect("pressed",this,"_hide_pressed"); + + replace_options_hbc = memnew(HBoxContainer); + options_vbc->add_child(replace_options_hbc); + replace_options_hbc->hide(); + + selection_only = memnew(CheckBox); + replace_options_hbc->add_child(selection_only); + selection_only->set_text(TTR("Selection Only")); + selection_only->set_focus_mode(FOCUS_NONE); + selection_only->connect("toggled",this,"_search_options_changed"); +} + + void FindReplaceDialog::popup_search() { set_title(TTR("Search")); @@ -602,10 +1033,16 @@ void CodeTextEditor::_bind_methods() { CodeTextEditor::CodeTextEditor() { + find_replace_bar = memnew( FindReplaceBar ); + add_child(find_replace_bar); + find_replace_bar->set_h_size_flags(SIZE_EXPAND_FILL); + find_replace_bar->hide(); + text_editor = memnew( TextEdit ); add_child(text_editor); - text_editor->set_area_as_parent_rect(); - text_editor->set_margin(MARGIN_BOTTOM,20); + text_editor->set_v_size_flags(SIZE_EXPAND_FILL); + + find_replace_bar->set_text_edit(text_editor); String editor_font = EDITOR_DEF("text_editor/font", ""); bool font_overrode = false; @@ -624,13 +1061,17 @@ CodeTextEditor::CodeTextEditor() { text_editor->set_brace_matching(true); text_editor->set_auto_indent(true); - line_col = memnew( Label ); - add_child(line_col); - line_col->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_END,135); - line_col->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,15); - line_col->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,1); - line_col->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,5); - //line_col->set_align(Label::ALIGN_RIGHT); + MarginContainer *status_mc = memnew( MarginContainer ); + add_child(status_mc); + status_mc->set("custom_constants/margin_left", 2); + status_mc->set("custom_constants/margin_top", 5); + status_mc->set("custom_constants/margin_right", 2); + status_mc->set("custom_constants/margin_bottom", 1); + + HBoxContainer *status_bar = memnew( HBoxContainer ); + status_mc->add_child(status_bar); + status_bar->set_h_size_flags(SIZE_EXPAND_FILL); + idle = memnew( Timer ); add_child(idle); idle->set_one_shot(true); @@ -644,14 +1085,16 @@ CodeTextEditor::CodeTextEditor() { code_complete_timer->set_wait_time(EDITOR_DEF("text_editor/code_complete_delay",.3f)); error = memnew( Label ); - add_child(error); - error->set_anchor_and_margin(MARGIN_LEFT,ANCHOR_BEGIN,5); - error->set_anchor_and_margin(MARGIN_TOP,ANCHOR_END,15); - error->set_anchor_and_margin(MARGIN_BOTTOM,ANCHOR_END,1); - error->set_anchor_and_margin(MARGIN_RIGHT,ANCHOR_END,130); + status_bar->add_child(error); error->hide(); + error->set_valign(Label::VALIGN_CENTER); error->add_color_override("font_color",Color(1,0.7,0.6,0.9)); + status_bar->add_spacer(); + + line_col = memnew( Label ); + status_bar->add_child(line_col); + line_col->set_valign(Label::VALIGN_CENTER); text_editor->connect("cursor_changed", this,"_line_col_changed"); diff --git a/tools/editor/code_editor.h b/tools/editor/code_editor.h index e28517c6010..e786a1e8a27 100644 --- a/tools/editor/code_editor.h +++ b/tools/editor/code_editor.h @@ -33,7 +33,9 @@ #include "scene/gui/text_edit.h" #include "scene/gui/dialogs.h" #include "scene/main/timer.h" +#include "scene/gui/tool_button.h" #include "scene/gui/check_button.h" +#include "scene/gui/check_box.h" #include "scene/gui/line_edit.h" @@ -58,8 +60,71 @@ public: GotoLineDialog(); }; +class FindReplaceBar : public HBoxContainer { + OBJ_TYPE(FindReplaceBar,HBoxContainer); + LineEdit *search_text; + ToolButton *find_prev; + ToolButton *find_next; + CheckBox *case_sensitive; + CheckBox *whole_words; + Label *error_label; + TextureButton *hide_button; + + LineEdit *replace_text; + ToolButton *replace; + ToolButton *replace_all; + CheckBox *selection_only; + + VBoxContainer *text_vbc; + HBoxContainer *replace_hbc; + HBoxContainer *replace_options_hbc; + + TextEdit *text_edit; + + int current_result_line; + int current_result_col; + + bool replace_all_mode; + + void _show_search(); + void _hide_bar(); + void _search_options_changed(bool p_pressed); + void _search_text_changed(const String& p_text); + void _search_text_entered(const String& p_text); + +protected: + void _notification(int p_what); + void _unhandled_input(const InputEvent &p_event); + + bool _search(bool p_include_current=false, bool p_backwards=false); + + void _replace(); + void _replace_all(); + + static void _bind_methods(); + +public: + String get_search_text() const; + String get_replace_text() const; + + bool is_case_sensitive() const; + bool is_whole_words() const; + bool is_selection_only() const; + void set_error(const String& p_label); + + void set_text_edit(TextEdit *p_text_edit); + + void popup_search(); + void popup_replace(); + + void search_current(); + void search_prev(); + void search_next(); + + FindReplaceBar(); +}; class FindReplaceDialog : public ConfirmationDialog { @@ -119,11 +184,12 @@ public: }; -class CodeTextEditor : public Control { +class CodeTextEditor : public VBoxContainer { - OBJ_TYPE(CodeTextEditor,Control); + OBJ_TYPE(CodeTextEditor,VBoxContainer); TextEdit *text_editor; + FindReplaceBar *find_replace_bar; Label *line_col; Label *info; @@ -157,6 +223,7 @@ protected: public: TextEdit *get_text_edit() { return text_editor; } + FindReplaceBar *get_find_replace_bar() { return find_replace_bar; } virtual void apply_code() {} CodeTextEditor(); diff --git a/tools/editor/editor_settings.cpp b/tools/editor/editor_settings.cpp index ad990e3fab4..125323af789 100644 --- a/tools/editor/editor_settings.cpp +++ b/tools/editor/editor_settings.cpp @@ -559,6 +559,8 @@ void EditorSettings::_load_default_text_editor_theme() { set("text_editor/mark_color", Color(1.0,0.4,0.4,0.4)); set("text_editor/breakpoint_color", Color(0.8,0.8,0.4,0.2)); set("text_editor/word_highlighted_color",Color(0.8,0.9,0.9,0.15)); + set("text_editor/search_result_color",Color(0.05,0.25,0.05,1)); + set("text_editor/search_result_border_color",Color(0.1,0.45,0.1,1)); } void EditorSettings::notify_changes() { @@ -790,6 +792,8 @@ bool EditorSettings::_save_text_editor_theme(String p_file) { cf->set_value(theme_section, "mark_color", ((Color)get("text_editor/mark_color")).to_html()); cf->set_value(theme_section, "breakpoint_color", ((Color)get("text_editor/breakpoint_color")).to_html()); cf->set_value(theme_section, "word_highlighted_color", ((Color)get("text_editor/word_highlighted_color")).to_html()); + cf->set_value(theme_section, "search_result_color", ((Color)get("text_editor/search_result_color")).to_html()); + cf->set_value(theme_section, "search_result_border_color", ((Color)get("text_editor/search_result_border_color")).to_html()); Error err = cf->save(p_file); if (err == OK) { diff --git a/tools/editor/plugins/script_editor_plugin.cpp b/tools/editor/plugins/script_editor_plugin.cpp index e3c339f1d64..34f7c7b5e8f 100644 --- a/tools/editor/plugins/script_editor_plugin.cpp +++ b/tools/editor/plugins/script_editor_plugin.cpp @@ -300,6 +300,8 @@ void ScriptTextEditor::_load_theme_settings() { get_text_edit()->add_color_override("member_variable_color",EDITOR_DEF("text_editor/member_variable_color",Color(0.9,0.3,0.3))); get_text_edit()->add_color_override("mark_color", EDITOR_DEF("text_editor/mark_color", Color(1.0,0.4,0.4,0.4))); get_text_edit()->add_color_override("breakpoint_color", EDITOR_DEF("text_editor/breakpoint_color", Color(0.8,0.8,0.4,0.2))); + get_text_edit()->add_color_override("search_result_color",EDITOR_DEF("text_editor/search_result_color",Color(0.05,0.25,0.05,1))); + get_text_edit()->add_color_override("search_result_border_color",EDITOR_DEF("text_editor/search_result_border_color",Color(0.1,0.45,0.1,1))); Color keyword_color= EDITOR_DEF("text_editor/keyword_color",Color(0.5,0.0,0.2)); @@ -1405,18 +1407,19 @@ void ScriptEditor::_menu_option(int p_option) { } break; case SEARCH_FIND: { - find_replace_dialog->set_text_edit(current->get_text_edit()); - find_replace_dialog->popup_search(); + current->get_find_replace_bar()->popup_search(); } break; case SEARCH_FIND_NEXT: { - find_replace_dialog->set_text_edit(current->get_text_edit()); - find_replace_dialog->search_next(); + current->get_find_replace_bar()->search_next(); + } break; + case SEARCH_FIND_PREV: { + + current->get_find_replace_bar()->search_prev(); } break; case SEARCH_REPLACE: { - find_replace_dialog->set_text_edit(current->get_text_edit()); - find_replace_dialog->popup_replace(); + current->get_find_replace_bar()->popup_replace(); } break; case SEARCH_LOCATE_FUNCTION: { @@ -2531,6 +2534,7 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { search_menu->set_text(TTR("Search")); search_menu->get_popup()->add_item(TTR("Find.."),SEARCH_FIND,KEY_MASK_CMD|KEY_F); search_menu->get_popup()->add_item(TTR("Find Next"),SEARCH_FIND_NEXT,KEY_F3); + search_menu->get_popup()->add_item(TTR("Find Previous"),SEARCH_FIND_PREV,KEY_MASK_SHIFT|KEY_F3); search_menu->get_popup()->add_item(TTR("Replace.."),SEARCH_REPLACE,KEY_MASK_CMD|KEY_R); search_menu->get_popup()->add_separator(); search_menu->get_popup()->add_item(TTR("Goto Function.."),SEARCH_LOCATE_FUNCTION,KEY_MASK_SHIFT|KEY_MASK_CMD|KEY_F); @@ -2635,9 +2639,6 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) { tab_container->connect("tab_changed", this,"_tab_changed"); - find_replace_dialog = memnew(FindReplaceDialog); - add_child(find_replace_dialog); - erase_tab_confirm = memnew( ConfirmationDialog ); add_child(erase_tab_confirm); erase_tab_confirm->connect("confirmed", this,"_close_current_tab"); diff --git a/tools/editor/plugins/script_editor_plugin.h b/tools/editor/plugins/script_editor_plugin.h index 20e0b621c44..c6610a02094 100644 --- a/tools/editor/plugins/script_editor_plugin.h +++ b/tools/editor/plugins/script_editor_plugin.h @@ -144,6 +144,7 @@ class ScriptEditor : public VBoxContainer { EDIT_CLONE_DOWN, SEARCH_FIND, SEARCH_FIND_NEXT, + SEARCH_FIND_PREV, SEARCH_REPLACE, SEARCH_LOCATE_FUNCTION, SEARCH_GOTO_LINE, @@ -184,7 +185,6 @@ class ScriptEditor : public VBoxContainer { HSplitContainer *script_split; TabContainer *tab_container; EditorFileDialog *file_dialog; - FindReplaceDialog *find_replace_dialog; GotoLineDialog *goto_line_dialog; ConfirmationDialog *erase_tab_confirm; ScriptCreateDialog *script_create_dialog; diff --git a/tools/editor/plugins/shader_editor_plugin.cpp b/tools/editor/plugins/shader_editor_plugin.cpp index cc121d6c6f3..0ca6a069bc7 100644 --- a/tools/editor/plugins/shader_editor_plugin.cpp +++ b/tools/editor/plugins/shader_editor_plugin.cpp @@ -90,6 +90,8 @@ void ShaderTextEditor::_load_theme_settings() { get_text_edit()->add_color_override("member_variable_color",EDITOR_DEF("text_editor/member_variable_color",Color(0.9,0.3,0.3))); get_text_edit()->add_color_override("mark_color", EDITOR_DEF("text_editor/mark_color", Color(1.0,0.4,0.4,0.4))); get_text_edit()->add_color_override("breakpoint_color", EDITOR_DEF("text_editor/breakpoint_color", Color(0.8,0.8,0.4,0.2))); + get_text_edit()->add_color_override("search_result_color",EDITOR_DEF("text_editor/search_result_color",Color(0.05,0.25,0.05,1))); + get_text_edit()->add_color_override("search_result_border_color",EDITOR_DEF("text_editor/search_result_border_color",Color(0.1,0.45,0.1,1))); Color keyword_color= EDITOR_DEF("text_editor/keyword_color",Color(0.5,0.0,0.2)); @@ -212,18 +214,19 @@ void ShaderEditor::_menu_option(int p_option) { } break; case SEARCH_FIND: { - find_replace_dialog->set_text_edit(current->get_text_edit()); - find_replace_dialog->popup_search(); + current->get_find_replace_bar()->popup_search(); } break; case SEARCH_FIND_NEXT: { - find_replace_dialog->set_text_edit(current->get_text_edit()); - find_replace_dialog->search_next(); + current->get_find_replace_bar()->search_next(); + } break; + case SEARCH_FIND_PREV: { + + current->get_find_replace_bar()->search_prev(); } break; case SEARCH_REPLACE: { - find_replace_dialog->set_text_edit(current->get_text_edit()); - find_replace_dialog->popup_replace(); + current->get_find_replace_bar()->popup_replace(); } break; // case SEARCH_LOCATE_SYMBOL: { @@ -507,6 +510,7 @@ ShaderEditor::ShaderEditor() { search_menu->set_text(TTR("Search")); search_menu->get_popup()->add_item(TTR("Find.."),SEARCH_FIND,KEY_MASK_CMD|KEY_F); search_menu->get_popup()->add_item(TTR("Find Next"),SEARCH_FIND_NEXT,KEY_F3); + search_menu->get_popup()->add_item(TTR("Find Previous"),SEARCH_FIND_PREV,KEY_MASK_SHIFT|KEY_F3); search_menu->get_popup()->add_item(TTR("Replace.."),SEARCH_REPLACE,KEY_MASK_CMD|KEY_R); search_menu->get_popup()->add_separator(); // search_menu->get_popup()->add_item("Locate Symbol..",SEARCH_LOCATE_SYMBOL,KEY_MASK_CMD|KEY_K); @@ -516,9 +520,6 @@ ShaderEditor::ShaderEditor() { tab_container->connect("tab_changed", this,"_tab_changed"); - find_replace_dialog = memnew(FindReplaceDialog); - add_child(find_replace_dialog); - erase_tab_confirm = memnew( ConfirmationDialog ); add_child(erase_tab_confirm); erase_tab_confirm->connect("confirmed", this,"_close_current_tab"); diff --git a/tools/editor/plugins/shader_editor_plugin.h b/tools/editor/plugins/shader_editor_plugin.h index e10c10a4463..9219a1fbc27 100644 --- a/tools/editor/plugins/shader_editor_plugin.h +++ b/tools/editor/plugins/shader_editor_plugin.h @@ -76,6 +76,7 @@ class ShaderEditor : public Control { EDIT_SELECT_ALL, SEARCH_FIND, SEARCH_FIND_NEXT, + SEARCH_FIND_PREV, SEARCH_REPLACE, //SEARCH_LOCATE_SYMBOL, SEARCH_GOTO_LINE, @@ -88,7 +89,6 @@ class ShaderEditor : public Control { uint64_t idle; TabContainer *tab_container; - FindReplaceDialog *find_replace_dialog; GotoLineDialog *goto_line_dialog; ConfirmationDialog *erase_tab_confirm;