ESPHome 2026.10.2
Loading...
Searching...
No Matches
display.h
Go to the documentation of this file.
1#pragma once
2
3#include <cstdarg>
4#include <vector>
5
6#include "rect.h"
7
10#include "esphome/core/time.h"
11#include "esphome/core/log.h"
12#include "display_color_utils.h"
13
14#ifdef USE_GRAPH
16#endif
17
18#ifdef USE_QR_CODE
20#endif
21
22#ifdef USE_GRAPHICAL_DISPLAY_MENU
24#endif
25
26namespace esphome::display {
27
78
126
132
139
140const int EDGES_TRIGON = 3;
141const int EDGES_TRIANGLE = 3;
142const int EDGES_TETRAGON = 4;
144const int EDGES_PENTAGON = 5;
145const int EDGES_HEXAGON = 6;
146const int EDGES_HEPTAGON = 7;
147const int EDGES_OCTAGON = 8;
148const int EDGES_NONAGON = 9;
149const int EDGES_ENNEAGON = 9;
150const int EDGES_DECAGON = 10;
151const int EDGES_HENDECAGON = 11;
152const int EDGES_DODECAGON = 12;
153const int EDGES_TRIDECAGON = 13;
154const int EDGES_TETRADECAGON = 14;
155const int EDGES_PENTADECAGON = 15;
156const int EDGES_HEXADECAGON = 16;
157
158const float ROTATION_0_DEGREES = 0.0;
159const float ROTATION_45_DEGREES = 45.0;
160const float ROTATION_90_DEGREES = 90.0;
161const float ROTATION_180_DEGREES = 180.0;
162const float ROTATION_270_DEGREES = 270.0;
163
168
173
174class Display;
175class DisplayPage;
176class DisplayOnPageChangeTrigger;
177
189template<typename T> class DisplayWriter {
190 public:
192
193 // For stateless lambdas (convertible to function pointer): use function pointer (4 bytes)
194 template<typename F>
195 DisplayWriter(F f) requires std::invocable<F, T &> && std::convertible_to<F, void (*)(T &)>
197 this->stateless_f_ = f; // Implicit conversion to function pointer
198 }
199
200 // For stateful lambdas and std::function (not convertible to function pointer): use std::function* (heap allocated)
201 // This handles backwards compatibility with external components
202 template<typename F>
203 DisplayWriter(F f) requires std::invocable<F, T &> &&(!std::convertible_to<F, void (*)(T &)>) : type_(LAMBDA) {
204 this->f_ = new std::function<void(T &)>(std::move(f));
205 }
206
207 // Copy constructor
208 DisplayWriter(const DisplayWriter &other) : type_(other.type_) {
209 if (type_ == LAMBDA) {
210 this->f_ = new std::function<void(T &)>(*other.f_);
211 } else if (type_ == STATELESS_LAMBDA) {
212 this->stateless_f_ = other.stateless_f_;
213 }
214 }
215
216 // Move constructor
217 DisplayWriter(DisplayWriter &&other) noexcept : type_(other.type_) {
218 if (type_ == LAMBDA) {
219 this->f_ = other.f_;
220 other.f_ = nullptr;
221 } else if (type_ == STATELESS_LAMBDA) {
222 this->stateless_f_ = other.stateless_f_;
223 }
224 other.type_ = NONE;
225 }
226
227 // Assignment operators
229 if (this != &other) {
230 this->~DisplayWriter();
231 new (this) DisplayWriter(other);
232 }
233 return *this;
234 }
235
237 if (this != &other) {
238 this->~DisplayWriter();
239 new (this) DisplayWriter(std::move(other));
240 }
241 return *this;
242 }
243
245 if (type_ == LAMBDA) {
246 delete this->f_;
247 }
248 // STATELESS_LAMBDA/NONE: no cleanup needed (function pointer or empty)
249 }
250
251 bool has_value() const { return this->type_ != NONE; }
252
253 void call(T &display) const {
254 switch (this->type_) {
255 case STATELESS_LAMBDA:
256 this->stateless_f_(display); // Direct function pointer call
257 break;
258 case LAMBDA:
259 (*this->f_)(display); // std::function call
260 break;
261 case NONE:
262 default:
263 break;
264 }
265 }
266
267 // Operator() for convenience
268 void operator()(T &display) const { this->call(display); }
269
270 // Operator* for backwards compatibility with (*writer_)(*this) pattern
271 DisplayWriter &operator*() { return *this; }
272 const DisplayWriter &operator*() const { return *this; }
273
274 protected:
275 enum : uint8_t {
279 } type_;
280
281 union {
282 std::function<void(T &)> *f_;
283 void (*stateless_f_)(T &);
284 };
285};
286
287// Type alias for Display writer - uses optimized DisplayWriter instead of std::function
289
290// Callers usually pass `this`; checking a copy keeps GCC's -Wnonnull-compare quiet.
291#define LOG_DISPLAY(prefix, type, obj) \
292 if (auto *log_display_obj = (obj); log_display_obj != nullptr) { \
293 ESP_LOGCONFIG(TAG, \
294 prefix type "\n" \
295 "%s Rotations: %d °\n" \
296 "%s Dimensions: %dpx x %dpx", \
297 prefix, log_display_obj->rotation_, prefix, log_display_obj->get_width(), \
298 log_display_obj->get_height()); \
299 }
300
302inline constexpr Color COLOR_OFF(0, 0, 0, 0);
304inline constexpr Color COLOR_ON(255, 255, 255, 255);
305
307 public:
308 virtual void draw(int x, int y, Display *display, Color color_on, Color color_off) = 0;
309 virtual int get_width() const = 0;
310 virtual int get_height() const = 0;
311};
312
313class BaseFont {
314 public:
315 virtual void print(int x, int y, Display *display, Color color, const char *text, Color background) = 0;
316 virtual void measure(const char *str, int *width, int *x_offset, int *baseline, int *height) = 0;
317};
318
319class Display : public PollingComponent {
320 public:
322 virtual void fill(Color color);
324 virtual void clear();
325
327 virtual int get_width() { return this->get_width_internal(); }
329 virtual int get_height() { return this->get_height_internal(); }
330
332 int get_native_width() { return this->get_width_internal(); }
334 int get_native_height() { return this->get_height_internal(); }
335
337 inline void draw_pixel_at(int x, int y) { this->draw_pixel_at(x, y, COLOR_ON); }
338
340 virtual void draw_pixel_at(int x, int y, Color color) = 0;
341
361 virtual void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
362 ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad);
363
365 void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
366 ColorBitness bitness, bool big_endian) {
367 this->draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, 0, 0, 0);
368 }
369
371 void line(int x1, int y1, int x2, int y2, Color color = COLOR_ON);
372
374 void line_at_angle(int x, int y, int angle, int length, Color color = COLOR_ON);
375
378 void line_at_angle(int x, int y, int angle, int start_radius, int stop_radius, Color color = COLOR_ON);
379
381 void horizontal_line(int x, int y, int width, Color color = COLOR_ON);
382
384 void vertical_line(int x, int y, int height, Color color = COLOR_ON);
385
388 void rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON);
389
391 void filled_rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON);
392
394 void circle(int center_x, int center_xy, int radius, Color color = COLOR_ON);
395
397 void filled_circle(int center_x, int center_y, int radius, Color color = COLOR_ON);
398
401 void filled_ring(int center_x, int center_y, int radius1, int radius2, Color color = COLOR_ON);
404 void filled_gauge(int center_x, int center_y, int radius1, int radius2, int progress, Color color = COLOR_ON);
405
407 void triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color = COLOR_ON);
408
410 void filled_triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color = COLOR_ON);
411
420 void get_regular_polygon_vertex(int vertex_id, int *vertex_x, int *vertex_y, int center_x, int center_y, int radius,
421 int edges, RegularPolygonVariation variation = VARIATION_POINTY_TOP,
422 float rotation_degrees = ROTATION_0_DEGREES);
423
430 void regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation = VARIATION_POINTY_TOP,
431 float rotation_degrees = ROTATION_0_DEGREES, Color color = COLOR_ON,
432 RegularPolygonDrawing drawing = DRAWING_OUTLINE);
433 void regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation, Color color,
434 RegularPolygonDrawing drawing = DRAWING_OUTLINE);
435 void regular_polygon(int x, int y, int radius, int edges, Color color,
436 RegularPolygonDrawing drawing = DRAWING_OUTLINE);
437
442 void filled_regular_polygon(int x, int y, int radius, int edges,
443 RegularPolygonVariation variation = VARIATION_POINTY_TOP,
444 float rotation_degrees = ROTATION_0_DEGREES, Color color = COLOR_ON);
445 void filled_regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation, Color color);
446 void filled_regular_polygon(int x, int y, int radius, int edges, Color color);
447
458 void print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text,
459 Color background = COLOR_OFF);
460
470 void print(int x, int y, BaseFont *font, Color color, const char *text, Color background = COLOR_OFF);
471
480 void print(int x, int y, BaseFont *font, TextAlign align, const char *text);
481
489 void print(int x, int y, BaseFont *font, const char *text);
490
502 void printf(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format, ...)
503 __attribute__((format(printf, 8, 9)));
504
515 void printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...)
516 __attribute__((format(printf, 7, 8)));
517
527 void printf(int x, int y, BaseFont *font, Color color, const char *format, ...) __attribute__((format(printf, 6, 7)));
528
538 void printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...)
539 __attribute__((format(printf, 6, 7)));
540
549 void printf(int x, int y, BaseFont *font, const char *format, ...) __attribute__((format(printf, 5, 6)));
550
562 void strftime(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,
563 ESPTime time) __attribute__((format(strftime, 8, 0)));
564
575 void strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time)
576 __attribute__((format(strftime, 7, 0)));
577
587 void strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time)
588 __attribute__((format(strftime, 6, 0)));
589
599 void strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time)
600 __attribute__((format(strftime, 6, 0)));
601
610 void strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) __attribute__((format(strftime, 5, 0)));
611
620 void image(int x, int y, BaseImage *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
621
631 void image(int x, int y, BaseImage *image, ImageAlign align, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
632
633#ifdef USE_GRAPH
641 void graph(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
642
654 void legend(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
655#endif // USE_GRAPH
656
657#ifdef USE_QR_CODE
665 void qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on = COLOR_ON, int scale = 1);
666#endif
667
668#ifdef USE_GRAPHICAL_DISPLAY_MENU
676 void menu(int x, int y, graphical_display_menu::GraphicalDisplayMenu *menu, int width, int height);
677#endif // USE_GRAPHICAL_DISPLAY_MENU
678
691 void get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1, int *width,
692 int *height);
693
695 void set_writer(display_writer_t &&writer);
696
697 void show_page(DisplayPage *page);
698 void show_next_page();
699 void show_prev_page();
700
701 void set_pages(std::vector<DisplayPage *> pages);
702
703 const DisplayPage *get_active_page() const { return this->page_; }
704
705 void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t) { this->on_page_change_triggers_.push_back(t); }
706
708 virtual void set_rotation(DisplayRotation rotation);
709
710 // Internal method to set display auto clearing.
711 void set_auto_clear(bool auto_clear_enabled) { this->auto_clear_enabled_ = auto_clear_enabled; }
712
713 DisplayRotation get_rotation() const { return this->rotation_; }
714
719
726 void start_clipping(Rect rect);
727 void start_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
728 start_clipping(Rect(left, top, right - left, bottom - top));
729 };
730
736 void extend_clipping(Rect rect);
737 void extend_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
738 this->extend_clipping(Rect(left, top, right - left, bottom - top));
739 };
740
746 void shrink_clipping(Rect rect);
747 void shrink_clipping(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) {
748 this->shrink_clipping(Rect(left, top, right - left, bottom - top));
749 };
750
753 void end_clipping();
754
759 Rect get_clipping() const;
760
761 bool is_clipping() const { return !this->clipping_rectangle_.empty(); }
762
766 bool ESPHOME_ALWAYS_INLINE is_point_clipped(int x, int y) const {
767 return this->is_clipping() && !this->clipping_rectangle_.back().inside(x, y);
768 }
769
772 bool clip(int x, int y);
773
774 void test_card();
775 void show_test_card() { this->show_test_card_ = true; }
776
777 protected:
778 bool clamp_x_(int x, int w, int &min_x, int &max_x);
779 bool clamp_y_(int y, int h, int &min_y, int &max_y);
780 void vprintf_(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,
781 va_list arg);
782
783 void do_update_();
784 void clear_clipping_();
785
791 void ESPHOME_ALWAYS_INLINE feed_wdt_per_pixel_() {
792 if (++this->wdt_pixel_counter_ == 0)
793 this->feed_wdt_pixel_slow_();
794 }
795 void feed_wdt_pixel_slow_();
796
797 virtual int get_height_internal() = 0;
798 virtual int get_width_internal() = 0;
799
806 void filled_flat_side_triangle_(int x1, int y1, int x2, int y2, int x3, int y3, Color color);
807 void sort_triangle_points_by_y_(int *x1, int *y1, int *x2, int *y2, int *x3, int *y3);
808
811 DisplayPage *page_{nullptr};
812 DisplayPage *previous_page_{nullptr};
813 std::vector<DisplayOnPageChangeTrigger *> on_page_change_triggers_;
814 bool auto_clear_enabled_{true};
815 std::vector<Rect> clipping_rectangle_;
816 uint8_t wdt_pixel_counter_{0};
817 bool show_test_card_{false};
818};
819
820class DisplayPage final {
821 public:
823 void show();
824 void show_next();
825 void show_prev();
826 void set_parent(Display *parent) { this->parent_ = parent; }
827 void set_prev(DisplayPage *prev) { this->prev_ = prev; }
828 void set_next(DisplayPage *next) { this->next_ = next; }
829 const display_writer_t &get_writer() const;
830
831 protected:
834 DisplayPage *prev_{nullptr};
835 DisplayPage *next_{nullptr};
836};
837
838inline void Display::show_next_page() { this->page_->show_next(); }
839inline void Display::show_prev_page() { this->page_->show_prev(); }
840
841template<typename... Ts> class DisplayPageShowAction final : public Action<Ts...> {
842 public:
844
845 void play(const Ts &...x) override {
846 auto *page = this->page_.value(x...);
847 if (page != nullptr) {
848 page->show();
849 }
850 }
851};
852
853class DisplayOnPageChangeTrigger final : public Trigger<DisplayPage *, DisplayPage *> {
854 public:
856 void process(DisplayPage *from, DisplayPage *to);
857 void set_from(DisplayPage *p) { this->from_ = p; }
858 void set_to(DisplayPage *p) { this->to_ = p; }
859
860 protected:
861 DisplayPage *from_{nullptr};
862 DisplayPage *to_{nullptr};
863};
864
865const LogString *text_align_to_string(TextAlign textalign);
866
867} // namespace esphome::display
uint8_t h
Definition bl0906.h:2
This class simplifies creating components that periodically check a state.
Definition component.h:510
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
void shrink_clipping(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
Definition display.h:747
void ESPHOME_ALWAYS_INLINE feed_wdt_per_pixel_()
Watchdog feed for per pixel loops.
Definition display.h:791
bool is_clipping() const
Definition display.h:761
const DisplayPage * get_active_page() const
Definition display.h:703
int get_native_width()
Get the native (original) width of the display in pixels.
Definition display.h:332
virtual int get_height()
Get the calculated height of the display in pixels with rotation applied.
Definition display.h:329
void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t)
Definition display.h:705
virtual int get_width()
Get the calculated width of the display in pixels with rotation applied.
Definition display.h:327
virtual void draw_pixel_at(int x, int y, Color color)=0
Set a single pixel at the specified coordinates to the given color.
void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order, ColorBitness bitness, bool big_endian)
Convenience overload for base case where the pixels are packed into the buffer with no gaps (e....
Definition display.h:365
bool ESPHOME_ALWAYS_INLINE is_point_clipped(int x, int y) const
Whether (x, y) falls outside the active clipping rectangle.
Definition display.h:766
virtual DisplayType get_display_type()=0
Get the type of display that the buffer corresponds to.
void start_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom)
Definition display.h:727
DisplayRotation get_rotation() const
Definition display.h:713
virtual int get_width_internal()=0
void draw_pixel_at(int x, int y)
Set a single pixel at the specified coordinates to default color.
Definition display.h:337
int get_native_height()
Get the native (original) height of the display in pixels.
Definition display.h:334
virtual int get_height_internal()=0
void set_auto_clear(bool auto_clear_enabled)
Definition display.h:711
std::vector< DisplayOnPageChangeTrigger * > on_page_change_triggers_
Definition display.h:813
void extend_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom)
Definition display.h:737
std::vector< Rect > clipping_rectangle_
Definition display.h:815
display_writer_t writer_
Definition display.h:833
void set_next(DisplayPage *next)
Definition display.h:828
void set_parent(Display *parent)
Definition display.h:826
void set_prev(DisplayPage *prev)
Definition display.h:827
TEMPLATABLE_VALUE(DisplayPage *, page) void play(const Ts &...x) override
Definition display.h:843
Optimized display writer that uses function pointers for stateless lambdas.
Definition display.h:189
DisplayWriter(DisplayWriter &&other) noexcept
Definition display.h:217
std::function< void(T &)> * f_
Definition display.h:282
DisplayWriter & operator=(DisplayWriter &&other) noexcept
Definition display.h:236
void operator()(T &display) const
Definition display.h:268
enum esphome::display::DisplayWriter::@74 type_
DisplayWriter & operator=(const DisplayWriter &other)
Definition display.h:228
DisplayWriter(const DisplayWriter &other)
Definition display.h:208
const DisplayWriter & operator*() const
Definition display.h:272
DisplayWriter & operator*()
Definition display.h:271
void call(T &display) const
Definition display.h:253
const char * format
@ DISPLAY_ROTATION_0_DEGREES
Definition display.h:134
@ DISPLAY_ROTATION_270_DEGREES
Definition display.h:137
@ DISPLAY_ROTATION_180_DEGREES
Definition display.h:136
@ DISPLAY_ROTATION_90_DEGREES
Definition display.h:135
constexpr Color COLOR_ON(255, 255, 255, 255)
Turn the pixel ON.
constexpr Color COLOR_OFF(0, 0, 0, 0)
Turn the pixel OFF.
const int EDGES_TRIGON
Definition display.h:140
const int EDGES_PENTADECAGON
Definition display.h:155
const int EDGES_OCTAGON
Definition display.h:147
const int EDGES_HEXADECAGON
Definition display.h:156
const int EDGES_DODECAGON
Definition display.h:152
const int EDGES_PENTAGON
Definition display.h:144
const float ROTATION_45_DEGREES
Definition display.h:159
const int EDGES_TRIANGLE
Definition display.h:141
ImageAlign
ImageAlign is used to tell the display class how to position a image.
Definition display.h:102
const int EDGES_QUADRILATERAL
Definition display.h:143
const int EDGES_DECAGON
Definition display.h:150
const int EDGES_TETRADECAGON
Definition display.h:154
const float ROTATION_270_DEGREES
Definition display.h:162
const float ROTATION_180_DEGREES
Definition display.h:161
const int EDGES_HEPTAGON
Definition display.h:146
const int EDGES_HENDECAGON
Definition display.h:151
const int EDGES_TRIDECAGON
Definition display.h:153
TextAlign
TextAlign is used to tell the display class how to position a piece of text.
Definition display.h:52
const int EDGES_NONAGON
Definition display.h:148
const float ROTATION_90_DEGREES
Definition display.h:160
const int EDGES_ENNEAGON
Definition display.h:149
const int EDGES_TETRAGON
Definition display.h:142
const int EDGES_HEXAGON
Definition display.h:145
const float ROTATION_0_DEGREES
Definition display.h:158
A more user-friendly version of struct tm from time.h.
Definition time.h:23
std::string print()
uint16_t length
Definition tt21100.cpp:0
uint16_t x
Definition tt21100.cpp:5
uint16_t y
Definition tt21100.cpp:6