diff --git a/esphome/components/display/display.cpp b/esphome/components/display/display.cpp index 22454aeddb..49c9d8a80a 100644 --- a/esphome/components/display/display.cpp +++ b/esphome/components/display/display.cpp @@ -334,6 +334,35 @@ bool Display::clip(int x, int y) { return false; return true; } + +void Display::set_local_coordinates_relative_to_current(int x_offset, int y_offset) { + Point p(0, 0); + if (!this->local_coordinate_.empty()) { + p = this->local_coordinate_.back(); + } + p.x += x_offset; + p.y += y_offset; + + this->local_coordinate_.push_back(p); + +} +void Display::pop_local_coordinates() { + if (this->local_coordinate_.empty()) { + ESP_LOGE(TAG, "pop_local_coordinates: No local coordinates set"); + } else { + this->local_coordinate_.pop_back(); + } +} + +Point Display::get_local_coordinates() { + Point p(0, 0); + if (!this->local_coordinate_.empty()) { + p = this->local_coordinate_.back(); + } + + return p; +} + bool Display::clamp_x_(int x, int w, int &min_x, int &max_x) { min_x = std::max(x, 0); max_x = std::min(x + w, this->get_width()); diff --git a/esphome/components/display/display.h b/esphome/components/display/display.h index 7ce6d179ef..0e920aef1c 100644 --- a/esphome/components/display/display.h +++ b/esphome/components/display/display.h @@ -4,6 +4,7 @@ #include #include "rect.h" +#include "point.h" #include "esphome/core/color.h" #include "esphome/core/automation.h" @@ -480,6 +481,36 @@ class Display : public PollingComponent { */ bool clip(int x, int y); + /** Changes the local coordinates to be relative to (x, y). After calling a pixel + * drawn at (10, 20) would be drawn to the screen at (x + 10, y + 20) + * + * @param[in] x: x coordinate as the new local. Absolute to the displays underlying 0 + * @param[in] y: y coordinate as the new local. Absolute to the displays underlying 0 + */ + void set_local_coordinate(int x, int y) { this->local_coordinate_.push_back(Point(x, y)); }; + + /** Changes the local coordinates to be to be (x_local + x_offset, y_local + y_offset) + * After calling a pixel drawn at (10, 20) would be drawn to the screen at + * (x_local + x_offset + 10, y_local + y_offset + 20) + * + * @param[in] x_offset: x offset from the current local. Relative to the local x + * @param[in] y_offset: y offset from the current local. Relative to the local y + */ + void set_local_coordinates_relative_to_current(int x_offset, int y_offset); + + /** Removes the most recent local coordinate system from use + */ + void pop_local_coordinates(); + + /** Gets the current local coordinates in the displays absolute coordinate system + */ + Point get_local_coordinates(); + + /** Clears all the local coordinate systems and revers to the displays absolute coordinate + * system + */ + void clear_local_coordinates() { this->local_coordinate_.clear(); }; + protected: bool clamp_x_(int x, int w, int &min_x, int &max_x); bool clamp_y_(int y, int h, int &min_y, int &max_y); @@ -495,6 +526,7 @@ class Display : public PollingComponent { std::vector on_page_change_triggers_; bool auto_clear_enabled_{true}; std::vector clipping_rectangle_; + std::vector local_coordinate_; }; class DisplayPage { diff --git a/esphome/components/display/display_buffer.cpp b/esphome/components/display/display_buffer.cpp index 3af1b63e01..5015c8f3fd 100644 --- a/esphome/components/display/display_buffer.cpp +++ b/esphome/components/display/display_buffer.cpp @@ -4,6 +4,7 @@ #include "esphome/core/application.h" #include "esphome/core/log.h" +#include "point.h" namespace esphome { namespace display { @@ -45,6 +46,11 @@ int DisplayBuffer::get_height() { } void HOT DisplayBuffer::draw_pixel_at(int x, int y, Color color) { + // Convert (x, y) from the local coordinate system to the display absolute coordinate system + Point local_coord = this->get_local_coordinates(); + x += local_coord.x; + y += local_coord.y; + if (!this->get_clipping().inside(x, y)) return; // NOLINT diff --git a/esphome/components/display/point.h b/esphome/components/display/point.h new file mode 100644 index 0000000000..63dabdfa05 --- /dev/null +++ b/esphome/components/display/point.h @@ -0,0 +1,18 @@ +#pragma once + +#include "esphome/core/helpers.h" + +namespace esphome { +namespace display { + +class Point { + public: + int16_t x; + int16_t y; + + Point() : x(VALUE_NO_SET), y(VALUE_NO_SET) {}; + inline Point(int16_t x, int16_t y) ALWAYS_INLINE : x(x), y(y) {}; +}; + +} // namespace display +} // namespace esphome \ No newline at end of file