MBED Import of ADAFRUIT graphics library, BSD License

Dependents:   GP9002adafruit GP9002af_gray

Notes on this library

This was imported into MBED specifically to support the GP9002 VFD, as a result it has some "hacks" to optimize it for the GP9002.

Due to the GP9002 internal organization it draws vertical lines much faster than horizontal (assuming you orient it "landscape"). This is likely to be true of other displays that have bits in a byte arranged vertically, which seems a common theme in small GLCDs. Some types may have a more CGA-like memory organization and will draw faster horizontally.

On a vertical-organised display the graphics functions are often substantially faster if X and Y are exchanged, especially with the dot-write optimization. This is because vertical lines can be written byte-at-a-time with no need for read-modify-write, and even when individual bits are written a significant number will "land" in the byte previously written. In contrast a horizontal line would require changing one bit of each byte in turn, requiring a sequence of set-address,read,write operations for each dot in turn.

I've hacked this in the library. I forget exactly how but I believe I simply exchanged X with W in the code for drawing filled shapes.

I would like to come up with a more generic way to do this, such as having internal coordinates that are not defined as X and Y, then leaving it up to the display library to "wrap" them in the way that is best for that display.

I would like to apologize for abandoning this project, but the test harness still exists and I might return to it, though I'm more interested in TFT systems like the STM discovery now.

Committer:
oliverb
Date:
Sat May 07 12:50:37 2016 +0000
Revision:
0:3bf8ef959338
Converting to Library, this is a base class that needs extending for a specific device. Note that as it stands it favors devices with vertical bit-organisation

Who changed what in which revision?

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