summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2021-01-03 00:11:56 +0100
committerAndreas Kling <kling@serenityos.org>2021-01-03 10:49:20 +0100
commit906e310411a50273b9c4aa9f1d2ed2fb62b56ec9 (patch)
tree49d9f2d65f29d3e5781082269897c702f97e81a5
parentbd2a7c414c7fe5b4ce0d5834506452f577a2aafb (diff)
downloadserenity-906e310411a50273b9c4aa9f1d2ed2fb62b56ec9.zip
LibGUI: Improve up/down arrow behavior in TextEditor with wrapping
Instead of moving between physical lines, the up/down arrow keys now move between visual lines.
-rw-r--r--Libraries/LibGUI/TextEditor.cpp48
-rw-r--r--Libraries/LibGUI/TextEditor.h1
2 files changed, 35 insertions, 14 deletions
diff --git a/Libraries/LibGUI/TextEditor.cpp b/Libraries/LibGUI/TextEditor.cpp
index c85bfbd162..7ad7a88af1 100644
--- a/Libraries/LibGUI/TextEditor.cpp
+++ b/Libraries/LibGUI/TextEditor.cpp
@@ -148,13 +148,9 @@ void TextEditor::update_content_size()
set_size_occupied_by_fixed_elements({ ruler_width(), 0 });
}
-TextPosition TextEditor::text_position_at(const Gfx::IntPoint& a_position) const
+TextPosition TextEditor::text_position_at_content_position(const Gfx::IntPoint& content_position) const
{
- auto position = a_position;
- position.move_by(horizontal_scrollbar().value(), vertical_scrollbar().value());
- position.move_by(-(m_horizontal_content_padding + ruler_width()), 0);
- position.move_by(-frame_thickness(), -frame_thickness());
-
+ auto position = content_position;
if (is_single_line() && icon())
position.move_by(-(icon_size() + icon_padding()), 0);
@@ -212,6 +208,15 @@ TextPosition TextEditor::text_position_at(const Gfx::IntPoint& a_position) const
return { line_index, column_index };
}
+TextPosition TextEditor::text_position_at(const Gfx::IntPoint& widget_position) const
+{
+ auto content_position = widget_position;
+ content_position.move_by(horizontal_scrollbar().value(), vertical_scrollbar().value());
+ content_position.move_by(-(m_horizontal_content_padding + ruler_width()), 0);
+ content_position.move_by(-frame_thickness(), -frame_thickness());
+ return text_position_at_content_position(content_position);
+}
+
void TextEditor::doubleclick_event(MouseEvent& event)
{
if (event.button() != MouseButton::Left)
@@ -760,15 +765,22 @@ void TextEditor::keydown_event(KeyEvent& event)
return;
}
if (is_multi_line() && event.key() == KeyCode::Key_Up) {
- if (m_cursor.line() > 0) {
+ if (m_cursor.line() > 0 || m_line_wrapping_enabled) {
if (event.ctrl() && event.shift()) {
move_selected_lines_up();
return;
}
- size_t new_line = m_cursor.line() - 1;
- size_t new_column = min(m_cursor.column(), line(new_line).length());
+ TextPosition new_cursor;
+ if (m_line_wrapping_enabled) {
+ auto position_above = cursor_content_rect().location().translated(0, -line_height());
+ new_cursor = text_position_at_content_position(position_above);
+ } else {
+ size_t new_line = m_cursor.line() - 1;
+ size_t new_column = min(m_cursor.column(), line(new_line).length());
+ new_cursor = { new_line, new_column };
+ }
toggle_selection_if_needed_for_event(event);
- set_cursor(new_line, new_column);
+ set_cursor(new_cursor);
if (event.shift() && m_selection.start().is_valid()) {
m_selection.set_end(m_cursor);
did_update_selection();
@@ -781,15 +793,23 @@ void TextEditor::keydown_event(KeyEvent& event)
return;
}
if (is_multi_line() && event.key() == KeyCode::Key_Down) {
- if (m_cursor.line() < (line_count() - 1)) {
+ if (m_cursor.line() < (line_count() - 1) || m_line_wrapping_enabled) {
if (event.ctrl() && event.shift()) {
move_selected_lines_down();
return;
}
- size_t new_line = m_cursor.line() + 1;
- size_t new_column = min(m_cursor.column(), line(new_line).length());
+ TextPosition new_cursor;
+ if (m_line_wrapping_enabled) {
+ new_cursor = text_position_at_content_position(cursor_content_rect().location().translated(0, line_height()));
+ auto position_below = cursor_content_rect().location().translated(0, line_height());
+ new_cursor = text_position_at_content_position(position_below);
+ } else {
+ size_t new_line = m_cursor.line() + 1;
+ size_t new_column = min(m_cursor.column(), line(new_line).length());
+ new_cursor = { new_line, new_column };
+ }
toggle_selection_if_needed_for_event(event);
- set_cursor(new_line, new_column);
+ set_cursor(new_cursor);
if (event.shift() && m_selection.start().is_valid()) {
m_selection.set_end(m_cursor);
did_update_selection();
diff --git a/Libraries/LibGUI/TextEditor.h b/Libraries/LibGUI/TextEditor.h
index 7a0dcb0456..bfc146fac8 100644
--- a/Libraries/LibGUI/TextEditor.h
+++ b/Libraries/LibGUI/TextEditor.h
@@ -191,6 +191,7 @@ protected:
Gfx::IntRect ruler_content_rect(size_t line) const;
TextPosition text_position_at(const Gfx::IntPoint&) const;
+ TextPosition text_position_at_content_position(const Gfx::IntPoint&) const;
bool ruler_visible() const { return m_ruler_visible; }
Gfx::IntRect content_rect_for_position(const TextPosition&) const;
int ruler_width() const;