ESPHome  2024.5.5
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 
8 #include "esphome/core/color.h"
10 #include "esphome/core/time.h"
11 #include "display_color_utils.h"
12 
13 #ifdef USE_GRAPH
15 #endif
16 
17 #ifdef USE_QR_CODE
19 #endif
20 
21 #ifdef USE_GRAPHICAL_DISPLAY_MENU
23 #endif
24 
25 namespace esphome {
26 namespace display {
27 
52 enum class TextAlign {
53  TOP = 0x00,
54  CENTER_VERTICAL = 0x01,
55  BASELINE = 0x02,
56  BOTTOM = 0x04,
57 
58  LEFT = 0x00,
59  CENTER_HORIZONTAL = 0x08,
60  RIGHT = 0x10,
61 
62  TOP_LEFT = TOP | LEFT,
64  TOP_RIGHT = TOP | RIGHT,
65 
69 
73 
77 };
78 
102 enum class ImageAlign {
103  TOP = 0x00,
104  CENTER_VERTICAL = 0x01,
105  BOTTOM = 0x02,
106 
107  LEFT = 0x00,
108  CENTER_HORIZONTAL = 0x04,
109  RIGHT = 0x08,
110 
111  TOP_LEFT = TOP | LEFT,
113  TOP_RIGHT = TOP | RIGHT,
114 
118 
119  BOTTOM_LEFT = BOTTOM | LEFT,
122 
125 };
126 
131 };
132 
138 };
139 
140 #define PI 3.1415926535897932384626433832795
141 
142 const int EDGES_TRIGON = 3;
143 const int EDGES_TRIANGLE = 3;
144 const int EDGES_TETRAGON = 4;
145 const int EDGES_QUADRILATERAL = 4;
146 const int EDGES_PENTAGON = 5;
147 const int EDGES_HEXAGON = 6;
148 const int EDGES_HEPTAGON = 7;
149 const int EDGES_OCTAGON = 8;
150 const int EDGES_NONAGON = 9;
151 const int EDGES_ENNEAGON = 9;
152 const int EDGES_DECAGON = 10;
153 const int EDGES_HENDECAGON = 11;
154 const int EDGES_DODECAGON = 12;
155 const int EDGES_TRIDECAGON = 13;
156 const int EDGES_TETRADECAGON = 14;
157 const int EDGES_PENTADECAGON = 15;
158 const int EDGES_HEXADECAGON = 16;
159 
160 const float ROTATION_0_DEGREES = 0.0;
161 const float ROTATION_45_DEGREES = 45.0;
162 const float ROTATION_90_DEGREES = 90.0;
163 const float ROTATION_180_DEGREES = 180.0;
164 const float ROTATION_270_DEGREES = 270.0;
165 
169 };
170 
174 };
175 
176 class Display;
177 class DisplayPage;
179 
180 using display_writer_t = std::function<void(Display &)>;
181 
182 #define LOG_DISPLAY(prefix, type, obj) \
183  if ((obj) != nullptr) { \
184  ESP_LOGCONFIG(TAG, prefix type); \
185  ESP_LOGCONFIG(TAG, "%s Rotations: %d °", prefix, (obj)->rotation_); \
186  ESP_LOGCONFIG(TAG, "%s Dimensions: %dpx x %dpx", prefix, (obj)->get_width(), (obj)->get_height()); \
187  }
188 
190 extern const Color COLOR_OFF;
192 extern const Color COLOR_ON;
193 
194 class BaseImage {
195  public:
196  virtual void draw(int x, int y, Display *display, Color color_on, Color color_off) = 0;
197  virtual int get_width() const = 0;
198  virtual int get_height() const = 0;
199 };
200 
201 class BaseFont {
202  public:
203  virtual void print(int x, int y, Display *display, Color color, const char *text, Color background) = 0;
204  virtual void measure(const char *str, int *width, int *x_offset, int *baseline, int *height) = 0;
205 };
206 
207 class Display : public PollingComponent {
208  public:
210  virtual void fill(Color color);
212  void clear();
213 
215  virtual int get_width() { return this->get_width_internal(); }
217  virtual int get_height() { return this->get_height_internal(); }
218 
220  int get_native_width() { return this->get_width_internal(); }
222  int get_native_height() { return this->get_height_internal(); }
223 
225  inline void draw_pixel_at(int x, int y) { this->draw_pixel_at(x, y, COLOR_ON); }
226 
228  virtual void draw_pixel_at(int x, int y, Color color) = 0;
229 
249  virtual void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
250  ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad);
251 
253  void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
254  ColorBitness bitness, bool big_endian) {
255  this->draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, 0, 0, 0);
256  }
257 
259  void line(int x1, int y1, int x2, int y2, Color color = COLOR_ON);
260 
262  void line_at_angle(int x, int y, int angle, int length, Color color = COLOR_ON);
263 
266  void line_at_angle(int x, int y, int angle, int start_radius, int stop_radius, Color color = COLOR_ON);
267 
269  void horizontal_line(int x, int y, int width, Color color = COLOR_ON);
270 
272  void vertical_line(int x, int y, int height, Color color = COLOR_ON);
273 
276  void rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON);
277 
279  void filled_rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON);
280 
282  void circle(int center_x, int center_xy, int radius, Color color = COLOR_ON);
283 
285  void filled_circle(int center_x, int center_y, int radius, Color color = COLOR_ON);
286 
288  void triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color = COLOR_ON);
289 
291  void filled_triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color = COLOR_ON);
292 
301  void get_regular_polygon_vertex(int vertex_id, int *vertex_x, int *vertex_y, int center_x, int center_y, int radius,
302  int edges, RegularPolygonVariation variation = VARIATION_POINTY_TOP,
303  float rotation_degrees = ROTATION_0_DEGREES);
304 
311  void regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation = VARIATION_POINTY_TOP,
312  float rotation_degrees = ROTATION_0_DEGREES, Color color = COLOR_ON,
314  void regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation, Color color,
316  void regular_polygon(int x, int y, int radius, int edges, Color color,
318 
323  void filled_regular_polygon(int x, int y, int radius, int edges,
325  float rotation_degrees = ROTATION_0_DEGREES, Color color = COLOR_ON);
326  void filled_regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation, Color color);
327  void filled_regular_polygon(int x, int y, int radius, int edges, Color color);
328 
339  void print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text,
340  Color background = COLOR_OFF);
341 
351  void print(int x, int y, BaseFont *font, Color color, const char *text, Color background = COLOR_OFF);
352 
361  void print(int x, int y, BaseFont *font, TextAlign align, const char *text);
362 
370  void print(int x, int y, BaseFont *font, const char *text);
371 
383  void printf(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format, ...)
384  __attribute__((format(printf, 8, 9)));
385 
396  void printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...)
397  __attribute__((format(printf, 7, 8)));
398 
408  void printf(int x, int y, BaseFont *font, Color color, const char *format, ...) __attribute__((format(printf, 6, 7)));
409 
419  void printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...)
420  __attribute__((format(printf, 6, 7)));
421 
430  void printf(int x, int y, BaseFont *font, const char *format, ...) __attribute__((format(printf, 5, 6)));
431 
442  void strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time)
443  __attribute__((format(strftime, 7, 0)));
444 
454  void strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time)
455  __attribute__((format(strftime, 6, 0)));
456 
466  void strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time)
467  __attribute__((format(strftime, 6, 0)));
468 
477  void strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) __attribute__((format(strftime, 5, 0)));
478 
487  void image(int x, int y, BaseImage *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
488 
498  void image(int x, int y, BaseImage *image, ImageAlign align, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
499 
500 #ifdef USE_GRAPH
501 
508  void graph(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
509 
521  void legend(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
522 #endif // USE_GRAPH
523 
524 #ifdef USE_QR_CODE
525 
532  void qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on = COLOR_ON, int scale = 1);
533 #endif
534 
535 #ifdef USE_GRAPHICAL_DISPLAY_MENU
536 
543  void menu(int x, int y, graphical_display_menu::GraphicalDisplayMenu *menu, int width, int height);
544 #endif // USE_GRAPHICAL_DISPLAY_MENU
545 
558  void get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1, int *width,
559  int *height);
560 
562  void set_writer(display_writer_t &&writer);
563 
564  void show_page(DisplayPage *page);
565  void show_next_page();
566  void show_prev_page();
567 
568  void set_pages(std::vector<DisplayPage *> pages);
569 
570  const DisplayPage *get_active_page() const { return this->page_; }
571 
572  void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t) { this->on_page_change_triggers_.push_back(t); }
573 
575  void set_rotation(DisplayRotation rotation);
576 
577  // Internal method to set display auto clearing.
578  void set_auto_clear(bool auto_clear_enabled) { this->auto_clear_enabled_ = auto_clear_enabled; }
579 
580  DisplayRotation get_rotation() const { return this->rotation_; }
581 
585  virtual DisplayType get_display_type() = 0;
586 
593  void start_clipping(Rect rect);
594  void start_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
595  start_clipping(Rect(left, top, right - left, bottom - top));
596  };
597 
603  void extend_clipping(Rect rect);
604  void extend_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
605  this->extend_clipping(Rect(left, top, right - left, bottom - top));
606  };
607 
613  void shrink_clipping(Rect rect);
614  void shrink_clipping(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) {
615  this->shrink_clipping(Rect(left, top, right - left, bottom - top));
616  };
617 
620  void end_clipping();
621 
626  Rect get_clipping() const;
627 
628  bool is_clipping() const { return !this->clipping_rectangle_.empty(); }
629 
632  bool clip(int x, int y);
633 
634  void test_card();
635  void show_test_card() { this->show_test_card_ = true; }
636 
637  protected:
638  bool clamp_x_(int x, int w, int &min_x, int &max_x);
639  bool clamp_y_(int y, int h, int &min_y, int &max_y);
640  void vprintf_(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,
641  va_list arg);
642 
643  void do_update_();
644  void clear_clipping_();
645 
646  virtual int get_height_internal() = 0;
647  virtual int get_width_internal() = 0;
648 
655  void filled_flat_side_triangle_(int x1, int y1, int x2, int y2, int x3, int y3, Color color);
656  void sort_triangle_points_by_y_(int *x1, int *y1, int *x2, int *y2, int *x3, int *y3);
657 
660  DisplayPage *page_{nullptr};
661  DisplayPage *previous_page_{nullptr};
662  std::vector<DisplayOnPageChangeTrigger *> on_page_change_triggers_;
663  bool auto_clear_enabled_{true};
664  std::vector<Rect> clipping_rectangle_;
665  bool show_test_card_{false};
666 };
667 
668 class DisplayPage {
669  public:
671  void show();
672  void show_next();
673  void show_prev();
674  void set_parent(Display *parent);
675  void set_prev(DisplayPage *prev);
676  void set_next(DisplayPage *next);
677  const display_writer_t &get_writer() const;
678 
679  protected:
682  DisplayPage *prev_{nullptr};
683  DisplayPage *next_{nullptr};
684 };
685 
686 template<typename... Ts> class DisplayPageShowAction : public Action<Ts...> {
687  public:
689 
690  void play(Ts... x) override {
691  auto *page = this->page_.value(x...);
692  if (page != nullptr) {
693  page->show();
694  }
695  }
696 };
697 
698 template<typename... Ts> class DisplayPageShowNextAction : public Action<Ts...> {
699  public:
700  DisplayPageShowNextAction(Display *buffer) : buffer_(buffer) {}
701 
702  void play(Ts... x) override { this->buffer_->show_next_page(); }
703 
705 };
706 
707 template<typename... Ts> class DisplayPageShowPrevAction : public Action<Ts...> {
708  public:
709  DisplayPageShowPrevAction(Display *buffer) : buffer_(buffer) {}
710 
711  void play(Ts... x) override { this->buffer_->show_prev_page(); }
712 
714 };
715 
716 template<typename... Ts> class DisplayIsDisplayingPageCondition : public Condition<Ts...> {
717  public:
718  DisplayIsDisplayingPageCondition(Display *parent) : parent_(parent) {}
719 
720  void set_page(DisplayPage *page) { this->page_ = page; }
721  bool check(Ts... x) override { return this->parent_->get_active_page() == this->page_; }
722 
723  protected:
726 };
727 
728 class DisplayOnPageChangeTrigger : public Trigger<DisplayPage *, DisplayPage *> {
729  public:
730  explicit DisplayOnPageChangeTrigger(Display *parent) { parent->add_on_page_change_trigger(this); }
731  void process(DisplayPage *from, DisplayPage *to);
732  void set_from(DisplayPage *p) { this->from_ = p; }
733  void set_to(DisplayPage *p) { this->to_ = p; }
734 
735  protected:
736  DisplayPage *from_{nullptr};
737  DisplayPage *to_{nullptr};
738 };
739 
740 } // namespace display
741 } // namespace esphome
const int EDGES_OCTAGON
Definition: display.h:149
const int EDGES_HEXADECAGON
Definition: display.h:158
const int EDGES_TETRAGON
Definition: display.h:144
std::vector< DisplayOnPageChangeTrigger * > on_page_change_triggers_
Definition: display.h:662
const int EDGES_PENTAGON
Definition: display.h:146
DisplayRotation get_rotation() const
Definition: display.h:580
const int EDGES_QUADRILATERAL
Definition: display.h:145
const float ROTATION_45_DEGREES
Definition: display.h:161
uint16_t x
Definition: tt21100.cpp:17
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:253
int get_native_height()
Get the native (original) height of the display in pixels.
Definition: display.h:222
const int EDGES_HEPTAGON
Definition: display.h:148
A more user-friendly version of struct tm from time.h.
Definition: time.h:17
const Color COLOR_OFF(0, 0, 0, 0)
Turn the pixel OFF.
Definition: display.h:190
void extend_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom)
Definition: display.h:604
This class simplifies creating components that periodically check a state.
Definition: component.h:283
const DisplayPage * get_active_page() const
Definition: display.h:570
const int EDGES_TETRADECAGON
Definition: display.h:156
virtual int get_width()
Get the calculated width of the display in pixels with rotation applied.
Definition: display.h:215
const float ROTATION_270_DEGREES
Definition: display.h:164
uint16_t y
Definition: tt21100.cpp:18
int get_native_width()
Get the native (original) width of the display in pixels.
Definition: display.h:220
const float ROTATION_180_DEGREES
Definition: display.h:163
bool is_clipping() const
Definition: display.h:628
TextAlign
TextAlign is used to tell the display class how to position a piece of text.
Definition: display.h:52
std::function< void(Display &)> display_writer_t
Definition: display.h:180
Base class for all automation conditions.
Definition: automation.h:74
const float ROTATION_90_DEGREES
Definition: display.h:162
void shrink_clipping(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
Definition: display.h:614
ImageAlign
ImageAlign is used to tell the display class how to position a image.
Definition: display.h:102
void start_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom)
Definition: display.h:594
const float ROTATION_0_DEGREES
Definition: display.h:160
const int EDGES_TRIDECAGON
Definition: display.h:155
const int EDGES_PENTADECAGON
Definition: display.h:157
enum esphome::EntityCategory __attribute__
const int EDGES_DODECAGON
Definition: display.h:154
display_writer_t writer_
Definition: display.h:681
virtual int get_height()
Get the calculated height of the display in pixels with rotation applied.
Definition: display.h:217
const Color COLOR_ON(255, 255, 255, 255)
Turn the pixel ON.
Definition: display.h:192
TEMPLATABLE_VALUE(DisplayPage *, page) void play(Ts... x) override
Definition: display.h:688
const int EDGES_NONAGON
Definition: display.h:150
const int EDGES_HENDECAGON
Definition: display.h:153
uint8_t h
Definition: bl0939.h:21
uint16_t length
Definition: tt21100.cpp:12
void draw_pixel_at(int x, int y)
Set a single pixel at the specified coordinates to default color.
Definition: display.h:225
void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t)
Definition: display.h:572
const int EDGES_TRIGON
Definition: display.h:142
This is a workaround until we can figure out a way to get the tflite-micro idf component code availab...
Definition: a01nyub.cpp:7
void set_auto_clear(bool auto_clear_enabled)
Definition: display.h:578
std::vector< Rect > clipping_rectangle_
Definition: display.h:664
const int EDGES_DECAGON
Definition: display.h:152
const int EDGES_TRIANGLE
Definition: display.h:143
const int EDGES_HEXAGON
Definition: display.h:147
const int EDGES_ENNEAGON
Definition: display.h:151