diff options
author | thankyouverycool <66646555+thankyouverycool@users.noreply.github.com> | 2022-12-15 12:26:05 -0500 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-12-20 10:22:27 +0100 |
commit | c4ac73d0738243fd3cd0246d5038b2319f0f07a4 (patch) | |
tree | bf824cb07323d53fc2135f65f4f4d614a0b3f294 | |
parent | 12cd30f1acd6bccfba07d3054d71feb0467a3d78 (diff) | |
download | serenity-c4ac73d0738243fd3cd0246d5038b2319f0f07a4.zip |
LibGUI: Check bounds when moving GlyphMapWidget selections
Fixes crashing on invalid code points when creating selections
with the keyboard and applying actions to them.
Also adds Home/End key support for selections. Ctrl+Shift+{Home,End}
now extends the selection to the beginning or end of the active range,
respectively. Shift+{Home,End} extends the selection to the start or
end of the row. Alt+{Home,End} resets the selection and moves the
active glyph to the beginning or end of the active range.
-rw-r--r-- | Userland/Libraries/LibGUI/GlyphMapWidget.cpp | 129 |
1 files changed, 79 insertions, 50 deletions
diff --git a/Userland/Libraries/LibGUI/GlyphMapWidget.cpp b/Userland/Libraries/LibGUI/GlyphMapWidget.cpp index 9157ebda58..6ddc8319d2 100644 --- a/Userland/Libraries/LibGUI/GlyphMapWidget.cpp +++ b/Userland/Libraries/LibGUI/GlyphMapWidget.cpp @@ -264,78 +264,107 @@ void GlyphMapWidget::keydown_event(KeyEvent& event) return; } - int range_offset = m_active_range.first; - if (!event.ctrl() && !event.shift() && event.key() != KeyCode::Key_Delete) { m_selection.set_size(1); m_selection.set_start(m_active_glyph); } + int first_glyph = m_active_range.first; + int last_glyph = m_active_range.last; + auto selection = m_selection.normalized(); + if (event.key() == KeyCode::Key_Up) { - if (m_selection.start() - range_offset >= m_columns) { - if (event.shift()) - m_selection.resize_by(-m_columns); - else - m_selection.set_start(m_selection.start() - m_columns); - set_active_glyph(m_active_glyph - m_columns, ShouldResetSelection::No); - scroll_to_glyph(m_active_glyph); + if (m_active_glyph - m_columns < first_glyph) return; - } + if (event.ctrl() && selection.start() - m_columns < first_glyph) + return; + if (event.shift()) + m_selection.extend_to(m_active_glyph - m_columns); + else + m_selection.set_start(m_selection.start() - m_columns); + set_active_glyph(m_active_glyph - m_columns, ShouldResetSelection::No); + scroll_to_glyph(m_active_glyph); + return; } + if (event.key() == KeyCode::Key_Down) { - if (m_selection.start() < m_glyph_count + range_offset - m_columns) { - if (event.shift()) - m_selection.resize_by(m_columns); - else - m_selection.set_start(m_selection.start() + m_columns); - set_active_glyph(m_active_glyph + m_columns, ShouldResetSelection::No); - scroll_to_glyph(m_active_glyph); + if (m_active_glyph + m_columns > last_glyph) return; - } + if (event.ctrl() && selection.start() + selection.size() - 1 + m_columns > last_glyph) + return; + if (event.shift()) + m_selection.extend_to(m_active_glyph + m_columns); + else + m_selection.set_start(m_selection.start() + m_columns); + set_active_glyph(m_active_glyph + m_columns, ShouldResetSelection::No); + scroll_to_glyph(m_active_glyph); + return; } + if (event.key() == KeyCode::Key_Left) { - if (m_selection.start() > range_offset) { - if (event.shift()) - m_selection.resize_by(-1); - else - m_selection.set_start(m_selection.start() - 1); - set_active_glyph(m_active_glyph - 1, ShouldResetSelection::No); - scroll_to_glyph(m_active_glyph); + if (m_active_glyph - 1 < first_glyph) return; - } - } - if (event.key() == KeyCode::Key_Right) { - if (m_selection.start() < m_glyph_count + range_offset - 1) { - if (event.shift()) - m_selection.resize_by(1); - else - m_selection.set_start(m_selection.start() + 1); - set_active_glyph(m_active_glyph + 1, ShouldResetSelection::No); - scroll_to_glyph(m_active_glyph); + if (event.ctrl() && selection.start() - 1 < first_glyph) return; - } - } - - // FIXME: Support selection for these. - if (event.ctrl() && event.key() == KeyCode::Key_Home) { - set_active_glyph(m_active_range.first); + if (event.shift()) + m_selection.resize_by(-1); + else + m_selection.set_start(m_selection.start() - 1); + set_active_glyph(m_active_glyph - 1, ShouldResetSelection::No); scroll_to_glyph(m_active_glyph); return; } - if (event.ctrl() && event.key() == KeyCode::Key_End) { - set_active_glyph(m_active_range.last); + + if (event.key() == KeyCode::Key_Right) { + if (m_active_glyph + 1 > last_glyph) + return; + if (event.ctrl() && selection.start() + selection.size() > last_glyph) + return; + if (event.shift()) + m_selection.resize_by(1); + else + m_selection.set_start(m_selection.start() + 1); + set_active_glyph(m_active_glyph + 1, ShouldResetSelection::No); scroll_to_glyph(m_active_glyph); return; } - if (!event.ctrl() && event.key() == KeyCode::Key_Home) { - auto start_of_row = (m_active_glyph - range_offset) / m_columns * m_columns; - set_active_glyph(start_of_row + range_offset); + + if (event.key() == KeyCode::Key_Home) { + if (event.alt()) { + set_active_glyph(first_glyph); + scroll_to_glyph(m_active_glyph); + return; + } + if (event.ctrl() && event.shift()) { + m_selection.extend_to(first_glyph); + set_active_glyph(first_glyph, ShouldResetSelection::No); + scroll_to_glyph(m_active_glyph); + return; + } + auto start_of_row = (m_active_glyph - first_glyph) / m_columns * m_columns; + if (event.shift()) + m_selection.extend_to(start_of_row + first_glyph); + set_active_glyph(start_of_row + first_glyph, event.shift() ? ShouldResetSelection::No : ShouldResetSelection::Yes); return; } - if (!event.ctrl() && event.key() == KeyCode::Key_End) { - auto end_of_row = (m_active_glyph - range_offset) / m_columns * m_columns + (m_columns - 1); - end_of_row = clamp(end_of_row + range_offset, m_active_range.first, m_active_range.last); - set_active_glyph(end_of_row); + + if (event.key() == KeyCode::Key_End) { + if (event.alt()) { + set_active_glyph(last_glyph); + scroll_to_glyph(m_active_glyph); + return; + } + if (event.ctrl() && event.shift()) { + m_selection.extend_to(last_glyph); + set_active_glyph(last_glyph, ShouldResetSelection::No); + scroll_to_glyph(m_active_glyph); + return; + } + auto end_of_row = (m_active_glyph - first_glyph) / m_columns * m_columns + (m_columns - 1); + end_of_row = clamp(end_of_row + first_glyph, first_glyph, last_glyph); + if (event.shift()) + m_selection.extend_to(end_of_row); + set_active_glyph(end_of_row, event.shift() ? ShouldResetSelection::No : ShouldResetSelection::Yes); return; } |