Linduino  1.3.0
Linear Technology Arduino-Compatible Demonstration Board
Adafruit_GFX.cpp
Go to the documentation of this file.
1 /*
2 This is the core graphics library for all our displays, providing a common
3 set of graphics primitives (points, lines, circles, etc.). It needs to be
4 paired with a hardware-specific library for each display device we carry
5 (to handle the lower-level functions).
6 
7 Adafruit invests time and resources providing this open source code, please
8 support Adafruit & open-source hardware by purchasing products from Adafruit!
9 
10 Copyright (c) 2013 Adafruit Industries. All rights reserved.
11 
12 Redistribution and use in source and binary forms, with or without
13 modification, 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 
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 POSSIBILITY OF SUCH DAMAGE.
32 */
33 
34 #ifdef __AVR__
35 #include <avr/pgmspace.h>
36 #elif defined(ESP8266)
37 #include <pgmspace.h>
38 #endif
39 #include "Adafruit_GFX.h"
40 #include "glcdfont.c"
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 
65 #ifndef min
66 #define min(a,b) (((a) < (b)) ? (a) : (b))
67 #endif
68 
69 #ifndef _swap_int16_t
70 #define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
71 #endif
72 
73 Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h):
74  WIDTH(w), HEIGHT(h)
75 {
76  _width = WIDTH;
77  _height = HEIGHT;
78  rotation = 0;
79  cursor_y = cursor_x = 0;
80  textsize = 1;
81  textcolor = textbgcolor = 0xFFFF;
82  wrap = true;
83  _cp437 = false;
84  gfxFont = NULL;
85 }
86 
87 // Draw a circle outline
88 void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r,
89  uint16_t color)
90 {
91  int16_t f = 1 - r;
92  int16_t ddF_x = 1;
93  int16_t ddF_y = -2 * r;
94  int16_t x = 0;
95  int16_t y = r;
96 
97  drawPixel(x0 , y0+r, color);
98  drawPixel(x0 , y0-r, color);
99  drawPixel(x0+r, y0 , color);
100  drawPixel(x0-r, y0 , color);
101 
102  while (x<y)
103  {
104  if (f >= 0)
105  {
106  y--;
107  ddF_y += 2;
108  f += ddF_y;
109  }
110  x++;
111  ddF_x += 2;
112  f += ddF_x;
113 
114  drawPixel(x0 + x, y0 + y, color);
115  drawPixel(x0 - x, y0 + y, color);
116  drawPixel(x0 + x, y0 - y, color);
117  drawPixel(x0 - x, y0 - y, color);
118  drawPixel(x0 + y, y0 + x, color);
119  drawPixel(x0 - y, y0 + x, color);
120  drawPixel(x0 + y, y0 - x, color);
121  drawPixel(x0 - y, y0 - x, color);
122  }
123 }
124 
125 void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0,
126  int16_t r, uint8_t cornername, uint16_t color)
127 {
128  int16_t f = 1 - r;
129  int16_t ddF_x = 1;
130  int16_t ddF_y = -2 * r;
131  int16_t x = 0;
132  int16_t y = r;
133 
134  while (x<y)
135  {
136  if (f >= 0)
137  {
138  y--;
139  ddF_y += 2;
140  f += ddF_y;
141  }
142  x++;
143  ddF_x += 2;
144  f += ddF_x;
145  if (cornername & 0x4)
146  {
147  drawPixel(x0 + x, y0 + y, color);
148  drawPixel(x0 + y, y0 + x, color);
149  }
150  if (cornername & 0x2)
151  {
152  drawPixel(x0 + x, y0 - y, color);
153  drawPixel(x0 + y, y0 - x, color);
154  }
155  if (cornername & 0x8)
156  {
157  drawPixel(x0 - y, y0 + x, color);
158  drawPixel(x0 - x, y0 + y, color);
159  }
160  if (cornername & 0x1)
161  {
162  drawPixel(x0 - y, y0 - x, color);
163  drawPixel(x0 - x, y0 - y, color);
164  }
165  }
166 }
167 
168 void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r,
169  uint16_t color)
170 {
171  drawFastVLine(x0, y0-r, 2*r+1, color);
172  fillCircleHelper(x0, y0, r, 3, 0, color);
173 }
174 
175 // Used to do circles and roundrects
176 void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
177  uint8_t cornername, int16_t delta, uint16_t color)
178 {
179 
180  int16_t f = 1 - r;
181  int16_t ddF_x = 1;
182  int16_t ddF_y = -2 * r;
183  int16_t x = 0;
184  int16_t y = r;
185 
186  while (x<y)
187  {
188  if (f >= 0)
189  {
190  y--;
191  ddF_y += 2;
192  f += ddF_y;
193  }
194  x++;
195  ddF_x += 2;
196  f += ddF_x;
197 
198  if (cornername & 0x1)
199  {
200  drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
201  drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
202  }
203  if (cornername & 0x2)
204  {
205  drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
206  drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
207  }
208  }
209 }
210 
211 // Bresenham's algorithm - thx wikpedia
212 void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
213  uint16_t color)
214 {
215  int16_t steep = abs(y1 - y0) > abs(x1 - x0);
216  if (steep)
217  {
218  _swap_int16_t(x0, y0);
219  _swap_int16_t(x1, y1);
220  }
221 
222  if (x0 > x1)
223  {
224  _swap_int16_t(x0, x1);
225  _swap_int16_t(y0, y1);
226  }
227 
228  int16_t dx, dy;
229  dx = x1 - x0;
230  dy = abs(y1 - y0);
231 
232  int16_t err = dx / 2;
233  int16_t ystep;
234 
235  if (y0 < y1)
236  {
237  ystep = 1;
238  }
239  else
240  {
241  ystep = -1;
242  }
243 
244  for (; x0<=x1; x0++)
245  {
246  if (steep)
247  {
248  drawPixel(y0, x0, color);
249  }
250  else
251  {
252  drawPixel(x0, y0, color);
253  }
254  err -= dy;
255  if (err < 0)
256  {
257  y0 += ystep;
258  err += dx;
259  }
260  }
261 }
262 
263 // Draw a rectangle
264 void Adafruit_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
265  uint16_t color)
266 {
267  drawFastHLine(x, y, w, color);
268  drawFastHLine(x, y+h-1, w, color);
269  drawFastVLine(x, y, h, color);
270  drawFastVLine(x+w-1, y, h, color);
271 }
272 
273 void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y,
274  int16_t h, uint16_t color)
275 {
276  // Update in subclasses if desired!
277  drawLine(x, y, x, y+h-1, color);
278 }
279 
280 void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y,
281  int16_t w, uint16_t color)
282 {
283  // Update in subclasses if desired!
284  drawLine(x, y, x+w-1, y, color);
285 }
286 
287 void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
288  uint16_t color)
289 {
290  // Update in subclasses if desired!
291  for (int16_t i=x; i<x+w; i++)
292  {
293  drawFastVLine(i, y, h, color);
294  }
295 }
296 
297 void Adafruit_GFX::fillScreen(uint16_t color)
298 {
299  fillRect(0, 0, _width, _height, color);
300 }
301 
302 // Draw a rounded rectangle
303 void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w,
304  int16_t h, int16_t r, uint16_t color)
305 {
306  // smarter version
307  drawFastHLine(x+r , y , w-2*r, color); // Top
308  drawFastHLine(x+r , y+h-1, w-2*r, color); // Bottom
309  drawFastVLine(x , y+r , h-2*r, color); // Left
310  drawFastVLine(x+w-1, y+r , h-2*r, color); // Right
311  // draw four corners
312  drawCircleHelper(x+r , y+r , r, 1, color);
313  drawCircleHelper(x+w-r-1, y+r , r, 2, color);
314  drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
315  drawCircleHelper(x+r , y+h-r-1, r, 8, color);
316 }
317 
318 // Fill a rounded rectangle
319 void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w,
320  int16_t h, int16_t r, uint16_t color)
321 {
322  // smarter version
323  fillRect(x+r, y, w-2*r, h, color);
324 
325  // draw four corners
326  fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
327  fillCircleHelper(x+r , y+r, r, 2, h-2*r-1, color);
328 }
329 
330 // Draw a triangle
331 void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0,
332  int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
333 {
334  drawLine(x0, y0, x1, y1, color);
335  drawLine(x1, y1, x2, y2, color);
336  drawLine(x2, y2, x0, y0, color);
337 }
338 
339 // Fill a triangle
340 void Adafruit_GFX::fillTriangle(int16_t x0, int16_t y0,
341  int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
342 {
343 
344  int16_t a, b, y, last;
345 
346  // Sort coordinates by Y order (y2 >= y1 >= y0)
347  if (y0 > y1)
348  {
349  _swap_int16_t(y0, y1);
350  _swap_int16_t(x0, x1);
351  }
352  if (y1 > y2)
353  {
354  _swap_int16_t(y2, y1);
355  _swap_int16_t(x2, x1);
356  }
357  if (y0 > y1)
358  {
359  _swap_int16_t(y0, y1);
360  _swap_int16_t(x0, x1);
361  }
362 
363  if (y0 == y2) // Handle awkward all-on-same-line case as its own thing
364  {
365  a = b = x0;
366  if (x1 < a) a = x1;
367  else if (x1 > b) b = x1;
368  if (x2 < a) a = x2;
369  else if (x2 > b) b = x2;
370  drawFastHLine(a, y0, b-a+1, color);
371  return;
372  }
373 
374  int16_t
375  dx01 = x1 - x0,
376  dy01 = y1 - y0,
377  dx02 = x2 - x0,
378  dy02 = y2 - y0,
379  dx12 = x2 - x1,
380  dy12 = y2 - y1;
381  int32_t
382  sa = 0,
383  sb = 0;
384 
385  // For upper part of triangle, find scanline crossings for segments
386  // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1
387  // is included here (and second loop will be skipped, avoiding a /0
388  // error there), otherwise scanline y1 is skipped here and handled
389  // in the second loop...which also avoids a /0 error here if y0=y1
390  // (flat-topped triangle).
391  if (y1 == y2) last = y1; // Include y1 scanline
392  else last = y1-1; // Skip it
393 
394  for (y=y0; y<=last; y++)
395  {
396  a = x0 + sa / dy01;
397  b = x0 + sb / dy02;
398  sa += dx01;
399  sb += dx02;
400  /* longhand:
401  a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
402  b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
403  */
404  if (a > b) _swap_int16_t(a,b);
405  drawFastHLine(a, y, b-a+1, color);
406  }
407 
408  // For lower part of triangle, find scanline crossings for segments
409  // 0-2 and 1-2. This loop is skipped if y1=y2.
410  sa = dx12 * (y - y1);
411  sb = dx02 * (y - y0);
412  for (; y<=y2; y++)
413  {
414  a = x1 + sa / dy12;
415  b = x0 + sb / dy02;
416  sa += dx12;
417  sb += dx02;
418  /* longhand:
419  a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
420  b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
421  */
422  if (a > b) _swap_int16_t(a,b);
423  drawFastHLine(a, y, b-a+1, color);
424  }
425 }
426 
427 // Draw a 1-bit image (bitmap) at the specified (x,y) position from the
428 // provided bitmap buffer (must be PROGMEM memory) using the specified
429 // foreground color (unset bits are transparent).
430 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
431  const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
432 {
433 
434  int16_t i, j, byteWidth = (w + 7) / 8;
435  uint8_t byte;
436 
437  for (j=0; j<h; j++)
438  {
439  for (i=0; i<w; i++)
440  {
441  if (i & 7) byte <<= 1;
442  else byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
443  if (byte & 0x80) drawPixel(x+i, y+j, color);
444  }
445  }
446 }
447 
448 // Draw a 1-bit image (bitmap) at the specified (x,y) position from the
449 // provided bitmap buffer (must be PROGMEM memory) using the specified
450 // foreground (for set bits) and background (for clear bits) colors.
451 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
452  const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg)
453 {
454 
455  int16_t i, j, byteWidth = (w + 7) / 8;
456  uint8_t byte;
457 
458  for (j=0; j<h; j++)
459  {
460  for (i=0; i<w; i++ )
461  {
462  if (i & 7) byte <<= 1;
463  else byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
464  if (byte & 0x80) drawPixel(x+i, y+j, color);
465  else drawPixel(x+i, y+j, bg);
466  }
467  }
468 }
469 
470 // drawBitmap() variant for RAM-resident (not PROGMEM) bitmaps.
471 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
472  uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
473 {
474 
475  int16_t i, j, byteWidth = (w + 7) / 8;
476  uint8_t byte;
477 
478  for (j=0; j<h; j++)
479  {
480  for (i=0; i<w; i++ )
481  {
482  if (i & 7) byte <<= 1;
483  else byte = bitmap[j * byteWidth + i / 8];
484  if (byte & 0x80) drawPixel(x+i, y+j, color);
485  }
486  }
487 }
488 
489 // drawBitmap() variant w/background for RAM-resident (not PROGMEM) bitmaps.
490 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
491  uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg)
492 {
493 
494  int16_t i, j, byteWidth = (w + 7) / 8;
495  uint8_t byte;
496 
497  for (j=0; j<h; j++)
498  {
499  for (i=0; i<w; i++ )
500  {
501  if (i & 7) byte <<= 1;
502  else byte = bitmap[j * byteWidth + i / 8];
503  if (byte & 0x80) drawPixel(x+i, y+j, color);
504  else drawPixel(x+i, y+j, bg);
505  }
506  }
507 }
508 
509 //Draw XBitMap Files (*.xbm), exported from GIMP,
510 //Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor.
511 //C Array can be directly used with this function
512 void Adafruit_GFX::drawXBitmap(int16_t x, int16_t y,
513  const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
514 {
515 
516  int16_t i, j, byteWidth = (w + 7) / 8;
517  uint8_t byte;
518 
519  for (j=0; j<h; j++)
520  {
521  for (i=0; i<w; i++ )
522  {
523  if (i & 7) byte >>= 1;
524  else byte = pgm_read_byte(bitmap + j * byteWidth + i / 8);
525  if (byte & 0x01) drawPixel(x+i, y+j, color);
526  }
527  }
528 }
529 
530 #if ARDUINO >= 100
531 size_t Adafruit_GFX::write(uint8_t c)
532 {
533 #else
534 void Adafruit_GFX::write(uint8_t c)
535 {
536 #endif
537 
538  if (!gfxFont) // 'Classic' built-in font
539  {
540 
541  if (c == '\n')
542  {
543  cursor_y += textsize*8;
544  cursor_x = 0;
545  }
546  else if (c == '\r')
547  {
548  // skip em
549  }
550  else
551  {
552  if (wrap && ((cursor_x + textsize * 6) >= _width)) // Heading off edge?
553  {
554  cursor_x = 0; // Reset x to zero
555  cursor_y += textsize * 8; // Advance y one line
556  }
558  cursor_x += textsize * 6;
559  }
560 
561  }
562  else // Custom font
563  {
564 
565  if (c == '\n')
566  {
567  cursor_x = 0;
568  cursor_y += (int16_t)textsize *
569  (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
570  }
571  else if (c != '\r')
572  {
573  uint8_t first = pgm_read_byte(&gfxFont->first);
574  if ((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last)))
575  {
576  uint8_t c2 = c - pgm_read_byte(&gfxFont->first);
577  GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c2]);
578  uint8_t w = pgm_read_byte(&glyph->width),
579  h = pgm_read_byte(&glyph->height);
580  if ((w > 0) && (h > 0)) // Is there an associated bitmap?
581  {
582  int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic
583  if (wrap && ((cursor_x + textsize * (xo + w)) >= _width))
584  {
585  // Drawing character would go off right edge; wrap to new line
586  cursor_x = 0;
587  cursor_y += (int16_t)textsize *
588  (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
589  }
591  }
592  cursor_x += pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize;
593  }
594  }
595 
596  }
597 #if ARDUINO >= 100
598  return 1;
599 #endif
600 }
601 
602 // Draw a character
603 void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
604  uint16_t color, uint16_t bg, uint8_t size)
605 {
606 
607  if (!gfxFont) // 'Classic' built-in font
608  {
609 
610  if ((x >= _width) || // Clip right
611  (y >= _height) || // Clip bottom
612  ((x + 6 * size - 1) < 0) || // Clip left
613  ((y + 8 * size - 1) < 0)) // Clip top
614  return;
615 
616  if (!_cp437 && (c >= 176)) c++; // Handle 'classic' charset behavior
617 
618  for (int8_t i=0; i<6; i++ )
619  {
620  uint8_t line;
621  if (i < 5) line = pgm_read_byte(font+(c*5)+i);
622  else line = 0x0;
623  for (int8_t j=0; j<8; j++, line >>= 1)
624  {
625  if (line & 0x1)
626  {
627  if (size == 1) drawPixel(x+i, y+j, color);
628  else fillRect(x+(i*size), y+(j*size), size, size, color);
629  }
630  else if (bg != color)
631  {
632  if (size == 1) drawPixel(x+i, y+j, bg);
633  else fillRect(x+i*size, y+j*size, size, size, bg);
634  }
635  }
636  }
637 
638  }
639  else // Custom font
640  {
641 
642  // Character is assumed previously filtered by write() to eliminate
643  // newlines, returns, non-printable characters, etc. Calling drawChar()
644  // directly with 'bad' characters of font may cause mayhem!
645 
646  c -= pgm_read_byte(&gfxFont->first);
647  GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
648  uint8_t *bitmap = (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);
649 
650  uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
651  uint8_t w = pgm_read_byte(&glyph->width),
652  h = pgm_read_byte(&glyph->height),
653  xa = pgm_read_byte(&glyph->xAdvance);
654  int8_t xo = pgm_read_byte(&glyph->xOffset),
655  yo = pgm_read_byte(&glyph->yOffset);
656  uint8_t xx, yy, bits, bit = 0;
657  int16_t xo16, yo16;
658 
659  if (size > 1)
660  {
661  xo16 = xo;
662  yo16 = yo;
663  }
664 
665  // Todo: Add character clipping here
666 
667  // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS.
668  // THIS IS ON PURPOSE AND BY DESIGN. The background color feature
669  // has typically been used with the 'classic' font to overwrite old
670  // screen contents with new data. This ONLY works because the
671  // characters are a uniform size; it's not a sensible thing to do with
672  // proportionally-spaced fonts with glyphs of varying sizes (and that
673  // may overlap). To replace previously-drawn text when using a custom
674  // font, use the getTextBounds() function to determine the smallest
675  // rectangle encompassing a string, erase the area with fillRect(),
676  // then draw new text. This WILL infortunately 'blink' the text, but
677  // is unavoidable. Drawing 'background' pixels will NOT fix this,
678  // only creates a new set of problems. Have an idea to work around
679  // this (a canvas object type for MCUs that can afford the RAM and
680  // displays supporting setAddrWindow() and pushColors()), but haven't
681  // implemented this yet.
682 
683  for (yy=0; yy<h; yy++)
684  {
685  for (xx=0; xx<w; xx++)
686  {
687  if (!(bit++ & 7))
688  {
689  bits = pgm_read_byte(&bitmap[bo++]);
690  }
691  if (bits & 0x80)
692  {
693  if (size == 1)
694  {
695  drawPixel(x+xo+xx, y+yo+yy, color);
696  }
697  else
698  {
699  fillRect(x+(xo16+xx)*size, y+(yo16+yy)*size, size, size, color);
700  }
701  }
702  bits <<= 1;
703  }
704  }
705 
706  } // End classic vs custom font
707 }
708 
709 void Adafruit_GFX::setCursor(int16_t x, int16_t y)
710 {
711  cursor_x = x;
712  cursor_y = y;
713 }
714 
715 int16_t Adafruit_GFX::getCursorX(void) const
716 {
717  return cursor_x;
718 }
719 
720 int16_t Adafruit_GFX::getCursorY(void) const
721 {
722  return cursor_y;
723 }
724 
726 {
727  textsize = (s > 0) ? s : 1;
728 }
729 
731 {
732  // For 'transparent' background, we'll set the bg
733  // to the same as fg instead of using a flag
734  textcolor = textbgcolor = c;
735 }
736 
737 void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b)
738 {
739  textcolor = c;
740  textbgcolor = b;
741 }
742 
744 {
745  wrap = w;
746 }
747 
748 uint8_t Adafruit_GFX::getRotation(void) const
749 {
750  return rotation;
751 }
752 
754 {
755  rotation = (x & 3);
756  switch (rotation)
757  {
758  case 0:
759  case 2:
760  _width = WIDTH;
761  _height = HEIGHT;
762  break;
763  case 1:
764  case 3:
765  _width = HEIGHT;
766  _height = WIDTH;
767  break;
768  }
769 }
770 
771 // Enable (or disable) Code Page 437-compatible charset.
772 // There was an error in glcdfont.c for the longest time -- one character
773 // (#176, the 'light shade' block) was missing -- this threw off the index
774 // of every character that followed it. But a TON of code has been written
775 // with the erroneous character indices. By default, the library uses the
776 // original 'wrong' behavior and old sketches will still work. Pass 'true'
777 // to this function to use correct CP437 character values in your code.
778 void Adafruit_GFX::cp437(boolean x)
779 {
780  _cp437 = x;
781 }
782 
784 {
785  if (f) // Font struct pointer passed in?
786  {
787  if (!gfxFont) // And no current font struct?
788  {
789  // Switching from classic to new font behavior.
790  // Move cursor pos down 6 pixels so it's on baseline.
791  cursor_y += 6;
792  }
793  }
794  else if (gfxFont) // NULL passed. Current font struct defined?
795  {
796  // Switching from new to classic font behavior.
797  // Move cursor pos up 6 pixels so it's at top-left of char.
798  cursor_y -= 6;
799  }
800  gfxFont = (GFXfont *)f;
801 }
802 
803 // Pass string and a cursor position, returns UL corner and W,H.
804 void Adafruit_GFX::getTextBounds(char *str, int16_t x, int16_t y,
805  int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
806 {
807  uint8_t c; // Current character
808 
809  *x1 = x;
810  *y1 = y;
811  *w = *h = 0;
812 
813  if (gfxFont)
814  {
815 
816  GFXglyph *glyph;
817  uint8_t first = pgm_read_byte(&gfxFont->first),
818  last = pgm_read_byte(&gfxFont->last),
819  gw, gh, xa;
820  int8_t xo, yo;
821  int16_t minx = _width, miny = _height, maxx = -1, maxy = -1,
822  gx1, gy1, gx2, gy2, ts = (int16_t)textsize,
823  ya = ts * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
824 
825  while ((c = *str++))
826  {
827  if (c != '\n') // Not a newline
828  {
829  if (c != '\r') // Not a carriage return, is normal char
830  {
831  if ((c >= first) && (c <= last)) // Char present in current font
832  {
833  c -= first;
834  glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
835  gw = pgm_read_byte(&glyph->width);
836  gh = pgm_read_byte(&glyph->height);
837  xa = pgm_read_byte(&glyph->xAdvance);
838  xo = pgm_read_byte(&glyph->xOffset);
839  yo = pgm_read_byte(&glyph->yOffset);
840  if (wrap && ((x + (((int16_t)xo + gw) * ts)) >= _width))
841  {
842  // Line wrap
843  x = 0; // Reset x to 0
844  y += ya; // Advance y by 1 line
845  }
846  gx1 = x + xo * ts;
847  gy1 = y + yo * ts;
848  gx2 = gx1 + gw * ts - 1;
849  gy2 = gy1 + gh * ts - 1;
850  if (gx1 < minx) minx = gx1;
851  if (gy1 < miny) miny = gy1;
852  if (gx2 > maxx) maxx = gx2;
853  if (gy2 > maxy) maxy = gy2;
854  x += xa * ts;
855  }
856  } // Carriage return = do nothing
857  }
858  else // Newline
859  {
860  x = 0; // Reset x
861  y += ya; // Advance y by 1 line
862  }
863  }
864  // End of string
865  *x1 = minx;
866  *y1 = miny;
867  if (maxx >= minx) *w = maxx - minx + 1;
868  if (maxy >= miny) *h = maxy - miny + 1;
869 
870  }
871  else // Default font
872  {
873 
874  uint16_t lineWidth = 0, maxWidth = 0; // Width of current, all lines
875 
876  while ((c = *str++))
877  {
878  if (c != '\n') // Not a newline
879  {
880  if (c != '\r') // Not a carriage return, is normal char
881  {
882  if (wrap && ((x + textsize * 6) >= _width))
883  {
884  x = 0; // Reset x to 0
885  y += textsize * 8; // Advance y by 1 line
886  if (lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line
887  lineWidth = textsize * 6; // First char on new line
888  }
889  else // No line wrap, just keep incrementing X
890  {
891  lineWidth += textsize * 6; // Includes interchar x gap
892  }
893  } // Carriage return = do nothing
894  }
895  else // Newline
896  {
897  x = 0; // Reset x to 0
898  y += textsize * 8; // Advance y by 1 line
899  if (lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line
900  lineWidth = 0; // Reset lineWidth for new line
901  }
902  }
903  // End of string
904  if (lineWidth) y += textsize * 8; // Add height of last (or only) line
905  *w = maxWidth - 1; // Don't include last interchar x gap
906  *h = y - *y1;
907 
908  } // End classic vs custom font
909 }
910 
911 // Same as above, but for PROGMEM strings
912 void Adafruit_GFX::getTextBounds(const __FlashStringHelper *str,
913  int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
914 {
915  uint8_t *s = (uint8_t *)str, c;
916 
917  *x1 = x;
918  *y1 = y;
919  *w = *h = 0;
920 
921  if (gfxFont)
922  {
923 
924  GFXglyph *glyph;
925  uint8_t first = pgm_read_byte(&gfxFont->first),
926  last = pgm_read_byte(&gfxFont->last),
927  gw, gh, xa;
928  int8_t xo, yo;
929  int16_t minx = _width, miny = _height, maxx = -1, maxy = -1,
930  gx1, gy1, gx2, gy2, ts = (int16_t)textsize,
931  ya = ts * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
932 
933  while ((c = pgm_read_byte(s++)))
934  {
935  if (c != '\n') // Not a newline
936  {
937  if (c != '\r') // Not a carriage return, is normal char
938  {
939  if ((c >= first) && (c <= last)) // Char present in current font
940  {
941  c -= first;
942  glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
943  gw = pgm_read_byte(&glyph->width);
944  gh = pgm_read_byte(&glyph->height);
945  xa = pgm_read_byte(&glyph->xAdvance);
946  xo = pgm_read_byte(&glyph->xOffset);
947  yo = pgm_read_byte(&glyph->yOffset);
948  if (wrap && ((x + (((int16_t)xo + gw) * ts)) >= _width))
949  {
950  // Line wrap
951  x = 0; // Reset x to 0
952  y += ya; // Advance y by 1 line
953  }
954  gx1 = x + xo * ts;
955  gy1 = y + yo * ts;
956  gx2 = gx1 + gw * ts - 1;
957  gy2 = gy1 + gh * ts - 1;
958  if (gx1 < minx) minx = gx1;
959  if (gy1 < miny) miny = gy1;
960  if (gx2 > maxx) maxx = gx2;
961  if (gy2 > maxy) maxy = gy2;
962  x += xa * ts;
963  }
964  } // Carriage return = do nothing
965  }
966  else // Newline
967  {
968  x = 0; // Reset x
969  y += ya; // Advance y by 1 line
970  }
971  }
972  // End of string
973  *x1 = minx;
974  *y1 = miny;
975  if (maxx >= minx) *w = maxx - minx + 1;
976  if (maxy >= miny) *h = maxy - miny + 1;
977 
978  }
979  else // Default font
980  {
981 
982  uint16_t lineWidth = 0, maxWidth = 0; // Width of current, all lines
983 
984  while ((c = pgm_read_byte(s++)))
985  {
986  if (c != '\n') // Not a newline
987  {
988  if (c != '\r') // Not a carriage return, is normal char
989  {
990  if (wrap && ((x + textsize * 6) >= _width))
991  {
992  x = 0; // Reset x to 0
993  y += textsize * 8; // Advance y by 1 line
994  if (lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line
995  lineWidth = textsize * 6; // First char on new line
996  }
997  else // No line wrap, just keep incrementing X
998  {
999  lineWidth += textsize * 6; // Includes interchar x gap
1000  }
1001  } // Carriage return = do nothing
1002  }
1003  else // Newline
1004  {
1005  x = 0; // Reset x to 0
1006  y += textsize * 8; // Advance y by 1 line
1007  if (lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line
1008  lineWidth = 0; // Reset lineWidth for new line
1009  }
1010  }
1011  // End of string
1012  if (lineWidth) y += textsize * 8; // Add height of last (or only) line
1013  *w = maxWidth - 1; // Don't include last interchar x gap
1014  *h = y - *y1;
1015 
1016  } // End classic vs custom font
1017 }
1018 
1019 // Return the size of the display (per current rotation)
1020 int16_t Adafruit_GFX::width(void) const
1021 {
1022  return _width;
1023 }
1024 
1025 int16_t Adafruit_GFX::height(void) const
1026 {
1027  return _height;
1028 }
1029 
1031 {
1032  // Do nothing, must be subclassed if supported by hardware
1033 }
1034 
1035 /***************************************************************************/
1036 // code for the GFX button UI element
1037 
1039 {
1040  _gfx = 0;
1041 }
1042 
1044  Adafruit_GFX *gfx, int16_t x, int16_t y, uint8_t w, uint8_t h,
1045  uint16_t outline, uint16_t fill, uint16_t textcolor,
1046  char *label, uint8_t textsize)
1047 {
1048  _x = x;
1049  _y = y;
1050  _w = w;
1051  _h = h;
1052  _outlinecolor = outline;
1053  _fillcolor = fill;
1054  _textcolor = textcolor;
1055  _textsize = textsize;
1056  _gfx = gfx;
1057  strncpy(_label, label, 9);
1058  _label[9] = 0;
1059 }
1060 
1061 void Adafruit_GFX_Button::drawButton(boolean inverted)
1062 {
1063  uint16_t fill, outline, text;
1064 
1065  if (!inverted)
1066  {
1067  fill = _fillcolor;
1068  outline = _outlinecolor;
1069  text = _textcolor;
1070  }
1071  else
1072  {
1073  fill = _textcolor;
1074  outline = _outlinecolor;
1075  text = _fillcolor;
1076  }
1077 
1078  _gfx->fillRoundRect(_x - (_w/2), _y - (_h/2), _w, _h, min(_w,_h)/4, fill);
1079  _gfx->drawRoundRect(_x - (_w/2), _y - (_h/2), _w, _h, min(_w,_h)/4, outline);
1080 
1081  _gfx->setCursor(_x - strlen(_label)*3*_textsize, _y-4*_textsize);
1082  _gfx->setTextColor(text);
1083  _gfx->setTextSize(_textsize);
1084  _gfx->print(_label);
1085 }
1086 
1087 boolean Adafruit_GFX_Button::contains(int16_t x, int16_t y)
1088 {
1089  if ((x < (_x - _w/2)) || (x > (_x + _w/2))) return false;
1090  if ((y < (_y - _h/2)) || (y > (_y + _h/2))) return false;
1091  return true;
1092 }
1093 
1095 {
1096  laststate = currstate;
1097  currstate = p;
1098 }
1099 
1101 {
1102  return currstate;
1103 }
1105 {
1106  return (currstate && !laststate);
1107 }
1109 {
1110  return (!currstate && laststate);
1111 }
1112 
1113 // -------------------------------------------------------------------------
1114 
1115 // GFXcanvas1 and GFXcanvas16 (currently a WIP, don't get too comfy with the
1116 // implementation) provide 1- and 16-bit offscreen canvases, the address of
1117 // which can be passed to drawBitmap() or pushColors() (the latter appears
1118 // to only be in Adafruit_TFTLCD at this time). This is here mostly to
1119 // help with the recently-added proportionally-spaced fonts; adds a way to
1120 // refresh a section of the screen without a massive flickering clear-and-
1121 // redraw...but maybe you'll find other uses too. VERY RAM-intensive, since
1122 // the buffer is in MCU memory and not the display driver...GXFcanvas1 might
1123 // be minimally useful on an Uno-class board, but this and GFXcanvas16 are
1124 // much more likely to require at least a Mega or various recent ARM-type
1125 // boards (recomment, as the text+bitmap draw can be pokey). GFXcanvas1
1126 // requires 1 bit per pixel (rounded up to nearest byte per scanline),
1127 // GFXcanvas16 requires 2 bytes per pixel (no scanline pad).
1128 // NOT EXTENSIVELY TESTED YET. MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND.
1129 
1130 GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h)
1131 {
1132  uint16_t bytes = ((w + 7) / 8) * h;
1133  if ((buffer = (uint8_t *)malloc(bytes)))
1134  {
1135  memset(buffer, 0, bytes);
1136  }
1137 }
1138 
1140 {
1141  if (buffer) free(buffer);
1142 }
1143 
1145 {
1146  return buffer;
1147 }
1148 
1149 void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color)
1150 {
1151  // Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR
1152  static const uint8_t PROGMEM
1153  GFXsetBit[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 },
1154  GFXclrBit[] = { 0x7F, 0xBF, 0xDF, 0xEF, 0xF7, 0xFB, 0xFD, 0xFE };
1155 
1156  if (buffer)
1157  {
1158  if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
1159 
1160  int16_t t;
1161  switch (rotation)
1162  {
1163  case 1:
1164  t = x;
1165  x = WIDTH - 1 - y;
1166  y = t;
1167  break;
1168  case 2:
1169  x = WIDTH - 1 - x;
1170  y = HEIGHT - 1 - y;
1171  break;
1172  case 3:
1173  t = x;
1174  x = y;
1175  y = HEIGHT - 1 - t;
1176  break;
1177  }
1178 
1179  uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)];
1180  if (color) *ptr |= pgm_read_byte(&GFXsetBit[x & 7]);
1181  else *ptr &= pgm_read_byte(&GFXclrBit[x & 7]);
1182  }
1183 }
1184 
1185 void GFXcanvas1::fillScreen(uint16_t color)
1186 {
1187  if (buffer)
1188  {
1189  uint16_t bytes = ((WIDTH + 7) / 8) * HEIGHT;
1190  memset(buffer, color ? 0xFF : 0x00, bytes);
1191  }
1192 }
1193 
1194 GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h)
1195 {
1196  uint16_t bytes = w * h * 2;
1197  if ((buffer = (uint16_t *)malloc(bytes)))
1198  {
1199  memset(buffer, 0, bytes);
1200  }
1201 }
1202 
1203 GFXcanvas16::~GFXcanvas16(void)
1204 {
1205  if (buffer) free(buffer);
1206 }
1207 
1208 uint16_t *GFXcanvas16::getBuffer(void)
1209 {
1210  return buffer;
1211 }
1212 
1213 void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color)
1214 {
1215  if (buffer)
1216  {
1217  if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) return;
1218 
1219  int16_t t;
1220  switch (rotation)
1221  {
1222  case 1:
1223  t = x;
1224  x = WIDTH - 1 - y;
1225  y = t;
1226  break;
1227  case 2:
1228  x = WIDTH - 1 - x;
1229  y = HEIGHT - 1 - y;
1230  break;
1231  case 3:
1232  t = x;
1233  x = y;
1234  y = HEIGHT - 1 - t;
1235  break;
1236  }
1237 
1238  buffer[x + y * WIDTH] = color;
1239  }
1240 }
1241 
1242 void GFXcanvas16::fillScreen(uint16_t color)
1243 {
1244  if (buffer)
1245  {
1246  uint8_t hi = color >> 8, lo = color & 0xFF;
1247  if (hi == lo)
1248  {
1249  memset(buffer, lo, WIDTH * HEIGHT * 2);
1250  }
1251  else
1252  {
1253  uint16_t i, pixels = WIDTH * HEIGHT;
1254  for (i=0; i<pixels; i++) buffer[i] = color;
1255  }
1256  }
1257 }
1258 
void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
virtual void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
uint8_t textsize
Definition: Adafruit_GFX.h:99
uint8_t width
Definition: gfxfont.h:13
virtual void invertDisplay(boolean i)
int16_t height(void) const
int16_t cursor_y
Definition: Adafruit_GFX.h:94
uint8_t yAdvance
Definition: gfxfont.h:23
#define pgm_read_pointer(addr)
void setFont(const GFXfont *f=NULL)
void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color)
int16_t getCursorY(void) const
void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color)
void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
void setCursor(int16_t x, int16_t y)
void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color)
uint16_t textbgcolor
Definition: Adafruit_GFX.h:97
uint8_t xAdvance
Definition: gfxfont.h:14
int16_t width(void) const
uint8_t rotation
Definition: Adafruit_GFX.h:99
boolean contains(int16_t x, int16_t y)
int16_t getCursorX(void) const
GFXcanvas1(uint16_t w, uint16_t h)
int16_t cursor_x
Definition: Adafruit_GFX.h:94
virtual void drawPixel(int16_t x, int16_t y, uint16_t color)=0
#define min(a, b)
void drawXBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color)
uint16_t bitmapOffset
Definition: gfxfont.h:12
void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color)
GFXglyph * glyph
Definition: gfxfont.h:21
void fillScreen(uint16_t color)
virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color)
int8_t xOffset
Definition: gfxfont.h:15
void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint16_t color)
void getTextBounds(char *string, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h)
#define pgm_read_word(addr)
void setTextColor(uint16_t c)
virtual void fillScreen(uint16_t color)
boolean _cp437
Definition: Adafruit_GFX.h:102
uint8_t last
Definition: gfxfont.h:22
void drawButton(boolean inverted=false)
virtual void write(uint8_t)
int16_t _height
Definition: Adafruit_GFX.h:94
void drawPixel(int16_t x, int16_t y, uint16_t color)
void cp437(boolean x=true)
uint8_t getRotation(void) const
uint8_t first
Definition: gfxfont.h:22
virtual void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color)
TouchScreen ts
uint8_t * bitmap
Definition: gfxfont.h:20
void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size)
void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color)
void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color)
GFXfont * gfxFont
Definition: Adafruit_GFX.h:105
int8_t yOffset
Definition: gfxfont.h:15
uint16_t textcolor
Definition: Adafruit_GFX.h:97
boolean wrap
Definition: Adafruit_GFX.h:102
void setTextWrap(boolean w)
void setTextSize(uint8_t s)
const int16_t HEIGHT
Definition: Adafruit_GFX.h:92
uint8_t height
Definition: gfxfont.h:13
Adafruit_GFX(int16_t w, int16_t h)
void setRotation(uint8_t r)
static int i
Definition: DC2430A.ino:184
uint8_t * getBuffer(void)
virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color)
void press(boolean p)
#define PROGMEM
Definition: glcdfont.c:13
void initButton(Adafruit_GFX *gfx, int16_t x, int16_t y, uint8_t w, uint8_t h, uint16_t outline, uint16_t fill, uint16_t textcolor, char *label, uint8_t textsize)
#define pgm_read_byte(addr)
#define _swap_int16_t(a, b)
int16_t _width
Definition: Adafruit_GFX.h:94
const int16_t WIDTH
Definition: Adafruit_GFX.h:92