mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-31 23:22:03 +03:00
LibGUI: Support cycling through focusable widgets with Tab and Shift-Tab.
This commit is contained in:
parent
01ffcdfa31
commit
ad731cc08f
Notes:
sideshowbarker
2024-07-19 14:08:48 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/ad731cc08f2
@ -21,7 +21,6 @@ private:
|
||||
virtual void paint_event(GPaintEvent&) override;
|
||||
virtual void mousedown_event(GMouseEvent&) override;
|
||||
virtual void mousemove_event(GMouseEvent&) override;
|
||||
virtual bool accepts_focus() const override { return true; }
|
||||
|
||||
void draw_at_mouse(const GMouseEvent&);
|
||||
|
||||
|
@ -27,7 +27,6 @@ public:
|
||||
private:
|
||||
virtual void paint_event(GPaintEvent&) override;
|
||||
virtual void mousedown_event(GMouseEvent&) override;
|
||||
virtual bool accepts_focus() const override { return true; }
|
||||
|
||||
Rect get_outer_rect(byte glyph) const;
|
||||
|
||||
|
@ -60,9 +60,15 @@ void GButton::paint_event(GPaintEvent& event)
|
||||
content_rect.move_by(m_icon->width() + 4, 0);
|
||||
content_rect.set_width(content_rect.width() - m_icon->width() - 4);
|
||||
}
|
||||
if (is_enabled())
|
||||
if (is_enabled()) {
|
||||
painter.draw_text(content_rect, m_caption, font, text_alignment(), foreground_color(), TextElision::Right);
|
||||
else {
|
||||
if (is_focused()) {
|
||||
Rect focus_rect = { 0, 0, font.width(m_caption), font.glyph_height() };
|
||||
focus_rect.inflate(6, 4);
|
||||
focus_rect.center_within(content_rect);
|
||||
painter.draw_rect(focus_rect, Color(140, 140, 140));
|
||||
}
|
||||
} else {
|
||||
painter.draw_text(content_rect.translated(1, 1), m_caption, font, text_alignment(), Color::White, TextElision::Right);
|
||||
painter.draw_text(content_rect, m_caption, font, text_alignment(), Color::from_rgb(0x808080), TextElision::Right);
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ public:
|
||||
void set_action(GAction&);
|
||||
|
||||
virtual const char* class_name() const override { return "GButton"; }
|
||||
virtual bool accepts_focus() const override { return true; }
|
||||
|
||||
protected:
|
||||
virtual void paint_event(GPaintEvent&) override;
|
||||
|
@ -60,7 +60,9 @@ void GCheckBox::paint_event(GPaintEvent& event)
|
||||
|
||||
auto text_rect = rect();
|
||||
text_rect.set_left(s_box_width + 4);
|
||||
text_rect.set_width(font().width(m_caption));
|
||||
text_rect.set_top(height() / 2 - font().glyph_height() / 2);
|
||||
text_rect.set_height(font().glyph_height());
|
||||
|
||||
if (fill_with_background_color())
|
||||
painter.fill_rect(rect(), background_color());
|
||||
@ -78,8 +80,14 @@ void GCheckBox::paint_event(GPaintEvent& event)
|
||||
if (m_checked)
|
||||
painter.draw_bitmap(box_rect.shrunken(4, 4).location(), *s_checked_bitmap, foreground_color());
|
||||
|
||||
if (!caption().is_empty())
|
||||
if (!caption().is_empty()) {
|
||||
painter.draw_text(text_rect, caption(), TextAlignment::TopLeft, foreground_color());
|
||||
if (is_focused()) {
|
||||
Rect focus_rect = text_rect;
|
||||
focus_rect.inflate(6, 4);
|
||||
painter.draw_rect(focus_rect, Color(140, 140, 140));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GCheckBox::mousemove_event(GMouseEvent& event)
|
||||
|
@ -315,6 +315,9 @@ void GTextEditor::toggle_selection_if_needed_for_event(const GKeyEvent& event)
|
||||
|
||||
void GTextEditor::keydown_event(GKeyEvent& event)
|
||||
{
|
||||
if (is_single_line() && event.key() == KeyCode::Key_Tab)
|
||||
return GWidget::keydown_event(event);
|
||||
|
||||
if (event.key() == KeyCode::Key_Escape) {
|
||||
if (on_escape_pressed)
|
||||
on_escape_pressed();
|
||||
@ -505,8 +508,6 @@ void GTextEditor::keydown_event(GKeyEvent& event)
|
||||
|
||||
if (!is_readonly() && !event.ctrl() && !event.alt() && !event.text().is_empty())
|
||||
insert_at_cursor_or_replace_selection(event.text());
|
||||
|
||||
return GWidget::keydown_event(event);
|
||||
}
|
||||
|
||||
void GTextEditor::delete_current_line()
|
||||
|
@ -243,8 +243,14 @@ void GWidget::hide_event(GHideEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void GWidget::keydown_event(GKeyEvent&)
|
||||
void GWidget::keydown_event(GKeyEvent& event)
|
||||
{
|
||||
if (!event.alt() && !event.ctrl() && !event.logo() && event.key() == KeyCode::Key_Tab) {
|
||||
if (event.shift())
|
||||
focus_previous_widget();
|
||||
else
|
||||
focus_next_widget();
|
||||
}
|
||||
}
|
||||
|
||||
void GWidget::keyup_event(GKeyEvent&)
|
||||
@ -543,3 +549,29 @@ void GWidget::set_updates_enabled(bool enabled)
|
||||
if (enabled)
|
||||
update();
|
||||
}
|
||||
|
||||
void GWidget::focus_previous_widget()
|
||||
{
|
||||
auto focusable_widgets = window()->focusable_widgets();
|
||||
for (int i = focusable_widgets.size() - 1; i >= 0; --i) {
|
||||
if (focusable_widgets[i] != this)
|
||||
continue;
|
||||
if (i > 0)
|
||||
focusable_widgets[i - 1]->set_focus(true);
|
||||
else
|
||||
focusable_widgets.last()->set_focus(true);
|
||||
}
|
||||
}
|
||||
|
||||
void GWidget::focus_next_widget()
|
||||
{
|
||||
auto focusable_widgets = window()->focusable_widgets();
|
||||
for (int i = 0; i < focusable_widgets.size(); ++i) {
|
||||
if (focusable_widgets[i] != this)
|
||||
continue;
|
||||
if (i < focusable_widgets.size() - 1)
|
||||
focusable_widgets[i + 1]->set_focus(true);
|
||||
else
|
||||
focusable_widgets.first()->set_focus(true);
|
||||
}
|
||||
}
|
||||
|
@ -194,6 +194,8 @@ private:
|
||||
void handle_enter_event(CEvent&);
|
||||
void handle_leave_event(CEvent&);
|
||||
void do_layout();
|
||||
void focus_previous_widget();
|
||||
void focus_next_widget();
|
||||
|
||||
CElapsedTimer& click_clock(GMouseButton);
|
||||
|
||||
|
@ -513,3 +513,27 @@ void GWindow::start_wm_resize()
|
||||
message.wm.window_id = m_window_id;
|
||||
GEventLoop::post_message_to_server(message);
|
||||
}
|
||||
|
||||
Vector<GWidget*> GWindow::focusable_widgets() const
|
||||
{
|
||||
if (!m_main_widget)
|
||||
return { };
|
||||
|
||||
Vector<GWidget*> collected_widgets;
|
||||
|
||||
Function<void(GWidget&)> collect_focusable_widgets = [&] (GWidget& widget) {
|
||||
if (widget.accepts_focus())
|
||||
collected_widgets.append(&widget);
|
||||
for (auto& child : widget.children()) {
|
||||
if (!child->is_widget())
|
||||
continue;
|
||||
auto& child_widget = *static_cast<GWidget*>(child);
|
||||
if (!child_widget.is_visible())
|
||||
continue;
|
||||
collect_focusable_widgets(child_widget);
|
||||
}
|
||||
};
|
||||
|
||||
collect_focusable_widgets(*m_main_widget);
|
||||
return collected_widgets;
|
||||
}
|
||||
|
@ -113,6 +113,8 @@ public:
|
||||
String icon_path() const { return m_icon_path; }
|
||||
void set_icon_path(const String&);
|
||||
|
||||
Vector<GWidget*> focusable_widgets() const;
|
||||
|
||||
virtual const char* class_name() const override { return "GWindow"; }
|
||||
|
||||
protected:
|
||||
|
Loading…
Reference in New Issue
Block a user