BuGUI
BUtton Grid User Interface
Loading...
Searching...
No Matches
grid.hpp
1#pragma once
2#include "base_hardware.hpp"
3#include <io/presser.hpp>
4#include <color/color_converter.hpp>
5#include <concepts/device.hpp>
6
7#include <chrono>
8#include <list>
9#include <iostream>
10#include <functional>
11
12namespace bugui
13{
16template <typename Device, typename Controller>
17struct grid : virtual base_hardware
18{ };
19
22template <has_grid Device, typename Controller>
23class grid<Device, Controller>
24 : virtual public base_hardware
25{
26 using id_t = std::remove_cvref_t
27 <decltype(Device::grid::ids()[0][0])>;
28
30
31 int width() const override { return Device::grid::width(); }
32 int height() const override { return Device::grid::height(); }
33
35 color_grid[Device::grid::width()][Device::grid::height()];
36
37 struct previous_press
38 {
39 std::chrono::time_point<std::chrono::steady_clock> t;
40 int i, j;
41 bool down, dragged{false};
42 };
43
44 std::list<previous_press> presses{};
45
46public:
47 ~grid()
48 { std::cout << "presses size: " << presses.size() << '\n'; }
50 presser& get_presser() { return prsr; }
51
52protected:
53 grid()
54 : color_grid{}
55 { }
56
57 void paint(painter& paint
58 , std::function
59 <void(id_t, const color_cnvtr&)>
60 && func)
61 {
62 const auto& top_left{paint.get_top_left()};
63 const auto& bottom_right{paint.get_bottom_right()};
64
65 for (int i{top_left.y}; i < bottom_right.y; i++)
66 for (int j{top_left.x}; j < bottom_right.x; j++)
67 {
68 color c{paint.read_clear(j, i)};
69 color_cnvtr& g{color_grid[i][j]};
70
71 if (g == c) continue;
72
73 g.set(c);
74 func(Device::grid::ids()[i][j], g);
75 }
76 }
77
78 void clear(std::function<void(id_t id)>&& func)
79 {
80 for (int i{0}; i < Device::grid::height(); i++)
81 for (int j{0}; j < Device::grid::width(); j++)
82 {
83 color_converter<typename Device::color>&
84 g{color_grid[i][j]};
85
86 if (!g.is_clear())
87 func(Device::grid::ids()[i][j]);
88 }
89 }
90
91 bool on_grid_received(Controller* ctrlr, id_t id)
92 {
93 // FIXME : ignore the next unpress after a double press ?
94 for (int i{0}; i < Device::grid::height(); i++)
95 for (int j{0}; j < Device::grid::width(); j++)
96 if (id == Device::grid::ids()[i][j])
97 {
98 prsr.set(j, i);
99 bool down{prsr.get_bool()};
100 auto it{presses.begin()};
101
102 using namespace std;
103 using namespace chrono;
104 auto now{steady_clock::now()};
105
106 while (it != presses.end())
107 {
108 if (!it->dragged && duration_cast<milliseconds>
109 (now - it->t) > 200ms)
110 {
111 it = presses.erase(it);
112 continue;
113 }
114
115 if (it->i == i && it->j == j)
116 { // looking for double press
117 if (down && !it->down)
118 {
119 prsr.button_presser::set_double_press();
120 presses.erase(it);
121 ctrlr->handle_presser(prsr);
122 return true;
123 }
124 // looking for drop
125 if (!down && it->down)
126 {
127 if (it->dragged)
128 {
129 prsr.set_drop();
130 presses.erase(it);
131 ctrlr->handle_presser(prsr);
132 return true;
133 }
134 }
135 }
136 // looking for drag : presses one cell apart
137 else if (sqrt(pow(it->i - i, 2) +
138 pow(it->j - j, 2)) == 1)
139 {
140 if (!down && it->down)
141 {
142 prsr.set_drag(it->j, it->i);
143 it->dragged = true;
144 // cleanup previous drag
145 it++;
146 while (it != presses.end())
147 {
148 if (it->i == i && it->j == j && it->dragged)
149 {
150 presses.erase(it);
151 break;
152 }
153 else it++;
154 }
155
156 ctrlr->handle_presser(prsr);
157 return true;
158 }
159 }
160
161 it++;
162 };
163
164 down ? presses.emplace_front(
165 previous_press{now, i, j, true})
166 : presses.emplace_back(
167 previous_press{now, i , j, false});
168 ctrlr->handle_presser(prsr);
169 return true;
170 }
171
172 return false;
173 }
174
175 presser prsr;
176};
177
178} // nemaspace bugui
presser & get_presser()
reties the presser object
Definition grid.hpp:50
virtual void clear()=0
Turns off all LEDs.
virtual int height() const =0
Retrieves the height of the device's grid.
virtual int width() const =0
Retrieves the with of the device's grid.
Povides convertion of color objects to device specific integer values.
Definition color_converter.hpp:94
Empty struct fro device's that do not feature a button grid.
Definition grid.hpp:18
Definition presser.hpp:14