mirror of
https://github.com/SerenityOS/serenity.git
synced 2025-01-23 09:51:57 -05:00
GWidget: Add some new child z-ordering facilities.
- child_at(Point) - move_to_front() - move_to_back() - is_frontmost() - is_backmost() This patch also makes it possible to receive the mouse event that triggers a context menu before the context menu is shown. I'm not sure this is the best design for context menus but it works for now.
This commit is contained in:
parent
d31b47b371
commit
04500c1ae2
3 changed files with 69 additions and 7 deletions
|
@ -18,6 +18,7 @@ public:
|
|||
virtual void event(CEvent&);
|
||||
|
||||
Vector<CObject*>& children() { return m_children; }
|
||||
const Vector<CObject*>& children() const { return m_children; }
|
||||
|
||||
CObject* parent() { return m_parent; }
|
||||
const CObject* parent() const { return m_parent; }
|
||||
|
|
|
@ -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<GMenu>&& context_menu)
|
||||
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();
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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<GMenu>&&);
|
||||
void set_context_menu(OwnPtr<GMenu>&&, 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<GMenu> m_context_menu;
|
||||
ContextMenuMode m_context_menu_mode { ContextMenuMode::SwallowMouseEvent };
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue