mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 15:48:12 +00:00
GTextEditor: Work on cut/copy/paste operations.
This commit is contained in:
parent
b8581b0069
commit
48d48679b0
4 changed files with 88 additions and 7 deletions
|
@ -38,6 +38,8 @@ String String::isolated_copy() const
|
||||||
|
|
||||||
String String::substring(ssize_t start, ssize_t length) const
|
String String::substring(ssize_t start, ssize_t length) const
|
||||||
{
|
{
|
||||||
|
if (!length)
|
||||||
|
return empty();
|
||||||
ASSERT(m_impl);
|
ASSERT(m_impl);
|
||||||
ASSERT(start + length <= m_impl->length());
|
ASSERT(start + length <= m_impl->length());
|
||||||
// FIXME: This needs some input bounds checking.
|
// FIXME: This needs some input bounds checking.
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
#include <LibGUI/GTextEditor.h>
|
#include <LibGUI/GTextEditor.h>
|
||||||
#include <LibGUI/GAction.h>
|
#include <LibGUI/GAction.h>
|
||||||
#include <LibGUI/GFontDatabase.h>
|
#include <LibGUI/GFontDatabase.h>
|
||||||
#include <LibGUI/GClipboard.h>
|
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <stdio.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&) {
|
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 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();
|
text_editor->copy();
|
||||||
printf("Copy: \"%s\"\n", selected_text.characters());
|
|
||||||
GClipboard::the().set_data(selected_text);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
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_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();
|
text_editor->paste();
|
||||||
printf("Paste: \"%s\"\n", paste_text.characters());
|
|
||||||
});
|
});
|
||||||
|
|
||||||
auto menubar = make<GMenuBar>();
|
auto menubar = make<GMenuBar>();
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
#include <LibGUI/GTextEditor.h>
|
#include <LibGUI/GTextEditor.h>
|
||||||
#include <LibGUI/GScrollBar.h>
|
#include <LibGUI/GScrollBar.h>
|
||||||
#include <LibGUI/GFontDatabase.h>
|
#include <LibGUI/GFontDatabase.h>
|
||||||
|
#include <LibGUI/GClipboard.h>
|
||||||
#include <SharedGraphics/Painter.h>
|
#include <SharedGraphics/Painter.h>
|
||||||
#include <Kernel/KeyCode.h>
|
#include <Kernel/KeyCode.h>
|
||||||
#include <AK/StringBuilder.h>
|
#include <AK/StringBuilder.h>
|
||||||
|
@ -344,6 +345,14 @@ void GTextEditor::keydown_event(GKeyEvent& event)
|
||||||
return GWidget::keydown_event(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)
|
void GTextEditor::insert_at_cursor(char ch)
|
||||||
{
|
{
|
||||||
bool at_head = m_cursor.column() == 0;
|
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)
|
void GTextEditor::set_cursor(const GTextPosition& position)
|
||||||
{
|
{
|
||||||
|
ASSERT(!m_lines.is_empty());
|
||||||
if (m_cursor == position)
|
if (m_cursor == position)
|
||||||
return;
|
return;
|
||||||
auto old_cursor_line_rect = line_widget_rect(m_cursor.line());
|
auto old_cursor_line_rect = line_widget_rect(m_cursor.line());
|
||||||
|
@ -596,3 +606,69 @@ String GTextEditor::selected_text() const
|
||||||
|
|
||||||
return builder.to_string();
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -56,6 +56,10 @@ public:
|
||||||
bool has_selection() const { return m_selection_start.is_valid(); }
|
bool has_selection() const { return m_selection_start.is_valid(); }
|
||||||
String selected_text() const;
|
String selected_text() const;
|
||||||
|
|
||||||
|
void cut();
|
||||||
|
void copy();
|
||||||
|
void paste();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void paint_event(GPaintEvent&) override;
|
virtual void paint_event(GPaintEvent&) override;
|
||||||
virtual void resize_event(GResizeEvent&) override;
|
virtual void resize_event(GResizeEvent&) override;
|
||||||
|
@ -98,9 +102,12 @@ private:
|
||||||
const Line& current_line() const { return *m_lines[m_cursor.line()]; }
|
const Line& current_line() const { return *m_lines[m_cursor.line()]; }
|
||||||
GTextPosition text_position_at(const Point&) const;
|
GTextPosition text_position_at(const Point&) const;
|
||||||
void insert_at_cursor(char);
|
void insert_at_cursor(char);
|
||||||
|
void insert_at_cursor(const String&);
|
||||||
int ruler_width() const;
|
int ruler_width() const;
|
||||||
Rect ruler_content_rect(int line) const;
|
Rect ruler_content_rect(int line) const;
|
||||||
void toggle_selection_if_needed_for_event(const GKeyEvent&);
|
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_vertical_scrollbar { nullptr };
|
||||||
GScrollBar* m_horizontal_scrollbar { nullptr };
|
GScrollBar* m_horizontal_scrollbar { nullptr };
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue