displayLayout and Rendering TUI library |
git clone git://git.dimitrijedobrota.com/display.git |
Log | Files | Refs | README | LICENSE | HACKING | CONTRIBUTING | CODE_OF_CONDUCT | BUILDING |
example.cpp (6328B)
0 #include <iostream>
2 #include <alec/alec.hpp>
3 #include <based/types/literals.hpp>
5 #include "display/display.hpp"
6 #include "display/layout_rigid.hpp"
7 #include "display/window_pivot.hpp"
9 namespace
10 {
12 using namespace display; // NOLINT(*namespace*)
13 using namespace based::literals; // NOLINT(*namespace*)
15 class WindowCustom : public WindowPivot
16 {
17 public:
18 explicit WindowCustom(plc_t aplc, piv_t piv, dim_t dim)
19 : WindowPivot(aplc, pad_t(0_w, 0_h), piv, dim)
20 {
21 }
23 void render() const override
24 {
25 static constexpr based::u8 inc = 0_u8;
26 static constexpr based::u8 mod = 255_u8;
27 static constexpr based::u8 color_green = 0_u8;
28 static constexpr based::u8 color_blue = 0_u8;
29 static based::u8 color_red = 0_u8;
31 color_red = (color_red + inc) % mod;
32 std::cout << alec::background(
33 color_red.value, color_green.value, color_blue.value
34 );
36 line_reset();
37 for (auto i = 0_h; i < hgt(); ++i) {
38 line_empty();
39 }
41 std::cout << alec::background_v<alec::color::def>;
42 std::cout << std::flush;
43 }
44 };
46 class LayoutCustom : public LayoutRigid<Layout<WindowCustom>>
47 {
48 public:
49 explicit LayoutCustom(plc_t aplc)
50 // NOLINTNEXTLINE(*magic*)
51 : LayoutRigid(aplc, {{0, 1, 2}, {7, 8, 3}, {6, 5, 4}})
52 {
53 using x = piv_t::x;
54 using y = piv_t::y;
56 const dim_t dim(12_w, 4_h);
58 append().set_child(piv_t(x::left, y::top), dim);
59 append().set_child(piv_t(x::center, y::top), dim);
60 append().set_child(piv_t(x::right, y::top), dim);
61 append().set_child(piv_t(x::right, y::center), dim);
62 append().set_child(piv_t(x::right, y::bottom), dim);
63 append().set_child(piv_t(x::center, y::bottom), dim);
64 append().set_child(piv_t(x::left, y::bottom), dim);
65 append().set_child(piv_t(x::left, y::center), dim);
66 append().set_child(piv_t(x::center, y::center), dim);
67 }
68 };
70 class LayoutRigidBorder : public LayoutRigid<LayoutCustom>
71 {
72 public:
73 LayoutRigidBorder(plc_t aplc, const layout_t& layout)
74 : LayoutRigid<LayoutCustom>(aplc, layout)
75 {
76 const auto [m, n] = get_grid();
78 const auto valid = [&](std::size_t xpos, std::size_t ypos)
79 {
80 return xpos < n.value && ypos < m.value;
81 };
83 const auto get = [&](std::size_t xpos, std::size_t ypos) -> based::bu8
84 {
85 static constexpr auto not_found = 0xFF;
86 return valid(xpos, ypos) ? layout[xpos][ypos] : not_found;
87 };
89 for (std::size_t i = 0; i <= n.value; i++) {
90 for (std::size_t j = 0; j <= m.value; j++) {
91 const based::bu8 ptl = get(i - 1, j - 1);
92 const based::bu8 ptr = get(i - 1, j);
93 const based::bu8 pbl = get(i, j - 1);
94 const based::bu8 pbr = get(i, j);
96 based::bu8 mask = 0;
97 mask |= ((ptl != ptr) ? 1U : 0U); // Top
98 mask |= ((ptr != pbr) ? 1U : 0U) << 1U; // Right
99 mask |= ((pbr != pbl) ? 1U : 0U) << 2U; // Bottom
100 mask |= ((pbl != ptl) ? 1U : 0U) << 3U; // Left
102 m_corners.emplace_back(mask, wth_t(j), hgt_t(i));
103 }
104 }
105 }
107 template<class... Args>
108 LayoutCustom& append(Args&&... args)
109 {
110 return LayoutMulti<LayoutCustom>::template append<LayoutCustom>(
111 place(size()), std::forward<Args>(args)...
112 );
113 }
115 void resize(plc_t aplc) override
116 {
117 LayoutRigid<LayoutCustom>::resize(aplc);
119 for (std::size_t i = 0; i < size(); i++) {
120 get(i).resize(place(i));
121 }
122 }
124 void render() const override
125 {
126 LayoutRigid<LayoutCustom>::render();
127 for (std::size_t i = 0; i < size(); i++) {
128 const auto [pos, dim] = LayoutRigid<LayoutCustom>::place(i);
130 // Top of each element
131 set_cursor(pos.x + 1_x, pos.y);
132 for (auto j = 1_w; j < dim.width; ++j) {
133 std::cout << "─";
134 }
136 // Left of each element
137 for (auto j = pos.y + 1_y; j < pos.y + dim.height; ++j) {
138 set_cursor(pos.x, j) << "│";
139 }
140 }
142 // Right of the layout
143 for (auto j = aypos() + 1_y; j < aypos() + ahgt(); ++j) {
144 set_cursor(axpos() + awth() - 1_w, j) << "│";
145 }
147 // Bottom of the layout
148 set_cursor(axpos() + 1_x, aypos() + ahgt() - 1_h);
149 for (auto i = 2_w; i < awth(); ++i) {
150 std::cout << "─";
151 }
153 const auto [m, n] = get_grid();
154 const auto [w, h] = adim();
155 const auto unw = w / m;
156 const auto unh = h / n;
157 for (const auto [mask, wth, hgt] : m_corners) {
158 const auto xloc = wth != m ? xpos_t((wth * unw).value) : axpos() + w;
159 const auto yloc = hgt != n ? ypos_t((hgt * unh).value) : aypos() + h;
160 set_cursor(xloc, yloc) << corner_t::lookup[mask]; // NOLINT
161 };
163 std::cout << std::flush;
164 }
166 private:
167 plc_t place(std::size_t idx)
168 {
169 const auto [pos, dim] = LayoutRigid<LayoutCustom>::place(idx);
170 dim_t sub = {1_w, 1_h};
172 if (get_record(idx).addw) {
173 sub.width += 1_w;
174 }
176 if (get_record(idx).addh) {
177 sub.height += 1_h;
178 }
180 return {pos + pos_t(1_x, 1_y), dim - sub};
181 }
183 struct corner_t
184 {
185 // clang-format off
186 constexpr static const char* lookup[] = { // NOLINT
187 "", "", "", "└", "", "│", "┌", "├",
188 "", "┘", "─", "┴", "┐", "┤", "┬", "┼"
189 };
190 // clang-format on
192 corner_t(based::bu8 msk, wth_t wth, hgt_t hgt) // NOLINT
193 : mask(msk)
194 , wigth(wth)
195 , height(hgt)
196 {
197 }
199 based::bu8 mask;
200 wth_t wigth;
201 hgt_t height;
202 };
204 std::vector<corner_t> m_corners;
205 };
207 } // namespace
209 int main()
210 {
211 try {
212 using namespace display; // NOLINT
214 auto& display = Display::display();
216 // clang-format off
217 const LayoutRigid<>::layout_t split = {
218 {1, 1, 2},
219 {0, 4, 2},
220 {3, 4, 2},
221 };
222 // clang-format on
224 auto& layout = display.layout().set_child<LayoutRigidBorder>(split);
225 layout.append();
226 layout.append();
227 layout.append();
228 layout.append();
229 layout.append();
231 display.render();
232 while (true) {
233 const auto evnt = display.get_event();
234 if (evnt.type() == event::type::resize) {
235 std::cout << alec::erase_display_v<alec::motion::whole>;
236 display.render();
237 continue;
238 }
240 if (evnt.type() == event::type::key && evnt.key() == 'q') {
241 break;
242 }
243 }
244 } catch (std::exception& err) {
245 std::cout << err.what() << '\n' << std::flush;
246 }
248 return 0;
249 }