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