Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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
Generated on Wed Jul 13 2022 16:35:49 by
1.7.2