ESPHome  2023.3.1
display_buffer.h
Go to the documentation of this file.
1 #pragma once
2 
4 #include "esphome/core/defines.h"
6 #include "display_color_utils.h"
7 #include <cstdarg>
8 #include <vector>
9 
10 #ifdef USE_TIME
12 #endif
13 
14 #ifdef USE_GRAPH
16 #endif
17 
18 #ifdef USE_QR_CODE
20 #endif
21 
22 namespace esphome {
23 namespace display {
24 
49 enum class TextAlign {
50  TOP = 0x00,
51  CENTER_VERTICAL = 0x01,
52  BASELINE = 0x02,
53  BOTTOM = 0x04,
54 
55  LEFT = 0x00,
56  CENTER_HORIZONTAL = 0x08,
57  RIGHT = 0x10,
58 
59  TOP_LEFT = TOP | LEFT,
61  TOP_RIGHT = TOP | RIGHT,
62 
66 
70 
74 };
75 
77 extern const Color COLOR_OFF;
79 extern const Color COLOR_ON;
80 
81 enum ImageType {
87 };
88 
93 };
94 
100 };
101 
102 static const int16_t VALUE_NO_SET = 32766;
103 
104 class Rect {
105  public:
106  int16_t x;
107  int16_t y;
108  int16_t w;
109  int16_t h;
110 
111  Rect() : x(VALUE_NO_SET), y(VALUE_NO_SET), w(VALUE_NO_SET), h(VALUE_NO_SET) {} // NOLINT
112  inline Rect(int16_t x, int16_t y, int16_t w, int16_t h) ALWAYS_INLINE : x(x), y(y), w(w), h(h) {}
113  inline int16_t x2() { return this->x + this->w; };
114  inline int16_t y2() { return this->y + this->h; };
115 
116  inline bool is_set() ALWAYS_INLINE { return (this->h != VALUE_NO_SET) && (this->w != VALUE_NO_SET); }
117 
118  void expand(int16_t horizontal, int16_t vertical);
119 
120  void extend(Rect rect);
121  void shrink(Rect rect);
122 
123  bool inside(Rect rect, bool absolute = true);
124  bool inside(int16_t test_x, int16_t test_y, bool absolute = true);
125  bool equal(Rect rect);
126  void info(const std::string &prefix = "rect info:");
127 };
128 
129 class Font;
130 class Image;
131 class DisplayBuffer;
132 class DisplayPage;
134 
135 using display_writer_t = std::function<void(DisplayBuffer &)>;
136 
137 #define LOG_DISPLAY(prefix, type, obj) \
138  if ((obj) != nullptr) { \
139  ESP_LOGCONFIG(TAG, prefix type); \
140  ESP_LOGCONFIG(TAG, "%s Rotations: %d °", prefix, (obj)->rotation_); \
141  ESP_LOGCONFIG(TAG, "%s Dimensions: %dpx x %dpx", prefix, (obj)->get_width(), (obj)->get_height()); \
142  }
143 
145  public:
147  virtual void fill(Color color);
149  void clear();
150 
152  int get_width();
154  int get_height();
155 
157  void draw_pixel_at(int x, int y, Color color = COLOR_ON);
158 
160  void line(int x1, int y1, int x2, int y2, Color color = COLOR_ON);
161 
163  void horizontal_line(int x, int y, int width, Color color = COLOR_ON);
164 
166  void vertical_line(int x, int y, int height, Color color = COLOR_ON);
167 
170  void rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON);
171 
173  void filled_rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON);
174 
176  void circle(int center_x, int center_xy, int radius, Color color = COLOR_ON);
177 
179  void filled_circle(int center_x, int center_y, int radius, Color color = COLOR_ON);
180 
190  void print(int x, int y, Font *font, Color color, TextAlign align, const char *text);
191 
200  void print(int x, int y, Font *font, Color color, const char *text);
201 
210  void print(int x, int y, Font *font, TextAlign align, const char *text);
211 
219  void print(int x, int y, Font *font, const char *text);
220 
231  void printf(int x, int y, Font *font, Color color, TextAlign align, const char *format, ...)
232  __attribute__((format(printf, 7, 8)));
233 
243  void printf(int x, int y, Font *font, Color color, const char *format, ...) __attribute__((format(printf, 6, 7)));
244 
254  void printf(int x, int y, Font *font, TextAlign align, const char *format, ...) __attribute__((format(printf, 6, 7)));
255 
264  void printf(int x, int y, Font *font, const char *format, ...) __attribute__((format(printf, 5, 6)));
265 
266 #ifdef USE_TIME
267 
277  void strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, time::ESPTime time)
278  __attribute__((format(strftime, 7, 0)));
279 
289  void strftime(int x, int y, Font *font, Color color, const char *format, time::ESPTime time)
290  __attribute__((format(strftime, 6, 0)));
291 
301  void strftime(int x, int y, Font *font, TextAlign align, const char *format, time::ESPTime time)
302  __attribute__((format(strftime, 6, 0)));
303 
312  void strftime(int x, int y, Font *font, const char *format, time::ESPTime time)
313  __attribute__((format(strftime, 5, 0)));
314 #endif
315 
324  void image(int x, int y, Image *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
325 
326 #ifdef USE_GRAPH
327 
334  void graph(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
335 
347  void legend(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
348 #endif // USE_GRAPH
349 
350 #ifdef USE_QR_CODE
351 
358  void qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on = COLOR_ON, int scale = 1);
359 #endif
360 
373  void get_text_bounds(int x, int y, const char *text, Font *font, TextAlign align, int *x1, int *y1, int *width,
374  int *height);
375 
377  void set_writer(display_writer_t &&writer);
378 
379  void show_page(DisplayPage *page);
380  void show_next_page();
381  void show_prev_page();
382 
383  void set_pages(std::vector<DisplayPage *> pages);
384 
385  const DisplayPage *get_active_page() const { return this->page_; }
386 
387  void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t) { this->on_page_change_triggers_.push_back(t); }
388 
390  void set_rotation(DisplayRotation rotation);
391 
392  // Internal method to set display auto clearing.
393  void set_auto_clear(bool auto_clear_enabled) { this->auto_clear_enabled_ = auto_clear_enabled; }
394 
395  virtual int get_height_internal() = 0;
396  virtual int get_width_internal() = 0;
397  DisplayRotation get_rotation() const { return this->rotation_; }
398 
402  virtual DisplayType get_display_type() = 0;
403 
410  void start_clipping(Rect rect);
411  void start_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
412  start_clipping(Rect(left, top, right - left, bottom - top));
413  };
414 
420  void extend_clipping(Rect rect);
421  void extend_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
422  this->extend_clipping(Rect(left, top, right - left, bottom - top));
423  };
424 
430  void shrink_clipping(Rect rect);
431  void shrink_clipping(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) {
432  this->shrink_clipping(Rect(left, top, right - left, bottom - top));
433  };
434 
437  void end_clipping();
438 
443  Rect get_clipping();
444 
445  bool is_clipping() const { return !this->clipping_rectangle_.empty(); }
446 
447  protected:
448  void vprintf_(int x, int y, Font *font, Color color, TextAlign align, const char *format, va_list arg);
449 
450  virtual void draw_absolute_pixel_internal(int x, int y, Color color) = 0;
451 
452  void init_internal_(uint32_t buffer_length);
453 
454  void do_update_();
455 
456  uint8_t *buffer_{nullptr};
459  DisplayPage *page_{nullptr};
460  DisplayPage *previous_page_{nullptr};
461  std::vector<DisplayOnPageChangeTrigger *> on_page_change_triggers_;
462  bool auto_clear_enabled_{true};
463  std::vector<Rect> clipping_rectangle_;
464 };
465 
466 class DisplayPage {
467  public:
469  void show();
470  void show_next();
471  void show_prev();
472  void set_parent(DisplayBuffer *parent);
473  void set_prev(DisplayPage *prev);
474  void set_next(DisplayPage *next);
475  const display_writer_t &get_writer() const;
476 
477  protected:
480  DisplayPage *prev_{nullptr};
481  DisplayPage *next_{nullptr};
482 };
483 
484 struct GlyphData {
485  const char *a_char;
486  const uint8_t *data;
487  int offset_x;
488  int offset_y;
489  int width;
490  int height;
491 };
492 
493 class Glyph {
494  public:
495  Glyph(const GlyphData *data) : glyph_data_(data) {}
496 
497  bool get_pixel(int x, int y) const;
498 
499  const char *get_char() const;
500 
501  bool compare_to(const char *str) const;
502 
503  int match_length(const char *str) const;
504 
505  void scan_area(int *x1, int *y1, int *width, int *height) const;
506 
507  protected:
508  friend Font;
510 
512 };
513 
514 class Font {
515  public:
522  Font(const GlyphData *data, int data_nr, int baseline, int height);
523 
524  int match_next_glyph(const char *str, int *match_length);
525 
526  void measure(const char *str, int *width, int *x_offset, int *baseline, int *height);
527  inline int get_baseline() { return this->baseline_; }
528  inline int get_height() { return this->height_; }
529 
530  const std::vector<Glyph, ExternalRAMAllocator<Glyph>> &get_glyphs() const { return glyphs_; }
531 
532  protected:
533  std::vector<Glyph, ExternalRAMAllocator<Glyph>> glyphs_;
535  int height_;
536 };
537 
538 class Image {
539  public:
540  Image(const uint8_t *data_start, int width, int height, ImageType type);
541  virtual bool get_pixel(int x, int y) const;
542  virtual Color get_color_pixel(int x, int y) const;
543  virtual Color get_rgb565_pixel(int x, int y) const;
544  virtual Color get_grayscale_pixel(int x, int y) const;
545  int get_width() const;
546  int get_height() const;
547  ImageType get_type() const;
548 
549  virtual int get_current_frame() const;
550 
551  protected:
552  int width_;
553  int height_;
555  const uint8_t *data_start_;
556 };
557 
558 class Animation : public Image {
559  public:
560  Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type);
561  bool get_pixel(int x, int y) const override;
562  Color get_color_pixel(int x, int y) const override;
563  Color get_rgb565_pixel(int x, int y) const override;
564  Color get_grayscale_pixel(int x, int y) const override;
565 
566  int get_animation_frame_count() const;
567  int get_current_frame() const override;
568  void next_frame();
569  void prev_frame();
570 
575  void set_frame(int frame);
576 
577  protected:
580 };
581 
582 template<typename... Ts> class DisplayPageShowAction : public Action<Ts...> {
583  public:
585 
586  void play(Ts... x) override {
587  auto *page = this->page_.value(x...);
588  if (page != nullptr) {
589  page->show();
590  }
591  }
592 };
593 
594 template<typename... Ts> class DisplayPageShowNextAction : public Action<Ts...> {
595  public:
596  DisplayPageShowNextAction(DisplayBuffer *buffer) : buffer_(buffer) {}
597 
598  void play(Ts... x) override { this->buffer_->show_next_page(); }
599 
601 };
602 
603 template<typename... Ts> class DisplayPageShowPrevAction : public Action<Ts...> {
604  public:
605  DisplayPageShowPrevAction(DisplayBuffer *buffer) : buffer_(buffer) {}
606 
607  void play(Ts... x) override { this->buffer_->show_prev_page(); }
608 
610 };
611 
612 template<typename... Ts> class DisplayIsDisplayingPageCondition : public Condition<Ts...> {
613  public:
614  DisplayIsDisplayingPageCondition(DisplayBuffer *parent) : parent_(parent) {}
615 
616  void set_page(DisplayPage *page) { this->page_ = page; }
617  bool check(Ts... x) override { return this->parent_->get_active_page() == this->page_; }
618 
619  protected:
622 };
623 
624 class DisplayOnPageChangeTrigger : public Trigger<DisplayPage *, DisplayPage *> {
625  public:
627  void process(DisplayPage *from, DisplayPage *to);
628  void set_from(DisplayPage *p) { this->from_ = p; }
629  void set_to(DisplayPage *p) { this->to_ = p; }
630 
631  protected:
632  DisplayPage *from_{nullptr};
633  DisplayPage *to_{nullptr};
634 };
635 
636 } // namespace display
637 } // namespace esphome
void extend_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom)
void set_auto_clear(bool auto_clear_enabled)
std::vector< Glyph, ExternalRAMAllocator< Glyph > > glyphs_
DisplayPageShowPrevAction(DisplayBuffer *buffer)
int16_t x
X coordinate of corner.
const Color COLOR_OFF(0, 0, 0, 0)
Turn the pixel OFF.
DisplayRotation get_rotation() const
int16_t h
Height of region.
const uint8_t * data_start_
int16_t y
Y coordinate of corner.
Glyph(const GlyphData *data)
DisplayPageShowNextAction(DisplayBuffer *buffer)
TextAlign
TextAlign is used to tell the display class how to position a piece of text.
A more user-friendly version of struct tm from time.h.
Base class for all automation conditions.
Definition: automation.h:74
const DisplayPage * get_active_page() const
Rect(int16_t x, int16_t y, int16_t w, int16_t h) ALWAYS_INLINE
uint8_t type
bool is_set() ALWAYS_INLINE
Y coordinate of corner.
std::vector< DisplayOnPageChangeTrigger * > on_page_change_triggers_
enum esphome::EntityCategory __attribute__
const std::vector< Glyph, ExternalRAMAllocator< Glyph > > & get_glyphs() const
const Color COLOR_ON(255, 255, 255, 255)
Turn the pixel ON.
TEMPLATABLE_VALUE(DisplayPage *, page) void play(Ts... x) override
int16_t y2()
X coordinate of corner.
uint8_t h
Definition: bl0939.h:21
Definition: a4988.cpp:4
const GlyphData * glyph_data_
void shrink_clipping(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom)
void start_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom)
std::function< void(DisplayBuffer &)> display_writer_t
std::vector< Rect > clipping_rectangle_
void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t)
int16_t w
Width of region.