gigaTerminal text editor |
git clone git://git.dimitrijedobrota.com/giga.git |
Log | Files | Refs | README | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |
layout_dynamic.cpp (5803B)
0 #include <stack>
1 #include <stdexcept>
3 #include "layout_dynamic.hpp"
5 namespace display
6 {
8 void Panel::resize(plc_t aplc)
9 {
10 std::stack<std::pair<plc_t, Panel*>> stk;
11 stk.emplace(aplc, this);
13 while (!stk.empty()) {
14 auto [plc, crnt] = stk.top();
15 stk.pop();
17 std::visit(
18 [&]<typename M>(M& var)
19 {
20 var.resize(plc);
22 if constexpr (!std::is_same_v<M, layout_t>) {
23 auto& panels = var.panels();
24 for (std::size_t i = 0; i < panels.size(); i++) {
25 stk.emplace(var.place(i, panels.size()), panels[i].get());
26 }
27 }
28 },
29 crnt->m_payload);
30 }
31 }
33 void Panel::render() const
34 {
35 std::stack<const Panel*> stk;
36 stk.emplace(this);
38 while (!stk.empty()) {
39 const auto* crnt = stk.top();
40 stk.pop();
42 std::visit(
43 [&]<typename M>(const M& var)
44 {
45 if constexpr (std::is_same_v<M, layout_t>) {
46 var.render();
47 }
49 if constexpr (!std::is_same_v<M, layout_t>) {
50 for (const auto& panel : var.panels()) {
51 stk.emplace(panel.get());
52 }
53 }
54 },
55 crnt->m_payload);
56 }
57 }
59 Panel* Panel::close()
60 {
61 const auto visit_parent = [&]<typename M>(M& pcont) -> Panel*
62 {
63 if constexpr (std::is_same_v<M, layout_t>) {
64 throw std::runtime_error("Invalid node handle [close() layout_t]");
65 }
67 if constexpr (!std::is_same_v<M, layout_t>) {
68 // need this here because 'this' is going to deleted
69 auto* parent = m_parent;
70 const auto pos = get_elem().apos();
72 pcont.panels().erase(pcont.find_child(this));
73 // 'this' is not to be used anymore
75 if (pcont.panels().size() > 1) {
76 parent->resize(pcont.aplc());
77 return parent->select(pos);
78 }
80 // one child left, no need for Panel anymore
82 // need this here because this is going to overridden
83 auto payload = std::move(pcont.panels()[0]->m_payload);
84 const auto aplc = pcont.aplc();
86 parent->m_payload = std::move(payload);
87 // pcnot is not to be used anymore
89 // re-parent if needed
90 std::visit(
91 [&]<typename L>(L& val)
92 {
93 if constexpr (!std::is_same_v<L, layout_t>) {
94 for (const auto& panel : val.panels()) {
95 panel->m_parent = parent;
96 }
97 }
98 },
99 parent->m_payload);
101 parent->resize(aplc);
102 return parent->select(aplc.pos);
103 }
104 };
106 if (m_parent == nullptr) {
107 // I am the last one
108 return nullptr;
109 }
111 return std::visit(visit_parent, m_parent->m_payload);
112 }
114 template<Panel::Direction D>
115 requires is_enum_valid_v<Panel::Direction, D>
116 Panel* Panel::select(Panel* sel)
117 {
118 const auto& sele = sel->get_elem();
120 pos_t tpos = {0, 0};
121 if constexpr (D == Direction::Up) {
122 tpos = sele.apos() + pos_t(0, -1);
123 } else if (D == Direction::Left) {
124 tpos = sele.apos() + pos_t(-1, 0);
125 } else if (D == Direction::Down) {
126 tpos = sele.apos() + pos_t(0UL, sele.ahgt().value());
127 } else if (D == Direction::Right) {
128 tpos = sele.apos() + pos_t(sele.awth().value(), 0UL);
129 }
131 const auto& roote = get_elem();
132 if (!(roote.apos() <= tpos && tpos < roote.apos() + roote.adim())) {
133 return sel;
134 }
136 return select(tpos);
137 }
139 Panel* Panel::select(pos_t tpos)
140 {
141 Panel* crnt = this;
143 while (true) {
144 auto* next = std::visit(
145 [&]<typename M>(const M& val) -> Panel*
146 {
147 if constexpr (std::is_same_v<M, layout_t>) {
148 return nullptr;
149 }
151 if constexpr (!std::is_same_v<M, layout_t>) {
152 for (const auto& panel : val.panels()) {
153 const auto plc = panel->get_elem().aplc();
154 if (plc.pos <= tpos && tpos < plc.pos + plc.dim) {
155 return panel.get();
156 }
157 }
159 throw std::runtime_error("Something's wrong, I can feel it!");
160 }
161 },
162 crnt->m_payload);
164 if (next == nullptr) {
165 return crnt;
166 }
168 crnt = next;
169 }
170 }
172 template<Panel::Split T>
173 requires is_enum_valid_v<Panel::Split, T>
174 Panel* Panel::split()
175 {
176 const auto visit_parent = [&]<typename M>(M& pcont) -> Panel*
177 {
178 if constexpr (std::is_same_v<M, layout_t>) {
179 throw std::runtime_error("Invalid node handle [split() layout_t]");
180 }
182 if constexpr (!std::is_same_v<M, layout_t>) {
183 if constexpr (M::type() != T) {
184 return nullptr;
185 }
187 auto itr = pcont.panels().emplace(
188 pcont.find_child(this) + 1,
189 std::make_unique<Panel>(m_parent, plc_t({0, 0}, {0, 0})));
191 m_parent->resize(pcont.aplc());
193 return itr->get();
194 }
195 };
197 // can it by handled by the parent?
198 if (m_parent != nullptr) {
199 auto* ret = std::visit(visit_parent, m_parent->m_payload);
200 if (ret != nullptr) {
201 return ret;
202 }
203 }
205 // Nope I'll do it myself
206 const auto aplc = std::get<layout_t>(m_payload).aplc();
207 auto child = std::get<layout_t>(m_payload).release_child();
209 auto& container = m_payload.emplace<Container<T>>(aplc);
210 // var is not to be used anymore
212 container.panels().emplace_back(
213 std::make_unique<Panel>(this, container.place(0, 2), std::move(child)));
215 container.panels().emplace_back(
216 std::make_unique<Panel>(this, container.place(1, 2)));
218 return container.panels().back().get();
219 }
221 template Panel* Panel::split<Panel::Split::Horizontal>();
222 template Panel* Panel::split<Panel::Split::Vertical>();
224 template Panel* Panel::select<Panel::Direction::Up>(Panel*);
225 template Panel* Panel::select<Panel::Direction::Left>(Panel*);
226 template Panel* Panel::select<Panel::Direction::Right>(Panel*);
227 template Panel* Panel::select<Panel::Direction::Down>(Panel*);
229 } // namespace display