diff --git a/Libraries/LibCore/CEvent.cpp b/Libraries/LibCore/CEvent.cpp index eacce964c2..ebc9eeff3d 100644 --- a/Libraries/LibCore/CEvent.cpp +++ b/Libraries/LibCore/CEvent.cpp @@ -1,9 +1,10 @@ #include #include -CChildEvent::CChildEvent(Type type, CObject& child) +CChildEvent::CChildEvent(Type type, CObject& child, CObject* insertion_before_child) : CEvent(type) , m_child(child.make_weak_ptr()) + , m_insertion_before_child(insertion_before_child ? insertion_before_child->make_weak_ptr() : nullptr) { } diff --git a/Libraries/LibCore/CEvent.h b/Libraries/LibCore/CEvent.h index 8e49c07fd4..28c593be45 100644 --- a/Libraries/LibCore/CEvent.h +++ b/Libraries/LibCore/CEvent.h @@ -100,14 +100,18 @@ private: class CChildEvent final : public CEvent { public: - CChildEvent(Type, CObject& child); + CChildEvent(Type, CObject& child, CObject* insertion_before_child = nullptr); ~CChildEvent(); CObject* child() { return m_child.ptr(); } const CObject* child() const { return m_child.ptr(); } + CObject* insertion_before_child() { return m_insertion_before_child.ptr(); } + const CObject* insertion_before_child() const { return m_insertion_before_child.ptr(); } + private: WeakPtr m_child; + WeakPtr m_insertion_before_child; }; class CCustomEvent : public CEvent { diff --git a/Libraries/LibCore/CObject.cpp b/Libraries/LibCore/CObject.cpp index 0058de5b39..7de5a5a044 100644 --- a/Libraries/LibCore/CObject.cpp +++ b/Libraries/LibCore/CObject.cpp @@ -64,6 +64,15 @@ void CObject::add_child(CObject& object) event(*make(CEvent::ChildAdded, object)); } +void CObject::insert_child_before(CObject& new_child, CObject& before_child) +{ + // FIXME: Should we support reparenting objects? + ASSERT(!new_child.parent() || new_child.parent() == this); + new_child.m_parent = this; + m_children.insert_before_matching(new_child, [&](auto& existing_child) { return existing_child.ptr() == &before_child; }); + event(*make(CEvent::ChildAdded, new_child, &before_child)); +} + void CObject::remove_child(CObject& object) { for (int i = 0; i < m_children.size(); ++i) { diff --git a/Libraries/LibCore/CObject.h b/Libraries/LibCore/CObject.h index 7a5ce63785..709d2e607e 100644 --- a/Libraries/LibCore/CObject.h +++ b/Libraries/LibCore/CObject.h @@ -70,6 +70,7 @@ public: bool has_timer() const { return m_timer_id; } void add_child(CObject&); + void insert_child_before(CObject& new_child, CObject& before_child); void remove_child(CObject&); void dump_tree(int indent = 0); diff --git a/Libraries/LibGUI/GLayout.cpp b/Libraries/LibGUI/GLayout.cpp index 13a547e4c0..0875c4ffed 100644 --- a/Libraries/LibGUI/GLayout.cpp +++ b/Libraries/LibGUI/GLayout.cpp @@ -52,6 +52,18 @@ void GLayout::add_widget(GWidget& widget) add_entry(move(entry)); } +void GLayout::insert_widget_before(GWidget& widget, GWidget& before_widget) +{ + Entry entry; + entry.type = Entry::Type::Widget; + entry.widget = widget.make_weak_ptr(); + m_entries.insert_before_matching(move(entry), [&](auto& existing_entry) { + return existing_entry.type == Entry::Type::Widget && existing_entry.widget.ptr() == &before_widget; + }); + if (m_owner) + m_owner->notify_layout_changed({}); +} + void GLayout::remove_widget(GWidget& widget) { m_entries.remove_first_matching([&](auto& entry) { diff --git a/Libraries/LibGUI/GLayout.h b/Libraries/LibGUI/GLayout.h index c98e113426..935c271e42 100644 --- a/Libraries/LibGUI/GLayout.h +++ b/Libraries/LibGUI/GLayout.h @@ -14,6 +14,7 @@ public: virtual ~GLayout(); void add_widget(GWidget&); + void insert_widget_before(GWidget& widget, GWidget& before_widget); void add_layout(OwnPtr&&); void add_spacer(); diff --git a/Libraries/LibGUI/GWidget.cpp b/Libraries/LibGUI/GWidget.cpp index a5004de332..56d9137339 100644 --- a/Libraries/LibGUI/GWidget.cpp +++ b/Libraries/LibGUI/GWidget.cpp @@ -27,8 +27,12 @@ GWidget::~GWidget() void GWidget::child_event(CChildEvent& event) { if (event.type() == GEvent::ChildAdded) { - if (event.child() && is(*event.child()) && layout()) - layout()->add_widget(to(*event.child())); + if (event.child() && is(*event.child()) && layout()) { + if (event.insertion_before_child() && event.insertion_before_child()->is_widget()) + layout()->insert_widget_before(to(*event.child()), to(*event.insertion_before_child())); + else + layout()->add_widget(to(*event.child())); + } } if (event.type() == GEvent::ChildRemoved) { if (layout()) {