giga

Terminal text editor
git clone git://git.dimitrijedobrota.com/giga.git
Log | Files | Refs | README | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING

layout_dynamic.cpp (5803B)


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 template<Panel::Direction D> 116 requires is_enum_valid_v<Panel::Direction, D> 117 Panel* Panel::select(Panel* sel) 118 { 119 const auto& sele = sel->get_elem(); 120 121 pos_t tpos = {0, 0}; 122 if constexpr (D == Direction::Up) { 123 tpos = sele.apos() + pos_t(0, -1); 124 } else if (D == Direction::Left) { 125 tpos = sele.apos() + pos_t(-1, 0); 126 } else if (D == Direction::Down) { 127 tpos = sele.apos() + pos_t(0UL, sele.ahgt().value()); 128 } else if (D == Direction::Right) { 129 tpos = sele.apos() + pos_t(sele.awth().value(), 0UL); 130 } 131 132 const auto& roote = get_elem(); 133 if (!(roote.apos() <= tpos && tpos < roote.apos() + roote.adim())) { 134 return sel; 135 } 136 137 return select(tpos); 138 } 139 140 Panel* Panel::select(pos_t tpos) 141 { 142 Panel* crnt = this; 143 144 while (true) { 145 auto* next = std::visit( 146 [&]<typename M>(const M& val) -> Panel* 147 { 148 if constexpr (std::is_same_v<M, layout_t>) { 149 return nullptr; 150 } 151 152 if constexpr (!std::is_same_v<M, layout_t>) { 153 for (const auto& panel : val.panels()) { 154 const auto plc = panel->get_elem().aplc(); 155 if (plc.pos <= tpos && tpos < plc.pos + plc.dim) { 156 return panel.get(); 157 } 158 } 159 160 throw std::runtime_error("Something's wrong, I can feel it!"); 161 } 162 }, 163 crnt->m_payload); 164 165 if (next == nullptr) { 166 return crnt; 167 } 168 169 crnt = next; 170 } 171 } 172 173 template<Panel::Split T> 174 requires is_enum_valid_v<Panel::Split, T> 175 Panel* Panel::split() 176 { 177 const auto visit_parent = [&]<typename M>(M& pcont) -> Panel* 178 { 179 if constexpr (std::is_same_v<M, layout_t>) { 180 throw std::runtime_error("Invalid node handle [split() layout_t]"); 181 } 182 183 if constexpr (!std::is_same_v<M, layout_t>) { 184 if constexpr (M::type() != T) { 185 return nullptr; 186 } 187 188 auto itr = pcont.panels().emplace( 189 pcont.find_child(this) + 1, 190 std::make_unique<Panel>(m_parent, plc_t({0, 0}, {0, 0}))); 191 192 m_parent->resize(pcont.aplc()); 193 194 return itr->get(); 195 } 196 }; 197 198 // can it by handled by the parent? 199 if (m_parent != nullptr) { 200 auto* ret = std::visit(visit_parent, m_parent->m_payload); 201 if (ret != nullptr) { 202 return ret; 203 } 204 } 205 206 // Nope I'll do it myself 207 const auto aplc = std::get<layout_t>(m_payload).aplc(); 208 auto child = std::get<layout_t>(m_payload).release_child(); 209 210 auto& container = m_payload.emplace<Container<T>>(aplc); 211 // var is not to be used anymore 212 213 container.panels().emplace_back( 214 std::make_unique<Panel>(this, container.place(0, 2), std::move(child))); 215 216 container.panels().emplace_back( 217 std::make_unique<Panel>(this, container.place(1, 2))); 218 219 return container.panels().back().get(); 220 } 221 222 template Panel* Panel::split<Panel::Split::Horizontal>(); 223 template Panel* Panel::split<Panel::Split::Vertical>(); 224 225 template Panel* Panel::select<Panel::Direction::Up>(Panel*); 226 template Panel* Panel::select<Panel::Direction::Left>(Panel*); 227 template Panel* Panel::select<Panel::Direction::Right>(Panel*); 228 template Panel* Panel::select<Panel::Direction::Down>(Panel*); 229 230 } // namespace display