F439_CPP_SPI_RA8875_TFT_LCD_03 1.0
STM32F439 SPI RA8875 7-inch TFT display demo built on the STM32_GFX and STM32_RA8875 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
65inline GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) {
66#ifdef __AVR__
67 return &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
68#else
69 // expression in __AVR__ section may generate "dereferencing type-punned
70 // pointer will break strict-aliasing rules" warning In fact, on other
71 // platforms (such as STM32) there is no need to do this pointer magic as
72 // program memory may be read in a usual way So expression may be simplified
73 return gfxFont->glyph + c;
74#endif //__AVR__
75}
76
77inline uint8_t *pgm_read_bitmap_ptr(const GFXfont *gfxFont) {
78#ifdef __AVR__
79 return (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);
80#else
81 // expression in __AVR__ section generates "dereferencing type-punned pointer
82 // will break strict-aliasing rules" warning In fact, on other platforms (such
83 // as STM32) there is no need to do this pointer magic as program memory may
84 // be read in a usual way So expression may be simplified
85 return gfxFont->bitmap;
86#endif //__AVR__
87}
88
89#ifndef min
90#define min(a, b) (((a) < (b)) ? (a) : (b))
91#endif
92
93#ifndef _swap_int16_t
94#define _swap_int16_t(a, b) \
95 { \
96 int16_t t = a; \
97 a = b; \
98 b = t; \
99 }
100#endif
101
108/**************************************************************************/
109Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h) {
110 _width = WIDTH;
111 _height = HEIGHT;
112 rotation = 0;
113 cursor_y = cursor_x = 0;
115 textcolor = textbgcolor = 0xFFFF;
116 wrap = true;
117 _cp437 = false;
118 gfxFont = NULL;
119}
120
129/**************************************************************************/
130void Adafruit_GFX::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
131 uint16_t color) {
132#if defined(ESP8266)
133 yield();
134#endif
135 int16_t steep = abs(y1 - y0) > abs(x1 - x0);
136 if (steep) {
137 _swap_int16_t(x0, y0);
138 _swap_int16_t(x1, y1);
139 }
140
141 if (x0 > x1) {
142 _swap_int16_t(x0, x1);
143 _swap_int16_t(y0, y1);
144 }
145
146 int16_t dx, dy;
147 dx = x1 - x0;
148 dy = abs(y1 - y0);
149
150 int16_t err = dx / 2;
151 int16_t ystep;
152
153 if (y0 < y1) {
154 ystep = 1;
155 } else {
156 ystep = -1;
157 }
158
159 for (; x0 <= x1; x0++) {
160 if (steep) {
161 writePixel(y0, x0, color);
162 } else {
163 writePixel(x0, y0, color);
164 }
165 err -= dy;
166 if (err < 0) {
167 y0 += ystep;
168 err += dx;
169 }
170 }
171}
172
173/**************************************************************************/
177/**************************************************************************/
179
180/**************************************************************************/
187/**************************************************************************/
188void Adafruit_GFX::writePixel(int16_t x, int16_t y, uint16_t color) {
189 drawPixel(x, y, color);
190}
191
192/**************************************************************************/
201/**************************************************************************/
202void Adafruit_GFX::writeFastVLine(int16_t x, int16_t y, int16_t h,
203 uint16_t color) {
204 // Overwrite in subclasses if startWrite is defined!
205 // Can be just writeLine(x, y, x, y+h-1, color);
206 // or writeFillRect(x, y, 1, h, color);
207 drawFastVLine(x, y, h, color);
208}
209
210/**************************************************************************/
219/**************************************************************************/
220void Adafruit_GFX::writeFastHLine(int16_t x, int16_t y, int16_t w,
221 uint16_t color) {
222 // Overwrite in subclasses if startWrite is defined!
223 // Example: writeLine(x, y, x+w-1, y, color);
224 // or writeFillRect(x, y, w, 1, color);
225 drawFastHLine(x, y, w, color);
226}
227
228/**************************************************************************/
238/**************************************************************************/
239void Adafruit_GFX::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h,
240 uint16_t color) {
241 // Overwrite in subclasses if desired!
242 fillRect(x, y, w, h, color);
243}
244
245/**************************************************************************/
250/**************************************************************************/
252
253/**************************************************************************/
262/**************************************************************************/
263void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, int16_t h,
264 uint16_t color) {
265 startWrite();
266 writeLine(x, y, x, y + h - 1, color);
267 endWrite();
268}
269
270/**************************************************************************/
279/**************************************************************************/
280void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, int16_t w,
281 uint16_t color) {
282 startWrite();
283 writeLine(x, y, x + w - 1, y, color);
284 endWrite();
285}
286
287/**************************************************************************/
297/**************************************************************************/
298void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
299 uint16_t color) {
300 startWrite();
301 for (int16_t i = x; i < x + w; i++) {
302 writeFastVLine(i, y, h, color);
303 }
304 endWrite();
305}
306
307/**************************************************************************/
313/**************************************************************************/
314void Adafruit_GFX::fillScreen(uint16_t color) {
315 fillRect(0, 0, _width, _height, color);
316}
317
318/**************************************************************************/
327/**************************************************************************/
328void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
329 uint16_t color) {
330 // Update in subclasses if desired!
331 if (x0 == x1) {
332 if (y0 > y1)
333 _swap_int16_t(y0, y1);
334 drawFastVLine(x0, y0, y1 - y0 + 1, color);
335 } else if (y0 == y1) {
336 if (x0 > x1)
337 _swap_int16_t(x0, x1);
338 drawFastHLine(x0, y0, x1 - x0 + 1, color);
339 } else {
340 startWrite();
341 writeLine(x0, y0, x1, y1, color);
342 endWrite();
343 }
344}
345
346/**************************************************************************/
355/**************************************************************************/
356void Adafruit_GFX::drawEllipse(int16_t x0, int16_t y0, int16_t rw, int16_t rh,
357 uint16_t color) {
358#if defined(ESP8266)
359 yield();
360#endif
361 // Bresenham's ellipse algorithm
362 int16_t x = 0, y = rh;
363 int32_t rw2 = rw * rw, rh2 = rh * rh;
364 int32_t twoRw2 = 2 * rw2, twoRh2 = 2 * rh2;
365
366 int32_t decision = rh2 - (rw2 * rh) + (rw2 / 4);
367
368 startWrite();
369
370 // region 1
371 while ((twoRh2 * x) < (twoRw2 * y)) {
372 writePixel(x0 + x, y0 + y, color);
373 writePixel(x0 - x, y0 + y, color);
374 writePixel(x0 + x, y0 - y, color);
375 writePixel(x0 - x, y0 - y, color);
376 x++;
377 if (decision < 0) {
378 decision += rh2 + (twoRh2 * x);
379 } else {
380 decision += rh2 + (twoRh2 * x) - (twoRw2 * y);
381 y--;
382 }
383 }
384
385 // region 2
386 decision = ((rh2 * (2 * x + 1) * (2 * x + 1)) >> 2) +
387 (rw2 * (y - 1) * (y - 1)) - (rw2 * rh2);
388 while (y >= 0) {
389 writePixel(x0 + x, y0 + y, color);
390 writePixel(x0 - x, y0 + y, color);
391 writePixel(x0 + x, y0 - y, color);
392 writePixel(x0 - x, y0 - y, color);
393 y--;
394 if (decision > 0) {
395 decision += rw2 - (twoRw2 * y);
396 } else {
397 decision += rw2 + (twoRh2 * x) - (twoRw2 * y);
398 x++;
399 }
400 }
401
402 endWrite();
403}
404
405/**************************************************************************/
414/**************************************************************************/
415void Adafruit_GFX::fillEllipse(int16_t x0, int16_t y0, int16_t rw, int16_t rh,
416 uint16_t color) {
417#if defined(ESP8266)
418 yield();
419#endif
420 // Bresenham's ellipse algorithm
421 int16_t x = 0, y = rh;
422 int32_t rw2 = rw * rw, rh2 = rh * rh;
423 int32_t twoRw2 = 2 * rw2, twoRh2 = 2 * rh2;
424
425 int32_t decision = rh2 - (rw2 * rh) + (rw2 / 4);
426
427 startWrite();
428
429 // region 1
430 while ((twoRh2 * x) < (twoRw2 * y)) {
431 x++;
432 if (decision < 0) {
433 decision += rh2 + (twoRh2 * x);
434 } else {
435 decision += rh2 + (twoRh2 * x) - (twoRw2 * y);
436 drawFastHLine(x0 - (x - 1), y0 + y, 2 * (x - 1) + 1, color);
437 drawFastHLine(x0 - (x - 1), y0 - y, 2 * (x - 1) + 1, color);
438 y--;
439 }
440 }
441
442 // region 2
443 decision = ((rh2 * (2 * x + 1) * (2 * x + 1)) >> 2) +
444 (rw2 * (y - 1) * (y - 1)) - (rw2 * rh2);
445 while (y >= 0) {
446 drawFastHLine(x0 - x, y0 + y, 2 * x + 1, color);
447 drawFastHLine(x0 - x, y0 - y, 2 * x + 1, color);
448
449 y--;
450 if (decision > 0) {
451 decision += rw2 - (twoRw2 * y);
452 } else {
453 decision += rw2 + (twoRh2 * x) - (twoRw2 * y);
454 x++;
455 }
456 }
457
458 endWrite();
459}
460
461/**************************************************************************/
469/**************************************************************************/
470void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r,
471 uint16_t color) {
472#if defined(ESP8266)
473 yield();
474#endif
475 int16_t f = 1 - r;
476 int16_t ddF_x = 1;
477 int16_t ddF_y = -2 * r;
478 int16_t x = 0;
479 int16_t y = r;
480
481 startWrite();
482 writePixel(x0, y0 + r, color);
483 writePixel(x0, y0 - r, color);
484 writePixel(x0 + r, y0, color);
485 writePixel(x0 - r, y0, color);
486
487 while (x < y) {
488 if (f >= 0) {
489 y--;
490 ddF_y += 2;
491 f += ddF_y;
492 }
493 x++;
494 ddF_x += 2;
495 f += ddF_x;
496
497 writePixel(x0 + x, y0 + y, color);
498 writePixel(x0 - x, y0 + y, color);
499 writePixel(x0 + x, y0 - y, color);
500 writePixel(x0 - x, y0 - y, color);
501 writePixel(x0 + y, y0 + x, color);
502 writePixel(x0 - y, y0 + x, color);
503 writePixel(x0 + y, y0 - x, color);
504 writePixel(x0 - y, y0 - x, color);
505 }
506 endWrite();
507}
508
509/**************************************************************************/
519/**************************************************************************/
520void Adafruit_GFX::drawCircleHelper(int16_t x0, int16_t y0, int16_t r,
521 uint8_t cornername, uint16_t color) {
522 int16_t f = 1 - r;
523 int16_t ddF_x = 1;
524 int16_t ddF_y = -2 * r;
525 int16_t x = 0;
526 int16_t y = r;
527
528 while (x < y) {
529 if (f >= 0) {
530 y--;
531 ddF_y += 2;
532 f += ddF_y;
533 }
534 x++;
535 ddF_x += 2;
536 f += ddF_x;
537 if (cornername & 0x4) {
538 writePixel(x0 + x, y0 + y, color);
539 writePixel(x0 + y, y0 + x, color);
540 }
541 if (cornername & 0x2) {
542 writePixel(x0 + x, y0 - y, color);
543 writePixel(x0 + y, y0 - x, color);
544 }
545 if (cornername & 0x8) {
546 writePixel(x0 - y, y0 + x, color);
547 writePixel(x0 - x, y0 + y, color);
548 }
549 if (cornername & 0x1) {
550 writePixel(x0 - y, y0 - x, color);
551 writePixel(x0 - x, y0 - y, color);
552 }
553 }
554}
555
556/**************************************************************************/
564/**************************************************************************/
565void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r,
566 uint16_t color) {
567 startWrite();
568 writeFastVLine(x0, y0 - r, 2 * r + 1, color);
569 fillCircleHelper(x0, y0, r, 3, 0, color);
570 endWrite();
571}
572
573/**************************************************************************/
584/**************************************************************************/
585void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
586 uint8_t corners, int16_t delta,
587 uint16_t color) {
588
589 int16_t f = 1 - r;
590 int16_t ddF_x = 1;
591 int16_t ddF_y = -2 * r;
592 int16_t x = 0;
593 int16_t y = r;
594 int16_t px = x;
595 int16_t py = y;
596
597 delta++; // Avoid some +1's in the loop
598
599 while (x < y) {
600 if (f >= 0) {
601 y--;
602 ddF_y += 2;
603 f += ddF_y;
604 }
605 x++;
606 ddF_x += 2;
607 f += ddF_x;
608 // These checks avoid double-drawing certain lines, important
609 // for the SSD1306 library which has an INVERT drawing mode.
610 if (x < (y + 1)) {
611 if (corners & 1)
612 writeFastVLine(x0 + x, y0 - y, 2 * y + delta, color);
613 if (corners & 2)
614 writeFastVLine(x0 - x, y0 - y, 2 * y + delta, color);
615 }
616 if (y != py) {
617 if (corners & 1)
618 writeFastVLine(x0 + py, y0 - px, 2 * px + delta, color);
619 if (corners & 2)
620 writeFastVLine(x0 - py, y0 - px, 2 * px + delta, color);
621 py = y;
622 }
623 px = x;
624 }
625}
626
627/**************************************************************************/
636/**************************************************************************/
637void Adafruit_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
638 uint16_t color) {
639 startWrite();
640 writeFastHLine(x, y, w, color);
641 writeFastHLine(x, y + h - 1, w, color);
642 writeFastVLine(x, y, h, color);
643 writeFastVLine(x + w - 1, y, h, color);
644 endWrite();
645}
646
647/**************************************************************************/
657/**************************************************************************/
658void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h,
659 int16_t r, uint16_t color) {
660 int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
661 if (r > max_radius)
662 r = max_radius;
663 // smarter version
664 startWrite();
665 writeFastHLine(x + r, y, w - 2 * r, color); // Top
666 writeFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom
667 writeFastVLine(x, y + r, h - 2 * r, color); // Left
668 writeFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right
669 // draw four corners
670 drawCircleHelper(x + r, y + r, r, 1, color);
671 drawCircleHelper(x + w - r - 1, y + r, r, 2, color);
672 drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color);
673 drawCircleHelper(x + r, y + h - r - 1, r, 8, color);
674 endWrite();
675}
676
677/**************************************************************************/
687/**************************************************************************/
688void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h,
689 int16_t r, uint16_t color) {
690 int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis
691 if (r > max_radius)
692 r = max_radius;
693 // smarter version
694 startWrite();
695 writeFillRect(x + r, y, w - 2 * r, h, color);
696 // draw four corners
697 fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color);
698 fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color);
699 endWrite();
700}
701
702/**************************************************************************/
718/**************************************************************************/
719void Adafruit_GFX::drawRotatedRect(int16_t cenX, int16_t cenY, int16_t w,
720 int16_t h, int16_t angleDeg,
721 uint16_t color) {
722
723 if (w < 1 || h < 1)
724 return; // We don't draw zero dimensioned objects
725
726 int16_t W = w - 1;
727 int16_t H = h - 1;
728
729 int16_t halfW = (W / 2); // Midpoint should always be integer
730 int16_t halfH = (H / 2); // Midpoint should always be integer
731
732 int16_t x0 = W - halfW; // bottom-right
733 int16_t y0 = H - halfH; // bottom-right
734 int16_t x1 = -halfW; // bottom-left
735 int16_t y1 = H - halfH; // bottom-left
736 int16_t x2 = -halfW; // top-left
737 int16_t y2 = -halfH; // top-left
738 int16_t x3 = W - halfW; // top-right
739 int16_t y3 = -halfH; // top-right
740
741 rotatePoint(x0, y0, angleDeg);
742 rotatePoint(x1, y1, angleDeg);
743 rotatePoint(x2, y2, angleDeg);
744 rotatePoint(x3, y3, angleDeg);
745
746 x0 += cenX;
747 x1 += cenX;
748 x2 += cenX;
749 x3 += cenX;
750
751 y0 += cenY;
752 y1 += cenY;
753 y2 += cenY;
754 y3 += cenY;
755
756 drawLine(x0, y0, x1, y1, color); // bottom right to bottom left
757 drawLine(x1, y1, x2, y2, color); // bottom left to top left
758 drawLine(x2, y2, x3, y3, color); // top left to top right
759 drawLine(x3, y3, x0, y0, color); // top right to bottom right
760}
761
762/**************************************************************************/
778/**************************************************************************/
779void Adafruit_GFX::fillRotatedRect(int16_t cenX, int16_t cenY, int16_t w,
780 int16_t h, int16_t angleDeg,
781 uint16_t color) {
782
783 if (w < 1 || h < 1)
784 return; // We don't draw zero dimensioned objects
785
786 int16_t W = w - 1;
787 int16_t H = h - 1;
788
789 int16_t halfW = (W / 2); // Midpoint should always be integer
790 int16_t halfH = (H / 2); // Midpoint should always be integer
791
792 int16_t x0 = W - halfW; // bottom-right
793 int16_t y0 = H - halfH; // bottom-right
794 int16_t x1 = -halfW; // bottom-left
795 int16_t y1 = H - halfH; // bottom-left
796 int16_t x2 = -halfW; // top-left
797 int16_t y2 = -halfH; // top-left
798 int16_t x3 = W - halfW; // top-right
799 int16_t y3 = -halfH; // top-right
800
801 rotatePoint(x0, y0, angleDeg);
802 rotatePoint(x1, y1, angleDeg);
803 rotatePoint(x2, y2, angleDeg);
804 rotatePoint(x3, y3, angleDeg);
805
806 x0 += cenX;
807 x1 += cenX;
808 x2 += cenX;
809 x3 += cenX;
810
811 y0 += cenY;
812 y1 += cenY;
813 y2 += cenY;
814 y3 += cenY;
815
816 fillTriangle(x0, y0, x1, y1, x2, y2, color);
817 fillTriangle(x2, y2, x3, y3, x0, y0, color);
818}
819
820/**************************************************************************/
829/**************************************************************************/
830void Adafruit_GFX::rotatePoint(int16_t &x0, int16_t &y0, int16_t angleDeg) {
831 float angleRad = radians(angleDeg);
832 float s = sin(angleRad);
833 float c = cos(angleRad);
834
835 float x = x0;
836 float y = y0;
837
838 // Rotate point
839 x0 = (int16_t)((x * c) - (y * s));
840 y0 = (int16_t)((x * s) + (y * c));
841}
842
843/**************************************************************************/
854/**************************************************************************/
855void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
856 int16_t x2, int16_t y2, uint16_t color) {
857 drawLine(x0, y0, x1, y1, color);
858 drawLine(x1, y1, x2, y2, color);
859 drawLine(x2, y2, x0, y0, color);
860}
861
862/**************************************************************************/
873/**************************************************************************/
874void Adafruit_GFX::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
875 int16_t x2, int16_t y2, uint16_t color) {
876
877 int16_t a, b, y, last;
878
879 // Sort coordinates by Y order (y2 >= y1 >= y0)
880 if (y0 > y1) {
881 _swap_int16_t(y0, y1);
882 _swap_int16_t(x0, x1);
883 }
884 if (y1 > y2) {
885 _swap_int16_t(y2, y1);
886 _swap_int16_t(x2, x1);
887 }
888 if (y0 > y1) {
889 _swap_int16_t(y0, y1);
890 _swap_int16_t(x0, x1);
891 }
892
893 startWrite();
894 if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing
895 a = b = x0;
896 if (x1 < a)
897 a = x1;
898 else if (x1 > b)
899 b = x1;
900 if (x2 < a)
901 a = x2;
902 else if (x2 > b)
903 b = x2;
904 writeFastHLine(a, y0, b - a + 1, color);
905 endWrite();
906 return;
907 }
908
909 int16_t dx01 = x1 - x0, dy01 = y1 - y0, dx02 = x2 - x0, dy02 = y2 - y0,
910 dx12 = x2 - x1, dy12 = y2 - y1;
911 int32_t sa = 0, sb = 0;
912
913 // For upper part of triangle, find scanline crossings for segments
914 // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
915 // is included here (and second loop will be skipped, avoiding a /0
916 // error there), otherwise scanline y1 is skipped here and handled
917 // in the second loop...which also avoids a /0 error here if y0=y1
918 // (flat-topped triangle).
919 if (y1 == y2)
920 last = y1; // Include y1 scanline
921 else
922 last = y1 - 1; // Skip it
923
924 for (y = y0; y <= last; y++) {
925 a = x0 + sa / dy01;
926 b = x0 + sb / dy02;
927 sa += dx01;
928 sb += dx02;
929 /* longhand:
930 a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
931 b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
932 */
933 if (a > b)
934 _swap_int16_t(a, b);
935 writeFastHLine(a, y, b - a + 1, color);
936 }
937
938 // For lower part of triangle, find scanline crossings for segments
939 // 0-2 and 1-2. This loop is skipped if y1=y2.
940 sa = (int32_t)dx12 * (y - y1);
941 sb = (int32_t)dx02 * (y - y0);
942 for (; y <= y2; y++) {
943 a = x1 + sa / dy12;
944 b = x0 + sb / dy02;
945 sa += dx12;
946 sb += dx02;
947 /* longhand:
948 a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
949 b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
950 */
951 if (a > b)
952 _swap_int16_t(a, b);
953 writeFastHLine(a, y, b - a + 1, color);
954 }
955 endWrite();
956}
957
958// BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS ---------------------
959
960/**************************************************************************/
971/**************************************************************************/
972void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
973 int16_t w, int16_t h, uint16_t color) {
974
975 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
976 uint8_t b = 0;
977
978 startWrite();
979 for (int16_t j = 0; j < h; j++, y++) {
980 for (int16_t i = 0; i < w; i++) {
981 if (i & 7)
982 b <<= 1;
983 else
984 b = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
985 if (b & 0x80)
986 writePixel(x + i, y, color);
987 }
988 }
989 endWrite();
990}
991
992/**************************************************************************/
1005/**************************************************************************/
1006void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
1007 int16_t w, int16_t h, uint16_t color,
1008 uint16_t bg) {
1009
1010 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
1011 uint8_t b = 0;
1012
1013 startWrite();
1014 for (int16_t j = 0; j < h; j++, y++) {
1015 for (int16_t i = 0; i < w; i++) {
1016 if (i & 7)
1017 b <<= 1;
1018 else
1019 b = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
1020 writePixel(x + i, y, (b & 0x80) ? color : bg);
1021 }
1022 }
1023 endWrite();
1024}
1025
1026/**************************************************************************/
1037/**************************************************************************/
1038void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w,
1039 int16_t h, uint16_t color) {
1040
1041 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
1042 uint8_t b = 0;
1043
1044 startWrite();
1045 for (int16_t j = 0; j < h; j++, y++) {
1046 for (int16_t i = 0; i < w; i++) {
1047 if (i & 7)
1048 b <<= 1;
1049 else
1050 b = bitmap[j * byteWidth + i / 8];
1051 if (b & 0x80)
1052 writePixel(x + i, y, color);
1053 }
1054 }
1055 endWrite();
1056}
1057
1058/**************************************************************************/
1071/**************************************************************************/
1072void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w,
1073 int16_t h, uint16_t color, uint16_t bg) {
1074
1075 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
1076 uint8_t b = 0;
1077
1078 startWrite();
1079 for (int16_t j = 0; j < h; j++, y++) {
1080 for (int16_t i = 0; i < w; i++) {
1081 if (i & 7)
1082 b <<= 1;
1083 else
1084 b = bitmap[j * byteWidth + i / 8];
1085 writePixel(x + i, y, (b & 0x80) ? color : bg);
1086 }
1087 }
1088 endWrite();
1089}
1090
1091/**************************************************************************/
1105/**************************************************************************/
1106void Adafruit_GFX::drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[],
1107 int16_t w, int16_t h, uint16_t color) {
1108
1109 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte
1110 uint8_t b = 0;
1111
1112 startWrite();
1113 for (int16_t j = 0; j < h; j++, y++) {
1114 for (int16_t i = 0; i < w; i++) {
1115 if (i & 7)
1116 b >>= 1;
1117 else
1118 b = pgm_read_byte(&bitmap[j * byteWidth + i / 8]);
1119 // Nearly identical to drawBitmap(), only the bit order
1120 // is reversed here (left-to-right = LSB to MSB):
1121 if (b & 0x01)
1122 writePixel(x + i, y, color);
1123 }
1124 }
1125 endWrite();
1126}
1127
1128/**************************************************************************/
1139/**************************************************************************/
1140void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
1141 const uint8_t bitmap[], int16_t w,
1142 int16_t h) {
1143 startWrite();
1144 for (int16_t j = 0; j < h; j++, y++) {
1145 for (int16_t i = 0; i < w; i++) {
1146 writePixel(x + i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i]));
1147 }
1148 }
1149 endWrite();
1150}
1151
1152/**************************************************************************/
1163/**************************************************************************/
1164void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap,
1165 int16_t w, int16_t h) {
1166 startWrite();
1167 for (int16_t j = 0; j < h; j++, y++) {
1168 for (int16_t i = 0; i < w; i++) {
1169 writePixel(x + i, y, bitmap[j * w + i]);
1170 }
1171 }
1172 endWrite();
1173}
1174
1175/**************************************************************************/
1189/**************************************************************************/
1190void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y,
1191 const uint8_t bitmap[],
1192 const uint8_t mask[], int16_t w,
1193 int16_t h) {
1194 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
1195 uint8_t b = 0;
1196 startWrite();
1197 for (int16_t j = 0; j < h; j++, y++) {
1198 for (int16_t i = 0; i < w; i++) {
1199 if (i & 7)
1200 b <<= 1;
1201 else
1202 b = pgm_read_byte(&mask[j * bw + i / 8]);
1203 if (b & 0x80) {
1204 writePixel(x + i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i]));
1205 }
1206 }
1207 }
1208 endWrite();
1209}
1210
1211/**************************************************************************/
1225/**************************************************************************/
1226void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap,
1227 uint8_t *mask, int16_t w, int16_t h) {
1228 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
1229 uint8_t b = 0;
1230 startWrite();
1231 for (int16_t j = 0; j < h; j++, y++) {
1232 for (int16_t i = 0; i < w; i++) {
1233 if (i & 7)
1234 b <<= 1;
1235 else
1236 b = mask[j * bw + i / 8];
1237 if (b & 0x80) {
1238 writePixel(x + i, y, bitmap[j * w + i]);
1239 }
1240 }
1241 }
1242 endWrite();
1243}
1244
1245/**************************************************************************/
1255/**************************************************************************/
1256void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[],
1257 int16_t w, int16_t h) {
1258 startWrite();
1259 for (int16_t j = 0; j < h; j++, y++) {
1260 for (int16_t i = 0; i < w; i++) {
1261 writePixel(x + i, y, pgm_read_word(&bitmap[j * w + i]));
1262 }
1263 }
1264 endWrite();
1265}
1266
1267/**************************************************************************/
1277/**************************************************************************/
1278void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap,
1279 int16_t w, int16_t h) {
1280 startWrite();
1281 for (int16_t j = 0; j < h; j++, y++) {
1282 for (int16_t i = 0; i < w; i++) {
1283 writePixel(x + i, y, bitmap[j * w + i]);
1284 }
1285 }
1286 endWrite();
1287}
1288
1289/**************************************************************************/
1302/**************************************************************************/
1303void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[],
1304 const uint8_t mask[], int16_t w, int16_t h) {
1305 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
1306 uint8_t b = 0;
1307 startWrite();
1308 for (int16_t j = 0; j < h; j++, y++) {
1309 for (int16_t i = 0; i < w; i++) {
1310 if (i & 7)
1311 b <<= 1;
1312 else
1313 b = pgm_read_byte(&mask[j * bw + i / 8]);
1314 if (b & 0x80) {
1315 writePixel(x + i, y, pgm_read_word(&bitmap[j * w + i]));
1316 }
1317 }
1318 }
1319 endWrite();
1320}
1321
1322/**************************************************************************/
1335/**************************************************************************/
1336void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap,
1337 uint8_t *mask, int16_t w, int16_t h) {
1338 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte
1339 uint8_t b = 0;
1340 startWrite();
1341 for (int16_t j = 0; j < h; j++, y++) {
1342 for (int16_t i = 0; i < w; i++) {
1343 if (i & 7)
1344 b <<= 1;
1345 else
1346 b = mask[j * bw + i / 8];
1347 if (b & 0x80) {
1348 writePixel(x + i, y, bitmap[j * w + i]);
1349 }
1350 }
1351 }
1352 endWrite();
1353}
1354
1355// TEXT- AND CHARACTER-HANDLING FUNCTIONS ----------------------------------
1356
1357// Draw a character
1358/**************************************************************************/
1369/**************************************************************************/
1370void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
1371 uint16_t color, uint16_t bg, uint8_t size) {
1372 drawChar(x, y, c, color, bg, size, size);
1373}
1374
1375// Draw a character
1376/**************************************************************************/
1388/**************************************************************************/
1389void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
1390 uint16_t color, uint16_t bg, uint8_t size_x,
1391 uint8_t size_y) {
1392
1393 if (!gfxFont) { // 'Classic' built-in font
1394
1395 if ((x >= _width) || // Clip right
1396 (y >= _height) || // Clip bottom
1397 ((x + 6 * size_x - 1) < 0) || // Clip left
1398 ((y + 8 * size_y - 1) < 0)) // Clip top
1399 return;
1400
1401 if (!_cp437 && (c >= 176))
1402 c++; // Handle 'classic' charset behavior
1403
1404 startWrite();
1405 for (int8_t i = 0; i < 5; i++) { // Char bitmap = 5 columns
1406 uint8_t line = pgm_read_byte(&font[c * 5 + i]);
1407 for (int8_t j = 0; j < 8; j++, line >>= 1) {
1408 if (line & 1) {
1409 if (size_x == 1 && size_y == 1)
1410 writePixel(x + i, y + j, color);
1411 else
1412 writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y,
1413 color);
1414 } else if (bg != color) {
1415 if (size_x == 1 && size_y == 1)
1416 writePixel(x + i, y + j, bg);
1417 else
1418 writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y, bg);
1419 }
1420 }
1421 }
1422 if (bg != color) { // If opaque, draw vertical line for last column
1423 if (size_x == 1 && size_y == 1)
1424 writeFastVLine(x + 5, y, 8, bg);
1425 else
1426 writeFillRect(x + 5 * size_x, y, size_x, 8 * size_y, bg);
1427 }
1428 endWrite();
1429
1430 } else { // Custom font
1431
1432 // Character is assumed previously filtered by write() to eliminate
1433 // newlines, returns, non-printable characters, etc. Calling
1434 // drawChar() directly with 'bad' characters of font may cause mayhem!
1435
1436 c -= (uint8_t)pgm_read_byte(&gfxFont->first);
1437 GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c);
1438 uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont);
1439
1440 uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
1441 uint8_t w = pgm_read_byte(&glyph->width), h = pgm_read_byte(&glyph->height);
1442 int8_t xo = pgm_read_byte(&glyph->xOffset),
1443 yo = pgm_read_byte(&glyph->yOffset);
1444 uint8_t xx, yy, bits = 0, bit = 0;
1445 int16_t xo16 = 0, yo16 = 0;
1446
1447 if (size_x > 1 || size_y > 1) {
1448 xo16 = xo;
1449 yo16 = yo;
1450 }
1451
1452 // Todo: Add character clipping here
1453
1454 // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS.
1455 // THIS IS ON PURPOSE AND BY DESIGN. The background color feature
1456 // has typically been used with the 'classic' font to overwrite old
1457 // screen contents with new data. This ONLY works because the
1458 // characters are a uniform size; it's not a sensible thing to do with
1459 // proportionally-spaced fonts with glyphs of varying sizes (and that
1460 // may overlap). To replace previously-drawn text when using a custom
1461 // font, use the getTextBounds() function to determine the smallest
1462 // rectangle encompassing a string, erase the area with fillRect(),
1463 // then draw new text. This WILL infortunately 'blink' the text, but
1464 // is unavoidable. Drawing 'background' pixels will NOT fix this,
1465 // only creates a new set of problems. Have an idea to work around
1466 // this (a canvas object type for MCUs that can afford the RAM and
1467 // displays supporting setAddrWindow() and pushColors()), but haven't
1468 // implemented this yet.
1469
1470 startWrite();
1471 for (yy = 0; yy < h; yy++) {
1472 for (xx = 0; xx < w; xx++) {
1473 if (!(bit++ & 7)) {
1474 bits = pgm_read_byte(&bitmap[bo++]);
1475 }
1476 if (bits & 0x80) {
1477 if (size_x == 1 && size_y == 1) {
1478 writePixel(x + xo + xx, y + yo + yy, color);
1479 } else {
1480 writeFillRect(x + (xo16 + xx) * size_x, y + (yo16 + yy) * size_y,
1481 size_x, size_y, color);
1482 }
1483 }
1484 bits <<= 1;
1485 }
1486 }
1487 endWrite();
1488
1489 } // End classic vs custom font
1490}
1491/**************************************************************************/
1496/**************************************************************************/
1497size_t Adafruit_GFX::write(uint8_t c) {
1498 if (!gfxFont) { // 'Classic' built-in font
1499
1500 if (c == '\n') { // Newline?
1501 cursor_x = 0; // Reset x to zero,
1502 cursor_y += textsize_y * 8; // advance y one line
1503 } else if (c != '\r') { // Ignore carriage returns
1504 if (wrap && ((cursor_x + textsize_x * 6) > _width)) { // Off right?
1505 cursor_x = 0; // Reset x to zero,
1506 cursor_y += textsize_y * 8; // advance y one line
1507 }
1509 textsize_y);
1510 cursor_x += textsize_x * 6; // Advance x one char
1511 }
1512
1513 } else { // Custom font
1514
1515 if (c == '\n') {
1516 cursor_x = 0;
1517 cursor_y +=
1518 (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
1519 } else if (c != '\r') {
1520 uint8_t first = pgm_read_byte(&gfxFont->first);
1521 if ((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) {
1522 GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
1523 uint8_t w = pgm_read_byte(&glyph->width),
1524 h = pgm_read_byte(&glyph->height);
1525 if ((w > 0) && (h > 0)) { // Is there an associated bitmap?
1526 int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic
1527 if (wrap && ((cursor_x + textsize_x * (xo + w)) > _width)) {
1528 cursor_x = 0;
1529 cursor_y += (int16_t)textsize_y *
1530 (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
1531 }
1533 textsize_y);
1534 }
1535 cursor_x +=
1536 (uint8_t)pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize_x;
1537 }
1538 }
1539 }
1540 return 1;
1541}
1542
1543/**************************************************************************/
1549/**************************************************************************/
1550void Adafruit_GFX::setTextSize(uint8_t s) { setTextSize(s, s); }
1551
1552/**************************************************************************/
1559/**************************************************************************/
1560void Adafruit_GFX::setTextSize(uint8_t s_x, uint8_t s_y) {
1561 textsize_x = (s_x > 0) ? s_x : 1;
1562 textsize_y = (s_y > 0) ? s_y : 1;
1563}
1564
1565/**************************************************************************/
1570/**************************************************************************/
1572 rotation = (x & 3);
1573 switch (rotation) {
1574 case 0:
1575 case 2:
1576 _width = WIDTH;
1577 _height = HEIGHT;
1578 break;
1579 case 1:
1580 case 3:
1581 _width = HEIGHT;
1582 _height = WIDTH;
1583 break;
1584 }
1585}
1586
1587/**************************************************************************/
1592/**************************************************************************/
1593void Adafruit_GFX::setFont(const GFXfont *f) {
1594 if (f) { // Font struct pointer passed in?
1595 if (!gfxFont) { // And no current font struct?
1596 // Switching from classic to new font behavior.
1597 // Move cursor pos down 6 pixels so it's on baseline.
1598 cursor_y += 6;
1599 }
1600 } else if (gfxFont) { // NULL passed. Current font struct defined?
1601 // Switching from new to classic font behavior.
1602 // Move cursor pos up 6 pixels so it's at top-left of char.
1603 cursor_y -= 6;
1604 }
1605 gfxFont = (GFXfont *)f;
1606}
1607
1608/**************************************************************************/
1625/**************************************************************************/
1626void Adafruit_GFX::charBounds(unsigned char c, int16_t *x, int16_t *y,
1627 int16_t *minx, int16_t *miny, int16_t *maxx,
1628 int16_t *maxy) {
1629
1630 if (gfxFont) {
1631
1632 if (c == '\n') { // Newline?
1633 *x = 0; // Reset x to zero, advance y by one line
1634 *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
1635 } else if (c != '\r') { // Not a carriage return; is normal char
1636 uint8_t first = pgm_read_byte(&gfxFont->first),
1637 last = pgm_read_byte(&gfxFont->last);
1638 if ((c >= first) && (c <= last)) { // Char present in this font?
1639 GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first);
1640 uint8_t gw = pgm_read_byte(&glyph->width),
1641 gh = pgm_read_byte(&glyph->height),
1642 xa = pgm_read_byte(&glyph->xAdvance);
1643 int8_t xo = pgm_read_byte(&glyph->xOffset),
1644 yo = pgm_read_byte(&glyph->yOffset);
1645 if (wrap && ((*x + (((int16_t)xo + gw) * textsize_x)) > _width)) {
1646 *x = 0; // Reset x to zero, advance y by one line
1647 *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
1648 }
1649 int16_t tsx = (int16_t)textsize_x, tsy = (int16_t)textsize_y,
1650 x1 = *x + xo * tsx, y1 = *y + yo * tsy, x2 = x1 + gw * tsx - 1,
1651 y2 = y1 + gh * tsy - 1;
1652 if (x1 < *minx)
1653 *minx = x1;
1654 if (y1 < *miny)
1655 *miny = y1;
1656 if (x2 > *maxx)
1657 *maxx = x2;
1658 if (y2 > *maxy)
1659 *maxy = y2;
1660 *x += xa * tsx;
1661 }
1662 }
1663
1664 } else { // Default font
1665
1666 if (c == '\n') { // Newline?
1667 *x = 0; // Reset x to zero,
1668 *y += textsize_y * 8; // advance y one line
1669 // min/max x/y unchaged -- that waits for next 'normal' character
1670 } else if (c != '\r') { // Normal char; ignore carriage returns
1671 if (wrap && ((*x + textsize_x * 6) > _width)) { // Off right?
1672 *x = 0; // Reset x to zero,
1673 *y += textsize_y * 8; // advance y one line
1674 }
1675 int x2 = *x + textsize_x * 6 - 1, // Lower-right pixel of char
1676 y2 = *y + textsize_y * 8 - 1;
1677 if (x2 > *maxx)
1678 *maxx = x2; // Track max x, y
1679 if (y2 > *maxy)
1680 *maxy = y2;
1681 if (*x < *minx)
1682 *minx = *x; // Track min x, y
1683 if (*y < *miny)
1684 *miny = *y;
1685 *x += textsize_x * 6; // Advance x one char
1686 }
1687 }
1688}
1689
1690/**************************************************************************/
1702/**************************************************************************/
1703void Adafruit_GFX::getTextBounds(const char *str, int16_t x, int16_t y,
1704 int16_t *x1, int16_t *y1, uint16_t *w,
1705 uint16_t *h) {
1706
1707 uint8_t c; // Current character
1708 int16_t minx = 0x7FFF, miny = 0x7FFF, maxx = -1, maxy = -1; // Bound rect
1709 // Bound rect is intentionally initialized inverted, so 1st char sets it
1710
1711 *x1 = x; // Initial position is value passed in
1712 *y1 = y;
1713 *w = *h = 0; // Initial size is zero
1714
1715 while ((c = *str++)) {
1716 // charBounds() modifies x/y to advance for each character,
1717 // and min/max x/y are updated to incrementally build bounding rect.
1718 charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
1719 }
1720
1721 if (maxx >= minx) { // If legit string bounds were found...
1722 *x1 = minx; // Update x1 to least X coord,
1723 *w = maxx - minx + 1; // And w to bound rect width
1724 }
1725 if (maxy >= miny) { // Same for height
1726 *y1 = miny;
1727 *h = maxy - miny + 1;
1728 }
1729}
1730
1731/**************************************************************************/
1743/**************************************************************************/
1744void Adafruit_GFX::getTextBounds(const String &str, int16_t x, int16_t y,
1745 int16_t *x1, int16_t *y1, uint16_t *w,
1746 uint16_t *h) {
1747 if (str.length() != 0) {
1748 getTextBounds(const_cast<char *>(str.c_str()), x, y, x1, y1, w, h);
1749 }
1750}
1751
1752/**************************************************************************/
1764/**************************************************************************/
1765void Adafruit_GFX::getTextBounds(const __FlashStringHelper *str, int16_t x,
1766 int16_t y, int16_t *x1, int16_t *y1,
1767 uint16_t *w, uint16_t *h) {
1768 uint8_t *s = (uint8_t *)str, c;
1769
1770 *x1 = x;
1771 *y1 = y;
1772 *w = *h = 0;
1773
1774 int16_t minx = _width, miny = _height, maxx = -1, maxy = -1;
1775
1776 while ((c = pgm_read_byte(s++)))
1777 charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy);
1778
1779 if (maxx >= minx) {
1780 *x1 = minx;
1781 *w = maxx - minx + 1;
1782 }
1783 if (maxy >= miny) {
1784 *y1 = miny;
1785 *h = maxy - miny + 1;
1786 }
1787}
1788
1789/**************************************************************************/
1794/**************************************************************************/
1796 // Do nothing, must be subclassed if supported by hardware
1797 (void)i; // disable -Wunused-parameter warning
1798}
1799
1800/***************************************************************************/
1801
1802/**************************************************************************/
1806/**************************************************************************/
1808
1809/**************************************************************************/
1823/**************************************************************************/
1824// Classic initButton() function: pass center & size
1825void Adafruit_GFX_Button::initButton(Adafruit_GFX *gfx, int16_t x, int16_t y,
1826 uint16_t w, uint16_t h, uint16_t outline,
1827 uint16_t fill, uint16_t textcolor,
1828 char *label, uint8_t textsize) {
1829 // Tweak arguments and pass to the newer initButtonUL() function...
1830 initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill, textcolor,
1831 label, textsize);
1832}
1833
1834/**************************************************************************/
1849/**************************************************************************/
1850// Classic initButton() function: pass center & size
1851void Adafruit_GFX_Button::initButton(Adafruit_GFX *gfx, int16_t x, int16_t y,
1852 uint16_t w, uint16_t h, uint16_t outline,
1853 uint16_t fill, uint16_t textcolor,
1854 char *label, uint8_t textsize_x,
1855 uint8_t textsize_y) {
1856 // Tweak arguments and pass to the newer initButtonUL() function...
1857 initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill, textcolor,
1858 label, textsize_x, textsize_y);
1859}
1860
1861/**************************************************************************/
1876/**************************************************************************/
1878 int16_t y1, uint16_t w, uint16_t h,
1879 uint16_t outline, uint16_t fill,
1880 uint16_t textcolor, char *label,
1881 uint8_t textsize) {
1882 initButtonUL(gfx, x1, y1, w, h, outline, fill, textcolor, label, textsize,
1883 textsize);
1884}
1885
1886/**************************************************************************/
1902/**************************************************************************/
1904 int16_t y1, uint16_t w, uint16_t h,
1905 uint16_t outline, uint16_t fill,
1906 uint16_t textcolor, char *label,
1907 uint8_t textsize_x, uint8_t textsize_y) {
1908 _x1 = x1;
1909 _y1 = y1;
1910 _w = w;
1911 _h = h;
1912 _outlinecolor = outline;
1913 _fillcolor = fill;
1914 _textcolor = textcolor;
1915 _textsize_x = textsize_x;
1916 _textsize_y = textsize_y;
1917 _gfx = gfx;
1918 strncpy(_label, label, 9);
1919 _label[9] = 0; // strncpy does not place a null at the end.
1920 // When 'label' is >9 characters, _label is not terminated.
1921}
1922
1923/**************************************************************************/
1929/**************************************************************************/
1931 uint16_t fill, outline, text;
1932
1933 if (!inverted) {
1934 fill = _fillcolor;
1935 outline = _outlinecolor;
1936 text = _textcolor;
1937 } else {
1938 fill = _textcolor;
1939 outline = _outlinecolor;
1940 text = _fillcolor;
1941 }
1942
1943 uint8_t r = min(_w, _h) / 4; // Corner radius
1944 _gfx->fillRoundRect(_x1, _y1, _w, _h, r, fill);
1945 _gfx->drawRoundRect(_x1, _y1, _w, _h, r, outline);
1946
1947 _gfx->setCursor(_x1 + (_w / 2) - (strlen(_label) * 3 * _textsize_x),
1948 _y1 + (_h / 2) - (4 * _textsize_y));
1949 _gfx->setTextColor(text);
1950 _gfx->setTextSize(_textsize_x, _textsize_y);
1951 _gfx->print(_label);
1952}
1953
1954/**************************************************************************/
1962/**************************************************************************/
1963bool Adafruit_GFX_Button::contains(int16_t x, int16_t y) {
1964 return ((x >= _x1) && (x < (int16_t)(_x1 + _w)) && (y >= _y1) &&
1965 (y < (int16_t)(_y1 + _h)));
1966}
1967
1968/**************************************************************************/
1973/**************************************************************************/
1974bool Adafruit_GFX_Button::justPressed() { return (currstate && !laststate); }
1975
1976/**************************************************************************/
1981/**************************************************************************/
1982bool Adafruit_GFX_Button::justReleased() { return (!currstate && laststate); }
1983
1984// -------------------------------------------------------------------------
1985
1986// GFXcanvas1, GFXcanvas8 and GFXcanvas16 (currently a WIP, don't get too
1987// comfy with the implementation) provide 1-, 8- and 16-bit offscreen
1988// canvases, the address of which can be passed to drawBitmap() or
1989// pushColors() (the latter appears only in a couple of GFX-subclassed TFT
1990// libraries at this time). This is here mostly to help with the recently-
1991// added proportionally-spaced fonts; adds a way to refresh a section of the
1992// screen without a massive flickering clear-and-redraw...but maybe you'll
1993// find other uses too. VERY RAM-intensive, since the buffer is in MCU
1994// memory and not the display driver...GXFcanvas1 might be minimally useful
1995// on an Uno-class board, but this and the others are much more likely to
1996// require at least a Mega or various recent ARM-type boards (recommended,
1997// as the text+bitmap draw can be pokey). GFXcanvas1 requires 1 bit per
1998// pixel (rounded up to nearest byte per scanline), GFXcanvas8 is 1 byte
1999// per pixel (no scanline pad), and GFXcanvas16 uses 2 bytes per pixel (no
2000// scanline pad).
2001// NOT EXTENSIVELY TESTED YET. MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND.
2002
2003#ifdef __AVR__
2004// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
2005const uint8_t PROGMEM GFXcanvas1::GFXsetBit[] = {0x80, 0x40, 0x20, 0x10,
2006 0x08, 0x04, 0x02, 0x01};
2007const uint8_t PROGMEM GFXcanvas1::GFXclrBit[] = {0x7F, 0xBF, 0xDF, 0xEF,
2008 0xF7, 0xFB, 0xFD, 0xFE};
2009#endif
2010
2011/**************************************************************************/
2021/**************************************************************************/
2022GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h, bool allocate_buffer)
2023 : Adafruit_GFX(w, h), buffer_owned(allocate_buffer) {
2024 if (allocate_buffer) {
2025 uint32_t bytes = ((w + 7) / 8) * h;
2026 if ((buffer = (uint8_t *)malloc(bytes))) {
2027 memset(buffer, 0, bytes);
2028 }
2029 } else {
2030 buffer = nullptr;
2031 }
2032}
2033
2034/**************************************************************************/
2038/**************************************************************************/
2040 if (buffer && buffer_owned)
2041 free(buffer);
2042}
2043
2044/**************************************************************************/
2051/**************************************************************************/
2052void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) {
2053 if (buffer) {
2054 if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
2055 return;
2056
2057 int16_t t;
2058 switch (rotation) {
2059 case 1:
2060 t = x;
2061 x = WIDTH - 1 - y;
2062 y = t;
2063 break;
2064 case 2:
2065 x = WIDTH - 1 - x;
2066 y = HEIGHT - 1 - y;
2067 break;
2068 case 3:
2069 t = x;
2070 x = y;
2071 y = HEIGHT - 1 - t;
2072 break;
2073 }
2074
2075 uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
2076#ifdef __AVR__
2077 if (color)
2078 *ptr |= pgm_read_byte(&GFXsetBit[x & 7]);
2079 else
2080 *ptr &= pgm_read_byte(&GFXclrBit[x & 7]);
2081#else
2082 if (color)
2083 *ptr |= 0x80 >> (x & 7);
2084 else
2085 *ptr &= ~(0x80 >> (x & 7));
2086#endif
2087 }
2088}
2089
2090/**********************************************************************/
2097bool GFXcanvas1::getPixel(int16_t x, int16_t y) const {
2098 int16_t t;
2099 switch (rotation) {
2100 case 1:
2101 t = x;
2102 x = WIDTH - 1 - y;
2103 y = t;
2104 break;
2105 case 2:
2106 x = WIDTH - 1 - x;
2107 y = HEIGHT - 1 - y;
2108 break;
2109 case 3:
2110 t = x;
2111 x = y;
2112 y = HEIGHT - 1 - t;
2113 break;
2114 }
2115 return getRawPixel(x, y);
2116}
2117
2118/**********************************************************************/
2127bool GFXcanvas1::getRawPixel(int16_t x, int16_t y) const {
2128 if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
2129 return 0;
2130 if (buffer) {
2131 uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
2132
2133#ifdef __AVR__
2134 return ((*ptr) & pgm_read_byte(&GFXsetBit[x & 7])) != 0;
2135#else
2136 return ((*ptr) & (0x80 >> (x & 7))) != 0;
2137#endif
2138 }
2139 return 0;
2140}
2141
2142/**************************************************************************/
2147/**************************************************************************/
2148void GFXcanvas1::fillScreen(uint16_t color) {
2149 if (buffer) {
2150 uint32_t bytes = ((WIDTH + 7) / 8) * HEIGHT;
2151 memset(buffer, color ? 0xFF : 0x00, bytes);
2152 }
2153}
2154
2155/**************************************************************************/
2163/**************************************************************************/
2164void GFXcanvas1::drawFastVLine(int16_t x, int16_t y, int16_t h,
2165 uint16_t color) {
2166
2167 if (h < 0) { // Convert negative heights to positive equivalent
2168 h *= -1;
2169 y -= h - 1;
2170 if (y < 0) {
2171 h += y;
2172 y = 0;
2173 }
2174 }
2175
2176 // Edge rejection (no-draw if totally off canvas)
2177 if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) {
2178 return;
2179 }
2180
2181 if (y < 0) { // Clip top
2182 h += y;
2183 y = 0;
2184 }
2185 if (y + h > height()) { // Clip bottom
2186 h = height() - y;
2187 }
2188
2189 if (getRotation() == 0) {
2190 drawFastRawVLine(x, y, h, color);
2191 } else if (getRotation() == 1) {
2192 int16_t t = x;
2193 x = WIDTH - 1 - y;
2194 y = t;
2195 x -= h - 1;
2196 drawFastRawHLine(x, y, h, color);
2197 } else if (getRotation() == 2) {
2198 x = WIDTH - 1 - x;
2199 y = HEIGHT - 1 - y;
2200
2201 y -= h - 1;
2202 drawFastRawVLine(x, y, h, color);
2203 } else if (getRotation() == 3) {
2204 int16_t t = x;
2205 x = y;
2206 y = HEIGHT - 1 - t;
2207 drawFastRawHLine(x, y, h, color);
2208 }
2209}
2210
2211/**************************************************************************/
2219/**************************************************************************/
2220void GFXcanvas1::drawFastHLine(int16_t x, int16_t y, int16_t w,
2221 uint16_t color) {
2222 if (w < 0) { // Convert negative widths to positive equivalent
2223 w *= -1;
2224 x -= w - 1;
2225 if (x < 0) {
2226 w += x;
2227 x = 0;
2228 }
2229 }
2230
2231 // Edge rejection (no-draw if totally off canvas)
2232 if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) {
2233 return;
2234 }
2235
2236 if (x < 0) { // Clip left
2237 w += x;
2238 x = 0;
2239 }
2240 if (x + w >= width()) { // Clip right
2241 w = width() - x;
2242 }
2243
2244 if (getRotation() == 0) {
2245 drawFastRawHLine(x, y, w, color);
2246 } else if (getRotation() == 1) {
2247 int16_t t = x;
2248 x = WIDTH - 1 - y;
2249 y = t;
2250 drawFastRawVLine(x, y, w, color);
2251 } else if (getRotation() == 2) {
2252 x = WIDTH - 1 - x;
2253 y = HEIGHT - 1 - y;
2254
2255 x -= w - 1;
2256 drawFastRawHLine(x, y, w, color);
2257 } else if (getRotation() == 3) {
2258 int16_t t = x;
2259 x = y;
2260 y = HEIGHT - 1 - t;
2261 y -= w - 1;
2262 drawFastRawVLine(x, y, w, color);
2263 }
2264}
2265
2266/**************************************************************************/
2274/**************************************************************************/
2275void GFXcanvas1::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
2276 uint16_t color) {
2277 // x & y already in raw (rotation 0) coordinates, no need to transform.
2278 int16_t row_bytes = ((WIDTH + 7) / 8);
2279 uint8_t *ptr = &buffer[(x / 8) + y * row_bytes];
2280
2281 if (color > 0) {
2282#ifdef __AVR__
2283 uint8_t bit_mask = pgm_read_byte(&GFXsetBit[x & 7]);
2284#else
2285 uint8_t bit_mask = (0x80 >> (x & 7));
2286#endif
2287 for (int16_t i = 0; i < h; i++) {
2288 *ptr |= bit_mask;
2289 ptr += row_bytes;
2290 }
2291 } else {
2292#ifdef __AVR__
2293 uint8_t bit_mask = pgm_read_byte(&GFXclrBit[x & 7]);
2294#else
2295 uint8_t bit_mask = ~(0x80 >> (x & 7));
2296#endif
2297 for (int16_t i = 0; i < h; i++) {
2298 *ptr &= bit_mask;
2299 ptr += row_bytes;
2300 }
2301 }
2302}
2303
2304/**************************************************************************/
2312/**************************************************************************/
2313void GFXcanvas1::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
2314 uint16_t color) {
2315 // x & y already in raw (rotation 0) coordinates, no need to transform.
2316 int16_t rowBytes = ((WIDTH + 7) / 8);
2317 uint8_t *ptr = &buffer[(x / 8) + y * rowBytes];
2318 size_t remainingWidthBits = w;
2319
2320 // check to see if first byte needs to be partially filled
2321 if ((x & 7) > 0) {
2322 // create bit mask for first byte
2323 uint8_t startByteBitMask = 0x00;
2324 for (int8_t i = (x & 7); ((i < 8) && (remainingWidthBits > 0)); i++) {
2325#ifdef __AVR__
2326 startByteBitMask |= pgm_read_byte(&GFXsetBit[i]);
2327#else
2328 startByteBitMask |= (0x80 >> i);
2329#endif
2330 remainingWidthBits--;
2331 }
2332 if (color > 0) {
2333 *ptr |= startByteBitMask;
2334 } else {
2335 *ptr &= ~startByteBitMask;
2336 }
2337
2338 ptr++;
2339 }
2340
2341 // do the next remainingWidthBits bits
2342 if (remainingWidthBits > 0) {
2343 size_t remainingWholeBytes = remainingWidthBits / 8;
2344 size_t lastByteBits = remainingWidthBits % 8;
2345 uint8_t wholeByteColor = color > 0 ? 0xFF : 0x00;
2346
2347 memset(ptr, wholeByteColor, remainingWholeBytes);
2348
2349 if (lastByteBits > 0) {
2350 uint8_t lastByteBitMask = 0x00;
2351 for (size_t i = 0; i < lastByteBits; i++) {
2352#ifdef __AVR__
2353 lastByteBitMask |= pgm_read_byte(&GFXsetBit[i]);
2354#else
2355 lastByteBitMask |= (0x80 >> i);
2356#endif
2357 }
2358 ptr += remainingWholeBytes;
2359
2360 if (color > 0) {
2361 *ptr |= lastByteBitMask;
2362 } else {
2363 *ptr &= ~lastByteBitMask;
2364 }
2365 }
2366 }
2367}
2368
2369/**************************************************************************/
2379/**************************************************************************/
2380GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h, bool allocate_buffer)
2381 : Adafruit_GFX(w, h), buffer_owned(allocate_buffer) {
2382 if (allocate_buffer) {
2383 uint32_t bytes = w * h;
2384 if ((buffer = (uint8_t *)malloc(bytes))) {
2385 memset(buffer, 0, bytes);
2386 }
2387 } else
2388 buffer = nullptr;
2389}
2390
2391/**************************************************************************/
2395/**************************************************************************/
2397 if (buffer && buffer_owned)
2398 free(buffer);
2399}
2400
2401/**************************************************************************/
2408/**************************************************************************/
2409void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) {
2410 if (buffer) {
2411 if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
2412 return;
2413
2414 int16_t t;
2415 switch (rotation) {
2416 case 1:
2417 t = x;
2418 x = WIDTH - 1 - y;
2419 y = t;
2420 break;
2421 case 2:
2422 x = WIDTH - 1 - x;
2423 y = HEIGHT - 1 - y;
2424 break;
2425 case 3:
2426 t = x;
2427 x = y;
2428 y = HEIGHT - 1 - t;
2429 break;
2430 }
2431
2432 buffer[x + y * WIDTH] = color;
2433 }
2434}
2435
2436/**********************************************************************/
2443/**********************************************************************/
2444uint8_t GFXcanvas8::getPixel(int16_t x, int16_t y) const {
2445 int16_t t;
2446 switch (rotation) {
2447 case 1:
2448 t = x;
2449 x = WIDTH - 1 - y;
2450 y = t;
2451 break;
2452 case 2:
2453 x = WIDTH - 1 - x;
2454 y = HEIGHT - 1 - y;
2455 break;
2456 case 3:
2457 t = x;
2458 x = y;
2459 y = HEIGHT - 1 - t;
2460 break;
2461 }
2462 return getRawPixel(x, y);
2463}
2464
2465/**********************************************************************/
2474/**********************************************************************/
2475uint8_t GFXcanvas8::getRawPixel(int16_t x, int16_t y) const {
2476 if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
2477 return 0;
2478 if (buffer) {
2479 return buffer[x + y * WIDTH];
2480 }
2481 return 0;
2482}
2483
2484/**************************************************************************/
2489/**************************************************************************/
2490void GFXcanvas8::fillScreen(uint16_t color) {
2491 if (buffer) {
2492 memset(buffer, color, WIDTH * HEIGHT);
2493 }
2494}
2495
2496/**************************************************************************/
2505/**************************************************************************/
2506void GFXcanvas8::drawFastVLine(int16_t x, int16_t y, int16_t h,
2507 uint16_t color) {
2508 if (h < 0) { // Convert negative heights to positive equivalent
2509 h *= -1;
2510 y -= h - 1;
2511 if (y < 0) {
2512 h += y;
2513 y = 0;
2514 }
2515 }
2516
2517 // Edge rejection (no-draw if totally off canvas)
2518 if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) {
2519 return;
2520 }
2521
2522 if (y < 0) { // Clip top
2523 h += y;
2524 y = 0;
2525 }
2526 if (y + h > height()) { // Clip bottom
2527 h = height() - y;
2528 }
2529
2530 if (getRotation() == 0) {
2531 drawFastRawVLine(x, y, h, color);
2532 } else if (getRotation() == 1) {
2533 int16_t t = x;
2534 x = WIDTH - 1 - y;
2535 y = t;
2536 x -= h - 1;
2537 drawFastRawHLine(x, y, h, color);
2538 } else if (getRotation() == 2) {
2539 x = WIDTH - 1 - x;
2540 y = HEIGHT - 1 - y;
2541
2542 y -= h - 1;
2543 drawFastRawVLine(x, y, h, color);
2544 } else if (getRotation() == 3) {
2545 int16_t t = x;
2546 x = y;
2547 y = HEIGHT - 1 - t;
2548 drawFastRawHLine(x, y, h, color);
2549 }
2550}
2551
2552/**************************************************************************/
2561/**************************************************************************/
2562void GFXcanvas8::drawFastHLine(int16_t x, int16_t y, int16_t w,
2563 uint16_t color) {
2564
2565 if (w < 0) { // Convert negative widths to positive equivalent
2566 w *= -1;
2567 x -= w - 1;
2568 if (x < 0) {
2569 w += x;
2570 x = 0;
2571 }
2572 }
2573
2574 // Edge rejection (no-draw if totally off canvas)
2575 if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) {
2576 return;
2577 }
2578
2579 if (x < 0) { // Clip left
2580 w += x;
2581 x = 0;
2582 }
2583 if (x + w >= width()) { // Clip right
2584 w = width() - x;
2585 }
2586
2587 if (getRotation() == 0) {
2588 drawFastRawHLine(x, y, w, color);
2589 } else if (getRotation() == 1) {
2590 int16_t t = x;
2591 x = WIDTH - 1 - y;
2592 y = t;
2593 drawFastRawVLine(x, y, w, color);
2594 } else if (getRotation() == 2) {
2595 x = WIDTH - 1 - x;
2596 y = HEIGHT - 1 - y;
2597
2598 x -= w - 1;
2599 drawFastRawHLine(x, y, w, color);
2600 } else if (getRotation() == 3) {
2601 int16_t t = x;
2602 x = y;
2603 y = HEIGHT - 1 - t;
2604 y -= w - 1;
2605 drawFastRawVLine(x, y, w, color);
2606 }
2607}
2608
2609/**************************************************************************/
2618/**************************************************************************/
2619void GFXcanvas8::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
2620 uint16_t color) {
2621 // x & y already in raw (rotation 0) coordinates, no need to transform.
2622 uint8_t *buffer_ptr = buffer + y * WIDTH + x;
2623 for (int16_t i = 0; i < h; i++) {
2624 (*buffer_ptr) = color;
2625 buffer_ptr += WIDTH;
2626 }
2627}
2628
2629/**************************************************************************/
2638/**************************************************************************/
2639void GFXcanvas8::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
2640 uint16_t color) {
2641 // x & y already in raw (rotation 0) coordinates, no need to transform.
2642 memset(buffer + y * WIDTH + x, color, w);
2643}
2644
2645/**************************************************************************/
2655/**************************************************************************/
2656GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h, bool allocate_buffer)
2657 : Adafruit_GFX(w, h), buffer_owned(allocate_buffer) {
2658 if (allocate_buffer) {
2659 uint32_t bytes = w * h * 2;
2660 if ((buffer = (uint16_t *)malloc(bytes))) {
2661 memset(buffer, 0, bytes);
2662 }
2663 } else {
2664 buffer = nullptr;
2665 }
2666}
2667
2668/**************************************************************************/
2672/**************************************************************************/
2674 if (buffer && buffer_owned)
2675 free(buffer);
2676}
2677
2678/**************************************************************************/
2685/**************************************************************************/
2686void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) {
2687 if (buffer) {
2688 if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height))
2689 return;
2690
2691 int16_t t;
2692 switch (rotation) {
2693 case 1:
2694 t = x;
2695 x = WIDTH - 1 - y;
2696 y = t;
2697 break;
2698 case 2:
2699 x = WIDTH - 1 - x;
2700 y = HEIGHT - 1 - y;
2701 break;
2702 case 3:
2703 t = x;
2704 x = y;
2705 y = HEIGHT - 1 - t;
2706 break;
2707 }
2708
2709 buffer[x + y * WIDTH] = color;
2710 }
2711}
2712
2713/**********************************************************************/
2720/**********************************************************************/
2721uint16_t GFXcanvas16::getPixel(int16_t x, int16_t y) const {
2722 int16_t t;
2723 switch (rotation) {
2724 case 1:
2725 t = x;
2726 x = WIDTH - 1 - y;
2727 y = t;
2728 break;
2729 case 2:
2730 x = WIDTH - 1 - x;
2731 y = HEIGHT - 1 - y;
2732 break;
2733 case 3:
2734 t = x;
2735 x = y;
2736 y = HEIGHT - 1 - t;
2737 break;
2738 }
2739 return getRawPixel(x, y);
2740}
2741
2742/**********************************************************************/
2751/**********************************************************************/
2752uint16_t GFXcanvas16::getRawPixel(int16_t x, int16_t y) const {
2753 if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT))
2754 return 0;
2755 if (buffer) {
2756 return buffer[x + y * WIDTH];
2757 }
2758 return 0;
2759}
2760
2761/**************************************************************************/
2766/**************************************************************************/
2767void GFXcanvas16::fillScreen(uint16_t color) {
2768 if (buffer) {
2769 uint8_t hi = color >> 8, lo = color & 0xFF;
2770 if (hi == lo) {
2771 memset(buffer, lo, WIDTH * HEIGHT * 2);
2772 } else {
2773 uint32_t i, pixels = WIDTH * HEIGHT;
2774 for (i = 0; i < pixels; i++)
2775 buffer[i] = color;
2776 }
2777 }
2778}
2779
2780/**************************************************************************/
2792/**************************************************************************/
2794 if (buffer) {
2795 uint32_t i, pixels = WIDTH * HEIGHT;
2796 for (i = 0; i < pixels; i++)
2797 buffer[i] = __builtin_bswap16(buffer[i]);
2798 }
2799}
2800
2801/**************************************************************************/
2809/**************************************************************************/
2810void GFXcanvas16::drawFastVLine(int16_t x, int16_t y, int16_t h,
2811 uint16_t color) {
2812 if (h < 0) { // Convert negative heights to positive equivalent
2813 h *= -1;
2814 y -= h - 1;
2815 if (y < 0) {
2816 h += y;
2817 y = 0;
2818 }
2819 }
2820
2821 // Edge rejection (no-draw if totally off canvas)
2822 if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) {
2823 return;
2824 }
2825
2826 if (y < 0) { // Clip top
2827 h += y;
2828 y = 0;
2829 }
2830 if (y + h > height()) { // Clip bottom
2831 h = height() - y;
2832 }
2833
2834 if (getRotation() == 0) {
2835 drawFastRawVLine(x, y, h, color);
2836 } else if (getRotation() == 1) {
2837 int16_t t = x;
2838 x = WIDTH - 1 - y;
2839 y = t;
2840 x -= h - 1;
2841 drawFastRawHLine(x, y, h, color);
2842 } else if (getRotation() == 2) {
2843 x = WIDTH - 1 - x;
2844 y = HEIGHT - 1 - y;
2845
2846 y -= h - 1;
2847 drawFastRawVLine(x, y, h, color);
2848 } else if (getRotation() == 3) {
2849 int16_t t = x;
2850 x = y;
2851 y = HEIGHT - 1 - t;
2852 drawFastRawHLine(x, y, h, color);
2853 }
2854}
2855
2856/**************************************************************************/
2864/**************************************************************************/
2865void GFXcanvas16::drawFastHLine(int16_t x, int16_t y, int16_t w,
2866 uint16_t color) {
2867 if (w < 0) { // Convert negative widths to positive equivalent
2868 w *= -1;
2869 x -= w - 1;
2870 if (x < 0) {
2871 w += x;
2872 x = 0;
2873 }
2874 }
2875
2876 // Edge rejection (no-draw if totally off canvas)
2877 if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) {
2878 return;
2879 }
2880
2881 if (x < 0) { // Clip left
2882 w += x;
2883 x = 0;
2884 }
2885 if (x + w >= width()) { // Clip right
2886 w = width() - x;
2887 }
2888
2889 if (getRotation() == 0) {
2890 drawFastRawHLine(x, y, w, color);
2891 } else if (getRotation() == 1) {
2892 int16_t t = x;
2893 x = WIDTH - 1 - y;
2894 y = t;
2895 drawFastRawVLine(x, y, w, color);
2896 } else if (getRotation() == 2) {
2897 x = WIDTH - 1 - x;
2898 y = HEIGHT - 1 - y;
2899
2900 x -= w - 1;
2901 drawFastRawHLine(x, y, w, color);
2902 } else if (getRotation() == 3) {
2903 int16_t t = x;
2904 x = y;
2905 y = HEIGHT - 1 - t;
2906 y -= w - 1;
2907 drawFastRawVLine(x, y, w, color);
2908 }
2909}
2910
2911/**************************************************************************/
2919/**************************************************************************/
2920void GFXcanvas16::drawFastRawVLine(int16_t x, int16_t y, int16_t h,
2921 uint16_t color) {
2922 // x & y already in raw (rotation 0) coordinates, no need to transform.
2923 uint16_t *buffer_ptr = buffer + y * WIDTH + x;
2924 for (int16_t i = 0; i < h; i++) {
2925 (*buffer_ptr) = color;
2926 buffer_ptr += WIDTH;
2927 }
2928}
2929
2930/**************************************************************************/
2938/**************************************************************************/
2939void GFXcanvas16::drawFastRawHLine(int16_t x, int16_t y, int16_t w,
2940 uint16_t color) {
2941 // x & y already in raw (rotation 0) coordinates, no need to transform.
2942 uint32_t buffer_index = y * WIDTH + x;
2943 for (uint32_t i = buffer_index; i < buffer_index + w; i++) {
2944 buffer[i] = color;
2945 }
2946}
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)
Definition Print.cpp:19
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