mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-11 01:06:01 +03: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:
parent
e74b5bc054
commit
a747a10eab
Notes:
sideshowbarker
2024-07-19 14:40:14 +09:00
Author: https://github.com/awesomekling Commit: https://github.com/SerenityOS/serenity/commit/a747a10eabd
@ -35,16 +35,20 @@ VBForm::VBForm(const String& name, GWidget* parent)
|
||||
groupbox1->set_rect({ 300, 150, 161, 51 });
|
||||
m_widgets.append(move(groupbox1));
|
||||
|
||||
auto context_menu = make<GMenu>("Context menu");
|
||||
context_menu->add_action(GAction::create("Move to front", [this] (auto&) {
|
||||
m_context_menu = make<GMenu>("Context menu");
|
||||
m_context_menu->add_action(GAction::create("Move to front", [this] (auto&) {
|
||||
if (m_selected_widget)
|
||||
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)
|
||||
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)
|
||||
|
@ -31,6 +31,7 @@ protected:
|
||||
virtual void mousedown_event(GMouseEvent&) override;
|
||||
virtual void mousemove_event(GMouseEvent&) override;
|
||||
virtual void mouseup_event(GMouseEvent&) override;
|
||||
virtual void context_menu_event(GContextMenuEvent&) override;
|
||||
virtual void keydown_event(GKeyEvent&) override;
|
||||
|
||||
private:
|
||||
@ -47,4 +48,5 @@ private:
|
||||
Rect m_transform_widget_origin_rect;
|
||||
Point m_next_insertion_position;
|
||||
Direction m_resize_direction { Direction::None };
|
||||
OwnPtr<GMenu> m_context_menu;
|
||||
};
|
||||
|
@ -29,6 +29,7 @@ public:
|
||||
FocusIn,
|
||||
FocusOut,
|
||||
WindowCloseRequest,
|
||||
ContextMenu,
|
||||
WM_WindowRemoved,
|
||||
WM_WindowStateChanged,
|
||||
WM_WindowIconChanged,
|
||||
@ -141,6 +142,23 @@ private:
|
||||
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 {
|
||||
public:
|
||||
GShowEvent()
|
||||
|
@ -178,18 +178,14 @@ void GWidget::handle_mousedown_event(GMouseEvent& event)
|
||||
{
|
||||
if (accepts_focus())
|
||||
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.
|
||||
if (!m_click_clock.is_valid())
|
||||
m_click_clock.start();
|
||||
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)
|
||||
@ -253,6 +249,10 @@ void GWidget::mousemove_event(GMouseEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void GWidget::context_menu_event(GContextMenuEvent&)
|
||||
{
|
||||
}
|
||||
|
||||
void GWidget::focusin_event(CEvent&)
|
||||
{
|
||||
}
|
||||
@ -437,14 +437,6 @@ void GWidget::set_enabled(bool enabled)
|
||||
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()
|
||||
{
|
||||
auto* parent = parent_widget();
|
||||
|
@ -42,11 +42,6 @@ public:
|
||||
bool is_enabled() const { return m_enabled; }
|
||||
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 paint_event(GPaintEvent&);
|
||||
virtual void resize_event(GResizeEvent&);
|
||||
@ -59,6 +54,7 @@ public:
|
||||
virtual void mouseup_event(GMouseEvent&);
|
||||
virtual void click_event(GMouseEvent&);
|
||||
virtual void doubleclick_event(GMouseEvent&);
|
||||
virtual void context_menu_event(GContextMenuEvent&);
|
||||
virtual void focusin_event(CEvent&);
|
||||
virtual void focusout_event(CEvent&);
|
||||
virtual void enter_event(CEvent&);
|
||||
@ -206,6 +202,4 @@ private:
|
||||
bool m_enabled { true };
|
||||
|
||||
CElapsedTimer m_click_clock;
|
||||
OwnPtr<GMenu> m_context_menu;
|
||||
ContextMenuMode m_context_menu_mode { ContextMenuMode::SwallowMouseEvent };
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user