Eric Johnson / Mbed 2 deprecated SSD1306-I2C

Dependencies:   mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers Adafruit_GFX.cpp Source File

Adafruit_GFX.cpp

00001 /*
00002 This is the core graphics library for all our displays, providing a common
00003 set of graphics primitives (points, lines, circles, etc.).  It needs to be
00004 paired with a hardware-specific library for each display device we carry
00005 (to handle the lower-level functions).
00006 
00007 Adafruit invests time and resources providing this open source code, please
00008 support Adafruit & open-source hardware by purchasing products from Adafruit!
00009 
00010 Copyright (c) 2013 Adafruit Industries.  All rights reserved.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014 
00015 - Redistributions of source code must retain the above copyright notice,
00016   this list of conditions and the following disclaimer.
00017 - Redistributions in binary form must reproduce the above copyright notice,
00018   this list of conditions and the following disclaimer in the documentation
00019   and/or other materials provided with the distribution.
00020 
00021 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00022 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00023 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00024 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
00025 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00026 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00027 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00028 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00029 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00030 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00031 POSSIBILITY OF SUCH DAMAGE.
00032 */
00033 
00034 #include "Adafruit_GFX.h"
00035 #include "glcdfont.c"
00036 
00037 // Many (but maybe not all) non-AVR board installs define macros
00038 // for compatibility with existing PROGMEM-reading AVR code.
00039 // Do our own checks and defines here for good measure...
00040 
00041 #ifndef pgm_read_byte
00042  #define pgm_read_byte(addr) (*(const unsigned char *)(addr))
00043 #endif
00044 #ifndef pgm_read_word
00045  #define pgm_read_word(addr) (*(const unsigned short *)(addr))
00046 #endif
00047 #ifndef pgm_read_dword
00048  #define pgm_read_dword(addr) (*(const unsigned long *)(addr))
00049 #endif
00050 
00051 // Pointers are a peculiar case...typically 16-bit on AVR boards,
00052 // 32 bits elsewhere.  Try to accommodate both...
00053 
00054 #if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF)
00055  #define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr))
00056 #else
00057  #define pgm_read_pointer(addr) ((void *)pgm_read_word(addr))
00058 #endif
00059 
00060 #ifndef min
00061 #define min(a,b) (((a) < (b)) ? (a) : (b))
00062 #endif
00063 
00064 #ifndef _swap_int16_t
00065 #define _swap_int16_t(a, b) { int16_t t = a; a = b; b = t; }
00066 #endif
00067 
00068 Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h):
00069   WIDTH(w), HEIGHT(h)
00070 {
00071   _width    = WIDTH;
00072   _height   = HEIGHT;
00073   rotation  = 0;
00074   cursor_y  = cursor_x    = 0;
00075   textsize  = 1;
00076   textcolor = textbgcolor = 0xFFFF;
00077   wrap      = true;
00078   gfxFont   = NULL;
00079 }
00080 
00081 // Draw a circle outline
00082 void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r,
00083  uint16_t color) {
00084   int16_t f = 1 - r;
00085   int16_t ddF_x = 1;
00086   int16_t ddF_y = -2 * r;
00087   int16_t x = 0;
00088   int16_t y = r;
00089 
00090   drawPixel(x0  , y0+r, color);
00091   drawPixel(x0  , y0-r, color);
00092   drawPixel(x0+r, y0  , color);
00093   drawPixel(x0-r, y0  , color);
00094 
00095   while (x<y) {
00096     if (f >= 0) {
00097       y--;
00098       ddF_y += 2;
00099       f += ddF_y;
00100     }
00101     x++;
00102     ddF_x += 2;
00103     f += ddF_x;
00104 
00105     drawPixel(x0 + x, y0 + y, color);
00106     drawPixel(x0 - x, y0 + y, color);
00107     drawPixel(x0 + x, y0 - y, color);
00108     drawPixel(x0 - x, y0 - y, color);
00109     drawPixel(x0 + y, y0 + x, color);
00110     drawPixel(x0 - y, y0 + x, color);
00111     drawPixel(x0 + y, y0 - x, color);
00112     drawPixel(x0 - y, y0 - x, color);
00113   }
00114 }
00115 
00116 void Adafruit_GFX::drawCircleHelper( int16_t x0, int16_t y0,
00117  int16_t r, uint8_t cornername, uint16_t color) {
00118   int16_t f     = 1 - r;
00119   int16_t ddF_x = 1;
00120   int16_t ddF_y = -2 * r;
00121   int16_t x     = 0;
00122   int16_t y     = r;
00123 
00124   while (x<y) {
00125     if (f >= 0) {
00126       y--;
00127       ddF_y += 2;
00128       f     += ddF_y;
00129     }
00130     x++;
00131     ddF_x += 2;
00132     f     += ddF_x;
00133     if (cornername & 0x4) {
00134       drawPixel(x0 + x, y0 + y, color);
00135       drawPixel(x0 + y, y0 + x, color);
00136     }
00137     if (cornername & 0x2) {
00138       drawPixel(x0 + x, y0 - y, color);
00139       drawPixel(x0 + y, y0 - x, color);
00140     }
00141     if (cornername & 0x8) {
00142       drawPixel(x0 - y, y0 + x, color);
00143       drawPixel(x0 - x, y0 + y, color);
00144     }
00145     if (cornername & 0x1) {
00146       drawPixel(x0 - y, y0 - x, color);
00147       drawPixel(x0 - x, y0 - y, color);
00148     }
00149   }
00150 }
00151 
00152 void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r,  uint16_t color) {
00153   drawFastVLine(x0, y0-r, 2*r+1, color);
00154   fillCircleHelper(x0, y0, r, 3, 0, color);
00155 }
00156 
00157 // Used to do circles and roundrects
00158 void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r,
00159  uint8_t cornername, int16_t delta, uint16_t color) {
00160 
00161   int16_t f     = 1 - r;
00162   int16_t ddF_x = 1;
00163   int16_t ddF_y = -2 * r;
00164   int16_t x     = 0;
00165   int16_t y     = r;
00166 
00167   while (x<y) {
00168     if (f >= 0) {
00169       y--;
00170       ddF_y += 2;
00171       f     += ddF_y;
00172     }
00173     x++;
00174     ddF_x += 2;
00175     f     += ddF_x;
00176 
00177     if (cornername & 0x1) {
00178       drawFastVLine(x0+x, y0-y, 2*y+1+delta, color);
00179       drawFastVLine(x0+y, y0-x, 2*x+1+delta, color);
00180     }
00181     if (cornername & 0x2) {
00182       drawFastVLine(x0-x, y0-y, 2*y+1+delta, color);
00183       drawFastVLine(x0-y, y0-x, 2*x+1+delta, color);
00184     }
00185   }
00186 }
00187 
00188 // Bresenham's algorithm - thx wikpedia
00189 void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1,
00190  uint16_t color) {
00191   int16_t steep = abs(y1 - y0) > abs(x1 - x0);
00192   if (steep) {
00193     _swap_int16_t(x0, y0);
00194     _swap_int16_t(x1, y1);
00195   }
00196 
00197   if (x0 > x1) {
00198     _swap_int16_t(x0, x1);
00199     _swap_int16_t(y0, y1);
00200   }
00201 
00202   int16_t dx, dy;
00203   dx = x1 - x0;
00204   dy = abs(y1 - y0);
00205 
00206   int16_t err = dx / 2;
00207   int16_t ystep;
00208 
00209   if (y0 < y1) {
00210     ystep = 1;
00211   } else {
00212     ystep = -1;
00213   }
00214 
00215   for (; x0<=x1; x0++) {
00216     if (steep) {
00217       drawPixel(y0, x0, color);
00218     } else {
00219       drawPixel(x0, y0, color);
00220     }
00221     err -= dy;
00222     if (err < 0) {
00223       y0 += ystep;
00224       err += dx;
00225     }
00226   }
00227 }
00228 
00229 // Draw a rectangle
00230 void Adafruit_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h,
00231  uint16_t color) {
00232   drawFastHLine(x, y, w, color);
00233   drawFastHLine(x, y+h-1, w, color);
00234   drawFastVLine(x, y, h, color);
00235   drawFastVLine(x+w-1, y, h, color);
00236 }
00237 
00238 void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y,
00239  int16_t h, uint16_t color) {
00240   // Update in subclasses if desired!
00241   drawLine(x, y, x, y+h-1, color);
00242 }
00243 
00244 void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y,
00245  int16_t w, uint16_t color) {
00246   // Update in subclasses if desired!
00247   drawLine(x, y, x+w-1, y, color);
00248 }
00249 
00250 void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h,
00251  uint16_t color) {
00252   // Update in subclasses if desired!
00253   for (int16_t i=x; i<x+w; i++) {
00254     drawFastVLine(i, y, h, color);
00255   }
00256 }
00257 
00258 void Adafruit_GFX::fillScreen(uint16_t color) {
00259   fillRect(0, 0, _width, _height, color);
00260 }
00261 
00262 // Draw a rounded rectangle
00263 void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w,
00264  int16_t h, int16_t r, uint16_t color) {
00265   // smarter version
00266   drawFastHLine(x+r  , y    , w-2*r, color); // Top
00267   drawFastHLine(x+r  , y+h-1, w-2*r, color); // Bottom
00268   drawFastVLine(x    , y+r  , h-2*r, color); // Left
00269   drawFastVLine(x+w-1, y+r  , h-2*r, color); // Right
00270   // draw four corners
00271   drawCircleHelper(x+r    , y+r    , r, 1, color);
00272   drawCircleHelper(x+w-r-1, y+r    , r, 2, color);
00273   drawCircleHelper(x+w-r-1, y+h-r-1, r, 4, color);
00274   drawCircleHelper(x+r    , y+h-r-1, r, 8, color);
00275 }
00276 
00277 // Fill a rounded rectangle
00278 void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w,
00279  int16_t h, int16_t r, uint16_t color) {
00280   // smarter version
00281   fillRect(x+r, y, w-2*r, h, color);
00282 
00283   // draw four corners
00284   fillCircleHelper(x+w-r-1, y+r, r, 1, h-2*r-1, color);
00285   fillCircleHelper(x+r    , y+r, r, 2, h-2*r-1, color);
00286 }
00287 
00288 // Draw a triangle
00289 void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0,
00290  int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
00291   drawLine(x0, y0, x1, y1, color);
00292   drawLine(x1, y1, x2, y2, color);
00293   drawLine(x2, y2, x0, y0, color);
00294 }
00295 
00296 // Fill a triangle
00297 void Adafruit_GFX::fillTriangle(int16_t x0, int16_t y0,
00298  int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) {
00299 
00300   int16_t a, b, y, last;
00301 
00302   // Sort coordinates by Y order (y2 >= y1 >= y0)
00303   if (y0 > y1) {
00304     _swap_int16_t(y0, y1); _swap_int16_t(x0, x1);
00305   }
00306   if (y1 > y2) {
00307     _swap_int16_t(y2, y1); _swap_int16_t(x2, x1);
00308   }
00309   if (y0 > y1) {
00310     _swap_int16_t(y0, y1); _swap_int16_t(x0, x1);
00311   }
00312 
00313   if(y0 == y2) { // Handle awkward all-on-same-line case as its own thing
00314     a = b = x0;
00315     if(x1 < a)      a = x1;
00316     else if(x1 > b) b = x1;
00317     if(x2 < a)      a = x2;
00318     else if(x2 > b) b = x2;
00319     drawFastHLine(a, y0, b-a+1, color);
00320     return;
00321   }
00322 
00323   int16_t
00324     dx01 = x1 - x0,
00325     dy01 = y1 - y0,
00326     dx02 = x2 - x0,
00327     dy02 = y2 - y0,
00328     dx12 = x2 - x1,
00329     dy12 = y2 - y1;
00330   int32_t
00331     sa   = 0,
00332     sb   = 0;
00333 
00334   // For upper part of triangle, find scanline crossings for segments
00335   // 0-1 and 0-2.  If y1=y2 (flat-bottomed triangle), the scanline y1
00336   // is included here (and second loop will be skipped, avoiding a /0
00337   // error there), otherwise scanline y1 is skipped here and handled
00338   // in the second loop...which also avoids a /0 error here if y0=y1
00339   // (flat-topped triangle).
00340   if(y1 == y2) last = y1;   // Include y1 scanline
00341   else         last = y1-1; // Skip it
00342 
00343   for(y=y0; y<=last; y++) {
00344     a   = x0 + sa / dy01;
00345     b   = x0 + sb / dy02;
00346     sa += dx01;
00347     sb += dx02;
00348     /* longhand:
00349     a = x0 + (x1 - x0) * (y - y0) / (y1 - y0);
00350     b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
00351     */
00352     if(a > b) _swap_int16_t(a,b);
00353     drawFastHLine(a, y, b-a+1, color);
00354   }
00355 
00356   // For lower part of triangle, find scanline crossings for segments
00357   // 0-2 and 1-2.  This loop is skipped if y1=y2.
00358   sa = dx12 * (y - y1);
00359   sb = dx02 * (y - y0);
00360   for(; y<=y2; y++) {
00361     a   = x1 + sa / dy12;
00362     b   = x0 + sb / dy02;
00363     sa += dx12;
00364     sb += dx02;
00365     /* longhand:
00366     a = x1 + (x2 - x1) * (y - y1) / (y2 - y1);
00367     b = x0 + (x2 - x0) * (y - y0) / (y2 - y0);
00368     */
00369     if(a > b) _swap_int16_t(a,b);
00370     drawFastHLine(a, y, b-a+1, color);
00371   }
00372 }
00373 
00374 
00375 // Draw a 1-bit image (bitmap) at the specified (x,y) position from the
00376 // provided bitmap buffer using the specified
00377 // foreground color (unset bits are transparent).
00378 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, 
00379      const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {
00380 
00381   int16_t i, j, byteWidth = (w + 7) / 8;
00382   uint8_t byte;
00383 
00384   for(j=0; j<h; j++) {
00385     for(i=0; i<w; i++ ) {
00386       if(i & 7) byte <<= 1;
00387       else      byte   = bitmap[j * byteWidth + i / 8];
00388       if(byte & 0x80) drawPixel(x+i, y+j, color);
00389     }
00390   }
00391 }
00392 
00393 // Draw a 1-bit image (bitmap) at the specified (x,y) position from the
00394 // provided bitmap buffer using the specified
00395 // foreground (for set bits) and background (for clear bits) colors.
00396 void Adafruit_GFX::drawBitmap(int16_t x, int16_t y,
00397         const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) {
00398 
00399   int16_t i, j, byteWidth = (w + 7) / 8;
00400   uint8_t byte;
00401 
00402   for(j=0; j<h; j++) {
00403     for(i=0; i<w; i++ ) {
00404       if(i & 7) byte <<= 1;
00405       else      byte   = bitmap[j * byteWidth + i / 8];
00406       if(byte & 0x80) drawPixel(x+i, y+j, color);
00407       else            drawPixel(x+i, y+j, bg);
00408     }
00409   }
00410 }
00411 
00412 //Draw XBitMap Files (*.xbm), exported from GIMP,
00413 //Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor.
00414 //C Array can be directly used with this function
00415 void Adafruit_GFX::drawXBitmap(int16_t x, int16_t y,
00416  const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) {
00417 
00418   int16_t i, j, byteWidth = (w + 7) / 8;
00419   uint8_t byte;
00420 
00421   for(j=0; j<h; j++) {
00422     for(i=0; i<w; i++ ) {
00423       if(i & 7) byte >>= 1;
00424       else      byte   = pgm_read_byte(bitmap + j * byteWidth + i / 8);
00425       if(byte & 0x01) drawPixel(x+i, y+j, color);
00426     }
00427   }
00428 }
00429 
00430 size_t Adafruit_GFX::write(uint8_t c) {
00431   if(!gfxFont) { // 'Classic' built-in font
00432 
00433     if(c == '\n') {
00434       cursor_y += textsize*8;
00435       cursor_x  = 0;
00436     } else if(c == '\r') {
00437       // skip em
00438     } else {
00439       if(wrap && ((cursor_x + textsize * 6) >= _width)) { // Heading off edge?
00440         cursor_x  = 0;            // Reset x to zero
00441         cursor_y += textsize * 8; // Advance y one line
00442       }
00443       drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize);
00444       cursor_x += textsize * 6;
00445     }
00446 
00447   } else { // Custom font
00448 
00449     if(c == '\n') {
00450       cursor_x  = 0;
00451       cursor_y += (int16_t)textsize *
00452                   (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
00453     } else if(c != '\r') {
00454       uint8_t first = pgm_read_byte(&gfxFont->first);
00455       if((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) {
00456         uint8_t   c2    = c - pgm_read_byte(&gfxFont->first);
00457         GFXglyph *glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c2]);
00458         uint8_t   w     = pgm_read_byte(&glyph->width),
00459                   h     = pgm_read_byte(&glyph->height);
00460         if((w > 0) && (h > 0)) { // Is there an associated bitmap?
00461           int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic
00462           if(wrap && ((cursor_x + textsize * (xo + w)) >= _width)) {
00463             // Drawing character would go off right edge; wrap to new line
00464             cursor_x  = 0;
00465             cursor_y += (int16_t)textsize *
00466                         (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
00467           }
00468           drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize);
00469         }
00470         cursor_x += pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize;
00471       }
00472     }
00473 
00474   }
00475   return 1;
00476 }
00477 
00478 // Draw a character
00479 void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c,
00480  uint16_t color, uint16_t bg, uint8_t size) {
00481 
00482   if(!gfxFont) { // 'Classic' built-in font
00483 
00484     if((x >= _width)            || // Clip right
00485        (y >= _height)           || // Clip bottom
00486        ((x + 6 * size - 1) < 0) || // Clip left
00487        ((y + 8 * size - 1) < 0))   // Clip top
00488       return;
00489 
00490     for(int8_t i=0; i<6; i++ ) {
00491       uint8_t line;
00492       if(i < 5) line = pgm_read_byte(font+(c*5)+i);
00493       else      line = 0x0;
00494       for(int8_t j=0; j<8; j++, line >>= 1) {
00495         if(line & 0x1) {
00496           if(size == 1) drawPixel(x+i, y+j, color);
00497           else          fillRect(x+(i*size), y+(j*size), size, size, color);
00498         } else if(bg != color) {
00499           if(size == 1) drawPixel(x+i, y+j, bg);
00500           else          fillRect(x+i*size, y+j*size, size, size, bg);
00501         }
00502       }
00503     }
00504 
00505   } else { // Custom font
00506 
00507     // Character is assumed previously filtered by write() to eliminate
00508     // newlines, returns, non-printable characters, etc.  Calling drawChar()
00509     // directly with 'bad' characters of font may cause mayhem!
00510 
00511     c -= pgm_read_byte(&gfxFont->first);
00512     GFXglyph *glyph  = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
00513     uint8_t  *bitmap = (uint8_t *)pgm_read_pointer(&gfxFont->bitmap);
00514 
00515     uint16_t bo = pgm_read_word(&glyph->bitmapOffset);
00516     uint8_t  w  = pgm_read_byte(&glyph->width),
00517              h  = pgm_read_byte(&glyph->height),
00518              xa = pgm_read_byte(&glyph->xAdvance);
00519     int8_t   xo = pgm_read_byte(&glyph->xOffset);
00520     int8_t   yo = pgm_read_byte(&glyph->yOffset);
00521     uint8_t  xx, yy, bits, bit = 0;
00522     int16_t  xo16, yo16;
00523 
00524     if(size > 1) {
00525       xo16 = xo;
00526       yo16 = yo;
00527     }
00528 
00529     // Todo: Add character clipping here
00530 
00531     // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS.
00532     // THIS IS ON PURPOSE AND BY DESIGN.  The background color feature
00533     // has typically been used with the 'classic' font to overwrite old
00534     // screen contents with new data.  This ONLY works because the
00535     // characters are a uniform size; it's not a sensible thing to do with
00536     // proportionally-spaced fonts with glyphs of varying sizes (and that
00537     // may overlap).  To replace previously-drawn text when using a custom
00538     // font, use the getTextBounds() function to determine the smallest
00539     // rectangle encompassing a string, erase the area with fillRect(),
00540     // then draw new text.  This WILL infortunately 'blink' the text, but
00541     // is unavoidable.  Drawing 'background' pixels will NOT fix this,
00542     // only creates a new set of problems.  Have an idea to work around
00543     // this (a canvas object type for MCUs that can afford the RAM and
00544     // displays supporting setAddrWindow() and pushColors()), but haven't
00545     // implemented this yet.
00546 
00547     for(yy=0; yy<h; yy++) {
00548       for(xx=0; xx<w; xx++) {
00549         if(!(bit++ & 7)) {
00550           bits = pgm_read_byte(&bitmap[bo++]);
00551         }
00552         if(bits & 0x80) {
00553           if(size == 1) {
00554             drawPixel(x+xo+xx, y+yo+yy, color);
00555           } else {
00556             fillRect(x+(xo16+xx)*size, y+(yo16+yy)*size, size, size, color);
00557           }
00558         }
00559         bits <<= 1;
00560       }
00561     }
00562 
00563   } // End classic vs custom font
00564 }
00565 
00566 void Adafruit_GFX::setCursor(int16_t x, int16_t y) {
00567   cursor_x = x;
00568   cursor_y = y;
00569 }
00570 
00571 int16_t Adafruit_GFX::getCursorX(void) const {
00572   return cursor_x;
00573 }
00574 
00575 int16_t Adafruit_GFX::getCursorY(void) const {
00576   return cursor_y;
00577 }
00578 
00579 void Adafruit_GFX::setTextSize(uint8_t s) {
00580   textsize = (s > 0) ? s : 1;
00581 }
00582 
00583 void Adafruit_GFX::setTextColor(uint16_t c) {
00584   // For 'transparent' background, we'll set the bg
00585   // to the same as fg instead of using a flag
00586   textcolor = textbgcolor = c;
00587 }
00588 
00589 void Adafruit_GFX::setTextColor(uint16_t c, uint16_t b) {
00590   textcolor   = c;
00591   textbgcolor = b;
00592 }
00593 
00594 void Adafruit_GFX::setTextWrap(bool w) {
00595   wrap = w;
00596 }
00597 
00598 uint8_t Adafruit_GFX::getRotation(void) const {
00599   return rotation;
00600 }
00601 
00602 void Adafruit_GFX::setRotation(uint8_t x) {
00603   rotation = (x & 3);
00604   switch(rotation) {
00605    case 0:
00606    case 2:
00607     _width  = WIDTH;
00608     _height = HEIGHT;
00609     break;
00610    case 1:
00611    case 3:
00612     _width  = HEIGHT;
00613     _height = WIDTH;
00614     break;
00615   }
00616 }
00617 
00618 
00619 void Adafruit_GFX::setFont(const GFXfont *f) {
00620   if(f) {          // Font struct pointer passed in?
00621     if(!gfxFont) { // And no current font struct?
00622       // Switching from classic to new font behavior.
00623       // Move cursor pos down 6 pixels so it's on baseline.
00624       cursor_y += 6;
00625     }
00626   } else if(gfxFont) { // NULL passed.  Current font struct defined?
00627     // Switching from new to classic font behavior.
00628     // Move cursor pos up 6 pixels so it's at top-left of char.
00629     cursor_y -= 6;
00630   }
00631   gfxFont = (GFXfont *)f;
00632 }
00633 
00634 // Pass string and a cursor position, returns UL corner and W,H.
00635 void Adafruit_GFX::getTextBounds(char *str, int16_t x, int16_t y,
00636  int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) {
00637   uint8_t c; // Current character
00638 
00639   *x1 = x;
00640   *y1 = y;
00641   *w  = *h = 0;
00642 
00643   if(gfxFont) {
00644 
00645     GFXglyph *glyph;
00646     uint8_t   first = pgm_read_byte(&gfxFont->first),
00647               last  = pgm_read_byte(&gfxFont->last),
00648               gw, gh, xa;
00649     int8_t    xo, yo;
00650     int16_t   minx = _width, miny = _height, maxx = -1, maxy = -1,
00651               gx1, gy1, gx2, gy2, ts = (int16_t)textsize,
00652               ya = ts * (uint8_t)pgm_read_byte(&gfxFont->yAdvance);
00653 
00654     while((c = *str++)) {
00655       if(c != '\n') { // Not a newline
00656         if(c != '\r') { // Not a carriage return, is normal char
00657           if((c >= first) && (c <= last)) { // Char present in current font
00658             c    -= first;
00659             glyph = &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]);
00660             gw    = pgm_read_byte(&glyph->width);
00661             gh    = pgm_read_byte(&glyph->height);
00662             xa    = pgm_read_byte(&glyph->xAdvance);
00663             xo    = pgm_read_byte(&glyph->xOffset);
00664             yo    = pgm_read_byte(&glyph->yOffset);
00665             if(wrap && ((x + (((int16_t)xo + gw) * ts)) >= _width)) {
00666               // Line wrap
00667               x  = 0;  // Reset x to 0
00668               y += ya; // Advance y by 1 line
00669             }
00670             gx1 = x   + xo * ts;
00671             gy1 = y   + yo * ts;
00672             gx2 = gx1 + gw * ts - 1;
00673             gy2 = gy1 + gh * ts - 1;
00674             if(gx1 < minx) minx = gx1;
00675             if(gy1 < miny) miny = gy1;
00676             if(gx2 > maxx) maxx = gx2;
00677             if(gy2 > maxy) maxy = gy2;
00678             x += xa * ts;
00679           }
00680         } // Carriage return = do nothing
00681       } else { // Newline
00682         x  = 0;  // Reset x
00683         y += ya; // Advance y by 1 line
00684       }
00685     }
00686     // End of string
00687     *x1 = minx;
00688     *y1 = miny;
00689     if(maxx >= minx) *w  = maxx - minx + 1;
00690     if(maxy >= miny) *h  = maxy - miny + 1;
00691 
00692   } else { // Default font
00693 
00694     uint16_t lineWidth = 0, maxWidth = 0; // Width of current, all lines
00695 
00696     while((c = *str++)) {
00697       if(c != '\n') { // Not a newline
00698         if(c != '\r') { // Not a carriage return, is normal char
00699           if(wrap && ((x + textsize * 6) >= _width)) {
00700             x  = 0;            // Reset x to 0
00701             y += textsize * 8; // Advance y by 1 line
00702             if(lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line
00703             lineWidth  = textsize * 6; // First char on new line
00704           } else { // No line wrap, just keep incrementing X
00705             lineWidth += textsize * 6; // Includes interchar x gap
00706           }
00707         } // Carriage return = do nothing
00708       } else { // Newline
00709         x  = 0;            // Reset x to 0
00710         y += textsize * 8; // Advance y by 1 line
00711         if(lineWidth > maxWidth) maxWidth = lineWidth; // Save widest line
00712         lineWidth = 0;     // Reset lineWidth for new line
00713       }
00714     }
00715     // End of string
00716     if(lineWidth) y += textsize * 8; // Add height of last (or only) line
00717     if(lineWidth > maxWidth) maxWidth = lineWidth; // Is the last or only line the widest?
00718     *w = maxWidth - 1;               // Don't include last interchar x gap
00719     *h = y - *y1;
00720 
00721   } // End classic vs custom font
00722 }
00723 
00724 
00725 
00726 void Adafruit_GFX::print(const char* str) {
00727     const char* p = str;
00728     while (*p!=0)
00729         write(*p++);
00730 }
00731 
00732 void Adafruit_GFX::println(const char* str) {
00733     print(str);
00734     write('\n');
00735 }
00736 
00737 // Return the size of the display (per current rotation)
00738 int16_t Adafruit_GFX::width(void) const {
00739   return _width;
00740 }
00741 
00742 int16_t Adafruit_GFX::height(void) const {
00743   return _height;
00744 }
00745 
00746 void Adafruit_GFX::invertDisplay(bool i) {
00747   // Do nothing, must be subclassed if supported by hardware
00748 }
00749 
00750 
00751 /***************************************************************************/
00752