F439_CPP_SPI_RA8875_TFT_LCD_04 1.0
STM32F439 SPI RA8875 7-inch TFT display with FRAM-backed touch calibration, built on the STM32_GFX, STM32_RA8875 and STM32_MB85RS64V libraries
Loading...
Searching...
No Matches
Adafruit_GFX.cpp
1/*
2This is the core graphics library for all our displays, providing a common
3set of graphics primitives (points, lines, circles, etc.). It needs to be
4paired with a hardware-specific library for each display device we carry
5(to handle the lower-level functions).
6
7Adafruit invests time and resources providing this open source code, please
8support Adafruit & open-source hardware by purchasing products from Adafruit!
9
10Copyright (c) 2013 Adafruit Industries. All rights reserved.
11
12Redistribution and use in source and binary forms, with or without
13modification, are permitted provided that the following conditions are met:
14
15- Redistributions of source code must retain the above copyright notice,
16 this list of conditions and the following disclaimer.
17- Redistributions in binary form must reproduce the above copyright notice,
18 this list of conditions and the following disclaimer in the documentation
19 and/or other materials provided with the distribution.
20
21THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31POSSIBILITY OF SUCH DAMAGE.
32 */
33
34#include "Adafruit_GFX.h"
35#include "glcdfont.c"
36#ifdef __AVR__
37#include <avr/pgmspace.h>
38#elif defined(ESP8266) || defined(ESP32)
39#include <pgmspace.h>
40#endif
41
42// Many (but maybe not all) non-AVR board installs define macros
43// for compatibility with existing PROGMEM-reading AVR code.
44// Do our own checks and defines here for good measure...
45
46#ifndef pgm_read_byte
47#define pgm_read_byte(addr) (*(const unsigned char *)(addr))
48#endif
49#ifndef pgm_read_word
50#define pgm_read_word(addr) (*(const unsigned short *)(addr))
51#endif
52#ifndef pgm_read_dword
53#define pgm_read_dword(addr) (*(const unsigned long *)(addr))
54#endif
55
56// Pointers are a peculiar case...typically 16-bit on AVR boards,
57// 32 bits elsewhere. Try to accommodate both...
58
59#if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF)
60#define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr))
61#else
62#define pgm_read_pointer(addr) ((void *)pgm_read_word(addr))
63#endif
64
71inline GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) {
72#ifdef __AVR__
73 return &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
74#else
75 // expression in __AVR__ section may generate "dereferencing type-punned
76 // pointer will break strict-aliasing rules" warning In fact, on other
77 // platforms (such as STM32) there is no need to do this pointer magic as
78 // program memory may be read in a usual way So expression may be simplified
79 return gfxFont->glyph + c;
80#endif //__AVR__
81}
82
88inline uint8_t *pgm_read_bitmap_ptr(const GFXfont *gfxFont) {
89#ifdef __AVR__
90 return (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);
91#else
92 // expression in __AVR__ section generates "dereferencing type-punned pointer
93 // will break strict-aliasing rules" warning In fact, on other platforms (such
94 // as STM32) there is no need to do this pointer magic as program memory may
95 // be read in a usual way So expression may be simplified
96 return gfxFont->bitmap;
97#endif //__AVR__
98}
99
100#ifndef min
101#define min(a, b) (((a) < (b)) ? (a) : (b))
102#endif
103
104#ifndef _swap_int16_t
105#define _swap_int16_t(a, b) \
106 { \
107 int16_t t = a; \
108 a = b; \
109 b = t; \
110 }
111#endif
112
119/**************************************************************************/
120Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h) {
121 _width = WIDTH;
122 _height = HEIGHT;
123 rotation = 0;
124 cursor_y = cursor_x = 0;
126 textcolor = textbgcolor = 0xFFFF;
127 wrap = true;
128 _cp437 = false;
129 gfxFont = NULL;
130}
131
140/**************************************************************************/
141void Adafruit_GFX::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
142 uint16_t color) {
143#if defined(ESP8266)
144 yield();
145#endif
146 int16_t steep = abs(y1 - y0) > abs(x1 - x0);
147 if (steep) {
148 _swap_int16_t(x0, y0);
149 _swap_int16_t(x1, y1);
150 }
151
152 if (x0 > x1) {
153 _swap_int16_t(x0, x1);
154 _swap_int16_t(y0, y1);
155 }
156
157 int16_t dx, dy;
158 dx = x1 - x0;
159 dy = abs(y1 - y0);
160
161 int16_t err = dx / 2;
162 int16_t ystep;
163
164 if (y0 < y1) {
165 ystep = 1;
166 } else {
167 ystep = -1;
168 }
169
170 for (; x0 <= x1; x0++) {
171 if (steep) {
172 writePixel(y0, x0, color);
173 } else {
174 writePixel(x0, y0, color);
175 }
176 err -= dy;
177 if (err < 0) {
178 y0 += ystep;
179 err += dx;
180 }
181 }
182}
183
184/**************************************************************************/
188/**************************************************************************/
190
191/**************************************************************************/
198/**************************************************************************/
199void Adafruit_GFX::writePixel(int16_t x, int16_t y, uint16_t color) {
200 drawPixel(x, y, color);
201}
202
203/**************************************************************************/
212/**************************************************************************/
213void Adafruit_GFX::writeFastVLine(int16_t x, int16_t y, int16_t h,
214 uint16_t color) {
215 // Overwrite in subclasses if startWrite is defined!
216 // Can be just writeLine(x, y, x, y+h-1, color);
217 // or writeFillRect(x, y, 1, h, color);
218 drawFastVLine(x, y, h, color);
219}
220
221/**************************************************************************/
230/**************************************************************************/
231void Adafruit_GFX::writeFastHLine(int16_t x, int16_t y, int16_t w,
232 uint16_t color) {
233 // Overwrite in subclasses if startWrite is defined!
234 // Example: writeLine(x, y, x+w-1, y, color);
235 // or writeFillRect(x, y, w, 1, color);
236 drawFastHLine(x, y, w, color);
237}
238
239/**************************************************************************/
249/**************************************************************************/
250void Adafruit_GFX::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
251 uint16_t color) {
252 // Overwrite in subclasses if desired!
253 fillRect(x, y, w, h, color);
254}
255
256/**************************************************************************/
261/**************************************************************************/
263
264/**************************************************************************/
273/**************************************************************************/
274void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, int16_t h,
275 uint16_t color) {
276 startWrite();
277 writeLine(x, y, x, y + h - 1, color);
278 endWrite();
279}
280
281/**************************************************************************/
290/**************************************************************************/
291void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, int16_t w,
292 uint16_t color) {
293 startWrite();
294 writeLine(x, y, x + w - 1, y, color);
295 endWrite();
296}
297
298/**************************************************************************/
308/**************************************************************************/
309void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
310 uint16_t color) {
311 startWrite();
312 for (int16_t i = x; i < x + w; i++) {
313 writeFastVLine(i, y, h, color);
314 }
315 endWrite();
316}
317
318/**************************************************************************/
324/**************************************************************************/
325void Adafruit_GFX::fillScreen(uint16_t color) {
326 fillRect(0, 0, _width, _height, color);
327}
328
329/**************************************************************************/
338/**************************************************************************/
339void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
340 uint16_t color) {
341 // Update in subclasses if desired!
342 if (x0 == x1) {
343 if (y0 > y1)
344 _swap_int16_t(y0, y1);
345 drawFastVLine(x0, y0, y1 - y0 + 1, color);
346 } else if (y0 == y1) {
347 if (x0 > x1)
348 _swap_int16_t(x0, x1);
349 drawFastHLine(x0, y0, x1 - x0 + 1, color);
350 } else {
351 startWrite();
352 writeLine(x0, y0, x1, y1, color);
353 endWrite();
354 }
355}
356
357/**************************************************************************/
366/**************************************************************************/
367void Adafruit_GFX::drawEllipse(int16_t x0, int16_t y0, int16_t rw, int16_t rh,
368 uint16_t color) {
369#if defined(ESP8266)
370 yield();
371#endif
372 // Bresenham's ellipse algorithm
373 int16_t x = 0, y = rh;
374 int32_t rw2 = rw * rw, rh2 = rh * rh;
375 int32_t twoRw2 = 2 * rw2, twoRh2 = 2 * rh2;
376
377 int32_t decision = rh2 - (rw2 * rh) + (rw2 / 4);
378
379 startWrite();
380
381 // region 1
382 while ((twoRh2 * x) < (twoRw2 * y)) {
383 writePixel(x0 + x, y0 + y, color);
384 writePixel(x0 - x, y0 + y, color);
385 writePixel(x0 + x, y0 - y, color);
386 writePixel(x0 - x, y0 - y, color);
387 x++;
388 if (decision < 0) {
389 decision += rh2 + (twoRh2 * x);
390 } else {
391 decision += rh2 + (twoRh2 * x) - (twoRw2 * y);
392 y--;
393 }
394 }
395
396 // region 2
397 decision = ((rh2 * (2 * x + 1) * (2 * x + 1)) >> 2) +
398 (rw2 * (y - 1) * (y - 1)) - (rw2 * rh2);
399 while (y >= 0) {
400 writePixel(x0 + x, y0 + y, color);
401 writePixel(x0 - x, y0 + y, color);
402 writePixel(x0 + x, y0 - y, color);
403 writePixel(x0 - x, y0 - y, color);
404 y--;
405 if (decision > 0) {
406 decision += rw2 - (twoRw2 * y);
407 } else {
408 decision += rw2 + (twoRh2 * x) - (twoRw2 * y);
409 x++;
410 }
411 }
412
413 endWrite();
414}
415
416/**************************************************************************/
425/**************************************************************************/
426void Adafruit_GFX::fillEllipse(int16_t x0, int16_t y0, int16_t rw, int16_t rh,
427 uint16_t color) {
428#if defined(ESP8266)
429 yield();
430#endif
431 // Bresenham's ellipse algorithm
432 int16_t x = 0, y = rh;
433 int32_t rw2 = rw * rw, rh2 = rh * rh;
434 int32_t twoRw2 = 2 * rw2, twoRh2 = 2 * rh2;
435
436 int32_t decision = rh2 - (rw2 * rh) + (rw2 / 4);
437
438 startWrite();
439
440 // region 1
441 while ((twoRh2 * x) < (twoRw2 * y)) {
442 x++;
443 if (decision < 0) {
444 decision += rh2 + (twoRh2 * x);
445 } else {
446 decision += rh2 + (twoRh2 * x) - (twoRw2 * y);
447 drawFastHLine(x0 - (x - 1), y0 + y, 2 * (x - 1) + 1, color);
448 drawFastHLine(x0 - (x - 1), y0 - y, 2 * (x - 1) + 1, color);
449 y--;
450 }
451 }
452
453 // region 2
454 decision = ((rh2 * (2 * x + 1) * (2 * x + 1)) >> 2) +
455 (rw2 * (y - 1) * (y - 1)) - (rw2 * rh2);
456 while (y >= 0) {
457 drawFastHLine(x0 - x, y0 + y, 2 * x + 1, color);
458 drawFastHLine(x0 - x, y0 - y, 2 * x + 1, color);
459
460 y--;
461 if (decision > 0) {
462 decision += rw2 - (twoRw2 * y);
463 } else {
464 decision += rw2 + (twoRh2 * x) - (twoRw2 * y);
465 x++;
466 }
467 }
468
469 endWrite();
470}
471
472/**************************************************************************/
480/**************************************************************************/
481void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r,
482 uint16_t color) {
483#if defined(ESP8266)
484 yield();
485#endif
486 int16_t f = 1 - r;
487 int16_t ddF_x = 1;
488 int16_t ddF_y = -2 * r;
489 int16_t x = 0;
490 int16_t y = r;
491
492 startWrite();
493 writePixel(x0, y0 + r, color);
494 writePixel(x0, y0 - r, color);
495 writePixel(x0 + r, y0, color);
496 writePixel(x0 - r, y0, color);
497
498 while (x < y) {
499 if (f >= 0) {
500 y--;
501 ddF_y += 2;
502 f += ddF_y;
503 }
504 x++;
505 ddF_x += 2;
506 f += ddF_x;
507
508 writePixel(x0 + x, y0 + y, color);
509 writePixel(x0 - x, y0 + y, color);
510 writePixel(x0 + x, y0 - y, color);
511 writePixel(x0 - x, y0 - y, color);
512 writePixel(x0 + y, y0 + x, color);
513 writePixel(x0 - y, y0 + x, color);
514 writePixel(x0 + y, y0 - x, color);
515 writePixel(x0 - y, y0 - x, color);
516 }
517 endWrite();
518}
519
520/**************************************************************************/
530/**************************************************************************/
531void Adafruit_GFX::drawCircleHelper(int16_t x0, int16_t y0, int16_t r,
532 uint8_t cornername, uint16_t color) {
533 int16_t f = 1 - r;
534 int16_t ddF_x = 1;
535 int16_t ddF_y = -2 * r;
536 int16_t x = 0;
537 int16_t y = r;
538
539 while (x < y) {
540 if (f >= 0) {
541 y--;
542 ddF_y += 2;
543 f += ddF_y;
544 }
545 x++;
546 ddF_x += 2;
547 f += ddF_x;
548 if (cornername & 0x4) {
549 writePixel(x0 + x, y0 + y, color);
550 writePixel(x0 + y, y0 + x, color);
551 }
552 if (cornername & 0x2) {
553 writePixel(x0 + x, y0 - y, color);
554 writePixel(x0 + y, y0 - x, color);
555 }
556 if (cornername & 0x8) {
557 writePixel(x0 - y, y0 + x, color);
558 writePixel(x0 - x, y0 + y, color);
559 }
560 if (cornername & 0x1) {
561 writePixel(x0 - y, y0 - x, color);
562 writePixel(x0 - x, y0 - y, color);
563 }
564 }
565}
566
567/**************************************************************************/
575/**************************************************************************/
576void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r,
577 uint16_t color) {
578 startWrite();
579 writeFastVLine(x0, y0 - r, 2 * r + 1, color);
580 fillCircleHelper(x0, y0, r, 3, 0, color);
581 endWrite();
582}
583
584/**************************************************************************/
595/**************************************************************************/
596void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
597 uint8_t corners, int16_t delta,
598 uint16_t color) {
599
600 int16_t f = 1 - r;
601 int16_t ddF_x = 1;
602 int16_t ddF_y = -2 * r;
603 int16_t x = 0;
604 int16_t y = r;
605 int16_t px = x;
606 int16_t py = y;
607
608 delta++; // Avoid some +1's in the loop
609
610 while (x < y) {
611 if (f >= 0) {
612 y--;
613 ddF_y += 2;
614 f += ddF_y;
615 }
616 x++;
617 ddF_x += 2;
618 f += ddF_x;
619 // These checks avoid double-drawing certain lines, important
620 // for the SSD1306 library which has an INVERT drawing mode.
621 if (x < (y + 1)) {
622 if (corners & 1)
623 writeFastVLine(x0 + x, y0 - y, 2 * y + delta, color);
624 if (corners & 2)
625 writeFastVLine(x0 - x, y0 - y, 2 * y + delta, color);
626 }
627 if (y != py) {
628 if (corners & 1)
629 writeFastVLine(x0 + py, y0 - px, 2 * px + delta, color);
630 if (corners & 2)
631 writeFastVLine(x0 - py, y0 - px, 2 * px + delta, color);
632 py = y;
633 }
634 px = x;
635 }
636}
637
638/**************************************************************************/
647/**************************************************************************/
648void Adafruit_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
649 uint16_t color) {
650 startWrite();
651 writeFastHLine(x, y, w, color);
652 writeFastHLine(x, y + h - 1, w, color);
653 writeFastVLine(x, y, h, color);
654 writeFastVLine(x + w - 1, y, h, color);
655 endWrite();
656}
657
658/**************************************************************************/
668/**************************************************************************/
669void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h,
670 int16_t r, uint16_t color) {
671 int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
672 if (r > max_radius)
673 r = max_radius;
674 // smarter version
675 startWrite();
676 writeFastHLine(x + r, y, w - 2 * r, color); // Top
677 writeFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom
678 writeFastVLine(x, y + r, h - 2 * r, color); // Left
679 writeFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right
680 // draw four corners
681 drawCircleHelper(x + r, y + r, r, 1, color);
682 drawCircleHelper(x + w - r - 1, y + r, r, 2, color);
683 drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color);
684 drawCircleHelper(x + r, y + h - r - 1, r, 8, color);
685 endWrite();
686}
687
688/**************************************************************************/
698/**************************************************************************/
699void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h,
700 int16_t r, uint16_t color) {
701 int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
702 if (r > max_radius)
703 r = max_radius;
704 // smarter version
705 startWrite();
706 writeFillRect(x + r, y, w - 2 * r, h, color);
707 // draw four corners
708 fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color);
709 fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color);
710 endWrite();
711}
712
713/**************************************************************************/
729/**************************************************************************/
730void Adafruit_GFX::drawRotatedRect(int16_t cenX, int16_t cenY, int16_t w,
731 int16_t h, int16_t angleDeg,
732 uint16_t color) {
733
734 if (w < 1 || h < 1)
735 return; // We don't draw zero dimensioned objects
736
737 int16_t W = w - 1;
738 int16_t H = h - 1;
739
740 int16_t halfW = (W / 2); // Midpoint should always be integer
741 int16_t halfH = (H / 2); // Midpoint should always be integer
742
743 int16_t x0 = W - halfW; // bottom-right
744 int16_t y0 = H - halfH; // bottom-right
745 int16_t x1 = -halfW; // bottom-left
746 int16_t y1 = H - halfH; // bottom-left
747 int16_t x2 = -halfW; // top-left
748 int16_t y2 = -halfH; // top-left
749 int16_t x3 = W - halfW; // top-right
750 int16_t y3 = -halfH; // top-right
751
752 rotatePoint(x0, y0, angleDeg);
753 rotatePoint(x1, y1, angleDeg);
754 rotatePoint(x2, y2, angleDeg);
755 rotatePoint(x3, y3, angleDeg);
756
757 x0 += cenX;
758 x1 += cenX;
759 x2 += cenX;
760 x3 += cenX;
761
762 y0 += cenY;
763 y1 += cenY;
764 y2 += cenY;
765 y3 += cenY;
766
767 drawLine(x0, y0, x1, y1, color); // bottom right to bottom left
768 drawLine(x1, y1, x2, y2, color); // bottom left to top left
769 drawLine(x2, y2, x3, y3, color); // top left to top right
770 drawLine(x3, y3, x0, y0, color); // top right to bottom right
771}
772
773/**************************************************************************/
789/**************************************************************************/
790void Adafruit_GFX::fillRotatedRect(int16_t cenX, int16_t cenY, int16_t w,
791 int16_t h, int16_t angleDeg,
792 uint16_t color) {
793
794 if (w < 1 || h < 1)
795 return; // We don't draw zero dimensioned objects
796
797 int16_t W = w - 1;
798 int16_t H = h - 1;
799
800 int16_t halfW = (W / 2); // Midpoint should always be integer
801 int16_t halfH = (H / 2); // Midpoint should always be integer
802
803 int16_t x0 = W - halfW; // bottom-right
804 int16_t y0 = H - halfH; // bottom-right
805 int16_t x1 = -halfW; // bottom-left
806 int16_t y1 = H - halfH; // bottom-left
807 int16_t x2 = -halfW; // top-left
808 int16_t y2 = -halfH; // top-left
809 int16_t x3 = W - halfW; // top-right
810 int16_t y3 = -halfH; // top-right
811
812 rotatePoint(x0, y0, angleDeg);
813 rotatePoint(x1, y1, angleDeg);
814 rotatePoint(x2, y2, angleDeg);
815 rotatePoint(x3, y3, angleDeg);
816
817 x0 += cenX;
818 x1 += cenX;
819 x2 += cenX;
820 x3 += cenX;
821
822 y0 += cenY;
823 y1 += cenY;
824 y2 += cenY;
825 y3 += cenY;
826
827 fillTriangle(x0, y0, x1, y1, x2, y2, color);
828 fillTriangle(x2, y2, x3, y3, x0, y0, color);
829}
830
831/**************************************************************************/
840/**************************************************************************/
841void Adafruit_GFX::rotatePoint(int16_t &x0, int16_t &y0, int16_t angleDeg) {
842 float angleRad = radians(angleDeg);
843 float s = sin(angleRad);
844 float c = cos(angleRad);
845
846 float x = x0;
847 float y = y0;
848
849 // Rotate point
850 x0 = (int16_t)((x * c) - (y * s));
851 y0 = (int16_t)((x * s) + (y * c));
852}
853
854/**************************************************************************/
865/**************************************************************************/
866void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
867 int16_t x2, int16_t y2, uint16_t color) {
868 drawLine(x0, y0, x1, y1, color);
869 drawLine(x1, y1, x2, y2, color);
870 drawLine(x2, y2, x0, y0, color);
871}
872
873/**************************************************************************/
884/**************************************************************************/
885void Adafruit_GFX::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
886 int16_t x2, int16_t y2, uint16_t color) {
887
888 int16_t a, b, y, last;
889
890 // Sort coordinates by Y order (y2 >= y1 >= y0)
891 if (y0 > y1) {
892 _swap_int16_t(y0, y1);
893 _swap_int16_t(x0, x1);
894 }
895 if (y1 > y2) {
896 _swap_int16_t(y2, y1);
897 _swap_int16_t(x2, x1);
898 }
899 if (y0 > y1) {
900 _swap_int16_t(y0, y1);
901 _swap_int16_t(x0, x1);
902 }
903
904 startWrite();
905 if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing
906 a = b = x0;
907 if (x1 < a)
908 a = x1;
909 else if (x1 > b)
910 b = x1;
911 if (x2 < a)
912 a = x2;
913 else if (x2 > b)
914 b = x2;
915 writeFastHLine(a, y0, b - a + 1, color);
916 endWrite();
917 return;
918 }
919
920 int16_t dx01 = x1 - x0, dy01 = y1 - y0, dx02 = x2 - x0, dy02 = y2 - y0,
921 dx12 = x2 - x1, dy12 = y2 - y1;
922 int32_t sa = 0, sb = 0;
923
924 // For upper part of triangle, find scanline crossings for segments
925 // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
926 // is included here (and second loop will be skipped, avoiding a /0
927 // error there), otherwise scanline y1 is skipped here and handled
928 // in the second loop...which also avoids a /0 error here if y0=y1
929 // (flat-topped triangle).
930 if (y1 == y2)
931 last = y1; // Include y1 scanline
932 else
933 last = y1 - 1; // Skip it
934
935 for (y = y0; y <= last; y++) {
936 a = x0 + sa / dy01;
937 b = x0 + sb / dy02;
938 sa += dx01;
939 sb += dx02;
940 /* longhand:
941 a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
942 b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
943 */
944 if (a > b)
945 _swap_int16_t(a, b);
946 writeFastHLine(a, y, b - a + 1, color);
947 }
948
949 // For lower part of triangle, find scanline crossings for segments
950 // 0-2 and 1-2. This loop is skipped if y1=y2.
951 sa = (int32_t)dx12 * (y - y1);
952 sb = (int32_t)dx02 * (y - y0);
953 for (; y <= y2; y++) {
954 a = x1 + sa / dy12;
955 b = x0 + sb / dy02;
956 sa += dx12;
957 sb += dx02;
958 /* longhand:
959 a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
960 b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
961 */
962 if (a > b)
963 _swap_int16_t(a, b);
964 writeFastHLine(a, y, b - a + 1, color);
965 }
966 endWrite();
967}
968
969// BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS ---------------------
970
971/**************************************************************************/
982/**************************************************************************/
983void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
984 int16_t w, int16_t h, uint16_t color) {
985
986 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
987 uint8_t b = 0;
988
989 startWrite();
990 for (int16_t j = 0; j < h; j++, y++) {
991 for (int16_t i = 0; i < w; i++) {
992 if (i & 7)
993 b <<= 1;
994 else
995 b = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
996 if (b & 0x80)
997 writePixel(x + i, y, color);
998 }
999 }
1000 endWrite();
1001}
1002
1003/**************************************************************************/
1016/**************************************************************************/
1017void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
1018 int16_t w, int16_t h, uint16_t color,
1019 uint16_t bg) {
1020
1021 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
1022 uint8_t b = 0;
1023
1024 startWrite();
1025 for (int16_t j = 0; j < h; j++, y++) {
1026 for (int16_t i = 0; i < w; i++) {
1027 if (i & 7)
1028 b <<= 1;
1029 else
1030 b = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
1031 writePixel(x + i, y, (b & 0x80) ? color : bg);
1032 }
1033 }
1034 endWrite();
1035}
1036
1037/**************************************************************************/
1048/**************************************************************************/
1049void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w,
1050 int16_t h, uint16_t color) {
1051
1052 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
1053 uint8_t b = 0;
1054
1055 startWrite();
1056 for (int16_t j = 0; j < h; j++, y++) {
1057 for (int16_t i = 0; i < w; i++) {
1058 if (i & 7)
1059 b <<= 1;
1060 else
1061 b = bitmap[j * byteWidth + i / 8];
1062 if (b & 0x80)
1063 writePixel(x + i, y, color);
1064 }
1065 }
1066 endWrite();
1067}
1068
1069/**************************************************************************/
1082/**************************************************************************/
1083void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w,
1084 int16_t h, uint16_t color, uint16_t bg) {
1085
1086 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
1087 uint8_t b = 0;
1088
1089 startWrite();
1090 for (int16_t j = 0; j < h; j++, y++) {
1091 for (int16_t i = 0; i < w; i++) {
1092 if (i & 7)
1093 b <<= 1;
1094 else
1095 b = bitmap[j * byteWidth + i / 8];
1096 writePixel(x + i, y, (b & 0x80) ? color : bg);
1097 }
1098 }
1099 endWrite();
1100}
1101
1102/**************************************************************************/
1116/**************************************************************************/
1117void Adafruit_GFX::drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
1118 int16_t w, int16_t h, uint16_t color) {
1119
1120 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
1121 uint8_t b = 0;
1122
1123 startWrite();
1124 for (int16_t j = 0; j < h; j++, y++) {
1125 for (int16_t i = 0; i < w; i++) {
1126 if (i & 7)
1127 b >>= 1;
1128 else
1129 b = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
1130 // Nearly identical to drawBitmap(), only the bit order
1131 // is reversed here (left-to-right = LSB to MSB):
1132 if (b & 0x01)
1133 writePixel(x + i, y, color);
1134 }
1135 }
1136 endWrite();
1137}
1138
1139/**************************************************************************/
1150/**************************************************************************/
1151void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
1152 const uint8_t bitmap[], int16_t w,
1153 int16_t h) {
1154 startWrite();
1155 for (int16_t j = 0; j < h; j++, y++) {
1156 for (int16_t i = 0; i < w; i++) {
1157 writePixel(x + i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i]));
1158 }
1159 }
1160 endWrite();
1161}
1162
1163/**************************************************************************/
1174/**************************************************************************/
1175void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap,
1176 int16_t w, int16_t h) {
1177 startWrite();
1178 for (int16_t j = 0; j < h; j++, y++) {
1179 for (int16_t i = 0; i < w; i++) {
1180 writePixel(x + i, y, bitmap[j * w + i]);
1181 }
1182 }
1183 endWrite();
1184}
1185
1186/**************************************************************************/
1200/**************************************************************************/
1201void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
1202 const uint8_t bitmap[],
1203 const uint8_t mask[], int16_t w,
1204 int16_t h) {
1205 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
1206 uint8_t b = 0;
1207 startWrite();
1208 for (int16_t j = 0; j < h; j++, y++) {
1209 for (int16_t i = 0; i < w; i++) {
1210 if (i & 7)
1211 b <<= 1;
1212 else
1213 b = pgm_read_byte(&mask[j * bw + i / 8]);
1214 if (b & 0x80) {
1215 writePixel(x + i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i]));
1216 }
1217 }
1218 }
1219 endWrite();
1220}
1221
1222/**************************************************************************/
1236/**************************************************************************/
1237void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap,
1238 uint8_t *mask, int16_t w, int16_t h) {
1239 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
1240 uint8_t b = 0;
1241 startWrite();
1242 for (int16_t j = 0; j < h; j++, y++) {
1243 for (int16_t i = 0; i < w; i++) {
1244 if (i & 7)
1245 b <<= 1;
1246 else
1247 b = mask[j * bw + i / 8];
1248 if (b & 0x80) {
1249 writePixel(x + i, y, bitmap[j * w + i]);
1250 }
1251 }
1252 }
1253 endWrite();
1254}
1255
1256/**************************************************************************/
1266/**************************************************************************/
1267void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[],
1268 int16_t w, int16_t h) {
1269 startWrite();
1270 for (int16_t j = 0; j < h; j++, y++) {
1271 for (int16_t i = 0; i < w; i++) {
1272 writePixel(x + i, y, pgm_read_word(&bitmap[j * w + i]));
1273 }
1274 }
1275 endWrite();
1276}
1277
1278/**************************************************************************/
1288/**************************************************************************/
1289void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap,
1290 int16_t w, int16_t h) {
1291 startWrite();
1292 for (int16_t j = 0; j < h; j++, y++) {
1293 for (int16_t i = 0; i < w; i++) {
1294 writePixel(x + i, y, bitmap[j * w + i]);
1295 }
1296 }
1297 endWrite();
1298}
1299
1300/**************************************************************************/
1313/**************************************************************************/
1314void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[],
1315 const uint8_t mask[], int16_t w, int16_t h) {
1316 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
1317 uint8_t b = 0;
1318 startWrite();
1319 for (int16_t j = 0; j < h; j++, y++) {
1320 for (int16_t i = 0; i < w; i++) {
1321 if (i & 7)
1322 b <<= 1;
1323 else
1324 b = pgm_read_byte(&mask[j * bw + i / 8]);
1325 if (b & 0x80) {
1326 writePixel(x + i, y, pgm_read_word(&bitmap[j * w + i]));
1327 }
1328 }
1329 }
1330 endWrite();
1331}
1332
1333/**************************************************************************/
1346/**************************************************************************/
1347void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap,
1348 uint8_t *mask, int16_t w, int16_t h) {
1349 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
1350 uint8_t b = 0;
1351 startWrite();
1352 for (int16_t j = 0; j < h; j++, y++) {
1353 for (int16_t i = 0; i < w; i++) {
1354 if (i & 7)
1355 b <<= 1;
1356 else
1357 b = mask[j * bw + i / 8];
1358 if (b & 0x80) {
1359 writePixel(x + i, y, bitmap[j * w + i]);
1360 }
1361 }
1362 }
1363 endWrite();
1364}
1365
1366// TEXT- AND CHARACTER-HANDLING FUNCTIONS ----------------------------------
1367
1368// Draw a character
1369/**************************************************************************/
1380/**************************************************************************/
1381void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
1382 uint16_t color, uint16_t bg, uint8_t size) {
1383 drawChar(x, y, c, color, bg, size, size);
1384}
1385
1386// Draw a character
1387/**************************************************************************/
1399/**************************************************************************/
1400void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
1401 uint16_t color, uint16_t bg, uint8_t size_x,
1402 uint8_t size_y) {
1403
1404 if (!gfxFont) { // 'Classic' built-in font
1405
1406 if ((x >= _width) || // Clip right
1407 (y >= _height) || // Clip bottom
1408 ((x + 6 * size_x - 1) < 0) || // Clip left
1409 ((y + 8 * size_y - 1) < 0)) // Clip top
1410 return;
1411
1412 if (!_cp437 && (c >= 176))
1413 c++; // Handle 'classic' charset behavior
1414
1415 startWrite();
1416 for (int8_t i = 0; i < 5; i++) { // Char bitmap = 5 columns
1417 uint8_t line = pgm_read_byte(&font[c * 5 + i]);
1418 for (int8_t j = 0; j < 8; j++, line >>= 1) {
1419 if (line & 1) {
1420 if (size_x == 1 && size_y == 1)
1421 writePixel(x + i, y + j, color);
1422 else
1423 writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y,
1424 color);
1425 } else if (bg != color) {
1426 if (size_x == 1 && size_y == 1)
1427 writePixel(x + i, y + j, bg);
1428 else
1429 writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y, bg);
1430 }
1431 }
1432 }
1433 if (bg != color) { // If opaque, draw vertical line for last column
1434 if (size_x == 1 && size_y == 1)
1435 writeFastVLine(x + 5, y, 8, bg);
1436 else
1437 writeFillRect(x + 5 * size_x, y, size_x, 8 * size_y, bg);
1438 }
1439 endWrite();
1440
1441 } else { // Custom font
1442
1443 // Character is assumed previously filtered by write() to eliminate
1444 // newlines, returns, non-printable characters, etc. Calling
1445 // drawChar() directly with 'bad' characters of font may cause mayhem!
1446
1447 c -= (uint8_t)pgm_read_byte(&gfxFont->first);
1448 GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c);
1449 uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont);
1450
1451 uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
1452 uint8_t w = pgm_read_byte(&glyph->width), h = pgm_read_byte(&glyph->height);
1453 int8_t xo = pgm_read_byte(&glyph->xOffset),
1454 yo = pgm_read_byte(&glyph->yOffset);
1455 uint8_t xx, yy, bits = 0, bit = 0;
1456 int16_t xo16 = 0, yo16 = 0;
1457
1458 if (size_x > 1 || size_y > 1) {
1459 xo16 = xo;
1460 yo16 = yo;
1461 }
1462
1463 // Todo: Add character clipping here
1464
1465 // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS.
1466 // THIS IS ON PURPOSE AND BY DESIGN. The background color feature
1467 // has typically been used with the 'classic' font to overwrite old
1468 // screen contents with new data. This ONLY works because the
1469 // characters are a uniform size; it's not a sensible thing to do with
1470 // proportionally-spaced fonts with glyphs of varying sizes (and that
1471 // may overlap). To replace previously-drawn text when using a custom
1472 // font, use the getTextBounds() function to determine the smallest
1473 // rectangle encompassing a string, erase the area with fillRect(),
1474 // then draw new text. This WILL infortunately 'blink' the text, but
1475 // is unavoidable. Drawing 'background' pixels will NOT fix this,
1476 // only creates a new set of problems. Have an idea to work around
1477 // this (a canvas object type for MCUs that can afford the RAM and
1478 // displays supporting setAddrWindow() and pushColors()), but haven't
1479 // implemented this yet.
1480
1481 startWrite();
1482 for (yy = 0; yy < h; yy++) {
1483 for (xx = 0; xx < w; xx++) {
1484 if (!(bit++ & 7)) {
1485 bits = pgm_read_byte(&bitmap[bo++]);
1486 }
1487 if (bits & 0x80) {
1488 if (size_x == 1 && size_y == 1) {
1489 writePixel(x + xo + xx, y + yo + yy, color);
1490 } else {
1491 writeFillRect(x + (xo16 + xx) * size_x, y + (yo16 + yy) * size_y,
1492 size_x, size_y, color);
1493 }
1494 }
1495 bits <<= 1;
1496 }
1497 }
1498 endWrite();
1499
1500 } // End classic vs custom font
1501}
1502/**************************************************************************/
1507/**************************************************************************/
1508size_t Adafruit_GFX::write(uint8_t c) {
1509 if (!gfxFont) { // 'Classic' built-in font
1510
1511 if (c == '\n') { // Newline?
1512 cursor_x = 0; // Reset x to zero,
1513 cursor_y += textsize_y * 8; // advance y one line
1514 } else if (c != '\r') { // Ignore carriage returns
1515 if (wrap && ((cursor_x + textsize_x * 6) > _width)) { // Off right?
1516 cursor_x = 0; // Reset x to zero,
1517 cursor_y += textsize_y * 8; // advance y one line
1518 }
1520 textsize_y);
1521 cursor_x += textsize_x * 6; // Advance x one char
1522 }
1523
1524 } else { // Custom font
1525
1526 if (c == '\n') {
1527 cursor_x = 0;
1528 cursor_y +=
1529 (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
1530 } else if (c != '\r') {
1531 uint8_t first = pgm_read_byte(&gfxFont->first);
1532 if ((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) {
1533 GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
1534 uint8_t w = pgm_read_byte(&glyph->width),
1535 h = pgm_read_byte(&glyph->height);
1536 if ((w > 0) && (h > 0)) { // Is there an associated bitmap?
1537 int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic
1538 if (wrap && ((cursor_x + textsize_x * (xo + w)) > _width)) {
1539 cursor_x = 0;
1540 cursor_y += (int16_t)textsize_y *
1541 (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
1542 }
1544 textsize_y);
1545 }
1546 cursor_x +=
1547 (uint8_t)pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize_x;
1548 }
1549 }
1550 }
1551 return 1;
1552}
1553
1554/**************************************************************************/
1560/**************************************************************************/
1561void Adafruit_GFX::setTextSize(uint8_t s) { setTextSize(s, s); }
1562
1563/**************************************************************************/
1570/**************************************************************************/
1571void Adafruit_GFX::setTextSize(uint8_t s_x, uint8_t s_y) {
1572 textsize_x = (s_x > 0) ? s_x : 1;
1573 textsize_y = (s_y > 0) ? s_y : 1;
1574}
1575
1576/**************************************************************************/
1581/**************************************************************************/
1583 rotation = (x & 3);
1584 switch (rotation) {
1585 case 0:
1586 case 2:
1587 _width = WIDTH;
1588 _height = HEIGHT;
1589 break;
1590 case 1:
1591 case 3:
1592 _width = HEIGHT;
1593 _height = WIDTH;
1594 break;
1595 }
1596}
1597
1598/**************************************************************************/
1603/**************************************************************************/
1604void Adafruit_GFX::setFont(const GFXfont *f) {
1605 if (f) { // Font struct pointer passed in?
1606 if (!gfxFont) { // And no current font struct?
1607 // Switching from classic to new font behavior.
1608 // Move cursor pos down 6 pixels so it's on baseline.
1609 cursor_y += 6;
1610 }
1611 } else if (gfxFont) { // NULL passed. Current font struct defined?
1612 // Switching from new to classic font behavior.
1613 // Move cursor pos up 6 pixels so it's at top-left of char.
1614 cursor_y -= 6;
1615 }
1616 gfxFont = (GFXfont *)f;
1617}
1618
1619/**************************************************************************/
1636/**************************************************************************/
1637void Adafruit_GFX::charBounds(unsigned char c, int16_t *x, int16_t *y,
1638 int16_t *minx, int16_t *miny, int16_t *maxx,
1639 int16_t *maxy) {
1640
1641 if (gfxFont) {
1642
1643 if (c == '\n') { // Newline?
1644 *x = 0; // Reset x to zero, advance y by one line
1645 *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
1646 } else if (c != '\r') { // Not a carriage return; is normal char
1647 uint8_t first = pgm_read_byte(&gfxFont->first),
1648 last = pgm_read_byte(&gfxFont->last);
1649 if ((c >= first) && (c <= last)) { // Char present in this font?
1650 GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
1651 uint8_t gw = pgm_read_byte(&glyph->width),
1652 gh = pgm_read_byte(&glyph->height),
1653 xa = pgm_read_byte(&glyph->xAdvance);
1654 int8_t xo = pgm_read_byte(&glyph->xOffset),
1655 yo = pgm_read_byte(&glyph->yOffset);
1656 if (wrap && ((*x + (((int16_t)xo + gw) * textsize_x)) > _width)) {
1657 *x = 0; // Reset x to zero, advance y by one line
1658 *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
1659 }
1660 int16_t tsx = (int16_t)textsize_x, tsy = (int16_t)textsize_y,
1661 x1 = *x + xo * tsx, y1 = *y + yo * tsy, x2 = x1 + gw * tsx - 1,
1662 y2 = y1 + gh * tsy - 1;
1663 if (x1 < *minx)
1664 *minx = x1;
1665 if (y1 < *miny)
1666 *miny = y1;
1667 if (x2 > *maxx)
1668 *maxx = x2;
1669 if (y2 > *maxy)
1670 *maxy = y2;
1671 *x += xa * tsx;
1672 }
1673 }
1674
1675 } else { // Default font
1676
1677 if (c == '\n') { // Newline?
1678 *x = 0; // Reset x to zero,
1679 *y += textsize_y * 8; // advance y one line
1680 // min/max x/y unchaged -- that waits for next 'normal' character
1681 } else if (c != '\r') { // Normal char; ignore carriage returns
1682 if (wrap && ((*x + textsize_x * 6) > _width)) { // Off right?
1683 *x = 0; // Reset x to zero,
1684 *y += textsize_y * 8; // advance y one line
1685 }
1686 int x2 = *x + textsize_x * 6 - 1, // Lower-right pixel of char
1687 y2 = *y + textsize_y * 8 - 1;
1688 if (x2 > *maxx)
1689 *maxx = x2; // Track max x, y
1690 if (y2 > *maxy)
1691 *maxy = y2;
1692 if (*x < *minx)
1693 *minx = *x; // Track min x, y
1694 if (*y < *miny)
1695 *miny = *y;
1696 *x += textsize_x * 6; // Advance x one char
1697 }
1698 }
1699}
1700
1701/**************************************************************************/
1713/**************************************************************************/
1714void Adafruit_GFX::getTextBounds(const char *str, int16_t x, int16_t y,
1715 int16_t *x1, int16_t *y1, uint16_t *w,
1716 uint16_t *h) {
1717
1718 uint8_t c; // Current character
1719 int16_t minx = 0x7FFF, miny = 0x7FFF, maxx = -1, maxy = -1; // Bound rect
1720 // Bound rect is intentionally initialized inverted, so 1st char sets it
1721
1722 *x1 = x; // Initial position is value passed in
1723 *y1 = y;
1724 *w = *h = 0; // Initial size is zero
1725
1726 while ((c = *str++)) {
1727 // charBounds() modifies x/y to advance for each character,
1728 // and min/max x/y are updated to incrementally build bounding rect.
1729 charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
1730 }
1731
1732 if (maxx >= minx) { // If legit string bounds were found...
1733 *x1 = minx; // Update x1 to least X coord,
1734 *w = maxx - minx + 1; // And w to bound rect width
1735 }
1736 if (maxy >= miny) { // Same for height
1737 *y1 = miny;
1738 *h = maxy - miny + 1;
1739 }
1740}
1741
1742/**************************************************************************/
1754/**************************************************************************/
1755void Adafruit_GFX::getTextBounds(const String &str, int16_t x, int16_t y,
1756 int16_t *x1, int16_t *y1, uint16_t *w,
1757 uint16_t *h) {
1758 if (str.length() != 0) {
1759 getTextBounds(const_cast<char *>(str.c_str()), x, y, x1, y1, w, h);
1760 }
1761}
1762
1763/**************************************************************************/
1775/**************************************************************************/
1776void Adafruit_GFX::getTextBounds(const __FlashStringHelper *str, int16_t x,
1777 int16_t y, int16_t *x1, int16_t *y1,
1778 uint16_t *w, uint16_t *h) {
1779 uint8_t *s = (uint8_t *)str, c;
1780
1781 *x1 = x;
1782 *y1 = y;
1783 *w = *h = 0;
1784
1785 int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;
1786
1787 while ((c = pgm_read_byte(s++)))
1788 charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
1789
1790 if (maxx >= minx) {
1791 *x1 = minx;
1792 *w = maxx - minx + 1;
1793 }
1794 if (maxy >= miny) {
1795 *y1 = miny;
1796 *h = maxy - miny + 1;
1797 }
1798}
1799
1800/**************************************************************************/
1805/**************************************************************************/
1807 // Do nothing, must be subclassed if supported by hardware
1808 (void)i; // disable -Wunused-parameter warning
1809}
1810
1811/***************************************************************************/
1812
1813/**************************************************************************/
1817/**************************************************************************/
1819
1820/**************************************************************************/
1834/**************************************************************************/
1835// Classic initButton() function: pass center & size
1836void Adafruit_GFX_Button::initButton(Adafruit_GFX *gfx, int16_t x, int16_t y,
1837 uint16_t w, uint16_t h, uint16_t outline,
1838 uint16_t fill, uint16_t textcolor,
1839 char *label, uint8_t textsize) {
1840 // Tweak arguments and pass to the newer initButtonUL() function...
1841 initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill, textcolor,
1842 label, textsize);
1843}
1844
1845/**************************************************************************/
1860/**************************************************************************/
1861// Classic initButton() function: pass center & size
1862void Adafruit_GFX_Button::initButton(Adafruit_GFX *gfx, int16_t x, int16_t y,
1863 uint16_t w, uint16_t h, uint16_t outline,
1864 uint16_t fill, uint16_t textcolor,
1865 char *label, uint8_t textsize_x,
1866 uint8_t textsize_y) {
1867 // Tweak arguments and pass to the newer initButtonUL() function...
1868 initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill, textcolor,
1869 label, textsize_x, textsize_y);
1870}
1871
1872/**************************************************************************/
1887/**************************************************************************/
1889 int16_t y1, uint16_t w, uint16_t h,
1890 uint16_t outline, uint16_t fill,
1891 uint16_t textcolor, char *label,
1892 uint8_t textsize) {
1893 initButtonUL(gfx, x1, y1, w, h, outline, fill, textcolor, label, textsize,
1894 textsize);
1895}
1896
1897/**************************************************************************/
1913/**************************************************************************/
1915 int16_t y1, uint16_t w, uint16_t h,
1916 uint16_t outline, uint16_t fill,
1917 uint16_t textcolor, char *label,
1918 uint8_t textsize_x, uint8_t textsize_y) {
1919 _x1 = x1;
1920 _y1 = y1;
1921 _w = w;
1922 _h = h;
1923 _outlinecolor = outline;
1924 _fillcolor = fill;
1925 _textcolor = textcolor;
1926 _textsize_x = textsize_x;
1927 _textsize_y = textsize_y;
1928 _gfx = gfx;
1929 strncpy(_label, label, 9);
1930 _label[9] = 0; // strncpy does not place a null at the end.
1931 // When 'label' is >9 characters, _label is not terminated.
1932}
1933
1934/**************************************************************************/
1940/**************************************************************************/
1942 uint16_t fill, outline, text;
1943
1944 if (!inverted) {
1945 fill = _fillcolor;
1946 outline = _outlinecolor;
1947 text = _textcolor;
1948 } else {
1949 fill = _textcolor;
1950 outline = _outlinecolor;
1951 text = _fillcolor;
1952 }
1953
1954 uint8_t r = min(_w, _h) / 4; // Corner radius
1955 _gfx->fillRoundRect(_x1, _y1, _w, _h, r, fill);
1956 _gfx->drawRoundRect(_x1, _y1, _w, _h, r, outline);
1957
1958 _gfx->setCursor(_x1 + (_w / 2) - (strlen(_label) * 3 * _textsize_x),
1959 _y1 + (_h / 2) - (4 * _textsize_y));
1960 _gfx->setTextColor(text);
1961 _gfx->setTextSize(_textsize_x, _textsize_y);
1962 _gfx->print(_label);
1963}
1964
1965/**************************************************************************/
1973/**************************************************************************/
1974bool Adafruit_GFX_Button::contains(int16_t x, int16_t y) {
1975 return ((x >= _x1) && (x < (int16_t)(_x1 + _w)) && (y >= _y1) &&
1976 (y < (int16_t)(_y1 + _h)));
1977}
1978
1979/**************************************************************************/
1984/**************************************************************************/
1985bool Adafruit_GFX_Button::justPressed() { return (currstate && !laststate); }
1986
1987/**************************************************************************/
1992/**************************************************************************/
1993bool Adafruit_GFX_Button::justReleased() { return (!currstate && laststate); }
1994
1995// -------------------------------------------------------------------------
1996
1997// GFXcanvas1, GFXcanvas8 and GFXcanvas16 (currently a WIP, don't get too
1998// comfy with the implementation) provide 1-, 8- and 16-bit offscreen
1999// canvases, the address of which can be passed to drawBitmap() or
2000// pushColors() (the latter appears only in a couple of GFX-subclassed TFT
2001// libraries at this time). This is here mostly to help with the recently-
2002// added proportionally-spaced fonts; adds a way to refresh a section of the
2003// screen without a massive flickering clear-and-redraw...but maybe you'll
2004// find other uses too. VERY RAM-intensive, since the buffer is in MCU
2005// memory and not the display driver...GXFcanvas1 might be minimally useful
2006// on an Uno-class board, but this and the others are much more likely to
2007// require at least a Mega or various recent ARM-type boards (recommended,
2008// as the text+bitmap draw can be pokey). GFXcanvas1 requires 1 bit per
2009// pixel (rounded up to nearest byte per scanline), GFXcanvas8 is 1 byte
2010// per pixel (no scanline pad), and GFXcanvas16 uses 2 bytes per pixel (no
2011// scanline pad).
2012// NOT EXTENSIVELY TESTED YET. MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND.
2013
2014#ifdef __AVR__
2015// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
2016const uint8_t PROGMEM GFXcanvas1::GFXsetBit[] = {0x80, 0x40, 0x20, 0x10,
2017 0x08, 0x04, 0x02, 0x01};
2018const uint8_t PROGMEM GFXcanvas1::GFXclrBit[] = {0x7F, 0xBF, 0xDF, 0xEF,
2019 0xF7, 0xFB, 0xFD, 0xFE};
2020#endif
2021
2022/**************************************************************************/
2032/**************************************************************************/
2033GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h, bool allocate_buffer)
2034 : Adafruit_GFX(w, h), buffer_owned(allocate_buffer) {
2035 if (allocate_buffer) {
2036 uint32_t bytes = ((w + 7) / 8) * h;
2037 if ((buffer = (uint8_t *)malloc(bytes))) {
2038 memset(buffer, 0, bytes);
2039 }
2040 } else {
2041 buffer = nullptr;
2042 }
2043}
2044
2045/**************************************************************************/
2049/**************************************************************************/
2051 if (buffer && buffer_owned)
2052 free(buffer);
2053}
2054
2055/**************************************************************************/
2062/**************************************************************************/
2063void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) {
2064 if (buffer) {
2065 if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
2066 return;
2067
2068 int16_t t;
2069 switch (rotation) {
2070 case 1:
2071 t = x;
2072 x = WIDTH - 1 - y;
2073 y = t;
2074 break;
2075 case 2:
2076 x = WIDTH - 1 - x;
2077 y = HEIGHT - 1 - y;
2078 break;
2079 case 3:
2080 t = x;
2081 x = y;
2082 y = HEIGHT - 1 - t;
2083 break;
2084 }
2085
2086 uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
2087#ifdef __AVR__
2088 if (color)
2089 *ptr |= pgm_read_byte(&GFXsetBit[x & 7]);
2090 else
2091 *ptr &= pgm_read_byte(&GFXclrBit[x & 7]);
2092#else
2093 if (color)
2094 *ptr |= 0x80 >> (x & 7);
2095 else
2096 *ptr &= ~(0x80 >> (x & 7));
2097#endif
2098 }
2099}
2100
2101/**********************************************************************/
2108bool GFXcanvas1::getPixel(int16_t x, int16_t y) const {
2109 int16_t t;
2110 switch (rotation) {
2111 case 1:
2112 t = x;
2113 x = WIDTH - 1 - y;
2114 y = t;
2115 break;
2116 case 2:
2117 x = WIDTH - 1 - x;
2118 y = HEIGHT - 1 - y;
2119 break;
2120 case 3:
2121 t = x;
2122 x = y;
2123 y = HEIGHT - 1 - t;
2124 break;
2125 }
2126 return getRawPixel(x, y);
2127}
2128
2129/**********************************************************************/
2138bool GFXcanvas1::getRawPixel(int16_t x, int16_t y) const {
2139 if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
2140 return 0;
2141 if (buffer) {
2142 uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
2143
2144#ifdef __AVR__
2145 return ((*ptr) & pgm_read_byte(&GFXsetBit[x & 7])) != 0;
2146#else
2147 return ((*ptr) & (0x80 >> (x & 7))) != 0;
2148#endif
2149 }
2150 return 0;
2151}
2152
2153/**************************************************************************/
2158/**************************************************************************/
2159void GFXcanvas1::fillScreen(uint16_t color) {
2160 if (buffer) {
2161 uint32_t bytes = ((WIDTH + 7) / 8) * HEIGHT;
2162 memset(buffer, color ? 0xFF : 0x00, bytes);
2163 }
2164}
2165
2166/**************************************************************************/
2174/**************************************************************************/
2175void GFXcanvas1::drawFastVLine(int16_t x, int16_t y, int16_t h,
2176 uint16_t color) {
2177
2178 if (h < 0) { // Convert negative heights to positive equivalent
2179 h *= -1;
2180 y -= h - 1;
2181 if (y < 0) {
2182 h += y;
2183 y = 0;
2184 }
2185 }
2186
2187 // Edge rejection (no-draw if totally off canvas)
2188 if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) {
2189 return;
2190 }
2191
2192 if (y < 0) { // Clip top
2193 h += y;
2194 y = 0;
2195 }
2196 if (y + h > height()) { // Clip bottom
2197 h = height() - y;
2198 }
2199
2200 if (getRotation() == 0) {
2201 drawFastRawVLine(x, y, h, color);
2202 } else if (getRotation() == 1) {
2203 int16_t t = x;
2204 x = WIDTH - 1 - y;
2205 y = t;
2206 x -= h - 1;
2207 drawFastRawHLine(x, y, h, color);
2208 } else if (getRotation() == 2) {
2209 x = WIDTH - 1 - x;
2210 y = HEIGHT - 1 - y;
2211
2212 y -= h - 1;
2213 drawFastRawVLine(x, y, h, color);
2214 } else if (getRotation() == 3) {
2215 int16_t t = x;
2216 x = y;
2217 y = HEIGHT - 1 - t;
2218 drawFastRawHLine(x, y, h, color);
2219 }
2220}
2221
2222/**************************************************************************/
2230/**************************************************************************/
2231void GFXcanvas1::drawFastHLine(int16_t x, int16_t y, int16_t w,
2232 uint16_t color) {
2233 if (w < 0) { // Convert negative widths to positive equivalent
2234 w *= -1;
2235 x -= w - 1;
2236 if (x < 0) {
2237 w += x;
2238 x = 0;
2239 }
2240 }
2241
2242 // Edge rejection (no-draw if totally off canvas)
2243 if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) {
2244 return;
2245 }
2246
2247 if (x < 0) { // Clip left
2248 w += x;
2249 x = 0;
2250 }
2251 if (x + w >= width()) { // Clip right
2252 w = width() - x;
2253 }
2254
2255 if (getRotation() == 0) {
2256 drawFastRawHLine(x, y, w, color);
2257 } else if (getRotation() == 1) {
2258 int16_t t = x;
2259 x = WIDTH - 1 - y;
2260 y = t;
2261 drawFastRawVLine(x, y, w, color);
2262 } else if (getRotation() == 2) {
2263 x = WIDTH - 1 - x;
2264 y = HEIGHT - 1 - y;
2265
2266 x -= w - 1;
2267 drawFastRawHLine(x, y, w, color);
2268 } else if (getRotation() == 3) {
2269 int16_t t = x;
2270 x = y;
2271 y = HEIGHT - 1 - t;
2272 y -= w - 1;
2273 drawFastRawVLine(x, y, w, color);
2274 }
2275}
2276
2277/**************************************************************************/
2285/**************************************************************************/
2286void GFXcanvas1::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
2287 uint16_t color) {
2288 // x & y already in raw (rotation 0) coordinates, no need to transform.
2289 int16_t row_bytes = ((WIDTH + 7) / 8);
2290 uint8_t *ptr = &buffer[(x / 8) + y * row_bytes];
2291
2292 if (color > 0) {
2293#ifdef __AVR__
2294 uint8_t bit_mask = pgm_read_byte(&GFXsetBit[x & 7]);
2295#else
2296 uint8_t bit_mask = (0x80 >> (x & 7));
2297#endif
2298 for (int16_t i = 0; i < h; i++) {
2299 *ptr |= bit_mask;
2300 ptr += row_bytes;
2301 }
2302 } else {
2303#ifdef __AVR__
2304 uint8_t bit_mask = pgm_read_byte(&GFXclrBit[x & 7]);
2305#else
2306 uint8_t bit_mask = ~(0x80 >> (x & 7));
2307#endif
2308 for (int16_t i = 0; i < h; i++) {
2309 *ptr &= bit_mask;
2310 ptr += row_bytes;
2311 }
2312 }
2313}
2314
2315/**************************************************************************/
2323/**************************************************************************/
2324void GFXcanvas1::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
2325 uint16_t color) {
2326 // x & y already in raw (rotation 0) coordinates, no need to transform.
2327 int16_t rowBytes = ((WIDTH + 7) / 8);
2328 uint8_t *ptr = &buffer[(x / 8) + y * rowBytes];
2329 size_t remainingWidthBits = w;
2330
2331 // check to see if first byte needs to be partially filled
2332 if ((x & 7) > 0) {
2333 // create bit mask for first byte
2334 uint8_t startByteBitMask = 0x00;
2335 for (int8_t i = (x & 7); ((i < 8) && (remainingWidthBits > 0)); i++) {
2336#ifdef __AVR__
2337 startByteBitMask |= pgm_read_byte(&GFXsetBit[i]);
2338#else
2339 startByteBitMask |= (0x80 >> i);
2340#endif
2341 remainingWidthBits--;
2342 }
2343 if (color > 0) {
2344 *ptr |= startByteBitMask;
2345 } else {
2346 *ptr &= ~startByteBitMask;
2347 }
2348
2349 ptr++;
2350 }
2351
2352 // do the next remainingWidthBits bits
2353 if (remainingWidthBits > 0) {
2354 size_t remainingWholeBytes = remainingWidthBits / 8;
2355 size_t lastByteBits = remainingWidthBits % 8;
2356 uint8_t wholeByteColor = color > 0 ? 0xFF : 0x00;
2357
2358 memset(ptr, wholeByteColor, remainingWholeBytes);
2359
2360 if (lastByteBits > 0) {
2361 uint8_t lastByteBitMask = 0x00;
2362 for (size_t i = 0; i < lastByteBits; i++) {
2363#ifdef __AVR__
2364 lastByteBitMask |= pgm_read_byte(&GFXsetBit[i]);
2365#else
2366 lastByteBitMask |= (0x80 >> i);
2367#endif
2368 }
2369 ptr += remainingWholeBytes;
2370
2371 if (color > 0) {
2372 *ptr |= lastByteBitMask;
2373 } else {
2374 *ptr &= ~lastByteBitMask;
2375 }
2376 }
2377 }
2378}
2379
2380/**************************************************************************/
2390/**************************************************************************/
2391GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h, bool allocate_buffer)
2392 : Adafruit_GFX(w, h), buffer_owned(allocate_buffer) {
2393 if (allocate_buffer) {
2394 uint32_t bytes = w * h;
2395 if ((buffer = (uint8_t *)malloc(bytes))) {
2396 memset(buffer, 0, bytes);
2397 }
2398 } else
2399 buffer = nullptr;
2400}
2401
2402/**************************************************************************/
2406/**************************************************************************/
2408 if (buffer && buffer_owned)
2409 free(buffer);
2410}
2411
2412/**************************************************************************/
2419/**************************************************************************/
2420void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) {
2421 if (buffer) {
2422 if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
2423 return;
2424
2425 int16_t t;
2426 switch (rotation) {
2427 case 1:
2428 t = x;
2429 x = WIDTH - 1 - y;
2430 y = t;
2431 break;
2432 case 2:
2433 x = WIDTH - 1 - x;
2434 y = HEIGHT - 1 - y;
2435 break;
2436 case 3:
2437 t = x;
2438 x = y;
2439 y = HEIGHT - 1 - t;
2440 break;
2441 }
2442
2443 buffer[x + y * WIDTH] = color;
2444 }
2445}
2446
2447/**********************************************************************/
2454/**********************************************************************/
2455uint8_t GFXcanvas8::getPixel(int16_t x, int16_t y) const {
2456 int16_t t;
2457 switch (rotation) {
2458 case 1:
2459 t = x;
2460 x = WIDTH - 1 - y;
2461 y = t;
2462 break;
2463 case 2:
2464 x = WIDTH - 1 - x;
2465 y = HEIGHT - 1 - y;
2466 break;
2467 case 3:
2468 t = x;
2469 x = y;
2470 y = HEIGHT - 1 - t;
2471 break;
2472 }
2473 return getRawPixel(x, y);
2474}
2475
2476/**********************************************************************/
2485/**********************************************************************/
2486uint8_t GFXcanvas8::getRawPixel(int16_t x, int16_t y) const {
2487 if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
2488 return 0;
2489 if (buffer) {
2490 return buffer[x + y * WIDTH];
2491 }
2492 return 0;
2493}
2494
2495/**************************************************************************/
2500/**************************************************************************/
2501void GFXcanvas8::fillScreen(uint16_t color) {
2502 if (buffer) {
2503 memset(buffer, color, WIDTH * HEIGHT);
2504 }
2505}
2506
2507/**************************************************************************/
2516/**************************************************************************/
2517void GFXcanvas8::drawFastVLine(int16_t x, int16_t y, int16_t h,
2518 uint16_t color) {
2519 if (h < 0) { // Convert negative heights to positive equivalent
2520 h *= -1;
2521 y -= h - 1;
2522 if (y < 0) {
2523 h += y;
2524 y = 0;
2525 }
2526 }
2527
2528 // Edge rejection (no-draw if totally off canvas)
2529 if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) {
2530 return;
2531 }
2532
2533 if (y < 0) { // Clip top
2534 h += y;
2535 y = 0;
2536 }
2537 if (y + h > height()) { // Clip bottom
2538 h = height() - y;
2539 }
2540
2541 if (getRotation() == 0) {
2542 drawFastRawVLine(x, y, h, color);
2543 } else if (getRotation() == 1) {
2544 int16_t t = x;
2545 x = WIDTH - 1 - y;
2546 y = t;
2547 x -= h - 1;
2548 drawFastRawHLine(x, y, h, color);
2549 } else if (getRotation() == 2) {
2550 x = WIDTH - 1 - x;
2551 y = HEIGHT - 1 - y;
2552
2553 y -= h - 1;
2554 drawFastRawVLine(x, y, h, color);
2555 } else if (getRotation() == 3) {
2556 int16_t t = x;
2557 x = y;
2558 y = HEIGHT - 1 - t;
2559 drawFastRawHLine(x, y, h, color);
2560 }
2561}
2562
2563/**************************************************************************/
2572/**************************************************************************/
2573void GFXcanvas8::drawFastHLine(int16_t x, int16_t y, int16_t w,
2574 uint16_t color) {
2575
2576 if (w < 0) { // Convert negative widths to positive equivalent
2577 w *= -1;
2578 x -= w - 1;
2579 if (x < 0) {
2580 w += x;
2581 x = 0;
2582 }
2583 }
2584
2585 // Edge rejection (no-draw if totally off canvas)
2586 if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) {
2587 return;
2588 }
2589
2590 if (x < 0) { // Clip left
2591 w += x;
2592 x = 0;
2593 }
2594 if (x + w >= width()) { // Clip right
2595 w = width() - x;
2596 }
2597
2598 if (getRotation() == 0) {
2599 drawFastRawHLine(x, y, w, color);
2600 } else if (getRotation() == 1) {
2601 int16_t t = x;
2602 x = WIDTH - 1 - y;
2603 y = t;
2604 drawFastRawVLine(x, y, w, color);
2605 } else if (getRotation() == 2) {
2606 x = WIDTH - 1 - x;
2607 y = HEIGHT - 1 - y;
2608
2609 x -= w - 1;
2610 drawFastRawHLine(x, y, w, color);
2611 } else if (getRotation() == 3) {
2612 int16_t t = x;
2613 x = y;
2614 y = HEIGHT - 1 - t;
2615 y -= w - 1;
2616 drawFastRawVLine(x, y, w, color);
2617 }
2618}
2619
2620/**************************************************************************/
2629/**************************************************************************/
2630void GFXcanvas8::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
2631 uint16_t color) {
2632 // x & y already in raw (rotation 0) coordinates, no need to transform.
2633 uint8_t *buffer_ptr = buffer + y * WIDTH + x;
2634 for (int16_t i = 0; i < h; i++) {
2635 (*buffer_ptr) = color;
2636 buffer_ptr += WIDTH;
2637 }
2638}
2639
2640/**************************************************************************/
2649/**************************************************************************/
2650void GFXcanvas8::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
2651 uint16_t color) {
2652 // x & y already in raw (rotation 0) coordinates, no need to transform.
2653 memset(buffer + y * WIDTH + x, color, w);
2654}
2655
2656/**************************************************************************/
2666/**************************************************************************/
2667GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h, bool allocate_buffer)
2668 : Adafruit_GFX(w, h), buffer_owned(allocate_buffer) {
2669 if (allocate_buffer) {
2670 uint32_t bytes = w * h * 2;
2671 if ((buffer = (uint16_t *)malloc(bytes))) {
2672 memset(buffer, 0, bytes);
2673 }
2674 } else {
2675 buffer = nullptr;
2676 }
2677}
2678
2679/**************************************************************************/
2683/**************************************************************************/
2685 if (buffer && buffer_owned)
2686 free(buffer);
2687}
2688
2689/**************************************************************************/
2696/**************************************************************************/
2697void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) {
2698 if (buffer) {
2699 if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
2700 return;
2701
2702 int16_t t;
2703 switch (rotation) {
2704 case 1:
2705 t = x;
2706 x = WIDTH - 1 - y;
2707 y = t;
2708 break;
2709 case 2:
2710 x = WIDTH - 1 - x;
2711 y = HEIGHT - 1 - y;
2712 break;
2713 case 3:
2714 t = x;
2715 x = y;
2716 y = HEIGHT - 1 - t;
2717 break;
2718 }
2719
2720 buffer[x + y * WIDTH] = color;
2721 }
2722}
2723
2724/**********************************************************************/
2731/**********************************************************************/
2732uint16_t GFXcanvas16::getPixel(int16_t x, int16_t y) const {
2733 int16_t t;
2734 switch (rotation) {
2735 case 1:
2736 t = x;
2737 x = WIDTH - 1 - y;
2738 y = t;
2739 break;
2740 case 2:
2741 x = WIDTH - 1 - x;
2742 y = HEIGHT - 1 - y;
2743 break;
2744 case 3:
2745 t = x;
2746 x = y;
2747 y = HEIGHT - 1 - t;
2748 break;
2749 }
2750 return getRawPixel(x, y);
2751}
2752
2753/**********************************************************************/
2762/**********************************************************************/
2763uint16_t GFXcanvas16::getRawPixel(int16_t x, int16_t y) const {
2764 if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
2765 return 0;
2766 if (buffer) {
2767 return buffer[x + y * WIDTH];
2768 }
2769 return 0;
2770}
2771
2772/**************************************************************************/
2777/**************************************************************************/
2778void GFXcanvas16::fillScreen(uint16_t color) {
2779 if (buffer) {
2780 uint8_t hi = color >> 8, lo = color & 0xFF;
2781 if (hi == lo) {
2782 memset(buffer, lo, WIDTH * HEIGHT * 2);
2783 } else {
2784 uint32_t i, pixels = WIDTH * HEIGHT;
2785 for (i = 0; i < pixels; i++)
2786 buffer[i] = color;
2787 }
2788 }
2789}
2790
2791/**************************************************************************/
2803/**************************************************************************/
2805 if (buffer) {
2806 uint32_t i, pixels = WIDTH * HEIGHT;
2807 for (i = 0; i < pixels; i++)
2808 buffer[i] = __builtin_bswap16(buffer[i]);
2809 }
2810}
2811
2812/**************************************************************************/
2820/**************************************************************************/
2821void GFXcanvas16::drawFastVLine(int16_t x, int16_t y, int16_t h,
2822 uint16_t color) {
2823 if (h < 0) { // Convert negative heights to positive equivalent
2824 h *= -1;
2825 y -= h - 1;
2826 if (y < 0) {
2827 h += y;
2828 y = 0;
2829 }
2830 }
2831
2832 // Edge rejection (no-draw if totally off canvas)
2833 if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) {
2834 return;
2835 }
2836
2837 if (y < 0) { // Clip top
2838 h += y;
2839 y = 0;
2840 }
2841 if (y + h > height()) { // Clip bottom
2842 h = height() - y;
2843 }
2844
2845 if (getRotation() == 0) {
2846 drawFastRawVLine(x, y, h, color);
2847 } else if (getRotation() == 1) {
2848 int16_t t = x;
2849 x = WIDTH - 1 - y;
2850 y = t;
2851 x -= h - 1;
2852 drawFastRawHLine(x, y, h, color);
2853 } else if (getRotation() == 2) {
2854 x = WIDTH - 1 - x;
2855 y = HEIGHT - 1 - y;
2856
2857 y -= h - 1;
2858 drawFastRawVLine(x, y, h, color);
2859 } else if (getRotation() == 3) {
2860 int16_t t = x;
2861 x = y;
2862 y = HEIGHT - 1 - t;
2863 drawFastRawHLine(x, y, h, color);
2864 }
2865}
2866
2867/**************************************************************************/
2875/**************************************************************************/
2876void GFXcanvas16::drawFastHLine(int16_t x, int16_t y, int16_t w,
2877 uint16_t color) {
2878 if (w < 0) { // Convert negative widths to positive equivalent
2879 w *= -1;
2880 x -= w - 1;
2881 if (x < 0) {
2882 w += x;
2883 x = 0;
2884 }
2885 }
2886
2887 // Edge rejection (no-draw if totally off canvas)
2888 if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) {
2889 return;
2890 }
2891
2892 if (x < 0) { // Clip left
2893 w += x;
2894 x = 0;
2895 }
2896 if (x + w >= width()) { // Clip right
2897 w = width() - x;
2898 }
2899
2900 if (getRotation() == 0) {
2901 drawFastRawHLine(x, y, w, color);
2902 } else if (getRotation() == 1) {
2903 int16_t t = x;
2904 x = WIDTH - 1 - y;
2905 y = t;
2906 drawFastRawVLine(x, y, w, color);
2907 } else if (getRotation() == 2) {
2908 x = WIDTH - 1 - x;
2909 y = HEIGHT - 1 - y;
2910
2911 x -= w - 1;
2912 drawFastRawHLine(x, y, w, color);
2913 } else if (getRotation() == 3) {
2914 int16_t t = x;
2915 x = y;
2916 y = HEIGHT - 1 - t;
2917 y -= w - 1;
2918 drawFastRawVLine(x, y, w, color);
2919 }
2920}
2921
2922/**************************************************************************/
2930/**************************************************************************/
2931void GFXcanvas16::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
2932 uint16_t color) {
2933 // x & y already in raw (rotation 0) coordinates, no need to transform.
2934 uint16_t *buffer_ptr = buffer + y * WIDTH + x;
2935 for (int16_t i = 0; i < h; i++) {
2936 (*buffer_ptr) = color;
2937 buffer_ptr += WIDTH;
2938 }
2939}
2940
2941/**************************************************************************/
2949/**************************************************************************/
2950void GFXcanvas16::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
2951 uint16_t color) {
2952 // x & y already in raw (rotation 0) coordinates, no need to transform.
2953 uint32_t buffer_index = y * WIDTH + x;
2954 for (uint32_t i = buffer_index; i < buffer_index + w; i++) {
2955 buffer[i] = color;
2956 }
2957}
void initButton(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t outline, uint16_t fill, uint16_t textcolor, char *label, uint8_t textsize)
Initialize button with our desired color/size/settings.
Adafruit_GFX_Button(void)
Create a simple drawn button UI element.
void initButtonUL(Adafruit_GFX *gfx, int16_t x1, int16_t y1, uint16_t w, uint16_t h, uint16_t outline, uint16_t fill, uint16_t textcolor, char *label, uint8_t textsize)
Initialize button with our desired color/size/settings, with upper-left coordinates.
void drawButton(bool inverted=false)
Draw the button on the screen.
bool justReleased()
Query whether the button was released since we last checked state.
bool justPressed()
Query whether the button was pressed since we last checked state.
bool contains(int16_t x, int16_t y)
Helper to let us know if a coordinate is within the bounds of the button.
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
Draw a perfectly vertical line (this is often optimized in a subclass!)
void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint16_t color)
Half-circle drawer with fill, used for circles and roundrects.
uint16_t textbgcolor
16-bit text color for print()
virtual void fillScreen(uint16_t color)
Fill the screen completely with one color. Update in subclasses if desired!
int16_t HEIGHT
This is the 'raw' display height - never changes.
int16_t width(void) const
Get width of the display, accounting for current rotation.
uint8_t rotation
Display rotation (0 thru 3)
void setTextSize(uint8_t s)
Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger.
void rotatePoint(int16_t &x0, int16_t &y0, int16_t angleDeg)
Rotate a point in standard position.
void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color)
Quarter-circle drawer, used to do circles and roundrects.
void fillRotatedRect(int16_t cenX, int16_t cenY, int16_t w, int16_t h, int16_t angleDeg, uint16_t color)
Draw a filled rotated rectangle.
virtual void invertDisplay(bool i)
Invert the display (ideally using built-in hardware command)
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
Draw a triangle with no fill color.
int16_t height(void) const
Get height of the display, accounting for current rotation.
void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
Draw a triangle with color-fill.
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
Draw a perfectly horizontal line (this is often optimized in a subclass!)
void setTextColor(uint16_t c)
Set text font color with transparant background.
virtual void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
Write a rectangle completely with one color, overwrite in subclasses if startWrite is defined!
void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
Draw a circle with filled color.
void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
Draw a circle outline.
void charBounds(unsigned char c, int16_t *x, int16_t *y, int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy)
Helper to determine size of a character with current font/size. Broke this out as it's used by both t...
virtual void setRotation(uint8_t r)
Set rotation setting for display.
Adafruit_GFX(int16_t w, int16_t h)
Instatiate a GFX context for graphics! Can only be done by a superclass.
bool _cp437
If set, use correct CP437 charset (default is off)
void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color)
Draw a rounded rectangle with fill color.
void fillEllipse(int16_t x0, int16_t y0, int16_t rw, int16_t rh, uint16_t color)
Draw an ellipse with filled colour.
void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color)
Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground c...
virtual void write(uint8_t)
Print one byte/character of data, used to support print()
bool wrap
If set, 'wrap' text at right edge of display.
uint16_t textcolor
16-bit background color for print()
int16_t cursor_x
x location to start print()ing text
void getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
Helper to determine size of a string with current font/size. Pass string and a cursor position,...
uint8_t textsize_x
Desired magnification in X-axis of text to print()
virtual void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
Draw a rectangle with no fill color.
virtual void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)
Draw a line.
virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
Fill a rectangle completely with one color. Update in subclasses if desired!
void drawEllipse(int16_t x0, int16_t y0, int16_t rw, int16_t rh, uint16_t color)
Draw an ellipse outline.
void drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color)
Draw PROGMEM-resident XBitMap Files (*.xbm), exported from GIMP. Usage: Export from GIMP to *....
uint8_t textsize_y
Desired magnification in Y-axis of text to print()
virtual void startWrite(void)
Start a display-writing routine, overwrite in subclasses.
void setCursor(int16_t x, int16_t y)
Set text cursor location.
void setFont(const GFXfont *f=NULL)
Set the font to display when print()ing, either custom or default.
int16_t _width
Display width as modified by current rotation.
void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color)
Draw a rounded rectangle with no fill color.
virtual void writePixel(int16_t x, int16_t y, uint16_t color)
Write a pixel, overwrite in subclasses if startWrite is defined!
void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size)
Draw a single character.
virtual void drawPixel(int16_t x, int16_t y, uint16_t color)=0
Draw to the screen/framebuffer/etc. Must be overridden in subclass.
uint8_t getRotation(void) const
Get rotation setting for display.
int16_t _height
Display height as modified by current rotation.
virtual void endWrite(void)
End a display-writing routine, overwrite in subclasses if startWrite is defined!
virtual void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
Write a perfectly horizontal line, overwrite in subclasses if startWrite is defined!
int16_t WIDTH
This is the 'raw' display width - never changes.
virtual void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
Write a perfectly vertical line, overwrite in subclasses if startWrite is defined!
virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)
Write a line. Bresenham's algorithm - thx wikpedia.
int16_t cursor_y
y location to start print()ing text
void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h)
Draw a PROGMEM-resident 8-bit image (grayscale) at the specified (x,y) pos. Specifically for 8-bit di...
void drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h)
Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position. For 16-bit display ...
void drawRotatedRect(int16_t cenX, int16_t cenY, int16_t w, int16_t h, int16_t angleDeg, uint16_t color)
Draw a rotated rectangle.
GFXfont * gfxFont
Pointer to special font.
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
Speed optimized horizontal line drawing into the raw canvas buffer.
uint16_t * buffer
Raster data: no longer private, allow subclass access.
~GFXcanvas16(void)
Delete the canvas, free memory.
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
Speed optimized vertical line drawing.
void byteSwap(void)
Reverses the "endian-ness" of each 16-bit pixel within the canvas; little-endian to big-endian,...
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
Speed optimized vertical line drawing into the raw canvas buffer.
uint16_t getPixel(int16_t x, int16_t y) const
Get the pixel color value at a given coordinate.
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
Speed optimized horizontal line drawing.
void drawPixel(int16_t x, int16_t y, uint16_t color)
Draw a pixel to the canvas framebuffer.
void fillScreen(uint16_t color)
Fill the framebuffer completely with one color.
uint16_t getRawPixel(int16_t x, int16_t y) const
Get the pixel color value at a given, unrotated coordinate. This method is intended for hardware driv...
GFXcanvas16(uint16_t w, uint16_t h, bool allocate_buffer=true)
Instatiate a GFX 16-bit canvas context for graphics.
void drawPixel(int16_t x, int16_t y, uint16_t color)
Draw a pixel to the canvas framebuffer.
bool buffer_owned
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
Speed optimized vertical line drawing.
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
Speed optimized vertical line drawing into the raw canvas buffer.
GFXcanvas1(uint16_t w, uint16_t h, bool allocate_buffer=true)
Instatiate a GFX 1-bit canvas context for graphics.
bool getRawPixel(int16_t x, int16_t y) const
Get the pixel color value at a given, unrotated coordinate. This method is intended for hardware driv...
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
Speed optimized horizontal line drawing into the raw canvas buffer.
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
Speed optimized horizontal line drawing.
~GFXcanvas1(void)
Delete the canvas, free memory.
bool getPixel(int16_t x, int16_t y) const
Get the pixel color value at a given coordinate.
void fillScreen(uint16_t color)
Fill the framebuffer completely with one color.
uint8_t * buffer
Raster data: no longer private, allow subclass access.
~GFXcanvas8(void)
Delete the canvas, free memory.
uint8_t getRawPixel(int16_t x, int16_t y) const
Get the pixel color value at a given, unrotated coordinate. This method is intended for hardware driv...
void drawPixel(int16_t x, int16_t y, uint16_t color)
Draw a pixel to the canvas framebuffer.
uint8_t getPixel(int16_t x, int16_t y) const
Get the pixel color value at a given coordinate.
GFXcanvas8(uint16_t w, uint16_t h, bool allocate_buffer=true)
Instatiate a GFX 8-bit canvas context for graphics.
void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
Speed optimized horizontal line drawing into the raw canvas buffer.
void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
Speed optimized vertical line drawing.
void fillScreen(uint16_t color)
Fill the framebuffer completely with one color.
uint8_t * buffer
Raster data: no longer private, allow subclass access.
void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
Speed optimized vertical line drawing into the raw canvas buffer.
bool buffer_owned
void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
Speed optimized horizontal line drawing.
size_t print(const __FlashStringHelper *ifsh)
Print a flash-resident string, e.g. print(F("text")).
Definition Print.cpp:30
Minimal Arduino-String stand-in (see file description).
Definition WString.h:22
const char * c_str() const
Definition WString.h:49
unsigned int length() const
Definition WString.h:51