mirror of
https://github.com/esphome/esphome.git
synced 2024-12-22 13:34:54 +01:00
display: split DisplayBuffer
and Display
(#5001)
This commit is contained in:
parent
301a78f983
commit
677b2c6618
15 changed files with 960 additions and 902 deletions
343
esphome/components/display/display.cpp
Normal file
343
esphome/components/display/display.cpp
Normal file
|
@ -0,0 +1,343 @@
|
|||
#include "display.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
namespace display {
|
||||
|
||||
static const char *const TAG = "display";
|
||||
|
||||
const Color COLOR_OFF(0, 0, 0, 0);
|
||||
const Color COLOR_ON(255, 255, 255, 255);
|
||||
|
||||
void Display::fill(Color color) { this->filled_rectangle(0, 0, this->get_width(), this->get_height(), color); }
|
||||
void Display::clear() { this->fill(COLOR_OFF); }
|
||||
void Display::set_rotation(DisplayRotation rotation) { this->rotation_ = rotation; }
|
||||
void HOT Display::line(int x1, int y1, int x2, int y2, Color color) {
|
||||
const int32_t dx = abs(x2 - x1), sx = x1 < x2 ? 1 : -1;
|
||||
const int32_t dy = -abs(y2 - y1), sy = y1 < y2 ? 1 : -1;
|
||||
int32_t err = dx + dy;
|
||||
|
||||
while (true) {
|
||||
this->draw_pixel_at(x1, y1, color);
|
||||
if (x1 == x2 && y1 == y2)
|
||||
break;
|
||||
int32_t e2 = 2 * err;
|
||||
if (e2 >= dy) {
|
||||
err += dy;
|
||||
x1 += sx;
|
||||
}
|
||||
if (e2 <= dx) {
|
||||
err += dx;
|
||||
y1 += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
void HOT Display::horizontal_line(int x, int y, int width, Color color) {
|
||||
// Future: Could be made more efficient by manipulating buffer directly in certain rotations.
|
||||
for (int i = x; i < x + width; i++)
|
||||
this->draw_pixel_at(i, y, color);
|
||||
}
|
||||
void HOT Display::vertical_line(int x, int y, int height, Color color) {
|
||||
// Future: Could be made more efficient by manipulating buffer directly in certain rotations.
|
||||
for (int i = y; i < y + height; i++)
|
||||
this->draw_pixel_at(x, i, color);
|
||||
}
|
||||
void Display::rectangle(int x1, int y1, int width, int height, Color color) {
|
||||
this->horizontal_line(x1, y1, width, color);
|
||||
this->horizontal_line(x1, y1 + height - 1, width, color);
|
||||
this->vertical_line(x1, y1, height, color);
|
||||
this->vertical_line(x1 + width - 1, y1, height, color);
|
||||
}
|
||||
void Display::filled_rectangle(int x1, int y1, int width, int height, Color color) {
|
||||
// Future: Use vertical_line and horizontal_line methods depending on rotation to reduce memory accesses.
|
||||
for (int i = y1; i < y1 + height; i++) {
|
||||
this->horizontal_line(x1, i, width, color);
|
||||
}
|
||||
}
|
||||
void HOT Display::circle(int center_x, int center_xy, int radius, Color color) {
|
||||
int dx = -radius;
|
||||
int dy = 0;
|
||||
int err = 2 - 2 * radius;
|
||||
int e2;
|
||||
|
||||
do {
|
||||
this->draw_pixel_at(center_x - dx, center_xy + dy, color);
|
||||
this->draw_pixel_at(center_x + dx, center_xy + dy, color);
|
||||
this->draw_pixel_at(center_x + dx, center_xy - dy, color);
|
||||
this->draw_pixel_at(center_x - dx, center_xy - dy, color);
|
||||
e2 = err;
|
||||
if (e2 < dy) {
|
||||
err += ++dy * 2 + 1;
|
||||
if (-dx == dy && e2 <= dx) {
|
||||
e2 = 0;
|
||||
}
|
||||
}
|
||||
if (e2 > dx) {
|
||||
err += ++dx * 2 + 1;
|
||||
}
|
||||
} while (dx <= 0);
|
||||
}
|
||||
void Display::filled_circle(int center_x, int center_y, int radius, Color color) {
|
||||
int dx = -int32_t(radius);
|
||||
int dy = 0;
|
||||
int err = 2 - 2 * radius;
|
||||
int e2;
|
||||
|
||||
do {
|
||||
this->draw_pixel_at(center_x - dx, center_y + dy, color);
|
||||
this->draw_pixel_at(center_x + dx, center_y + dy, color);
|
||||
this->draw_pixel_at(center_x + dx, center_y - dy, color);
|
||||
this->draw_pixel_at(center_x - dx, center_y - dy, color);
|
||||
int hline_width = 2 * (-dx) + 1;
|
||||
this->horizontal_line(center_x + dx, center_y + dy, hline_width, color);
|
||||
this->horizontal_line(center_x + dx, center_y - dy, hline_width, color);
|
||||
e2 = err;
|
||||
if (e2 < dy) {
|
||||
err += ++dy * 2 + 1;
|
||||
if (-dx == dy && e2 <= dx) {
|
||||
e2 = 0;
|
||||
}
|
||||
}
|
||||
if (e2 > dx) {
|
||||
err += ++dx * 2 + 1;
|
||||
}
|
||||
} while (dx <= 0);
|
||||
}
|
||||
|
||||
void Display::print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text) {
|
||||
int x_start, y_start;
|
||||
int width, height;
|
||||
this->get_text_bounds(x, y, text, font, align, &x_start, &y_start, &width, &height);
|
||||
font->print(x_start, y_start, this, color, text);
|
||||
}
|
||||
void Display::vprintf_(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, va_list arg) {
|
||||
char buffer[256];
|
||||
int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
|
||||
if (ret > 0)
|
||||
this->print(x, y, font, color, align, buffer);
|
||||
}
|
||||
|
||||
void Display::image(int x, int y, BaseImage *image, Color color_on, Color color_off) {
|
||||
this->image(x, y, image, ImageAlign::TOP_LEFT, color_on, color_off);
|
||||
}
|
||||
|
||||
void Display::image(int x, int y, BaseImage *image, ImageAlign align, Color color_on, Color color_off) {
|
||||
auto x_align = ImageAlign(int(align) & (int(ImageAlign::HORIZONTAL_ALIGNMENT)));
|
||||
auto y_align = ImageAlign(int(align) & (int(ImageAlign::VERTICAL_ALIGNMENT)));
|
||||
|
||||
switch (x_align) {
|
||||
case ImageAlign::RIGHT:
|
||||
x -= image->get_width();
|
||||
break;
|
||||
case ImageAlign::CENTER_HORIZONTAL:
|
||||
x -= image->get_width() / 2;
|
||||
break;
|
||||
case ImageAlign::LEFT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (y_align) {
|
||||
case ImageAlign::BOTTOM:
|
||||
y -= image->get_height();
|
||||
break;
|
||||
case ImageAlign::CENTER_VERTICAL:
|
||||
y -= image->get_height() / 2;
|
||||
break;
|
||||
case ImageAlign::TOP:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
image->draw(x, y, this, color_on, color_off);
|
||||
}
|
||||
|
||||
#ifdef USE_GRAPH
|
||||
void Display::graph(int x, int y, graph::Graph *graph, Color color_on) { graph->draw(this, x, y, color_on); }
|
||||
void Display::legend(int x, int y, graph::Graph *graph, Color color_on) { graph->draw_legend(this, x, y, color_on); }
|
||||
#endif // USE_GRAPH
|
||||
|
||||
#ifdef USE_QR_CODE
|
||||
void Display::qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on, int scale) {
|
||||
qr_code->draw(this, x, y, color_on, scale);
|
||||
}
|
||||
#endif // USE_QR_CODE
|
||||
|
||||
void Display::get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1,
|
||||
int *width, int *height) {
|
||||
int x_offset, baseline;
|
||||
font->measure(text, width, &x_offset, &baseline, height);
|
||||
|
||||
auto x_align = TextAlign(int(align) & 0x18);
|
||||
auto y_align = TextAlign(int(align) & 0x07);
|
||||
|
||||
switch (x_align) {
|
||||
case TextAlign::RIGHT:
|
||||
*x1 = x - *width;
|
||||
break;
|
||||
case TextAlign::CENTER_HORIZONTAL:
|
||||
*x1 = x - (*width) / 2;
|
||||
break;
|
||||
case TextAlign::LEFT:
|
||||
default:
|
||||
// LEFT
|
||||
*x1 = x;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (y_align) {
|
||||
case TextAlign::BOTTOM:
|
||||
*y1 = y - *height;
|
||||
break;
|
||||
case TextAlign::BASELINE:
|
||||
*y1 = y - baseline;
|
||||
break;
|
||||
case TextAlign::CENTER_VERTICAL:
|
||||
*y1 = y - (*height) / 2;
|
||||
break;
|
||||
case TextAlign::TOP:
|
||||
default:
|
||||
*y1 = y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
void Display::print(int x, int y, BaseFont *font, Color color, const char *text) {
|
||||
this->print(x, y, font, color, TextAlign::TOP_LEFT, text);
|
||||
}
|
||||
void Display::print(int x, int y, BaseFont *font, TextAlign align, const char *text) {
|
||||
this->print(x, y, font, COLOR_ON, align, text);
|
||||
}
|
||||
void Display::print(int x, int y, BaseFont *font, const char *text) {
|
||||
this->print(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, text);
|
||||
}
|
||||
void Display::printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
this->vprintf_(x, y, font, color, align, format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
void Display::printf(int x, int y, BaseFont *font, Color color, const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
this->vprintf_(x, y, font, color, TextAlign::TOP_LEFT, format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
void Display::printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
this->vprintf_(x, y, font, COLOR_ON, align, format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
void Display::printf(int x, int y, BaseFont *font, const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
this->vprintf_(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
void Display::set_writer(display_writer_t &&writer) { this->writer_ = writer; }
|
||||
void Display::set_pages(std::vector<DisplayPage *> pages) {
|
||||
for (auto *page : pages)
|
||||
page->set_parent(this);
|
||||
|
||||
for (uint32_t i = 0; i < pages.size() - 1; i++) {
|
||||
pages[i]->set_next(pages[i + 1]);
|
||||
pages[i + 1]->set_prev(pages[i]);
|
||||
}
|
||||
pages[0]->set_prev(pages[pages.size() - 1]);
|
||||
pages[pages.size() - 1]->set_next(pages[0]);
|
||||
this->show_page(pages[0]);
|
||||
}
|
||||
void Display::show_page(DisplayPage *page) {
|
||||
this->previous_page_ = this->page_;
|
||||
this->page_ = page;
|
||||
if (this->previous_page_ != this->page_) {
|
||||
for (auto *t : on_page_change_triggers_)
|
||||
t->process(this->previous_page_, this->page_);
|
||||
}
|
||||
}
|
||||
void Display::show_next_page() { this->page_->show_next(); }
|
||||
void Display::show_prev_page() { this->page_->show_prev(); }
|
||||
void Display::do_update_() {
|
||||
if (this->auto_clear_enabled_) {
|
||||
this->clear();
|
||||
}
|
||||
if (this->page_ != nullptr) {
|
||||
this->page_->get_writer()(*this);
|
||||
} else if (this->writer_.has_value()) {
|
||||
(*this->writer_)(*this);
|
||||
}
|
||||
// remove all not ended clipping regions
|
||||
while (is_clipping()) {
|
||||
end_clipping();
|
||||
}
|
||||
}
|
||||
void DisplayOnPageChangeTrigger::process(DisplayPage *from, DisplayPage *to) {
|
||||
if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to))
|
||||
this->trigger(from, to);
|
||||
}
|
||||
void Display::strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time) {
|
||||
char buffer[64];
|
||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||
if (ret > 0)
|
||||
this->print(x, y, font, color, align, buffer);
|
||||
}
|
||||
void Display::strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) {
|
||||
this->strftime(x, y, font, color, TextAlign::TOP_LEFT, format, time);
|
||||
}
|
||||
void Display::strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time) {
|
||||
this->strftime(x, y, font, COLOR_ON, align, format, time);
|
||||
}
|
||||
void Display::strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) {
|
||||
this->strftime(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, time);
|
||||
}
|
||||
|
||||
void Display::start_clipping(Rect rect) {
|
||||
if (!this->clipping_rectangle_.empty()) {
|
||||
Rect r = this->clipping_rectangle_.back();
|
||||
rect.shrink(r);
|
||||
}
|
||||
this->clipping_rectangle_.push_back(rect);
|
||||
}
|
||||
void Display::end_clipping() {
|
||||
if (this->clipping_rectangle_.empty()) {
|
||||
ESP_LOGE(TAG, "clear: Clipping is not set.");
|
||||
} else {
|
||||
this->clipping_rectangle_.pop_back();
|
||||
}
|
||||
}
|
||||
void Display::extend_clipping(Rect add_rect) {
|
||||
if (this->clipping_rectangle_.empty()) {
|
||||
ESP_LOGE(TAG, "add: Clipping is not set.");
|
||||
} else {
|
||||
this->clipping_rectangle_.back().extend(add_rect);
|
||||
}
|
||||
}
|
||||
void Display::shrink_clipping(Rect add_rect) {
|
||||
if (this->clipping_rectangle_.empty()) {
|
||||
ESP_LOGE(TAG, "add: Clipping is not set.");
|
||||
} else {
|
||||
this->clipping_rectangle_.back().shrink(add_rect);
|
||||
}
|
||||
}
|
||||
Rect Display::get_clipping() {
|
||||
if (this->clipping_rectangle_.empty()) {
|
||||
return Rect();
|
||||
} else {
|
||||
return this->clipping_rectangle_.back();
|
||||
}
|
||||
}
|
||||
|
||||
DisplayPage::DisplayPage(display_writer_t writer) : writer_(std::move(writer)) {}
|
||||
void DisplayPage::show() { this->parent_->show_page(this); }
|
||||
void DisplayPage::show_next() { this->next_->show(); }
|
||||
void DisplayPage::show_prev() { this->prev_->show(); }
|
||||
void DisplayPage::set_parent(Display *parent) { this->parent_ = parent; }
|
||||
void DisplayPage::set_prev(DisplayPage *prev) { this->prev_ = prev; }
|
||||
void DisplayPage::set_next(DisplayPage *next) { this->next_ = next; }
|
||||
const display_writer_t &DisplayPage::get_writer() const { return this->writer_; }
|
||||
|
||||
} // namespace display
|
||||
} // namespace esphome
|
575
esphome/components/display/display.h
Normal file
575
esphome/components/display/display.h
Normal file
|
@ -0,0 +1,575 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstdarg>
|
||||
#include <vector>
|
||||
|
||||
#include "rect.h"
|
||||
|
||||
#include "esphome/core/color.h"
|
||||
#include "esphome/core/automation.h"
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
#ifdef USE_GRAPH
|
||||
#include "esphome/components/graph/graph.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_QR_CODE
|
||||
#include "esphome/components/qr_code/qr_code.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace display {
|
||||
|
||||
/** TextAlign is used to tell the display class how to position a piece of text. By default
|
||||
* the coordinates you enter for the print*() functions take the upper left corner of the text
|
||||
* as the "anchor" point. You can customize this behavior to, for example, make the coordinates
|
||||
* refer to the *center* of the text.
|
||||
*
|
||||
* All text alignments consist of an X and Y-coordinate alignment. For the alignment along the X-axis
|
||||
* these options are allowed:
|
||||
*
|
||||
* - LEFT (x-coordinate of anchor point is on left)
|
||||
* - CENTER_HORIZONTAL (x-coordinate of anchor point is in the horizontal center of the text)
|
||||
* - RIGHT (x-coordinate of anchor point is on right)
|
||||
*
|
||||
* For the Y-Axis alignment these options are allowed:
|
||||
*
|
||||
* - TOP (y-coordinate of anchor is on the top of the text)
|
||||
* - CENTER_VERTICAL (y-coordinate of anchor is in the vertical center of the text)
|
||||
* - BASELINE (y-coordinate of anchor is on the baseline of the text)
|
||||
* - BOTTOM (y-coordinate of anchor is on the bottom of the text)
|
||||
*
|
||||
* These options are then combined to create combined TextAlignment options like:
|
||||
* - TOP_LEFT (default)
|
||||
* - CENTER (anchor point is in the middle of the text bounds)
|
||||
* - ...
|
||||
*/
|
||||
enum class TextAlign {
|
||||
TOP = 0x00,
|
||||
CENTER_VERTICAL = 0x01,
|
||||
BASELINE = 0x02,
|
||||
BOTTOM = 0x04,
|
||||
|
||||
LEFT = 0x00,
|
||||
CENTER_HORIZONTAL = 0x08,
|
||||
RIGHT = 0x10,
|
||||
|
||||
TOP_LEFT = TOP | LEFT,
|
||||
TOP_CENTER = TOP | CENTER_HORIZONTAL,
|
||||
TOP_RIGHT = TOP | RIGHT,
|
||||
|
||||
CENTER_LEFT = CENTER_VERTICAL | LEFT,
|
||||
CENTER = CENTER_VERTICAL | CENTER_HORIZONTAL,
|
||||
CENTER_RIGHT = CENTER_VERTICAL | RIGHT,
|
||||
|
||||
BASELINE_LEFT = BASELINE | LEFT,
|
||||
BASELINE_CENTER = BASELINE | CENTER_HORIZONTAL,
|
||||
BASELINE_RIGHT = BASELINE | RIGHT,
|
||||
|
||||
BOTTOM_LEFT = BOTTOM | LEFT,
|
||||
BOTTOM_CENTER = BOTTOM | CENTER_HORIZONTAL,
|
||||
BOTTOM_RIGHT = BOTTOM | RIGHT,
|
||||
};
|
||||
|
||||
/** ImageAlign is used to tell the display class how to position a image. By default
|
||||
* the coordinates you enter for the image() functions take the upper left corner of the image
|
||||
* as the "anchor" point. You can customize this behavior to, for example, make the coordinates
|
||||
* refer to the *center* of the image.
|
||||
*
|
||||
* All image alignments consist of an X and Y-coordinate alignment. For the alignment along the X-axis
|
||||
* these options are allowed:
|
||||
*
|
||||
* - LEFT (x-coordinate of anchor point is on left)
|
||||
* - CENTER_HORIZONTAL (x-coordinate of anchor point is in the horizontal center of the image)
|
||||
* - RIGHT (x-coordinate of anchor point is on right)
|
||||
*
|
||||
* For the Y-Axis alignment these options are allowed:
|
||||
*
|
||||
* - TOP (y-coordinate of anchor is on the top of the image)
|
||||
* - CENTER_VERTICAL (y-coordinate of anchor is in the vertical center of the image)
|
||||
* - BOTTOM (y-coordinate of anchor is on the bottom of the image)
|
||||
*
|
||||
* These options are then combined to create combined TextAlignment options like:
|
||||
* - TOP_LEFT (default)
|
||||
* - CENTER (anchor point is in the middle of the image bounds)
|
||||
* - ...
|
||||
*/
|
||||
enum class ImageAlign {
|
||||
TOP = 0x00,
|
||||
CENTER_VERTICAL = 0x01,
|
||||
BOTTOM = 0x02,
|
||||
|
||||
LEFT = 0x00,
|
||||
CENTER_HORIZONTAL = 0x04,
|
||||
RIGHT = 0x08,
|
||||
|
||||
TOP_LEFT = TOP | LEFT,
|
||||
TOP_CENTER = TOP | CENTER_HORIZONTAL,
|
||||
TOP_RIGHT = TOP | RIGHT,
|
||||
|
||||
CENTER_LEFT = CENTER_VERTICAL | LEFT,
|
||||
CENTER = CENTER_VERTICAL | CENTER_HORIZONTAL,
|
||||
CENTER_RIGHT = CENTER_VERTICAL | RIGHT,
|
||||
|
||||
BOTTOM_LEFT = BOTTOM | LEFT,
|
||||
BOTTOM_CENTER = BOTTOM | CENTER_HORIZONTAL,
|
||||
BOTTOM_RIGHT = BOTTOM | RIGHT,
|
||||
|
||||
HORIZONTAL_ALIGNMENT = LEFT | CENTER_HORIZONTAL | RIGHT,
|
||||
VERTICAL_ALIGNMENT = TOP | CENTER_VERTICAL | BOTTOM
|
||||
};
|
||||
|
||||
enum DisplayType {
|
||||
DISPLAY_TYPE_BINARY = 1,
|
||||
DISPLAY_TYPE_GRAYSCALE = 2,
|
||||
DISPLAY_TYPE_COLOR = 3,
|
||||
};
|
||||
|
||||
enum DisplayRotation {
|
||||
DISPLAY_ROTATION_0_DEGREES = 0,
|
||||
DISPLAY_ROTATION_90_DEGREES = 90,
|
||||
DISPLAY_ROTATION_180_DEGREES = 180,
|
||||
DISPLAY_ROTATION_270_DEGREES = 270,
|
||||
};
|
||||
|
||||
class Display;
|
||||
class DisplayBuffer;
|
||||
class DisplayPage;
|
||||
class DisplayOnPageChangeTrigger;
|
||||
|
||||
using display_writer_t = std::function<void(Display &)>;
|
||||
using display_buffer_writer_t = std::function<void(DisplayBuffer &)>;
|
||||
|
||||
#define LOG_DISPLAY(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, prefix type); \
|
||||
ESP_LOGCONFIG(TAG, "%s Rotations: %d °", prefix, (obj)->rotation_); \
|
||||
ESP_LOGCONFIG(TAG, "%s Dimensions: %dpx x %dpx", prefix, (obj)->get_width(), (obj)->get_height()); \
|
||||
}
|
||||
|
||||
/// Turn the pixel OFF.
|
||||
extern const Color COLOR_OFF;
|
||||
/// Turn the pixel ON.
|
||||
extern const Color COLOR_ON;
|
||||
|
||||
class BaseImage {
|
||||
public:
|
||||
virtual void draw(int x, int y, Display *display, Color color_on, Color color_off) = 0;
|
||||
virtual int get_width() const = 0;
|
||||
virtual int get_height() const = 0;
|
||||
};
|
||||
|
||||
class BaseFont {
|
||||
public:
|
||||
virtual void print(int x, int y, Display *display, Color color, const char *text) = 0;
|
||||
virtual void measure(const char *str, int *width, int *x_offset, int *baseline, int *height) = 0;
|
||||
};
|
||||
|
||||
class Display {
|
||||
public:
|
||||
/// Fill the entire screen with the given color.
|
||||
virtual void fill(Color color);
|
||||
/// Clear the entire screen by filling it with OFF pixels.
|
||||
void clear();
|
||||
|
||||
/// Get the width of the image in pixels with rotation applied.
|
||||
virtual int get_width() = 0;
|
||||
/// Get the height of the image in pixels with rotation applied.
|
||||
virtual int get_height() = 0;
|
||||
|
||||
/// Set a single pixel at the specified coordinates to default color.
|
||||
inline void draw_pixel_at(int x, int y) { this->draw_pixel_at(x, y, COLOR_ON); }
|
||||
|
||||
/// Set a single pixel at the specified coordinates to the given color.
|
||||
virtual void draw_pixel_at(int x, int y, Color color) = 0;
|
||||
|
||||
/// Draw a straight line from the point [x1,y1] to [x2,y2] with the given color.
|
||||
void line(int x1, int y1, int x2, int y2, Color color = COLOR_ON);
|
||||
|
||||
/// Draw a horizontal line from the point [x,y] to [x+width,y] with the given color.
|
||||
void horizontal_line(int x, int y, int width, Color color = COLOR_ON);
|
||||
|
||||
/// Draw a vertical line from the point [x,y] to [x,y+width] with the given color.
|
||||
void vertical_line(int x, int y, 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+width,y1+height].
|
||||
void 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,y1+height].
|
||||
void filled_rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON);
|
||||
|
||||
/// Draw the outline of a circle centered around [center_x,center_y] with the radius radius with the given color.
|
||||
void circle(int center_x, int center_xy, 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_circle(int center_x, int center_y, int radius, Color color = COLOR_ON);
|
||||
|
||||
/** Print `text` with the anchor point at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the text alignment anchor point.
|
||||
* @param y The y coordinate of the text alignment anchor point.
|
||||
* @param font The font to draw the text with.
|
||||
* @param color The color to draw the text with.
|
||||
* @param align The alignment of the text.
|
||||
* @param text The text to draw.
|
||||
*/
|
||||
void print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text);
|
||||
|
||||
/** Print `text` with the top left at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param font The font to draw the text with.
|
||||
* @param color The color to draw the text with.
|
||||
* @param text The text to draw.
|
||||
*/
|
||||
void print(int x, int y, BaseFont *font, Color color, const char *text);
|
||||
|
||||
/** Print `text` with the anchor point at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the text alignment anchor point.
|
||||
* @param y The y coordinate of the text alignment anchor point.
|
||||
* @param font The font to draw the text with.
|
||||
* @param align The alignment of the text.
|
||||
* @param text The text to draw.
|
||||
*/
|
||||
void print(int x, int y, BaseFont *font, TextAlign align, const char *text);
|
||||
|
||||
/** Print `text` with the top left at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param font The font to draw the text with.
|
||||
* @param text The text to draw.
|
||||
*/
|
||||
void print(int x, int y, BaseFont *font, const char *text);
|
||||
|
||||
/** Evaluate the printf-format `format` and print the result with the anchor point at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the text alignment anchor point.
|
||||
* @param y The y coordinate of the text alignment anchor point.
|
||||
* @param font The font to draw the text with.
|
||||
* @param color The color to draw the text with.
|
||||
* @param align The alignment of the text.
|
||||
* @param format The format to use.
|
||||
* @param ... The arguments to use for the text formatting.
|
||||
*/
|
||||
void printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...)
|
||||
__attribute__((format(printf, 7, 8)));
|
||||
|
||||
/** Evaluate the printf-format `format` and print the result with the top left at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param font The font to draw the text with.
|
||||
* @param color The color to draw the text with.
|
||||
* @param format The format to use.
|
||||
* @param ... The arguments to use for the text formatting.
|
||||
*/
|
||||
void printf(int x, int y, BaseFont *font, Color color, const char *format, ...) __attribute__((format(printf, 6, 7)));
|
||||
|
||||
/** Evaluate the printf-format `format` and print the result with the anchor point at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the text alignment anchor point.
|
||||
* @param y The y coordinate of the text alignment anchor point.
|
||||
* @param font The font to draw the text with.
|
||||
* @param align The alignment of the text.
|
||||
* @param format The format to use.
|
||||
* @param ... The arguments to use for the text formatting.
|
||||
*/
|
||||
void printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...)
|
||||
__attribute__((format(printf, 6, 7)));
|
||||
|
||||
/** Evaluate the printf-format `format` and print the result with the top left at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param font The font to draw the text with.
|
||||
* @param format The format to use.
|
||||
* @param ... The arguments to use for the text formatting.
|
||||
*/
|
||||
void printf(int x, int y, BaseFont *font, const char *format, ...) __attribute__((format(printf, 5, 6)));
|
||||
|
||||
/** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the text alignment anchor point.
|
||||
* @param y The y coordinate of the text alignment anchor point.
|
||||
* @param font The font to draw the text with.
|
||||
* @param color The color to draw the text with.
|
||||
* @param align The alignment of the text.
|
||||
* @param format The strftime format to use.
|
||||
* @param time The time to format.
|
||||
*/
|
||||
void strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time)
|
||||
__attribute__((format(strftime, 7, 0)));
|
||||
|
||||
/** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param font The font to draw the text with.
|
||||
* @param color The color to draw the text with.
|
||||
* @param format The strftime format to use.
|
||||
* @param time The time to format.
|
||||
*/
|
||||
void strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time)
|
||||
__attribute__((format(strftime, 6, 0)));
|
||||
|
||||
/** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the text alignment anchor point.
|
||||
* @param y The y coordinate of the text alignment anchor point.
|
||||
* @param font The font to draw the text with.
|
||||
* @param align The alignment of the text.
|
||||
* @param format The strftime format to use.
|
||||
* @param time The time to format.
|
||||
*/
|
||||
void strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time)
|
||||
__attribute__((format(strftime, 6, 0)));
|
||||
|
||||
/** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param font The font to draw the text with.
|
||||
* @param format The strftime format to use.
|
||||
* @param time The time to format.
|
||||
*/
|
||||
void strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) __attribute__((format(strftime, 5, 0)));
|
||||
|
||||
/** Draw the `image` with the top-left corner at [x,y] to the screen.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param image The image to draw.
|
||||
* @param color_on The color to replace in binary images for the on bits.
|
||||
* @param color_off The color to replace in binary images for the off bits.
|
||||
*/
|
||||
void image(int x, int y, BaseImage *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
|
||||
|
||||
/** Draw the `image` at [x,y] to the screen.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param image The image to draw.
|
||||
* @param align The alignment of the image.
|
||||
* @param color_on The color to replace in binary images for the on bits.
|
||||
* @param color_off The color to replace in binary images for the off bits.
|
||||
*/
|
||||
void image(int x, int y, BaseImage *image, ImageAlign align, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
|
||||
|
||||
#ifdef USE_GRAPH
|
||||
/** Draw the `graph` with the top-left corner at [x,y] to the screen.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param graph The graph id to draw
|
||||
* @param color_on The color to replace in binary images for the on bits.
|
||||
*/
|
||||
void graph(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.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param graph The graph id for which the legend applies to
|
||||
* @param graph The graph id for which the legend applies to
|
||||
* @param graph The graph id for which the legend applies to
|
||||
* @param name_font The font used for the trace name
|
||||
* @param value_font The font used for the trace value and units
|
||||
* @param color_on The color of the border
|
||||
*/
|
||||
void legend(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
|
||||
#endif // USE_GRAPH
|
||||
|
||||
#ifdef USE_QR_CODE
|
||||
/** Draw the `qr_code` with the top-left corner at [x,y] to the screen.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param qr_code The qr_code to draw
|
||||
* @param color_on The color to replace in binary images for the on bits.
|
||||
*/
|
||||
void qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on = COLOR_ON, int scale = 1);
|
||||
#endif
|
||||
|
||||
/** Get the text bounds of the given string.
|
||||
*
|
||||
* @param x The x coordinate to place the string at, can be 0 if only interested in dimensions.
|
||||
* @param y The y coordinate to place the string at, can be 0 if only interested in dimensions.
|
||||
* @param text The text to measure.
|
||||
* @param font The font to measure the text bounds with.
|
||||
* @param align The alignment of the text. Set to TextAlign::TOP_LEFT if only interested in dimensions.
|
||||
* @param x1 A pointer to store the returned x coordinate of the upper left corner in.
|
||||
* @param y1 A pointer to store the returned y coordinate of the upper left corner in.
|
||||
* @param width A pointer to store the returned text width in.
|
||||
* @param height A pointer to store the returned text height in.
|
||||
*/
|
||||
void get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1, int *width,
|
||||
int *height);
|
||||
|
||||
/// Internal method to set the display writer lambda.
|
||||
void set_writer(display_writer_t &&writer);
|
||||
void set_writer(const display_buffer_writer_t &writer) {
|
||||
// Temporary mapping to be removed once all lambdas are changed to use `display.DisplayRef`
|
||||
this->set_writer([writer](Display &display) { return writer((display::DisplayBuffer &) display); });
|
||||
}
|
||||
|
||||
void show_page(DisplayPage *page);
|
||||
void show_next_page();
|
||||
void show_prev_page();
|
||||
|
||||
void set_pages(std::vector<DisplayPage *> pages);
|
||||
|
||||
const DisplayPage *get_active_page() const { return this->page_; }
|
||||
|
||||
void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t) { this->on_page_change_triggers_.push_back(t); }
|
||||
|
||||
/// Internal method to set the display rotation with.
|
||||
void set_rotation(DisplayRotation rotation);
|
||||
|
||||
// Internal method to set display auto clearing.
|
||||
void set_auto_clear(bool auto_clear_enabled) { this->auto_clear_enabled_ = auto_clear_enabled; }
|
||||
|
||||
DisplayRotation get_rotation() const { return this->rotation_; }
|
||||
|
||||
/** Get the type of display that the buffer corresponds to. In case of dynamically configurable displays,
|
||||
* returns the type the display is currently configured to.
|
||||
*/
|
||||
virtual DisplayType get_display_type() = 0;
|
||||
|
||||
/** Set the clipping rectangle for further drawing
|
||||
*
|
||||
* @param[in] rect: Pointer to Rect for clipping (or NULL for entire screen)
|
||||
*
|
||||
* return true if success, false if error
|
||||
*/
|
||||
void start_clipping(Rect rect);
|
||||
void start_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
|
||||
start_clipping(Rect(left, top, right - left, bottom - top));
|
||||
};
|
||||
|
||||
/** Add a rectangular region to the invalidation region
|
||||
* - This is usually called when an element has been modified
|
||||
*
|
||||
* @param[in] rect: Rectangle to add to the invalidation region
|
||||
*/
|
||||
void extend_clipping(Rect rect);
|
||||
void extend_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
|
||||
this->extend_clipping(Rect(left, top, right - left, bottom - top));
|
||||
};
|
||||
|
||||
/** substract a rectangular region to the invalidation region
|
||||
* - This is usually called when an element has been modified
|
||||
*
|
||||
* @param[in] rect: Rectangle to add to the invalidation region
|
||||
*/
|
||||
void shrink_clipping(Rect rect);
|
||||
void shrink_clipping(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) {
|
||||
this->shrink_clipping(Rect(left, top, right - left, bottom - top));
|
||||
};
|
||||
|
||||
/** Reset the invalidation region
|
||||
*/
|
||||
void end_clipping();
|
||||
|
||||
/** Get the current the clipping rectangle
|
||||
*
|
||||
* return rect for active clipping region
|
||||
*/
|
||||
Rect get_clipping();
|
||||
|
||||
bool is_clipping() const { return !this->clipping_rectangle_.empty(); }
|
||||
|
||||
protected:
|
||||
void vprintf_(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, va_list arg);
|
||||
|
||||
void do_update_();
|
||||
|
||||
DisplayRotation rotation_{DISPLAY_ROTATION_0_DEGREES};
|
||||
optional<display_writer_t> writer_{};
|
||||
DisplayPage *page_{nullptr};
|
||||
DisplayPage *previous_page_{nullptr};
|
||||
std::vector<DisplayOnPageChangeTrigger *> on_page_change_triggers_;
|
||||
bool auto_clear_enabled_{true};
|
||||
std::vector<Rect> clipping_rectangle_;
|
||||
};
|
||||
|
||||
class DisplayPage {
|
||||
public:
|
||||
DisplayPage(display_writer_t writer);
|
||||
// Temporary mapping to be removed once all lambdas are changed to use `display.DisplayRef`
|
||||
DisplayPage(const display_buffer_writer_t &writer)
|
||||
: DisplayPage([writer](Display &display) { return writer((display::DisplayBuffer &) display); }) {}
|
||||
void show();
|
||||
void show_next();
|
||||
void show_prev();
|
||||
void set_parent(Display *parent);
|
||||
void set_prev(DisplayPage *prev);
|
||||
void set_next(DisplayPage *next);
|
||||
const display_writer_t &get_writer() const;
|
||||
|
||||
protected:
|
||||
Display *parent_;
|
||||
display_writer_t writer_;
|
||||
DisplayPage *prev_{nullptr};
|
||||
DisplayPage *next_{nullptr};
|
||||
};
|
||||
|
||||
template<typename... Ts> class DisplayPageShowAction : public Action<Ts...> {
|
||||
public:
|
||||
TEMPLATABLE_VALUE(DisplayPage *, page)
|
||||
|
||||
void play(Ts... x) override {
|
||||
auto *page = this->page_.value(x...);
|
||||
if (page != nullptr) {
|
||||
page->show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Ts> class DisplayPageShowNextAction : public Action<Ts...> {
|
||||
public:
|
||||
DisplayPageShowNextAction(Display *buffer) : buffer_(buffer) {}
|
||||
|
||||
void play(Ts... x) override { this->buffer_->show_next_page(); }
|
||||
|
||||
Display *buffer_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class DisplayPageShowPrevAction : public Action<Ts...> {
|
||||
public:
|
||||
DisplayPageShowPrevAction(Display *buffer) : buffer_(buffer) {}
|
||||
|
||||
void play(Ts... x) override { this->buffer_->show_prev_page(); }
|
||||
|
||||
Display *buffer_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class DisplayIsDisplayingPageCondition : public Condition<Ts...> {
|
||||
public:
|
||||
DisplayIsDisplayingPageCondition(Display *parent) : parent_(parent) {}
|
||||
|
||||
void set_page(DisplayPage *page) { this->page_ = page; }
|
||||
bool check(Ts... x) override { return this->parent_->get_active_page() == this->page_; }
|
||||
|
||||
protected:
|
||||
Display *parent_;
|
||||
DisplayPage *page_;
|
||||
};
|
||||
|
||||
class DisplayOnPageChangeTrigger : public Trigger<DisplayPage *, DisplayPage *> {
|
||||
public:
|
||||
explicit DisplayOnPageChangeTrigger(Display *parent) { parent->add_on_page_change_trigger(this); }
|
||||
void process(DisplayPage *from, DisplayPage *to);
|
||||
void set_from(DisplayPage *p) { this->from_ = p; }
|
||||
void set_to(DisplayPage *p) { this->to_ = p; }
|
||||
|
||||
protected:
|
||||
DisplayPage *from_{nullptr};
|
||||
DisplayPage *to_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace display
|
||||
} // namespace esphome
|
|
@ -1,10 +1,8 @@
|
|||
#include "display_buffer.h"
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "esphome/core/application.h"
|
||||
#include "esphome/core/color.h"
|
||||
#include "esphome/core/hal.h"
|
||||
#include "esphome/core/helpers.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
namespace esphome {
|
||||
|
@ -12,9 +10,6 @@ namespace display {
|
|||
|
||||
static const char *const TAG = "display";
|
||||
|
||||
const Color COLOR_OFF(0, 0, 0, 0);
|
||||
const Color COLOR_ON(255, 255, 255, 255);
|
||||
|
||||
void DisplayBuffer::init_internal_(uint32_t buffer_length) {
|
||||
ExternalRAMAllocator<uint8_t> allocator(ExternalRAMAllocator<uint8_t>::ALLOW_FAILURE);
|
||||
this->buffer_ = allocator.allocate(buffer_length);
|
||||
|
@ -25,8 +20,6 @@ void DisplayBuffer::init_internal_(uint32_t buffer_length) {
|
|||
this->clear();
|
||||
}
|
||||
|
||||
void DisplayBuffer::fill(Color color) { this->filled_rectangle(0, 0, this->get_width(), this->get_height(), color); }
|
||||
void DisplayBuffer::clear() { this->fill(COLOR_OFF); }
|
||||
int DisplayBuffer::get_width() {
|
||||
switch (this->rotation_) {
|
||||
case DISPLAY_ROTATION_90_DEGREES:
|
||||
|
@ -38,6 +31,7 @@ int DisplayBuffer::get_width() {
|
|||
return this->get_width_internal();
|
||||
}
|
||||
}
|
||||
|
||||
int DisplayBuffer::get_height() {
|
||||
switch (this->rotation_) {
|
||||
case DISPLAY_ROTATION_0_DEGREES:
|
||||
|
@ -49,7 +43,7 @@ int DisplayBuffer::get_height() {
|
|||
return this->get_width_internal();
|
||||
}
|
||||
}
|
||||
void DisplayBuffer::set_rotation(DisplayRotation rotation) { this->rotation_ = rotation; }
|
||||
|
||||
void HOT DisplayBuffer::draw_pixel_at(int x, int y, Color color) {
|
||||
if (!this->get_clipping().inside(x, y))
|
||||
return; // NOLINT
|
||||
|
@ -73,333 +67,6 @@ void HOT DisplayBuffer::draw_pixel_at(int x, int y, Color color) {
|
|||
this->draw_absolute_pixel_internal(x, y, color);
|
||||
App.feed_wdt();
|
||||
}
|
||||
void HOT DisplayBuffer::line(int x1, int y1, int x2, int y2, Color color) {
|
||||
const int32_t dx = abs(x2 - x1), sx = x1 < x2 ? 1 : -1;
|
||||
const int32_t dy = -abs(y2 - y1), sy = y1 < y2 ? 1 : -1;
|
||||
int32_t err = dx + dy;
|
||||
|
||||
while (true) {
|
||||
this->draw_pixel_at(x1, y1, color);
|
||||
if (x1 == x2 && y1 == y2)
|
||||
break;
|
||||
int32_t e2 = 2 * err;
|
||||
if (e2 >= dy) {
|
||||
err += dy;
|
||||
x1 += sx;
|
||||
}
|
||||
if (e2 <= dx) {
|
||||
err += dx;
|
||||
y1 += sy;
|
||||
}
|
||||
}
|
||||
}
|
||||
void HOT DisplayBuffer::horizontal_line(int x, int y, int width, Color color) {
|
||||
// Future: Could be made more efficient by manipulating buffer directly in certain rotations.
|
||||
for (int i = x; i < x + width; i++)
|
||||
this->draw_pixel_at(i, y, color);
|
||||
}
|
||||
void HOT DisplayBuffer::vertical_line(int x, int y, int height, Color color) {
|
||||
// Future: Could be made more efficient by manipulating buffer directly in certain rotations.
|
||||
for (int i = y; i < y + height; i++)
|
||||
this->draw_pixel_at(x, i, color);
|
||||
}
|
||||
void DisplayBuffer::rectangle(int x1, int y1, int width, int height, Color color) {
|
||||
this->horizontal_line(x1, y1, width, color);
|
||||
this->horizontal_line(x1, y1 + height - 1, width, color);
|
||||
this->vertical_line(x1, y1, height, color);
|
||||
this->vertical_line(x1 + width - 1, y1, height, color);
|
||||
}
|
||||
void DisplayBuffer::filled_rectangle(int x1, int y1, int width, int height, Color color) {
|
||||
// Future: Use vertical_line and horizontal_line methods depending on rotation to reduce memory accesses.
|
||||
for (int i = y1; i < y1 + height; i++) {
|
||||
this->horizontal_line(x1, i, width, color);
|
||||
}
|
||||
}
|
||||
void HOT DisplayBuffer::circle(int center_x, int center_xy, int radius, Color color) {
|
||||
int dx = -radius;
|
||||
int dy = 0;
|
||||
int err = 2 - 2 * radius;
|
||||
int e2;
|
||||
|
||||
do {
|
||||
this->draw_pixel_at(center_x - dx, center_xy + dy, color);
|
||||
this->draw_pixel_at(center_x + dx, center_xy + dy, color);
|
||||
this->draw_pixel_at(center_x + dx, center_xy - dy, color);
|
||||
this->draw_pixel_at(center_x - dx, center_xy - dy, color);
|
||||
e2 = err;
|
||||
if (e2 < dy) {
|
||||
err += ++dy * 2 + 1;
|
||||
if (-dx == dy && e2 <= dx) {
|
||||
e2 = 0;
|
||||
}
|
||||
}
|
||||
if (e2 > dx) {
|
||||
err += ++dx * 2 + 1;
|
||||
}
|
||||
} while (dx <= 0);
|
||||
}
|
||||
void DisplayBuffer::filled_circle(int center_x, int center_y, int radius, Color color) {
|
||||
int dx = -int32_t(radius);
|
||||
int dy = 0;
|
||||
int err = 2 - 2 * radius;
|
||||
int e2;
|
||||
|
||||
do {
|
||||
this->draw_pixel_at(center_x - dx, center_y + dy, color);
|
||||
this->draw_pixel_at(center_x + dx, center_y + dy, color);
|
||||
this->draw_pixel_at(center_x + dx, center_y - dy, color);
|
||||
this->draw_pixel_at(center_x - dx, center_y - dy, color);
|
||||
int hline_width = 2 * (-dx) + 1;
|
||||
this->horizontal_line(center_x + dx, center_y + dy, hline_width, color);
|
||||
this->horizontal_line(center_x + dx, center_y - dy, hline_width, color);
|
||||
e2 = err;
|
||||
if (e2 < dy) {
|
||||
err += ++dy * 2 + 1;
|
||||
if (-dx == dy && e2 <= dx) {
|
||||
e2 = 0;
|
||||
}
|
||||
}
|
||||
if (e2 > dx) {
|
||||
err += ++dx * 2 + 1;
|
||||
}
|
||||
} while (dx <= 0);
|
||||
}
|
||||
|
||||
void DisplayBuffer::print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text) {
|
||||
int x_start, y_start;
|
||||
int width, height;
|
||||
this->get_text_bounds(x, y, text, font, align, &x_start, &y_start, &width, &height);
|
||||
font->print(x_start, y_start, this, color, text);
|
||||
}
|
||||
void DisplayBuffer::vprintf_(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format,
|
||||
va_list arg) {
|
||||
char buffer[256];
|
||||
int ret = vsnprintf(buffer, sizeof(buffer), format, arg);
|
||||
if (ret > 0)
|
||||
this->print(x, y, font, color, align, buffer);
|
||||
}
|
||||
|
||||
void DisplayBuffer::image(int x, int y, BaseImage *image, Color color_on, Color color_off) {
|
||||
this->image(x, y, image, ImageAlign::TOP_LEFT, color_on, color_off);
|
||||
}
|
||||
|
||||
void DisplayBuffer::image(int x, int y, BaseImage *image, ImageAlign align, Color color_on, Color color_off) {
|
||||
auto x_align = ImageAlign(int(align) & (int(ImageAlign::HORIZONTAL_ALIGNMENT)));
|
||||
auto y_align = ImageAlign(int(align) & (int(ImageAlign::VERTICAL_ALIGNMENT)));
|
||||
|
||||
switch (x_align) {
|
||||
case ImageAlign::RIGHT:
|
||||
x -= image->get_width();
|
||||
break;
|
||||
case ImageAlign::CENTER_HORIZONTAL:
|
||||
x -= image->get_width() / 2;
|
||||
break;
|
||||
case ImageAlign::LEFT:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (y_align) {
|
||||
case ImageAlign::BOTTOM:
|
||||
y -= image->get_height();
|
||||
break;
|
||||
case ImageAlign::CENTER_VERTICAL:
|
||||
y -= image->get_height() / 2;
|
||||
break;
|
||||
case ImageAlign::TOP:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
image->draw(x, y, this, color_on, color_off);
|
||||
}
|
||||
|
||||
#ifdef USE_GRAPH
|
||||
void DisplayBuffer::graph(int x, int y, graph::Graph *graph, Color color_on) { graph->draw(this, x, y, color_on); }
|
||||
void DisplayBuffer::legend(int x, int y, graph::Graph *graph, Color color_on) {
|
||||
graph->draw_legend(this, x, y, color_on);
|
||||
}
|
||||
#endif // USE_GRAPH
|
||||
|
||||
#ifdef USE_QR_CODE
|
||||
void DisplayBuffer::qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on, int scale) {
|
||||
qr_code->draw(this, x, y, color_on, scale);
|
||||
}
|
||||
#endif // USE_QR_CODE
|
||||
|
||||
void DisplayBuffer::get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1,
|
||||
int *width, int *height) {
|
||||
int x_offset, baseline;
|
||||
font->measure(text, width, &x_offset, &baseline, height);
|
||||
|
||||
auto x_align = TextAlign(int(align) & 0x18);
|
||||
auto y_align = TextAlign(int(align) & 0x07);
|
||||
|
||||
switch (x_align) {
|
||||
case TextAlign::RIGHT:
|
||||
*x1 = x - *width;
|
||||
break;
|
||||
case TextAlign::CENTER_HORIZONTAL:
|
||||
*x1 = x - (*width) / 2;
|
||||
break;
|
||||
case TextAlign::LEFT:
|
||||
default:
|
||||
// LEFT
|
||||
*x1 = x;
|
||||
break;
|
||||
}
|
||||
|
||||
switch (y_align) {
|
||||
case TextAlign::BOTTOM:
|
||||
*y1 = y - *height;
|
||||
break;
|
||||
case TextAlign::BASELINE:
|
||||
*y1 = y - baseline;
|
||||
break;
|
||||
case TextAlign::CENTER_VERTICAL:
|
||||
*y1 = y - (*height) / 2;
|
||||
break;
|
||||
case TextAlign::TOP:
|
||||
default:
|
||||
*y1 = y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
void DisplayBuffer::print(int x, int y, BaseFont *font, Color color, const char *text) {
|
||||
this->print(x, y, font, color, TextAlign::TOP_LEFT, text);
|
||||
}
|
||||
void DisplayBuffer::print(int x, int y, BaseFont *font, TextAlign align, const char *text) {
|
||||
this->print(x, y, font, COLOR_ON, align, text);
|
||||
}
|
||||
void DisplayBuffer::print(int x, int y, BaseFont *font, const char *text) {
|
||||
this->print(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, text);
|
||||
}
|
||||
void DisplayBuffer::printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
this->vprintf_(x, y, font, color, align, format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
void DisplayBuffer::printf(int x, int y, BaseFont *font, Color color, const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
this->vprintf_(x, y, font, color, TextAlign::TOP_LEFT, format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
void DisplayBuffer::printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
this->vprintf_(x, y, font, COLOR_ON, align, format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
void DisplayBuffer::printf(int x, int y, BaseFont *font, const char *format, ...) {
|
||||
va_list arg;
|
||||
va_start(arg, format);
|
||||
this->vprintf_(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, arg);
|
||||
va_end(arg);
|
||||
}
|
||||
void DisplayBuffer::set_writer(display_writer_t &&writer) { this->writer_ = writer; }
|
||||
void DisplayBuffer::set_pages(std::vector<DisplayPage *> pages) {
|
||||
for (auto *page : pages)
|
||||
page->set_parent(this);
|
||||
|
||||
for (uint32_t i = 0; i < pages.size() - 1; i++) {
|
||||
pages[i]->set_next(pages[i + 1]);
|
||||
pages[i + 1]->set_prev(pages[i]);
|
||||
}
|
||||
pages[0]->set_prev(pages[pages.size() - 1]);
|
||||
pages[pages.size() - 1]->set_next(pages[0]);
|
||||
this->show_page(pages[0]);
|
||||
}
|
||||
void DisplayBuffer::show_page(DisplayPage *page) {
|
||||
this->previous_page_ = this->page_;
|
||||
this->page_ = page;
|
||||
if (this->previous_page_ != this->page_) {
|
||||
for (auto *t : on_page_change_triggers_)
|
||||
t->process(this->previous_page_, this->page_);
|
||||
}
|
||||
}
|
||||
void DisplayBuffer::show_next_page() { this->page_->show_next(); }
|
||||
void DisplayBuffer::show_prev_page() { this->page_->show_prev(); }
|
||||
void DisplayBuffer::do_update_() {
|
||||
if (this->auto_clear_enabled_) {
|
||||
this->clear();
|
||||
}
|
||||
if (this->page_ != nullptr) {
|
||||
this->page_->get_writer()(*this);
|
||||
} else if (this->writer_.has_value()) {
|
||||
(*this->writer_)(*this);
|
||||
}
|
||||
// remove all not ended clipping regions
|
||||
while (is_clipping()) {
|
||||
end_clipping();
|
||||
}
|
||||
}
|
||||
void DisplayOnPageChangeTrigger::process(DisplayPage *from, DisplayPage *to) {
|
||||
if ((this->from_ == nullptr || this->from_ == from) && (this->to_ == nullptr || this->to_ == to))
|
||||
this->trigger(from, to);
|
||||
}
|
||||
void DisplayBuffer::strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format,
|
||||
ESPTime time) {
|
||||
char buffer[64];
|
||||
size_t ret = time.strftime(buffer, sizeof(buffer), format);
|
||||
if (ret > 0)
|
||||
this->print(x, y, font, color, align, buffer);
|
||||
}
|
||||
void DisplayBuffer::strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time) {
|
||||
this->strftime(x, y, font, color, TextAlign::TOP_LEFT, format, time);
|
||||
}
|
||||
void DisplayBuffer::strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time) {
|
||||
this->strftime(x, y, font, COLOR_ON, align, format, time);
|
||||
}
|
||||
void DisplayBuffer::strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) {
|
||||
this->strftime(x, y, font, COLOR_ON, TextAlign::TOP_LEFT, format, time);
|
||||
}
|
||||
|
||||
void DisplayBuffer::start_clipping(Rect rect) {
|
||||
if (!this->clipping_rectangle_.empty()) {
|
||||
Rect r = this->clipping_rectangle_.back();
|
||||
rect.shrink(r);
|
||||
}
|
||||
this->clipping_rectangle_.push_back(rect);
|
||||
}
|
||||
void DisplayBuffer::end_clipping() {
|
||||
if (this->clipping_rectangle_.empty()) {
|
||||
ESP_LOGE(TAG, "clear: Clipping is not set.");
|
||||
} else {
|
||||
this->clipping_rectangle_.pop_back();
|
||||
}
|
||||
}
|
||||
void DisplayBuffer::extend_clipping(Rect add_rect) {
|
||||
if (this->clipping_rectangle_.empty()) {
|
||||
ESP_LOGE(TAG, "add: Clipping is not set.");
|
||||
} else {
|
||||
this->clipping_rectangle_.back().extend(add_rect);
|
||||
}
|
||||
}
|
||||
void DisplayBuffer::shrink_clipping(Rect add_rect) {
|
||||
if (this->clipping_rectangle_.empty()) {
|
||||
ESP_LOGE(TAG, "add: Clipping is not set.");
|
||||
} else {
|
||||
this->clipping_rectangle_.back().shrink(add_rect);
|
||||
}
|
||||
}
|
||||
Rect DisplayBuffer::get_clipping() {
|
||||
if (this->clipping_rectangle_.empty()) {
|
||||
return Rect();
|
||||
} else {
|
||||
return this->clipping_rectangle_.back();
|
||||
}
|
||||
}
|
||||
|
||||
DisplayPage::DisplayPage(display_writer_t writer) : writer_(std::move(writer)) {}
|
||||
void DisplayPage::show() { this->parent_->show_page(this); }
|
||||
void DisplayPage::show_next() { this->next_->show(); }
|
||||
void DisplayPage::show_prev() { this->prev_->show(); }
|
||||
void DisplayPage::set_parent(DisplayBuffer *parent) { this->parent_ = parent; }
|
||||
void DisplayPage::set_prev(DisplayPage *prev) { this->prev_ = prev; }
|
||||
void DisplayPage::set_next(DisplayPage *next) { this->next_ = next; }
|
||||
const display_writer_t &DisplayPage::get_writer() const { return this->writer_; }
|
||||
|
||||
} // namespace display
|
||||
} // namespace esphome
|
||||
|
|
|
@ -2,568 +2,35 @@
|
|||
|
||||
#include <cstdarg>
|
||||
#include <vector>
|
||||
#include "rect.h"
|
||||
|
||||
#include "display.h"
|
||||
#include "display_color_utils.h"
|
||||
#include "esphome/core/automation.h"
|
||||
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/defines.h"
|
||||
#include "esphome/core/time.h"
|
||||
|
||||
#ifdef USE_GRAPH
|
||||
#include "esphome/components/graph/graph.h"
|
||||
#endif
|
||||
|
||||
#ifdef USE_QR_CODE
|
||||
#include "esphome/components/qr_code/qr_code.h"
|
||||
#endif
|
||||
|
||||
namespace esphome {
|
||||
namespace display {
|
||||
|
||||
/** TextAlign is used to tell the display class how to position a piece of text. By default
|
||||
* the coordinates you enter for the print*() functions take the upper left corner of the text
|
||||
* as the "anchor" point. You can customize this behavior to, for example, make the coordinates
|
||||
* refer to the *center* of the text.
|
||||
*
|
||||
* All text alignments consist of an X and Y-coordinate alignment. For the alignment along the X-axis
|
||||
* these options are allowed:
|
||||
*
|
||||
* - LEFT (x-coordinate of anchor point is on left)
|
||||
* - CENTER_HORIZONTAL (x-coordinate of anchor point is in the horizontal center of the text)
|
||||
* - RIGHT (x-coordinate of anchor point is on right)
|
||||
*
|
||||
* For the Y-Axis alignment these options are allowed:
|
||||
*
|
||||
* - TOP (y-coordinate of anchor is on the top of the text)
|
||||
* - CENTER_VERTICAL (y-coordinate of anchor is in the vertical center of the text)
|
||||
* - BASELINE (y-coordinate of anchor is on the baseline of the text)
|
||||
* - BOTTOM (y-coordinate of anchor is on the bottom of the text)
|
||||
*
|
||||
* These options are then combined to create combined TextAlignment options like:
|
||||
* - TOP_LEFT (default)
|
||||
* - CENTER (anchor point is in the middle of the text bounds)
|
||||
* - ...
|
||||
*/
|
||||
enum class TextAlign {
|
||||
TOP = 0x00,
|
||||
CENTER_VERTICAL = 0x01,
|
||||
BASELINE = 0x02,
|
||||
BOTTOM = 0x04,
|
||||
|
||||
LEFT = 0x00,
|
||||
CENTER_HORIZONTAL = 0x08,
|
||||
RIGHT = 0x10,
|
||||
|
||||
TOP_LEFT = TOP | LEFT,
|
||||
TOP_CENTER = TOP | CENTER_HORIZONTAL,
|
||||
TOP_RIGHT = TOP | RIGHT,
|
||||
|
||||
CENTER_LEFT = CENTER_VERTICAL | LEFT,
|
||||
CENTER = CENTER_VERTICAL | CENTER_HORIZONTAL,
|
||||
CENTER_RIGHT = CENTER_VERTICAL | RIGHT,
|
||||
|
||||
BASELINE_LEFT = BASELINE | LEFT,
|
||||
BASELINE_CENTER = BASELINE | CENTER_HORIZONTAL,
|
||||
BASELINE_RIGHT = BASELINE | RIGHT,
|
||||
|
||||
BOTTOM_LEFT = BOTTOM | LEFT,
|
||||
BOTTOM_CENTER = BOTTOM | CENTER_HORIZONTAL,
|
||||
BOTTOM_RIGHT = BOTTOM | RIGHT,
|
||||
};
|
||||
|
||||
/** ImageAlign is used to tell the display class how to position a image. By default
|
||||
* the coordinates you enter for the image() functions take the upper left corner of the image
|
||||
* as the "anchor" point. You can customize this behavior to, for example, make the coordinates
|
||||
* refer to the *center* of the image.
|
||||
*
|
||||
* All image alignments consist of an X and Y-coordinate alignment. For the alignment along the X-axis
|
||||
* these options are allowed:
|
||||
*
|
||||
* - LEFT (x-coordinate of anchor point is on left)
|
||||
* - CENTER_HORIZONTAL (x-coordinate of anchor point is in the horizontal center of the image)
|
||||
* - RIGHT (x-coordinate of anchor point is on right)
|
||||
*
|
||||
* For the Y-Axis alignment these options are allowed:
|
||||
*
|
||||
* - TOP (y-coordinate of anchor is on the top of the image)
|
||||
* - CENTER_VERTICAL (y-coordinate of anchor is in the vertical center of the image)
|
||||
* - BOTTOM (y-coordinate of anchor is on the bottom of the image)
|
||||
*
|
||||
* These options are then combined to create combined TextAlignment options like:
|
||||
* - TOP_LEFT (default)
|
||||
* - CENTER (anchor point is in the middle of the image bounds)
|
||||
* - ...
|
||||
*/
|
||||
enum class ImageAlign {
|
||||
TOP = 0x00,
|
||||
CENTER_VERTICAL = 0x01,
|
||||
BOTTOM = 0x02,
|
||||
|
||||
LEFT = 0x00,
|
||||
CENTER_HORIZONTAL = 0x04,
|
||||
RIGHT = 0x08,
|
||||
|
||||
TOP_LEFT = TOP | LEFT,
|
||||
TOP_CENTER = TOP | CENTER_HORIZONTAL,
|
||||
TOP_RIGHT = TOP | RIGHT,
|
||||
|
||||
CENTER_LEFT = CENTER_VERTICAL | LEFT,
|
||||
CENTER = CENTER_VERTICAL | CENTER_HORIZONTAL,
|
||||
CENTER_RIGHT = CENTER_VERTICAL | RIGHT,
|
||||
|
||||
BOTTOM_LEFT = BOTTOM | LEFT,
|
||||
BOTTOM_CENTER = BOTTOM | CENTER_HORIZONTAL,
|
||||
BOTTOM_RIGHT = BOTTOM | RIGHT,
|
||||
|
||||
HORIZONTAL_ALIGNMENT = LEFT | CENTER_HORIZONTAL | RIGHT,
|
||||
VERTICAL_ALIGNMENT = TOP | CENTER_VERTICAL | BOTTOM
|
||||
};
|
||||
|
||||
enum DisplayType {
|
||||
DISPLAY_TYPE_BINARY = 1,
|
||||
DISPLAY_TYPE_GRAYSCALE = 2,
|
||||
DISPLAY_TYPE_COLOR = 3,
|
||||
};
|
||||
|
||||
enum DisplayRotation {
|
||||
DISPLAY_ROTATION_0_DEGREES = 0,
|
||||
DISPLAY_ROTATION_90_DEGREES = 90,
|
||||
DISPLAY_ROTATION_180_DEGREES = 180,
|
||||
DISPLAY_ROTATION_270_DEGREES = 270,
|
||||
};
|
||||
|
||||
class DisplayBuffer;
|
||||
class DisplayPage;
|
||||
class DisplayOnPageChangeTrigger;
|
||||
|
||||
using display_writer_t = std::function<void(DisplayBuffer &)>;
|
||||
|
||||
#define LOG_DISPLAY(prefix, type, obj) \
|
||||
if ((obj) != nullptr) { \
|
||||
ESP_LOGCONFIG(TAG, prefix type); \
|
||||
ESP_LOGCONFIG(TAG, "%s Rotations: %d °", prefix, (obj)->rotation_); \
|
||||
ESP_LOGCONFIG(TAG, "%s Dimensions: %dpx x %dpx", prefix, (obj)->get_width(), (obj)->get_height()); \
|
||||
}
|
||||
|
||||
/// Turn the pixel OFF.
|
||||
extern const Color COLOR_OFF;
|
||||
/// Turn the pixel ON.
|
||||
extern const Color COLOR_ON;
|
||||
|
||||
class BaseImage {
|
||||
class DisplayBuffer : public Display {
|
||||
public:
|
||||
virtual void draw(int x, int y, DisplayBuffer *display, Color color_on, Color color_off) = 0;
|
||||
virtual int get_width() const = 0;
|
||||
virtual int get_height() const = 0;
|
||||
};
|
||||
|
||||
class BaseFont {
|
||||
public:
|
||||
virtual void print(int x, int y, DisplayBuffer *display, Color color, const char *text) = 0;
|
||||
virtual void measure(const char *str, int *width, int *x_offset, int *baseline, int *height) = 0;
|
||||
};
|
||||
|
||||
class DisplayBuffer {
|
||||
public:
|
||||
/// Fill the entire screen with the given color.
|
||||
virtual void fill(Color color);
|
||||
/// Clear the entire screen by filling it with OFF pixels.
|
||||
void clear();
|
||||
|
||||
/// Get the width of the image in pixels with rotation applied.
|
||||
int get_width();
|
||||
int get_width() override;
|
||||
/// Get the height of the image in pixels with rotation applied.
|
||||
int get_height();
|
||||
int get_height() override;
|
||||
|
||||
/// Set a single pixel at the specified coordinates to the given color.
|
||||
void draw_pixel_at(int x, int y, Color color = COLOR_ON);
|
||||
|
||||
/// Draw a straight line from the point [x1,y1] to [x2,y2] with the given color.
|
||||
void line(int x1, int y1, int x2, int y2, Color color = COLOR_ON);
|
||||
|
||||
/// Draw a horizontal line from the point [x,y] to [x+width,y] with the given color.
|
||||
void horizontal_line(int x, int y, int width, Color color = COLOR_ON);
|
||||
|
||||
/// Draw a vertical line from the point [x,y] to [x,y+width] with the given color.
|
||||
void vertical_line(int x, int y, 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+width,y1+height].
|
||||
void 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,y1+height].
|
||||
void filled_rectangle(int x1, int y1, int width, int height, Color color = COLOR_ON);
|
||||
|
||||
/// Draw the outline of a circle centered around [center_x,center_y] with the radius radius with the given color.
|
||||
void circle(int center_x, int center_xy, 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_circle(int center_x, int center_y, int radius, Color color = COLOR_ON);
|
||||
|
||||
/** Print `text` with the anchor point at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the text alignment anchor point.
|
||||
* @param y The y coordinate of the text alignment anchor point.
|
||||
* @param font The font to draw the text with.
|
||||
* @param color The color to draw the text with.
|
||||
* @param align The alignment of the text.
|
||||
* @param text The text to draw.
|
||||
*/
|
||||
void print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text);
|
||||
|
||||
/** Print `text` with the top left at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param font The font to draw the text with.
|
||||
* @param color The color to draw the text with.
|
||||
* @param text The text to draw.
|
||||
*/
|
||||
void print(int x, int y, BaseFont *font, Color color, const char *text);
|
||||
|
||||
/** Print `text` with the anchor point at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the text alignment anchor point.
|
||||
* @param y The y coordinate of the text alignment anchor point.
|
||||
* @param font The font to draw the text with.
|
||||
* @param align The alignment of the text.
|
||||
* @param text The text to draw.
|
||||
*/
|
||||
void print(int x, int y, BaseFont *font, TextAlign align, const char *text);
|
||||
|
||||
/** Print `text` with the top left at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param font The font to draw the text with.
|
||||
* @param text The text to draw.
|
||||
*/
|
||||
void print(int x, int y, BaseFont *font, const char *text);
|
||||
|
||||
/** Evaluate the printf-format `format` and print the result with the anchor point at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the text alignment anchor point.
|
||||
* @param y The y coordinate of the text alignment anchor point.
|
||||
* @param font The font to draw the text with.
|
||||
* @param color The color to draw the text with.
|
||||
* @param align The alignment of the text.
|
||||
* @param format The format to use.
|
||||
* @param ... The arguments to use for the text formatting.
|
||||
*/
|
||||
void printf(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ...)
|
||||
__attribute__((format(printf, 7, 8)));
|
||||
|
||||
/** Evaluate the printf-format `format` and print the result with the top left at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param font The font to draw the text with.
|
||||
* @param color The color to draw the text with.
|
||||
* @param format The format to use.
|
||||
* @param ... The arguments to use for the text formatting.
|
||||
*/
|
||||
void printf(int x, int y, BaseFont *font, Color color, const char *format, ...) __attribute__((format(printf, 6, 7)));
|
||||
|
||||
/** Evaluate the printf-format `format` and print the result with the anchor point at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the text alignment anchor point.
|
||||
* @param y The y coordinate of the text alignment anchor point.
|
||||
* @param font The font to draw the text with.
|
||||
* @param align The alignment of the text.
|
||||
* @param format The format to use.
|
||||
* @param ... The arguments to use for the text formatting.
|
||||
*/
|
||||
void printf(int x, int y, BaseFont *font, TextAlign align, const char *format, ...)
|
||||
__attribute__((format(printf, 6, 7)));
|
||||
|
||||
/** Evaluate the printf-format `format` and print the result with the top left at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param font The font to draw the text with.
|
||||
* @param format The format to use.
|
||||
* @param ... The arguments to use for the text formatting.
|
||||
*/
|
||||
void printf(int x, int y, BaseFont *font, const char *format, ...) __attribute__((format(printf, 5, 6)));
|
||||
|
||||
/** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the text alignment anchor point.
|
||||
* @param y The y coordinate of the text alignment anchor point.
|
||||
* @param font The font to draw the text with.
|
||||
* @param color The color to draw the text with.
|
||||
* @param align The alignment of the text.
|
||||
* @param format The strftime format to use.
|
||||
* @param time The time to format.
|
||||
*/
|
||||
void strftime(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, ESPTime time)
|
||||
__attribute__((format(strftime, 7, 0)));
|
||||
|
||||
/** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param font The font to draw the text with.
|
||||
* @param color The color to draw the text with.
|
||||
* @param format The strftime format to use.
|
||||
* @param time The time to format.
|
||||
*/
|
||||
void strftime(int x, int y, BaseFont *font, Color color, const char *format, ESPTime time)
|
||||
__attribute__((format(strftime, 6, 0)));
|
||||
|
||||
/** Evaluate the strftime-format `format` and print the result with the anchor point at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the text alignment anchor point.
|
||||
* @param y The y coordinate of the text alignment anchor point.
|
||||
* @param font The font to draw the text with.
|
||||
* @param align The alignment of the text.
|
||||
* @param format The strftime format to use.
|
||||
* @param time The time to format.
|
||||
*/
|
||||
void strftime(int x, int y, BaseFont *font, TextAlign align, const char *format, ESPTime time)
|
||||
__attribute__((format(strftime, 6, 0)));
|
||||
|
||||
/** Evaluate the strftime-format `format` and print the result with the top left at [x,y] with `font`.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param font The font to draw the text with.
|
||||
* @param format The strftime format to use.
|
||||
* @param time The time to format.
|
||||
*/
|
||||
void strftime(int x, int y, BaseFont *font, const char *format, ESPTime time) __attribute__((format(strftime, 5, 0)));
|
||||
|
||||
/** Draw the `image` with the top-left corner at [x,y] to the screen.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param image The image to draw.
|
||||
* @param color_on The color to replace in binary images for the on bits.
|
||||
* @param color_off The color to replace in binary images for the off bits.
|
||||
*/
|
||||
void image(int x, int y, BaseImage *image, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
|
||||
|
||||
/** Draw the `image` at [x,y] to the screen.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param image The image to draw.
|
||||
* @param align The alignment of the image.
|
||||
* @param color_on The color to replace in binary images for the on bits.
|
||||
* @param color_off The color to replace in binary images for the off bits.
|
||||
*/
|
||||
void image(int x, int y, BaseImage *image, ImageAlign align, Color color_on = COLOR_ON, Color color_off = COLOR_OFF);
|
||||
|
||||
#ifdef USE_GRAPH
|
||||
/** Draw the `graph` with the top-left corner at [x,y] to the screen.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param graph The graph id to draw
|
||||
* @param color_on The color to replace in binary images for the on bits.
|
||||
*/
|
||||
void graph(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.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param graph The graph id for which the legend applies to
|
||||
* @param graph The graph id for which the legend applies to
|
||||
* @param graph The graph id for which the legend applies to
|
||||
* @param name_font The font used for the trace name
|
||||
* @param value_font The font used for the trace value and units
|
||||
* @param color_on The color of the border
|
||||
*/
|
||||
void legend(int x, int y, graph::Graph *graph, Color color_on = COLOR_ON);
|
||||
#endif // USE_GRAPH
|
||||
|
||||
#ifdef USE_QR_CODE
|
||||
/** Draw the `qr_code` with the top-left corner at [x,y] to the screen.
|
||||
*
|
||||
* @param x The x coordinate of the upper left corner.
|
||||
* @param y The y coordinate of the upper left corner.
|
||||
* @param qr_code The qr_code to draw
|
||||
* @param color_on The color to replace in binary images for the on bits.
|
||||
*/
|
||||
void qr_code(int x, int y, qr_code::QrCode *qr_code, Color color_on = COLOR_ON, int scale = 1);
|
||||
#endif
|
||||
|
||||
/** Get the text bounds of the given string.
|
||||
*
|
||||
* @param x The x coordinate to place the string at, can be 0 if only interested in dimensions.
|
||||
* @param y The y coordinate to place the string at, can be 0 if only interested in dimensions.
|
||||
* @param text The text to measure.
|
||||
* @param font The font to measure the text bounds with.
|
||||
* @param align The alignment of the text. Set to TextAlign::TOP_LEFT if only interested in dimensions.
|
||||
* @param x1 A pointer to store the returned x coordinate of the upper left corner in.
|
||||
* @param y1 A pointer to store the returned y coordinate of the upper left corner in.
|
||||
* @param width A pointer to store the returned text width in.
|
||||
* @param height A pointer to store the returned text height in.
|
||||
*/
|
||||
void get_text_bounds(int x, int y, const char *text, BaseFont *font, TextAlign align, int *x1, int *y1, int *width,
|
||||
int *height);
|
||||
|
||||
/// Internal method to set the display writer lambda.
|
||||
void set_writer(display_writer_t &&writer);
|
||||
|
||||
void show_page(DisplayPage *page);
|
||||
void show_next_page();
|
||||
void show_prev_page();
|
||||
|
||||
void set_pages(std::vector<DisplayPage *> pages);
|
||||
|
||||
const DisplayPage *get_active_page() const { return this->page_; }
|
||||
|
||||
void add_on_page_change_trigger(DisplayOnPageChangeTrigger *t) { this->on_page_change_triggers_.push_back(t); }
|
||||
|
||||
/// Internal method to set the display rotation with.
|
||||
void set_rotation(DisplayRotation rotation);
|
||||
|
||||
// Internal method to set display auto clearing.
|
||||
void set_auto_clear(bool auto_clear_enabled) { this->auto_clear_enabled_ = auto_clear_enabled; }
|
||||
void draw_pixel_at(int x, int y, Color color) override;
|
||||
|
||||
virtual int get_height_internal() = 0;
|
||||
virtual int get_width_internal() = 0;
|
||||
DisplayRotation get_rotation() const { return this->rotation_; }
|
||||
|
||||
/** Get the type of display that the buffer corresponds to. In case of dynamically configurable displays,
|
||||
* returns the type the display is currently configured to.
|
||||
*/
|
||||
virtual DisplayType get_display_type() = 0;
|
||||
|
||||
/** Set the clipping rectangle for further drawing
|
||||
*
|
||||
* @param[in] rect: Pointer to Rect for clipping (or NULL for entire screen)
|
||||
*
|
||||
* return true if success, false if error
|
||||
*/
|
||||
void start_clipping(Rect rect);
|
||||
void start_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
|
||||
start_clipping(Rect(left, top, right - left, bottom - top));
|
||||
};
|
||||
|
||||
/** Add a rectangular region to the invalidation region
|
||||
* - This is usually called when an element has been modified
|
||||
*
|
||||
* @param[in] rect: Rectangle to add to the invalidation region
|
||||
*/
|
||||
void extend_clipping(Rect rect);
|
||||
void extend_clipping(int16_t left, int16_t top, int16_t right, int16_t bottom) {
|
||||
this->extend_clipping(Rect(left, top, right - left, bottom - top));
|
||||
};
|
||||
|
||||
/** substract a rectangular region to the invalidation region
|
||||
* - This is usually called when an element has been modified
|
||||
*
|
||||
* @param[in] rect: Rectangle to add to the invalidation region
|
||||
*/
|
||||
void shrink_clipping(Rect rect);
|
||||
void shrink_clipping(uint16_t left, uint16_t top, uint16_t right, uint16_t bottom) {
|
||||
this->shrink_clipping(Rect(left, top, right - left, bottom - top));
|
||||
};
|
||||
|
||||
/** Reset the invalidation region
|
||||
*/
|
||||
void end_clipping();
|
||||
|
||||
/** Get the current the clipping rectangle
|
||||
*
|
||||
* return rect for active clipping region
|
||||
*/
|
||||
Rect get_clipping();
|
||||
|
||||
bool is_clipping() const { return !this->clipping_rectangle_.empty(); }
|
||||
|
||||
protected:
|
||||
void vprintf_(int x, int y, BaseFont *font, Color color, TextAlign align, const char *format, va_list arg);
|
||||
|
||||
virtual void draw_absolute_pixel_internal(int x, int y, Color color) = 0;
|
||||
|
||||
void init_internal_(uint32_t buffer_length);
|
||||
|
||||
void do_update_();
|
||||
|
||||
uint8_t *buffer_{nullptr};
|
||||
DisplayRotation rotation_{DISPLAY_ROTATION_0_DEGREES};
|
||||
optional<display_writer_t> writer_{};
|
||||
DisplayPage *page_{nullptr};
|
||||
DisplayPage *previous_page_{nullptr};
|
||||
std::vector<DisplayOnPageChangeTrigger *> on_page_change_triggers_;
|
||||
bool auto_clear_enabled_{true};
|
||||
std::vector<Rect> clipping_rectangle_;
|
||||
};
|
||||
|
||||
class DisplayPage {
|
||||
public:
|
||||
DisplayPage(display_writer_t writer);
|
||||
void show();
|
||||
void show_next();
|
||||
void show_prev();
|
||||
void set_parent(DisplayBuffer *parent);
|
||||
void set_prev(DisplayPage *prev);
|
||||
void set_next(DisplayPage *next);
|
||||
const display_writer_t &get_writer() const;
|
||||
|
||||
protected:
|
||||
DisplayBuffer *parent_;
|
||||
display_writer_t writer_;
|
||||
DisplayPage *prev_{nullptr};
|
||||
DisplayPage *next_{nullptr};
|
||||
};
|
||||
|
||||
template<typename... Ts> class DisplayPageShowAction : public Action<Ts...> {
|
||||
public:
|
||||
TEMPLATABLE_VALUE(DisplayPage *, page)
|
||||
|
||||
void play(Ts... x) override {
|
||||
auto *page = this->page_.value(x...);
|
||||
if (page != nullptr) {
|
||||
page->show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename... Ts> class DisplayPageShowNextAction : public Action<Ts...> {
|
||||
public:
|
||||
DisplayPageShowNextAction(DisplayBuffer *buffer) : buffer_(buffer) {}
|
||||
|
||||
void play(Ts... x) override { this->buffer_->show_next_page(); }
|
||||
|
||||
DisplayBuffer *buffer_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class DisplayPageShowPrevAction : public Action<Ts...> {
|
||||
public:
|
||||
DisplayPageShowPrevAction(DisplayBuffer *buffer) : buffer_(buffer) {}
|
||||
|
||||
void play(Ts... x) override { this->buffer_->show_prev_page(); }
|
||||
|
||||
DisplayBuffer *buffer_;
|
||||
};
|
||||
|
||||
template<typename... Ts> class DisplayIsDisplayingPageCondition : public Condition<Ts...> {
|
||||
public:
|
||||
DisplayIsDisplayingPageCondition(DisplayBuffer *parent) : parent_(parent) {}
|
||||
|
||||
void set_page(DisplayPage *page) { this->page_ = page; }
|
||||
bool check(Ts... x) override { return this->parent_->get_active_page() == this->page_; }
|
||||
|
||||
protected:
|
||||
DisplayBuffer *parent_;
|
||||
DisplayPage *page_;
|
||||
};
|
||||
|
||||
class DisplayOnPageChangeTrigger : public Trigger<DisplayPage *, DisplayPage *> {
|
||||
public:
|
||||
explicit DisplayOnPageChangeTrigger(DisplayBuffer *parent) { parent->add_on_page_change_trigger(this); }
|
||||
void process(DisplayPage *from, DisplayPage *to);
|
||||
void set_from(DisplayPage *p) { this->from_ = p; }
|
||||
void set_to(DisplayPage *p) { this->to_ = p; }
|
||||
|
||||
protected:
|
||||
DisplayPage *from_{nullptr};
|
||||
DisplayPage *to_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace display
|
||||
|
|
|
@ -10,7 +10,7 @@ namespace font {
|
|||
|
||||
static const char *const TAG = "font";
|
||||
|
||||
void Glyph::draw(int x_at, int y_start, display::DisplayBuffer *display, Color color) const {
|
||||
void Glyph::draw(int x_at, int y_start, display::Display *display, Color color) const {
|
||||
int scan_x1, scan_y1, scan_width, scan_height;
|
||||
this->scan_area(&scan_x1, &scan_y1, &scan_width, &scan_height);
|
||||
|
||||
|
@ -118,7 +118,7 @@ void Font::measure(const char *str, int *width, int *x_offset, int *baseline, in
|
|||
*x_offset = min_x;
|
||||
*width = x - min_x;
|
||||
}
|
||||
void Font::print(int x_start, int y_start, display::DisplayBuffer *display, Color color, const char *text) {
|
||||
void Font::print(int x_start, int y_start, display::Display *display, Color color, const char *text) {
|
||||
int i = 0;
|
||||
int x_at = x_start;
|
||||
while (text[i] != '\0') {
|
||||
|
|
|
@ -22,7 +22,7 @@ class Glyph {
|
|||
public:
|
||||
Glyph(const GlyphData *data) : glyph_data_(data) {}
|
||||
|
||||
void draw(int x, int y, display::DisplayBuffer *display, Color color) const;
|
||||
void draw(int x, int y, display::Display *display, Color color) const;
|
||||
|
||||
const char *get_char() const;
|
||||
|
||||
|
@ -50,7 +50,7 @@ class Font : public display::BaseFont {
|
|||
|
||||
int match_next_glyph(const char *str, int *match_length);
|
||||
|
||||
void print(int x_start, int y_start, display::DisplayBuffer *display, Color color, const char *text) override;
|
||||
void print(int x_start, int y_start, display::Display *display, Color color, const char *text) override;
|
||||
void measure(const char *str, int *width, int *x_offset, int *baseline, int *height) override;
|
||||
inline int get_baseline() { return this->baseline_; }
|
||||
inline int get_height() { return this->height_; }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "graph.h"
|
||||
#include "esphome/components/display/display_buffer.h"
|
||||
#include "esphome/components/display/display.h"
|
||||
#include "esphome/core/color.h"
|
||||
#include "esphome/core/log.h"
|
||||
#include "esphome/core/hal.h"
|
||||
|
@ -56,7 +56,7 @@ void GraphTrace::init(Graph *g) {
|
|||
this->data_.set_update_time_ms(g->get_duration() * 1000 / g->get_width());
|
||||
}
|
||||
|
||||
void Graph::draw(DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color) {
|
||||
void Graph::draw(Display *buff, uint16_t x_offset, uint16_t y_offset, Color color) {
|
||||
/// Plot border
|
||||
if (this->border_) {
|
||||
buff->horizontal_line(x_offset, y_offset, this->width_, color);
|
||||
|
@ -303,7 +303,7 @@ void GraphLegend::init(Graph *g) {
|
|||
}
|
||||
}
|
||||
|
||||
void Graph::draw_legend(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color) {
|
||||
void Graph::draw_legend(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color) {
|
||||
if (!legend_)
|
||||
return;
|
||||
|
||||
|
|
|
@ -8,9 +8,9 @@
|
|||
|
||||
namespace esphome {
|
||||
|
||||
// forward declare DisplayBuffer
|
||||
// forward declare Display
|
||||
namespace display {
|
||||
class DisplayBuffer;
|
||||
class Display;
|
||||
class BaseFont;
|
||||
} // namespace display
|
||||
|
||||
|
@ -133,8 +133,8 @@ class GraphTrace {
|
|||
|
||||
class Graph : public Component {
|
||||
public:
|
||||
void draw(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color);
|
||||
void draw_legend(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color);
|
||||
void draw(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color);
|
||||
void draw_legend(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color);
|
||||
|
||||
void setup() override;
|
||||
float get_setup_priority() const override { return setup_priority::PROCESSOR; }
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
namespace esphome {
|
||||
namespace image {
|
||||
|
||||
void Image::draw(int x, int y, display::DisplayBuffer *display, Color color_on, Color color_off) {
|
||||
void Image::draw(int x, int y, display::Display *display, Color color_on, Color color_off) {
|
||||
switch (type_) {
|
||||
case IMAGE_TYPE_BINARY: {
|
||||
for (int img_x = 0; img_x < width_; img_x++) {
|
||||
|
|
|
@ -39,7 +39,7 @@ class Image : public display::BaseImage {
|
|||
int get_height() const override;
|
||||
ImageType get_type() const;
|
||||
|
||||
void draw(int x, int y, display::DisplayBuffer *display, Color color_on, Color color_off) override;
|
||||
void draw(int x, int y, display::Display *display, Color color_on, Color color_off) override;
|
||||
|
||||
void set_transparency(bool transparent) { transparent_ = transparent; }
|
||||
bool has_transparency() const { return transparent_; }
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "qr_code.h"
|
||||
#include "esphome/components/display/display_buffer.h"
|
||||
#include "esphome/components/display/display.h"
|
||||
#include "esphome/core/color.h"
|
||||
#include "esphome/core/log.h"
|
||||
|
||||
|
@ -33,7 +33,7 @@ void QrCode::generate_qr_code() {
|
|||
}
|
||||
}
|
||||
|
||||
void QrCode::draw(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color, int scale) {
|
||||
void QrCode::draw(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color, int scale) {
|
||||
ESP_LOGV(TAG, "Drawing QR code at (%d, %d)", x_offset, y_offset);
|
||||
|
||||
if (this->needs_update_) {
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
namespace esphome {
|
||||
// forward declare DisplayBuffer
|
||||
namespace display {
|
||||
class DisplayBuffer;
|
||||
class Display;
|
||||
} // namespace display
|
||||
|
||||
namespace qr_code {
|
||||
class QrCode : public Component {
|
||||
public:
|
||||
void draw(display::DisplayBuffer *buff, uint16_t x_offset, uint16_t y_offset, Color color, int scale);
|
||||
void draw(display::Display *buff, uint16_t x_offset, uint16_t y_offset, Color color, int scale);
|
||||
|
||||
void dump_config() override;
|
||||
|
||||
|
|
|
@ -7,6 +7,17 @@ namespace touchscreen {
|
|||
|
||||
static const char *const TAG = "touchscreen";
|
||||
|
||||
void Touchscreen::set_display(display::Display *display) {
|
||||
this->display_ = display;
|
||||
this->display_width_ = display->get_width();
|
||||
this->display_height_ = display->get_height();
|
||||
this->rotation_ = static_cast<TouchRotation>(display->get_rotation());
|
||||
|
||||
if (this->rotation_ == ROTATE_90_DEGREES || this->rotation_ == ROTATE_270_DEGREES) {
|
||||
std::swap(this->display_width_, this->display_height_);
|
||||
}
|
||||
}
|
||||
|
||||
void Touchscreen::send_touch_(TouchPoint tp) {
|
||||
ESP_LOGV(TAG, "Touch (x=%d, y=%d)", tp.x, tp.y);
|
||||
this->touch_trigger_.trigger(tp);
|
||||
|
|
|
@ -31,13 +31,8 @@ enum TouchRotation {
|
|||
|
||||
class Touchscreen {
|
||||
public:
|
||||
void set_display(display::DisplayBuffer *display) {
|
||||
this->display_ = display;
|
||||
this->display_width_ = display->get_width_internal();
|
||||
this->display_height_ = display->get_height_internal();
|
||||
this->rotation_ = static_cast<TouchRotation>(display->get_rotation());
|
||||
}
|
||||
display::DisplayBuffer *get_display() const { return this->display_; }
|
||||
void set_display(display::Display *display);
|
||||
display::Display *get_display() const { return this->display_; }
|
||||
|
||||
Trigger<TouchPoint> *get_touch_trigger() { return &this->touch_trigger_; }
|
||||
|
||||
|
@ -49,7 +44,7 @@ class Touchscreen {
|
|||
|
||||
uint16_t display_width_;
|
||||
uint16_t display_height_;
|
||||
display::DisplayBuffer *display_;
|
||||
display::Display *display_;
|
||||
TouchRotation rotation_;
|
||||
Trigger<TouchPoint> touch_trigger_;
|
||||
std::vector<TouchListener *> touch_listeners_;
|
||||
|
|
|
@ -607,7 +607,7 @@ def lint_trailing_whitespace(fname, match):
|
|||
"esphome/components/button/button.h",
|
||||
"esphome/components/climate/climate.h",
|
||||
"esphome/components/cover/cover.h",
|
||||
"esphome/components/display/display_buffer.h",
|
||||
"esphome/components/display/display.h",
|
||||
"esphome/components/fan/fan.h",
|
||||
"esphome/components/i2c/i2c.h",
|
||||
"esphome/components/lock/lock.h",
|
||||
|
|
Loading…
Reference in a new issue