acid-drop- Hacking the planet from a LilyGo T-Deck using custom firmware |
git clone git://git.acid.vegas/acid-drop.git |
Log | Files | Refs | Archive | README | LICENSE |
Arduino_GFX.cpp (86019B)
1 /* 2 * start rewrite from: 3 * https://github.com/adafruit/Adafruit-GFX-Library.git 4 * 5 * Arc function come from: 6 * https://github.com/lovyan03/LovyanGFX.git 7 */ 8 #include "Arduino_DataBus.h" 9 #include "Arduino_GFX.h" 10 #include "font/glcdfont.h" 11 #include "float.h" 12 #ifdef __AVR__ 13 #include <avr/pgmspace.h> 14 #elif defined(ESP8266) || defined(ESP32) 15 #include <pgmspace.h> 16 #endif 17 18 /**************************************************************************/ 19 /*! 20 @brief Instatiate a GFX context for graphics! Can only be done by a superclass 21 @param w Display width, in pixels 22 @param h Display height, in pixels 23 */ 24 /**************************************************************************/ 25 #if defined(LITTLE_FOOT_PRINT) 26 Arduino_GFX::Arduino_GFX(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h) 27 #else 28 Arduino_GFX::Arduino_GFX(int16_t w, int16_t h) : Arduino_G(w, h) 29 #endif // !defined(LITTLE_FOOT_PRINT) 30 { 31 _width = WIDTH; 32 _height = HEIGHT; 33 _max_x = _width - 1; ///< x zero base bound 34 _max_y = _height - 1; ///< y zero base bound 35 _rotation = 0; 36 cursor_y = cursor_x = 0; 37 textsize_x = textsize_y = 1; 38 text_pixel_margin = 0; 39 textcolor = textbgcolor = 0xFFFF; 40 wrap = true; 41 #if !defined(ATTINY_CORE) 42 gfxFont = NULL; 43 #if defined(U8G2_FONT_SUPPORT) 44 u8g2Font = NULL; 45 #endif // defined(U8G2_FONT_SUPPORT) 46 #endif // !defined(ATTINY_CORE) 47 } 48 49 /**************************************************************************/ 50 /*! 51 @brief Write a line. Check straight or slash line and call corresponding function 52 @param x0 Start point x coordinate 53 @param y0 Start point y coordinate 54 @param x1 End point x coordinate 55 @param y1 End point y coordinate 56 @param color 16-bit 5-6-5 Color to draw with 57 */ 58 /**************************************************************************/ 59 void Arduino_GFX::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, 60 uint16_t color) 61 { 62 if (x0 == x1) 63 { 64 if (y0 > y1) 65 { 66 _swap_int16_t(y0, y1); 67 } 68 writeFastVLine(x0, y0, y1 - y0 + 1, color); 69 } 70 else if (y0 == y1) 71 { 72 if (x0 > x1) 73 { 74 _swap_int16_t(x0, x1); 75 } 76 writeFastHLine(x0, y0, x1 - x0 + 1, color); 77 } 78 else 79 { 80 writeSlashLine(x0, y0, x1, y1, color); 81 } 82 } 83 84 /**************************************************************************/ 85 /*! 86 @brief Write a line. Bresenham's algorithm - thx wikpedia 87 @param x0 Start point x coordinate 88 @param y0 Start point y coordinate 89 @param x1 End point x coordinate 90 @param y1 End point y coordinate 91 @param color 16-bit 5-6-5 Color to draw with 92 */ 93 /**************************************************************************/ 94 void Arduino_GFX::writeSlashLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, 95 uint16_t color) 96 { 97 bool steep = _diff(y1, y0) > _diff(x1, x0); 98 if (steep) 99 { 100 _swap_int16_t(x0, y0); 101 _swap_int16_t(x1, y1); 102 } 103 104 if (x0 > x1) 105 { 106 _swap_int16_t(x0, x1); 107 _swap_int16_t(y0, y1); 108 } 109 110 int16_t dx = x1 - x0; 111 int16_t dy = _diff(y1, y0); 112 int16_t err = dx >> 1; 113 int16_t step = (y0 < y1) ? 1 : -1; 114 115 for (; x0 <= x1; x0++) 116 { 117 if (steep) 118 { 119 writePixel(y0, x0, color); 120 } 121 else 122 { 123 writePixel(x0, y0, color); 124 } 125 err -= dy; 126 if (err < 0) 127 { 128 err += dx; 129 y0 += step; 130 } 131 } 132 } 133 134 /**************************************************************************/ 135 /*! 136 @brief Start a display-writing routine, overwrite in subclasses. 137 */ 138 /**************************************************************************/ 139 INLINE void Arduino_GFX::startWrite() 140 { 141 } 142 143 void Arduino_GFX::writePixel(int16_t x, int16_t y, uint16_t color) 144 { 145 if (_ordered_in_range(x, 0, _max_x) && _ordered_in_range(y, 0, _max_y)) 146 { 147 writePixelPreclipped(x, y, color); 148 } 149 } 150 151 /**************************************************************************/ 152 /*! 153 @brief Write a pixel, overwrite in subclasses if startWrite is defined! 154 @param x x coordinate 155 @param y y coordinate 156 @param color 16-bit 5-6-5 Color to fill with 157 */ 158 /**************************************************************************/ 159 void Arduino_GFX::drawPixel(int16_t x, int16_t y, uint16_t color) 160 { 161 startWrite(); 162 writePixel(x, y, color); 163 endWrite(); 164 } 165 166 /**************************************************************************/ 167 /*! 168 @brief Write a perfectly vertical line, overwrite in subclasses if startWrite is defined! 169 @param x Top-most x coordinate 170 @param y Top-most y coordinate 171 @param h Height in pixels 172 @param color 16-bit 5-6-5 Color to fill with 173 */ 174 /**************************************************************************/ 175 void Arduino_GFX::writeFastVLine(int16_t x, int16_t y, 176 int16_t h, uint16_t color) 177 { 178 for (int16_t i = y; i < y + h; i++) 179 { 180 writePixel(x, i, color); 181 } 182 } 183 184 /**************************************************************************/ 185 /*! 186 @brief Write a perfectly horizontal line, overwrite in subclasses if startWrite is defined! 187 @param x Left-most x coordinate 188 @param y Left-most y coordinate 189 @param w Width in pixels 190 @param color 16-bit 5-6-5 Color to fill with 191 */ 192 /**************************************************************************/ 193 void Arduino_GFX::writeFastHLine(int16_t x, int16_t y, 194 int16_t w, uint16_t color) 195 { 196 for (int16_t i = x; i < x + w; i++) 197 { 198 writePixel(i, y, color); 199 } 200 } 201 202 /**************************************************************************/ 203 /*! 204 @brief Draw a filled rectangle to the display. Not self-contained; 205 should follow startWrite(). Typically used by higher-level 206 graphics primitives; user code shouldn't need to call this and 207 is likely to use the self-contained fillRect() instead. 208 writeFillRect() performs its own edge clipping and rejection; 209 see writeFillRectPreclipped() for a more 'raw' implementation. 210 @param x Horizontal position of first corner. 211 @param y Vertical position of first corner. 212 @param w Rectangle width in pixels (positive = right of first 213 corner, negative = left of first corner). 214 @param h Rectangle height in pixels (positive = below first 215 corner, negative = above first corner). 216 @param color 16-bit fill color in '565' RGB format. 217 @note Written in this deep-nested way because C by definition will 218 optimize for the 'if' case, not the 'else' -- avoids branches 219 and rejects clipped rectangles at the least-work possibility. 220 */ 221 /**************************************************************************/ 222 void Arduino_GFX::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, 223 uint16_t color) 224 { 225 if (w && h) 226 { // Nonzero width and height? 227 if (w < 0) 228 { // If negative width... 229 x += w + 1; // Move X to left edge 230 w = -w; // Use positive width 231 } 232 if (x <= _max_x) 233 { // Not off right 234 if (h < 0) 235 { // If negative height... 236 y += h + 1; // Move Y to top edge 237 h = -h; // Use positive height 238 } 239 if (y <= _max_y) 240 { // Not off bottom 241 int16_t x2 = x + w - 1; 242 if (x2 >= 0) 243 { // Not off left 244 int16_t y2 = y + h - 1; 245 if (y2 >= 0) 246 { // Not off top 247 // Rectangle partly or fully overlaps screen 248 if (x < 0) 249 { 250 x = 0; 251 w = x2 + 1; 252 } // Clip left 253 if (y < 0) 254 { 255 y = 0; 256 h = y2 + 1; 257 } // Clip top 258 if (x2 > _max_x) 259 { 260 w = _max_x - x + 1; 261 } // Clip right 262 if (y2 > _max_y) 263 { 264 h = _max_y - y + 1; 265 } // Clip bottom 266 writeFillRectPreclipped(x, y, w, h, color); 267 } 268 } 269 } 270 } 271 } 272 } 273 274 /**************************************************************************/ 275 /*! 276 @brief Write a rectangle completely with one color, overwrite in subclasses if startWrite is defined! 277 @param x Top left corner x coordinate 278 @param y Top left corner y coordinate 279 @param w Width in pixels 280 @param h Height in pixels 281 @param color 16-bit 5-6-5 Color to fill with 282 */ 283 /**************************************************************************/ 284 void Arduino_GFX::writeFillRectPreclipped(int16_t x, int16_t y, int16_t w, int16_t h, 285 uint16_t color) 286 { 287 // Overwrite in subclasses if desired! 288 for (int16_t i = y; i < y + h; i++) 289 { 290 writeFastHLine(x, i, w, color); 291 } 292 } 293 294 /**************************************************************************/ 295 /*! 296 @brief End a display-writing routine, overwrite in subclasses if startWrite is defined! 297 */ 298 /**************************************************************************/ 299 INLINE void Arduino_GFX::endWrite() 300 { 301 } 302 303 /**************************************************************************/ 304 /*! 305 @brief Draw a perfectly vertical line (this is often optimized in a subclass!) 306 @param x Top-most x coordinate 307 @param y Top-most y coordinate 308 @param h Height in pixels 309 @param color 16-bit 5-6-5 Color to fill with 310 */ 311 /**************************************************************************/ 312 void Arduino_GFX::drawFastVLine(int16_t x, int16_t y, 313 int16_t h, uint16_t color) 314 { 315 startWrite(); 316 writeFastVLine(x, y, h, color); 317 endWrite(); 318 } 319 320 /**************************************************************************/ 321 /*! 322 @brief Draw a perfectly horizontal line (this is often optimized in a subclass!) 323 @param x Left-most x coordinate 324 @param y Left-most y coordinate 325 @param w Width in pixels 326 @param color 16-bit 5-6-5 Color to fill with 327 */ 328 /**************************************************************************/ 329 void Arduino_GFX::drawFastHLine(int16_t x, int16_t y, 330 int16_t w, uint16_t color) 331 { 332 startWrite(); 333 writeFastHLine(x, y, w, color); 334 endWrite(); 335 } 336 337 /**************************************************************************/ 338 /*! 339 @brief Fill a rectangle completely with one color. Update in subclasses if desired! 340 @param x Top left corner x coordinate 341 @param y Top left corner y coordinate 342 @param w Width in pixels 343 @param h Height in pixels 344 @param color 16-bit 5-6-5 Color to fill with 345 */ 346 /**************************************************************************/ 347 void Arduino_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, 348 uint16_t color) 349 { 350 startWrite(); 351 writeFillRect(x, y, w, h, color); 352 endWrite(); 353 } 354 355 /**************************************************************************/ 356 /*! 357 @brief Fill the screen completely with one color. Update in subclasses if desired! 358 @param color 16-bit 5-6-5 Color to fill with 359 */ 360 /**************************************************************************/ 361 void Arduino_GFX::fillScreen(uint16_t color) 362 { 363 fillRect(0, 0, _width, _height, color); 364 } 365 366 /**************************************************************************/ 367 /*! 368 @brief Draw a line 369 @param x0 Start point x coordinate 370 @param y0 Start point y coordinate 371 @param x1 End point x coordinate 372 @param y1 End point y coordinate 373 @param color 16-bit 5-6-5 Color to draw with 374 */ 375 /**************************************************************************/ 376 void Arduino_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, 377 uint16_t color) 378 { 379 // Update in subclasses if desired! 380 startWrite(); 381 writeLine(x0, y0, x1, y1, color); 382 endWrite(); 383 } 384 385 /**************************************************************************/ 386 /*! 387 @brief Draw a circle outline 388 @param x Center-point x coordinate 389 @param y Center-point y coordinate 390 @param r Radius of circle 391 @param color 16-bit 5-6-5 Color to draw with 392 */ 393 /**************************************************************************/ 394 void Arduino_GFX::drawCircle(int16_t x, int16_t y, 395 int16_t r, uint16_t color) 396 { 397 startWrite(); 398 drawEllipseHelper(x, y, r, r, 0xf, color); 399 endWrite(); 400 } 401 402 /**************************************************************************/ 403 /*! 404 @brief Quarter-ellipse drawer, used to do circles and roundrects 405 @param x Center-point x coordinate 406 @param y Center-point y coordinate 407 @param rx radius of x coordinate 408 @param ry radius of y coordinate 409 @param cornername Mask bit #1 or bit #2 to indicate which quarters of the circle we're doing 410 @param color 16-bit 5-6-5 Color to draw with 411 */ 412 /**************************************************************************/ 413 void Arduino_GFX::drawEllipseHelper(int32_t x, int32_t y, 414 int32_t rx, int32_t ry, 415 uint8_t cornername, uint16_t color) 416 { 417 if (rx < 0 || ry < 0 || ((rx == 0) && (ry == 0))) 418 { 419 return; 420 } 421 if (ry == 0) 422 { 423 drawFastHLine(x - rx, y, (ry << 2) + 1, color); 424 return; 425 } 426 if (rx == 0) 427 { 428 drawFastVLine(x, y - ry, (rx << 2) + 1, color); 429 return; 430 } 431 432 int32_t xt, yt, s, i; 433 int32_t rx2 = rx * rx; 434 int32_t ry2 = ry * ry; 435 436 i = -1; 437 xt = 0; 438 yt = ry; 439 s = (ry2 << 1) + rx2 * (1 - (ry << 1)); 440 do 441 { 442 while (s < 0) 443 s += ry2 * ((++xt << 2) + 2); 444 if (cornername & 0x1) 445 { 446 writeFastHLine(x - xt, y - yt, xt - i, color); 447 } 448 if (cornername & 0x2) 449 { 450 writeFastHLine(x + i + 1, y - yt, xt - i, color); 451 } 452 if (cornername & 0x4) 453 { 454 writeFastHLine(x + i + 1, y + yt, xt - i, color); 455 } 456 if (cornername & 0x8) 457 { 458 writeFastHLine(x - xt, y + yt, xt - i, color); 459 } 460 i = xt; 461 s -= (--yt) * rx2 << 2; 462 } while (ry2 * xt <= rx2 * yt); 463 464 i = -1; 465 yt = 0; 466 xt = rx; 467 s = (rx2 << 1) + ry2 * (1 - (rx << 1)); 468 do 469 { 470 while (s < 0) 471 s += rx2 * ((++yt << 2) + 2); 472 if (cornername & 0x1) 473 { 474 writeFastVLine(x - xt, y - yt, yt - i, color); 475 } 476 if (cornername & 0x2) 477 { 478 writeFastVLine(x + xt, y - yt, yt - i, color); 479 } 480 if (cornername & 0x4) 481 { 482 writeFastVLine(x + xt, y + i + 1, yt - i, color); 483 } 484 if (cornername & 0x8) 485 { 486 writeFastVLine(x - xt, y + i + 1, yt - i, color); 487 } 488 i = yt; 489 s -= (--xt) * ry2 << 2; 490 } while (rx2 * yt <= ry2 * xt); 491 } 492 493 /**************************************************************************/ 494 /*! 495 @brief Draw a circle with filled color 496 @param x Center-point x coordinate 497 @param y Center-point y coordinate 498 @param r Radius of circle 499 @param color 16-bit 5-6-5 Color to fill with 500 */ 501 /**************************************************************************/ 502 void Arduino_GFX::fillCircle(int16_t x, int16_t y, 503 int16_t r, uint16_t color) 504 { 505 startWrite(); 506 fillEllipseHelper(x, y, r, r, 3, 0, color); 507 endWrite(); 508 } 509 510 /**************************************************************************/ 511 /*! 512 @brief Quarter-circle drawer with fill, used for circles and roundrects 513 @param x Center-point x coordinate 514 @param y Center-point y coordinate 515 @param rx Radius of x coordinate 516 @param ry Radius of y coordinate 517 @param corners Mask bits indicating which quarters we're doing 518 @param delta Offset from center-point, used for round-rects 519 @param color 16-bit 5-6-5 Color to fill with 520 */ 521 /**************************************************************************/ 522 void Arduino_GFX::fillEllipseHelper(int32_t x, int32_t y, 523 int32_t rx, int32_t ry, 524 uint8_t corners, int16_t delta, uint16_t color) 525 { 526 if (rx < 0 || ry < 0 || ((rx == 0) && (ry == 0))) 527 { 528 return; 529 } 530 if (ry == 0) 531 { 532 drawFastHLine(x - rx, y, (ry << 2) + 1, color); 533 return; 534 } 535 if (rx == 0) 536 { 537 drawFastVLine(x, y - ry, (rx << 2) + 1, color); 538 return; 539 } 540 541 int32_t xt, yt, i; 542 int32_t rx2 = (int32_t)rx * rx; 543 int32_t ry2 = (int32_t)ry * ry; 544 int32_t s; 545 546 writeFastHLine(x - rx, y, (rx << 1) + 1, color); 547 i = 0; 548 yt = 0; 549 xt = rx; 550 s = (rx2 << 1) + ry2 * (1 - (rx << 1)); 551 do 552 { 553 while (s < 0) 554 { 555 s += rx2 * ((++yt << 2) + 2); 556 } 557 if (corners & 1) 558 { 559 writeFillRect(x - xt, y - yt, (xt << 1) + 1 + delta, yt - i, color); 560 } 561 if (corners & 2) 562 { 563 writeFillRect(x - xt, y + i + 1, (xt << 1) + 1 + delta, yt - i, color); 564 } 565 i = yt; 566 s -= (--xt) * ry2 << 2; 567 } while (rx2 * yt <= ry2 * xt); 568 569 xt = 0; 570 yt = ry; 571 s = (ry2 << 1) + rx2 * (1 - (ry << 1)); 572 do 573 { 574 while (s < 0) 575 { 576 s += ry2 * ((++xt << 2) + 2); 577 } 578 if (corners & 1) 579 { 580 writeFastHLine(x - xt, y - yt, (xt << 1) + 1 + delta, color); 581 } 582 if (corners & 2) 583 { 584 writeFastHLine(x - xt, y + yt, (xt << 1) + 1 + delta, color); 585 } 586 s -= (--yt) * rx2 << 2; 587 } while (ry2 * xt <= rx2 * yt); 588 } 589 590 /**************************************************************************/ 591 /*! 592 @brief Draw an ellipse outline 593 @param x Center-point x coordinate 594 @param y Center-point y coordinate 595 @param rx radius of x coordinate 596 @param ry radius of y coordinate 597 @param start degree of ellipse start 598 @param end degree of ellipse end 599 @param color 16-bit 5-6-5 Color to draw with 600 */ 601 /**************************************************************************/ 602 void Arduino_GFX::drawEllipse(int16_t x, int16_t y, int16_t rx, int16_t ry, uint16_t color) 603 { 604 startWrite(); 605 drawEllipseHelper(x, y, rx, ry, 0xf, color); 606 endWrite(); 607 } 608 609 /**************************************************************************/ 610 /*! 611 @brief Draw an ellipse with filled color 612 @param x Center-point x coordinate 613 @param y Center-point y coordinate 614 @param rx radius of x coordinate 615 @param ry radius of y coordinate 616 @param start degree of ellipse start 617 @param end degree of ellipse end 618 @param color 16-bit 5-6-5 Color to fill with 619 */ 620 /**************************************************************************/ 621 void Arduino_GFX::fillEllipse(int16_t x, int16_t y, int16_t rx, int16_t ry, uint16_t color) 622 { 623 startWrite(); 624 fillEllipseHelper(x, y, rx, ry, 3, 0, color); 625 endWrite(); 626 } 627 628 /**************************************************************************/ 629 /*! 630 @brief Draw an arc outline 631 @param x Center-point x coordinate 632 @param y Center-point y coordinate 633 @param r1 Outer radius of arc 634 @param r2 Inner radius of arc 635 @param start degree of arc start 636 @param end degree of arc end 637 @param color 16-bit 5-6-5 Color to draw with 638 */ 639 /**************************************************************************/ 640 void Arduino_GFX::drawArc(int16_t x, int16_t y, int16_t r1, int16_t r2, float start, float end, uint16_t color) 641 { 642 if (r1 < r2) 643 { 644 _swap_int16_t(r1, r2); 645 } 646 if (r1 < 1) 647 { 648 r1 = 1; 649 } 650 if (r2 < 1) 651 { 652 r2 = 1; 653 } 654 bool equal = fabsf(start - end) < FLT_EPSILON; 655 start = fmodf(start, 360); 656 end = fmodf(end, 360); 657 if (start < 0) 658 start += 360.0; 659 if (end < 0) 660 end += 360.0; 661 662 startWrite(); 663 fillArcHelper(x, y, r1, r2, start, start, color); 664 fillArcHelper(x, y, r1, r2, end, end, color); 665 if (!equal && (fabsf(start - end) <= 0.0001)) 666 { 667 start = .0; 668 end = 360.0; 669 } 670 fillArcHelper(x, y, r1, r1, start, end, color); 671 fillArcHelper(x, y, r2, r2, start, end, color); 672 endWrite(); 673 } 674 675 /**************************************************************************/ 676 /*! 677 @brief Draw an arc with filled color 678 @param x Center-point x coordinate 679 @param y Center-point y coordinate 680 @param r1 Outer radius of arc 681 @param r2 Inner radius of arc 682 @param start degree of arc start 683 @param end degree of arc end 684 @param color 16-bit 5-6-5 Color to fill with 685 */ 686 /**************************************************************************/ 687 void Arduino_GFX::fillArc(int16_t x, int16_t y, int16_t r1, int16_t r2, float start, float end, uint16_t color) 688 { 689 if (r1 < r2) 690 { 691 _swap_int16_t(r1, r2); 692 } 693 if (r1 < 1) 694 { 695 r1 = 1; 696 } 697 if (r2 < 1) 698 { 699 r2 = 1; 700 } 701 bool equal = fabsf(start - end) < FLT_EPSILON; 702 start = fmodf(start, 360); 703 end = fmodf(end, 360); 704 if (start < 0) 705 start += 360.0; 706 if (end < 0) 707 end += 360.0; 708 if (!equal && (fabsf(start - end) <= 0.0001)) 709 { 710 start = .0; 711 end = 360.0; 712 } 713 714 startWrite(); 715 fillArcHelper(x, y, r1, r2, start, end, color); 716 endWrite(); 717 } 718 719 /**************************************************************************/ 720 /*! 721 @brief Arc drawer with fill 722 @param cx Center-point x coordinate 723 @param cy Center-point y coordinate 724 @param oradius Outer radius of arc 725 @param iradius Inner radius of arc 726 @param start degree of arc start 727 @param end degree of arc end 728 @param color 16-bit 5-6-5 Color to fill with 729 */ 730 /**************************************************************************/ 731 void Arduino_GFX::fillArcHelper(int16_t cx, int16_t cy, int16_t oradius, int16_t iradius, float start, float end, uint16_t color) 732 { 733 if ((start == 90.0) || (start == 180.0) || (start == 270.0) || (start == 360.0)) 734 { 735 start -= 0.1; 736 } 737 738 if ((end == 90.0) || (end == 180.0) || (end == 270.0) || (end == 360.0)) 739 { 740 end -= 0.1; 741 } 742 743 float s_cos = (cos(start * DEGTORAD)); 744 float e_cos = (cos(end * DEGTORAD)); 745 float sslope = s_cos / (sin(start * DEGTORAD)); 746 float eslope = e_cos / (sin(end * DEGTORAD)); 747 float swidth = 0.5 / s_cos; 748 float ewidth = -0.5 / e_cos; 749 --iradius; 750 int32_t ir2 = iradius * iradius + iradius; 751 int32_t or2 = oradius * oradius + oradius; 752 753 bool start180 = !(start < 180.0); 754 bool end180 = end < 180.0; 755 bool reversed = start + 180.0 < end || (end < start && start < end + 180.0); 756 757 int32_t xs = -oradius; 758 int32_t y = -oradius; 759 int32_t ye = oradius; 760 int32_t xe = oradius + 1; 761 if (!reversed) 762 { 763 if ((end >= 270 || end < 90) && (start >= 270 || start < 90)) 764 { 765 xs = 0; 766 } 767 else if (end < 270 && end >= 90 && start < 270 && start >= 90) 768 { 769 xe = 1; 770 } 771 if (end >= 180 && start >= 180) 772 { 773 ye = 0; 774 } 775 else if (end < 180 && start < 180) 776 { 777 y = 0; 778 } 779 } 780 do 781 { 782 int32_t y2 = y * y; 783 int32_t x = xs; 784 if (x < 0) 785 { 786 while (x * x + y2 >= or2) 787 { 788 ++x; 789 } 790 if (xe != 1) 791 { 792 xe = 1 - x; 793 } 794 } 795 float ysslope = (y + swidth) * sslope; 796 float yeslope = (y + ewidth) * eslope; 797 int32_t len = 0; 798 do 799 { 800 bool flg1 = start180 != (x <= ysslope); 801 bool flg2 = end180 != (x <= yeslope); 802 int32_t distance = x * x + y2; 803 if (distance >= ir2 && ((flg1 && flg2) || (reversed && (flg1 || flg2))) && x != xe && distance < or2) 804 { 805 ++len; 806 } 807 else 808 { 809 if (len) 810 { 811 writeFastHLine(cx + x - len, cy + y, len, color); 812 len = 0; 813 } 814 if (distance >= or2) 815 break; 816 if (x < 0 && distance < ir2) 817 { 818 x = -x; 819 } 820 } 821 } while (++x <= xe); 822 } while (++y <= ye); 823 } 824 825 /**************************************************************************/ 826 /*! 827 @brief Draw a rectangle with no fill color 828 @param x Top left corner x coordinate 829 @param y Top left corner y coordinate 830 @param w Width in pixels 831 @param h Height in pixels 832 @param color 16-bit 5-6-5 Color to draw with 833 */ 834 /**************************************************************************/ 835 void Arduino_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, 836 uint16_t color) 837 { 838 startWrite(); 839 writeFastHLine(x, y, w, color); 840 writeFastHLine(x, y + h - 1, w, color); 841 writeFastVLine(x, y, h, color); 842 writeFastVLine(x + w - 1, y, h, color); 843 endWrite(); 844 } 845 846 /**************************************************************************/ 847 /*! 848 @brief Draw a rounded rectangle with no fill color 849 @param x Top left corner x coordinate 850 @param y Top left corner y coordinate 851 @param w Width in pixels 852 @param h Height in pixels 853 @param r Radius of corner rounding 854 @param color 16-bit 5-6-5 Color to draw with 855 */ 856 /**************************************************************************/ 857 void Arduino_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w, 858 int16_t h, int16_t r, uint16_t color) 859 { 860 int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis 861 if (r > max_radius) 862 r = max_radius; 863 // smarter version 864 startWrite(); 865 writeFastHLine(x + r, y, w - 2 * r, color); // Top 866 writeFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom 867 writeFastVLine(x, y + r, h - 2 * r, color); // Left 868 writeFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right 869 // draw four corners 870 drawEllipseHelper(x + r, y + r, r, r, 1, color); 871 drawEllipseHelper(x + w - r - 1, y + r, r, r, 2, color); 872 drawEllipseHelper(x + w - r - 1, y + h - r - 1, r, r, 4, color); 873 drawEllipseHelper(x + r, y + h - r - 1, r, r, 8, color); 874 endWrite(); 875 } 876 877 /**************************************************************************/ 878 /*! 879 @brief Draw a rounded rectangle with fill color 880 @param x Top left corner x coordinate 881 @param y Top left corner y coordinate 882 @param w Width in pixels 883 @param h Height in pixels 884 @param r Radius of corner rounding 885 @param color 16-bit 5-6-5 Color to draw/fill with 886 */ 887 /**************************************************************************/ 888 void Arduino_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w, 889 int16_t h, int16_t r, uint16_t color) 890 { 891 int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis 892 if (r > max_radius) 893 r = max_radius; 894 // smarter version 895 startWrite(); 896 writeFillRect(x, y + r, w, h - (r << 1), color); 897 // draw four corners 898 fillEllipseHelper(x + r, y + r, r, r, 1, w - 2 * r - 1, color); 899 fillEllipseHelper(x + r, y + h - r - 1, r, r, 2, w - 2 * r - 1, color); 900 endWrite(); 901 } 902 903 /**************************************************************************/ 904 /*! 905 @brief Draw a triangle with no fill color 906 @param x0 Vertex #0 x coordinate 907 @param y0 Vertex #0 y coordinate 908 @param x1 Vertex #1 x coordinate 909 @param y1 Vertex #1 y coordinate 910 @param x2 Vertex #2 x coordinate 911 @param y2 Vertex #2 y coordinate 912 @param color 16-bit 5-6-5 Color to draw with 913 */ 914 /**************************************************************************/ 915 void Arduino_GFX::drawTriangle(int16_t x0, int16_t y0, 916 int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) 917 { 918 startWrite(); 919 writeLine(x0, y0, x1, y1, color); 920 writeLine(x1, y1, x2, y2, color); 921 writeLine(x2, y2, x0, y0, color); 922 endWrite(); 923 } 924 925 /**************************************************************************/ 926 /*! 927 @brief Draw a triangle with color-fill 928 @param x0 Vertex #0 x coordinate 929 @param y0 Vertex #0 y coordinate 930 @param x1 Vertex #1 x coordinate 931 @param y1 Vertex #1 y coordinate 932 @param x2 Vertex #2 x coordinate 933 @param y2 Vertex #2 y coordinate 934 @param color 16-bit 5-6-5 Color to fill/draw with 935 */ 936 /**************************************************************************/ 937 void Arduino_GFX::fillTriangle(int16_t x0, int16_t y0, 938 int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) 939 { 940 int16_t a, b, y, last; 941 942 // Sort coordinates by Y order (y2 >= y1 >= y0) 943 if (y0 > y1) 944 { 945 _swap_int16_t(y0, y1); 946 _swap_int16_t(x0, x1); 947 } 948 if (y1 > y2) 949 { 950 _swap_int16_t(y2, y1); 951 _swap_int16_t(x2, x1); 952 } 953 if (y0 > y1) 954 { 955 _swap_int16_t(y0, y1); 956 _swap_int16_t(x0, x1); 957 } 958 959 startWrite(); 960 if (y0 == y2) 961 { // Handle awkward all-on-same-line case as its own thing 962 a = b = x0; 963 if (x1 < a) 964 a = x1; 965 else if (x1 > b) 966 b = x1; 967 if (x2 < a) 968 a = x2; 969 else if (x2 > b) 970 b = x2; 971 writeFastHLine(a, y0, b - a + 1, color); 972 endWrite(); 973 return; 974 } 975 976 int16_t 977 dx01 = x1 - x0, 978 dy01 = y1 - y0, 979 dx02 = x2 - x0, 980 dy02 = y2 - y0, 981 dx12 = x2 - x1, 982 dy12 = y2 - y1; 983 int32_t 984 sa = 0, 985 sb = 0; 986 987 // For upper part of triangle, find scanline crossings for segments 988 // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 989 // is included here (and second loop will be skipped, avoiding a /0 990 // error there), otherwise scanline y1 is skipped here and handled 991 // in the second loop...which also avoids a /0 error here if y0=y1 992 // (flat-topped triangle). 993 if (y1 == y2) 994 { 995 last = y1; // Include y1 scanline 996 } 997 else 998 { 999 last = y1 - 1; // Skip it 1000 } 1001 1002 for (y = y0; y <= last; y++) 1003 { 1004 a = x0 + sa / dy01; 1005 b = x0 + sb / dy02; 1006 sa += dx01; 1007 sb += dx02; 1008 /* longhand: 1009 a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); 1010 b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); 1011 */ 1012 if (a > b) 1013 { 1014 _swap_int16_t(a, b); 1015 } 1016 writeFastHLine(a, y, b - a + 1, color); 1017 } 1018 1019 // For lower part of triangle, find scanline crossings for segments 1020 // 0-2 and 1-2. This loop is skipped if y1=y2. 1021 sa = (int32_t)dx12 * (y - y1); 1022 sb = (int32_t)dx02 * (y - y0); 1023 for (; y <= y2; y++) 1024 { 1025 a = x1 + sa / dy12; 1026 b = x0 + sb / dy02; 1027 sa += dx12; 1028 sb += dx02; 1029 /* longhand: 1030 a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); 1031 b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); 1032 */ 1033 if (a > b) 1034 { 1035 _swap_int16_t(a, b); 1036 } 1037 writeFastHLine(a, y, b - a + 1, color); 1038 } 1039 endWrite(); 1040 } 1041 1042 // BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS --------------------- 1043 1044 /**************************************************************************/ 1045 /*! 1046 @brief Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground color (unset bits are transparent). 1047 @param x Top left corner x coordinate 1048 @param y Top left corner y coordinate 1049 @param bitmap byte array with monochrome bitmap 1050 @param w Width of bitmap in pixels 1051 @param h Height of bitmap in pixels 1052 @param color 16-bit 5-6-5 Color to draw with 1053 */ 1054 /**************************************************************************/ 1055 void Arduino_GFX::drawBitmap(int16_t x, int16_t y, 1056 const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) 1057 { 1058 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte 1059 uint8_t byte = 0; 1060 1061 startWrite(); 1062 for (int16_t j = 0; j < h; j++, y++) 1063 { 1064 for (int16_t i = 0; i < w; i++) 1065 { 1066 if (i & 7) 1067 { 1068 byte <<= 1; 1069 } 1070 else 1071 { 1072 byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); 1073 } 1074 if (byte & 0x80) 1075 { 1076 writePixel(x + i, y, color); 1077 } 1078 } 1079 } 1080 endWrite(); 1081 } 1082 1083 /**************************************************************************/ 1084 /*! 1085 @brief Draw a PROGMEM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors. 1086 @param x Top left corner x coordinate 1087 @param y Top left corner y coordinate 1088 @param bitmap byte array with monochrome bitmap 1089 @param w Width of bitmap in pixels 1090 @param h Height of bitmap in pixels 1091 @param color 16-bit 5-6-5 Color to draw pixels with 1092 @param bg 16-bit 5-6-5 Color to draw background with 1093 */ 1094 /**************************************************************************/ 1095 void Arduino_GFX::drawBitmap(int16_t x, int16_t y, 1096 const uint8_t bitmap[], int16_t w, int16_t h, 1097 uint16_t color, uint16_t bg) 1098 { 1099 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte 1100 uint8_t byte = 0; 1101 1102 startWrite(); 1103 for (int16_t j = 0; j < h; j++, y++) 1104 { 1105 for (int16_t i = 0; i < w; i++) 1106 { 1107 if (i & 7) 1108 { 1109 byte <<= 1; 1110 } 1111 else 1112 { 1113 byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); 1114 } 1115 writePixel(x + i, y, (byte & 0x80) ? color : bg); 1116 } 1117 } 1118 endWrite(); 1119 } 1120 1121 /**************************************************************************/ 1122 /*! 1123 @brief Draw a RAM-resident 1-bit image at the specified (x,y) position, using the specified foreground color (unset bits are transparent). 1124 @param x Top left corner x coordinate 1125 @param y Top left corner y coordinate 1126 @param bitmap byte array with monochrome bitmap 1127 @param w Width of bitmap in pixels 1128 @param h Height of bitmap in pixels 1129 @param color 16-bit 5-6-5 Color to draw with 1130 */ 1131 /**************************************************************************/ 1132 void Arduino_GFX::drawBitmap(int16_t x, int16_t y, 1133 uint8_t *bitmap, int16_t w, int16_t h, uint16_t color) 1134 { 1135 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte 1136 uint8_t byte = 0; 1137 1138 startWrite(); 1139 for (int16_t j = 0; j < h; j++, y++) 1140 { 1141 for (int16_t i = 0; i < w; i++) 1142 { 1143 if (i & 7) 1144 { 1145 byte <<= 1; 1146 } 1147 else 1148 { 1149 byte = bitmap[j * byteWidth + i / 8]; 1150 } 1151 if (byte & 0x80) 1152 { 1153 writePixel(x + i, y, color); 1154 } 1155 } 1156 } 1157 endWrite(); 1158 } 1159 1160 /**************************************************************************/ 1161 /*! 1162 @brief Draw a RAM-resident 1-bit image at the specified (x,y) position, using the specified foreground (for set bits) and background (unset bits) colors. 1163 @param x Top left corner x coordinate 1164 @param y Top left corner y coordinate 1165 @param bitmap byte array with monochrome bitmap 1166 @param w Width of bitmap in pixels 1167 @param h Height of bitmap in pixels 1168 @param color 16-bit 5-6-5 Color to draw pixels with 1169 @param bg 16-bit 5-6-5 Color to draw background with 1170 */ 1171 /**************************************************************************/ 1172 void Arduino_GFX::drawBitmap(int16_t x, int16_t y, 1173 uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) 1174 { 1175 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte 1176 uint8_t byte = 0; 1177 1178 startWrite(); 1179 for (int16_t j = 0; j < h; j++, y++) 1180 { 1181 for (int16_t i = 0; i < w; i++) 1182 { 1183 if (i & 7) 1184 { 1185 byte <<= 1; 1186 } 1187 else 1188 { 1189 byte = bitmap[j * byteWidth + i / 8]; 1190 } 1191 writePixel(x + i, y, (byte & 0x80) ? color : bg); 1192 } 1193 } 1194 endWrite(); 1195 } 1196 1197 /**************************************************************************/ 1198 /*! 1199 @brief Draw PROGMEM-resident XBitMap Files (*.xbm), exported from GIMP. 1200 Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor. 1201 C Array can be directly used with this function. 1202 There is no RAM-resident version of this function; if generating bitmaps 1203 in RAM, use the format defined by drawBitmap() and call that instead. 1204 @param x Top left corner x coordinate 1205 @param y Top left corner y coordinate 1206 @param bitmap byte array with monochrome bitmap 1207 @param w Width of bitmap in pixels 1208 @param h Height of bitmap in pixels 1209 @param color 16-bit 5-6-5 Color to draw pixels with 1210 */ 1211 /**************************************************************************/ 1212 void Arduino_GFX::drawXBitmap(int16_t x, int16_t y, 1213 const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color) 1214 { 1215 int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte 1216 uint8_t byte = 0; 1217 1218 startWrite(); 1219 for (int16_t j = 0; j < h; j++, y++) 1220 { 1221 for (int16_t i = 0; i < w; i++) 1222 { 1223 if (i & 7) 1224 { 1225 byte >>= 1; 1226 } 1227 else 1228 { 1229 byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); 1230 } 1231 // Nearly identical to drawBitmap(), only the bit order 1232 // is reversed here (left-to-right = LSB to MSB): 1233 if (byte & 0x01) 1234 { 1235 writePixel(x + i, y, color); 1236 } 1237 } 1238 } 1239 endWrite(); 1240 } 1241 1242 /**************************************************************************/ 1243 /*! 1244 @brief Draw a PROGMEM-resident 8-bit image (grayscale) at the specified (x,y) pos. 1245 @param x Top left corner x coordinate 1246 @param y Top left corner y coordinate 1247 @param bitmap byte array with grayscale bitmap 1248 @param w Width of bitmap in pixels 1249 @param h Height of bitmap in pixels 1250 */ 1251 /**************************************************************************/ 1252 void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, 1253 const uint8_t bitmap[], int16_t w, int16_t h) 1254 { 1255 uint8_t v; 1256 startWrite(); 1257 for (int16_t j = 0; j < h; j++, y++) 1258 { 1259 for (int16_t i = 0; i < w; i++) 1260 { 1261 v = (uint8_t)pgm_read_byte(&bitmap[j * w + i]); 1262 writePixel(x + i, y, color565(v, v, v)); 1263 } 1264 } 1265 endWrite(); 1266 } 1267 1268 /**************************************************************************/ 1269 /*! 1270 @brief Draw a RAM-resident 8-bit image (grayscale) at the specified (x,y) pos. 1271 @param x Top left corner x coordinate 1272 @param y Top left corner y coordinate 1273 @param bitmap byte array with grayscale bitmap 1274 @param w Width of bitmap in pixels 1275 @param h Height of bitmap in pixels 1276 */ 1277 /**************************************************************************/ 1278 void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, 1279 uint8_t *bitmap, int16_t w, int16_t h) 1280 { 1281 uint8_t v; 1282 startWrite(); 1283 for (int16_t j = 0; j < h; j++, y++) 1284 { 1285 for (int16_t i = 0; i < w; i++) 1286 { 1287 v = bitmap[j * w + i]; 1288 writePixel(x + i, y, color565(v, v, v)); 1289 } 1290 } 1291 endWrite(); 1292 } 1293 1294 /**************************************************************************/ 1295 /*! 1296 @brief Draw a PROGMEM-resident 8-bit image (grayscale) with a 1-bit mask 1297 (set bits = opaque, unset bits = clear) at the specified (x,y) position. 1298 BOTH buffers (grayscale and mask) must be PROGMEM-resident. 1299 @param x Top left corner x coordinate 1300 @param y Top left corner y coordinate 1301 @param bitmap byte array with grayscale bitmap 1302 @param mask byte array with mask bitmap 1303 @param w Width of bitmap in pixels 1304 @param h Height of bitmap in pixels 1305 */ 1306 /**************************************************************************/ 1307 void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, 1308 const uint8_t bitmap[], const uint8_t mask[], 1309 int16_t w, int16_t h) 1310 { 1311 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte 1312 uint8_t byte = 0; 1313 uint8_t v; 1314 startWrite(); 1315 for (int16_t j = 0; j < h; j++, y++) 1316 { 1317 for (int16_t i = 0; i < w; i++) 1318 { 1319 if (i & 7) 1320 { 1321 byte <<= 1; 1322 } 1323 else 1324 { 1325 byte = pgm_read_byte(&mask[j * bw + i / 8]); 1326 } 1327 if (byte & 0x80) 1328 { 1329 v = (uint8_t)pgm_read_byte(&bitmap[j * w + i]); 1330 writePixel(x + i, y, color565(v, v, v)); 1331 } 1332 } 1333 } 1334 endWrite(); 1335 } 1336 1337 /**************************************************************************/ 1338 /*! 1339 @brief Draw a RAM-resident 8-bit image (grayscale) with a 1-bit mask 1340 (set bits = opaque, unset bits = clear) at the specified (x,y) position. 1341 BOTH buffers (grayscale and mask) must be RAM-residentt, no mix-and-match 1342 @param x Top left corner x coordinate 1343 @param y Top left corner y coordinate 1344 @param bitmap byte array with grayscale bitmap 1345 @param mask byte array with mask bitmap 1346 @param w Width of bitmap in pixels 1347 @param h Height of bitmap in pixels 1348 */ 1349 /**************************************************************************/ 1350 void Arduino_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, 1351 uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h) 1352 { 1353 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte 1354 uint8_t byte = 0; 1355 uint8_t v; 1356 startWrite(); 1357 for (int16_t j = 0; j < h; j++, y++) 1358 { 1359 for (int16_t i = 0; i < w; i++) 1360 { 1361 if (i & 7) 1362 { 1363 byte <<= 1; 1364 } 1365 else 1366 { 1367 byte = mask[j * bw + i / 8]; 1368 } 1369 if (byte & 0x80) 1370 { 1371 v = bitmap[j * w + i]; 1372 writePixel(x + i, y, color565(v, v, v)); 1373 } 1374 } 1375 } 1376 endWrite(); 1377 } 1378 1379 /**************************************************************************/ 1380 /*! 1381 @brief Draw a Indexed 16-bit image (RGB 5/6/5) at the specified (x,y) position. 1382 @param x Top left corner x coordinate 1383 @param y Top left corner y coordinate 1384 @param bitmap byte array of Indexed color bitmap 1385 @param color_index byte array of 16-bit color index 1386 @param w Width of bitmap in pixels 1387 @param h Height of bitmap in pixels 1388 */ 1389 /**************************************************************************/ 1390 void Arduino_GFX::drawIndexedBitmap(int16_t x, int16_t y, 1391 uint8_t *bitmap, uint16_t *color_index, int16_t w, int16_t h) 1392 { 1393 int32_t offset = 0; 1394 startWrite(); 1395 for (int16_t j = 0; j < h; j++, y++) 1396 { 1397 for (int16_t i = 0; i < w; i++) 1398 { 1399 writePixel(x + i, y, color_index[bitmap[offset++]]); 1400 } 1401 } 1402 endWrite(); 1403 } 1404 1405 /**************************************************************************/ 1406 /*! 1407 @brief Draw a RAM-resident 3-bit image (RGB 1/1/1) at the specified (x,y) position. 1408 @param x Top left corner x coordinate 1409 @param y Top left corner y coordinate 1410 @param bitmap byte array with 3-bit color bitmap 1411 @param w Width of bitmap in pixels 1412 @param h Height of bitmap in pixels 1413 */ 1414 /**************************************************************************/ 1415 void Arduino_GFX::draw3bitRGBBitmap(int16_t x, int16_t y, 1416 uint8_t *bitmap, int16_t w, int16_t h) 1417 { 1418 int32_t offset = 0, idx = 0; 1419 uint8_t c = 0; 1420 uint16_t d; 1421 startWrite(); 1422 for (int16_t j = 0; j < h; j++, y++) 1423 { 1424 for (int16_t i = 0; i < w; i++) 1425 { 1426 if (offset & 1) 1427 { 1428 d = (((c & 0b100) ? RED : 0) | 1429 ((c & 0b010) ? GREEN : 0) | 1430 ((c & 0b001) ? BLUE : 0)); 1431 } 1432 else 1433 { 1434 c = bitmap[idx++]; 1435 d = (((c & 0b100000) ? RED : 0) | 1436 ((c & 0b010000) ? GREEN : 0) | 1437 ((c & 0b001000) ? BLUE : 0)); 1438 } 1439 writePixel(x + i, y, d); 1440 offset++; 1441 } 1442 } 1443 endWrite(); 1444 } 1445 1446 /**************************************************************************/ 1447 /*! 1448 @brief Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position. 1449 @param x Top left corner x coordinate 1450 @param y Top left corner y coordinate 1451 @param bitmap byte array with 16-bit color bitmap 1452 @param w Width of bitmap in pixels 1453 @param h Height of bitmap in pixels 1454 */ 1455 /**************************************************************************/ 1456 void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y, 1457 const uint16_t bitmap[], int16_t w, int16_t h) 1458 { 1459 int32_t offset = 0; 1460 startWrite(); 1461 for (int16_t j = 0; j < h; j++, y++) 1462 { 1463 for (int16_t i = 0; i < w; i++) 1464 { 1465 writePixel(x + i, y, pgm_read_word(&bitmap[offset++])); 1466 } 1467 } 1468 endWrite(); 1469 } 1470 1471 /**************************************************************************/ 1472 /*! 1473 @brief Draw a RAM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) position. 1474 @param x Top left corner x coordinate 1475 @param y Top left corner y coordinate 1476 @param bitmap byte array with 16-bit color bitmap 1477 @param w Width of bitmap in pixels 1478 @param h Height of bitmap in pixels 1479 */ 1480 /**************************************************************************/ 1481 void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y, 1482 uint16_t *bitmap, int16_t w, int16_t h) 1483 { 1484 int32_t offset = 0; 1485 startWrite(); 1486 for (int16_t j = 0; j < h; j++, y++) 1487 { 1488 for (int16_t i = 0; i < w; i++) 1489 { 1490 writePixel(x + i, y, bitmap[offset++]); 1491 } 1492 } 1493 endWrite(); 1494 } 1495 1496 /**************************************************************************/ 1497 /*! 1498 @brief Draw a RAM-resident 16-bit Big Endian image (RGB 5/6/5) at the specified (x,y) position. 1499 @param x Top left corner x coordinate 1500 @param y Top left corner y coordinate 1501 @param bitmap byte array with 16-bit color bitmap 1502 @param w Width of bitmap in pixels 1503 @param h Height of bitmap in pixels 1504 */ 1505 /**************************************************************************/ 1506 void Arduino_GFX::draw16bitBeRGBBitmap(int16_t x, int16_t y, 1507 uint16_t *bitmap, int16_t w, int16_t h) 1508 { 1509 int32_t offset = 0; 1510 uint16_t p; 1511 startWrite(); 1512 for (int16_t j = 0; j < h; j++, y++) 1513 { 1514 for (int16_t i = 0; i < w; i++) 1515 { 1516 p = bitmap[offset++]; 1517 MSB_16_SET(p, p); 1518 writePixel(x + i, y, p); 1519 } 1520 } 1521 endWrite(); 1522 } 1523 1524 /**************************************************************************/ 1525 /*! 1526 @brief Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask 1527 (set bits = opaque, unset bits = clear) at the specified (x,y) position. 1528 BOTH buffers (color and mask) must be PROGMEM-resident. 1529 @param x Top left corner x coordinate 1530 @param y Top left corner y coordinate 1531 @param bitmap byte array with 16-bit color bitmap 1532 @param mask byte array with monochrome mask bitmap 1533 @param w Width of bitmap in pixels 1534 @param h Height of bitmap in pixels 1535 */ 1536 /**************************************************************************/ 1537 void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y, 1538 const uint16_t bitmap[], const uint8_t mask[], 1539 int16_t w, int16_t h) 1540 { 1541 int32_t offset = 0; 1542 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte 1543 uint8_t byte = 0; 1544 startWrite(); 1545 for (int16_t j = 0; j < h; j++, y++) 1546 { 1547 for (int16_t i = 0; i < w; i++) 1548 { 1549 if (i & 7) 1550 { 1551 byte <<= 1; 1552 } 1553 else 1554 { 1555 byte = pgm_read_byte(&mask[j * bw + i / 8]); 1556 } 1557 if (byte & 0x80) 1558 { 1559 writePixel(x + i, y, pgm_read_word(&bitmap[offset])); 1560 } 1561 offset++; 1562 } 1563 } 1564 endWrite(); 1565 } 1566 1567 /**************************************************************************/ 1568 /*! 1569 @brief Draw a RAM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask 1570 (set bits = opaque, unset bits = clear) at the specified (x,y) position. 1571 BOTH buffers (color and mask) must be RAM-resident. 1572 @param x Top left corner x coordinate 1573 @param y Top left corner y coordinate 1574 @param bitmap byte array with 16-bit color bitmap 1575 @param mask byte array with monochrome mask bitmap 1576 @param w Width of bitmap in pixels 1577 @param h Height of bitmap in pixels 1578 */ 1579 /**************************************************************************/ 1580 void Arduino_GFX::draw16bitRGBBitmap(int16_t x, int16_t y, 1581 uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h) 1582 { 1583 int32_t offset = 0, maskIdx = 0; 1584 uint8_t byte = 0; 1585 startWrite(); 1586 for (int16_t j = 0; j < h; j++, y++) 1587 { 1588 for (int16_t i = 0; i < w; i++) 1589 { 1590 if (i & 7) 1591 { 1592 byte <<= 1; 1593 } 1594 else 1595 { 1596 byte = mask[maskIdx++]; 1597 } 1598 if (byte & 0x80) 1599 { 1600 writePixel(x + i, y, bitmap[offset]); 1601 } 1602 offset++; 1603 } 1604 } 1605 endWrite(); 1606 } 1607 1608 /**************************************************************************/ 1609 /*! 1610 @brief Draw a PROGMEM-resident 24-bit image (RGB 5/6/5) at the specified (x,y) position. 1611 @param x Top left corner x coordinate 1612 @param y Top left corner y coordinate 1613 @param bitmap byte array with 16-bit color bitmap 1614 @param w Width of bitmap in pixels 1615 @param h Height of bitmap in pixels 1616 */ 1617 /**************************************************************************/ 1618 void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y, 1619 const uint8_t bitmap[], int16_t w, int16_t h) 1620 { 1621 int32_t offset = 0; 1622 startWrite(); 1623 for (int16_t j = 0; j < h; j++, y++) 1624 { 1625 for (int16_t i = 0; i < w; i++) 1626 { 1627 writePixel(x + i, y, color565(pgm_read_byte(&bitmap[offset]), pgm_read_byte(&bitmap[offset + 1]), pgm_read_byte(&bitmap[offset + 2]))); 1628 offset += 3; 1629 } 1630 } 1631 endWrite(); 1632 } 1633 1634 /**************************************************************************/ 1635 /*! 1636 @brief Draw a RAM-resident 24-bit image (RGB 5/6/5) at the specified (x,y) position. 1637 @param x Top left corner x coordinate 1638 @param y Top left corner y coordinate 1639 @param bitmap byte array with 16-bit color bitmap 1640 @param w Width of bitmap in pixels 1641 @param h Height of bitmap in pixels 1642 */ 1643 /**************************************************************************/ 1644 void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y, 1645 uint8_t *bitmap, int16_t w, int16_t h) 1646 { 1647 int32_t offset = 0; 1648 startWrite(); 1649 for (int16_t j = 0; j < h; j++, y++) 1650 { 1651 for (int16_t i = 0; i < w; i++) 1652 { 1653 writePixel(x + i, y, color565(bitmap[offset], bitmap[offset + 1], bitmap[offset + 2])); 1654 offset += 3; 1655 } 1656 } 1657 endWrite(); 1658 } 1659 1660 /**************************************************************************/ 1661 /*! 1662 @brief Draw a PROGMEM-resident 24-bit image (RGB 5/6/5) with a 1-bit mask 1663 (set bits = opaque, unset bits = clear) at the specified (x,y) position. 1664 BOTH buffers (color and mask) must be PROGMEM-resident. 1665 @param x Top left corner x coordinate 1666 @param y Top left corner y coordinate 1667 @param bitmap byte array with 16-bit color bitmap 1668 @param mask byte array with monochrome mask bitmap 1669 @param w Width of bitmap in pixels 1670 @param h Height of bitmap in pixels 1671 */ 1672 /**************************************************************************/ 1673 void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y, 1674 const uint8_t bitmap[], const uint8_t mask[], 1675 int16_t w, int16_t h) 1676 { 1677 int32_t offset = 0; 1678 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte 1679 uint8_t byte = 0; 1680 startWrite(); 1681 for (int16_t j = 0; j < h; j++, y++) 1682 { 1683 for (int16_t i = 0; i < w; i++) 1684 { 1685 if (i & 7) 1686 { 1687 byte <<= 1; 1688 } 1689 else 1690 { 1691 byte = pgm_read_byte(&mask[j * bw + i / 8]); 1692 } 1693 if (byte & 0x80) 1694 { 1695 writePixel(x + i, y, color565(pgm_read_byte(&bitmap[offset]), pgm_read_byte(&bitmap[offset + 1]), pgm_read_byte(&bitmap[offset + 2]))); 1696 } 1697 offset += 3; 1698 } 1699 } 1700 endWrite(); 1701 } 1702 1703 /**************************************************************************/ 1704 /*! 1705 @brief Draw a RAM-resident 24-bit image (RGB 5/6/5) with a 1-bit mask 1706 (set bits = opaque, unset bits = clear) at the specified (x,y) position. 1707 BOTH buffers (color and mask) must be RAM-resident. 1708 @param x Top left corner x coordinate 1709 @param y Top left corner y coordinate 1710 @param bitmap byte array with 16-bit color bitmap 1711 @param mask byte array with monochrome mask bitmap 1712 @param w Width of bitmap in pixels 1713 @param h Height of bitmap in pixels 1714 */ 1715 /**************************************************************************/ 1716 void Arduino_GFX::draw24bitRGBBitmap(int16_t x, int16_t y, 1717 uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h) 1718 { 1719 int32_t offset = 0; 1720 int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte 1721 uint8_t byte = 0; 1722 startWrite(); 1723 for (int16_t j = 0; j < h; j++, y++) 1724 { 1725 for (int16_t i = 0; i < w; i++) 1726 { 1727 if (i & 7) 1728 { 1729 byte <<= 1; 1730 } 1731 else 1732 { 1733 byte = mask[j * bw + i / 8]; 1734 } 1735 if (byte & 0x80) 1736 { 1737 writePixel(x + i, y, color565(bitmap[offset], bitmap[offset + 1], bitmap[offset + 2])); 1738 } 1739 offset += 3; 1740 } 1741 } 1742 endWrite(); 1743 } 1744 1745 #if defined(U8G2_FONT_SUPPORT) 1746 uint16_t Arduino_GFX::u8g2_font_get_word(const uint8_t *font, uint8_t offset) 1747 { 1748 uint16_t pos; 1749 font += offset; 1750 pos = pgm_read_byte(font); 1751 font++; 1752 pos <<= 8; 1753 pos += pgm_read_byte(font); 1754 1755 return pos; 1756 } 1757 1758 uint8_t Arduino_GFX::u8g2_font_decode_get_unsigned_bits(uint8_t cnt) 1759 { 1760 uint8_t val; 1761 uint8_t bit_pos = _u8g2_decode_bit_pos; 1762 uint8_t bit_pos_plus_cnt; 1763 1764 val = pgm_read_byte(_u8g2_decode_ptr); 1765 1766 val >>= bit_pos; 1767 bit_pos_plus_cnt = bit_pos; 1768 bit_pos_plus_cnt += cnt; 1769 if (bit_pos_plus_cnt >= 8) 1770 { 1771 uint8_t s = 8; 1772 s -= bit_pos; 1773 _u8g2_decode_ptr++; 1774 val |= pgm_read_byte(_u8g2_decode_ptr) << (s); 1775 bit_pos_plus_cnt -= 8; 1776 } 1777 val &= (1U << cnt) - 1; 1778 1779 _u8g2_decode_bit_pos = bit_pos_plus_cnt; 1780 1781 return val; 1782 } 1783 1784 int8_t Arduino_GFX::u8g2_font_decode_get_signed_bits(uint8_t cnt) 1785 { 1786 int8_t v, d; 1787 v = (int8_t)u8g2_font_decode_get_unsigned_bits(cnt); 1788 d = 1; 1789 cnt--; 1790 d <<= cnt; 1791 v -= d; 1792 1793 return v; 1794 } 1795 1796 void Arduino_GFX::u8g2_font_decode_len(uint8_t len, uint8_t is_foreground, uint16_t color, uint16_t bg) 1797 { 1798 uint8_t cnt; /* total number of remaining pixels, which have to be drawn */ 1799 uint8_t rem; /* remaining pixel to the right edge of the glyph */ 1800 uint8_t current; /* number of pixels, which need to be drawn for the draw procedure */ 1801 /* current is either equal to cnt or equal to rem */ 1802 1803 /* target position on the screen */ 1804 uint16_t x, y; 1805 1806 cnt = len; 1807 1808 /* get the local position */ 1809 uint8_t lx = _u8g2_dx; 1810 uint8_t ly = _u8g2_dy; 1811 1812 for (;;) 1813 { 1814 /* calculate the number of pixel to the right edge of the glyph */ 1815 rem = _u8g2_char_width; 1816 rem -= lx; 1817 1818 /* calculate how many pixel to draw. This is either to the right edge */ 1819 /* or lesser, if not enough pixel are left */ 1820 current = rem; 1821 if (cnt < rem) 1822 current = cnt; 1823 1824 /* now draw the line, but apply the rotation around the glyph target position */ 1825 // u8g2_font_decode_draw_pixel(u8g2, lx,ly,current, is_foreground); 1826 1827 if (textsize_x == 1 && textsize_y == 1) 1828 { 1829 /* get target position */ 1830 x = _u8g2_target_x + lx; 1831 y = _u8g2_target_y + ly; 1832 1833 /* draw foreground and background (if required) */ 1834 if (is_foreground) 1835 { 1836 writeFastHLine(x, y, current, color); 1837 } 1838 else if (bg != color) 1839 { 1840 writeFastHLine(x, y, current, bg); 1841 } 1842 } 1843 else 1844 { 1845 /* get target position */ 1846 x = _u8g2_target_x + (lx * textsize_x); 1847 y = _u8g2_target_y + (ly * textsize_y); 1848 1849 /* draw foreground and background (if required) */ 1850 if (is_foreground) 1851 { 1852 writeFillRect(x, y, (current * textsize_x) - text_pixel_margin, 1853 textsize_y - text_pixel_margin, color); 1854 } 1855 else if (bg != color) 1856 { 1857 writeFillRect(x, y, (current * textsize_x) - text_pixel_margin, 1858 textsize_y - text_pixel_margin, bg); 1859 } 1860 } 1861 1862 /* check, whether the end of the run length code has been reached */ 1863 if (cnt < rem) 1864 break; 1865 cnt -= rem; 1866 lx = 0; 1867 ly++; 1868 } 1869 lx += cnt; 1870 1871 _u8g2_dx = lx; 1872 _u8g2_dy = ly; 1873 } 1874 #endif // defined(U8G2_FONT_SUPPORT) 1875 1876 // TEXT- AND CHARACTER-HANDLING FUNCTIONS ---------------------------------- 1877 1878 // Draw a character 1879 /**************************************************************************/ 1880 /*! 1881 @brief Draw a single character 1882 @param x Bottom left corner x coordinate 1883 @param y Bottom left corner y coordinate 1884 @param c The 8-bit font-indexed character (likely ascii) 1885 @param color 16-bit 5-6-5 Color to draw chraracter with 1886 @param bg 16-bit 5-6-5 Color to fill background with (if same as color, no background) 1887 */ 1888 /**************************************************************************/ 1889 void Arduino_GFX::drawChar(int16_t x, int16_t y, unsigned char c, 1890 uint16_t color, uint16_t bg) 1891 { 1892 int16_t block_w; 1893 int16_t block_h; 1894 1895 #if !defined(ATTINY_CORE) 1896 if (gfxFont) // custom font 1897 { 1898 // Character is assumed previously filtered by write() to eliminate 1899 // newlines, returns, non-printable characters, etc. Calling 1900 // drawChar() directly with 'bad' characters of font may cause mayhem! 1901 1902 c -= (uint8_t)pgm_read_byte(&gfxFont->first); 1903 GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c); 1904 uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont); 1905 1906 uint16_t bo = pgm_read_word(&glyph->bitmapOffset); 1907 uint8_t w = pgm_read_byte(&glyph->width), 1908 h = pgm_read_byte(&glyph->height), 1909 xAdvance = pgm_read_byte(&glyph->xAdvance), 1910 yAdvance = pgm_read_byte(&gfxFont->yAdvance), 1911 baseline = yAdvance * 2 / 3; // TODO: baseline is an arbitrary currently, may be define in font file 1912 int8_t xo = pgm_read_byte(&glyph->xOffset), 1913 yo = pgm_read_byte(&glyph->yOffset); 1914 uint8_t xx, yy, bits = 0, bit = 0; 1915 int16_t xo16 = xo, yo16 = yo; 1916 1917 if (xAdvance < w) 1918 { 1919 xAdvance = w; // Don't know why it exists 1920 } 1921 1922 block_w = xAdvance * textsize_x; 1923 block_h = yAdvance * textsize_y; 1924 if ( 1925 (x > _max_x) || // Clip right 1926 (y > _max_y) || // Clip bottom 1927 ((x + block_w - 1) < 0) || // Clip left 1928 ((y + block_h - 1) < 0) // Clip top 1929 ) 1930 { 1931 return; 1932 } 1933 1934 // NOTE: Different from Adafruit_GFX design, Adruino_GFX also cater background. 1935 // Since it may introduce many ugly output, it should limited using on mono font only. 1936 startWrite(); 1937 if (bg != color) // have background color 1938 { 1939 writeFillRect(x, y - (baseline * textsize_y), block_w, block_h, bg); 1940 } 1941 for (yy = 0; yy < h; yy++) 1942 { 1943 for (xx = 0; xx < w; xx++) 1944 { 1945 if (!(bit++ & 7)) 1946 { 1947 bits = pgm_read_byte(&bitmap[bo++]); 1948 } 1949 if (bits & 0x80) 1950 { 1951 if (textsize_x == 1 && textsize_y == 1) 1952 { 1953 writePixel(x + xo + xx, y + yo + yy, color); 1954 } 1955 else 1956 { 1957 writeFillRect(x + (xo16 + xx) * textsize_x, y + (yo16 + yy) * textsize_y, 1958 textsize_x - text_pixel_margin, textsize_y - text_pixel_margin, color); 1959 } 1960 } 1961 bits <<= 1; 1962 } 1963 } 1964 endWrite(); 1965 } 1966 else // 'Classic' built-in font 1967 #endif // !defined(ATTINY_CORE) 1968 #if defined(U8G2_FONT_SUPPORT) 1969 if (u8g2Font) 1970 { 1971 if ((_u8g2_decode_ptr) && (_u8g2_char_width > 0)) 1972 { 1973 uint8_t a, b; 1974 1975 _u8g2_target_x = x + (_u8g2_char_x * textsize_x); 1976 _u8g2_target_y = y - ((_u8g2_char_height + _u8g2_char_y) * textsize_y); 1977 // log_d("_u8g2_target_x: %d, _u8g2_target_y: %d", _u8g2_target_x, _u8g2_target_y); 1978 1979 /* reset local x/y position */ 1980 _u8g2_dx = 0; 1981 _u8g2_dy = 0; 1982 /* decode glyph */ 1983 startWrite(); 1984 for (;;) 1985 { 1986 a = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_0); 1987 b = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_1); 1988 // log_d("a: %d, b: %d", a, b); 1989 do 1990 { 1991 u8g2_font_decode_len(a, 0, color, bg); 1992 u8g2_font_decode_len(b, 1, color, bg); 1993 } while (u8g2_font_decode_get_unsigned_bits(1) != 0); 1994 1995 if (_u8g2_dy >= _u8g2_char_height) 1996 break; 1997 } 1998 endWrite(); 1999 } 2000 } 2001 else // glcdfont 2002 #endif // defined(U8G2_FONT_SUPPORT) 2003 { 2004 block_w = 6 * textsize_x; 2005 block_h = 8 * textsize_y; 2006 if ( 2007 (x > _max_x) || // Clip right 2008 (y > _max_y) || // Clip bottom 2009 ((x + block_w - 1) < 0) || // Clip left 2010 ((y + block_h - 1) < 0) // Clip top 2011 ) 2012 { 2013 return; 2014 } 2015 2016 startWrite(); 2017 for (int8_t i = 0; i < 5; i++) 2018 { // Char bitmap = 5 columns 2019 uint8_t line = pgm_read_byte(&font[c * 5 + i]); 2020 for (int8_t j = 0; j < 8; j++, line >>= 1) 2021 { 2022 if (line & 1) 2023 { 2024 if (textsize_x == 1 && textsize_y == 1) 2025 { 2026 writePixel(x + i, y + j, color); 2027 } 2028 else 2029 { 2030 if (text_pixel_margin > 0) 2031 { 2032 writeFillRect(x + (i * textsize_x), y + j * textsize_y, textsize_x - text_pixel_margin, textsize_y - text_pixel_margin, color); 2033 writeFillRect(x + ((i + 1) * textsize_x) - text_pixel_margin, y + j * textsize_y, text_pixel_margin, textsize_y, bg); 2034 writeFillRect(x + (i * textsize_x), y + ((j + 1) * textsize_y) - text_pixel_margin, textsize_x - text_pixel_margin, text_pixel_margin, bg); 2035 } 2036 else 2037 { 2038 writeFillRect(x + i * textsize_x, y + j * textsize_y, textsize_x, textsize_y, color); 2039 } 2040 } 2041 } 2042 else if (bg != color) 2043 { 2044 if (textsize_x == 1 && textsize_y == 1) 2045 { 2046 writePixel(x + i, y + j, bg); 2047 } 2048 else 2049 { 2050 writeFillRect(x + i * textsize_x, y + j * textsize_y, textsize_x, textsize_y, bg); 2051 } 2052 } 2053 } 2054 } 2055 if (bg != color) 2056 { // If opaque, draw vertical line for last column 2057 if (textsize_x == 1 && textsize_y == 1) 2058 { 2059 writeFastVLine(x + 5, y, 8, bg); 2060 } 2061 else 2062 { 2063 writeFillRect(x + 5 * textsize_x, y, textsize_x, 8 * textsize_y, bg); 2064 } 2065 } 2066 endWrite(); 2067 } 2068 } 2069 2070 /**************************************************************************/ 2071 /*! 2072 @brief Print one byte/character of data, used to support print() 2073 @param c The 8-bit ascii character to write 2074 */ 2075 /**************************************************************************/ 2076 size_t Arduino_GFX::write(uint8_t c) 2077 { 2078 #if !defined(ATTINY_CORE) 2079 if (gfxFont) // custom font 2080 { 2081 if (c == '\n') // Newline 2082 { 2083 cursor_x = 0; // Reset x to zero, advance y by one line 2084 cursor_y += (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); 2085 } 2086 else if (c != '\r') // Not a carriage return; is normal char 2087 { 2088 uint8_t first = pgm_read_byte(&gfxFont->first), 2089 last = pgm_read_byte(&gfxFont->last); 2090 if ((c >= first) && (c <= last)) // Char present in this font? 2091 { 2092 GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first); 2093 uint8_t gw = pgm_read_byte(&glyph->width), 2094 xa = pgm_read_byte(&glyph->xAdvance); 2095 int16_t xo = pgm_read_byte(&glyph->xOffset); 2096 if (wrap && ((cursor_x + ((xo + gw) * textsize_x) - 1) > _max_x)) 2097 { 2098 cursor_x = 0; // Reset x to zero, advance y by one line 2099 cursor_y += (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); 2100 } 2101 drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor); 2102 cursor_x += (int16_t)textsize_x * xa; 2103 } 2104 } 2105 } 2106 else // not gfxFont 2107 #endif // !defined(ATTINY_CORE) 2108 #if defined(U8G2_FONT_SUPPORT) 2109 if (u8g2Font) 2110 { 2111 _u8g2_decode_ptr = 0; 2112 2113 if (_enableUTF8Print) 2114 { 2115 if (_utf8_state == 0) 2116 { 2117 if (c >= 0xfc) /* 6 byte sequence */ 2118 { 2119 _utf8_state = 5; 2120 c &= 1; 2121 } 2122 else if (c >= 0xf8) 2123 { 2124 _utf8_state = 4; 2125 c &= 3; 2126 } 2127 else if (c >= 0xf0) 2128 { 2129 _utf8_state = 3; 2130 c &= 7; 2131 } 2132 else if (c >= 0xe0) 2133 { 2134 _utf8_state = 2; 2135 c &= 15; 2136 } 2137 else if (c >= 0xc0) 2138 { 2139 _utf8_state = 1; 2140 c &= 0x01f; 2141 } 2142 _encoding = c; 2143 } 2144 else 2145 { 2146 _utf8_state--; 2147 /* The case b < 0x080 (an illegal UTF8 encoding) is not checked here. */ 2148 _encoding <<= 6; 2149 c &= 0x03f; 2150 _encoding |= c; 2151 } 2152 } // _enableUTF8Print 2153 else 2154 { 2155 _encoding = c; 2156 } 2157 2158 if (_utf8_state == 0) 2159 { 2160 if (_encoding == '\n') 2161 { 2162 cursor_x = 0; 2163 cursor_y += (int16_t)textsize_y * _u8g2_max_char_height; 2164 } 2165 else if (_encoding != '\r') 2166 { // Ignore carriage returns 2167 uint8_t *font = u8g2Font; 2168 const uint8_t *glyph_data = 0; 2169 2170 // extract from u8g2_font_get_glyph_data() 2171 font += 23; // U8G2_FONT_DATA_STRUCT_SIZE 2172 if (_encoding <= 255) 2173 { 2174 if (_encoding >= 'a') 2175 { 2176 font += _u8g2_start_pos_lower_a; 2177 } 2178 else if (_encoding >= 'A') 2179 { 2180 font += _u8g2_start_pos_upper_A; 2181 } 2182 2183 for (;;) 2184 { 2185 if (pgm_read_byte(font + 1) == 0) 2186 break; 2187 if (pgm_read_byte(font) == _encoding) 2188 { 2189 glyph_data = font + 2; /* skip encoding and glyph size */ 2190 } 2191 font += pgm_read_byte(font + 1); 2192 } 2193 } 2194 #ifdef U8G2_WITH_UNICODE 2195 else 2196 { 2197 uint16_t e; 2198 font += _u8g2_start_pos_unicode; 2199 const uint8_t *unicode_lookup_table = font; 2200 2201 /* issue 596: search for the glyph start in the unicode lookup table */ 2202 do 2203 { 2204 font += u8g2_font_get_word(unicode_lookup_table, 0); 2205 e = u8g2_font_get_word(unicode_lookup_table, 2); 2206 unicode_lookup_table += 4; 2207 } while (e < _encoding); 2208 2209 for (;;) 2210 { 2211 e = u8g2_font_get_word(font, 0); 2212 2213 if (e == 0) 2214 break; 2215 2216 if (e == _encoding) 2217 { 2218 glyph_data = font + 3; /* skip encoding and glyph size */ 2219 break; 2220 } 2221 font += pgm_read_byte(font + 2); 2222 } 2223 } 2224 #endif 2225 2226 if (glyph_data) 2227 { 2228 // u8g2_font_decode_glyph 2229 _u8g2_decode_ptr = glyph_data; 2230 _u8g2_decode_bit_pos = 0; 2231 2232 _u8g2_char_width = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_char_width); 2233 _u8g2_char_height = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_char_height); 2234 _u8g2_char_x = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_char_x); 2235 _u8g2_char_y = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_char_y); 2236 _u8g2_delta_x = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_delta_x); 2237 // log_d("c: %c, _encoding: %d, _u8g2_char_width: %d, _u8g2_char_height: %d, _u8g2_char_x: %d, _u8g2_char_y: %d, _u8g2_delta_x: %d", 2238 // c, _encoding, _u8g2_char_width, _u8g2_char_height, _u8g2_char_x, _u8g2_char_y, _u8g2_delta_x); 2239 2240 if (_u8g2_char_width > 0) 2241 { 2242 if (wrap && ((cursor_x + (textsize_x * _u8g2_char_width) - 1) > _max_x)) 2243 { 2244 cursor_x = 0; 2245 cursor_y += (int16_t)textsize_y * _u8g2_max_char_height; 2246 } 2247 } 2248 2249 drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor); 2250 cursor_x += (int16_t)textsize_x * _u8g2_delta_x; 2251 } 2252 } 2253 } 2254 } 2255 else // glcdfont 2256 #endif // defined(U8G2_FONT_SUPPORT) 2257 { 2258 if (c == '\n') 2259 { // Newline? 2260 cursor_x = 0; // Reset x to zero, 2261 cursor_y += textsize_y * 8; // advance y one line 2262 } 2263 else if (c != '\r') // Normal char; ignore carriage returns 2264 { 2265 if (wrap && ((cursor_x + (textsize_x * 6) - 1) > _max_x)) // Off right? 2266 { 2267 cursor_x = 0; // Reset x to zero, 2268 cursor_y += textsize_y * 8; // advance y one line 2269 } 2270 drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor); 2271 cursor_x += textsize_x * 6; // Advance x one char 2272 } 2273 } 2274 return 1; 2275 } 2276 2277 /**************************************************************************/ 2278 /*! 2279 @brief Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger. 2280 @param s Desired text size. 1 is default 6x8, 2 is 12x16, 3 is 18x24, etc 2281 */ 2282 /**************************************************************************/ 2283 void Arduino_GFX::setTextSize(uint8_t s) 2284 { 2285 setTextSize(s, s, 0); 2286 } 2287 2288 /**************************************************************************/ 2289 /*! 2290 @brief Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger. 2291 @param s_x Desired text width magnification level in X-axis. 1 is default 2292 @param s_y Desired text width magnification level in Y-axis. 1 is default 2293 */ 2294 /**************************************************************************/ 2295 void Arduino_GFX::setTextSize(uint8_t s_x, uint8_t s_y) 2296 { 2297 setTextSize(s_x, s_y, 0); 2298 } 2299 2300 /**************************************************************************/ 2301 /*! 2302 @brief Set text 'magnification' size. Each increase in s makes 1 pixel that much bigger. 2303 @param s_x Desired text width magnification level in X-axis. 1 is default 2304 @param s_y Desired text width magnification level in Y-axis. 1 is default 2305 @param pixel_margin Margin for each text pixel. 0 is default 2306 */ 2307 /**************************************************************************/ 2308 void Arduino_GFX::setTextSize(uint8_t s_x, uint8_t s_y, uint8_t pixel_margin) 2309 { 2310 text_pixel_margin = ((pixel_margin < s_x) && (pixel_margin < s_y)) ? pixel_margin : 0; 2311 textsize_x = (s_x > 0) ? s_x : 1; 2312 textsize_y = (s_y > 0) ? s_y : 1; 2313 } 2314 2315 /**************************************************************************/ 2316 /*! 2317 @brief Set rotation setting for display 2318 @param r 0 thru 3 corresponding to 4 cardinal rotations 2319 */ 2320 /**************************************************************************/ 2321 void Arduino_GFX::setRotation(uint8_t r) 2322 { 2323 _rotation = (r & 7); 2324 switch (_rotation) 2325 { 2326 case 7: 2327 case 5: 2328 case 3: 2329 case 1: 2330 _width = HEIGHT; 2331 _height = WIDTH; 2332 _max_x = _width - 1; ///< x zero base bound 2333 _max_y = _height - 1; ///< y zero base bound 2334 break; 2335 case 6: 2336 case 4: 2337 case 2: 2338 default: // case 0: 2339 _width = WIDTH; 2340 _height = HEIGHT; 2341 _max_x = _width - 1; ///< x zero base bound 2342 _max_y = _height - 1; ///< y zero base bound 2343 break; 2344 } 2345 } 2346 2347 #if !defined(ATTINY_CORE) 2348 /**************************************************************************/ 2349 /*! 2350 @brief Set the font to display when print()ing, either custom or default 2351 @param f The GFXfont object, if NULL use built in 6x8 font 2352 */ 2353 /**************************************************************************/ 2354 void Arduino_GFX::setFont(const GFXfont *f) 2355 { 2356 gfxFont = (GFXfont *)f; 2357 #if defined(U8G2_FONT_SUPPORT) 2358 u8g2Font = NULL; 2359 #endif // defined(U8G2_FONT_SUPPORT) 2360 } 2361 2362 /**************************************************************************/ 2363 /*! 2364 @brief flush framebuffer to output (for Canvas or NeoPixel sub-class) 2365 */ 2366 /**************************************************************************/ 2367 void Arduino_GFX::flush() 2368 { 2369 } 2370 #endif // !defined(ATTINY_CORE) 2371 2372 #if defined(U8G2_FONT_SUPPORT) 2373 void Arduino_GFX::setFont(const uint8_t *font) 2374 { 2375 gfxFont = NULL; 2376 u8g2Font = (uint8_t *)font; 2377 2378 // extract from u8g2_read_font_info() 2379 /* offset 0 */ 2380 _u8g2_glyph_cnt = pgm_read_byte(font); 2381 // uint8_t bbx_mode = pgm_read_byte(font + 1); 2382 _u8g2_bits_per_0 = pgm_read_byte(font + 2); 2383 _u8g2_bits_per_1 = pgm_read_byte(font + 3); 2384 // log_d("_u8g2_glyph_cnt: %d, bbx_mode: %d, _u8g2_bits_per_0: %d, _u8g2_bits_per_1: %d", 2385 // _u8g2_glyph_cnt, bbx_mode, _u8g2_bits_per_0, _u8g2_bits_per_1); 2386 2387 /* offset 4 */ 2388 _u8g2_bits_per_char_width = pgm_read_byte(font + 4); 2389 _u8g2_bits_per_char_height = pgm_read_byte(font + 5); 2390 _u8g2_bits_per_char_x = pgm_read_byte(font + 6); 2391 _u8g2_bits_per_char_y = pgm_read_byte(font + 7); 2392 _u8g2_bits_per_delta_x = pgm_read_byte(font + 8); 2393 // log_d("_u8g2_bits_per_char_width: %d, _u8g2_bits_per_char_height: %d, _u8g2_bits_per_char_x: %d, _u8g2_bits_per_char_y: %d, _u8g2_bits_per_delta_x: %d", 2394 // _u8g2_bits_per_char_width, _u8g2_bits_per_char_height, _u8g2_bits_per_char_x, _u8g2_bits_per_char_y, _u8g2_bits_per_delta_x); 2395 2396 /* offset 9 */ 2397 _u8g2_max_char_width = pgm_read_byte(font + 9); 2398 _u8g2_max_char_height = pgm_read_byte(font + 10); 2399 // int8_t x_offset = pgm_read_byte(font + 11); 2400 // int8_t y_offset = pgm_read_byte(font + 12); 2401 // log_d("_u8g2_max_char_width: %d, _u8g2_max_char_height: %d, x_offset: %d, y_offset: %d", 2402 // _u8g2_max_char_width, _u8g2_max_char_height, x_offset, y_offset); 2403 2404 /* offset 13 */ 2405 // int8_t ascent_A = pgm_read_byte(font + 13); 2406 // int8_t descent_g = pgm_read_byte(font + 14); 2407 // int8_t ascent_para = pgm_read_byte(font + 15); 2408 // int8_t descent_para = pgm_read_byte(font + 16); 2409 // log_d("ascent_A: %d, descent_g: %d, ascent_para: %d, descent_para: %d", 2410 // ascent_A, descent_g, ascent_para, descent_para); 2411 2412 /* offset 17 */ 2413 _u8g2_start_pos_upper_A = u8g2_font_get_word(font, 17); 2414 _u8g2_start_pos_lower_a = u8g2_font_get_word(font, 19); 2415 #ifdef U8G2_WITH_UNICODE 2416 _u8g2_start_pos_unicode = u8g2_font_get_word(font, 21); 2417 #endif 2418 _u8g2_first_char = pgm_read_byte(font + 23); 2419 // log_d("_u8g2_start_pos_upper_A: %d, _u8g2_start_pos_lower_a: %d, _u8g2_start_pos_unicode: %d, _u8g2_first_char: %d", 2420 // _u8g2_start_pos_upper_A, _u8g2_start_pos_lower_a, _u8g2_start_pos_unicode, _u8g2_first_char); 2421 } 2422 2423 void Arduino_GFX::setUTF8Print(bool isEnable) 2424 { 2425 _enableUTF8Print = isEnable; 2426 } 2427 #endif // defined(U8G2_FONT_SUPPORT) 2428 2429 /**************************************************************************/ 2430 /*! 2431 @brief Helper to determine size of a character with current font/size. 2432 Broke this out as it's used by both the PROGMEM- and RAM-resident getTextBounds() functions. 2433 @param c The ascii character in question 2434 @param x Pointer to x location of character 2435 @param y Pointer to y location of character 2436 @param minx Minimum clipping value for X 2437 @param miny Minimum clipping value for Y 2438 @param maxx Maximum clipping value for X 2439 @param maxy Maximum clipping value for Y 2440 */ 2441 /**************************************************************************/ 2442 void Arduino_GFX::charBounds(char c, int16_t *x, int16_t *y, 2443 int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy) 2444 { 2445 #if !defined(ATTINY_CORE) 2446 if (gfxFont) // custom font 2447 { 2448 if (c == '\n') // Newline 2449 { 2450 *x = 0; // Reset x to zero, advance y by one line 2451 *y += (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); 2452 } 2453 else if (c != '\r') // Not a carriage return; is normal char 2454 { 2455 uint8_t first = pgm_read_byte(&gfxFont->first), 2456 last = pgm_read_byte(&gfxFont->last); 2457 if ((c >= first) && (c <= last)) // Char present in this font? 2458 { 2459 GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first); 2460 uint8_t gw = pgm_read_byte(&glyph->width), 2461 gh = pgm_read_byte(&glyph->height), 2462 xa = pgm_read_byte(&glyph->xAdvance); 2463 int16_t xo = pgm_read_byte(&glyph->xOffset), 2464 yo = pgm_read_byte(&glyph->yOffset); 2465 if (wrap && ((*x + ((xo + gw) * textsize_x) - 1) > _max_x)) 2466 { 2467 *x = 0; // Reset x to zero, advance y by one line 2468 *y += (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); 2469 } 2470 int16_t x1 = *x + xo * textsize_x, 2471 y1 = *y + yo * textsize_y, 2472 x2 = x1 + ((int16_t)gw * textsize_x) - 1, 2473 y2 = y1 + ((int16_t)gh * textsize_y) - 1; 2474 if (x1 < *minx) 2475 { 2476 *minx = x1; 2477 } 2478 if (y1 < *miny) 2479 { 2480 *miny = y1; 2481 } 2482 if (x2 > *maxx) 2483 { 2484 *maxx = x2; 2485 } 2486 if (y2 > *maxy) 2487 { 2488 *maxy = y2; 2489 } 2490 *x += (int16_t)textsize_x * xa; 2491 } 2492 } 2493 } 2494 else // not gfxFont 2495 #endif // !defined(ATTINY_CORE) 2496 #if defined(U8G2_FONT_SUPPORT) 2497 if (u8g2Font) 2498 { 2499 _u8g2_decode_ptr = 0; 2500 2501 if (_enableUTF8Print) 2502 { 2503 if (_utf8_state == 0) 2504 { 2505 if (c >= 0xfc) /* 6 byte sequence */ 2506 { 2507 _utf8_state = 5; 2508 c &= 1; 2509 } 2510 else if (c >= 0xf8) 2511 { 2512 _utf8_state = 4; 2513 c &= 3; 2514 } 2515 else if (c >= 0xf0) 2516 { 2517 _utf8_state = 3; 2518 c &= 7; 2519 } 2520 else if (c >= 0xe0) 2521 { 2522 _utf8_state = 2; 2523 c &= 15; 2524 } 2525 else if (c >= 0xc0) 2526 { 2527 _utf8_state = 1; 2528 c &= 0x01f; 2529 } 2530 _encoding = c; 2531 } 2532 else 2533 { 2534 _utf8_state--; 2535 /* The case b < 0x080 (an illegal UTF8 encoding) is not checked here. */ 2536 _encoding <<= 6; 2537 c &= 0x03f; 2538 _encoding |= c; 2539 } 2540 } // _enableUTF8Print 2541 else 2542 { 2543 _encoding = c; 2544 } 2545 2546 if (_utf8_state == 0) 2547 { 2548 if (_encoding == '\n') 2549 { 2550 *x = 0; 2551 *y += (int16_t)textsize_y * _u8g2_max_char_height; 2552 } 2553 else if (_encoding != '\r') 2554 { // Ignore carriage returns 2555 uint8_t *font = u8g2Font; 2556 const uint8_t *glyph_data = 0; 2557 2558 // extract from u8g2_font_get_glyph_data() 2559 font += 23; // U8G2_FONT_DATA_STRUCT_SIZE 2560 if (_encoding <= 255) 2561 { 2562 if (_encoding >= 'a') 2563 { 2564 font += _u8g2_start_pos_lower_a; 2565 } 2566 else if (_encoding >= 'A') 2567 { 2568 font += _u8g2_start_pos_upper_A; 2569 } 2570 2571 for (;;) 2572 { 2573 if (pgm_read_byte(font + 1) == 0) 2574 break; 2575 if (pgm_read_byte(font) == _encoding) 2576 { 2577 glyph_data = font + 2; /* skip encoding and glyph size */ 2578 } 2579 font += pgm_read_byte(font + 1); 2580 } 2581 } 2582 #ifdef U8G2_WITH_UNICODE 2583 else 2584 { 2585 uint16_t e; 2586 font += _u8g2_start_pos_unicode; 2587 const uint8_t *unicode_lookup_table = font; 2588 2589 /* issue 596: search for the glyph start in the unicode lookup table */ 2590 do 2591 { 2592 font += u8g2_font_get_word(unicode_lookup_table, 0); 2593 e = u8g2_font_get_word(unicode_lookup_table, 2); 2594 unicode_lookup_table += 4; 2595 } while (e < _encoding); 2596 2597 for (;;) 2598 { 2599 e = u8g2_font_get_word(font, 0); 2600 2601 if (e == 0) 2602 break; 2603 2604 if (e == _encoding) 2605 { 2606 glyph_data = font + 3; /* skip encoding and glyph size */ 2607 break; 2608 } 2609 font += pgm_read_byte(font + 2); 2610 } 2611 } 2612 #endif 2613 2614 if (glyph_data) 2615 { 2616 // u8g2_font_decode_glyph 2617 _u8g2_decode_ptr = glyph_data; 2618 _u8g2_decode_bit_pos = 0; 2619 2620 _u8g2_char_width = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_char_width); 2621 _u8g2_char_height = u8g2_font_decode_get_unsigned_bits(_u8g2_bits_per_char_height); 2622 _u8g2_char_x = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_char_x); 2623 _u8g2_char_y = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_char_y); 2624 _u8g2_delta_x = u8g2_font_decode_get_signed_bits(_u8g2_bits_per_delta_x); 2625 // log_d("c: %c, _encoding: %d, _u8g2_char_width: %d, _u8g2_char_height: %d, _u8g2_char_x: %d, _u8g2_char_y: %d, _u8g2_delta_x: %d", 2626 // c, _encoding, _u8g2_char_width, _u8g2_char_height, _u8g2_char_x, _u8g2_char_y, _u8g2_delta_x); 2627 2628 if (_u8g2_char_width > 0) 2629 { 2630 if (wrap && ((*x + (textsize_x * _u8g2_char_width) - 1) > _max_x)) 2631 { 2632 *x = 0; 2633 *y += (int16_t)textsize_y * _u8g2_max_char_height; 2634 } 2635 } 2636 2637 int16_t x1 = *x + ((int16_t)_u8g2_char_x * textsize_x), 2638 y1 = *y - (((int16_t)_u8g2_char_height + _u8g2_char_y) * textsize_y), 2639 x2 = x1 + ((int16_t)_u8g2_char_width * textsize_x) - 1, 2640 y2 = y1 + ((int16_t)_u8g2_char_height * textsize_y) - 1; 2641 if (x1 < *minx) 2642 { 2643 *minx = x1; 2644 } 2645 if (y1 < *miny) 2646 { 2647 *miny = y1; 2648 } 2649 if (x2 > *maxx) 2650 { 2651 *maxx = x2; 2652 } 2653 if (y2 > *maxy) 2654 { 2655 *maxy = y2; 2656 } 2657 *x += (int16_t)textsize_x * _u8g2_delta_x; 2658 } 2659 } 2660 } 2661 } 2662 else // glcdfont 2663 #endif // defined(U8G2_FONT_SUPPORT) 2664 { 2665 if (c == '\n') 2666 { // Newline? 2667 *x = 0; // Reset x to zero, 2668 *y += textsize_y * 8; // advance y one line 2669 // min/max x/y unchaged -- that waits for next 'normal' character 2670 } 2671 else if (c != '\r') // Normal char; ignore carriage returns 2672 { 2673 if (wrap && ((*x + (textsize_x * 6) - 1) > _max_x)) // Off right? 2674 { 2675 *x = 0; // Reset x to zero, 2676 *y += textsize_y * 8; // advance y one line 2677 } 2678 int16_t x2 = *x + textsize_x * 6 - 1; // Lower-right pixel of char 2679 int16_t y2 = *y + textsize_y * 8 - 1; 2680 if (x2 > *maxx) 2681 { 2682 *maxx = x2; // Track max x, y 2683 } 2684 if (y2 > *maxy) 2685 { 2686 *maxy = y2; 2687 } 2688 if (*x < *minx) 2689 { 2690 *minx = *x; // Track min x, y 2691 } 2692 if (*y < *miny) 2693 { 2694 *miny = *y; 2695 } 2696 *x += textsize_x * 6; // Advance x one char 2697 } 2698 } 2699 } 2700 2701 /**************************************************************************/ 2702 /*! 2703 @brief Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H. 2704 @param str The ascii string to measure 2705 @param x The current cursor X 2706 @param y The current cursor Y 2707 @param x1 The boundary X coordinate, set by function 2708 @param y1 The boundary Y coordinate, set by function 2709 @param w The boundary width, set by function 2710 @param h The boundary height, set by function 2711 */ 2712 /**************************************************************************/ 2713 void Arduino_GFX::getTextBounds(const char *str, int16_t x, int16_t y, 2714 int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) 2715 { 2716 uint8_t c; // Current character 2717 2718 *x1 = x; 2719 *y1 = y; 2720 *w = *h = 0; 2721 2722 int16_t minx = _width, miny = _height, maxx = -1, maxy = -1; 2723 2724 while ((c = *str++)) 2725 { 2726 charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy); 2727 } 2728 2729 if (maxx >= minx) 2730 { 2731 *x1 = minx; 2732 *w = maxx - minx + 1; 2733 } 2734 if (maxy >= miny) 2735 { 2736 *y1 = miny; 2737 *h = maxy - miny + 1; 2738 } 2739 } 2740 2741 /**************************************************************************/ 2742 /*! 2743 @brief Helper to determine size of a string with current font/size. Pass string and a cursor position, returns UL corner and W,H. 2744 @param str The ascii string to measure (as an arduino String() class) 2745 @param x The current cursor X 2746 @param y The current cursor Y 2747 @param x1 The boundary X coordinate, set by function 2748 @param y1 The boundary Y coordinate, set by function 2749 @param w The boundary width, set by function 2750 @param h The boundary height, set by function 2751 */ 2752 /**************************************************************************/ 2753 void Arduino_GFX::getTextBounds(const String &str, int16_t x, int16_t y, 2754 int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) 2755 { 2756 if (str.length() != 0) 2757 { 2758 getTextBounds(const_cast<char *>(str.c_str()), x, y, x1, y1, w, h); 2759 } 2760 } 2761 2762 /**************************************************************************/ 2763 /*! 2764 @brief Helper to determine size of a PROGMEM string with current font/size. Pass string and a cursor position, returns UL corner and W,H. 2765 @param str The flash-memory ascii string to measure 2766 @param x The current cursor X 2767 @param y The current cursor Y 2768 @param x1 The boundary X coordinate, set by function 2769 @param y1 The boundary Y coordinate, set by function 2770 @param w The boundary width, set by function 2771 @param h The boundary height, set by function 2772 */ 2773 /**************************************************************************/ 2774 void Arduino_GFX::getTextBounds(const __FlashStringHelper *str, 2775 int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) 2776 { 2777 uint8_t *s = (uint8_t *)str, c; 2778 2779 *x1 = x; 2780 *y1 = y; 2781 *w = *h = 0; 2782 2783 int16_t minx = _width, miny = _height, maxx = -1, maxy = -1; 2784 2785 while ((c = pgm_read_byte(s++))) 2786 charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy); 2787 2788 if (maxx >= minx) 2789 { 2790 *x1 = minx; 2791 *w = maxx - minx + 1; 2792 } 2793 if (maxy >= miny) 2794 { 2795 *y1 = miny; 2796 *h = maxy - miny + 1; 2797 } 2798 } 2799 2800 /**************************************************************************/ 2801 /*! 2802 @brief Invert the display (ideally using built-in hardware command) 2803 @param i True if you want to invert, false to make 'normal' 2804 */ 2805 /**************************************************************************/ 2806 void Arduino_GFX::invertDisplay(bool i) 2807 { 2808 // Do nothing, must be subclassed if supported by hardware 2809 UNUSED(i); 2810 } 2811 2812 /**************************************************************************/ 2813 /*! 2814 @brief Turn on display after turned off 2815 */ 2816 /**************************************************************************/ 2817 void Arduino_GFX::displayOn() 2818 { 2819 } 2820 2821 /**************************************************************************/ 2822 /*! 2823 @brief Turn off display 2824 */ 2825 /**************************************************************************/ 2826 void Arduino_GFX::displayOff() 2827 { 2828 }