ESPHome  2024.11.3
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 
290  void filled_ring(int center_x, int center_y, int radius1, int radius2, Color color = COLOR_ON);
293  void filled_gauge(int center_x, int center_y, int radius1, int radius2, int progress, Color color = COLOR_ON);
294 
296  void triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color = COLOR_ON);
297 
299  void filled_triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color = COLOR_ON);
300 
309  void get_regular_polygon_vertex(int vertex_id, int *vertex_x, int *vertex_y, int center_x, int center_y, int radius,
310  int edges, RegularPolygonVariation variation = VARIATION_POINTY_TOP,
311  float rotation_degrees = ROTATION_0_DEGREES);
312 
319  void regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation = VARIATION_POINTY_TOP,
320  float rotation_degrees = ROTATION_0_DEGREES, Color color = COLOR_ON,
322  void regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation, Color color,
324  void regular_polygon(int x, int y, int radius, int edges, Color color,
326 
331  void filled_regular_polygon(int x, int y, int radius, int edges,
333  float rotation_degrees = ROTATION_0_DEGREES, Color color = COLOR_ON);
334  void filled_regular_polygon(int x, int y, int radius, int edges, RegularPolygonVariation variation, Color color);
335  void filled_regular_polygon(int x, int y, int radius, int edges, Color color);
336 
347  void print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text,
348  Color background = COLOR_OFF);
349 
359  void print(int x, int y, BaseFont *font, Color color, const char *text, Color background = COLOR_OFF);
360 
369  void print(int x, int y, BaseFont *font, TextAlign align, const char *text);
370 
378  void print(int x, int y, BaseFont *font, const char *text);
379 
391  void printf(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format, ...)
392  __attribute__((format(printf, 8, 9)));
393 
404  void printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...)
405  __attribute__((format(printf, 7, 8)));
406 
416  void printf(int x, int y, BaseFont *font, Color color, const char *format, ...) __attribute__((format(printf, 6, 7)));
417 
427  void printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...)
428  __attribute__((format(printf, 6, 7)));
429 
438  void printf(int x, int y, BaseFont *font, const char *format, ...) __attribute__((format(printf, 5, 6)));
439 
450  void strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time)
451  __attribute__((format(strftime, 7, 0)));
452 
462  void strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time)
463  __attribute__((format(strftime, 6, 0)));
464 
474  void strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time)
475  __attribute__((format(strftime, 6, 0)));
476 
485  void strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) __attribute__((format(strftime, 5, 0)));
486 
495  void image(int x, int y, BaseImage *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
496 
506  void image(int x, int y, BaseImage *image, ImageAlign align, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
507 
508 #ifdef USE_GRAPH
509 
516  void graph(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
517 
529  void legend(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
530 #endif // USE_GRAPH
531 
532 #ifdef USE_QR_CODE
533 
540  void qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on = COLOR_ON, int scale = 1);
541 #endif
542 
543 #ifdef USE_GRAPHICAL_DISPLAY_MENU
544 
551  void menu(int x, int y, graphical_display_menu::GraphicalDisplayMenu *menu, int width, int height);
552 #endif // USE_GRAPHICAL_DISPLAY_MENU
553 
566  void get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1, int *width,
567  int *height);
568 
570  void set_writer(display_writer_t &&writer);
571 
572  void show_page(DisplayPage *page);
573  void show_next_page();
574  void show_prev_page();
575 
576  void set_pages(std::vector<DisplayPage *> pages);
577 
578  const DisplayPage *get_active_page() const { return this->page_; }
579 
580  void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t) { this->on_page_change_triggers_.push_back(t); }
581 
583  void set_rotation(DisplayRotation rotation);
584 
585  // Internal method to set display auto clearing.
586  void set_auto_clear(bool auto_clear_enabled) { this->auto_clear_enabled_ = auto_clear_enabled; }
587 
588  DisplayRotation get_rotation() const { return this->rotation_; }
589 
593  virtual DisplayType get_display_type() = 0;
594 
601  void start_clipping(Rect rect);
602  void start_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
603  start_clipping(Rect(left, top, right - left, bottom - top));
604  };
605 
611  void extend_clipping(Rect rect);
612  void extend_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
613  this->extend_clipping(Rect(left, top, right - left, bottom - top));
614  };
615 
621  void shrink_clipping(Rect rect);
622  void shrink_clipping(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) {
623  this->shrink_clipping(Rect(left, top, right - left, bottom - top));
624  };
625 
628  void end_clipping();
629 
634  Rect get_clipping() const;
635 
636  bool is_clipping() const { return !this->clipping_rectangle_.empty(); }
637 
640  bool clip(int x, int y);
641 
642  void test_card();
643  void show_test_card() { this->show_test_card_ = true; }
644 
645  protected:
646  bool clamp_x_(int x, int w, int &min_x, int &max_x);
647  bool clamp_y_(int y, int h, int &min_y, int &max_y);
648  void vprintf_(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,
649  va_list arg);
650 
651  void do_update_();
652  void clear_clipping_();
653 
654  virtual int get_height_internal() = 0;
655  virtual int get_width_internal() = 0;
656 
663  void filled_flat_side_triangle_(int x1, int y1, int x2, int y2, int x3, int y3, Color color);
664  void sort_triangle_points_by_y_(int *x1, int *y1, int *x2, int *y2, int *x3, int *y3);
665 
668  DisplayPage *page_{nullptr};
669  DisplayPage *previous_page_{nullptr};
670  std::vector<DisplayOnPageChangeTrigger *> on_page_change_triggers_;
671  bool auto_clear_enabled_{true};
672  std::vector<Rect> clipping_rectangle_;
673  bool show_test_card_{false};
674 };
675 
676 class DisplayPage {
677  public:
679  void show();
680  void show_next();
681  void show_prev();
682  void set_parent(Display *parent);
683  void set_prev(DisplayPage *prev);
684  void set_next(DisplayPage *next);
685  const display_writer_t &get_writer() const;
686 
687  protected:
690  DisplayPage *prev_{nullptr};
691  DisplayPage *next_{nullptr};
692 };
693 
694 template<typename... Ts> class DisplayPageShowAction : public Action<Ts...> {
695  public:
697 
698  void play(Ts... x) override {
699  auto *page = this->page_.value(x...);
700  if (page != nullptr) {
701  page->show();
702  }
703  }
704 };
705 
706 template<typename... Ts> class DisplayPageShowNextAction : public Action<Ts...> {
707  public:
708  DisplayPageShowNextAction(Display *buffer) : buffer_(buffer) {}
709 
710  void play(Ts... x) override { this->buffer_->show_next_page(); }
711 
713 };
714 
715 template<typename... Ts> class DisplayPageShowPrevAction : public Action<Ts...> {
716  public:
717  DisplayPageShowPrevAction(Display *buffer) : buffer_(buffer) {}
718 
719  void play(Ts... x) override { this->buffer_->show_prev_page(); }
720 
722 };
723 
724 template<typename... Ts> class DisplayIsDisplayingPageCondition : public Condition<Ts...> {
725  public:
726  DisplayIsDisplayingPageCondition(Display *parent) : parent_(parent) {}
727 
728  void set_page(DisplayPage *page) { this->page_ = page; }
729  bool check(Ts... x) override { return this->parent_->get_active_page() == this->page_; }
730 
731  protected:
734 };
735 
736 class DisplayOnPageChangeTrigger : public Trigger<DisplayPage *, DisplayPage *> {
737  public:
738  explicit DisplayOnPageChangeTrigger(Display *parent) { parent->add_on_page_change_trigger(this); }
739  void process(DisplayPage *from, DisplayPage *to);
740  void set_from(DisplayPage *p) { this->from_ = p; }
741  void set_to(DisplayPage *p) { this->to_ = p; }
742 
743  protected:
744  DisplayPage *from_{nullptr};
745  DisplayPage *to_{nullptr};
746 };
747 
748 const LogString *text_align_to_string(TextAlign textalign);
749 
750 } // namespace display
751 } // 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:670
const int EDGES_PENTAGON
Definition: display.h:147
DisplayRotation get_rotation() const
Definition: display.h:588
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:15
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:612
This class simplifies creating components that periodically check a state.
Definition: component.h:283
const DisplayPage * get_active_page() const
Definition: display.h:578
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:636
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:622
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:602
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:689
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:696
const int EDGES_NONAGON
Definition: display.h:151
const LogString * text_align_to_string(TextAlign textalign)
Definition: display.cpp:820
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:580
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:586
std::vector< Rect > clipping_rectangle_
Definition: display.h:672
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