mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 06:48:12 +00:00
LibGUI: Make focus events more aware of why focus is changing
This patch adds GUI::FocusEvent which has a GUI::FocusSource. The focus source is one of three things: - Programmatic - Mouse - Keyboard This allows receivers of focus events to implement different behaviors depending on how they receive/lose focus.
This commit is contained in:
parent
110b3d89d3
commit
75b8f4e4e6
14 changed files with 94 additions and 41 deletions
|
@ -165,7 +165,7 @@ void ConsoleWidget::clear_output()
|
||||||
m_output_view->update();
|
m_output_view->update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConsoleWidget::focusin_event(Core::Event&)
|
void ConsoleWidget::focusin_event(GUI::FocusEvent&)
|
||||||
{
|
{
|
||||||
m_input->set_focus(true);
|
m_input->set_focus(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -48,7 +48,7 @@ private:
|
||||||
ConsoleWidget();
|
ConsoleWidget();
|
||||||
|
|
||||||
virtual bool accepts_focus() const override { return true; }
|
virtual bool accepts_focus() const override { return true; }
|
||||||
virtual void focusin_event(Core::Event&) override;
|
virtual void focusin_event(GUI::FocusEvent&) override;
|
||||||
|
|
||||||
RefPtr<GUI::TextBox> m_input;
|
RefPtr<GUI::TextBox> m_input;
|
||||||
RefPtr<Web::PageView> m_output_view;
|
RefPtr<Web::PageView> m_output_view;
|
||||||
|
|
|
@ -65,7 +65,7 @@ const EditorWrapper& Editor::wrapper() const
|
||||||
return static_cast<const EditorWrapper&>(*parent());
|
return static_cast<const EditorWrapper&>(*parent());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::focusin_event(Core::Event& event)
|
void Editor::focusin_event(GUI::FocusEvent& event)
|
||||||
{
|
{
|
||||||
wrapper().set_editor_has_focus({}, true);
|
wrapper().set_editor_has_focus({}, true);
|
||||||
if (on_focus)
|
if (on_focus)
|
||||||
|
@ -73,7 +73,7 @@ void Editor::focusin_event(Core::Event& event)
|
||||||
GUI::TextEditor::focusin_event(event);
|
GUI::TextEditor::focusin_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Editor::focusout_event(Core::Event& event)
|
void Editor::focusout_event(GUI::FocusEvent& event)
|
||||||
{
|
{
|
||||||
wrapper().set_editor_has_focus({}, false);
|
wrapper().set_editor_has_focus({}, false);
|
||||||
GUI::TextEditor::focusout_event(event);
|
GUI::TextEditor::focusout_event(event);
|
||||||
|
|
|
@ -51,8 +51,8 @@ public:
|
||||||
BreakpointChangeCallback on_breakpoint_change;
|
BreakpointChangeCallback on_breakpoint_change;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
virtual void focusin_event(Core::Event&) override;
|
virtual void focusin_event(GUI::FocusEvent&) override;
|
||||||
virtual void focusout_event(Core::Event&) override;
|
virtual void focusout_event(GUI::FocusEvent&) override;
|
||||||
virtual void paint_event(GUI::PaintEvent&) override;
|
virtual void paint_event(GUI::PaintEvent&) override;
|
||||||
virtual void mousemove_event(GUI::MouseEvent&) override;
|
virtual void mousemove_event(GUI::MouseEvent&) override;
|
||||||
virtual void mousedown_event(GUI::MouseEvent&) override;
|
virtual void mousedown_event(GUI::MouseEvent&) override;
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <Kernel/API/KeyCode.h>
|
#include <Kernel/API/KeyCode.h>
|
||||||
#include <LibCore/Event.h>
|
#include <LibCore/Event.h>
|
||||||
|
#include <LibGUI/FocusSource.h>
|
||||||
#include <LibGUI/WindowType.h>
|
#include <LibGUI/WindowType.h>
|
||||||
#include <LibGfx/Point.h>
|
#include <LibGfx/Point.h>
|
||||||
#include <LibGfx/Rect.h>
|
#include <LibGfx/Rect.h>
|
||||||
|
@ -76,12 +77,12 @@ public:
|
||||||
__End_WM_Events,
|
__End_WM_Events,
|
||||||
};
|
};
|
||||||
|
|
||||||
Event() {}
|
Event() { }
|
||||||
explicit Event(Type type)
|
explicit Event(Type type)
|
||||||
: Core::Event(type)
|
: Core::Event(type)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
virtual ~Event() {}
|
virtual ~Event() { }
|
||||||
|
|
||||||
bool is_key_event() const { return type() == KeyUp || type() == KeyDown; }
|
bool is_key_event() const { return type() == KeyUp || type() == KeyDown; }
|
||||||
bool is_paint_event() const { return type() == Paint; }
|
bool is_paint_event() const { return type() == Paint; }
|
||||||
|
@ -387,4 +388,18 @@ public:
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class FocusEvent final : public Event {
|
||||||
|
public:
|
||||||
|
explicit FocusEvent(Type type, FocusSource source)
|
||||||
|
: Event(type)
|
||||||
|
, m_source(source)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
FocusSource source() const { return m_source; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
FocusSource m_source { FocusSource::Programmatic };
|
||||||
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
37
Libraries/LibGUI/FocusSource.h
Normal file
37
Libraries/LibGUI/FocusSource.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Andreas Kling <kling@serenityos.org>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
* list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
||||||
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||||
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
||||||
|
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||||
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||||
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
namespace GUI {
|
||||||
|
|
||||||
|
enum class FocusSource {
|
||||||
|
Programmatic,
|
||||||
|
Keyboard,
|
||||||
|
Mouse,
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -1147,7 +1147,7 @@ void TextEditor::set_cursor(const TextPosition& a_position)
|
||||||
m_highlighter->cursor_did_change();
|
m_highlighter->cursor_did_change();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditor::focusin_event(Core::Event&)
|
void TextEditor::focusin_event(FocusEvent&)
|
||||||
{
|
{
|
||||||
m_cursor_state = true;
|
m_cursor_state = true;
|
||||||
update_cursor();
|
update_cursor();
|
||||||
|
@ -1156,7 +1156,7 @@ void TextEditor::focusin_event(Core::Event&)
|
||||||
on_focusin();
|
on_focusin();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditor::focusout_event(Core::Event&)
|
void TextEditor::focusout_event(FocusEvent&)
|
||||||
{
|
{
|
||||||
stop_timer();
|
stop_timer();
|
||||||
if (on_focusout)
|
if (on_focusout)
|
||||||
|
|
|
@ -166,8 +166,8 @@ protected:
|
||||||
virtual void mousemove_event(MouseEvent&) override;
|
virtual void mousemove_event(MouseEvent&) override;
|
||||||
virtual void doubleclick_event(MouseEvent&) override;
|
virtual void doubleclick_event(MouseEvent&) override;
|
||||||
virtual void keydown_event(KeyEvent&) override;
|
virtual void keydown_event(KeyEvent&) override;
|
||||||
virtual void focusin_event(Core::Event&) override;
|
virtual void focusin_event(FocusEvent&) override;
|
||||||
virtual void focusout_event(Core::Event&) override;
|
virtual void focusout_event(FocusEvent&) override;
|
||||||
virtual void timer_event(Core::TimerEvent&) override;
|
virtual void timer_event(Core::TimerEvent&) override;
|
||||||
virtual bool accepts_focus() const override { return true; }
|
virtual bool accepts_focus() const override { return true; }
|
||||||
virtual void enter_event(Core::Event&) override;
|
virtual void enter_event(Core::Event&) override;
|
||||||
|
|
|
@ -183,9 +183,9 @@ void Widget::event(Core::Event& event)
|
||||||
case Event::Resize:
|
case Event::Resize:
|
||||||
return handle_resize_event(static_cast<ResizeEvent&>(event));
|
return handle_resize_event(static_cast<ResizeEvent&>(event));
|
||||||
case Event::FocusIn:
|
case Event::FocusIn:
|
||||||
return focusin_event(event);
|
return focusin_event(static_cast<FocusEvent&>(event));
|
||||||
case Event::FocusOut:
|
case Event::FocusOut:
|
||||||
return focusout_event(event);
|
return focusout_event(static_cast<FocusEvent&>(event));
|
||||||
case Event::Show:
|
case Event::Show:
|
||||||
return show_event(static_cast<ShowEvent&>(event));
|
return show_event(static_cast<ShowEvent&>(event));
|
||||||
case Event::Hide:
|
case Event::Hide:
|
||||||
|
@ -302,7 +302,7 @@ void Widget::handle_mouseup_event(MouseEvent& event)
|
||||||
void Widget::handle_mousedown_event(MouseEvent& event)
|
void Widget::handle_mousedown_event(MouseEvent& event)
|
||||||
{
|
{
|
||||||
if (accepts_focus())
|
if (accepts_focus())
|
||||||
set_focus(true);
|
set_focus(true, FocusSource::Mouse);
|
||||||
mousedown_event(event);
|
mousedown_event(event);
|
||||||
if (event.button() == MouseButton::Right) {
|
if (event.button() == MouseButton::Right) {
|
||||||
ContextMenuEvent c_event(event.position(), screen_relative_rect().location().translated(event.position()));
|
ContextMenuEvent c_event(event.position(), screen_relative_rect().location().translated(event.position()));
|
||||||
|
@ -356,9 +356,9 @@ void Widget::keydown_event(KeyEvent& event)
|
||||||
{
|
{
|
||||||
if (!event.alt() && !event.ctrl() && !event.logo() && event.key() == KeyCode::Key_Tab) {
|
if (!event.alt() && !event.ctrl() && !event.logo() && event.key() == KeyCode::Key_Tab) {
|
||||||
if (event.shift())
|
if (event.shift())
|
||||||
focus_previous_widget();
|
focus_previous_widget(FocusSource::Keyboard);
|
||||||
else
|
else
|
||||||
focus_next_widget();
|
focus_next_widget(FocusSource::Keyboard);
|
||||||
event.accept();
|
event.accept();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -390,11 +390,11 @@ void Widget::context_menu_event(ContextMenuEvent&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::focusin_event(Core::Event&)
|
void Widget::focusin_event(FocusEvent&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::focusout_event(Core::Event&)
|
void Widget::focusout_event(FocusEvent&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -513,16 +513,16 @@ bool Widget::is_focused() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::set_focus(bool focus)
|
void Widget::set_focus(bool focus, FocusSource source)
|
||||||
{
|
{
|
||||||
auto* win = window();
|
auto* win = window();
|
||||||
if (!win)
|
if (!win)
|
||||||
return;
|
return;
|
||||||
if (focus) {
|
if (focus) {
|
||||||
win->set_focused_widget(this);
|
win->set_focused_widget(this, source);
|
||||||
} else {
|
} else {
|
||||||
if (win->focused_widget() == this)
|
if (win->focused_widget() == this)
|
||||||
win->set_focused_widget(nullptr);
|
win->set_focused_widget(nullptr, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -703,29 +703,29 @@ void Widget::set_updates_enabled(bool enabled)
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::focus_previous_widget()
|
void Widget::focus_previous_widget(FocusSource source)
|
||||||
{
|
{
|
||||||
auto focusable_widgets = window()->focusable_widgets();
|
auto focusable_widgets = window()->focusable_widgets();
|
||||||
for (int i = focusable_widgets.size() - 1; i >= 0; --i) {
|
for (int i = focusable_widgets.size() - 1; i >= 0; --i) {
|
||||||
if (focusable_widgets[i] != this)
|
if (focusable_widgets[i] != this)
|
||||||
continue;
|
continue;
|
||||||
if (i > 0)
|
if (i > 0)
|
||||||
focusable_widgets[i - 1]->set_focus(true);
|
focusable_widgets[i - 1]->set_focus(true, source);
|
||||||
else
|
else
|
||||||
focusable_widgets.last()->set_focus(true);
|
focusable_widgets.last()->set_focus(true, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Widget::focus_next_widget()
|
void Widget::focus_next_widget(FocusSource source)
|
||||||
{
|
{
|
||||||
auto focusable_widgets = window()->focusable_widgets();
|
auto focusable_widgets = window()->focusable_widgets();
|
||||||
for (size_t i = 0; i < focusable_widgets.size(); ++i) {
|
for (size_t i = 0; i < focusable_widgets.size(); ++i) {
|
||||||
if (focusable_widgets[i] != this)
|
if (focusable_widgets[i] != this)
|
||||||
continue;
|
continue;
|
||||||
if (i < focusable_widgets.size() - 1)
|
if (i < focusable_widgets.size() - 1)
|
||||||
focusable_widgets[i + 1]->set_focus(true);
|
focusable_widgets[i + 1]->set_focus(true, source);
|
||||||
else
|
else
|
||||||
focusable_widgets.first()->set_focus(true);
|
focusable_widgets.first()->set_focus(true, source);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -147,7 +147,7 @@ public:
|
||||||
virtual bool accepts_focus() const { return false; }
|
virtual bool accepts_focus() const { return false; }
|
||||||
|
|
||||||
bool is_focused() const;
|
bool is_focused() const;
|
||||||
void set_focus(bool);
|
void set_focus(bool, FocusSource = FocusSource::Programmatic);
|
||||||
|
|
||||||
enum class ShouldRespectGreediness { No = 0,
|
enum class ShouldRespectGreediness { No = 0,
|
||||||
Yes };
|
Yes };
|
||||||
|
@ -287,8 +287,8 @@ protected:
|
||||||
virtual void mousewheel_event(MouseEvent&);
|
virtual void mousewheel_event(MouseEvent&);
|
||||||
virtual void doubleclick_event(MouseEvent&);
|
virtual void doubleclick_event(MouseEvent&);
|
||||||
virtual void context_menu_event(ContextMenuEvent&);
|
virtual void context_menu_event(ContextMenuEvent&);
|
||||||
virtual void focusin_event(Core::Event&);
|
virtual void focusin_event(FocusEvent&);
|
||||||
virtual void focusout_event(Core::Event&);
|
virtual void focusout_event(FocusEvent&);
|
||||||
virtual void enter_event(Core::Event&);
|
virtual void enter_event(Core::Event&);
|
||||||
virtual void leave_event(Core::Event&);
|
virtual void leave_event(Core::Event&);
|
||||||
virtual void child_event(Core::ChildEvent&) override;
|
virtual void child_event(Core::ChildEvent&) override;
|
||||||
|
@ -310,8 +310,8 @@ private:
|
||||||
void handle_mouseup_event(MouseEvent&);
|
void handle_mouseup_event(MouseEvent&);
|
||||||
void handle_enter_event(Core::Event&);
|
void handle_enter_event(Core::Event&);
|
||||||
void handle_leave_event(Core::Event&);
|
void handle_leave_event(Core::Event&);
|
||||||
void focus_previous_widget();
|
void focus_previous_widget(FocusSource);
|
||||||
void focus_next_widget();
|
void focus_next_widget(FocusSource);
|
||||||
|
|
||||||
Window* m_window { nullptr };
|
Window* m_window { nullptr };
|
||||||
RefPtr<Layout> m_layout;
|
RefPtr<Layout> m_layout;
|
||||||
|
|
|
@ -525,17 +525,17 @@ void Window::set_main_widget(Widget* widget)
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Window::set_focused_widget(Widget* widget)
|
void Window::set_focused_widget(Widget* widget, FocusSource source)
|
||||||
{
|
{
|
||||||
if (m_focused_widget == widget)
|
if (m_focused_widget == widget)
|
||||||
return;
|
return;
|
||||||
if (m_focused_widget) {
|
if (m_focused_widget) {
|
||||||
Core::EventLoop::current().post_event(*m_focused_widget, make<Event>(Event::FocusOut));
|
Core::EventLoop::current().post_event(*m_focused_widget, make<FocusEvent>(Event::FocusOut, source));
|
||||||
m_focused_widget->update();
|
m_focused_widget->update();
|
||||||
}
|
}
|
||||||
m_focused_widget = widget ? widget->make_weak_ptr() : nullptr;
|
m_focused_widget = widget ? widget->make_weak_ptr() : nullptr;
|
||||||
if (m_focused_widget) {
|
if (m_focused_widget) {
|
||||||
Core::EventLoop::current().post_event(*m_focused_widget, make<Event>(Event::FocusIn));
|
Core::EventLoop::current().post_event(*m_focused_widget, make<FocusEvent>(Event::FocusIn, source));
|
||||||
m_focused_widget->update();
|
m_focused_widget->update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include <AK/String.h>
|
#include <AK/String.h>
|
||||||
#include <AK/WeakPtr.h>
|
#include <AK/WeakPtr.h>
|
||||||
#include <LibCore/Object.h>
|
#include <LibCore/Object.h>
|
||||||
|
#include <LibGUI/FocusSource.h>
|
||||||
#include <LibGUI/Forward.h>
|
#include <LibGUI/Forward.h>
|
||||||
#include <LibGUI/WindowType.h>
|
#include <LibGUI/WindowType.h>
|
||||||
#include <LibGfx/Color.h>
|
#include <LibGfx/Color.h>
|
||||||
|
@ -152,7 +153,7 @@ public:
|
||||||
|
|
||||||
Widget* focused_widget() { return m_focused_widget; }
|
Widget* focused_widget() { return m_focused_widget; }
|
||||||
const Widget* focused_widget() const { return m_focused_widget; }
|
const Widget* focused_widget() const { return m_focused_widget; }
|
||||||
void set_focused_widget(Widget*);
|
void set_focused_widget(Widget*, FocusSource = FocusSource::Programmatic);
|
||||||
|
|
||||||
void update();
|
void update();
|
||||||
void update(const Gfx::IntRect&);
|
void update(const Gfx::IntRect&);
|
||||||
|
|
|
@ -181,13 +181,13 @@ void TerminalWidget::set_logical_focus(bool focus)
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalWidget::focusin_event(Core::Event& event)
|
void TerminalWidget::focusin_event(GUI::FocusEvent& event)
|
||||||
{
|
{
|
||||||
set_logical_focus(true);
|
set_logical_focus(true);
|
||||||
return GUI::Frame::focusin_event(event);
|
return GUI::Frame::focusin_event(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TerminalWidget::focusout_event(Core::Event& event)
|
void TerminalWidget::focusout_event(GUI::FocusEvent& event)
|
||||||
{
|
{
|
||||||
set_logical_focus(false);
|
set_logical_focus(false);
|
||||||
return GUI::Frame::focusout_event(event);
|
return GUI::Frame::focusout_event(event);
|
||||||
|
|
|
@ -102,8 +102,8 @@ private:
|
||||||
virtual void mousemove_event(GUI::MouseEvent&) override;
|
virtual void mousemove_event(GUI::MouseEvent&) override;
|
||||||
virtual void mousewheel_event(GUI::MouseEvent&) override;
|
virtual void mousewheel_event(GUI::MouseEvent&) override;
|
||||||
virtual void doubleclick_event(GUI::MouseEvent&) override;
|
virtual void doubleclick_event(GUI::MouseEvent&) override;
|
||||||
virtual void focusin_event(Core::Event&) override;
|
virtual void focusin_event(GUI::FocusEvent&) override;
|
||||||
virtual void focusout_event(Core::Event&) override;
|
virtual void focusout_event(GUI::FocusEvent&) override;
|
||||||
virtual void context_menu_event(GUI::ContextMenuEvent&) override;
|
virtual void context_menu_event(GUI::ContextMenuEvent&) override;
|
||||||
virtual void drop_event(GUI::DropEvent&) override;
|
virtual void drop_event(GUI::DropEvent&) override;
|
||||||
virtual void leave_event(Core::Event&) override;
|
virtual void leave_event(Core::Event&) override;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue