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