Add a local coordinate system

This introduces a local coordinate system to the display component. This is useful for nested/localised drawing without having to do repeated and error prone coordinate maths
This commit is contained in:
Michael Davidson 2024-08-11 16:51:48 +10:00
parent b43c5b851a
commit fb06f98df3
No known key found for this signature in database
GPG key ID: B8D1A99712B8B0EB
4 changed files with 85 additions and 0 deletions

View file

@ -579,6 +579,31 @@ 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());

View file

@ -4,10 +4,12 @@
#include <vector>
#include "rect.h"
#include "point.h"
#include "esphome/core/color.h"
#include "esphome/core/automation.h"
#include "esphome/core/time.h"
#include "esphome/core/log.h"
#include "display_color_utils.h"
#ifdef USE_GRAPH
@ -631,6 +633,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_.emplace_back(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(); };
void test_card();
void show_test_card() { this->show_test_card_ = true; }
@ -662,6 +694,7 @@ class Display : public PollingComponent {
std::vector<DisplayOnPageChangeTrigger *> on_page_change_triggers_;
bool auto_clear_enabled_{true};
std::vector<Rect> clipping_rectangle_;
std::vector<Point> local_coordinate_;
bool show_test_card_{false};
};
@ -737,5 +770,7 @@ class DisplayOnPageChangeTrigger : public Trigger<DisplayPage *, DisplayPage *>
DisplayPage *to_{nullptr};
};
const LogString *text_align_to_string(TextAlign textalign);
} // namespace display
} // namespace esphome

View file

@ -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

View file

@ -0,0 +1,19 @@
#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) ESPHOME_ALWAYS_INLINE : x(x), y(y){};
};
} // namespace display
} // namespace esphome