summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Weller <andrewweller.cs@gmail.com>2019-08-24 12:09:35 -0600
committerAndreas Kling <awesomekling@gmail.com>2019-08-24 21:57:42 +0200
commite75e33eb46188eefa50ea4d11e4861b047d309fc (patch)
tree4d59fe0d69f79624856cc4559d4318cb8ea73a3b
parent952baf32cd97d44ec4226980a45a283d2068f45b (diff)
downloadserenity-e75e33eb46188eefa50ea4d11e4861b047d309fc.zip
TextEditor: Replaced 'Find' button with 'Prev' and 'Next' buttons.
-rw-r--r--Applications/TextEditor/TextEditorWidget.cpp39
-rw-r--r--Applications/TextEditor/TextEditorWidget.h3
-rw-r--r--Libraries/LibGUI/GTextEditor.cpp48
-rw-r--r--Libraries/LibGUI/GTextEditor.h8
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&);