mirror of
https://github.com/RGBCube/serenity
synced 2025-05-30 23:28:12 +00:00
TextEditor: Replaced 'Find' button with 'Prev' and 'Next' buttons.
This commit is contained in:
parent
952baf32cd
commit
e75e33eb46
4 changed files with 87 additions and 11 deletions
|
@ -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] {
|
||||
|
|
|
@ -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 };
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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&);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue