diff --git a/LibCore/CObject.h b/LibCore/CObject.h index c94ed2f167..f8ae55a7b2 100644 --- a/LibCore/CObject.h +++ b/LibCore/CObject.h @@ -18,6 +18,7 @@ public: virtual void event(CEvent&); Vector& children() { return m_children; } + const Vector& children() const { return m_children; } CObject* parent() { return m_parent; } const CObject* parent() const { return m_parent; } diff --git a/LibGUI/GWidget.cpp b/LibGUI/GWidget.cpp index 4bc8bb1c8e..9330b62a83 100644 --- a/LibGUI/GWidget.cpp +++ b/LibGUI/GWidget.cpp @@ -178,6 +178,8 @@ void GWidget::handle_mousedown_event(GMouseEvent& event) 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; } @@ -294,19 +296,26 @@ Rect GWidget::screen_relative_rect() const return window_relative_rect().translated(window()->position()); } -GWidget::HitTestResult GWidget::hit_test(int x, int y) +GWidget* GWidget::child_at(const Point& point) { - if (is_greedy_for_hits()) - return { this, x, y }; for (int i = children().size() - 1; i >= 0; --i) { if (!children()[i]->is_widget()) continue; auto& child = *(GWidget*)children()[i]; if (!child.is_visible()) continue; - if (child.relative_rect().contains(x, y)) - return child.hit_test(x - child.relative_rect().x(), y - child.relative_rect().y()); + if (child.relative_rect().contains(point)) + return &child; } + return nullptr; +} + +GWidget::HitTestResult GWidget::hit_test(int x, int y) +{ + if (is_greedy_for_hits()) + return { this, x, y }; + if (auto* child = child_at({ x, y })) + return child->hit_test(x - child->x(), y - child->y()); return { this, x, y }; } @@ -426,9 +435,50 @@ void GWidget::set_enabled(bool enabled) update(); } -void GWidget::set_context_menu(OwnPtr&& context_menu) +void GWidget::set_context_menu(OwnPtr&& 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(); + if (!parent) + return; + if (parent->children().size() == 1) + return; + parent->children().remove_first_matching([this] (auto& entry) { return entry == this; }); + parent->children().append(this); + parent_widget()->update(); +} + +void GWidget::move_to_back() +{ + auto* parent = parent_widget(); + if (!parent) + return; + if (parent->children().size() == 1) + return; + parent->children().remove_first_matching([this] (auto& entry) { return entry == this; }); + parent->children().prepend(this); + parent_widget()->update(); +} + +bool GWidget::is_frontmost() const +{ + auto* parent = parent_widget(); + if (!parent) + return true; + return parent->children().last() == this; +} + +bool GWidget::is_backmost() const +{ + auto* parent = parent_widget(); + if (!parent) + return true; + return parent->children().first() == this; } diff --git a/LibGUI/GWidget.h b/LibGUI/GWidget.h index 789a025d08..1fa31f4bf9 100644 --- a/LibGUI/GWidget.h +++ b/LibGUI/GWidget.h @@ -42,8 +42,10 @@ 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&&); + void set_context_menu(OwnPtr&&, ContextMenuMode = ContextMenuMode::SwallowMouseEvent); virtual void event(CEvent&) override; virtual void paint_event(GPaintEvent&); @@ -95,6 +97,8 @@ public: }; HitTestResult hit_test(int x, int y); + GWidget* child_at(const Point&); + virtual const char* class_name() const override { return "GWidget"; } void set_relative_rect(const Rect&); @@ -165,6 +169,12 @@ public: bool is_greedy_for_hits() const { return m_greedy_for_hits; } void set_greedy_for_hits(bool b) { m_greedy_for_hits = b; } + void move_to_front(); + void move_to_back(); + + bool is_frontmost() const; + bool is_backmost() const; + private: virtual bool is_widget() const final { return true; } @@ -196,4 +206,5 @@ private: CElapsedTimer m_click_clock; OwnPtr m_context_menu; + ContextMenuMode m_context_menu_mode { ContextMenuMode::SwallowMouseEvent }; };