From 6a569bbdd76a23d0875fa06c10e4ddb5838b0259 Mon Sep 17 00:00:00 2001 From: Zac Date: Fri, 13 Nov 2020 15:29:55 +1000 Subject: [PATCH] TextEditor: Change cursor behaviour when clicking empty space When clicking empty space (beneath any used lines) in the TextEditor, the cursor would jump to the start of the last line, rather than the correct column, or the end of the line where appropriate. This was because in the for_each_visual_line callback would return IterationDecision::Continue if the clicked point wasn't in the line's rect. Thus the callback would continue on each iteration and at the end, would set the cursor to the default column of 0. To fix this I added a bool to the callback's signature which tells the callback if the for_each_visual_line method is on the last visual line. The callback now does not return IterationDecision:Continue if for_each_visual_line method is on the last line and the correct column is then calculated with the line passed. --- Libraries/LibGUI/TextEditor.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Libraries/LibGUI/TextEditor.cpp b/Libraries/LibGUI/TextEditor.cpp index 5fe09d27af..67db277df3 100644 --- a/Libraries/LibGUI/TextEditor.cpp +++ b/Libraries/LibGUI/TextEditor.cpp @@ -170,8 +170,8 @@ TextPosition TextEditor::text_position_at(const Gfx::IntPoint& a_position) const size_t column_index = 0; switch (m_text_alignment) { case Gfx::TextAlignment::CenterLeft: - for_each_visual_line(line_index, [&](const Gfx::IntRect& rect, auto& view, size_t start_of_line) { - if (is_multi_line() && !rect.contains_vertically(position.y())) + for_each_visual_line(line_index, [&](const Gfx::IntRect& rect, auto& view, size_t start_of_line, [[maybe_unused]] bool is_last_visual_line) { + if (is_multi_line() && !rect.contains_vertically(position.y()) && !is_last_visual_line) return IterationDecision::Continue; column_index = start_of_line; if (position.x() <= 0) { @@ -459,7 +459,7 @@ void TextEditor::paint_event(PaintEvent& event) size_t selection_end_column_within_line = selection.end().line() == line_index ? selection.end().column() : line.length(); size_t visual_line_index = 0; - for_each_visual_line(line_index, [&](const Gfx::IntRect& visual_line_rect, auto& visual_line_text, size_t start_of_visual_line) { + for_each_visual_line(line_index, [&](const Gfx::IntRect& visual_line_rect, auto& visual_line_text, size_t start_of_visual_line, [[maybe_unused]] bool is_last_visual_line) { if (is_multi_line() && line_index == m_cursor.line()) painter.fill_rect(visual_line_rect, widget_background_color.darkened(0.9f)); #ifdef DEBUG_TEXTEDITOR @@ -1051,7 +1051,7 @@ int TextEditor::content_x_for_position(const TextPosition& position) const int x_offset = 0; switch (m_text_alignment) { case Gfx::TextAlignment::CenterLeft: - for_each_visual_line(position.line(), [&](const Gfx::IntRect&, auto& visual_line_view, size_t start_of_visual_line) { + for_each_visual_line(position.line(), [&](const Gfx::IntRect&, auto& visual_line_view, size_t start_of_visual_line, [[maybe_unused]] bool is_last_visual_line) { size_t offset_in_visual_line = position.column() - start_of_visual_line; if (position.column() >= start_of_visual_line && (offset_in_visual_line <= visual_line_view.length())) { if (offset_in_visual_line == 0) { @@ -1090,7 +1090,7 @@ Gfx::IntRect TextEditor::content_rect_for_position(const TextPosition& position) } Gfx::IntRect rect; - for_each_visual_line(position.line(), [&](const Gfx::IntRect& visual_line_rect, auto& view, size_t start_of_visual_line) { + for_each_visual_line(position.line(), [&](const Gfx::IntRect& visual_line_rect, auto& view, size_t start_of_visual_line, [[maybe_unused]] bool is_last_visual_line) { if (position.column() >= start_of_visual_line && ((position.column() - start_of_visual_line) <= view.length())) { // NOTE: We have to subtract the horizontal padding here since it's part of the visual line rect // *and* included in what we get from content_x_for_position(). @@ -1566,7 +1566,7 @@ void TextEditor::ensure_cursor_is_valid() size_t TextEditor::visual_line_containing(size_t line_index, size_t column) const { size_t visual_line_index = 0; - for_each_visual_line(line_index, [&](const Gfx::IntRect&, auto& view, size_t start_of_visual_line) { + for_each_visual_line(line_index, [&](const Gfx::IntRect&, auto& view, size_t start_of_visual_line, [[maybe_unused]] bool is_last_visual_line) { if (column >= start_of_visual_line && ((column - start_of_visual_line) < view.length())) return IterationDecision::Break; ++visual_line_index; @@ -1633,7 +1633,7 @@ void TextEditor::for_each_visual_line(size_t line_index, Callback callback) cons if (m_icon) visual_line_rect.move_by(icon_size() + icon_padding(), 0); } - if (callback(visual_line_rect, visual_line_view, start_of_line) == IterationDecision::Break) + if (callback(visual_line_rect, visual_line_view, start_of_line, visual_line_index == visual_data.visual_line_breaks.size() - 1) == IterationDecision::Break) break; start_of_line = visual_line_break; ++visual_line_index;