diff options
author | Andrew Weller <andrewweller.cs@gmail.com> | 2019-08-24 12:09:35 -0600 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-08-24 21:57:42 +0200 |
commit | e75e33eb46188eefa50ea4d11e4861b047d309fc (patch) | |
tree | 4d59fe0d69f79624856cc4559d4318cb8ea73a3b | |
parent | 952baf32cd97d44ec4226980a45a283d2068f45b (diff) | |
download | serenity-e75e33eb46188eefa50ea4d11e4861b047d309fc.zip |
TextEditor: Replaced 'Find' button with 'Prev' and 'Next' buttons.
-rw-r--r-- | Applications/TextEditor/TextEditorWidget.cpp | 39 | ||||
-rw-r--r-- | Applications/TextEditor/TextEditorWidget.h | 3 | ||||
-rw-r--r-- | Libraries/LibGUI/GTextEditor.cpp | 48 | ||||
-rw-r--r-- | Libraries/LibGUI/GTextEditor.h | 8 |
4 files changed, 87 insertions, 11 deletions
diff --git a/Applications/TextEditor/TextEditorWidget.cpp b/Applications/TextEditor/TextEditorWidget.cpp index cf006278fb..e3ee83daf0 100644 --- a/Applications/TextEditor/TextEditorWidget.cpp +++ b/Applications/TextEditor/TextEditorWidget.cpp @@ -34,14 +34,39 @@ TextEditorWidget::TextEditorWidget() m_find_textbox = new GTextBox(m_find_widget); - m_find_button = new GButton("Find", m_find_widget); - m_find_button->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill); - m_find_button->set_preferred_size(100, 0); + m_find_prev_button = new GButton("Prev", m_find_widget); + m_find_prev_button->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill); + m_find_prev_button->set_preferred_size(50, 0); - m_find_button->on_click = [this](auto&) { + m_find_next_button = new GButton("Next", m_find_widget); + m_find_next_button->set_size_policy(SizePolicy::Fixed, SizePolicy::Fill); + m_find_next_button->set_preferred_size(50, 0); + + m_find_next_button->on_click = [this](auto&) { auto needle = m_find_textbox->text(); - auto found_range = m_editor->find(needle, m_editor->normalized_selection().end()); - dbg() << "find(\"" << needle << "\") returned " << found_range; + auto found_range = m_editor->find_next(needle, m_editor->normalized_selection().end()); + dbg() << "find_next(\"" << needle << "\") returned " << found_range; + if (found_range.is_valid()) { + m_editor->set_selection(found_range); + } else { + GMessageBox::show( + String::format("Not found: \"%s\"", needle.characters()), + "Not found", + GMessageBox::Type::Information, + GMessageBox::InputType::OK, window()); + } + }; + + m_find_prev_button->on_click = [this](auto&) { + auto needle = m_find_textbox->text(); + + auto selection_start = m_editor->normalized_selection().start(); + if (!selection_start.is_valid()) + selection_start = m_editor->normalized_selection().end(); + + auto found_range = m_editor->find_prev(needle, selection_start); + + dbg() << "find_prev(\"" << needle << "\") returned " << found_range; if (found_range.is_valid()) { m_editor->set_selection(found_range); } else { @@ -54,7 +79,7 @@ TextEditorWidget::TextEditorWidget() }; m_find_textbox->on_return_pressed = [this] { - m_find_button->click(); + m_find_next_button->click(); }; m_find_textbox->on_escape_pressed = [this] { diff --git a/Applications/TextEditor/TextEditorWidget.h b/Applications/TextEditor/TextEditorWidget.h index cf7d8820de..714b054619 100644 --- a/Applications/TextEditor/TextEditorWidget.h +++ b/Applications/TextEditor/TextEditorWidget.h @@ -31,6 +31,7 @@ private: RefPtr<GAction> m_find_action; GTextBox* m_find_textbox { nullptr }; - GButton* m_find_button { nullptr }; + GButton* m_find_prev_button { nullptr }; + GButton* m_find_next_button { nullptr }; GWidget* m_find_widget { nullptr }; }; diff --git a/Libraries/LibGUI/GTextEditor.cpp b/Libraries/LibGUI/GTextEditor.cpp index 6200499111..5dc36c5a3b 100644 --- a/Libraries/LibGUI/GTextEditor.cpp +++ b/Libraries/LibGUI/GTextEditor.cpp @@ -1105,7 +1105,23 @@ GTextPosition GTextEditor::next_position_after(const GTextPosition& position, Sh return { position.line(), position.column() + 1 }; } -GTextRange GTextEditor::find(const StringView& needle, const GTextPosition& start) +GTextPosition GTextEditor::prev_position_before(const GTextPosition& position, ShouldWrapAtStartOfDocument should_wrap) +{ + if (position.column() == 0){ + if (position.line() == 0) { + if (should_wrap == ShouldWrapAtStartOfDocument::Yes) { + auto& last_line = m_lines[line_count() - 1]; + return { line_count() - 1, last_line.length() }; + } + return {}; + } + auto& prev_line = m_lines[position.line() - 1]; + return { position.line() - 1, prev_line.length() }; + } + return { position.line(), position.column() - 1 }; +} + +GTextRange GTextEditor::find_next(const StringView& needle, const GTextPosition& start) { if (needle.is_empty()) return {}; @@ -1135,6 +1151,36 @@ GTextRange GTextEditor::find(const StringView& needle, const GTextPosition& star return {}; } +GTextRange GTextEditor::find_prev(const StringView& needle, const GTextPosition& start) +{ + if (needle.is_empty()) + return {}; + + GTextPosition position = start.is_valid() ? start : GTextPosition(0, 0); + GTextPosition original_position = position; + + GTextPosition end_of_potential_match; + int needle_index = needle.length() - 1; + + do { + auto ch = character_at(position); + if (ch == needle[needle_index]) { + if (needle_index == needle.length() - 1) + end_of_potential_match = position; + --needle_index; + if (needle_index < 0) + return { position, next_position_after(end_of_potential_match) }; + } else { + if (needle_index < needle.length() - 1) + position = end_of_potential_match; + needle_index = needle.length() - 1; + } + position = prev_position_before(position); + } while(position.is_valid() && position != original_position); + + return {}; +} + void GTextEditor::set_selection(const GTextRange& selection) { if (m_selection == selection) diff --git a/Libraries/LibGUI/GTextEditor.h b/Libraries/LibGUI/GTextEditor.h index be9468644b..dfa26ef57f 100644 --- a/Libraries/LibGUI/GTextEditor.h +++ b/Libraries/LibGUI/GTextEditor.h @@ -12,6 +12,7 @@ class GScrollBar; class Painter; enum class ShouldWrapAtEndOfDocument { No = 0, Yes }; +enum class ShouldWrapAtStartOfDocument { No = 0, Yes }; class GTextPosition { public: @@ -126,9 +127,12 @@ public: bool write_to_file(const StringView& path); - GTextRange find(const StringView&, const GTextPosition& start = {}); - GTextPosition next_position_after(const GTextPosition&, ShouldWrapAtEndOfDocument = ShouldWrapAtEndOfDocument::Yes); + GTextRange find_next(const StringView&, const GTextPosition& start = {}); + GTextRange find_prev(const StringView&, const GTextPosition& start = {}); + GTextPosition next_position_after(const GTextPosition&, ShouldWrapAtEndOfDocument = ShouldWrapAtEndOfDocument::Yes); + GTextPosition prev_position_before(const GTextPosition&, ShouldWrapAtStartOfDocument = ShouldWrapAtStartOfDocument::Yes); + bool has_selection() const { return m_selection.is_valid(); } String selected_text() const; void set_selection(const GTextRange&); |