ESPHome  2024.9.0
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 "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 
26 namespace esphome {
27 namespace display {
28 
53 enum class TextAlign {
54  TOP = 0x00,
55  CENTER_VERTICAL = 0x01,
56  BASELINE = 0x02,
57  BOTTOM = 0x04,
58 
59  LEFT = 0x00,
60  CENTER_HORIZONTAL = 0x08,
61  RIGHT = 0x10,
62 
63  TOP_LEFT = TOP | LEFT,
65  TOP_RIGHT = TOP | RIGHT,
66 
70 
74 
78 };
79 
103 enum class ImageAlign {
104  TOP = 0x00,
105  CENTER_VERTICAL = 0x01,
106  BOTTOM = 0x02,
107 
108  LEFT = 0x00,
109  CENTER_HORIZONTAL = 0x04,
110  RIGHT = 0x08,
111 
112  TOP_LEFT = TOP | LEFT,
114  TOP_RIGHT = TOP | RIGHT,
115 
119 
120  BOTTOM_LEFT = BOTTOM | LEFT,
123 
126 };
127 
132 };
133 
139 };
140 
141 #define PI 3.1415926535897932384626433832795
142 
143 const int EDGES_TRIGON = 3;
144 const int EDGES_TRIANGLE = 3;
145 const int EDGES_TETRAGON = 4;
146 const int EDGES_QUADRILATERAL = 4;
147 const int EDGES_PENTAGON = 5;
148 const int EDGES_HEXAGON = 6;
149 const int EDGES_HEPTAGON = 7;
150 const int EDGES_OCTAGON = 8;
151 const int EDGES_NONAGON = 9;
152 const int EDGES_ENNEAGON = 9;
153 const int EDGES_DECAGON = 10;
154 const int EDGES_HENDECAGON = 11;
155 const int EDGES_DODECAGON = 12;
156 const int EDGES_TRIDECAGON = 13;
157 const int EDGES_TETRADECAGON = 14;
158 const int EDGES_PENTADECAGON = 15;
159 const int EDGES_HEXADECAGON = 16;
160 
161 const float ROTATION_0_DEGREES = 0.0;
162 const float ROTATION_45_DEGREES = 45.0;
163 const float ROTATION_90_DEGREES = 90.0;
164 const float ROTATION_180_DEGREES = 180.0;
165 const float ROTATION_270_DEGREES = 270.0;
166 
170 };
171 
175 };
176 
177 class Display;
178 class DisplayPage;
180 
181 using display_writer_t = std::function<void(Display &)>;
182 
183 #define LOG_DISPLAY(prefix, type, obj) \
184  if ((obj) != nullptr) { \
185  ESP_LOGCONFIG(TAG, prefix type); \
186  ESP_LOGCONFIG(TAG, "%s Rotations: %d °", prefix, (obj)->rotation_); \
187  ESP_LOGCONFIG(TAG, "%s Dimensions: %dpx x %dpx", prefix, (obj)->get_width(), (obj)->get_height()); \
188  }
189 
191 extern const Color COLOR_OFF;
193 extern const Color COLOR_ON;
194 
195 class BaseImage {
196  public:
197  virtual void draw(int x, int y, Display *display, Color color_on, Color color_off) = 0;
198  virtual int get_width() const = 0;
199  virtual int get_height() const = 0;
200 };
201 
202 class BaseFont {
203  public:
204  virtual void print(int x, int y, Display *display, Color color, const char *text, Color background) = 0;
205  virtual void measure(const char *str, int *width, int *x_offset, int *baseline, int *height) = 0;
206 };
207 
208 class Display : public PollingComponent {
209  public:
211  virtual void fill(Color color);
213  void clear();
214 
216  virtual int get_width() { return this->get_width_internal(); }
218  virtual int get_height() { return this->get_height_internal(); }
219 
221  int get_native_width() { return this->get_width_internal(); }
223  int get_native_height() { return this->get_height_internal(); }
224 
226  inline void draw_pixel_at(int x, int y) { this->draw_pixel_at(x, y, COLOR_ON); }
227 
229  virtual void draw_pixel_at(int x, int y, Color color) = 0;
230 
250  virtual void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
251  ColorBitness bitness, bool big_endian, int x_offset, int y_offset, int x_pad);
252 
254  void draw_pixels_at(int x_start, int y_start, int w, int h, const uint8_t *ptr, ColorOrder order,
255  ColorBitness bitness, bool big_endian) {
256  this->draw_pixels_at(x_start, y_start, w, h, ptr, order, bitness, big_endian, 0, 0, 0);
257  }
258 
260  void line(int x1, int y1, int x2, int y2, Color color = COLOR_ON);
261 
263  void line_at_angle(int x, int y, int angle, int length, Color color = COLOR_ON);
264 
267  void line_at_angle(int x, int y, int angle, int start_radius, int stop_radius, Color color = COLOR_ON);
268 
270  void horizontal_line(int x, int y, int width, Color color = COLOR_ON);
271 
273  void vertical_line(int x, int y, int height, Color color = COLOR_ON);
274 
277  void rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON);
278 
280  void filled_rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON);
281 
283  void circle(int center_x, int center_xy, int radius, Color color = COLOR_ON);
284 
286  void filled_circle(int center_x, int center_y, int radius, Color color = COLOR_ON);
287 
289  void triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color = COLOR_ON);
290 
292  void filled_triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color = COLOR_ON);
293 
302  void get_regular_polygon_vertex(int vertex_id, int *vertex_x, int *vertex_y, int center_x, int center_y, int radius,
303  int edges, RegularPolygonVariation variation = VARIATION_POINTY_TOP,
304  float rotation_degrees = ROTATION_0_DEGREES);
305 
312  void regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation = VARIATION_POINTY_TOP,
313  float rotation_degrees = ROTATION_0_DEGREES, Color color = COLOR_ON,
315  void regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation, Color color,
317  void regular_polygon(int x, int y, int radius, int edges, Color color,
319 
324  void filled_regular_polygon(int x, int y, int radius, int edges,
326  float rotation_degrees = ROTATION_0_DEGREES, Color color = COLOR_ON);
327  void filled_regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation, Color color);
328  void filled_regular_polygon(int x, int y, int radius, int edges, Color color);
329 
340  void print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text,
341  Color background = COLOR_OFF);
342 
352  void print(int x, int y, BaseFont *font, Color color, const char *text, Color background = COLOR_OFF);
353 
362  void print(int x, int y, BaseFont *font, TextAlign align, const char *text);
363 
371  void print(int x, int y, BaseFont *font, const char *text);
372 
384  void printf(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format, ...)
385  __attribute__((format(printf, 8, 9)));
386 
397  void printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...)
398  __attribute__((format(printf, 7, 8)));
399 
409  void printf(int x, int y, BaseFont *font, Color color, const char *format, ...) __attribute__((format(printf, 6, 7)));
410 
420  void printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...)
421  __attribute__((format(printf, 6, 7)));
422 
431  void printf(int x, int y, BaseFont *font, const char *format, ...) __attribute__((format(printf, 5, 6)));
432 
443  void strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time)
444  __attribute__((format(strftime, 7, 0)));
445 
455  void strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time)
456  __attribute__((format(strftime, 6, 0)));
457 
467  void strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time)
468  __attribute__((format(strftime, 6, 0)));
469 
478  void strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) __attribute__((format(strftime, 5, 0)));
479 
488  void image(int x, int y, BaseImage *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
489 
499  void image(int x, int y, BaseImage *image, ImageAlign align, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
500 
501 #ifdef USE_GRAPH
502 
509  void graph(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
510 
522  void legend(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
523 #endif // USE_GRAPH
524 
525 #ifdef USE_QR_CODE
526 
533  void qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on = COLOR_ON, int scale = 1);
534 #endif
535 
536 #ifdef USE_GRAPHICAL_DISPLAY_MENU
537 
544  void menu(int x, int y, graphical_display_menu::GraphicalDisplayMenu *menu, int width, int height);
545 #endif // USE_GRAPHICAL_DISPLAY_MENU
546 
559  void get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1, int *width,
560  int *height);
561 
563  void set_writer(display_writer_t &&writer);
564 
565  void show_page(DisplayPage *page);
566  void show_next_page();
567  void show_prev_page();
568 
569  void set_pages(std::vector<DisplayPage *> pages);
570 
571  const DisplayPage *get_active_page() const { return this->page_; }
572 
573  void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t) { this->on_page_change_triggers_.push_back(t); }
574 
576  void set_rotation(DisplayRotation rotation);
577 
578  // Internal method to set display auto clearing.
579  void set_auto_clear(bool auto_clear_enabled) { this->auto_clear_enabled_ = auto_clear_enabled; }
580 
581  DisplayRotation get_rotation() const { return this->rotation_; }
582 
586  virtual DisplayType get_display_type() = 0;
587 
594  void start_clipping(Rect rect);
595  void start_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
596  start_clipping(Rect(left, top, right - left, bottom - top));
597  };
598 
604  void extend_clipping(Rect rect);
605  void extend_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
606  this->extend_clipping(Rect(left, top, right - left, bottom - top));
607  };
608 
614  void shrink_clipping(Rect rect);
615  void shrink_clipping(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) {
616  this->shrink_clipping(Rect(left, top, right - left, bottom - top));
617  };
618 
621  void end_clipping();
622 
627  Rect get_clipping() const;
628 
629  bool is_clipping() const { return !this->clipping_rectangle_.empty(); }
630 
633  bool clip(int x, int y);
634 
635  void test_card();
636  void show_test_card() { this->show_test_card_ = true; }
637 
638  protected:
639  bool clamp_x_(int x, int w, int &min_x, int &max_x);
640  bool clamp_y_(int y, int h, int &min_y, int &max_y);
641  void vprintf_(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,
642  va_list arg);
643 
644  void do_update_();
645  void clear_clipping_();
646 
647  virtual int get_height_internal() = 0;
648  virtual int get_width_internal() = 0;
649 
656  void filled_flat_side_triangle_(int x1, int y1, int x2, int y2, int x3, int y3, Color color);
657  void sort_triangle_points_by_y_(int *x1, int *y1, int *x2, int *y2, int *x3, int *y3);
658 
661  DisplayPage *page_{nullptr};
662  DisplayPage *previous_page_{nullptr};
663  std::vector<DisplayOnPageChangeTrigger *> on_page_change_triggers_;
664  bool auto_clear_enabled_{true};
665  std::vector<Rect> clipping_rectangle_;
666  bool show_test_card_{false};
667 };
668 
669 class DisplayPage {
670  public:
672  void show();
673  void show_next();
674  void show_prev();
675  void set_parent(Display *parent);
676  void set_prev(DisplayPage *prev);
677  void set_next(DisplayPage *next);
678  const display_writer_t &get_writer() const;
679 
680  protected:
683  DisplayPage *prev_{nullptr};
684  DisplayPage *next_{nullptr};
685 };
686 
687 template<typename... Ts> class DisplayPageShowAction : public Action<Ts...> {
688  public:
690 
691  void play(Ts... x) override {
692  auto *page = this->page_.value(x...);
693  if (page != nullptr) {
694  page->show();
695  }
696  }
697 };
698 
699 template<typename... Ts> class DisplayPageShowNextAction : public Action<Ts...> {
700  public:
701  DisplayPageShowNextAction(Display *buffer) : buffer_(buffer) {}
702 
703  void play(Ts... x) override { this->buffer_->show_next_page(); }
704 
706 };
707 
708 template<typename... Ts> class DisplayPageShowPrevAction : public Action<Ts...> {
709  public:
710  DisplayPageShowPrevAction(Display *buffer) : buffer_(buffer) {}
711 
712  void play(Ts... x) override { this->buffer_->show_prev_page(); }
713 
715 };
716 
717 template<typename... Ts> class DisplayIsDisplayingPageCondition : public Condition<Ts...> {
718  public:
719  DisplayIsDisplayingPageCondition(Display *parent) : parent_(parent) {}
720 
721  void set_page(DisplayPage *page) { this->page_ = page; }
722  bool check(Ts... x) override { return this->parent_->get_active_page() == this->page_; }
723 
724  protected:
727 };
728 
729 class DisplayOnPageChangeTrigger : public Trigger<DisplayPage *, DisplayPage *> {
730  public:
731  explicit DisplayOnPageChangeTrigger(Display *parent) { parent->add_on_page_change_trigger(this); }
732  void process(DisplayPage *from, DisplayPage *to);
733  void set_from(DisplayPage *p) { this->from_ = p; }
734  void set_to(DisplayPage *p) { this->to_ = p; }
735 
736  protected:
737  DisplayPage *from_{nullptr};
738  DisplayPage *to_{nullptr};
739 };
740 
741 const LogString *text_align_to_string(TextAlign textalign);
742 
743 } // namespace display
744 } // namespace esphome
const int EDGES_OCTAGON
Definition: display.h:150
const int EDGES_HEXADECAGON
Definition: display.h:159
const int EDGES_TETRAGON
Definition: display.h:145
std::vector< DisplayOnPageChangeTrigger * > on_page_change_triggers_
Definition: display.h:663
const int EDGES_PENTAGON
Definition: display.h:147
DisplayRotation get_rotation() const
Definition: display.h:581
const int EDGES_QUADRILATERAL
Definition: display.h:146
const float ROTATION_45_DEGREES
Definition: display.h:162
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:254
int get_native_height()
Get the native (original) height of the display in pixels.
Definition: display.h:223
const int EDGES_HEPTAGON
Definition: display.h:149
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:191
void extend_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom)
Definition: display.h:605
This class simplifies creating components that periodically check a state.
Definition: component.h:283
const DisplayPage * get_active_page() const
Definition: display.h:571
const int EDGES_TETRADECAGON
Definition: display.h:157
uint8_t h
Definition: bl0906.h:209
virtual int get_width()
Get the calculated width of the display in pixels with rotation applied.
Definition: display.h:216
const float ROTATION_270_DEGREES
Definition: display.h:165
uint16_t y
Definition: tt21100.cpp:18
int get_native_width()
Get the native (original) width of the display in pixels.
Definition: display.h:221
const float ROTATION_180_DEGREES
Definition: display.h:164
bool is_clipping() const
Definition: display.h:629
TextAlign
TextAlign is used to tell the display class how to position a piece of text.
Definition: display.h:53
std::function< void(Display &)> display_writer_t
Definition: display.h:181
Base class for all automation conditions.
Definition: automation.h:74
const float ROTATION_90_DEGREES
Definition: display.h:163
void shrink_clipping(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
Definition: display.h:615
ImageAlign
ImageAlign is used to tell the display class how to position a image.
Definition: display.h:103
void start_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom)
Definition: display.h:595
const float ROTATION_0_DEGREES
Definition: display.h:161
const int EDGES_TRIDECAGON
Definition: display.h:156
const int EDGES_PENTADECAGON
Definition: display.h:158
enum esphome::EntityCategory __attribute__
const int EDGES_DODECAGON
Definition: display.h:155
display_writer_t writer_
Definition: display.h:682
virtual int get_height()
Get the calculated height of the display in pixels with rotation applied.
Definition: display.h:218
const Color COLOR_ON(255, 255, 255, 255)
Turn the pixel ON.
Definition: display.h:193
TEMPLATABLE_VALUE(DisplayPage *, page) void play(Ts... x) override
Definition: display.h:689
const int EDGES_NONAGON
Definition: display.h:151
const LogString * text_align_to_string(TextAlign textalign)
Definition: display.cpp:678
const int EDGES_HENDECAGON
Definition: display.h:154
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:226
void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t)
Definition: display.h:573
const int EDGES_TRIGON
Definition: display.h:143
Implementation of SPI Controller mode.
Definition: a01nyub.cpp:7
void set_auto_clear(bool auto_clear_enabled)
Definition: display.h:579
std::vector< Rect > clipping_rectangle_
Definition: display.h:665
const int EDGES_DECAGON
Definition: display.h:153
const int EDGES_TRIANGLE
Definition: display.h:144
const int EDGES_HEXAGON
Definition: display.h:148
const int EDGES_ENNEAGON
Definition: display.h:152