ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
display.cpp
Go to the documentation of this file.
1#include "display.h"
2#include <cmath>
3#include <utility>
4#include <numbers>
7#include "esphome/core/hal.h"
9#include "esphome/core/log.h"
10
12ESPHOME_LOG_TAG(TAG, "display");
13
14// COLOR_OFF and COLOR_ON are now inline constexpr in display.h
15
16void Display::fill(Color color) { this->filled_rectangle(0, 0, this->get_width(), this->get_height(), color); }
17void Display::clear() { this->fill(COLOR_OFF); }
18void Display::set_rotation(DisplayRotation rotation) { this->rotation_ = rotation; }
19
20void HOT Display::line(int x1, int y1, int x2, int y2, Color color) {
21 const int32_t dx = abs(x2 - x1), sx = x1 < x2 ? 1 : -1;
22 const int32_t dy = -abs(y2 - y1), sy = y1 < y2 ? 1 : -1;
23 int32_t err = dx + dy;
24
25 while (true) {
26 this->draw_pixel_at(x1, y1, color);
27 if (x1 == x2 && y1 == y2)
28 break;
29 int32_t e2 = 2 * err;
30 if (e2 >= dy) {
31 err += dy;
32 x1 += sx;
33 }
34 if (e2 <= dx) {
35 err += dx;
36 y1 += sy;
37 }
38 }
39}
40
41void Display::line_at_angle(int x, int y, int angle, int length, Color color) {
42 this->line_at_angle(x, y, angle, 0, length, color);
43}
44
45void Display::line_at_angle(int x, int y, int angle, int start_radius, int stop_radius, Color color) {
46 // Calculate start and end points
47 int x1 = (start_radius * std::cos(angle * std::numbers::pi_v<float> / 180)) + x;
48 int y1 = (start_radius * std::sin(angle * std::numbers::pi_v<float> / 180)) + y;
49 int x2 = (stop_radius * std::cos(angle * std::numbers::pi_v<float> / 180)) + x;
50 int y2 = (stop_radius * std::sin(angle * std::numbers::pi_v<float> / 180)) + y;
51
52 // Draw line
53 this->line(x1, y1, x2, y2, color);
54}
55
56// flatten keeps to_color() inlined in the pixel loop; in PSRAM builds GCC at
57// -Os stops inlining it once there are two call sites, which costs a call and
58// spills per pixel. Without PSRAM there is one call site and it changes
59// nothing, and draw_pixel_at() stays a virtual call either way.
60// HIGH_BYTE_FIRST (big endian) only matters for 565; as a template argument its test leaves the pixel loop.
61template<ColorBitness BITNESS, bool HIGH_BYTE_FIRST = false>
62static void __attribute__((flatten)) draw_packed_pixels(Display *display, int x_start, int y_start, int w, int h,
63 const uint8_t *ptr, int x_offset, int y_offset, int x_pad) {
64 const size_t line_stride = x_offset + w + x_pad; // length of each source line in pixels
65 // BITNESS is a constant here, so to_color()'s three per pixel divisions
66 // become a multiply and shift and its bitness switch folds.
67 const auto draw_source_pixel = [&](int x, int y, size_t source_idx) ESPHOME_ALWAYS_INLINE {
68 display->draw_pixel_at(
69 x + x_start, y + y_start,
70 ColorUtil::to_color(ColorUtil::read_packed<BITNESS>(ptr, source_idx, HIGH_BYTE_FIRST), BITNESS));
71 };
72 // The source and frame buffers are row-major, so walking rows keeps the read
73 // and the write sequential. When the display swaps the axes before writing,
74 // walking columns keeps the write sequential instead; with the frame buffer
75 // in PSRAM a strided write costs more than a strided read.
76#ifdef USE_PSRAM
77 if (display->pixel_axes_swapped()) {
78 size_t column_idx = y_offset * line_stride + x_offset;
79 for (int x = 0; x != w; x++, column_idx++) {
80 size_t source_idx = column_idx;
81 for (int y = 0; y != h; y++, source_idx += line_stride) {
82 draw_source_pixel(x, y, source_idx);
83 }
84 }
85 return;
86 }
87#endif
88 // Row walk: builds without PSRAM, and PSRAM builds whose axes are not swapped.
89 for (int y = 0; y != h; y++) {
90 size_t source_idx = (y_offset + y) * line_stride + x_offset;
91 for (int x = 0; x != w; x++, source_idx++) {
92 draw_source_pixel(x, y, source_idx);
93 }
94 }
95}
96
97// Remove before 2027.5.0. Draws a block in the deprecated BGR or GRB order, pixel by pixel. Not inlined, so
98// the RGB loops above compile as tightly as before.
99static void __attribute__((noinline)) draw_ordered_pixels(Display *display, int x_start, int y_start, int w, int h,
101 bool big_endian, int x_offset, int y_offset, int x_pad) {
102 const size_t line_stride = x_offset + w + x_pad;
103 for (int y = 0; y != h; y++) {
104 size_t source_idx = (y_offset + y) * line_stride + x_offset;
105 for (int x = 0; x != w; x++, source_idx++) {
106 uint32_t code;
107 if (bitness == COLOR_BITNESS_565) {
109 } else if (bitness == COLOR_BITNESS_888) {
111 } else {
113 }
114 display->draw_pixel_at(x + x_start, y + y_start, apply_color_order(ColorUtil::to_color(code, bitness), order));
115 }
116 }
117}
118
119void Display::draw_pixels_internal(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorBitness bitness,
120 bool big_endian, int x_offset, int y_offset, int x_pad) {
121 // Through the deprecated form, so a driver that still overrides only that one keeps its fast path.
122 // Remove before 2027.5.0, when the per pixel drawing below moves here.
123#pragma GCC diagnostic push
124#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
126#pragma GCC diagnostic pop
127}
128
129// Must not call draw_pixels_at() without a color order or draw_pixels_internal(): those call this, and a legacy
130// override's fallback ends up here.
131void Display::draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
132 ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad) {
133 if (order != COLOR_ORDER_RGB) {
134 draw_ordered_pixels(this, x_start, y_start, w, h, ptr, order, bitness, big_endian, x_offset, y_offset, x_pad);
135 return;
136 }
137 switch (bitness) {
139 if (big_endian) {
140 draw_packed_pixels<COLOR_BITNESS_565, true>(this, x_start, y_start, w, h, ptr, x_offset, y_offset, x_pad);
141 } else {
142 draw_packed_pixels<COLOR_BITNESS_565, false>(this, x_start, y_start, w, h, ptr, x_offset, y_offset, x_pad);
143 }
144 break;
146 draw_packed_pixels<COLOR_BITNESS_888>(this, x_start, y_start, w, h, ptr, x_offset, y_offset, x_pad);
147 break;
148 default:
149 draw_packed_pixels<COLOR_BITNESS_332>(this, x_start, y_start, w, h, ptr, x_offset, y_offset, x_pad);
150 break;
151 }
152}
153
154void HOT Display::horizontal_line(int x, int y, int width, Color color) {
155 // Future: Could be made more efficient by manipulating buffer directly in certain rotations.
156 for (int i = x; i < x + width; i++)
157 this->draw_pixel_at(i, y, color);
158}
159
160void HOT Display::vertical_line(int x, int y, int height, Color color) {
161 // Future: Could be made more efficient by manipulating buffer directly in certain rotations.
162 for (int i = y; i < y + height; i++)
163 this->draw_pixel_at(x, i, color);
164}
165
166void Display::rectangle(int x1, int y1, int width, int height, Color color) {
167 this->horizontal_line(x1, y1, width, color);
168 this->horizontal_line(x1, y1 + height - 1, width, color);
169 this->vertical_line(x1, y1, height, color);
170 this->vertical_line(x1 + width - 1, y1, height, color);
171}
172
173void Display::filled_rectangle(int x1, int y1, int width, int height, Color color) {
174 // Future: Use vertical_line and horizontal_line methods depending on rotation to reduce memory accesses.
175 for (int i = y1; i < y1 + height; i++) {
176 this->horizontal_line(x1, i, width, color);
177 }
178}
179
180void HOT Display::circle(int center_x, int center_xy, int radius, Color color) {
181 int dx = -radius;
182 int dy = 0;
183 int err = 2 - 2 * radius;
184 int e2;
185
186 do {
187 this->draw_pixel_at(center_x - dx, center_xy + dy, color);
188 this->draw_pixel_at(center_x + dx, center_xy + dy, color);
189 this->draw_pixel_at(center_x + dx, center_xy - dy, color);
190 this->draw_pixel_at(center_x - dx, center_xy - dy, color);
191 e2 = err;
192 if (e2 < dy) {
193 err += ++dy * 2 + 1;
194 if (-dx == dy && e2 <= dx) {
195 e2 = 0;
196 }
197 }
198 if (e2 > dx) {
199 err += ++dx * 2 + 1;
200 }
201 } while (dx <= 0);
202}
203
204void Display::filled_circle(int center_x, int center_y, int radius, Color color) {
205 int dx = -int32_t(radius);
206 int dy = 0;
207 int err = 2 - 2 * radius;
208 int e2;
209
210 do {
211 this->draw_pixel_at(center_x - dx, center_y + dy, color);
212 this->draw_pixel_at(center_x + dx, center_y + dy, color);
213 this->draw_pixel_at(center_x + dx, center_y - dy, color);
214 this->draw_pixel_at(center_x - dx, center_y - dy, color);
215 int hline_width = 2 * (-dx) + 1;
216 this->horizontal_line(center_x + dx, center_y + dy, hline_width, color);
217 this->horizontal_line(center_x + dx, center_y - dy, hline_width, color);
218 e2 = err;
219 if (e2 < dy) {
220 err += ++dy * 2 + 1;
221 if (-dx == dy && e2 <= dx) {
222 e2 = 0;
223 }
224 }
225 if (e2 > dx) {
226 err += ++dx * 2 + 1;
227 }
228 } while (dx <= 0);
229}
230
231void Display::filled_ring(int center_x, int center_y, int radius1, int radius2, Color color) {
232 int rmax = radius1 > radius2 ? radius1 : radius2;
233 int rmin = radius1 < radius2 ? radius1 : radius2;
234 int dxmax = -int32_t(rmax), dxmin = -int32_t(rmin);
235 int dymax = 0, dymin = 0;
236 int errmax = 2 - 2 * rmax, errmin = 2 - 2 * rmin;
237 int e2max, e2min;
238 do {
239 // 8 dots for borders
240 this->draw_pixel_at(center_x - dxmax, center_y + dymax, color);
241 this->draw_pixel_at(center_x + dxmax, center_y + dymax, color);
242 this->draw_pixel_at(center_x - dxmin, center_y + dymin, color);
243 this->draw_pixel_at(center_x + dxmin, center_y + dymin, color);
244 this->draw_pixel_at(center_x + dxmax, center_y - dymax, color);
245 this->draw_pixel_at(center_x - dxmax, center_y - dymax, color);
246 this->draw_pixel_at(center_x + dxmin, center_y - dymin, color);
247 this->draw_pixel_at(center_x - dxmin, center_y - dymin, color);
248 if (dymin < rmin) {
249 // two parts - four lines
250 int hline_width = -(dxmax - dxmin) + 1;
251 this->horizontal_line(center_x + dxmax, center_y + dymax, hline_width, color);
252 this->horizontal_line(center_x - dxmin, center_y + dymax, hline_width, color);
253 this->horizontal_line(center_x + dxmax, center_y - dymax, hline_width, color);
254 this->horizontal_line(center_x - dxmin, center_y - dymax, hline_width, color);
255 } else {
256 // one part - top and bottom
257 int hline_width = 2 * (-dxmax) + 1;
258 this->horizontal_line(center_x + dxmax, center_y + dymax, hline_width, color);
259 this->horizontal_line(center_x + dxmax, center_y - dymax, hline_width, color);
260 }
261 e2max = errmax;
262 // tune external
263 if (e2max < dymax) {
264 errmax += ++dymax * 2 + 1;
265 if (-dxmax == dymax && e2max <= dxmax) {
266 e2max = 0;
267 }
268 }
269 if (e2max > dxmax) {
270 errmax += ++dxmax * 2 + 1;
271 }
272 // tune internal
273 while (dymin < dymax && dymin < rmin) {
274 e2min = errmin;
275 if (e2min < dymin) {
276 errmin += ++dymin * 2 + 1;
277 if (-dxmin == dymin && e2min <= dxmin) {
278 e2min = 0;
279 }
280 }
281 if (e2min > dxmin) {
282 errmin += ++dxmin * 2 + 1;
283 }
284 }
285 } while (dxmax <= 0);
286}
287
288void Display::filled_gauge(int center_x, int center_y, int radius1, int radius2, int progress, Color color) {
289 int rmax = radius1 > radius2 ? radius1 : radius2;
290 int rmin = radius1 < radius2 ? radius1 : radius2;
291 int dxmax = -int32_t(rmax), dxmin = -int32_t(rmin), upd_dxmax, upd_dxmin;
292 int dymax = 0, dymin = 0;
293 int errmax = 2 - 2 * rmax, errmin = 2 - 2 * rmin;
294 int e2max, e2min;
295 progress = std::max(0, std::min(progress, 100)); // 0..100
296 int draw_progress = progress > 50 ? (100 - progress) : progress;
297 float tan_a = (progress == 50) ? 65535 : tanf(float(draw_progress) * std::numbers::pi_v<float> / 100); // slope
298
299 do {
300 // outer dots
301 this->draw_pixel_at(center_x + dxmax, center_y - dymax, color);
302 this->draw_pixel_at(center_x - dxmax, center_y - dymax, color);
303 if (dymin < rmin) {
304 // side parts
305 int lhline_width = -(dxmax - dxmin) + 1;
306 if (progress >= 50) {
307 if (float(dymax) < float(-dxmax) * tan_a) {
308 upd_dxmax = std::ceil(float(dymax) / tan_a);
309 } else {
310 upd_dxmax = -dxmax;
311 }
312 this->horizontal_line(center_x + dxmax, center_y - dymax, lhline_width, color); // left
313 if (!dymax)
314 this->horizontal_line(center_x - dxmin, center_y, lhline_width, color); // right horizontal border
315 if (upd_dxmax > -dxmin) {
316 // right
317 int rhline_width = (upd_dxmax + dxmin) + 1;
318 this->horizontal_line(center_x - dxmin, center_y - dymax,
319 rhline_width > lhline_width ? lhline_width : rhline_width, color);
320 }
321 } else {
322 if (float(dymin) > float(-dxmin) * tan_a) {
323 upd_dxmin = std::ceil(float(dymin) / tan_a);
324 } else {
325 upd_dxmin = -dxmin;
326 }
327 lhline_width = -(dxmax + upd_dxmin) + 1;
328 if (!dymax)
329 this->horizontal_line(center_x - dxmin, center_y, lhline_width, color); // right horizontal border
330 if (lhline_width > 0)
331 this->horizontal_line(center_x + dxmax, center_y - dymax, lhline_width, color);
332 }
333 } else {
334 // top part
335 int hline_width = 2 * (-dxmax) + 1;
336 if (progress >= 50) {
337 if (dymax < float(-dxmax) * tan_a) {
338 upd_dxmax = std::ceil(float(dymax) / tan_a);
339 hline_width = -dxmax + upd_dxmax + 1;
340 }
341 } else {
342 if (dymax < float(-dxmax) * tan_a) {
343 upd_dxmax = std::ceil(float(dymax) / tan_a);
344 hline_width = -dxmax - upd_dxmax + 1;
345 } else {
346 hline_width = 0;
347 }
348 }
349 if (hline_width > 0)
350 this->horizontal_line(center_x + dxmax, center_y - dymax, hline_width, color);
351 }
352 e2max = errmax;
353 if (e2max < dymax) {
354 errmax += ++dymax * 2 + 1;
355 if (-dxmax == dymax && e2max <= dxmax) {
356 e2max = 0;
357 }
358 }
359 if (e2max > dxmax) {
360 errmax += ++dxmax * 2 + 1;
361 }
362 while (dymin <= dymax && dymin <= rmin && dxmin <= 0) {
363 this->draw_pixel_at(center_x + dxmin, center_y - dymin, color);
364 this->draw_pixel_at(center_x - dxmin, center_y - dymin, color);
365 e2min = errmin;
366 if (e2min < dymin) {
367 errmin += ++dymin * 2 + 1;
368 if (-dxmin == dymin && e2min <= dxmin) {
369 e2min = 0;
370 }
371 }
372 if (e2min > dxmin) {
373 errmin += ++dxmin * 2 + 1;
374 }
375 }
376 } while (dxmax <= 0);
377}
378
379void HOT Display::triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color) {
380 this->line(x1, y1, x2, y2, color);
381 this->line(x1, y1, x3, y3, color);
382 this->line(x2, y2, x3, y3, color);
383}
384
385void Display::sort_triangle_points_by_y_(int *x1, int *y1, int *x2, int *y2, int *x3, int *y3) {
386 if (*y1 > *y2) {
387 int x_temp = *x1, y_temp = *y1;
388 *x1 = *x2, *y1 = *y2;
389 *x2 = x_temp, *y2 = y_temp;
390 }
391 if (*y1 > *y3) {
392 int x_temp = *x1, y_temp = *y1;
393 *x1 = *x3, *y1 = *y3;
394 *x3 = x_temp, *y3 = y_temp;
395 }
396 if (*y2 > *y3) {
397 int x_temp = *x2, y_temp = *y2;
398 *x2 = *x3, *y2 = *y3;
399 *x3 = x_temp, *y3 = y_temp;
400 }
401}
402
403void Display::filled_flat_side_triangle_(int x1, int y1, int x2, int y2, int x3, int y3, Color color) {
404 // y2 must be equal to y3 (same horizontal line)
405
406 // Initialize Bresenham's algorithm for side 1
407 int s1_current_x = x1;
408 int s1_current_y = y1;
409 bool s1_axis_swap = false;
410 int s1_dx = abs(x2 - x1);
411 int s1_dy = abs(y2 - y1);
412 int s1_sign_x = ((x2 - x1) >= 0) ? 1 : -1;
413 int s1_sign_y = ((y2 - y1) >= 0) ? 1 : -1;
414 if (s1_dy > s1_dx) {
415 // swap values
416 int tmp = s1_dx;
417 s1_dx = s1_dy;
418 s1_dy = tmp;
419 s1_axis_swap = true;
420 }
421 int s1_error = 2 * s1_dy - s1_dx;
422
423 // Initialize Bresenham's algorithm for side 2
424 int s2_current_x = x1;
425 int s2_current_y = y1;
426 bool s2_axis_swap = false;
427 int s2_dx = abs(x3 - x1);
428 int s2_dy = abs(y3 - y1);
429 int s2_sign_x = ((x3 - x1) >= 0) ? 1 : -1;
430 int s2_sign_y = ((y3 - y1) >= 0) ? 1 : -1;
431 if (s2_dy > s2_dx) {
432 // swap values
433 int tmp = s2_dx;
434 s2_dx = s2_dy;
435 s2_dy = tmp;
436 s2_axis_swap = true;
437 }
438 int s2_error = 2 * s2_dy - s2_dx;
439
440 // Iterate on side 1 and allow side 2 to be processed to match the advance of the y-axis.
441 for (int i = 0; i <= s1_dx; i++) {
442 if (s1_current_x <= s2_current_x) {
443 this->horizontal_line(s1_current_x, s1_current_y, s2_current_x - s1_current_x + 1, color);
444 } else {
445 this->horizontal_line(s2_current_x, s2_current_y, s1_current_x - s2_current_x + 1, color);
446 }
447
448 // Bresenham's #1
449 // Side 1 s1_current_x and s1_current_y calculation
450 while (s1_error >= 0) {
451 if (s1_axis_swap) {
452 s1_current_x += s1_sign_x;
453 } else {
454 s1_current_y += s1_sign_y;
455 }
456 s1_error = s1_error - 2 * s1_dx;
457 }
458 if (s1_axis_swap) {
459 s1_current_y += s1_sign_y;
460 } else {
461 s1_current_x += s1_sign_x;
462 }
463 s1_error = s1_error + 2 * s1_dy;
464
465 // Bresenham's #2
466 // Side 2 s2_current_x and s2_current_y calculation
467 while (s2_current_y != s1_current_y) {
468 while (s2_error >= 0) {
469 if (s2_axis_swap) {
470 s2_current_x += s2_sign_x;
471 } else {
472 s2_current_y += s2_sign_y;
473 }
474 s2_error = s2_error - 2 * s2_dx;
475 }
476 if (s2_axis_swap) {
477 s2_current_y += s2_sign_y;
478 } else {
479 s2_current_x += s2_sign_x;
480 }
481 s2_error = s2_error + 2 * s2_dy;
482 }
483 }
484}
485
486void Display::filled_triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color) {
487 // Sort the three points by y-coordinate ascending, so [x1,y1] is the topmost point
488 this->sort_triangle_points_by_y_(&x1, &y1, &x2, &y2, &x3, &y3);
489
490 if (y2 == y3) {
491 // Check for special case of a bottom-flat triangle
492 this->filled_flat_side_triangle_(x1, y1, x2, y2, x3, y3, color);
493 } else if (y1 == y2) {
494 // Check for special case of a top-flat triangle
495 this->filled_flat_side_triangle_(x3, y3, x1, y1, x2, y2, color);
496 } else {
497 // General case: split the no-flat-side triangle in a top-flat triangle and bottom-flat triangle
498 int x_temp = (int) (x1 + ((float) (y2 - y1) / (float) (y3 - y1)) * (x3 - x1)), y_temp = y2;
499 this->filled_flat_side_triangle_(x1, y1, x2, y2, x_temp, y_temp, color);
500 this->filled_flat_side_triangle_(x3, y3, x2, y2, x_temp, y_temp, color);
501 }
502}
503
504void HOT Display::get_regular_polygon_vertex(int vertex_id, int *vertex_x, int *vertex_y, int center_x, int center_y,
505 int radius, int edges, RegularPolygonVariation variation,
506 float rotation_degrees) {
507 if (edges >= 2) {
508 // Given the orientation of the display component, an angle is measured clockwise from the x axis.
509 // For a regular polygon, the human reference would be the top of the polygon,
510 // hence we rotate the shape by 270° to orient the polygon up.
511 rotation_degrees += ROTATION_270_DEGREES;
512 // Convert the rotation to radians, easier to use in trigonometrical calculations
513 float rotation_radians = rotation_degrees * std::numbers::pi_v<float> / 180;
514 // A pointy top variation means the first vertex of the polygon is at the top center of the shape, this requires no
515 // additional rotation of the shape.
516 // A flat top variation means the first point of the polygon has to be rotated so that the first edge is horizontal,
517 // this requires to rotate the shape by π/edges radians counter-clockwise so that the first point is located on the
518 // left side of the first horizontal edge.
519 rotation_radians -= (variation == VARIATION_FLAT_TOP) ? std::numbers::pi_v<float> / edges : 0.0f;
520
521 float vertex_angle = ((float) vertex_id) / edges * 2 * std::numbers::pi_v<float> + rotation_radians;
522 *vertex_x = (int) std::round(std::cos(vertex_angle) * radius) + center_x;
523 *vertex_y = (int) std::round(std::sin(vertex_angle) * radius) + center_y;
524 }
525}
526
527void HOT Display::regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation,
528 float rotation_degrees, Color color, RegularPolygonDrawing drawing) {
529 if (edges >= 2) {
530 int previous_vertex_x, previous_vertex_y;
531 for (int current_vertex_id = 0; current_vertex_id <= edges; current_vertex_id++) {
532 int current_vertex_x, current_vertex_y;
533 get_regular_polygon_vertex(current_vertex_id, &current_vertex_x, &current_vertex_y, x, y, radius, edges,
534 variation, rotation_degrees);
535 if (current_vertex_id > 0) {
536 // Start drawing after the 2nd vertex coordinates has been calculated
537 if (drawing == DRAWING_FILLED) {
538 this->filled_triangle(x, y, previous_vertex_x, previous_vertex_y, current_vertex_x, current_vertex_y, color);
539 } else if (drawing == DRAWING_OUTLINE) {
540 this->line(previous_vertex_x, previous_vertex_y, current_vertex_x, current_vertex_y, color);
541 }
542 }
543 previous_vertex_x = current_vertex_x;
544 previous_vertex_y = current_vertex_y;
545 }
546 }
547}
548
549void HOT Display::regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation, Color color,
550 RegularPolygonDrawing drawing) {
551 regular_polygon(x, y, radius, edges, variation, ROTATION_0_DEGREES, color, drawing);
552}
553
554void HOT Display::regular_polygon(int x, int y, int radius, int edges, Color color, RegularPolygonDrawing drawing) {
555 regular_polygon(x, y, radius, edges, VARIATION_POINTY_TOP, ROTATION_0_DEGREES, color, drawing);
556}
557
558void Display::filled_regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation,
559 float rotation_degrees, Color color) {
560 regular_polygon(x, y, radius, edges, variation, rotation_degrees, color, DRAWING_FILLED);
561}
562
563void Display::filled_regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation,
564 Color color) {
565 regular_polygon(x, y, radius, edges, variation, ROTATION_0_DEGREES, color, DRAWING_FILLED);
566}
567
568void Display::filled_regular_polygon(int x, int y, int radius, int edges, Color color) {
570}
571
572void Display::print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text, Color background) {
573 int x_start, y_start;
574 int width, height;
575 this->get_text_bounds(x, y, text, font, align, &x_start, &y_start, &width, &height);
576 font->print(x_start, y_start, this, color, text, background);
577}
578
579void Display::vprintf_(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,
580 va_list arg) {
581 char buffer[256];
582 int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
583 if (ret > 0)
584 this->print(x, y, font, color, align, buffer, background);
585}
586
587void Display::image(int x, int y, BaseImage *image, Color color_on, Color color_off) {
588 this->image(x, y, image, ImageAlign::TOP_LEFT, color_on, color_off);
589}
590
591void Display::image(int x, int y, BaseImage *image, ImageAlign align, Color color_on, Color color_off) {
592 auto x_align = ImageAlign(int(align) & (int(ImageAlign::HORIZONTAL_ALIGNMENT)));
593 auto y_align = ImageAlign(int(align) & (int(ImageAlign::VERTICAL_ALIGNMENT)));
594
595 switch (x_align) {
597 x -= image->get_width();
598 break;
600 x -= image->get_width() / 2;
601 break;
602 case ImageAlign::LEFT:
603 default:
604 break;
605 }
606
607 switch (y_align) {
609 y -= image->get_height();
610 break;
612 y -= image->get_height() / 2;
613 break;
614 case ImageAlign::TOP:
615 default:
616 break;
617 }
618
619 image->draw(x, y, this, color_on, color_off);
620}
621
622#ifdef USE_GRAPH
623void Display::graph(int x, int y, graph::Graph *graph, Color color_on) { graph->draw(this, x, y, color_on); }
624void Display::legend(int x, int y, graph::Graph *graph, Color color_on) { graph->draw_legend(this, x, y, color_on); }
625#endif // USE_GRAPH
626
627#ifdef USE_QR_CODE
628void Display::qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on, int scale) {
629 qr_code->draw(this, x, y, color_on, scale);
630}
631#endif // USE_QR_CODE
632
633#ifdef USE_GRAPHICAL_DISPLAY_MENU
634void Display::menu(int x, int y, graphical_display_menu::GraphicalDisplayMenu *menu, int width, int height) {
635 Rect rect(x, y, width, height);
636 menu->draw(this, &rect);
637}
638#endif // USE_GRAPHICAL_DISPLAY_MENU
639
640void Display::get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1,
641 int *width, int *height) {
642 int x_offset, baseline;
643 font->measure(text, width, &x_offset, &baseline, height);
644
645 auto x_align = TextAlign(int(align) & 0x18);
646 auto y_align = TextAlign(int(align) & 0x07);
647
648 switch (x_align) {
649 case TextAlign::RIGHT:
650 *x1 = x - *width - x_offset;
651 break;
653 *x1 = x - (*width + x_offset) / 2;
654 break;
655 case TextAlign::LEFT:
656 default:
657 // LEFT
658 *x1 = x;
659 break;
660 }
661
662 switch (y_align) {
664 *y1 = y - *height;
665 break;
667 *y1 = y - baseline;
668 break;
670 *y1 = y - (*height) / 2;
671 break;
672 case TextAlign::TOP:
673 default:
674 *y1 = y;
675 break;
676 }
677}
678
679void Display::print(int x, int y, BaseFont *font, Color color, const char *text, Color background) {
680 this->print(x, y, font, color, TextAlign::TOP_LEFT, text, background);
681}
682
683void Display::print(int x, int y, BaseFont *font, TextAlign align, const char *text) {
684 this->print(x, y, font, COLOR_ON, align, text);
685}
686
687void Display::print(int x, int y, BaseFont *font, const char *text) {
688 this->print(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, text);
689}
690
691void Display::printf(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,
692 ...) {
693 va_list arg;
694 va_start(arg, format);
695 this->vprintf_(x, y, font, color, background, align, format, arg);
696 va_end(arg);
697}
698
699void Display::printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...) {
700 va_list arg;
701 va_start(arg, format);
702 this->vprintf_(x, y, font, color, COLOR_OFF, align, format, arg);
703 va_end(arg);
704}
705
706void Display::printf(int x, int y, BaseFont *font, Color color, const char *format, ...) {
707 va_list arg;
708 va_start(arg, format);
709 this->vprintf_(x, y, font, color, COLOR_OFF, TextAlign::TOP_LEFT, format, arg);
710 va_end(arg);
711}
712
713void Display::printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...) {
714 va_list arg;
715 va_start(arg, format);
716 this->vprintf_(x, y, font, COLOR_ON, COLOR_OFF, align, format, arg);
717 va_end(arg);
718}
719
720void Display::printf(int x, int y, BaseFont *font, const char *format, ...) {
721 va_list arg;
722 va_start(arg, format);
723 this->vprintf_(x, y, font, COLOR_ON, COLOR_OFF, TextAlign::TOP_LEFT, format, arg);
724 va_end(arg);
725}
726
727void Display::set_writer(display_writer_t &&writer) { this->writer_ = writer; }
728
729void Display::set_pages(std::vector<DisplayPage *> pages) {
730 if (pages.empty())
731 return;
732
733 for (auto *page : pages)
734 page->set_parent(this);
735
736 for (uint32_t i = 0; i < pages.size() - 1; i++) {
737 pages[i]->set_next(pages[i + 1]);
738 pages[i + 1]->set_prev(pages[i]);
739 }
740 pages[0]->set_prev(pages[pages.size() - 1]);
741 pages[pages.size() - 1]->set_next(pages[0]);
742 this->show_page(pages[0]);
743}
744
746#ifdef DISPLAY_PAGE_CHANGE_CALLBACK_COUNT
747 DisplayPage *previous = this->page_;
748 this->page_ = page;
749 if (previous != page)
750 this->page_change_callback_.call(previous, page);
751#else
752 this->page_ = page;
753#endif
754}
755
757 if (this->auto_clear_enabled_) {
758 this->clear();
759 }
760 if (this->show_test_card_) {
761 this->test_card();
762 } else if (this->page_ != nullptr) {
763 this->page_->get_writer()(*this);
764 } else if (this->writer_.has_value()) {
765 (*this->writer_)(*this);
766 }
767 this->clear_clipping_();
768}
769
770void Display::strftime(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,
771 ESPTime time) {
772 char buffer[64];
773 size_t ret = time.strftime(buffer, sizeof(buffer), format);
774 if (ret > 0)
775 this->print(x, y, font, color, align, buffer, background);
776}
777
778void Display::strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time) {
779 this->strftime(x, y, font, color, COLOR_OFF, align, format, time);
780}
781
782void Display::strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) {
783 this->strftime(x, y, font, color, COLOR_OFF, TextAlign::TOP_LEFT, format, time);
784}
785
786void Display::strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time) {
787 this->strftime(x, y, font, COLOR_ON, COLOR_OFF, align, format, time);
788}
789
790void Display::strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) {
791 this->strftime(x, y, font, COLOR_ON, COLOR_OFF, TextAlign::TOP_LEFT, format, time);
792}
793
795 if (!this->clipping_rectangle_.empty()) {
796 Rect r = this->clipping_rectangle_.back();
797 rect.shrink(r);
798 }
799 this->clipping_rectangle_.push_back(rect);
800}
801
803 if (this->clipping_rectangle_.empty()) {
804 ESP_LOGE(TAG, "clear: Clipping is not set.");
805 } else {
806 this->clipping_rectangle_.pop_back();
807 }
808}
809
811 if (this->clipping_rectangle_.empty()) {
812 ESP_LOGE(TAG, "add: Clipping is not set.");
813 } else {
814 this->clipping_rectangle_.back().extend(add_rect);
815 }
816}
817
819 if (this->clipping_rectangle_.empty()) {
820 ESP_LOGE(TAG, "add: Clipping is not set.");
821 } else {
822 this->clipping_rectangle_.back().shrink(add_rect);
823 }
824}
825
827 if (this->clipping_rectangle_.empty()) {
828 return Rect();
829 } else {
830 return this->clipping_rectangle_.back();
831 }
832}
833
835
837
838bool Display::clip(int x, int y) {
839 if (x < 0 || x >= this->get_width() || y < 0 || y >= this->get_height())
840 return false;
841 if (this->is_point_clipped(x, y))
842 return false;
843 return true;
844}
845
846bool Display::clamp_x_(int x, int w, int &min_x, int &max_x) {
847 min_x = std::max(x, 0);
848 max_x = std::min(x + w, this->get_width());
849
850 if (!this->clipping_rectangle_.empty()) {
851 const auto &rect = this->clipping_rectangle_.back();
852 if (!rect.is_set())
853 return false;
854
855 min_x = std::max(min_x, (int) rect.x);
856 max_x = std::min(max_x, (int) rect.x2());
857 }
858
859 return min_x < max_x;
860}
861
862bool Display::clamp_y_(int y, int h, int &min_y, int &max_y) {
863 min_y = std::max(y, 0);
864 max_y = std::min(y + h, this->get_height());
865
866 if (!this->clipping_rectangle_.empty()) {
867 const auto &rect = this->clipping_rectangle_.back();
868 if (!rect.is_set())
869 return false;
870
871 min_y = std::max(min_y, (int) rect.y);
872 max_y = std::min(max_y, (int) rect.y2());
873 }
874
875 return min_y < max_y;
876}
877
878constexpr uint8_t TESTCARD_FONT[3][8] PROGMEM = {{0x41, 0x7F, 0x7F, 0x09, 0x19, 0x7F, 0x66, 0x00}, // 'R'
879 {0x1C, 0x3E, 0x63, 0x41, 0x51, 0x73, 0x72, 0x00}, // 'G'
880 {0x41, 0x7F, 0x7F, 0x49, 0x49, 0x7F, 0x36, 0x00}}; // 'B'
881
883 int w = get_width(), h = get_height(), image_w, image_h;
884 this->clear();
885 image_w = std::min(w - 20, 310);
886 image_h = std::min(h - 20, 255);
887 int shift_x = (w - image_w) / 2;
888 int shift_y = (h - image_h) / 2;
889 int line_w = (image_w - 6) / 6;
890 int image_c = image_w / 2;
891 if (this->get_display_type() == DISPLAY_TYPE_COLOR) {
892 Color r(255, 0, 0), g(0, 255, 0), b(0, 0, 255);
893
894 for (auto i = 0; i != image_h; i++) {
895 int c = esp_scale(i, image_h);
896 this->horizontal_line(shift_x + 0, shift_y + i, line_w, r.fade_to_white(c));
897 this->horizontal_line(shift_x + line_w, shift_y + i, line_w, r.fade_to_black(c)); //
898
899 this->horizontal_line(shift_x + image_c - line_w, shift_y + i, line_w, g.fade_to_white(c));
900 this->horizontal_line(shift_x + image_c, shift_y + i, line_w, g.fade_to_black(c));
901
902 this->horizontal_line(shift_x + image_w - (line_w * 2), shift_y + i, line_w, b.fade_to_white(c));
903 this->horizontal_line(shift_x + image_w - line_w, shift_y + i, line_w, b.fade_to_black(c));
904 }
905 }
906 this->rectangle(shift_x, shift_y, image_w, image_h, Color(127, 127, 0));
907
908 uint16_t shift_r = shift_x + line_w - (8 * 3);
909 uint16_t shift_g = shift_x + image_c - (8 * 3);
910 uint16_t shift_b = shift_x + image_w - line_w - (8 * 3);
911 shift_y = h / 2 - (8 * 3);
912 for (auto i = 0; i < 8; i++) {
913 uint8_t ftr = progmem_read_byte(&TESTCARD_FONT[0][i]);
914 uint8_t ftg = progmem_read_byte(&TESTCARD_FONT[1][i]);
915 uint8_t ftb = progmem_read_byte(&TESTCARD_FONT[2][i]);
916 for (auto k = 0; k < 8; k++) {
917 if ((ftr & (1 << k)) != 0) {
918 this->filled_rectangle(shift_r + (i * 6), shift_y + (k * 6), 6, 6, COLOR_OFF);
919 }
920 if ((ftg & (1 << k)) != 0) {
921 this->filled_rectangle(shift_g + (i * 6), shift_y + (k * 6), 6, 6, COLOR_OFF);
922 }
923 if ((ftb & (1 << k)) != 0) {
924 this->filled_rectangle(shift_b + (i * 6), shift_y + (k * 6), 6, 6, COLOR_OFF);
925 }
926 }
927 }
928 this->filled_rectangle(0, 0, 10, 10, Color(255, 0, 255));
929 this->filled_rectangle(w - 10, 0, 10, 10, Color(255, 0, 255));
930 this->filled_rectangle(0, h - 10, 10, 10, Color(255, 0, 255));
931 this->filled_rectangle(w - 10, h - 10, 10, 10, Color(255, 0, 255));
932 this->rectangle(0, 0, w, h, Color(255, 255, 255));
933 this->stop_poller();
934}
935
936DisplayPage::DisplayPage(display_writer_t writer) : writer_(std::move(writer)) {}
937
938void DisplayPage::show() { this->parent_->show_page(this); }
939
941 if (this->next_ == nullptr) {
942 ESP_LOGE(TAG, "no next page");
943 return;
944 }
945 this->next_->show();
946}
947
949 if (this->prev_ == nullptr) {
950 ESP_LOGE(TAG, "no previous page");
951 return;
952 }
953 this->prev_->show();
954}
955
956const display_writer_t &DisplayPage::get_writer() const { return this->writer_; }
957
958const LogString *text_align_to_string(TextAlign textalign) {
959 switch (textalign) {
961 return LOG_STR("TOP_LEFT");
963 return LOG_STR("TOP_CENTER");
965 return LOG_STR("TOP_RIGHT");
967 return LOG_STR("CENTER_LEFT");
969 return LOG_STR("CENTER");
971 return LOG_STR("CENTER_RIGHT");
973 return LOG_STR("BASELINE_LEFT");
975 return LOG_STR("BASELINE_CENTER");
977 return LOG_STR("BASELINE_RIGHT");
979 return LOG_STR("BOTTOM_LEFT");
981 return LOG_STR("BOTTOM_CENTER");
983 return LOG_STR("BOTTOM_RIGHT");
984 default:
985 return LOG_STR("UNKNOWN");
986 }
987}
988} // namespace esphome::display
void feed_wdt()
Feed the task watchdog.
virtual void measure(const char *str, int *width, int *x_offset, int *baseline, int *height)=0
virtual void print(int x, int y, Display *display, Color color, const char *text, Color background)=0
virtual int get_height() const =0
virtual int get_width() const =0
virtual void draw(int x, int y, Display *display, Color color_on, Color color_off)=0
static Color to_color(uint32_t colorcode, ColorBitness color_bitness=ColorBitness::COLOR_BITNESS_888, bool right_bit_aligned=true)
Unpacks a color of the given bitness, red in the most significant bits.
static ESPHOME_ALWAYS_INLINE uint32_t read_packed(const uint8_t *ptr, size_t index, bool big_endian)
Reads one packed pixel of the given bitness from a source buffer into the value to_color() takes.
void show_page(DisplayPage *page)
Definition display.cpp:745
virtual bool pixel_axes_swapped() const
True when draw_pixel_at() swaps x and y before writing, so pixels that are neighbours along x land a ...
Definition display.h:757
StaticCallbackManager< DISPLAY_PAGE_CHANGE_CALLBACK_COUNT, void(DisplayPage *, DisplayPage *)> page_change_callback_
Definition display.h:867
bool clip(int x, int y)
Check if pixel is within region of display.
Definition display.cpp:838
void get_regular_polygon_vertex(int vertex_id, int *vertex_x, int *vertex_y, int center_x, int center_y, int radius, int edges, RegularPolygonVariation variation=VARIATION_POINTY_TOP, float rotation_degrees=ROTATION_0_DEGREES)
Get the specified vertex (x,y) coordinates for the regular polygon inscribed in the circle centered o...
Definition display.cpp:504
display_writer_t writer_
Definition display.h:864
int int int const uint8_t ColorOrder ColorBitness bitness
Definition display.h:392
virtual void clear()
Clear the entire screen by filling it with OFF pixels.
Definition display.cpp:17
void end_clipping()
Reset the invalidation region.
Definition display.cpp:802
void start_clipping(Rect rect)
Set the clipping rectangle for further drawing.
Definition display.cpp:794
void set_pages(std::vector< DisplayPage * > pages)
Definition display.cpp:729
void vprintf_(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format, va_list arg)
Definition display.cpp:579
virtual int get_height()
Get the calculated height of the display in pixels with rotation applied.
Definition display.h:338
int int int const uint8_t ColorOrder ColorBitness bool int int y_offset
Definition display.h:392
virtual void fill(Color color)
Fill the entire screen with the given color.
Definition display.cpp:16
int int int const uint8_t ColorOrder ColorBitness bool int int int x_pad
Definition display.h:392
void horizontal_line(int x, int y, int width, Color color=COLOR_ON)
Draw a horizontal line from the point [x,y] to [x+width,y] with the given color.
Definition display.cpp:154
void sort_triangle_points_by_y_(int *x1, int *y1, int *x2, int *y2, int *x3, int *y3)
Definition display.cpp:385
int int int const uint8_t * ptr
Definition display.h:391
int int int const uint8_t ColorOrder order
Definition display.h:391
virtual int get_width()
Get the calculated width of the display in pixels with rotation applied.
Definition display.h:336
void circle(int center_x, int center_xy, int radius, Color color=COLOR_ON)
Draw the outline of a circle centered around [center_x,center_y] with the radius radius with the give...
Definition display.cpp:180
void filled_triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color=COLOR_ON)
Fill a triangle contained between the points [x1,y1], [x2,y2] and [x3,y3] with the given color.
Definition display.cpp:486
void print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text, Color background=COLOR_OFF)
Print text with the anchor point at [x,y] with font.
Definition display.cpp:572
virtual void set_rotation(DisplayRotation rotation)
Internal method to set the display rotation with.
Definition display.cpp:18
void filled_regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation=VARIATION_POINTY_TOP, float rotation_degrees=ROTATION_0_DEGREES, Color color=COLOR_ON)
Fill a regular polygon inscribed in the circle centered on [x,y] with the given radius and color.
Definition display.cpp:558
void qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on=COLOR_ON, int scale=1)
Draw the qr_code with the top-left corner at [x,y] to the screen.
Definition display.cpp:628
bool clamp_x_(int x, int w, int &min_x, int &max_x)
Definition display.cpp:846
bool ESPHOME_ALWAYS_INLINE is_point_clipped(int x, int y) const
Whether (x, y) falls outside the active clipping rectangle.
Definition display.h:810
void line(int x1, int y1, int x2, int y2, Color color=COLOR_ON)
Draw a straight line from the point [x1,y1] to [x2,y2] with the given color.
Definition display.cpp:20
bool clamp_y_(int y, int h, int &min_y, int &max_y)
Definition display.cpp:862
void filled_gauge(int center_x, int center_y, int radius1, int radius2, int progress, Color color=COLOR_ON)
Fill a half-ring "gauge" centered around [center_x,center_y] between two circles with the radius1 and...
Definition display.cpp:288
virtual DisplayType get_display_type()=0
Get the type of display that the buffer corresponds to.
void void void void void void void void void void void image(int x, int y, BaseImage *image, Color color_on=COLOR_ON, Color color_off=COLOR_OFF)
Draw the image with the top-left corner at [x,y] to the screen.
Definition display.cpp:587
void legend(int x, int y, graph::Graph *graph, Color color_on=COLOR_ON)
Draw the legend for graph with the top-left corner at [x,y] to the screen.
Definition display.cpp:624
void rectangle(int x1, int y1, int width, int height, Color color=COLOR_ON)
Draw the outline of a rectangle with the top left point at [x1,y1] and the bottom right point at [x1+...
Definition display.cpp:166
void filled_circle(int center_x, int center_y, int radius, Color color=COLOR_ON)
Fill a circle centered around [center_x,center_y] with the radius radius with the given color.
Definition display.cpp:204
void void void void void void strftime(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format, ESPTime time) __attribute__((format(strftime
Evaluate the strftime-format format and print the result with the anchor point at [x,...
Definition display.cpp:770
void triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color=COLOR_ON)
Draw the outline of a triangle contained between the points [x1,y1], [x2,y2] and [x3,...
Definition display.cpp:379
void printf(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,...) __attribute__((format(printf
Evaluate the printf-format format and print the result with the anchor point at [x,...
Definition display.cpp:691
DisplayPage * page_
Definition display.h:865
void set_writer(display_writer_t &&writer)
Internal method to set the display writer lambda.
Definition display.cpp:727
void draw_pixel_at(int x, int y)
Set a single pixel at the specified coordinates to default color.
Definition display.h:346
void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad)
Given an array of pixels encoded in the nominated format, draw these into the display's buffer.
Definition display.h:370
void vertical_line(int x, int y, int height, Color color=COLOR_ON)
Draw a vertical line from the point [x,y] to [x,y+width] with the given color.
Definition display.cpp:160
int int int const uint8_t ColorOrder ColorBitness bool big_endian
Definition display.h:392
void graph(int x, int y, graph::Graph *graph, Color color_on=COLOR_ON)
Draw the graph with the top-left corner at [x,y] to the screen.
Definition display.cpp:623
Rect get_clipping() const
Get the current the clipping rectangle.
Definition display.cpp:826
void filled_ring(int center_x, int center_y, int radius1, int radius2, Color color=COLOR_ON)
Fill a ring centered around [center_x,center_y] between two circles with the radius1 and radius2 with...
Definition display.cpp:231
void extend_clipping(Rect rect)
Add a rectangular region to the invalidation region.
Definition display.cpp:810
int int int const uint8_t ColorOrder ColorBitness bool int x_offset
Definition display.h:392
void menu(int x, int y, graphical_display_menu::GraphicalDisplayMenu *menu, int width, int height)
Definition display.cpp:634
void line_at_angle(int x, int y, int angle, int length, Color color=COLOR_ON)
Draw a straight line at the given angle based on the origin [x, y] for a specified length with the gi...
Definition display.cpp:41
void get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1, int *width, int *height)
Get the text bounds of the given string.
Definition display.cpp:640
DisplayRotation rotation_
Definition display.h:863
void regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation=VARIATION_POINTY_TOP, float rotation_degrees=ROTATION_0_DEGREES, Color color=COLOR_ON, RegularPolygonDrawing drawing=DRAWING_OUTLINE)
Draw the outline of a regular polygon inscribed in the circle centered on [x,y] with the given radius...
Definition display.cpp:527
void filled_flat_side_triangle_(int x1, int y1, int x2, int y2, int x3, int y3, Color color)
This method fills a triangle using only integer variables by using a modified bresenham algorithm.
Definition display.cpp:403
virtual void draw_pixels_internal(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad)
Draws a block for draw_pixels_at(); the parameters are the same.
Definition display.cpp:119
void shrink_clipping(Rect rect)
substract a rectangular region to the invalidation region
Definition display.cpp:818
void filled_rectangle(int x1, int y1, int width, int height, Color color=COLOR_ON)
Fill a rectangle with the top left point at [x1,y1] and the bottom right point at [x1+width,...
Definition display.cpp:173
std::vector< Rect > clipping_rectangle_
Definition display.h:870
display_writer_t writer_
Definition display.h:888
const display_writer_t & get_writer() const
Definition display.cpp:956
DisplayPage(display_writer_t writer)
Definition display.cpp:936
void shrink(Rect rect)
Definition rect.cpp:41
void draw(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color)
Definition graph.cpp:56
void draw_legend(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color)
Definition graph.cpp:337
void draw(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color, int scale)
Definition qr_code.cpp:46
struct @66::@67 __attribute__
Wake the main loop task from an ISR. ISR-safe.
Definition main_task.h:45
uint32_t buffer
Definition gif.cpp:50
int ret
const char * format
constexpr uint8_t TESTCARD_FONT[3][8] PROGMEM
Definition display.cpp:878
constexpr Color COLOR_ON(255, 255, 255, 255)
Turn the pixel ON.
constexpr Color COLOR_OFF(0, 0, 0, 0)
Turn the pixel OFF.
static void int int int int const uint8_t ColorOrder ColorBitness bool big_endian
Definition display.cpp:101
static void int int int int const uint8_t ColorOrder ColorBitness bitness
Definition display.cpp:100
static void int x_start
Definition display.cpp:62
const LogString * text_align_to_string(TextAlign textalign)
Definition display.cpp:958
ImageAlign
ImageAlign is used to tell the display class how to position a image.
Definition display.h:104
static void int int int int const uint8_t int x_offset
Definition display.cpp:63
const auto draw_source_pixel
Definition display.cpp:67
static void int int y_start
Definition display.cpp:62
static void int int int int const uint8_t ColorOrder order
Definition display.cpp:100
const float ROTATION_270_DEGREES
Definition display.h:169
static void int int int int const uint8_t int int y_offset
Definition display.cpp:63
static void int int int w
Definition display.cpp:62
ESPHOME_LOG_TAG(TAG, "display")
TextAlign
TextAlign is used to tell the display class how to position a piece of text.
Definition display.h:54
Color apply_color_order(Color color, ColorOrder order)
static void int int int int h
Definition display.cpp:62
static void int int int int const uint8_t * ptr
Definition display.cpp:63
static void int int int int const uint8_t int int int x_pad
Definition display.cpp:63
const float ROTATION_0_DEGREES
Definition display.h:165
va_end(args)
size_t size_t const char va_start(args, fmt)
Application App
Global storage of Application pointer - only one Application can exist.
uint8_t progmem_read_byte(const uint8_t *addr)
Definition hal.h:51
STL namespace.
static void uint32_t
A more user-friendly version of struct tm from time.h.
Definition time.h:23
size_t strftime(char *buffer, size_t buffer_len, const char *format)
Convert this ESPTime struct to a null-terminated c string buffer as specified by the format argument.
Definition time.cpp:20
std::string print()
uint16_t length
Definition tt21100.cpp:0
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6