diff options
author | Andreas Kling <awesomekling@gmail.com> | 2019-03-08 14:08:15 +0100 |
---|---|---|
committer | Andreas Kling <awesomekling@gmail.com> | 2019-03-08 14:08:15 +0100 |
commit | 48d48679b0475d525db9bc644acd3157d4117f69 (patch) | |
tree | 936fe6703aa06ebeaf98adbe0344a7309edf9821 | |
parent | b8581b0069ba8591013f00a08e6ba8ee8a0588e2 (diff) | |
download | serenity-48d48679b0475d525db9bc644acd3157d4117f69.zip |
GTextEditor: Work on cut/copy/paste operations.
-rw-r--r-- | AK/String.cpp | 2 | ||||
-rw-r--r-- | Applications/TextEditor/main.cpp | 10 | ||||
-rw-r--r-- | LibGUI/GTextEditor.cpp | 76 | ||||
-rw-r--r-- | LibGUI/GTextEditor.h | 7 |
4 files changed, 88 insertions, 7 deletions
diff --git a/AK/String.cpp b/AK/String.cpp index 8fd8e2fec2..4c3e2692ac 100644 --- a/AK/String.cpp +++ b/AK/String.cpp @@ -38,6 +38,8 @@ String String::isolated_copy() const String String::substring(ssize_t start, ssize_t length) const { + if (!length) + return empty(); ASSERT(m_impl); ASSERT(start + length <= m_impl->length()); // FIXME: This needs some input bounds checking. diff --git a/Applications/TextEditor/main.cpp b/Applications/TextEditor/main.cpp index 9200794c22..3ee579032c 100644 --- a/Applications/TextEditor/main.cpp +++ b/Applications/TextEditor/main.cpp @@ -8,7 +8,6 @@ #include <LibGUI/GTextEditor.h> #include <LibGUI/GAction.h> #include <LibGUI/GFontDatabase.h> -#include <LibGUI/GClipboard.h> #include <AK/StringBuilder.h> #include <unistd.h> #include <stdio.h> @@ -80,18 +79,15 @@ int main(int argc, char** argv) }); auto cut_action = GAction::create("Cut", { Mod_Ctrl, Key_X }, GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/cut16.rgb", { 16, 16 }), [&] (const GAction&) { - dbgprintf("FIXME: Implement Edit/Cut"); + text_editor->cut(); }); auto copy_action = GAction::create("Copy", { Mod_Ctrl, Key_C }, GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/copyfile16.rgb", { 16, 16 }), [&] (const GAction&) { - auto selected_text = text_editor->selected_text(); - printf("Copy: \"%s\"\n", selected_text.characters()); - GClipboard::the().set_data(selected_text); + text_editor->copy(); }); auto paste_action = GAction::create("Paste", { Mod_Ctrl, Key_V }, GraphicsBitmap::load_from_file(GraphicsBitmap::Format::RGBA32, "/res/icons/paste16.rgb", { 16, 16 }), [&] (const GAction&) { - auto paste_text = GClipboard::the().data(); - printf("Paste: \"%s\"\n", paste_text.characters()); + text_editor->paste(); }); auto menubar = make<GMenuBar>(); diff --git a/LibGUI/GTextEditor.cpp b/LibGUI/GTextEditor.cpp index 6a2652685e..696bd80c5e 100644 --- a/LibGUI/GTextEditor.cpp +++ b/LibGUI/GTextEditor.cpp @@ -1,6 +1,7 @@ #include <LibGUI/GTextEditor.h> #include <LibGUI/GScrollBar.h> #include <LibGUI/GFontDatabase.h> +#include <LibGUI/GClipboard.h> #include <SharedGraphics/Painter.h> #include <Kernel/KeyCode.h> #include <AK/StringBuilder.h> @@ -344,6 +345,14 @@ void GTextEditor::keydown_event(GKeyEvent& event) return GWidget::keydown_event(event); } +void GTextEditor::insert_at_cursor(const String& text) +{ + // FIXME: This should obviously not be implemented this way. + for (int i = 0; i < text.length(); ++i) { + insert_at_cursor(text[i]); + } +} + void GTextEditor::insert_at_cursor(char ch) { bool at_head = m_cursor.column() == 0; @@ -449,6 +458,7 @@ void GTextEditor::set_cursor(int line, int column) void GTextEditor::set_cursor(const GTextPosition& position) { + ASSERT(!m_lines.is_empty()); if (m_cursor == position) return; auto old_cursor_line_rect = line_widget_rect(m_cursor.line()); @@ -596,3 +606,69 @@ String GTextEditor::selected_text() const return builder.to_string(); } + +void GTextEditor::delete_selection() +{ + if (!has_selection()) + return; + + auto normalized_selection_start = m_selection_start; + auto normalized_selection_end = m_cursor; + if (m_cursor < m_selection_start) + swap(normalized_selection_start, normalized_selection_end); + + for (int i = normalized_selection_start.line(); i <= normalized_selection_end.line();) { + auto& line = *m_lines[i]; + int selection_start_column_on_line = normalized_selection_start.line() == i ? normalized_selection_start.column() : 0; + int selection_end_column_on_line = normalized_selection_end.line() == i ? normalized_selection_end.column() : line.length(); + bool whole_line_is_selected = selection_start_column_on_line == 0 && selection_end_column_on_line == line.length(); + if (whole_line_is_selected) { + m_lines.remove(i); + normalized_selection_end.set_line(normalized_selection_end.line() - 1); + continue; + } + auto before_selection = String(line.characters(), line.length()).substring(0, selection_start_column_on_line); + auto after_selection = String(line.characters(), line.length()).substring(selection_end_column_on_line, line.length() - selection_end_column_on_line); + StringBuilder builder(before_selection.length() + after_selection.length()); + builder.append(before_selection); + builder.append(after_selection); + line.set_text(builder.to_string()); + ++i; + } + + if (m_lines.is_empty()) + m_lines.append(make<Line>()); + + m_selection_start = { }; + set_cursor(normalized_selection_start); + update(); +} + +void GTextEditor::insert_at_cursor_or_replace_selection(const String& text) +{ + if (has_selection()) + delete_selection(); + insert_at_cursor(text); +} + +void GTextEditor::cut() +{ + auto selected_text = this->selected_text(); + printf("Cut: \"%s\"\n", selected_text.characters()); + GClipboard::the().set_data(selected_text); + delete_selection(); +} + +void GTextEditor::copy() +{ + auto selected_text = this->selected_text(); + printf("Copy: \"%s\"\n", selected_text.characters()); + GClipboard::the().set_data(selected_text); +} + +void GTextEditor::paste() +{ + auto paste_text = GClipboard::the().data(); + printf("Paste: \"%s\"\n", paste_text.characters()); + insert_at_cursor_or_replace_selection(paste_text); +} diff --git a/LibGUI/GTextEditor.h b/LibGUI/GTextEditor.h index 6ccc4b3297..145b42f1f6 100644 --- a/LibGUI/GTextEditor.h +++ b/LibGUI/GTextEditor.h @@ -56,6 +56,10 @@ public: bool has_selection() const { return m_selection_start.is_valid(); } String selected_text() const; + void cut(); + void copy(); + void paste(); + private: virtual void paint_event(GPaintEvent&) override; virtual void resize_event(GResizeEvent&) override; @@ -98,9 +102,12 @@ private: const Line& current_line() const { return *m_lines[m_cursor.line()]; } GTextPosition text_position_at(const Point&) const; void insert_at_cursor(char); + void insert_at_cursor(const String&); int ruler_width() const; Rect ruler_content_rect(int line) const; void toggle_selection_if_needed_for_event(const GKeyEvent&); + void insert_at_cursor_or_replace_selection(const String&); + void delete_selection(); GScrollBar* m_vertical_scrollbar { nullptr }; GScrollBar* m_horizontal_scrollbar { nullptr }; |