25#include "../initializer_list.h"
26#include "../types_traits.h"
27#include "../utilities.h"
83 template<
typename XCOORD,
typename YCOORD>
86 Point(XCOORD x, YCOORD y) : x{x}, y{y} {}
144 operator bool()
const
190 return source ^ dest;
193 return source & dest;
196 return source | dest;
217 return color_ ^ dest;
220 return color_ & dest;
223 return color_ | dest;
263 return (is_fill_ ? fill_ : draw_);
279 bool is_fill_ =
false;
281 DrawMode<COLOR> fill_{};
282 const Font<VERTICAL_FONT>* font_ =
nullptr;
284 template<
typename>
friend class Display;
391 template<
typename COLOR_, uint16_t WIDTH_, uint16_t HEIGHT_,
392 bool HAS_RASTER_ =
false,
bool VERTICAL_FONT_ =
false>
396 static constexpr bool IS_DISPLAY =
true;
397 using COLOR = COLOR_;
402 static constexpr XCOORD MAX_X = WIDTH_ - 1;
403 static constexpr YCOORD MAX_Y = HEIGHT_ - 1;
405 static constexpr uint16_t WIDTH = WIDTH_;
406 static constexpr uint16_t HEIGHT = HEIGHT_;
413 static constexpr bool VERTICAL_FONT = VERTICAL_FONT_;
414 static constexpr bool HAS_RASTER = HAS_RASTER_;
434 template<
typename DISPLAY_DEVICE>
class Display :
public DISPLAY_DEVICE
439 "DISPLAY_DEVICE must be a Display Device (a DisplayDeviceTrait must exist for it)!");
455 using POINT = Point<XCOORD, YCOORD>;
487 context_.draw_ = mode;
498 context_.fill_ = mode;
509 context_.font_ = &font;
531 DISPLAY_DEVICE::erase();
547 if (!check_font())
return;
549 const uint8_t width = context_.font_->
width();
552 if (!is_valid_char_xy(x, y, width))
return;
554 uint16_t glyph_ref = get_glyph(value);
555 if (glyph_ref == 0)
return;
557 uint8_t displayed_width = DISPLAY_DEVICE::write_char(x, y, glyph_ref, context_);
558 invalidate(x, y,
XCOORD(x + displayed_width),
YCOORD(y + context_.font_->
height() - 1));
573 if (!check_font())
return;
574 const uint8_t width = context_.font_->
width();
582 if (!is_valid_char_xy(xcurrent, y, width))
break;
584 uint16_t glyph_ref = get_glyph(*content);
585 if (glyph_ref == 0)
break;
587 const uint8_t displayed_width = DISPLAY_DEVICE::write_char(xcurrent, y, glyph_ref, context_);
588 xcurrent += displayed_width;
595 bool clear_error = (*content == 0);
596 invalidate(x, y,
XCOORD(xcurrent - 1),
YCOORD(y + context_.font_->
height() - 1), clear_error);
613 if (!check_font())
return;
614 const uint8_t width = context_.font_->
width();
619 uint16_t address = (uint16_t) content;
621 while ((value = pgm_read_byte(address)) != 0)
624 if (!is_valid_char_xy(xcurrent, y, width))
break;
626 uint16_t glyph_ref = get_glyph(value);
627 if (glyph_ref == 0)
break;
629 const uint8_t displayed_width = DISPLAY_DEVICE::write_char(xcurrent, y, glyph_ref, context_);
630 xcurrent += displayed_width;
637 bool clear_error = (value == 0);
638 invalidate(x, y,
XCOORD(xcurrent -1),
YCOORD(y + context_.font_->
height() - 1), clear_error);
651 if (!is_valid_xy(x, y))
return;
652 if (DISPLAY_DEVICE::set_pixel(x, y, context_))
653 invalidate(x, y, x, y);
671 if (!is_valid_xy(x1, y1))
return;
672 if (!is_valid_xy(x2, y2))
return;
684 swap_to_sort(y1, y2);
685 draw_vline(x1, y1, y2);
690 swap_to_sort(x1, x2);
691 draw_hline(x1, y1, x2);
698 draw_line_bresenham(x1, y1, x2, y2);
700 swap_to_sort(y1, y2);
702 invalidate(x1, y1, x2, y2);
730 if (!is_valid_xy(x1, y1))
return;
731 if (!is_valid_xy(x2, y2))
return;
732 if ((x1 == x2) || (y1 == y2))
738 swap_to_sort(x1, x2);
739 swap_to_sort(y1, y2);
740 if ((radius * 2 > x2 - x1) || (radius * 2 > y2 - y1))
750 SCALAR delta = (radius ? radius + 1 : 0);
752 draw_hline(x1 + radius, y1, x2 - delta);
753 draw_hline(x1 + radius, y2, x2 - delta);
756 draw_vline(x1, y1 + radius + 1, y2 - radius - 1);
757 draw_vline(x2, y1 + radius + 1, y2 - radius - 1);
760 if ((radius != 0) && (context_.draw_ || context_.fill_))
763 draw_circle_bresenham(x1 + radius, y1 + radius, x2 - radius, y2 - radius, radius);
769 context_.is_fill_ =
true;
772 SCALAR delta = (radius ? radius : 1);
773 for (
YCOORD y = y1 + delta; y < y2 - radius; ++y)
774 draw_hline(x1 + 1, y, x2 - 1);
775 context_.is_fill_ =
false;
778 invalidate(x1, y1, x2, y2);
791 if (!is_valid_xy(xc, yc))
return;
797 if ( (xc < radius) || (xc + radius >=
WIDTH)
798 || (yc < radius) || (yc + radius >=
HEIGHT))
804 draw_circle_bresenham(xc, yc, xc, yc, radius);
815 draw_lines(points,
false);
827 draw_lines(points,
true);
857 const XCOORD xorg = origin.x;
858 const YCOORD yorg = origin.y;
859 if (!is_valid_xy(xorg, yorg))
return;
862 if (!is_valid_xy(w, h))
return;
863 if (!is_valid_xy(xorg + w, yorg + h))
return;
865 if (context_.draw_ || context_.fill_)
867 const XCOORD cols = (w / 8) + (w % 8 ? 1 : 0);
870 for (ycurrent = yorg; ycurrent < yorg + h; ++ycurrent)
873 for (
XCOORD col = 0; col < cols; ++col)
875 uint8_t value = input_streamer();
877 for (uint8_t i = 0; i < 8; ++i)
881 DISPLAY_DEVICE::set_pixel(xcurrent, ycurrent, context_);
885 context_.is_fill_ =
true;
886 DISPLAY_DEVICE::set_pixel(xcurrent, ycurrent, context_);
887 context_.is_fill_ =
false;
895 invalidate(xorg, yorg,
XCOORD(xcurrent - 1),
YCOORD(ycurrent - 1));
910 DISPLAY_DEVICE::update(invalid_area_.x1, invalid_area_.y1, invalid_area_.x2, invalid_area_.y2);
911 invalid_area_.empty =
true;
931 InvalidArea() =
default;
932 InvalidArea(XCOORD x1, YCOORD y1, XCOORD x2, YCOORD y2)
933 : x1{x1}, y1{y1}, x2{x2}, y2{y2}, empty{false} {}
935 InvalidArea& operator+=(
const InvalidArea& a)
949 if (a.x1 < x1) x1 = a.x1;
950 if (a.y1 < y1) y1 = a.y1;
951 if (a.x2 > x2) x2 = a.x2;
952 if (a.y2 > y2) y2 = a.y2;
958 static InvalidArea EMPTY;
967 using INVALID_AREA = InvalidArea;
972 invalid_area_ += INVALID_AREA{x1, y1, x2, y2};
980 invalid_area_ = INVALID_AREA{0, 0,
WIDTH - 1,
HEIGHT - 1};
986 if (context_.font_ !=
nullptr)
return true;
998 bool is_valid_char_xy(
XCOORD x,
YCOORD y, uint8_t width)
1005 if (DISPLAY_DEVICE::is_valid_char_xy(x, y))
return true;
1010 uint16_t get_glyph(
char value)
1014 if (glyph_ref != 0)
return glyph_ref;
1021 if (points.
size() < 2)
1027 POINT current = *next;
1028 POINT first = current;
1029 while (++next != points.
end())
1034 if (!polygon || (next + 1) != points.
end())
1047 swap_to_sort(y1, y2);
1048 for (
YCOORD y = y1; y <= y2; ++y)
1049 DISPLAY_DEVICE::set_pixel(x1, y, context_);
1054 swap_to_sort(x1, x2);
1055 for (
XCOORD x = x1; x <= x2; ++x)
1056 DISPLAY_DEVICE::set_pixel(x, y1, context_);
1071 draw_line_bresenham_1st_quadrant(x1, y1, x2, y2, dx, dy);
1076 draw_line_bresenham_4th_quadrant(x1, y1, x2, y2, dx, dy);
1091 DISPLAY_DEVICE::set_pixel(x1, y1, context_);
1092 if (x1 == x2)
break;
1110 DISPLAY_DEVICE::set_pixel(x1, y1, context_);
1111 if (y1 == y2)
break;
1134 DISPLAY_DEVICE::set_pixel(x1, y1, context_);
1135 if (x1 == x2)
break;
1153 DISPLAY_DEVICE::set_pixel(x1, y1, context_);
1154 if (y1 == y2)
break;
1168 DISPLAY_DEVICE::set_pixel(x, y1, context_);
1170 DISPLAY_DEVICE::set_pixel(x, y2, context_);
1187 draw_pixels(x + xc2, y + yc2, -y + yc1);
1189 draw_pixels(-x + xc1, y + yc2, -y + yc1);
1192 draw_pixels(y + xc2, x + yc2, -x + yc1);
1194 draw_pixels(-y + xc1, x + yc2, -x + yc1);
1199 if (context_.fill_ && x != y)
1201 context_.is_fill_ =
true;
1202 draw_hline(y + xc2 - 1, x + yc2, -y + xc1 + 1);
1205 draw_hline(y + xc2 - 1, -x + yc1, -y + xc1 + 1);
1206 context_.is_fill_ =
false;
1211 if (context_.fill_ && y != radius)
1213 context_.is_fill_ =
true;
1214 draw_hline(xc2 + x - delta_x, yc1 - y, xc1 - x + delta_x);
1215 draw_hline(xc2 + x - delta_x, yc2 + y, xc1 - x + delta_x);
1216 context_.is_fill_ =
false;
1228 template<
typename COORD>
1229 static bool swap_to_sort(COORD& a1, COORD& a2)
1243 DRAW_CONTEXT context_{};
1249 INVALID_AREA invalid_area_ = INVALID_AREA::EMPTY;
1253 template<
typename DISPLAY_DEVICE>
1254 typename Display<DISPLAY_DEVICE>::InvalidArea Display<DISPLAY_DEVICE>::InvalidArea::EMPTY = InvalidArea{};
Class handling drawing primitives on any display device.
typename DISPLAY_TRAITS::SCALAR SCALAR
Integral type used in various calculations based on coordinates.
void draw_bitmap(POINT origin, POINT size, F input_streamer)
Draw a bitmap onto the display device.
Error last_error() const
Error code of latest called drawing primitive.
void draw_rectangle(POINT point1, POINT point2)
Draw a rectangle defined by 2 corner points, at given coordinates.
void erase()
Erase complete display.
Point< XCOORD, YCOORD > POINT
Coordinates of a point in the display.
Display()=default
Comstruct a display instance.
void draw_polyline(std::initializer_list< POINT > points)
Draw lines between consecutive points in the provided list.
typename DISPLAY_TRAITS::XCOORD XCOORD
Integral type of X coordinate.
void draw_string(POINT point, const char *content)
Draw a string of characters at the given display location.
void draw_char(POINT point, char value)
Draw one character at the given display location.
void draw_rounded_rectangle(POINT point1, POINT point2, SCALAR radius)
Draw a rounded rectangle defined by 2 corner points, at given coordinates, and the radius of circle a...
void draw_line(POINT point1, POINT point2)
Draw a line between 2 points, at given coordinates.
static constexpr XCOORD WIDTH
Display width.
void draw_point(POINT point)
Draw a pixel at given coordinate.
void set_draw_mode(const DRAW_MODE &mode)
Set draw mode (color, pixel op) to use for next calls to drawing primitives.
typename DISPLAY_TRAITS::COLOR COLOR
The type of one pixel color.
void draw_polygon(std::initializer_list< POINT > points)
Draw a polygon (closed surface) with lines between consecutive points in the provided list.
void force_update()
For display devices having a raster buffer, this method copies the whole raster buffer to the device.
void set_font(const FONT &font)
Set the new font to use for next calls to text drawing perimitives.
void update()
For display devices having a raster buffer, this method copies invalid (modified) parts of the raster...
typename DISPLAY_TRAITS::YCOORD YCOORD
Integral type of Y coordinate.
typename DISPLAY_TRAITS::SIGNED_SCALAR SIGNED_SCALAR
Integral signed type used in calculations of some drawing primitives.
static constexpr YCOORD HEIGHT
Display height.
void draw_circle(POINT center, SCALAR radius)
Draw a circle defined by its center, at given coordinates, and its radius.
void draw_string(POINT point, const flash::FlashStorage *content)
Draw a string of characters at the given display location.
void set_fill_mode(const DRAW_MODE &mode)
Set fill mode (color, pixel op) to use for next calls to drawing primitives (for closed surfaces only...
Drawing Context passed to display devices low-level primitives set_pixel() and write_char().
const Font< VERTICAL_FONT > & font() const
Return the current Font to use in the called primitive draw_char()
DrawMode< COLOR > draw_mode() const
Return the current DrawMode to use in the called primitive.
Drawing Mode to use for Display drawing primitives.
COLOR pixel_op(COLOR dest) const
Combine the predefined color (defined at construction time) with one destination pixel,...
DrawMode(Mode mode=Mode::NO_CHANGE, COLOR color=COLOR{})
Construct a new DrawMode object, to be sued with Display.
Mode mode() const
Return the current Mode for this DrawMode.
uint8_t bw_pixels_op(uint8_t source, uint8_t dest) const
Combine 8 source B&W pixels and 8 destination B&W pixels, all gathered in a byte, according to the Mo...
COLOR color() const
Return the current color for this DrawMode.
Generic font support class.
uint16_t get_char_glyph_ref(char value) const
Get a glyph reference for the requested character value.
uint8_t width() const
Width of font glyphs in pixels.
uint8_t height() const
Height of font glyphs in pixels.
C++ standard support for "initializer_list".
constexpr const T * begin() const
The first element of this initializer_list.
constexpr size_t size() const
The size of this initializer_list.
constexpr const T * end() const
One past the last element of this initializer_list.
#define F(ptr)
Force string constant to be stored as flash storage.
Generic API to handle Character Fonts for any display device.
Defines generic API for all display devices.
Error
Types of errors that can occur on Display instances.
@ INVALID_GEOMETRY
A drawing primitive would lead to incorrect geometry due to invalid arguments.
@ NO_FONT_SET
A text drawing primitive has been called but no font has been set yet.
@ OUT_OF_DISPLAY
A drawing primitive would draw its shape outside the display estate, which is forbidden.
@ NO_GLYPH_FOUND
A text drawing primitive has been called with a character value which has no glyph in current font.
@ COORDS_INVALID
A drawing primitive has been called with invalid (x,y) coordinates; this is different to COORDS_OUT_O...
@ NO_ERROR
No error occurred.
Mode
Mode used when drawing pixels.
@ NO_CHANGE
In this mode, the destination pixel never changes, whatever the source color.
@ OR
Destination pixel is or'ed with source color (set mode).
@ AND
Destination pixel is and'ed with source color (clear mode).
@ XOR
Destination pixel is xor'ed with source color (inversion mode).
@ COPY
Source color simply replaces destination pixel.
Defines all API for all external devices supported by FastArduino.
constexpr T min(T a, T b)
Compute the min of 2 integral values.
constexpr T max(T a, T b)
Compute the max of 2 integral values.
void swap(T &a, T &b)
Swap the values of 2 variables passed by reference.
Default base class for all DisplayDeviceTrait.
Traits for display devices.
uint8_t YCOORD
The shortest integral type that can hold Y coordinates for DEVICE.
static constexpr bool IS_DISPLAY
Marker of display devices.
uint8_t XCOORD
The shortest integral type that can hold X coordinates for DEVICE.
static constexpr uint8_t WIDTH
The width in pixels of DEVICE.
void COLOR
The type of a pixel for DEVICE.
static constexpr bool HAS_RASTER
Tells if DEVICE implements a bitmap raster in SRAM (e.g.
static constexpr uint8_t HEIGHT
The height in pixels of DEVICE.
int8_t SIGNED_SCALAR
The signed integral type used by Display algorithms in some drawing primitives, like Display::draw_li...
static constexpr YCOORD MAX_Y
The maximum Y coordinate for DEVICE.
uint8_t SCALAR
The longest type of XCOORD and YCOORD, used to hold scalar on some drawing primitives,...
static constexpr bool VERTICAL_FONT
Tells if DEVICE uses vertical fonts (e.g.
static constexpr XCOORD MAX_X
The maximum X coordinate for DEVICE.
Find the smallest integral types, signed and unsigned, tha can hold a given value.