1 #include <cppurses/widget/layouts/stack.hpp>
2
3 #include <algorithm>
4 #include <iterator>
5 #include <memory>
6 #include <utility>
7 #include <vector>
8
9 #include <signals/slot.hpp>
10
11 #include <cppurses/system/focus.hpp>
12 #include <cppurses/widget/widget.hpp>
13
14 namespace cppurses {
15 namespace layout {
16
set_active_page(std::size_t index)17 void Stack::set_active_page(std::size_t index)
18 {
19 if (index > this->size())
20 return;
21 active_page_ = this->children.get()[index].get();
22 this->enable(this->enabled(), false);
23 if (sets_focus_)
24 Focus::set_focus_to(*active_page_);
25 this->page_changed(index);
26 }
27
give_focus_on_change(bool sets_focus)28 void Stack::give_focus_on_change(bool sets_focus) { sets_focus_ = sets_focus; }
29
append_page(std::unique_ptr<Widget> widget)30 void Stack::append_page(std::unique_ptr<Widget> widget)
31 {
32 widget->disable();
33 this->children.append(std::move(widget));
34 }
35
insert_page(std::size_t index,std::unique_ptr<Widget> widget)36 void Stack::insert_page(std::size_t index, std::unique_ptr<Widget> widget)
37 {
38 widget->disable();
39 this->children.insert(std::move(widget), index);
40 }
41
delete_page(std::size_t index)42 void Stack::delete_page(std::size_t index)
43 {
44 if (index >= this->size())
45 return;
46 Widget* at_index{this->children.get()[index].get()};
47 if (at_index == this->active_page())
48 active_page_ = nullptr;
49 at_index->close();
50 }
51
remove_page(std::size_t index)52 std::unique_ptr<Widget> Stack::remove_page(std::size_t index)
53 {
54 std::unique_ptr<Widget> removed{nullptr};
55 if (index >= this->size())
56 return removed;
57 Widget* at_index{this->children.get()[index].get()};
58 if (at_index == this->active_page())
59 active_page_ = nullptr;
60 Widget* parent = this->parent();
61 if (parent != nullptr)
62 removed = parent->children.remove(at_index);
63 return removed;
64 }
65
clear()66 void Stack::clear()
67 {
68 active_page_ = nullptr;
69 while (!this->children.get().empty()) {
70 this->children.get().front()->close();
71 }
72 }
73
size() const74 std::size_t Stack::size() const { return this->children.get().size(); }
75
active_page() const76 Widget* Stack::active_page() const { return active_page_; }
77
active_page_index() const78 std::size_t Stack::active_page_index() const
79 {
80 if (active_page_ == nullptr)
81 return 0; // TODO need better value here.
82 const auto& child_vec = this->children.get();
83
84 auto at = std::find_if(
85 std::begin(child_vec), std::end(child_vec),
86 [this](const auto& w_ptr) { return w_ptr.get() == active_page_; });
87 return std::distance(std::begin(child_vec), at);
88 }
89
enable(bool enable,bool post_child_polished_event)90 void Stack::enable(bool enable, bool post_child_polished_event)
91 {
92 this->enable_and_post_events(enable, post_child_polished_event);
93 for (const std::unique_ptr<Widget>& child : this->children.get()) {
94 if (child.get() == active_page_)
95 child->enable(enable, post_child_polished_event);
96 else
97 child->disable();
98 }
99 }
100 } // namespace layout
101
102 namespace slot {
103
set_active_page(layout::Stack & stack)104 sig::Slot<void(std::size_t)> set_active_page(layout::Stack& stack)
105 {
106 sig::Slot<void(std::size_t)> slot{
107 [&stack](auto index) { stack.set_active_page(index); }};
108 slot.track(stack.destroyed);
109 return slot;
110 }
111
set_active_page(layout::Stack & stack,std::size_t index)112 sig::Slot<void()> set_active_page(layout::Stack& stack, std::size_t index)
113 {
114 sig::Slot<void()> slot{[&stack, index] { stack.set_active_page(index); }};
115 slot.track(stack.destroyed);
116 return slot;
117 }
118
delete_page(layout::Stack & stack)119 sig::Slot<void(std::size_t)> delete_page(layout::Stack& stack)
120 {
121 sig::Slot<void(std::size_t)> slot{
122 [&stack](auto index) { stack.delete_page(index); }};
123 slot.track(stack.destroyed);
124 return slot;
125 }
126
delete_page(layout::Stack & stack,std::size_t index)127 sig::Slot<void()> delete_page(layout::Stack& stack, std::size_t index)
128 {
129 sig::Slot<void()> slot{[&stack, index] { stack.delete_page(index); }};
130 slot.track(stack.destroyed);
131 return slot;
132 }
133
insert_page(layout::Stack & stack)134 sig::Slot<void(std::size_t, std::unique_ptr<Widget>)> insert_page(
135 layout::Stack& stack)
136 {
137 sig::Slot<void(std::size_t, std::unique_ptr<Widget>)> slot{
138 [&stack](auto index, auto widget) {
139 stack.insert_page(index, std::move(widget));
140 }};
141 slot.track(stack.destroyed);
142 return slot;
143 }
144
insert_page(layout::Stack & stack,std::size_t index)145 sig::Slot<void(std::unique_ptr<Widget>)> insert_page(layout::Stack& stack,
146 std::size_t index)
147 {
148 sig::Slot<void(std::unique_ptr<Widget>)> slot{[&stack, index](auto widget) {
149 stack.insert_page(index, std::move(widget));
150 }};
151 slot.track(stack.destroyed);
152 return slot;
153 }
154
155 } // namespace slot
156 } // namespace cppurses
157