Serenity Operating System
at master 154 lines 3.7 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * Copyright (c) 2022, the SerenityOS developers. 4 * 5 * SPDX-License-Identifier: BSD-2-Clause 6 */ 7 8#include <AK/Badge.h> 9#include <AK/JsonObject.h> 10#include <LibGUI/Layout.h> 11#include <LibGUI/Widget.h> 12 13REGISTER_ABSTRACT_CORE_OBJECT(GUI, Layout) 14 15namespace GUI { 16 17Layout::Layout(Margins initial_margins, int spacing) 18 : m_margins(initial_margins) 19 , m_spacing(spacing) 20{ 21 REGISTER_INT_PROPERTY("spacing", spacing, set_spacing); 22 REGISTER_MARGINS_PROPERTY("margins", margins, set_margins); 23 24 register_property("entries", 25 [this] { 26 JsonArray entries_array; 27 for (auto& entry : m_entries) { 28 JsonObject entry_object; 29 if (entry.type == Entry::Type::Widget) { 30 entry_object.set("type", "Widget"); 31 entry_object.set("widget", (FlatPtr)entry.widget.ptr()); 32 } else if (entry.type == Entry::Type::Spacer) { 33 entry_object.set("type", "Spacer"); 34 } else { 35 VERIFY_NOT_REACHED(); 36 } 37 entries_array.append(move(entry_object)); 38 } 39 return entries_array; 40 }); 41} 42 43Layout::~Layout() = default; 44 45void Layout::notify_adopted(Badge<Widget>, Widget& widget) 46{ 47 if (m_owner == &widget) 48 return; 49 m_owner = widget; 50 m_owner->for_each_child_widget([&](Widget& child) { 51 add_widget(child); 52 return IterationDecision::Continue; 53 }); 54} 55 56void Layout::notify_disowned(Badge<Widget>, Widget& widget) 57{ 58 VERIFY(m_owner == &widget); 59 m_owner.clear(); 60 m_entries.clear(); 61} 62 63ErrorOr<void> Layout::try_add_entry(Entry&& entry) 64{ 65 TRY(m_entries.try_append(move(entry))); 66 if (m_owner) 67 m_owner->notify_layout_changed({}); 68 return {}; 69} 70 71void Layout::add_entry(Entry&& entry) 72{ 73 MUST(try_add_entry(move(entry))); 74} 75 76ErrorOr<void> Layout::try_add_spacer() 77{ 78 TRY(try_add_entry(Entry { .type = Entry::Type::Spacer })); 79 return {}; 80} 81 82void Layout::add_spacer() 83{ 84 MUST(try_add_spacer()); 85} 86 87void Layout::add_layout(OwnPtr<Layout>&& layout) 88{ 89 Entry entry; 90 entry.type = Entry::Type::Layout; 91 entry.layout = move(layout); 92 add_entry(move(entry)); 93} 94 95ErrorOr<void> Layout::try_add_widget(Widget& widget) 96{ 97 TRY(try_add_entry(Entry { 98 .type = Entry::Type::Widget, 99 .widget = widget, 100 })); 101 return {}; 102} 103 104void Layout::add_widget(Widget& widget) 105{ 106 MUST(try_add_widget(widget)); 107} 108 109ErrorOr<void> Layout::try_insert_widget_before(Widget& widget, Widget& before_widget) 110{ 111 Entry entry; 112 entry.type = Entry::Type::Widget; 113 entry.widget = widget; 114 TRY(m_entries.try_insert_before_matching(move(entry), [&](auto& existing_entry) { 115 return existing_entry.type == Entry::Type::Widget && existing_entry.widget.ptr() == &before_widget; 116 })); 117 if (m_owner) 118 m_owner->notify_layout_changed({}); 119 return {}; 120} 121 122void Layout::insert_widget_before(Widget& widget, Widget& before_widget) 123{ 124 MUST(try_insert_widget_before(widget, before_widget)); 125} 126 127void Layout::remove_widget(Widget& widget) 128{ 129 m_entries.remove_first_matching([&](auto& entry) { 130 return entry.widget == &widget; 131 }); 132 if (m_owner) 133 m_owner->notify_layout_changed({}); 134} 135 136void Layout::set_spacing(int spacing) 137{ 138 if (m_spacing == spacing) 139 return; 140 m_spacing = spacing; 141 if (m_owner) 142 m_owner->notify_layout_changed({}); 143} 144 145void Layout::set_margins(Margins const& margins) 146{ 147 if (m_margins == margins) 148 return; 149 m_margins = margins; 150 if (m_owner) 151 m_owner->notify_layout_changed({}); 152} 153 154}