ESPHome  2022.6.2
display_buffer.cpp
Go to the documentation of this file.
1 #include "display_buffer.h"
2 
3 #include <utility>
5 #include "esphome/core/color.h"
6 #include "esphome/core/log.h"
7 #include "esphome/core/hal.h"
8 #include "esphome/core/helpers.h"
9 
10 namespace esphome {
11 namespace display {
12 
13 static const char *const TAG = "display";
14 
15 const Color COLOR_OFF(0, 0, 0, 0);
16 const Color COLOR_ON(255, 255, 255, 255);
17 
18 void DisplayBuffer::init_internal_(uint32_t buffer_length) {
20  this->buffer_ = allocator.allocate(buffer_length);
21  if (this->buffer_ == nullptr) {
22  ESP_LOGE(TAG, "Could not allocate buffer for display!");
23  return;
24  }
25  this->clear();
26 }
27 void DisplayBuffer::fill(Color color) { this->filled_rectangle(0, 0, this->get_width(), this->get_height(), color); }
28 void DisplayBuffer::clear() { this->fill(COLOR_OFF); }
30  switch (this->rotation_) {
33  return this->get_height_internal();
36  default:
37  return this->get_width_internal();
38  }
39 }
41  switch (this->rotation_) {
44  return this->get_height_internal();
47  default:
48  return this->get_width_internal();
49  }
50 }
51 void DisplayBuffer::set_rotation(DisplayRotation rotation) { this->rotation_ = rotation; }
52 void HOT DisplayBuffer::draw_pixel_at(int x, int y, Color color) {
53  switch (this->rotation_) {
55  break;
57  std::swap(x, y);
58  x = this->get_width_internal() - x - 1;
59  break;
61  x = this->get_width_internal() - x - 1;
62  y = this->get_height_internal() - y - 1;
63  break;
65  std::swap(x, y);
66  y = this->get_height_internal() - y - 1;
67  break;
68  }
69  this->draw_absolute_pixel_internal(x, y, color);
70  App.feed_wdt();
71 }
72 void HOT DisplayBuffer::line(int x1, int y1, int x2, int y2, Color color) {
73  const int32_t dx = abs(x2 - x1), sx = x1 < x2 ? 1 : -1;
74  const int32_t dy = -abs(y2 - y1), sy = y1 < y2 ? 1 : -1;
75  int32_t err = dx + dy;
76 
77  while (true) {
78  this->draw_pixel_at(x1, y1, color);
79  if (x1 == x2 && y1 == y2)
80  break;
81  int32_t e2 = 2 * err;
82  if (e2 >= dy) {
83  err += dy;
84  x1 += sx;
85  }
86  if (e2 <= dx) {
87  err += dx;
88  y1 += sy;
89  }
90  }
91 }
92 void HOT DisplayBuffer::horizontal_line(int x, int y, int width, Color color) {
93  // Future: Could be made more efficient by manipulating buffer directly in certain rotations.
94  for (int i = x; i < x + width; i++)
95  this->draw_pixel_at(i, y, color);
96 }
97 void HOT DisplayBuffer::vertical_line(int x, int y, int height, Color color) {
98  // Future: Could be made more efficient by manipulating buffer directly in certain rotations.
99  for (int i = y; i < y + height; i++)
100  this->draw_pixel_at(x, i, color);
101 }
102 void DisplayBuffer::rectangle(int x1, int y1, int width, int height, Color color) {
103  this->horizontal_line(x1, y1, width, color);
104  this->horizontal_line(x1, y1 + height - 1, width, color);
105  this->vertical_line(x1, y1, height, color);
106  this->vertical_line(x1 + width - 1, y1, height, color);
107 }
108 void DisplayBuffer::filled_rectangle(int x1, int y1, int width, int height, Color color) {
109  // Future: Use vertical_line and horizontal_line methods depending on rotation to reduce memory accesses.
110  for (int i = y1; i < y1 + height; i++) {
111  this->horizontal_line(x1, i, width, color);
112  }
113 }
114 void HOT DisplayBuffer::circle(int center_x, int center_xy, int radius, Color color) {
115  int dx = -radius;
116  int dy = 0;
117  int err = 2 - 2 * radius;
118  int e2;
119 
120  do {
121  this->draw_pixel_at(center_x - dx, center_xy + dy, color);
122  this->draw_pixel_at(center_x + dx, center_xy + dy, color);
123  this->draw_pixel_at(center_x + dx, center_xy - dy, color);
124  this->draw_pixel_at(center_x - dx, center_xy - dy, color);
125  e2 = err;
126  if (e2 < dy) {
127  err += ++dy * 2 + 1;
128  if (-dx == dy && e2 <= dx) {
129  e2 = 0;
130  }
131  }
132  if (e2 > dx) {
133  err += ++dx * 2 + 1;
134  }
135  } while (dx <= 0);
136 }
137 void DisplayBuffer::filled_circle(int center_x, int center_y, int radius, Color color) {
138  int dx = -int32_t(radius);
139  int dy = 0;
140  int err = 2 - 2 * radius;
141  int e2;
142 
143  do {
144  this->draw_pixel_at(center_x - dx, center_y + dy, color);
145  this->draw_pixel_at(center_x + dx, center_y + dy, color);
146  this->draw_pixel_at(center_x + dx, center_y - dy, color);
147  this->draw_pixel_at(center_x - dx, center_y - dy, color);
148  int hline_width = 2 * (-dx) + 1;
149  this->horizontal_line(center_x + dx, center_y + dy, hline_width, color);
150  this->horizontal_line(center_x + dx, center_y - dy, hline_width, color);
151  e2 = err;
152  if (e2 < dy) {
153  err += ++dy * 2 + 1;
154  if (-dx == dy && e2 <= dx) {
155  e2 = 0;
156  }
157  }
158  if (e2 > dx) {
159  err += ++dx * 2 + 1;
160  }
161  } while (dx <= 0);
162 }
163 
164 void DisplayBuffer::print(int x, int y, Font *font, Color color, TextAlign align, const char *text) {
165  int x_start, y_start;
166  int width, height;
167  this->get_text_bounds(x, y, text, font, align, &x_start, &y_start, &width, &height);
168 
169  int i = 0;
170  int x_at = x_start;
171  while (text[i] != '\0') {
172  int match_length;
173  int glyph_n = font->match_next_glyph(text + i, &match_length);
174  if (glyph_n < 0) {
175  // Unknown char, skip
176  ESP_LOGW(TAG, "Encountered character without representation in font: '%c'", text[i]);
177  if (!font->get_glyphs().empty()) {
178  uint8_t glyph_width = font->get_glyphs()[0].glyph_data_->width;
179  for (int glyph_x = 0; glyph_x < glyph_width; glyph_x++) {
180  for (int glyph_y = 0; glyph_y < height; glyph_y++)
181  this->draw_pixel_at(glyph_x + x_at, glyph_y + y_start, color);
182  }
183  x_at += glyph_width;
184  }
185 
186  i++;
187  continue;
188  }
189 
190  const Glyph &glyph = font->get_glyphs()[glyph_n];
191  int scan_x1, scan_y1, scan_width, scan_height;
192  glyph.scan_area(&scan_x1, &scan_y1, &scan_width, &scan_height);
193 
194  for (int glyph_x = scan_x1; glyph_x < scan_x1 + scan_width; glyph_x++) {
195  for (int glyph_y = scan_y1; glyph_y < scan_y1 + scan_height; glyph_y++) {
196  if (glyph.get_pixel(glyph_x, glyph_y)) {
197  this->draw_pixel_at(glyph_x + x_at, glyph_y + y_start, color);
198  }
199  }
200  }
201 
202  x_at += glyph.glyph_data_->width + glyph.glyph_data_->offset_x;
203 
204  i += match_length;
205  }
206 }
207 void DisplayBuffer::vprintf_(int x, int y, Font *font, Color color, TextAlign align, const char *format, va_list arg) {
208  char buffer[256];
209  int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
210  if (ret > 0)
211  this->print(x, y, font, color, align, buffer);
212 }
213 
214 void DisplayBuffer::image(int x, int y, Image *image, Color color_on, Color color_off) {
215  switch (image->get_type()) {
216  case IMAGE_TYPE_BINARY:
217  for (int img_x = 0; img_x < image->get_width(); img_x++) {
218  for (int img_y = 0; img_y < image->get_height(); img_y++) {
219  this->draw_pixel_at(x + img_x, y + img_y, image->get_pixel(img_x, img_y) ? color_on : color_off);
220  }
221  }
222  break;
224  for (int img_x = 0; img_x < image->get_width(); img_x++) {
225  for (int img_y = 0; img_y < image->get_height(); img_y++) {
226  this->draw_pixel_at(x + img_x, y + img_y, image->get_grayscale_pixel(img_x, img_y));
227  }
228  }
229  break;
230  case IMAGE_TYPE_RGB24:
231  for (int img_x = 0; img_x < image->get_width(); img_x++) {
232  for (int img_y = 0; img_y < image->get_height(); img_y++) {
233  this->draw_pixel_at(x + img_x, y + img_y, image->get_color_pixel(img_x, img_y));
234  }
235  }
236  break;
238  for (int img_x = 0; img_x < image->get_width(); img_x++) {
239  for (int img_y = 0; img_y < image->get_height(); img_y++) {
240  if (image->get_pixel(img_x, img_y))
241  this->draw_pixel_at(x + img_x, y + img_y, color_on);
242  }
243  }
244  break;
245  case IMAGE_TYPE_RGB565:
246  for (int img_x = 0; img_x < image->get_width(); img_x++) {
247  for (int img_y = 0; img_y < image->get_height(); img_y++) {
248  this->draw_pixel_at(x + img_x, y + img_y, image->get_rgb565_pixel(img_x, img_y));
249  }
250  }
251  break;
252  }
253 }
254 
255 #ifdef USE_GRAPH
256 void DisplayBuffer::graph(int x, int y, graph::Graph *graph, Color color_on) { graph->draw(this, x, y, color_on); }
257 void DisplayBuffer::legend(int x, int y, graph::Graph *graph, Color color_on) {
258  graph->draw_legend(this, x, y, color_on);
259 }
260 #endif // USE_GRAPH
261 
262 #ifdef USE_QR_CODE
263 void DisplayBuffer::qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on, int scale) {
264  qr_code->draw(this, x, y, color_on, scale);
265 }
266 #endif // USE_QR_CODE
267 
268 void DisplayBuffer::get_text_bounds(int x, int y, const char *text, Font *font, TextAlign align, int *x1, int *y1,
269  int *width, int *height) {
270  int x_offset, baseline;
271  font->measure(text, width, &x_offset, &baseline, height);
272 
273  auto x_align = TextAlign(int(align) & 0x18);
274  auto y_align = TextAlign(int(align) & 0x07);
275 
276  switch (x_align) {
277  case TextAlign::RIGHT:
278  *x1 = x - *width;
279  break;
281  *x1 = x - (*width) / 2;
282  break;
283  case TextAlign::LEFT:
284  default:
285  // LEFT
286  *x1 = x;
287  break;
288  }
289 
290  switch (y_align) {
291  case TextAlign::BOTTOM:
292  *y1 = y - *height;
293  break;
294  case TextAlign::BASELINE:
295  *y1 = y - baseline;
296  break;
298  *y1 = y - (*height) / 2;
299  break;
300  case TextAlign::TOP:
301  default:
302  *y1 = y;
303  break;
304  }
305 }
306 void DisplayBuffer::print(int x, int y, Font *font, Color color, const char *text) {
307  this->print(x, y, font, color, TextAlign::TOP_LEFT, text);
308 }
309 void DisplayBuffer::print(int x, int y, Font *font, TextAlign align, const char *text) {
310  this->print(x, y, font, COLOR_ON, align, text);
311 }
312 void DisplayBuffer::print(int x, int y, Font *font, const char *text) {
313  this->print(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, text);
314 }
315 void DisplayBuffer::printf(int x, int y, Font *font, Color color, TextAlign align, const char *format, ...) {
316  va_list arg;
317  va_start(arg, format);
318  this->vprintf_(x, y, font, color, align, format, arg);
319  va_end(arg);
320 }
321 void DisplayBuffer::printf(int x, int y, Font *font, Color color, const char *format, ...) {
322  va_list arg;
323  va_start(arg, format);
324  this->vprintf_(x, y, font, color, TextAlign::TOP_LEFT, format, arg);
325  va_end(arg);
326 }
327 void DisplayBuffer::printf(int x, int y, Font *font, TextAlign align, const char *format, ...) {
328  va_list arg;
329  va_start(arg, format);
330  this->vprintf_(x, y, font, COLOR_ON, align, format, arg);
331  va_end(arg);
332 }
333 void DisplayBuffer::printf(int x, int y, Font *font, const char *format, ...) {
334  va_list arg;
335  va_start(arg, format);
336  this->vprintf_(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, arg);
337  va_end(arg);
338 }
339 void DisplayBuffer::set_writer(display_writer_t &&writer) { this->writer_ = writer; }
340 void DisplayBuffer::set_pages(std::vector<DisplayPage *> pages) {
341  for (auto *page : pages)
342  page->set_parent(this);
343 
344  for (uint32_t i = 0; i < pages.size() - 1; i++) {
345  pages[i]->set_next(pages[i + 1]);
346  pages[i + 1]->set_prev(pages[i]);
347  }
348  pages[0]->set_prev(pages[pages.size() - 1]);
349  pages[pages.size() - 1]->set_next(pages[0]);
350  this->show_page(pages[0]);
351 }
353  this->previous_page_ = this->page_;
354  this->page_ = page;
355  if (this->previous_page_ != this->page_) {
356  for (auto *t : on_page_change_triggers_)
357  t->process(this->previous_page_, this->page_);
358  }
359 }
363  if (this->auto_clear_enabled_) {
364  this->clear();
365  }
366  if (this->page_ != nullptr) {
367  this->page_->get_writer()(*this);
368  } else if (this->writer_.has_value()) {
369  (*this->writer_)(*this);
370  }
371 }
373  if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to))
374  this->trigger(from, to);
375 }
376 #ifdef USE_TIME
377 void DisplayBuffer::strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format,
378  time::ESPTime time) {
379  char buffer[64];
380  size_t ret = time.strftime(buffer, sizeof(buffer), format);
381  if (ret > 0)
382  this->print(x, y, font, color, align, buffer);
383 }
384 void DisplayBuffer::strftime(int x, int y, Font *font, Color color, const char *format, time::ESPTime time) {
385  this->strftime(x, y, font, color, TextAlign::TOP_LEFT, format, time);
386 }
387 void DisplayBuffer::strftime(int x, int y, Font *font, TextAlign align, const char *format, time::ESPTime time) {
388  this->strftime(x, y, font, COLOR_ON, align, format, time);
389 }
390 void DisplayBuffer::strftime(int x, int y, Font *font, const char *format, time::ESPTime time) {
391  this->strftime(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, time);
392 }
393 #endif
394 
395 bool Glyph::get_pixel(int x, int y) const {
396  const int x_data = x - this->glyph_data_->offset_x;
397  const int y_data = y - this->glyph_data_->offset_y;
398  if (x_data < 0 || x_data >= this->glyph_data_->width || y_data < 0 || y_data >= this->glyph_data_->height)
399  return false;
400  const uint32_t width_8 = ((this->glyph_data_->width + 7u) / 8u) * 8u;
401  const uint32_t pos = x_data + y_data * width_8;
402  return progmem_read_byte(this->glyph_data_->data + (pos / 8u)) & (0x80 >> (pos % 8u));
403 }
404 const char *Glyph::get_char() const { return this->glyph_data_->a_char; }
405 bool Glyph::compare_to(const char *str) const {
406  // 1 -> this->char_
407  // 2 -> str
408  for (uint32_t i = 0;; i++) {
409  if (this->glyph_data_->a_char[i] == '\0')
410  return true;
411  if (str[i] == '\0')
412  return false;
413  if (this->glyph_data_->a_char[i] > str[i])
414  return false;
415  if (this->glyph_data_->a_char[i] < str[i])
416  return true;
417  }
418  // this should not happen
419  return false;
420 }
421 int Glyph::match_length(const char *str) const {
422  for (uint32_t i = 0;; i++) {
423  if (this->glyph_data_->a_char[i] == '\0')
424  return i;
425  if (str[i] != this->glyph_data_->a_char[i])
426  return 0;
427  }
428  // this should not happen
429  return 0;
430 }
431 void Glyph::scan_area(int *x1, int *y1, int *width, int *height) const {
432  *x1 = this->glyph_data_->offset_x;
433  *y1 = this->glyph_data_->offset_y;
434  *width = this->glyph_data_->width;
435  *height = this->glyph_data_->height;
436 }
437 int Font::match_next_glyph(const char *str, int *match_length) {
438  int lo = 0;
439  int hi = this->glyphs_.size() - 1;
440  while (lo != hi) {
441  int mid = (lo + hi + 1) / 2;
442  if (this->glyphs_[mid].compare_to(str)) {
443  lo = mid;
444  } else {
445  hi = mid - 1;
446  }
447  }
448  *match_length = this->glyphs_[lo].match_length(str);
449  if (*match_length <= 0)
450  return -1;
451  return lo;
452 }
453 void Font::measure(const char *str, int *width, int *x_offset, int *baseline, int *height) {
454  *baseline = this->baseline_;
455  *height = this->bottom_;
456  int i = 0;
457  int min_x = 0;
458  bool has_char = false;
459  int x = 0;
460  while (str[i] != '\0') {
461  int match_length;
462  int glyph_n = this->match_next_glyph(str + i, &match_length);
463  if (glyph_n < 0) {
464  // Unknown char, skip
465  if (!this->get_glyphs().empty())
466  x += this->get_glyphs()[0].glyph_data_->width;
467  i++;
468  continue;
469  }
470 
471  const Glyph &glyph = this->glyphs_[glyph_n];
472  if (!has_char) {
473  min_x = glyph.glyph_data_->offset_x;
474  } else {
475  min_x = std::min(min_x, x + glyph.glyph_data_->offset_x);
476  }
477  x += glyph.glyph_data_->width + glyph.glyph_data_->offset_x;
478 
479  i += match_length;
480  has_char = true;
481  }
482  *x_offset = min_x;
483  *width = x - min_x;
484 }
485 const std::vector<Glyph> &Font::get_glyphs() const { return this->glyphs_; }
486 Font::Font(const GlyphData *data, int data_nr, int baseline, int bottom) : baseline_(baseline), bottom_(bottom) {
487  for (int i = 0; i < data_nr; ++i)
488  glyphs_.emplace_back(data + i);
489 }
490 
491 bool Image::get_pixel(int x, int y) const {
492  if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
493  return false;
494  const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u;
495  const uint32_t pos = x + y * width_8;
496  return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u));
497 }
498 Color Image::get_color_pixel(int x, int y) const {
499  if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
500  return Color::BLACK;
501  const uint32_t pos = (x + y * this->width_) * 3;
502  const uint32_t color32 = (progmem_read_byte(this->data_start_ + pos + 2) << 0) |
503  (progmem_read_byte(this->data_start_ + pos + 1) << 8) |
504  (progmem_read_byte(this->data_start_ + pos + 0) << 16);
505  return Color(color32);
506 }
507 Color Image::get_rgb565_pixel(int x, int y) const {
508  if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
509  return Color::BLACK;
510  const uint32_t pos = (x + y * this->width_) * 2;
511  uint16_t rgb565 =
512  progmem_read_byte(this->data_start_ + pos + 0) << 8 | progmem_read_byte(this->data_start_ + pos + 1);
513  auto r = (rgb565 & 0xF800) >> 11;
514  auto g = (rgb565 & 0x07E0) >> 5;
515  auto b = rgb565 & 0x001F;
516  return Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2));
517 }
518 Color Image::get_grayscale_pixel(int x, int y) const {
519  if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
520  return Color::BLACK;
521  const uint32_t pos = (x + y * this->width_);
522  const uint8_t gray = progmem_read_byte(this->data_start_ + pos);
523  return Color(gray | gray << 8 | gray << 16 | gray << 24);
524 }
525 int Image::get_width() const { return this->width_; }
526 int Image::get_height() const { return this->height_; }
527 ImageType Image::get_type() const { return this->type_; }
528 Image::Image(const uint8_t *data_start, int width, int height, ImageType type)
529  : width_(width), height_(height), type_(type), data_start_(data_start) {}
530 
531 bool Animation::get_pixel(int x, int y) const {
532  if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
533  return false;
534  const uint32_t width_8 = ((this->width_ + 7u) / 8u) * 8u;
535  const uint32_t frame_index = this->height_ * width_8 * this->current_frame_;
536  if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
537  return false;
538  const uint32_t pos = x + y * width_8 + frame_index;
539  return progmem_read_byte(this->data_start_ + (pos / 8u)) & (0x80 >> (pos % 8u));
540 }
541 Color Animation::get_color_pixel(int x, int y) const {
542  if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
543  return Color::BLACK;
544  const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_;
545  if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
546  return Color::BLACK;
547  const uint32_t pos = (x + y * this->width_ + frame_index) * 3;
548  const uint32_t color32 = (progmem_read_byte(this->data_start_ + pos + 2) << 0) |
549  (progmem_read_byte(this->data_start_ + pos + 1) << 8) |
550  (progmem_read_byte(this->data_start_ + pos + 0) << 16);
551  return Color(color32);
552 }
553 Color Animation::get_rgb565_pixel(int x, int y) const {
554  if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
555  return Color::BLACK;
556  const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_;
557  if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
558  return Color::BLACK;
559  const uint32_t pos = (x + y * this->width_ + frame_index) * 2;
560  uint16_t rgb565 =
561  progmem_read_byte(this->data_start_ + pos + 0) << 8 | progmem_read_byte(this->data_start_ + pos + 1);
562  auto r = (rgb565 & 0xF800) >> 11;
563  auto g = (rgb565 & 0x07E0) >> 5;
564  auto b = rgb565 & 0x001F;
565  return Color((r << 3) | (r >> 2), (g << 2) | (g >> 4), (b << 3) | (b >> 2));
566 }
568  if (x < 0 || x >= this->width_ || y < 0 || y >= this->height_)
569  return Color::BLACK;
570  const uint32_t frame_index = this->width_ * this->height_ * this->current_frame_;
571  if (frame_index >= (uint32_t)(this->width_ * this->height_ * this->animation_frame_count_))
572  return Color::BLACK;
573  const uint32_t pos = (x + y * this->width_ + frame_index);
574  const uint8_t gray = progmem_read_byte(this->data_start_ + pos);
575  return Color(gray | gray << 8 | gray << 16 | gray << 24);
576 }
577 Animation::Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type)
578  : Image(data_start, width, height, type), current_frame_(0), animation_frame_count_(animation_frame_count) {}
580 int Animation::get_current_frame() const { return this->current_frame_; }
582  this->current_frame_++;
583  if (this->current_frame_ >= animation_frame_count_) {
584  this->current_frame_ = 0;
585  }
586 }
588  this->current_frame_--;
589  if (this->current_frame_ < 0) {
590  this->current_frame_ = this->animation_frame_count_ - 1;
591  }
592 }
593 
594 DisplayPage::DisplayPage(display_writer_t writer) : writer_(std::move(writer)) {}
595 void DisplayPage::show() { this->parent_->show_page(this); }
596 void DisplayPage::show_next() { this->next_->show(); }
597 void DisplayPage::show_prev() { this->prev_->show(); }
598 void DisplayPage::set_parent(DisplayBuffer *parent) { this->parent_ = parent; }
599 void DisplayPage::set_prev(DisplayPage *prev) { this->prev_ = prev; }
600 void DisplayPage::set_next(DisplayPage *next) { this->next_ = next; }
601 const display_writer_t &DisplayPage::get_writer() const { return this->writer_; }
602 
603 } // namespace display
604 } // namespace esphome
void printf(int x, int y, Font *font, Color color, TextAlign align, const char *format,...) __attribute__((format(printf
Evaluate the printf-format format and print the result with the anchor point at [x,y] with font.
void legend(int x, int y, graph::Graph *graph, Color color_on=COLOR_ON)
Draw the legend for graph with the top-left corner at [x,y] to the screen.
void void void void void strftime(int x, int y, Font *font, Color color, TextAlign align, const char *format, time::ESPTime time) __attribute__((format(strftime
Evaluate the strftime-format format and print the result with the anchor point at [x...
virtual Color get_grayscale_pixel(int x, int y) const
void show_page(DisplayPage *page)
virtual void draw_absolute_pixel_internal(int x, int y, Color color)=0
void draw(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color, int scale)
Definition: qr_code.cpp:36
void set_pages(std::vector< DisplayPage *> pages)
void qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on=COLOR_ON, int scale=1)
Draw the qr_code with the top-left corner at [x,y] to the screen.
Image(const uint8_t *data_start, int width, int height, ImageType type)
void scan_area(int *x1, int *y1, int *width, int *height) const
void filled_circle(int center_x, int center_y, int radius, Color color=COLOR_ON)
Fill a circle centered around [center_x,center_y] with the radius radius with the given color...
void filled_rectangle(int x1, int y1, int width, int height, Color color=COLOR_ON)
Fill a rectangle with the top left point at [x1,y1] and the bottom right point at [x1+width...
void set_next(DisplayPage *next)
void set_rotation(DisplayRotation rotation)
Internal method to set the display rotation with.
Color get_rgb565_pixel(int x, int y) const override
void clear()
Clear the entire screen by filling it with OFF pixels.
optional< display_writer_t > writer_
const Color COLOR_OFF(0, 0, 0, 0)
Turn the pixel OFF.
An STL allocator that uses SPI RAM.
Definition: helpers.h:591
STL namespace.
size_t strftime(char *buffer, size_t buffer_len, const char *format)
Convert this ESPTime struct to a null-terminated c string buffer as specified by the format argument...
void graph(int x, int y, graph::Graph *graph, Color color_on=COLOR_ON)
Draw the graph with the top-left corner at [x,y] to the screen.
virtual Color get_color_pixel(int x, int y) const
virtual int get_width_internal()=0
bool has_value() const
Definition: optional.h:87
bool get_pixel(int x, int y) const
DisplayPage(display_writer_t writer)
void vprintf_(int x, int y, Font *font, Color color, TextAlign align, const char *format, va_list arg)
const uint8_t * data_start_
void print(int x, int y, Font *font, Color color, TextAlign align, const char *text)
Print text with the anchor point at [x,y] with font.
const display_writer_t & get_writer() const
void init_internal_(uint32_t buffer_length)
bool compare_to(const char *str) const
void vertical_line(int x, int y, int height, Color color=COLOR_ON)
Draw a vertical line from the point [x,y] to [x,y+width] with the given color.
ImageType get_type() const
virtual void fill(Color color)
Fill the entire screen with the given color.
Color get_grayscale_pixel(int x, int y) const override
TextAlign
TextAlign is used to tell the display class how to position a piece of text.
void measure(const char *str, int *width, int *x_offset, int *baseline, int *height)
void line(int x1, int y1, int x2, int y2, Color color=COLOR_ON)
Draw a straight line from the point [x1,y1] to [x2,y2] with the given color.
void horizontal_line(int x, int y, int width, Color color=COLOR_ON)
Draw a horizontal line from the point [x,y] to [x+width,y] with the given color.
A more user-friendly version of struct tm from time.h.
void process(DisplayPage *from, DisplayPage *to)
const std::vector< Glyph > & get_glyphs() const
int match_length(const char *str) const
Color get_color_pixel(int x, int y) const override
int match_next_glyph(const char *str, int *match_length)
void circle(int center_x, int center_xy, int radius, Color color=COLOR_ON)
Draw the outline of a circle centered around [center_x,center_y] with the radius radius with the give...
uint8_t type
std::vector< Glyph > glyphs_
Application App
Global storage of Application pointer - only one Application can exist.
void set_writer(display_writer_t &&writer)
Internal method to set the display writer lambda.
void void void void void void void void void image(int x, int y, Image *image, Color color_on=COLOR_ON, Color color_off=COLOR_OFF)
Draw the image with the top-left corner at [x,y] to the screen.
std::vector< DisplayOnPageChangeTrigger * > on_page_change_triggers_
void swap(optional< T > &x, optional< T > &y)
Definition: optional.h:210
uint8_t progmem_read_byte(const uint8_t *addr)
Definition: core.cpp:56
const Color COLOR_ON(255, 255, 255, 255)
Turn the pixel ON.
void draw(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color)
Definition: graph.cpp:59
virtual int get_height_internal()=0
Font(const GlyphData *data, int data_nr, int baseline, int bottom)
Construct the font with the given glyphs.
static const Color BLACK
Definition: color.h:147
void get_text_bounds(int x, int y, const char *text, Font *font, TextAlign align, int *x1, int *y1, int *width, int *height)
Get the text bounds of the given string.
Definition: a4988.cpp:4
virtual Color get_rgb565_pixel(int x, int y) const
const GlyphData * glyph_data_
const char * get_char() const
std::function< void(DisplayBuffer &)> display_writer_t
void draw_legend(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color)
Definition: graph.cpp:299
void set_parent(DisplayBuffer *parent)
void draw_pixel_at(int x, int y, Color color=COLOR_ON)
Set a single pixel at the specified coordinates to the given color.
Animation(const uint8_t *data_start, int width, int height, uint32_t animation_frame_count, ImageType type)
int get_height()
Get the height of the image in pixels with rotation applied.
void rectangle(int x1, int y1, int width, int height, Color color=COLOR_ON)
Draw the outline of a rectangle with the top left point at [x1,y1] and the bottom right point at [x1+...
virtual bool get_pixel(int x, int y) const
void set_prev(DisplayPage *prev)
int get_width()
Get the width of the image in pixels with rotation applied.
bool get_pixel(int x, int y) const override