mirror of
https://github.com/RGBCube/serenity
synced 2025-07-24 21:57:35 +00:00
LibCore+LibGUI: Allow inserting a CObject/GWidget before another
When adding a widget to a parent, you don't always want to append it to the set of existing children, but instead insert it before one of them. This patch makes that possible by adding CObject::insert_child_before() which also produces a ChildAdded event with an additional before_child pointer. This pointer is then used by GWidget to make sure that any layout present maintains the correct order. (Without doing that, newly added children would still be appended into the layout order, despite having a different widget sibling order.)
This commit is contained in:
parent
0f81eaf8a2
commit
d3558b6137
7 changed files with 36 additions and 4 deletions
|
@ -1,9 +1,10 @@
|
|||
#include <LibCore/CEvent.h>
|
||||
#include <LibCore/CObject.h>
|
||||
|
||||
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)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
@ -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<CObject> m_child;
|
||||
WeakPtr<CObject> m_insertion_before_child;
|
||||
};
|
||||
|
||||
class CCustomEvent : public CEvent {
|
||||
|
|
|
@ -64,6 +64,15 @@ void CObject::add_child(CObject& object)
|
|||
event(*make<CChildEvent>(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<CChildEvent>(CEvent::ChildAdded, new_child, &before_child));
|
||||
}
|
||||
|
||||
void CObject::remove_child(CObject& object)
|
||||
{
|
||||
for (int i = 0; i < m_children.size(); ++i) {
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -14,6 +14,7 @@ public:
|
|||
virtual ~GLayout();
|
||||
|
||||
void add_widget(GWidget&);
|
||||
void insert_widget_before(GWidget& widget, GWidget& before_widget);
|
||||
void add_layout(OwnPtr<GLayout>&&);
|
||||
void add_spacer();
|
||||
|
||||
|
|
|
@ -27,9 +27,13 @@ GWidget::~GWidget()
|
|||
void GWidget::child_event(CChildEvent& event)
|
||||
{
|
||||
if (event.type() == GEvent::ChildAdded) {
|
||||
if (event.child() && is<GWidget>(*event.child()) && layout())
|
||||
if (event.child() && is<GWidget>(*event.child()) && layout()) {
|
||||
if (event.insertion_before_child() && event.insertion_before_child()->is_widget())
|
||||
layout()->insert_widget_before(to<GWidget>(*event.child()), to<GWidget>(*event.insertion_before_child()));
|
||||
else
|
||||
layout()->add_widget(to<GWidget>(*event.child()));
|
||||
}
|
||||
}
|
||||
if (event.type() == GEvent::ChildRemoved) {
|
||||
if (layout()) {
|
||||
if (event.child() && is<GWidget>(*event.child()))
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue