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.
This commit is contained in:
thankyouverycool 2022-12-15 12:26:05 -05:00 committed by Andreas Kling
parent 12cd30f1ac
commit c4ac73d073
Notes: sideshowbarker 2024-07-17 10:08:28 +09:00

View file

@ -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.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 (event.ctrl() && selection.start() - m_columns < first_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);
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);
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;
}
// FIXME: Support selection for these.
if (event.ctrl() && event.key() == KeyCode::Key_Home) {
set_active_glyph(m_active_range.first);
if (event.key() == KeyCode::Key_Down) {
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.ctrl() && event.key() == KeyCode::Key_End) {
set_active_glyph(m_active_range.last);
if (event.key() == KeyCode::Key_Left) {
if (m_active_glyph - 1 < first_glyph)
return;
if (event.ctrl() && selection.start() - 1 < first_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_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_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_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.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;
}