1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-05 12:37:34 +00:00

LibGUI: Refactor context menus to be event-driven instead of declarative.

The declarative approach had way too many limitations. This patch adds a
context menu event that can be hooked to prepare a custom context menu on
demand just-in-time. :^)
This commit is contained in:
Andreas Kling 2019-04-18 04:12:27 +02:00
parent e74b5bc054
commit a747a10eab
5 changed files with 37 additions and 27 deletions

View file

@ -35,16 +35,20 @@ VBForm::VBForm(const String& name, GWidget* parent)
groupbox1->set_rect({ 300, 150, 161, 51 }); groupbox1->set_rect({ 300, 150, 161, 51 });
m_widgets.append(move(groupbox1)); m_widgets.append(move(groupbox1));
auto context_menu = make<GMenu>("Context menu"); m_context_menu = make<GMenu>("Context menu");
context_menu->add_action(GAction::create("Move to front", [this] (auto&) { m_context_menu->add_action(GAction::create("Move to front", [this] (auto&) {
if (m_selected_widget) if (m_selected_widget)
m_selected_widget->gwidget()->move_to_front(); m_selected_widget->gwidget()->move_to_front();
})); }));
context_menu->add_action(GAction::create("Move to back", [this] (auto&) { m_context_menu->add_action(GAction::create("Move to back", [this] (auto&) {
if (m_selected_widget) if (m_selected_widget)
m_selected_widget->gwidget()->move_to_back(); m_selected_widget->gwidget()->move_to_back();
})); }));
set_context_menu(move(context_menu), GWidget::ContextMenuMode::PassthroughMouseEvent); }
void VBForm::context_menu_event(GContextMenuEvent& event)
{
m_context_menu->popup(event.screen_position());
} }
void VBForm::insert_widget(VBWidgetType type) void VBForm::insert_widget(VBWidgetType type)

View file

@ -31,6 +31,7 @@ protected:
virtual void mousedown_event(GMouseEvent&) override; virtual void mousedown_event(GMouseEvent&) override;
virtual void mousemove_event(GMouseEvent&) override; virtual void mousemove_event(GMouseEvent&) override;
virtual void mouseup_event(GMouseEvent&) override; virtual void mouseup_event(GMouseEvent&) override;
virtual void context_menu_event(GContextMenuEvent&) override;
virtual void keydown_event(GKeyEvent&) override; virtual void keydown_event(GKeyEvent&) override;
private: private:
@ -47,4 +48,5 @@ private:
Rect m_transform_widget_origin_rect; Rect m_transform_widget_origin_rect;
Point m_next_insertion_position; Point m_next_insertion_position;
Direction m_resize_direction { Direction::None }; Direction m_resize_direction { Direction::None };
OwnPtr<GMenu> m_context_menu;
}; };

View file

@ -29,6 +29,7 @@ public:
FocusIn, FocusIn,
FocusOut, FocusOut,
WindowCloseRequest, WindowCloseRequest,
ContextMenu,
WM_WindowRemoved, WM_WindowRemoved,
WM_WindowStateChanged, WM_WindowStateChanged,
WM_WindowIconChanged, WM_WindowIconChanged,
@ -141,6 +142,23 @@ private:
Size m_size; Size m_size;
}; };
class GContextMenuEvent final : public GEvent {
public:
explicit GContextMenuEvent(const Point& position, const Point& screen_position)
: GEvent(GEvent::ContextMenu)
, m_position(position)
, m_screen_position(screen_position)
{
}
const Point& position() const { return m_position; }
const Point& screen_position() const { return m_screen_position; }
private:
Point m_position;
Point m_screen_position;
};
class GShowEvent final : public GEvent { class GShowEvent final : public GEvent {
public: public:
GShowEvent() GShowEvent()

View file

@ -178,18 +178,14 @@ void GWidget::handle_mousedown_event(GMouseEvent& event)
{ {
if (accepts_focus()) if (accepts_focus())
set_focus(true); set_focus(true);
if (event.button() == GMouseButton::Right) {
if (m_context_menu) {
if (m_context_menu_mode == ContextMenuMode::PassthroughMouseEvent)
mousedown_event(event);
m_context_menu->popup(screen_relative_rect().location().translated(event.position()));
return;
}
}
// FIXME: Maybe the click clock should be per-button. // FIXME: Maybe the click clock should be per-button.
if (!m_click_clock.is_valid()) if (!m_click_clock.is_valid())
m_click_clock.start(); m_click_clock.start();
mousedown_event(event); mousedown_event(event);
if (event.button() == GMouseButton::Right) {
GContextMenuEvent c_event(event.position(), screen_relative_rect().location().translated(event.position()));
context_menu_event(c_event);
}
} }
void GWidget::handle_enter_event(CEvent& event) void GWidget::handle_enter_event(CEvent& event)
@ -253,6 +249,10 @@ void GWidget::mousemove_event(GMouseEvent&)
{ {
} }
void GWidget::context_menu_event(GContextMenuEvent&)
{
}
void GWidget::focusin_event(CEvent&) void GWidget::focusin_event(CEvent&)
{ {
} }
@ -437,14 +437,6 @@ void GWidget::set_enabled(bool enabled)
update(); update();
} }
void GWidget::set_context_menu(OwnPtr<GMenu>&& context_menu, ContextMenuMode mode)
{
// FIXME: Support switching context menus.
ASSERT(!m_context_menu);
m_context_menu = move(context_menu);
m_context_menu_mode = mode;
}
void GWidget::move_to_front() void GWidget::move_to_front()
{ {
auto* parent = parent_widget(); auto* parent = parent_widget();

View file

@ -42,11 +42,6 @@ public:
bool is_enabled() const { return m_enabled; } bool is_enabled() const { return m_enabled; }
void set_enabled(bool); void set_enabled(bool);
enum class ContextMenuMode { SwallowMouseEvent, PassthroughMouseEvent };
const GMenu* context_menu() const { return m_context_menu.ptr(); }
void set_context_menu(OwnPtr<GMenu>&&, ContextMenuMode = ContextMenuMode::SwallowMouseEvent);
virtual void event(CEvent&) override; virtual void event(CEvent&) override;
virtual void paint_event(GPaintEvent&); virtual void paint_event(GPaintEvent&);
virtual void resize_event(GResizeEvent&); virtual void resize_event(GResizeEvent&);
@ -59,6 +54,7 @@ public:
virtual void mouseup_event(GMouseEvent&); virtual void mouseup_event(GMouseEvent&);
virtual void click_event(GMouseEvent&); virtual void click_event(GMouseEvent&);
virtual void doubleclick_event(GMouseEvent&); virtual void doubleclick_event(GMouseEvent&);
virtual void context_menu_event(GContextMenuEvent&);
virtual void focusin_event(CEvent&); virtual void focusin_event(CEvent&);
virtual void focusout_event(CEvent&); virtual void focusout_event(CEvent&);
virtual void enter_event(CEvent&); virtual void enter_event(CEvent&);
@ -206,6 +202,4 @@ private:
bool m_enabled { true }; bool m_enabled { true };
CElapsedTimer m_click_clock; CElapsedTimer m_click_clock;
OwnPtr<GMenu> m_context_menu;
ContextMenuMode m_context_menu_mode { ContextMenuMode::SwallowMouseEvent };
}; };