Lamp-Da 0.1
A compact lantern project
Loading...
Searching...
No Matches
overlay.hpp
Go to the documentation of this file.
1
5#ifndef MODES_DRAW_OVERLAY_HPP
6#define MODES_DRAW_OVERLAY_HPP
7
8namespace lampda::modes::draw {
10namespace overlay {
11
13enum class ElementType : uint8_t
14{
15 NONE = 0,
16 RAMP,
17 DOT,
18};
19
20namespace __private {
21
23struct Color
24{
25 uint8_t red;
26 uint8_t green;
27 uint8_t blue;
28 uint32_t get_color() const { return (red << 16) | (green << 8) | blue; }
29};
30
35{
36 ElementType type = ElementType::NONE;
37 uint8_t progress;
38
39 uint16_t coordinateX;
40 uint16_t coordinateY;
41
43
44 int32_t timeout_ms = -1;
45};
46
47} // namespace __private
48
49template<int UIElementSize = 16, uint8_t freezeSize = 5, uint8_t nbBlackLines = 2> class Manager
50{
51public:
52 Manager() : activeUiElements(0) {}
53
57 void display_update(auto& ctx)
58 {
59 assert(activeUiElements < UIElementSize);
60
61 // restore first led skip to be able to draw
62 ctx.skipFirstLedsForFrames(0);
63
64 if (activeUiElements == 0)
65 return;
66
67 // clear overlay area first
68 for (uint8_t i = 0; i < ctx.lamp.maxWidth * nbBlackLines; ++i)
69 {
70 ctx.lamp.setPixelColor(i, 0);
71 }
72
73 // keep track of the last active element index
74 size_t lastActiveElementIndex = 0;
75 const auto timeNow = ctx.lamp.now;
76 const size_t activeUiElementsToDisplay = activeUiElements;
77 // display all elements
78 for (uint8_t i = 0; i < activeUiElementsToDisplay; ++i)
79 {
80 const auto elementTimeout = elements[i].timeout_ms;
81 // auto deletion of element
82 if (elementTimeout > 0 and timeNow > elementTimeout)
83 {
84 // remove one active element
85 if (activeUiElements > 0)
86 --activeUiElements;
87 platform::lampda_print("delete element %d", i);
88 }
89 else
90 {
91 drawElement(elements[i], ctx);
92
93 // if an element before this was delete, shift this element index
94 if (i != lastActiveElementIndex)
95 {
96 // shift the saved elements
97 elements[lastActiveElementIndex] = elements[i];
98 }
99 ++lastActiveElementIndex;
100 }
101 }
102
103 // relock the display capabilities for the remaining time
104 ctx.skipFirstLedsForFrames(ctx.lamp.maxWidth * nbBlackLines, freezeSize);
105 }
106
108 void clear() { activeUiElements = 0; }
109
111 uint8_t get_element_count(const ElementType type) const
112 {
113 uint8_t cnt = 0;
114 for (uint8_t i = 0; i < activeUiElements; ++i)
115 {
116 // find elements of a type
117 if (elements[i].type == type)
118 {
119 cnt++;
120 }
121 }
122 return cnt;
123 }
124
135 bool add_ui_element(const auto& ctx,
136 const ElementType type,
137 const colors::PaletteTy& palette,
138 const uint16_t coordinateX = 0,
139 const uint16_t coordinateY = 0,
140 const uint8_t progress = 0,
141 const uint32_t activityDelay_ms = 50)
142 {
143 if (activeUiElements >= UIElementSize - 1)
144 return false;
145
146 // set the UI element
147 __private::UIElement& element = elements[activeUiElements];
148 element.type = type;
149 element.progress = progress;
150 element.coordinateX = coordinateX;
151 element.coordinateY = coordinateY;
152 element.color = palette;
153 // set optionnal auto destroy
154 if (activityDelay_ms > 0)
155 element.timeout_ms = ctx.lamp.now + activityDelay_ms;
156
157 // increase element count
158 activeUiElements++;
159 return true;
160 }
161
169 template<bool shouldUpdateTimeout = true>
170 bool update_type_progress(const auto& ctx, const ElementType type, uint16_t desiredIndex, const uint8_t progress)
171 {
172 size_t index;
173 if (get_N_of_type(type, desiredIndex, index))
174 {
175 elements[index].progress = progress;
176
177 // if requested, update timeout
178 const uint32_t newTimeout = ctx.lamp.now + freezeSize * ctx.lamp.frameDurationMs;
179 if (shouldUpdateTimeout and elements[index].timeout_ms <= newTimeout)
180 {
181 // add two frames of breathing room
182 elements[index].timeout_ms = newTimeout;
183 }
184 return true;
185 }
186 return false;
187 }
188
196 template<bool shouldUpdateTimeout = true> bool update_type_color(const auto& ctx,
197 const ElementType type,
198 uint16_t desiredIndex,
199 const colors::PaletteTy& palette)
200 {
201 size_t index;
202 if (get_N_of_type(type, desiredIndex, index))
203 {
204 elements[index].color = palette;
205
206 // if requested, update timeout
207 const uint32_t newTimeout = ctx.lamp.now + freezeSize * ctx.lamp.frameDurationMs;
208 if (shouldUpdateTimeout and elements[index].timeout_ms <= newTimeout)
209 {
210 // add two frames of breathing room
211 elements[index].timeout_ms = newTimeout;
212 }
213 return true;
214 }
215 return false;
216 }
217
218 bool update_type_timeout(const auto& ctx, const ElementType type, uint16_t desiredIndex, const uint32_t timeout_ms)
219 {
220 size_t index;
221 if (get_N_of_type(type, desiredIndex, index))
222 {
223 // add two frames of breathing room
224 elements[index].timeout_ms = ctx.lamp.now + timeout_ms;
225 return true;
226 }
227 return false;
228 }
229
238 template<bool shouldUpdateTimeout = true> bool update_type(const auto& ctx,
239 const ElementType type,
240 uint16_t desiredIndex,
241 const uint8_t progress,
242 const colors::PaletteTy& palette)
243 {
244 size_t index;
245 if (get_N_of_type(type, desiredIndex, index))
246 {
247 elements[index].progress = progress;
248 elements[index].color = palette;
249
250 // if requested, update timeout
251 const uint32_t newTimeout = ctx.lamp.now + freezeSize * ctx.lamp.frameDurationMs;
252 if (shouldUpdateTimeout and elements[index].timeout_ms <= newTimeout)
253 {
254 // add two frames of breathing room
255 elements[index].timeout_ms = newTimeout;
256 }
257 return true;
258 }
259 return false;
260 }
261
262protected:
264 bool get_N_of_type(const ElementType type, uint16_t desiredIndex, size_t& elementId) const
265 {
266 // display all elements
267 for (uint8_t i = 0; i < activeUiElements; ++i)
268 {
269 // find elements of a type
270 if (elements[i].type == type)
271 {
272 // check that we reached the desired element
273 if (desiredIndex <= 0)
274 {
275 elementId = i;
276 return true;
277 }
278 // or decrement the element count
279 desiredIndex -= 1;
280 }
281 }
282 return false;
283 }
284
285 void drawElement(const __private::UIElement& e, auto& ctx) const
286 {
287 switch (e.type)
288 {
290 {
292 break;
293 }
294 case ElementType::DOT:
295 {
297 break;
298 }
299 case ElementType::NONE:
300 {
301 break;
302 }
303
304 // NO DEFAULT: so we have errors on compile
305 }
306 }
307
309 void display_ramp(auto& ctx,
310 const uint8_t progress,
311 const colors::PaletteTy& palette,
312 const uint16_t startCoordinateY) const
313 {
314 const uint16_t rampScale = (progress / 255.0) * ctx.lamp.maxWidth;
315 for (uint16_t i = 0; i < rampScale; ++i)
316 {
317 const auto color = modes::colors::from_palette<false>(lmpd_map<uint8_t>(i, 0, rampScale, 0, 255), palette);
318 ctx.lamp.setPixelColorXY(i, startCoordinateY, color);
319 }
320 }
321
323 void display_dot(auto& ctx,
324 const uint8_t progress,
325 const colors::PaletteTy& palette,
326 const uint16_t coordinateX,
327 const uint16_t coordinateY) const
328 {
329 const auto color = modes::colors::from_palette<false>(progress, palette);
330 ctx.lamp.setPixelColorXY(coordinateX, coordinateY, color);
331 }
332
333private:
335 std::array<__private::UIElement, UIElementSize> elements;
337 size_t activeUiElements = 0;
338};
339
340} // namespace overlay
341} // namespace lampda::modes::draw
342
343#endif
Definition: overlay.hpp:50
void display_dot(auto &ctx, const uint8_t progress, const colors::PaletteTy &palette, const uint16_t coordinateX, const uint16_t coordinateY) const
Display a single colored pixel.
Definition: overlay.hpp:323
bool add_ui_element(const auto &ctx, const ElementType type, const colors::PaletteTy &palette, const uint16_t coordinateX=0, const uint16_t coordinateY=0, const uint8_t progress=0, const uint32_t activityDelay_ms=50)
Add a new UI element to the overlay.
Definition: overlay.hpp:135
void display_ramp(auto &ctx, const uint8_t progress, const colors::PaletteTy &palette, const uint16_t startCoordinateY) const
Display a colored ramp.
Definition: overlay.hpp:309
uint8_t get_element_count(const ElementType type) const
Return the count of elements of a target type.
Definition: overlay.hpp:111
bool get_N_of_type(const ElementType type, uint16_t desiredIndex, size_t &elementId) const
Find and return the Nth element of a given type.
Definition: overlay.hpp:264
void clear()
Clear all UI elements.
Definition: overlay.hpp:108
bool update_type_color(const auto &ctx, const ElementType type, uint16_t desiredIndex, const colors::PaletteTy &palette)
Update the target UI element color palette.
Definition: overlay.hpp:196
bool update_type(const auto &ctx, const ElementType type, uint16_t desiredIndex, const uint8_t progress, const colors::PaletteTy &palette)
Update the target UI element.
Definition: overlay.hpp:238
bool update_type_progress(const auto &ctx, const ElementType type, uint16_t desiredIndex, const uint8_t progress)
Update the target UI element progress.
Definition: overlay.hpp:170
void display_update(auto &ctx)
Display and update the overlay.
Definition: overlay.hpp:57
std::array< uint32_t, 16 > PaletteTy
Palette types.
Definition: palettes.hpp:18
ElementType
< Define an UI element type
Definition: overlay.hpp:14
void lampda_print(const char *format,...)
Definition: print.cpp:43
< define a display color
Definition: overlay.hpp:24
Define an UI element.
Definition: overlay.hpp:35
uint16_t coordinateY
start Y coordinates
Definition: overlay.hpp:40
ElementType type
type of UI elements
Definition: overlay.hpp:36
colors::PaletteTy color
color palette to display
Definition: overlay.hpp:42
uint16_t coordinateX
start X coordinates
Definition: overlay.hpp:39
int32_t timeout_ms
If set to a positive number, this element will delete itself at the set time.
Definition: overlay.hpp:44
uint8_t progress
0-255 animation progress
Definition: overlay.hpp:37