ESPHome  2024.12.2
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 
451  void strftime(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,
452  ESPTime time) __attribute__((format(strftime, 8, 0)));
453 
464  void strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time)
465  __attribute__((format(strftime, 7, 0)));
466 
476  void strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time)
477  __attribute__((format(strftime, 6, 0)));
478 
488  void strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time)
489  __attribute__((format(strftime, 6, 0)));
490 
499  void strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) __attribute__((format(strftime, 5, 0)));
500 
509  void image(int x, int y, BaseImage *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
510 
520  void image(int x, int y, BaseImage *image, ImageAlign align, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
521 
522 #ifdef USE_GRAPH
523 
530  void graph(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
531 
543  void legend(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
544 #endif // USE_GRAPH
545 
546 #ifdef USE_QR_CODE
547 
554  void qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on = COLOR_ON, int scale = 1);
555 #endif
556 
557 #ifdef USE_GRAPHICAL_DISPLAY_MENU
558 
565  void menu(int x, int y, graphical_display_menu::GraphicalDisplayMenu *menu, int width, int height);
566 #endif // USE_GRAPHICAL_DISPLAY_MENU
567 
580  void get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1, int *width,
581  int *height);
582 
584  void set_writer(display_writer_t &&writer);
585 
586  void show_page(DisplayPage *page);
587  void show_next_page();
588  void show_prev_page();
589 
590  void set_pages(std::vector<DisplayPage *> pages);
591 
592  const DisplayPage *get_active_page() const { return this->page_; }
593 
594  void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t) { this->on_page_change_triggers_.push_back(t); }
595 
597  void set_rotation(DisplayRotation rotation);
598 
599  // Internal method to set display auto clearing.
600  void set_auto_clear(bool auto_clear_enabled) { this->auto_clear_enabled_ = auto_clear_enabled; }
601 
602  DisplayRotation get_rotation() const { return this->rotation_; }
603 
607  virtual DisplayType get_display_type() = 0;
608 
615  void start_clipping(Rect rect);
616  void start_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
617  start_clipping(Rect(left, top, right - left, bottom - top));
618  };
619 
625  void extend_clipping(Rect rect);
626  void extend_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
627  this->extend_clipping(Rect(left, top, right - left, bottom - top));
628  };
629 
635  void shrink_clipping(Rect rect);
636  void shrink_clipping(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) {
637  this->shrink_clipping(Rect(left, top, right - left, bottom - top));
638  };
639 
642  void end_clipping();
643 
648  Rect get_clipping() const;
649 
650  bool is_clipping() const { return !this->clipping_rectangle_.empty(); }
651 
654  bool clip(int x, int y);
655 
656  void test_card();
657  void show_test_card() { this->show_test_card_ = true; }
658 
659  protected:
660  bool clamp_x_(int x, int w, int &min_x, int &max_x);
661  bool clamp_y_(int y, int h, int &min_y, int &max_y);
662  void vprintf_(int x, int y, BaseFont *font, Color color, Color background, TextAlign align, const char *format,
663  va_list arg);
664 
665  void do_update_();
666  void clear_clipping_();
667 
668  virtual int get_height_internal() = 0;
669  virtual int get_width_internal() = 0;
670 
677  void filled_flat_side_triangle_(int x1, int y1, int x2, int y2, int x3, int y3, Color color);
678  void sort_triangle_points_by_y_(int *x1, int *y1, int *x2, int *y2, int *x3, int *y3);
679 
682  DisplayPage *page_{nullptr};
683  DisplayPage *previous_page_{nullptr};
684  std::vector<DisplayOnPageChangeTrigger *> on_page_change_triggers_;
685  bool auto_clear_enabled_{true};
686  std::vector<Rect> clipping_rectangle_;
687  bool show_test_card_{false};
688 };
689 
690 class DisplayPage {
691  public:
693  void show();
694  void show_next();
695  void show_prev();
696  void set_parent(Display *parent);
697  void set_prev(DisplayPage *prev);
698  void set_next(DisplayPage *next);
699  const display_writer_t &get_writer() const;
700 
701  protected:
704  DisplayPage *prev_{nullptr};
705  DisplayPage *next_{nullptr};
706 };
707 
708 template<typename... Ts> class DisplayPageShowAction : public Action<Ts...> {
709  public:
711 
712  void play(Ts... x) override {
713  auto *page = this->page_.value(x...);
714  if (page != nullptr) {
715  page->show();
716  }
717  }
718 };
719 
720 template<typename... Ts> class DisplayPageShowNextAction : public Action<Ts...> {
721  public:
722  DisplayPageShowNextAction(Display *buffer) : buffer_(buffer) {}
723 
724  void play(Ts... x) override { this->buffer_->show_next_page(); }
725 
727 };
728 
729 template<typename... Ts> class DisplayPageShowPrevAction : public Action<Ts...> {
730  public:
731  DisplayPageShowPrevAction(Display *buffer) : buffer_(buffer) {}
732 
733  void play(Ts... x) override { this->buffer_->show_prev_page(); }
734 
736 };
737 
738 template<typename... Ts> class DisplayIsDisplayingPageCondition : public Condition<Ts...> {
739  public:
740  DisplayIsDisplayingPageCondition(Display *parent) : parent_(parent) {}
741 
742  void set_page(DisplayPage *page) { this->page_ = page; }
743  bool check(Ts... x) override { return this->parent_->get_active_page() == this->page_; }
744 
745  protected:
748 };
749 
750 class DisplayOnPageChangeTrigger : public Trigger<DisplayPage *, DisplayPage *> {
751  public:
752  explicit DisplayOnPageChangeTrigger(Display *parent) { parent->add_on_page_change_trigger(this); }
753  void process(DisplayPage *from, DisplayPage *to);
754  void set_from(DisplayPage *p) { this->from_ = p; }
755  void set_to(DisplayPage *p) { this->to_ = p; }
756 
757  protected:
758  DisplayPage *from_{nullptr};
759  DisplayPage *to_{nullptr};
760 };
761 
762 const LogString *text_align_to_string(TextAlign textalign);
763 
764 } // namespace display
765 } // 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:684
const int EDGES_PENTAGON
Definition: display.h:147
DisplayRotation get_rotation() const
Definition: display.h:602
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:626
This class simplifies creating components that periodically check a state.
Definition: component.h:283
const DisplayPage * get_active_page() const
Definition: display.h:592
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:650
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:636
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:616
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:703
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:710
const int EDGES_NONAGON
Definition: display.h:151
const LogString * text_align_to_string(TextAlign textalign)
Definition: display.cpp:824
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:594
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:600
std::vector< Rect > clipping_rectangle_
Definition: display.h:686
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