diff --git a/examples/1. Basic Inkplate Functionality/2-Inkplate_basic_grayscale/2-Inkplate_basic_grayscale.ino b/examples/1. Basic Inkplate Functionality/2-Inkplate_basic_grayscale/2-Inkplate_basic_grayscale.ino index 393994c..8d4caf3 100644 --- a/examples/1. Basic Inkplate Functionality/2-Inkplate_basic_grayscale/2-Inkplate_basic_grayscale.ino +++ b/examples/1. Basic Inkplate Functionality/2-Inkplate_basic_grayscale/2-Inkplate_basic_grayscale.ino @@ -8,68 +8,78 @@ This example will show you how you can draw some simple graphics using Adafruit GFX functions. Yes, Inkplate library is 100% compatible with GFX lib! Learn more about Adafruit GFX: https://learn.adafruit.com/adafruit-gfx-graphics-library - Inkplate will be used in grayscale mode which is 3 bit, so you can have up to 8 different colors (black, 6 gray colors and white) - Color is represented by number, where number 0 means black and number 7 means white, while everything in between are shades of gray. + Inkplate will be used in grayscale mode which is 3 bit, so you can have up to 8 different colors (black, 6 gray + colors and white) Color is represented by number, where number 0 means black and number 7 means white, while + everything in between are shades of gray. Want to learn more about Inkplate? Visit www.inkplate.io Looking to get support? Write on our forums: http://forum.e-radionica.com/en/ 15 July 2020 by e-radionica.com */ -#include "Inkplate.h" //Include Inkplate library to the sketch -#include "image.h" //Include image file that holds grayscale image data. You can see it in next tab inside Arduino IDE. -Inkplate display(INKPLATE_3BIT); //Create object on Inkplate library and set library to work in grayscale mode (3-bit) - //Other option is monochrome mode, which is demonstrated in next example "2-Inkplate_basic_monochrome" +#include "Inkplate.h" //Include Inkplate library to the sketch +#include "image.h" //Include image file that holds grayscale image data. You can see it in next tab inside Arduino IDE. +Inkplate display(INKPLATE_3BIT); // Create object on Inkplate library and set library to work in grayscale mode (3-bit) + // Other option is monochrome mode, which is demonstrated in next example + // "2-Inkplate_basic_monochrome" -#define DELAY_MS 5000 //Delay in milliseconds between screen refresh. Refreshing e-paper screens more often than 5s is not recommended \ + +#define DELAY_MS \ + 5000 //Delay in milliseconds between screen refresh. Refreshing e-paper screens more often than 5s is not recommended \ //Want to refresh faster? Use partial update! Find example in "3-Inkplate-basic_partial_update" void setup() { - display.begin(); //Init library (you should call this function ONLY ONCE) - display.clearDisplay(); //Clear any data that may have been in (software) frame buffer. - //(NOTE! This does not clean image on screen, it only clears it in the frame buffer inside ESP32). - display.clean(); //Clear everything that has previously been on a screen + display.begin(); // Init library (you should call this function ONLY ONCE) + display.clearDisplay(); // Clear any data that may have been in (software) frame buffer. + //(NOTE! This does not clean image on screen, it only clears it in the frame buffer inside + // ESP32). + display.clean(); // Clear everything that has previously been on a screen display.setTextColor(0, 7); display.setCursor(150, 320); display.setTextSize(4); display.print("Welcome to Inkplate 6!"); - display.display(); //Write hello message - delay(5000); //Wait a little bit + display.display(); // Write hello message + delay(5000); // Wait a little bit } void loop() { - //Example will demostrate funcionality one by one. You always first set everything in the frame buffer and afterwards you show - //it on the screen using display.display(). + // Example will demostrate funcionality one by one. You always first set everything in the frame buffer and + // afterwards you show it on the screen using display.display(). - //Let'sstart by drawing pixel at x = 100 and y = 50 location - display.clearDisplay(); //Clear everytning that is inside frame buffer in ESP32 - display.drawPixel(100, 50, 0); //Draw one black pixel at X = 100, Y = 50 position in 0 (BLACK) color - displayCurrentAction("Drawing a pixel"); //Function which writes small text at bottom left indicating what's currently done - //NOTE: you do not need displayCurrentAction function to use Inkplate! - display.display(); //Send image to display. You need to call this one each time you want to transfer frame buffer to the screen. - delay(DELAY_MS); //Wait a little bit + // Let'sstart by drawing pixel at x = 100 and y = 50 location + display.clearDisplay(); // Clear everytning that is inside frame buffer in ESP32 + display.drawPixel(100, 50, 0); // Draw one black pixel at X = 100, Y = 50 position in 0 (BLACK) color + displayCurrentAction( + "Drawing a pixel"); // Function which writes small text at bottom left indicating what's currently done + // NOTE: you do not need displayCurrentAction function to use Inkplate! + display.display(); // Send image to display. You need to call this one each time you want to transfer frame buffer + // to the screen. + delay(DELAY_MS); // Wait a little bit - //Now, let's draw some random pixels! - display.clearDisplay(); //Clear everything that is inside frame buffer in ESP32 + // Now, let's draw some random pixels! + display.clearDisplay(); // Clear everything that is inside frame buffer in ESP32 for (int i = 0; i < 1000; i++) - { //Write 1000 random colored pixels at random locations - display.drawPixel(random(0, 799), random(0, 599), random(0, 7)); //We are setting color of the pixels using numbers from 0 to 7, - } //where 0 mens black, 7 white and gray is in between + { // Write 1000 random colored pixels at random locations + display.drawPixel(random(0, 799), random(0, 599), + random(0, 7)); // We are setting color of the pixels using numbers from 0 to 7, + } // where 0 mens black, 7 white and gray is in between displayCurrentAction("Drawing 600 random pixels in random colors"); - display.display(); //Write everything from frame buffer to screen - delay(DELAY_MS); //Wait + display.display(); // Write everything from frame buffer to screen + delay(DELAY_MS); // Wait - //Draw two diagonal lines accros screen + // Draw two diagonal lines accros screen display.clearDisplay(); - display.drawLine(0, 0, 799, 599, 0); //All of those drawing fuctions originate from Adafruit GFX library, so maybe you are already familiar - display.drawLine(799, 0, 0, 599, 0); //with those. Arguments are: start X, start Y, ending X, ending Y, color. + display.drawLine( + 0, 0, 799, 599, + 0); // All of those drawing fuctions originate from Adafruit GFX library, so maybe you are already familiar + display.drawLine(799, 0, 0, 599, 0); // with those. Arguments are: start X, start Y, ending X, ending Y, color. displayCurrentAction("Drawing two diagonal lines"); display.display(); delay(DELAY_MS); - //And again, let's draw some random lines on screen! + // And again, let's draw some random lines on screen! display.clearDisplay(); for (int i = 0; i < 100; i++) { @@ -79,43 +89,45 @@ void loop() display.display(); delay(DELAY_MS); - //Let's draw some random thick lines on screen! + // Let's draw some random thick lines on screen! display.clearDisplay(); for (int i = 0; i < 100; i++) { - display.drawThickLine(random(0, 799), random(0, 599), random(0, 799), random(0, 599), random(0, 7), (float)random(1, 20)); + display.drawThickLine(random(0, 799), random(0, 599), random(0, 799), random(0, 599), random(0, 7), + (float)random(1, 20)); } displayCurrentAction("Drawing 50 random lines in random colors and thickness"); display.display(); delay(DELAY_MS); - //Let's draw some random gradient thick lines on screen! + // Let's draw some random gradient thick lines on screen! display.clearDisplay(); for (int i = 0; i < 100; i++) { int startColor = random(0, 7); int endColor = random(startColor, 7); - display.drawGradientLine(random(0, 799), random(0, 599), random(0, 799), random(0, 599), startColor, endColor, (float)random(1, 20)); + display.drawGradientLine(random(0, 799), random(0, 599), random(0, 799), random(0, 599), startColor, endColor, + (float)random(1, 20)); } displayCurrentAction("Drawing 50 random gradient lines in random colors and thickness"); display.display(); delay(DELAY_MS); - //Now draw one horizontal... + // Now draw one horizontal... display.clearDisplay(); - display.drawFastHLine(100, 100, 600, 0); //Arguments are: starting X, starting Y, length, color + display.drawFastHLine(100, 100, 600, 0); // Arguments are: starting X, starting Y, length, color displayCurrentAction("Drawing one horizontal line"); display.display(); delay(DELAY_MS); //... and one vertical line display.clearDisplay(); - display.drawFastVLine(100, 100, 400, 0); //Arguments are: starting X, starting Y, length, color + display.drawFastVLine(100, 100, 400, 0); // Arguments are: starting X, starting Y, length, color displayCurrentAction("Drawing one vertical line"); display.display(); delay(DELAY_MS); - //Now, let' make a grid using only horizontal and vertical lines in random colors! + // Now, let' make a grid using only horizontal and vertical lines in random colors! display.clearDisplay(); for (int i = 0; i < 800; i += 8) { @@ -129,14 +141,14 @@ void loop() display.display(); delay(DELAY_MS); - //Draw rectangle at X = 200, Y = 200 and size of 400x300 pixels + // Draw rectangle at X = 200, Y = 200 and size of 400x300 pixels display.clearDisplay(); - display.drawRect(200, 200, 400, 300, 0); //Arguments are: start X, start Y, size X, size Y, color + display.drawRect(200, 200, 400, 300, 0); // Arguments are: start X, start Y, size X, size Y, color displayCurrentAction("Drawing rectangle"); display.display(); delay(DELAY_MS); - //Draw rectangles on random location, size 100x150 pixels in random color + // Draw rectangles on random location, size 100x150 pixels in random color display.clearDisplay(); for (int i = 0; i < 50; i++) { @@ -146,14 +158,14 @@ void loop() display.display(); delay(DELAY_MS); - //Draw filled black rectangle at X = 200, Y = 200, size of 400x300 pixels in gray color + // Draw filled black rectangle at X = 200, Y = 200, size of 400x300 pixels in gray color display.clearDisplay(); - display.fillRect(200, 200, 400, 300, 4); //Arguments are: start X, start Y, size X, size Y, color + display.fillRect(200, 200, 400, 300, 4); // Arguments are: start X, start Y, size X, size Y, color displayCurrentAction("Drawing gray rectangle"); display.display(); delay(DELAY_MS); - //Draw filled random colored rectangles on random location, size of 30x30 pixels in radnom color + // Draw filled random colored rectangles on random location, size of 30x30 pixels in radnom color display.clearDisplay(); for (int i = 0; i < 50; i++) { @@ -163,14 +175,14 @@ void loop() display.display(); delay(DELAY_MS); - //Draw circle at center of a screen with radius of 75 pixels + // Draw circle at center of a screen with radius of 75 pixels display.clearDisplay(); - display.drawCircle(400, 300, 75, 0); //Arguments are: start X, start Y, radius, color + display.drawCircle(400, 300, 75, 0); // Arguments are: start X, start Y, radius, color displayCurrentAction("Drawing a circle"); display.display(); delay(DELAY_MS); - //Draw some random colored circles at random location with radius of 25 pixels in random color + // Draw some random colored circles at random location with radius of 25 pixels in random color display.clearDisplay(); for (int i = 0; i < 40; i++) { @@ -180,31 +192,31 @@ void loop() display.display(); delay(DELAY_MS); - //Draw black filled circle at center of a screen with radius of 75 pixels + // Draw black filled circle at center of a screen with radius of 75 pixels display.clearDisplay(); - display.fillCircle(400, 300, 75, 0); //Arguments are: start X, start Y, radius, color + display.fillCircle(400, 300, 75, 0); // Arguments are: start X, start Y, radius, color displayCurrentAction("Drawing black-filled circle"); display.display(); delay(DELAY_MS); - //Draw some random colored filled circles at random location with radius of 15 pixels + // Draw some random colored filled circles at random location with radius of 15 pixels display.clearDisplay(); for (int i = 0; i < 40; i++) { display.fillCircle(random(0, 799), random(0, 599), 15, random(0, 7)); } displayCurrentAction("Drawing many filled circles randomly in random colors"); - display.display(); //To show stuff on screen, you always need to call display.display(); + display.display(); // To show stuff on screen, you always need to call display.display(); delay(DELAY_MS); - //Draw rounded rectangle at X = 200, Y = 200 and size of 400x300 pixels and radius of 10 pixels + // Draw rounded rectangle at X = 200, Y = 200 and size of 400x300 pixels and radius of 10 pixels display.clearDisplay(); - display.drawRoundRect(200, 200, 400, 300, 10, 0); //Arguments are: start X, start Y, size X, size Y, radius, color + display.drawRoundRect(200, 200, 400, 300, 10, 0); // Arguments are: start X, start Y, size X, size Y, radius, color displayCurrentAction("Drawing rectangle with rounded edges"); display.display(); delay(DELAY_MS); - //Draw rounded rectangles on random location, size 100x150 pixels, radius of 5 pixels in radnom color + // Draw rounded rectangles on random location, size 100x150 pixels, radius of 5 pixels in radnom color display.clearDisplay(); for (int i = 0; i < 50; i++) { @@ -214,14 +226,14 @@ void loop() display.display(); delay(DELAY_MS); - //Draw filled random colored rectangle at X = 200, Y = 200, size of 400x300 pixels and radius of 10 pixels + // Draw filled random colored rectangle at X = 200, Y = 200, size of 400x300 pixels and radius of 10 pixels display.clearDisplay(); - display.fillRoundRect(200, 200, 400, 300, 10, 0); //Arguments are: start X, start Y, size X, size Y, radius, color + display.fillRoundRect(200, 200, 400, 300, 10, 0); // Arguments are: start X, start Y, size X, size Y, radius, color displayCurrentAction("Drawing filled rectangle with rounded edges"); display.display(); delay(DELAY_MS); - //Draw filled random colored rectangle on random location, size of 30x30 pixels, radius of 3 pixels in radnom color + // Draw filled random colored rectangle on random location, size of 30x30 pixels, radius of 3 pixels in radnom color display.clearDisplay(); for (int i = 0; i < 50; i++) { @@ -231,43 +243,47 @@ void loop() display.display(); delay(DELAY_MS); - //Draw simple triangle + // Draw simple triangle display.clearDisplay(); - display.drawTriangle(250, 400, 550, 400, 400, 100, 0); //Arguments are: X1, Y1, X2, Y2, X3, Y3, color + display.drawTriangle(250, 400, 550, 400, 400, 100, 0); // Arguments are: X1, Y1, X2, Y2, X3, Y3, color display.display(); delay(DELAY_MS); - //Draw filled triangle inside simple triangle (so no display.clearDisplay() this time) - display.fillTriangle(300, 350, 500, 350, 400, 150, 0); //Arguments are: X1, Y1, X2, Y2, X3, Y3, color + // Draw filled triangle inside simple triangle (so no display.clearDisplay() this time) + display.fillTriangle(300, 350, 500, 350, 400, 150, 0); // Arguments are: X1, Y1, X2, Y2, X3, Y3, color displayCurrentAction("Drawing filled triangle inside exsisting one"); display.display(); delay(DELAY_MS); - //Display some grayscale image on screen. We are going to display e-radionica logo on display at location X = 100, Y = 100 - //Image size is 500x332 pixels. + // Display some grayscale image on screen. We are going to display e-radionica logo on display at location X = 100, + // Y = 100 Image size is 500x332 pixels. display.clearDisplay(); - display.drawBitmap3Bit(100, 100, picture1, 500, 332); //Arguments are: start X, start Y, array variable name, size X, size Y + display.drawBitmap3Bit(100, 100, picture1, 500, + 332); // Arguments are: start X, start Y, array variable name, size X, size Y displayCurrentAction("Drawing a bitmap image"); display.display(); delay(DELAY_MS); - //Write some text on screen with different sizes and color + // Write some text on screen with different sizes and color display.clearDisplay(); for (int i = 0; i < 6; i++) { display.setTextColor(i); - display.setTextSize(i + 1); //textSize parameter starts at 0 and goes up to 10 (larger won't fit Inkplate 6 screen) - display.setCursor(200, (i * i * 8)); //setCursor works as same as on LCD displays - sets "the cursor" at the place you want to write someting next - display.print("INKPLATE6!"); //The actual text you want to show on e-paper as String + display.setTextSize(i + + 1); // textSize parameter starts at 0 and goes up to 10 (larger won't fit Inkplate 6 screen) + display.setCursor(200, (i * i * 8)); // setCursor works as same as on LCD displays - sets "the cursor" at the + // place you want to write someting next + display.print("INKPLATE6!"); // The actual text you want to show on e-paper as String } displayCurrentAction("Text in different sizes and shadings"); - display.display(); //To show stuff on screen, you always need to call display.display(); + display.display(); // To show stuff on screen, you always need to call display.display(); delay(DELAY_MS); - //Write same text on different location, but now invert colors (text is white, text background is black) - display.setTextColor(7, 0); //First argument is text color, while second argument is background color. In greyscale, + // Write same text on different location, but now invert colors (text is white, text background is black) + display.setTextColor(7, 0); // First argument is text color, while second argument is background color. In + // greyscale, for (int i = 0; i < 6; i++) - { //you are able to choose from 8 different colors (0-7) + { // you are able to choose from 8 different colors (0-7) display.setTextSize(i + 1); display.setCursor(200, 300 + (i * i * 8)); display.print("INKPLATE6!"); @@ -328,7 +344,7 @@ void loop() delay(DELAY_MS); - //Write text and rotate it by 90 deg. forever + // Write text and rotate it by 90 deg. forever int r = 0; display.setTextSize(8); display.setTextColor(7, 0); @@ -336,18 +352,19 @@ void loop() { display.setCursor(100, 100); display.clearDisplay(); - display.setRotation(r); //Set rotation will sent rotation for the entire display, so you can use it sideways or upside-down + display.setRotation( + r); // Set rotation will sent rotation for the entire display, so you can use it sideways or upside-down display.print("INKPLATE6"); display.display(); r++; delay(DELAY_MS); } - //Did you know that you can change between monochrome and greyscale mode anytime? - //Just call Inkplate display(INKPLATE_1BIT) or Inkplate display(INKPLATE_3BIT) + // Did you know that you can change between monochrome and greyscale mode anytime? + // Just call Inkplate display(INKPLATE_1BIT) or Inkplate display(INKPLATE_3BIT) } -//Small function that will write on the screen what function is currently in demonstration. +// Small function that will write on the screen what function is currently in demonstration. void displayCurrentAction(String text) { display.setTextSize(2); diff --git a/src/Inkplate.cpp b/src/Inkplate.cpp index b827d1f..89cfa4b 100644 --- a/src/Inkplate.cpp +++ b/src/Inkplate.cpp @@ -95,7 +95,7 @@ #define DATA 0x0E8C0030 -Inkplate::Inkplate(uint8_t _mode) : Graphics(E_INK_WIDTH, E_INK_HEIGHT) +Inkplate::Inkplate(uint8_t _mode) : Adafruit_GFX(E_INK_WIDTH, E_INK_HEIGHT), Graphics(E_INK_WIDTH, E_INK_HEIGHT) { setDisplayMode(_mode); for (uint32_t i = 0; i < 256; ++i) @@ -194,7 +194,7 @@ void Inkplate::display1b() { memcpy(DMemoryNew, _partial, 60000); - uint16_t _pos; + uint32_t _send; uint8_t data; uint8_t dram; @@ -209,23 +209,23 @@ void Inkplate::display1b() cleanFast(0, 11); for (int k = 0; k < 3; ++k) { - _pos = 59999; + uint8_t *DMemoryNewPtr = DMemoryNew + 59999; vscan_start(); for (int i = 0; i < 600; ++i) { - dram = *(DMemoryNew + _pos); - data = LUTB[(dram >> 4) & 0x0F]; + dram = *(DMemoryNewPtr--); + data = LUTB[dram >> 4]; _send = pinLUT[data]; hscan_start(_send); data = LUTB[dram & 0x0F]; _send = pinLUT[data]; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; - _pos--; + for (int j = 0; j < 99; ++j) { - dram = *(DMemoryNew + _pos); - data = LUTB[(dram >> 4) & 0x0F]; + dram = *(DMemoryNewPtr--); + data = LUTB[dram >> 4]; _send = pinLUT[data]; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; @@ -233,7 +233,6 @@ void Inkplate::display1b() _send = pinLUT[data]; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; - _pos--; } GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; @@ -242,12 +241,12 @@ void Inkplate::display1b() delayMicroseconds(230); } - _pos = 59999; + uint16_t _pos = 59999; vscan_start(); for (int i = 0; i < 600; ++i) { dram = *(DMemoryNew + _pos); - data = LUT2[(dram >> 4) & 0x0F]; + data = LUT2[dram >> 4]; _send = pinLUT[data]; hscan_start(_send); data = LUT2[dram & 0x0F]; @@ -258,7 +257,7 @@ void Inkplate::display1b() for (int j = 0; j < 99; ++j) { dram = *(DMemoryNew + _pos); - data = LUT2[(dram >> 4) & 0x0F]; + data = LUT2[dram >> 4]; _send = pinLUT[data]; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; @@ -278,10 +277,10 @@ void Inkplate::display1b() for (int i = 0; i < 600; ++i) { dram = *(DMemoryNew + _pos); - data = 0b00000000; + data = 0; _send = pinLUT[data]; hscan_start(_send); - data = 0b00000000; + data = 0; GPIO.out_w1ts = (_send) | CL; GPIO.out_w1tc = DATA | CL; for (int j = 0; j < 99; ++j) @@ -387,10 +386,9 @@ void Inkplate::partialUpdate() uint16_t _pos = 59999; uint32_t _send; - uint8_t data; + uint8_t data = 0; uint8_t diffw, diffb; uint32_t n = 119999; - uint8_t dram; for (int i = 0; i < 600; ++i) { @@ -459,7 +457,7 @@ void Inkplate::clean() void Inkplate::cleanFast(uint8_t c, uint8_t rep) { einkOn(); - uint8_t data; + uint8_t data = 0; if (c == 0) data = B10101010; else if (c == 1) diff --git a/src/include/Font.cpp b/src/include/Font.cpp deleted file mode 100644 index 81dafc4..0000000 --- a/src/include/Font.cpp +++ /dev/null @@ -1,346 +0,0 @@ -#include "Font.h" - -inline GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) -{ - return gfxFont->glyph + c; -} - -inline uint8_t *pgm_read_bitmap_ptr(const GFXfont *gfxFont) -{ - return gfxFont->bitmap; -} - -void Font::setCursor(int16_t x, int16_t y) -{ - cursor_x = x; - cursor_y = y; -} - -void Font::setTextColor(uint16_t c) -{ - textcolor = textbgcolor = c; -} - -void Font::setTextColor(uint16_t c, uint16_t bg) -{ - textcolor = c; - textbgcolor = bg; -} - -void Font::setTextWrap(bool w) -{ - wrap = w; -} - -void Font::cp437(bool x = true) -{ - _cp437 = x; -} - -int16_t Font::getCursorX() -{ - return cursor_x; -} - -int16_t Font::getCursorY() -{ - return cursor_y; -} - -void Font::setTextSize(uint8_t s) -{ - setTextSize(s, s); -} - -void Font::setTextSize(uint8_t s_x, uint8_t s_y) -{ - textsize_x = (s_x > 0) ? s_x : 1; - textsize_y = (s_y > 0) ? s_y : 1; -} - -void Font::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size) -{ - drawChar(x, y, c, color, bg, size, size); -} - -void Font::drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size_x, uint8_t size_y) -{ - if (!gfxFont) - { - if ((x >= width()) || // Clip right - (y >= height()) || // Clip bottom - ((x + 6 * size_x - 1) < 0) || // Clip left - ((y + 8 * size_y - 1) < 0)) // Clip top - return; - - if (!_cp437 && (c >= 176)) - c++; - - startWrite(); - for (int8_t i = 0; i < 5; i++) - { - uint8_t line = pgm_read_byte(&font[c * 5 + i]); - for (int8_t j = 0; j < 8; j++, line >>= 1) - { - if (line & 1) - { - if (size_x == 1 && size_y == 1) - writePixel(x + i, y + j, color); - else - writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y, color); - } - else if (bg != color) - { - if (size_x == 1 && size_y == 1) - writePixel(x + i, y + j, bg); - else - writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y, bg); - } - } - } - if (bg != color) - { - if (size_x == 1 && size_y == 1) - writeFastVLine(x + 5, y, 8, bg); - else - writeFillRect(x + 5 * size_x, y, size_x, 8 * size_y, bg); - } - endWrite(); - } - else - { - c -= (uint8_t)pgm_read_byte(&gfxFont->first); - GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c); - uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont); - - uint16_t bo = pgm_read_word(&glyph->bitmapOffset); - uint8_t w = pgm_read_byte(&glyph->width), h = pgm_read_byte(&glyph->height); - int8_t xo = pgm_read_byte(&glyph->xOffset), yo = pgm_read_byte(&glyph->yOffset); - uint8_t xx, yy, bits = 0, bit = 0; - int16_t xo16 = 0, yo16 = 0; - - if (size_x > 1 || size_y > 1) - { - xo16 = xo; - yo16 = yo; - } - - startWrite(); - for (yy = 0; yy < h; yy++) - { - for (xx = 0; xx < w; xx++) - { - if (!(bit++ & 7)) - { - bits = pgm_read_byte(&bitmap[bo++]); - } - if (bits & 0x80) - { - if (size_x == 1 && size_y == 1) - { - writePixel(x + xo + xx, y + yo + yy, color); - } - else - { - writeFillRect(x + (xo16 + xx) * size_x, y + (yo16 + yy) * size_y, size_x, size_y, color); - } - } - bits <<= 1; - } - } - endWrite(); - } -} - -size_t Font::write(uint8_t c) -{ - if (!gfxFont) - { // 'Classic' built-in font - - if (c == '\n') - { // Newline? - cursor_x = 0; // Reset x to zero, - cursor_y += textsize_y * 8; // advance y one line - } - else if (c != '\r') - { // Ignore carriage returns - if (wrap && ((cursor_x + textsize_x * 6) > width())) - { // Off right? - cursor_x = 0; // Reset x to zero, - cursor_y += textsize_y * 8; // advance y one line - } - drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize_x, textsize_y); - cursor_x += textsize_x * 6; // Advance x one char - } - } - else - { // Custom font - - if (c == '\n') - { - cursor_x = 0; - cursor_y += (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); - } - else if (c != '\r') - { - uint8_t first = pgm_read_byte(&gfxFont->first); - if ((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) - { - GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first); - uint8_t w = pgm_read_byte(&glyph->width), h = pgm_read_byte(&glyph->height); - if ((w > 0) && (h > 0)) - { // Is there an associated bitmap? - int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic - if (wrap && ((cursor_x + textsize_x * (xo + w)) > width())) - { - cursor_x = 0; - cursor_y += (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); - } - drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize_x, textsize_y); - } - cursor_x += (uint8_t)pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize_x; - } - } - } - return 1; -} - -void Font::setFont(const GFXfont *f) -{ - if (f) - { - if (!gfxFont) - { - cursor_y += 6; - } - } - else if (gfxFont) - { - cursor_y -= 6; - } - gfxFont = (GFXfont *)f; -} - -void Font::charBounds(char c, int16_t *x, int16_t *y, int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy) -{ - if (gfxFont) - { - if (c == '\n') - { - *x = 0; - *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); - } - else if (c != '\r') - { - uint8_t first = pgm_read_byte(&gfxFont->first), last = pgm_read_byte(&gfxFont->last); - if ((c >= first) && (c <= last)) - { - GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first); - uint8_t gw = pgm_read_byte(&glyph->width), gh = pgm_read_byte(&glyph->height), - xa = pgm_read_byte(&glyph->xAdvance); - int8_t xo = pgm_read_byte(&glyph->xOffset), yo = pgm_read_byte(&glyph->yOffset); - if (wrap && ((*x + (((int16_t)xo + gw) * textsize_x)) > width())) - { - *x = 0; - *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); - } - int16_t tsx = (int16_t)textsize_x, tsy = (int16_t)textsize_y, x1 = *x + xo * tsx, y1 = *y + yo * tsy, - x2 = x1 + gw * tsx - 1, y2 = y1 + gh * tsy - 1; - if (x1 < *minx) - *minx = x1; - if (y1 < *miny) - *miny = y1; - if (x2 > *maxx) - *maxx = x2; - if (y2 > *maxy) - *maxy = y2; - *x += xa * tsx; - } - } - } - else - { - if (c == '\n') - { - *x = 0; - *y += textsize_y * 8; - } - else if (c != '\r') - { - if (wrap && ((*x + textsize_x * 6) > width())) - { - *x = 0; - *y += textsize_y * 8; - } - int x2 = *x + textsize_x * 6 - 1, y2 = *y + textsize_y * 8 - 1; - if (x2 > *maxx) - *maxx = x2; // Track max x, y - if (y2 > *maxy) - *maxy = y2; - if (*x < *minx) - *minx = *x; // Track min x, y - if (*y < *miny) - *miny = *y; - *x += textsize_x * 6; // Advance x one char - } - } -} - -void Font::getTextBounds(const char *str, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) -{ - uint8_t c; - - *x1 = x; - *y1 = y; - *w = *h = 0; - - int16_t minx = width(), miny = height(), maxx = -1, maxy = -1; - - while ((c = *str++)) - charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy); - - if (maxx >= minx) - { - *x1 = minx; - *w = maxx - minx + 1; - } - if (maxy >= miny) - { - *y1 = miny; - *h = maxy - miny + 1; - } -} - -void Font::getTextBounds(const String &str, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h) -{ - if (str.length() != 0) - { - getTextBounds(const_cast(str.c_str()), x, y, x1, y1, w, h); - } -} - -void Font::getTextBounds(const __FlashStringHelper *str, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, - uint16_t *h) -{ - uint8_t *s = (uint8_t *)str, c; - - *x1 = x; - *y1 = y; - *w = *h = 0; - - int16_t minx = width(), miny = height(), maxx = -1, maxy = -1; - - while ((c = pgm_read_byte(s++))) - charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy); - - if (maxx >= minx) - { - *x1 = minx; - *w = maxx - minx + 1; - } - if (maxy >= miny) - { - *y1 = miny; - *h = maxy - miny + 1; - } -} \ No newline at end of file diff --git a/src/include/Font.h b/src/include/Font.h deleted file mode 100644 index 6eaa55c..0000000 --- a/src/include/Font.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef __FONT_H__ -#define __FONT_H__ - -#include "Arduino.h" -#include "Print.h" - -#include "../libs/GFXFont/gfxfont.h" -#include "../libs/GFXFont/glcdfont.c" - - -class Font : public Print -{ - public: - virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0; - - virtual int16_t width() = 0; - virtual int16_t height() = 0; - - virtual size_t write(uint8_t); - - void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size); - void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size_x, uint8_t size_y); - - void getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); - void getTextBounds(const __FlashStringHelper *s, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, - uint16_t *h); - void getTextBounds(const String &str, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); - - void setTextSize(uint8_t s); - void setTextSize(uint8_t sx, uint8_t sy); - - void setFont(const GFXfont *f = NULL); - - int16_t getCursorX(); - int16_t getCursorY(); - void setCursor(int16_t x, int16_t y); - - void setTextColor(uint16_t c); - void setTextColor(uint16_t c, uint16_t bg); - - void setTextWrap(bool w); - void cp437(bool x); - - private: - int16_t cursor_x = 0; - int16_t cursor_y = 0; - uint16_t textcolor, textbgcolor; - uint8_t textsize_x, textsize_y; - bool wrap, _cp437; - - virtual void startWrite(void) = 0; - virtual void writePixel(int16_t x, int16_t y, uint16_t color) = 0; - virtual void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) = 0; - virtual void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) = 0; - virtual void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) = 0; - virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color) = 0; - virtual void endWrite(void) = 0; - - protected: - GFXfont *gfxFont; - void charBounds(char c, int16_t *x, int16_t *y, int16_t *minx, int16_t *miny, int16_t *maxx, int16_t *maxy); -}; - -#endif \ No newline at end of file diff --git a/src/include/Graphics.cpp b/src/include/Graphics.cpp index d428ca9..d5bcb4e 100644 --- a/src/include/Graphics.cpp +++ b/src/include/Graphics.cpp @@ -13,19 +13,6 @@ } #endif -Graphics::Graphics(int16_t w, int16_t h) -{ - _width = WIDTH = w; - _height = HEIGHT = h; - setRotation(0); - setCursor(0, 0); - setTextSize(1); - setTextColor(0xFFFF, 0xFFFF); - setTextWrap(true); - cp437(false); - gfxFont = NULL; -} - void Graphics::setRotation(uint8_t x) { rotation = (x & 3); @@ -84,7 +71,7 @@ void Graphics::writePixel(int16_t x0, int16_t y0, uint16_t color) int x = x0 >> 3; int x_sub = x0 & 7; uint8_t temp = *(_partial + 100 * y0 + x); - *(_partial + 100 * y0 + x) = ~pixelMaskLUT[x_sub] & temp | (color ? pixelMaskLUT[x_sub] : 0); + *(_partial + 100 * y0 + x) = (~pixelMaskLUT[x_sub] & temp) | (color ? pixelMaskLUT[x_sub] : 0); } else { @@ -93,7 +80,7 @@ void Graphics::writePixel(int16_t x0, int16_t y0, uint16_t color) int x_sub = x0 & 1; uint8_t temp; temp = *(D_memory4Bit + 400 * y0 + x); - *(D_memory4Bit + 400 * y0 + x) = pixelMaskGLUT[x_sub] & temp | (x_sub ? color : color << 4); + *(D_memory4Bit + 400 * y0 + x) = (pixelMaskGLUT[x_sub] & temp) | (x_sub ? color : color << 4); } } diff --git a/src/include/Graphics.h b/src/include/Graphics.h index 8e89c6a..661eb0b 100644 --- a/src/include/Graphics.h +++ b/src/include/Graphics.h @@ -1,9 +1,8 @@ -#ifndef __Graphics_H__ -#define __Graphics_H__ +#ifndef __GRAPHICS_H__ +#define __GRAPHICS_H__ #include "Arduino.h" -#include "Font.h" #include "Image.h" #include "Shapes.h" @@ -26,15 +25,15 @@ #endif -class Graphics : public Shapes, public Image, public Font +class Graphics : public Shapes, public Image { public: - Graphics(int16_t w, int16_t h); + Graphics(int16_t w, int16_t h) : Adafruit_GFX(w, h), Shapes(w, h), Image(w, h){}; void setRotation(uint8_t r); uint8_t getRotation(); - inline void drawPixel(int16_t x, int16_t y, uint16_t color) override; + void drawPixel(int16_t x, int16_t y, uint16_t color) override; void selectDisplayMode(uint8_t _mode); @@ -65,7 +64,7 @@ class Graphics : public Shapes, public Image, public Font private: void startWrite(void) override; - inline void writePixel(int16_t x, int16_t y, uint16_t color) override; + void writePixel(int16_t x, int16_t y, uint16_t color) override; void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) override; void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) override; void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) override; @@ -75,9 +74,6 @@ class Graphics : public Shapes, public Image, public Font uint8_t _displayMode = 0; protected: - int16_t WIDTH, HEIGHT; - int16_t _width, _height; - uint8_t rotation = 0; }; #endif \ No newline at end of file diff --git a/src/include/Image.cpp b/src/include/Image.cpp index 504ae09..fc219c2 100644 --- a/src/include/Image.cpp +++ b/src/include/Image.cpp @@ -9,7 +9,7 @@ Image *_imagePtrJpeg = nullptr; -Image::Image() +Image::Image(int16_t w, int16_t h) : Adafruit_GFX(w, h) { _imagePtrJpeg = this; } @@ -35,6 +35,7 @@ bool Image::drawImage(const char *path, int x, int y, bool dither, bool invert) if (strstr(path, ".jpg") != NULL || strstr(path, ".jpeg") != NULL) return drawJpegFromSd(path, x, y, dither, invert); } + return 0; }; bool Image::drawImage(const uint8_t *buf, int x, int y, int16_t w, int16_t h, uint8_t c, uint8_t bg) @@ -45,30 +46,7 @@ bool Image::drawImage(const uint8_t *buf, int x, int y, int16_t w, int16_t h, ui drawBitmap(x, y, buf, w, h, c, bg); else if (getDisplayMode() == INKPLATE_3BIT) drawBitmap3Bit(x, y, buf, w, h); -} - -void Image::drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg) -{ - int16_t byteWidth = (w + 7) >> 3; // Bitmap scanline pad = whole byte - uint8_t byte = 0; - - startWrite(); - for (int16_t j = 0; j < h; j++, y++) - { - for (int16_t i = 0; i < w; i++) - { - if (i & 7) - byte <<= 1; - else - byte = bitmap[j * byteWidth + (i >> 3)]; - - if (byte & 0x80) - writePixel(x + i, y, color); - else if (bg != 0xFFFF) - writePixel(x + i, y, bg); - } - } - endWrite(); + return 1; } void Image::drawBitmap3Bit(int16_t _x, int16_t _y, const unsigned char *_p, int16_t _w, int16_t _h) diff --git a/src/include/Image.h b/src/include/Image.h index 0ded7d5..09921a3 100644 --- a/src/include/Image.h +++ b/src/include/Image.h @@ -1,16 +1,17 @@ #ifndef __IMAGE_H__ #define __IMAGE_H__ +#include "../libs/Adafruit-GFX-Library/Adafruit_GFX.h" #include "../libs/SdFat/SdFat.h" #include "Arduino.h" #include "Network.h" #include "WiFiClient.h" #include "defines.h" -class Image : virtual public Network +class Image : virtual public Network, virtual public Adafruit_GFX { public: - Image(); + Image(int16_t w, int16_t h); virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0; @@ -23,8 +24,11 @@ class Image : virtual public Network bool drawImage(const String path, int x, int y, bool dither = 1, bool invert = 0); bool drawImage(const uint8_t *buf, int x, int y, int16_t w, int16_t h, uint8_t c = BLACK, uint8_t bg = 0xFF); - void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, - uint16_t bg = 0xFFFF); + // Defined in Adafruit-GFX-Library, but should fit here + // void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color); + // void drawBitmap(int16_t x, int16_t y, const uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, + // uint16_t bg); + void drawBitmap3Bit(int16_t _x, int16_t _y, const unsigned char *_p, int16_t _w, int16_t _h); bool drawBitmapFromBuffer(uint8_t *buf, int x, int y, bool dither, bool invert); diff --git a/src/include/ImageBMP.cpp b/src/include/ImageBMP.cpp index c54b918..c48d70a 100644 --- a/src/include/ImageBMP.cpp +++ b/src/include/ImageBMP.cpp @@ -116,7 +116,7 @@ bool Image::drawBitmapFromWeb(const char *url, int x, int y, bool dither, bool i ret = drawBitmapFromBuffer(buf, x, y, dither, invert); free(buf); - return 1; + return ret; } bool Image::drawBitmapFromWeb(WiFiClient *s, int x, int y, int32_t len, bool dither, bool invert) @@ -127,7 +127,7 @@ bool Image::drawBitmapFromWeb(WiFiClient *s, int x, int y, int32_t len, bool dit ret = drawBitmapFromBuffer(buf, x, y, dither, invert); free(buf); - return 1; + return ret; } bool Image::drawBitmapFromBuffer(uint8_t *buf, int x, int y, bool dither, bool invert) @@ -155,7 +155,7 @@ bool Image::drawBitmapFromBuffer(uint8_t *buf, int x, int y, bool dither, bool i void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool dither, bool invert) { - int16_t w = bmpHeader->width, h = bmpHeader->height; + int16_t w = bmpHeader->width; int8_t c = bmpHeader->color; startWrite(); @@ -164,7 +164,7 @@ void Image::displayBmpLine(int16_t x, int16_t y, bitmapHeader *bmpHeader, bool d switch (c) { case 1: - writePixel(x + j, y, (invert ^ (palette[0] < palette[1])) ^ !!(pixelBuffer[j >> 3] & (1 << (7 - j & 7)))); + writePixel(x + j, y, (invert ^ (palette[0] < palette[1])) ^ !!(pixelBuffer[j >> 3] & (1 << (7 - (j & 7))))); break; // as for 2 bit, literally cannot find an example online or in PS, so skipped case 4: { diff --git a/src/include/Shapes.cpp b/src/include/Shapes.cpp index 6682b49..6dd18a9 100644 --- a/src/include/Shapes.cpp +++ b/src/include/Shapes.cpp @@ -13,322 +13,6 @@ } #endif -void Shapes::drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color) -{ - startWrite(); - writeFastVLine(x, y, h, color); - endWrite(); -} - -void Shapes::drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color) -{ - startWrite(); - writeFastHLine(x, y, w, color); - endWrite(); -} - -void Shapes::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) -{ - startWrite(); - writeFillRect(x, y, w, h, color); - endWrite(); -} - -void Shapes::fillScreen(uint16_t color) -{ - startWrite(); - fillRect(0, 0, width(), height(), color); - endWrite(); -} - -void Shapes::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color) -{ - if (x0 == x1) - { - if (y0 > y1) - { - _swap_int16_t(y0, y1); - } - drawFastVLine(x0, y0, y1 - y0 + 1, color); - } - else if (y0 == y1) - { - if (x0 > x1) - { - _swap_int16_t(x0, x1); - } - drawFastHLine(x0, y0, x1 - x0 + 1, color); - } - else - { - startWrite(); - writeLine(x0, y0, x1, y1, color); - endWrite(); - } -} - -void Shapes::drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color) -{ - int16_t f = 1 - r; - int16_t ddF_x = 1; - int16_t ddF_y = -2 * r; - int16_t x = 0; - int16_t y = r; - - startWrite(); - writePixel(x0, y0 + r, color); - writePixel(x0, y0 - r, color); - writePixel(x0 + r, y0, color); - writePixel(x0 - r, y0, color); - - while (x < y) - { - if (f >= 0) - { - y--; - ddF_y += 2; - f += ddF_y; - } - x++; - ddF_x += 2; - f += ddF_x; - - writePixel(x0 + x, y0 + y, color); - writePixel(x0 - x, y0 + y, color); - writePixel(x0 + x, y0 - y, color); - writePixel(x0 - x, y0 - y, color); - writePixel(x0 + y, y0 + x, color); - writePixel(x0 - y, y0 + x, color); - writePixel(x0 + y, y0 - x, color); - writePixel(x0 - y, y0 - x, color); - } - endWrite(); -} - -void Shapes::drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color) -{ - startWrite(); - int16_t f = 1 - r; - int16_t ddF_x = 1; - int16_t ddF_y = -2 * r; - int16_t x = 0; - int16_t y = r; - - while (x < y) - { - if (f >= 0) - { - y--; - ddF_y += 2; - f += ddF_y; - } - x++; - ddF_x += 2; - f += ddF_x; - if (cornername & 0x4) - { - writePixel(x0 + x, y0 + y, color); - writePixel(x0 + y, y0 + x, color); - } - if (cornername & 0x2) - { - writePixel(x0 + x, y0 - y, color); - writePixel(x0 + y, y0 - x, color); - } - if (cornername & 0x8) - { - writePixel(x0 - y, y0 + x, color); - writePixel(x0 - x, y0 + y, color); - } - if (cornername & 0x1) - { - writePixel(x0 - y, y0 - x, color); - writePixel(x0 - x, y0 - y, color); - } - } - endWrite(); -} - -void Shapes::fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color) -{ - startWrite(); - writeFastVLine(x0, y0 - r, 2 * r + 1, color); - fillCircleHelper(x0, y0, r, 3, 0, color); - endWrite(); -} - -void Shapes::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t corners, int16_t delta, uint16_t color) -{ - startWrite(); - int16_t f = 1 - r; - int16_t ddF_x = 1; - int16_t ddF_y = -2 * r; - int16_t x = 0; - int16_t y = r; - int16_t px = x; - int16_t py = y; - - ++delta; - - while (x < y) - { - if (f >= 0) - { - y--; - ddF_y += 2; - f += ddF_y; - } - x++; - ddF_x += 2; - f += ddF_x; - if (x < (y + 1)) - { - if (corners & 1) - writeFastVLine(x0 + x, y0 - y, 2 * y + delta, color); - if (corners & 2) - writeFastVLine(x0 - x, y0 - y, 2 * y + delta, color); - } - if (y != py) - { - if (corners & 1) - writeFastVLine(x0 + py, y0 - px, 2 * px + delta, color); - if (corners & 2) - writeFastVLine(x0 - py, y0 - px, 2 * px + delta, color); - py = y; - } - px = x; - } - endWrite(); -} - -void Shapes::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color) -{ - startWrite(); - writeFastHLine(x, y, w, color); - writeFastHLine(x, y + h - 1, w, color); - writeFastVLine(x, y, h, color); - writeFastVLine(x + w - 1, y, h, color); - endWrite(); -} - -void Shapes::drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color) -{ - int16_t max_radius = ((w < h) ? w : h) / 2; - if (r > max_radius) - r = max_radius; - - startWrite(); - writeFastHLine(x + r, y, w - 2 * r, color); - writeFastHLine(x + r, y + h - 1, w - 2 * r, color); - writeFastVLine(x, y + r, h - 2 * r, color); - writeFastVLine(x + w - 1, y + r, h - 2 * r, color); - endWrite(); - - drawCircleHelper(x + r, y + r, r, 1, color); - drawCircleHelper(x + w - r - 1, y + r, r, 2, color); - drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color); - drawCircleHelper(x + r, y + h - r - 1, r, 8, color); -} - -void Shapes::fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, int16_t r, uint16_t color) -{ - int16_t max_radius = ((w < h) ? w : h) / 2; - if (r > max_radius) - r = max_radius; - - startWrite(); - writeFillRect(x + r, y, w - 2 * r, h, color); - endWrite(); - - fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color); - fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color); -} - -void Shapes::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) -{ - startWrite(); - writeLine(x0, y0, x1, y1, color); - writeLine(x1, y1, x2, y2, color); - writeLine(x2, y2, x0, y0, color); - endWrite(); -} - - -void Shapes::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color) -{ - int16_t a, b, y, last; - - if (y0 > y1) - { - _swap_int16_t(y0, y1); - _swap_int16_t(x0, x1); - } - if (y1 > y2) - { - _swap_int16_t(y2, y1); - _swap_int16_t(x2, x1); - } - if (y0 > y1) - { - _swap_int16_t(y0, y1); - _swap_int16_t(x0, x1); - } - - startWrite(); - if (y0 == y2) - { - a = b = x0; - if (x1 < a) - a = x1; - else if (x1 > b) - b = x1; - - if (x2 < a) - a = x2; - else if (x2 > b) - b = x2; - - writeFastHLine(a, y0, b - a + 1, color); - endWrite(); - return; - } - - int16_t dx01 = x1 - x0, dy01 = y1 - y0, dx02 = x2 - x0, dy02 = y2 - y0, dx12 = x2 - x1, dy12 = y2 - y1; - int32_t sa = 0, sb = 0; - - if (y1 == y2) - last = y1; - else - last = y1 - 1; - - for (y = y0; y <= last; y++) - { - a = x0 + sa / dy01; - b = x0 + sb / dy02; - sa += dx01; - sb += dx02; - if (a > b) - _swap_int16_t(a, b); - writeFastHLine(a, y, b - a + 1, color); - } - - sa = (int32_t)dx12 * (y - y1); - sb = (int32_t)dx02 * (y - y0); - for (; y <= y2; y++) - { - a = x1 + sa / dy12; - b = x0 + sb / dy02; - sa += dx12; - sb += dx02; - - if (a > b) - _swap_int16_t(a, b); - writeFastHLine(a, y, b - a + 1, color); - } - endWrite(); -} - - void Shapes::drawElipse(int rx, int ry, int xc, int yc, int c) { float dx, dy, d1, d2, x, y; @@ -437,7 +121,6 @@ void Shapes::drawThickLine(int x1, int y1, int x2, int y2, int color, float thic float deg = atan2f((float)(y2 - y1), (float)(x2 - x1)); float l1 = tan(deg); - float k1 = (float)y1 - l1 * (float)x1; float degShift = (l1 < 0 ? M_PI_2 : -M_PI_2); diff --git a/src/include/Shapes.h b/src/include/Shapes.h index 21c3e86..22f9110 100644 --- a/src/include/Shapes.h +++ b/src/include/Shapes.h @@ -1,34 +1,19 @@ #ifndef __SHAPES_H__ #define __SHAPES_H__ +#include "../libs/Adafruit-GFX-Library/Adafruit_GFX.h" #include "Arduino.h" #include "Triangulate.h" -class Shapes +class Shapes : virtual public Adafruit_GFX { public: + Shapes(int16_t w, int16_t h) : Adafruit_GFX(w, h){}; + virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0; virtual void selectDisplayMode(uint8_t _mode) = 0; virtual uint8_t getDisplayMode() = 0; - virtual int16_t width() = 0; - virtual int16_t height() = 0; - - void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); - void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); - void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - void fillScreen(uint16_t color); - void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); - void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); - - void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color); - void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color); - void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color); - void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint16_t color); - void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color); - void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color); - void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color); - void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color); void drawElipse(int rx, int ry, int xc, int yc, int c); void fillElipse(int rx, int ry, int xc, int yc, int c); diff --git a/src/libs/Adafruit-GFX-Library/Adafruit_GFX.cpp b/src/libs/Adafruit-GFX-Library/Adafruit_GFX.cpp new file mode 100644 index 0000000..2bec297 --- /dev/null +++ b/src/libs/Adafruit-GFX-Library/Adafruit_GFX.cpp @@ -0,0 +1,2623 @@ +/* +This is the core graphics library for all our displays, providing a common +set of graphics primitives (points, lines, circles, etc.). It needs to be +paired with a hardware-specific library for each display device we carry +(to handle the lower-level functions). + +Adafruit invests time and resources providing this open source code, please +support Adafruit & open-source hardware by purchasing products from Adafruit! + +Copyright (c) 2013 Adafruit Industries. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +- Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +- Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. + */ + +#include "Adafruit_GFX.h" +#include "glcdfont.c" +#ifdef __AVR__ +#include +#elif defined(ESP8266) || defined(ESP32) +#include +#endif + +// Many (but maybe not all) non-AVR board installs define macros +// for compatibility with existing PROGMEM-reading AVR code. +// Do our own checks and defines here for good measure... + +#ifndef pgm_read_byte +#define pgm_read_byte(addr) (*(const unsigned char *)(addr)) +#endif +#ifndef pgm_read_word +#define pgm_read_word(addr) (*(const unsigned short *)(addr)) +#endif +#ifndef pgm_read_dword +#define pgm_read_dword(addr) (*(const unsigned long *)(addr)) +#endif + +// Pointers are a peculiar case...typically 16-bit on AVR boards, +// 32 bits elsewhere. Try to accommodate both... + +#if !defined(__INT_MAX__) || (__INT_MAX__ > 0xFFFF) +#define pgm_read_pointer(addr) ((void *)pgm_read_dword(addr)) +#else +#define pgm_read_pointer(addr) ((void *)pgm_read_word(addr)) +#endif + +inline GFXglyph *pgm_read_glyph_ptr(const GFXfont *gfxFont, uint8_t c) { +#ifdef __AVR__ + return &(((GFXglyph *)pgm_read_pointer(&gfxFont->glyph))[c]); +#else + // expression in __AVR__ section may generate "dereferencing type-punned + // pointer will break strict-aliasing rules" warning In fact, on other + // platforms (such as STM32) there is no need to do this pointer magic as + // program memory may be read in a usual way So expression may be simplified + return gfxFont->glyph + c; +#endif //__AVR__ +} + +inline uint8_t *pgm_read_bitmap_ptr(const GFXfont *gfxFont) { +#ifdef __AVR__ + return (uint8_t *)pgm_read_pointer(&gfxFont->bitmap); +#else + // expression in __AVR__ section generates "dereferencing type-punned pointer + // will break strict-aliasing rules" warning In fact, on other platforms (such + // as STM32) there is no need to do this pointer magic as program memory may + // be read in a usual way So expression may be simplified + return gfxFont->bitmap; +#endif //__AVR__ +} + +#ifndef min +#define min(a, b) (((a) < (b)) ? (a) : (b)) +#endif + +#ifndef _swap_int16_t +#define _swap_int16_t(a, b) \ + { \ + int16_t t = a; \ + a = b; \ + b = t; \ + } +#endif + +/**************************************************************************/ +/*! + @brief Instatiate a GFX context for graphics! Can only be done by a + superclass + @param w Display width, in pixels + @param h Display height, in pixels +*/ +/**************************************************************************/ +Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h) { + _width = WIDTH; + _height = HEIGHT; + rotation = 0; + cursor_y = cursor_x = 0; + textsize_x = textsize_y = 1; + textcolor = textbgcolor = 0xFFFF; + wrap = true; + _cp437 = false; + gfxFont = NULL; +} + +/**************************************************************************/ +/*! + @brief Write a line. Bresenham's algorithm - thx wikpedia + @param x0 Start point x coordinate + @param y0 Start point y coordinate + @param x1 End point x coordinate + @param y1 End point y coordinate + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t color) { +#if defined(ESP8266) + yield(); +#endif + int16_t steep = abs(y1 - y0) > abs(x1 - x0); + if (steep) { + _swap_int16_t(x0, y0); + _swap_int16_t(x1, y1); + } + + if (x0 > x1) { + _swap_int16_t(x0, x1); + _swap_int16_t(y0, y1); + } + + int16_t dx, dy; + dx = x1 - x0; + dy = abs(y1 - y0); + + int16_t err = dx / 2; + int16_t ystep; + + if (y0 < y1) { + ystep = 1; + } else { + ystep = -1; + } + + for (; x0 <= x1; x0++) { + if (steep) { + writePixel(y0, x0, color); + } else { + writePixel(x0, y0, color); + } + err -= dy; + if (err < 0) { + y0 += ystep; + err += dx; + } + } +} + +/**************************************************************************/ +/*! + @brief Start a display-writing routine, overwrite in subclasses. +*/ +/**************************************************************************/ +void Adafruit_GFX::startWrite() {} + +/**************************************************************************/ +/*! + @brief Write a pixel, overwrite in subclasses if startWrite is defined! + @param x x coordinate + @param y y coordinate + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::writePixel(int16_t x, int16_t y, uint16_t color) { + drawPixel(x, y, color); +} + +/**************************************************************************/ +/*! + @brief Write a perfectly vertical line, overwrite in subclasses if + startWrite is defined! + @param x Top-most x coordinate + @param y Top-most y coordinate + @param h Height in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::writeFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + // Overwrite in subclasses if startWrite is defined! + // Can be just writeLine(x, y, x, y+h-1, color); + // or writeFillRect(x, y, 1, h, color); + drawFastVLine(x, y, h, color); +} + +/**************************************************************************/ +/*! + @brief Write a perfectly horizontal line, overwrite in subclasses if + startWrite is defined! + @param x Left-most x coordinate + @param y Left-most y coordinate + @param w Width in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::writeFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + // Overwrite in subclasses if startWrite is defined! + // Example: writeLine(x, y, x+w-1, y, color); + // or writeFillRect(x, y, w, 1, color); + drawFastHLine(x, y, w, color); +} + +/**************************************************************************/ +/*! + @brief Write a rectangle completely with one color, overwrite in + subclasses if startWrite is defined! + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) { + // Overwrite in subclasses if desired! + fillRect(x, y, w, h, color); +} + +/**************************************************************************/ +/*! + @brief End a display-writing routine, overwrite in subclasses if + startWrite is defined! +*/ +/**************************************************************************/ +void Adafruit_GFX::endWrite() {} + +/**************************************************************************/ +/*! + @brief Draw a perfectly vertical line (this is often optimized in a + subclass!) + @param x Top-most x coordinate + @param y Top-most y coordinate + @param h Height in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + startWrite(); + writeLine(x, y, x, y + h - 1, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a perfectly horizontal line (this is often optimized in a + subclass!) + @param x Left-most x coordinate + @param y Left-most y coordinate + @param w Width in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + startWrite(); + writeLine(x, y, x + w - 1, y, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Fill a rectangle completely with one color. Update in subclasses if + desired! + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::fillRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) { + startWrite(); + for (int16_t i = x; i < x + w; i++) { + writeFastVLine(i, y, h, color); + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Fill the screen completely with one color. Update in subclasses if + desired! + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::fillScreen(uint16_t color) { + fillRect(0, 0, _width, _height, color); +} + +/**************************************************************************/ +/*! + @brief Draw a line + @param x0 Start point x coordinate + @param y0 Start point y coordinate + @param x1 End point x coordinate + @param y1 End point y coordinate + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + uint16_t color) { + // Update in subclasses if desired! + if (x0 == x1) { + if (y0 > y1) + _swap_int16_t(y0, y1); + drawFastVLine(x0, y0, y1 - y0 + 1, color); + } else if (y0 == y1) { + if (x0 > x1) + _swap_int16_t(x0, x1); + drawFastHLine(x0, y0, x1 - x0 + 1, color); + } else { + startWrite(); + writeLine(x0, y0, x1, y1, color); + endWrite(); + } +} + +/**************************************************************************/ +/*! + @brief Draw a circle outline + @param x0 Center-point x coordinate + @param y0 Center-point y coordinate + @param r Radius of circle + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawCircle(int16_t x0, int16_t y0, int16_t r, + uint16_t color) { +#if defined(ESP8266) + yield(); +#endif + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + startWrite(); + writePixel(x0, y0 + r, color); + writePixel(x0, y0 - r, color); + writePixel(x0 + r, y0, color); + writePixel(x0 - r, y0, color); + + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + + writePixel(x0 + x, y0 + y, color); + writePixel(x0 - x, y0 + y, color); + writePixel(x0 + x, y0 - y, color); + writePixel(x0 - x, y0 - y, color); + writePixel(x0 + y, y0 + x, color); + writePixel(x0 - y, y0 + x, color); + writePixel(x0 + y, y0 - x, color); + writePixel(x0 - y, y0 - x, color); + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Quarter-circle drawer, used to do circles and roundrects + @param x0 Center-point x coordinate + @param y0 Center-point y coordinate + @param r Radius of circle + @param cornername Mask bit #1 or bit #2 to indicate which quarters of + the circle we're doing + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawCircleHelper(int16_t x0, int16_t y0, int16_t r, + uint8_t cornername, uint16_t color) { + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + if (cornername & 0x4) { + writePixel(x0 + x, y0 + y, color); + writePixel(x0 + y, y0 + x, color); + } + if (cornername & 0x2) { + writePixel(x0 + x, y0 - y, color); + writePixel(x0 + y, y0 - x, color); + } + if (cornername & 0x8) { + writePixel(x0 - y, y0 + x, color); + writePixel(x0 - x, y0 + y, color); + } + if (cornername & 0x1) { + writePixel(x0 - y, y0 - x, color); + writePixel(x0 - x, y0 - y, color); + } + } +} + +/**************************************************************************/ +/*! + @brief Draw a circle with filled color + @param x0 Center-point x coordinate + @param y0 Center-point y coordinate + @param r Radius of circle + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::fillCircle(int16_t x0, int16_t y0, int16_t r, + uint16_t color) { + startWrite(); + writeFastVLine(x0, y0 - r, 2 * r + 1, color); + fillCircleHelper(x0, y0, r, 3, 0, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Quarter-circle drawer with fill, used for circles and roundrects + @param x0 Center-point x coordinate + @param y0 Center-point y coordinate + @param r Radius of circle + @param corners Mask bits indicating which quarters we're doing + @param delta Offset from center-point, used for round-rects + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::fillCircleHelper(int16_t x0, int16_t y0, int16_t r, + uint8_t corners, int16_t delta, + uint16_t color) { + + int16_t f = 1 - r; + int16_t ddF_x = 1; + int16_t ddF_y = -2 * r; + int16_t x = 0; + int16_t y = r; + int16_t px = x; + int16_t py = y; + + delta++; // Avoid some +1's in the loop + + while (x < y) { + if (f >= 0) { + y--; + ddF_y += 2; + f += ddF_y; + } + x++; + ddF_x += 2; + f += ddF_x; + // These checks avoid double-drawing certain lines, important + // for the SSD1306 library which has an INVERT drawing mode. + if (x < (y + 1)) { + if (corners & 1) + writeFastVLine(x0 + x, y0 - y, 2 * y + delta, color); + if (corners & 2) + writeFastVLine(x0 - x, y0 - y, 2 * y + delta, color); + } + if (y != py) { + if (corners & 1) + writeFastVLine(x0 + py, y0 - px, 2 * px + delta, color); + if (corners & 2) + writeFastVLine(x0 - py, y0 - px, 2 * px + delta, color); + py = y; + } + px = x; + } +} + +/**************************************************************************/ +/*! + @brief Draw a rectangle with no fill color + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawRect(int16_t x, int16_t y, int16_t w, int16_t h, + uint16_t color) { + startWrite(); + writeFastHLine(x, y, w, color); + writeFastHLine(x, y + h - 1, w, color); + writeFastVLine(x, y, h, color); + writeFastVLine(x + w - 1, y, h, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a rounded rectangle with no fill color + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param r Radius of corner rounding + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, + int16_t r, uint16_t color) { + int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis + if (r > max_radius) + r = max_radius; + // smarter version + startWrite(); + writeFastHLine(x + r, y, w - 2 * r, color); // Top + writeFastHLine(x + r, y + h - 1, w - 2 * r, color); // Bottom + writeFastVLine(x, y + r, h - 2 * r, color); // Left + writeFastVLine(x + w - 1, y + r, h - 2 * r, color); // Right + // draw four corners + drawCircleHelper(x + r, y + r, r, 1, color); + drawCircleHelper(x + w - r - 1, y + r, r, 2, color); + drawCircleHelper(x + w - r - 1, y + h - r - 1, r, 4, color); + drawCircleHelper(x + r, y + h - r - 1, r, 8, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a rounded rectangle with fill color + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param w Width in pixels + @param h Height in pixels + @param r Radius of corner rounding + @param color 16-bit 5-6-5 Color to draw/fill with +*/ +/**************************************************************************/ +void Adafruit_GFX::fillRoundRect(int16_t x, int16_t y, int16_t w, int16_t h, + int16_t r, uint16_t color) { + int16_t max_radius = ((w < h) ? w : h) / 2; // 1/2 minor axis + if (r > max_radius) + r = max_radius; + // smarter version + startWrite(); + writeFillRect(x + r, y, w - 2 * r, h, color); + // draw four corners + fillCircleHelper(x + w - r - 1, y + r, r, 1, h - 2 * r - 1, color); + fillCircleHelper(x + r, y + r, r, 2, h - 2 * r - 1, color); + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a triangle with no fill color + @param x0 Vertex #0 x coordinate + @param y0 Vertex #0 y coordinate + @param x1 Vertex #1 x coordinate + @param y1 Vertex #1 y coordinate + @param x2 Vertex #2 x coordinate + @param y2 Vertex #2 y coordinate + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + int16_t x2, int16_t y2, uint16_t color) { + drawLine(x0, y0, x1, y1, color); + drawLine(x1, y1, x2, y2, color); + drawLine(x2, y2, x0, y0, color); +} + +/**************************************************************************/ +/*! + @brief Draw a triangle with color-fill + @param x0 Vertex #0 x coordinate + @param y0 Vertex #0 y coordinate + @param x1 Vertex #1 x coordinate + @param y1 Vertex #1 y coordinate + @param x2 Vertex #2 x coordinate + @param y2 Vertex #2 y coordinate + @param color 16-bit 5-6-5 Color to fill/draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, + int16_t x2, int16_t y2, uint16_t color) { + + int16_t a, b, y, last; + + // Sort coordinates by Y order (y2 >= y1 >= y0) + if (y0 > y1) { + _swap_int16_t(y0, y1); + _swap_int16_t(x0, x1); + } + if (y1 > y2) { + _swap_int16_t(y2, y1); + _swap_int16_t(x2, x1); + } + if (y0 > y1) { + _swap_int16_t(y0, y1); + _swap_int16_t(x0, x1); + } + + startWrite(); + if (y0 == y2) { // Handle awkward all-on-same-line case as its own thing + a = b = x0; + if (x1 < a) + a = x1; + else if (x1 > b) + b = x1; + if (x2 < a) + a = x2; + else if (x2 > b) + b = x2; + writeFastHLine(a, y0, b - a + 1, color); + endWrite(); + return; + } + + int16_t dx01 = x1 - x0, dy01 = y1 - y0, dx02 = x2 - x0, dy02 = y2 - y0, + dx12 = x2 - x1, dy12 = y2 - y1; + int32_t sa = 0, sb = 0; + + // For upper part of triangle, find scanline crossings for segments + // 0-1 and 0-2. If y1=y2 (flat-bottomed triangle), the scanline y1 + // is included here (and second loop will be skipped, avoiding a /0 + // error there), otherwise scanline y1 is skipped here and handled + // in the second loop...which also avoids a /0 error here if y0=y1 + // (flat-topped triangle). + if (y1 == y2) + last = y1; // Include y1 scanline + else + last = y1 - 1; // Skip it + + for (y = y0; y <= last; y++) { + a = x0 + sa / dy01; + b = x0 + sb / dy02; + sa += dx01; + sb += dx02; + /* longhand: + a = x0 + (x1 - x0) * (y - y0) / (y1 - y0); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if (a > b) + _swap_int16_t(a, b); + writeFastHLine(a, y, b - a + 1, color); + } + + // For lower part of triangle, find scanline crossings for segments + // 0-2 and 1-2. This loop is skipped if y1=y2. + sa = (int32_t)dx12 * (y - y1); + sb = (int32_t)dx02 * (y - y0); + for (; y <= y2; y++) { + a = x1 + sa / dy12; + b = x0 + sb / dy02; + sa += dx12; + sb += dx02; + /* longhand: + a = x1 + (x2 - x1) * (y - y1) / (y2 - y1); + b = x0 + (x2 - x0) * (y - y0) / (y2 - y0); + */ + if (a > b) + _swap_int16_t(a, b); + writeFastHLine(a, y, b - a + 1, color); + } + endWrite(); +} + +// BITMAP / XBITMAP / GRAYSCALE / RGB BITMAP FUNCTIONS --------------------- + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 1-bit image at the specified (x,y) + position, using the specified foreground color (unset bits are transparent). + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], + int16_t w, int16_t h, uint16_t color) { + + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); + if (byte & 0x80) + writePixel(x + i, y, color); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @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. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw pixels with + @param bg 16-bit 5-6-5 Color to draw background with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], + int16_t w, int16_t h, uint16_t color, + uint16_t bg) { + + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); + writePixel(x + i, y, (byte & 0x80) ? color : bg); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 1-bit image at the specified (x,y) position, + using the specified foreground color (unset bits are transparent). + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, + int16_t h, uint16_t color) { + + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = bitmap[j * byteWidth + i / 8]; + if (byte & 0x80) + writePixel(x + i, y, color); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @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. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw pixels with + @param bg 16-bit 5-6-5 Color to draw background with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, + int16_t h, uint16_t color, uint16_t bg) { + + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = bitmap[j * byteWidth + i / 8]; + writePixel(x + i, y, (byte & 0x80) ? color : bg); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw PROGMEM-resident XBitMap Files (*.xbm), exported from GIMP. + Usage: Export from GIMP to *.xbm, rename *.xbm to *.c and open in editor. + C Array can be directly used with this function. + There is no RAM-resident version of this function; if generating bitmaps + in RAM, use the format defined by drawBitmap() and call that instead. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with monochrome bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels + @param color 16-bit 5-6-5 Color to draw pixels with +*/ +/**************************************************************************/ +void Adafruit_GFX::drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[], + int16_t w, int16_t h, uint16_t color) { + + int16_t byteWidth = (w + 7) / 8; // Bitmap scanline pad = whole byte + uint8_t byte = 0; + + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte >>= 1; + else + byte = pgm_read_byte(&bitmap[j * byteWidth + i / 8]); + // Nearly identical to drawBitmap(), only the bit order + // is reversed here (left-to-right = LSB to MSB): + if (byte & 0x01) + writePixel(x + i, y, color); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 8-bit image (grayscale) at the specified + (x,y) pos. Specifically for 8-bit display devices such as IS31FL3731; no + color reduction/expansion is performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with grayscale bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, + const uint8_t bitmap[], int16_t w, + int16_t h) { + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + writePixel(x + i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i])); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 8-bit image (grayscale) at the specified (x,y) + pos. Specifically for 8-bit display devices such as IS31FL3731; no color + reduction/expansion is performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with grayscale bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, + int16_t w, int16_t h) { + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + writePixel(x + i, y, bitmap[j * w + i]); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 8-bit image (grayscale) with a 1-bit mask + (set bits = opaque, unset bits = clear) at the specified (x,y) position. + BOTH buffers (grayscale and mask) must be PROGMEM-resident. + Specifically for 8-bit display devices such as IS31FL3731; no color + reduction/expansion is performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with grayscale bitmap + @param mask byte array with mask bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, + const uint8_t bitmap[], + const uint8_t mask[], int16_t w, + int16_t h) { + int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte + uint8_t byte = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = pgm_read_byte(&mask[j * bw + i / 8]); + if (byte & 0x80) { + writePixel(x + i, y, (uint8_t)pgm_read_byte(&bitmap[j * w + i])); + } + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 8-bit image (grayscale) with a 1-bit mask + (set bits = opaque, unset bits = clear) at the specified (x,y) position. + BOTH buffers (grayscale and mask) must be RAM-residentt, no mix-and-match + Specifically for 8-bit display devices such as IS31FL3731; no color + reduction/expansion is performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with grayscale bitmap + @param mask byte array with mask bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, + uint8_t *mask, int16_t w, int16_t h) { + int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte + uint8_t byte = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = mask[j * bw + i / 8]; + if (byte & 0x80) { + writePixel(x + i, y, bitmap[j * w + i]); + } + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) at the specified + (x,y) position. For 16-bit display devices; no color reduction performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], + int16_t w, int16_t h) { + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + writePixel(x + i, y, pgm_read_word(&bitmap[j * w + i])); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 16-bit image (RGB 5/6/5) at the specified (x,y) + position. For 16-bit display devices; no color reduction performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, + int16_t w, int16_t h) { + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + writePixel(x + i, y, bitmap[j * w + i]); + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a PROGMEM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask + (set bits = opaque, unset bits = clear) at the specified (x,y) position. BOTH + buffers (color and mask) must be PROGMEM-resident. For 16-bit display + devices; no color reduction performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param mask byte array with monochrome mask bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], + const uint8_t mask[], int16_t w, int16_t h) { + int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte + uint8_t byte = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = pgm_read_byte(&mask[j * bw + i / 8]); + if (byte & 0x80) { + writePixel(x + i, y, pgm_read_word(&bitmap[j * w + i])); + } + } + } + endWrite(); +} + +/**************************************************************************/ +/*! + @brief Draw a RAM-resident 16-bit image (RGB 5/6/5) with a 1-bit mask (set + bits = opaque, unset bits = clear) at the specified (x,y) position. BOTH + buffers (color and mask) must be RAM-resident. For 16-bit display devices; no + color reduction performed. + @param x Top left corner x coordinate + @param y Top left corner y coordinate + @param bitmap byte array with 16-bit color bitmap + @param mask byte array with monochrome mask bitmap + @param w Width of bitmap in pixels + @param h Height of bitmap in pixels +*/ +/**************************************************************************/ +void Adafruit_GFX::drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, + uint8_t *mask, int16_t w, int16_t h) { + int16_t bw = (w + 7) / 8; // Bitmask scanline pad = whole byte + uint8_t byte = 0; + startWrite(); + for (int16_t j = 0; j < h; j++, y++) { + for (int16_t i = 0; i < w; i++) { + if (i & 7) + byte <<= 1; + else + byte = mask[j * bw + i / 8]; + if (byte & 0x80) { + writePixel(x + i, y, bitmap[j * w + i]); + } + } + } + endWrite(); +} + +// TEXT- AND CHARACTER-HANDLING FUNCTIONS ---------------------------------- + +// Draw a character +/**************************************************************************/ +/*! + @brief Draw a single character + @param x Bottom left corner x coordinate + @param y Bottom left corner y coordinate + @param c The 8-bit font-indexed character (likely ascii) + @param color 16-bit 5-6-5 Color to draw chraracter with + @param bg 16-bit 5-6-5 Color to fill background with (if same as color, + no background) + @param size Font magnification level, 1 is 'original' size +*/ +/**************************************************************************/ +void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c, + uint16_t color, uint16_t bg, uint8_t size) { + drawChar(x, y, c, color, bg, size, size); +} + +// Draw a character +/**************************************************************************/ +/*! + @brief Draw a single character + @param x Bottom left corner x coordinate + @param y Bottom left corner y coordinate + @param c The 8-bit font-indexed character (likely ascii) + @param color 16-bit 5-6-5 Color to draw chraracter with + @param bg 16-bit 5-6-5 Color to fill background with (if same as color, + no background) + @param size_x Font magnification level in X-axis, 1 is 'original' size + @param size_y Font magnification level in Y-axis, 1 is 'original' size +*/ +/**************************************************************************/ +void Adafruit_GFX::drawChar(int16_t x, int16_t y, unsigned char c, + uint16_t color, uint16_t bg, uint8_t size_x, + uint8_t size_y) { + + if (!gfxFont) { // 'Classic' built-in font + + if ((x >= _width) || // Clip right + (y >= _height) || // Clip bottom + ((x + 6 * size_x - 1) < 0) || // Clip left + ((y + 8 * size_y - 1) < 0)) // Clip top + return; + + if (!_cp437 && (c >= 176)) + c++; // Handle 'classic' charset behavior + + startWrite(); + for (int8_t i = 0; i < 5; i++) { // Char bitmap = 5 columns + uint8_t line = pgm_read_byte(&font[c * 5 + i]); + for (int8_t j = 0; j < 8; j++, line >>= 1) { + if (line & 1) { + if (size_x == 1 && size_y == 1) + writePixel(x + i, y + j, color); + else + writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y, + color); + } else if (bg != color) { + if (size_x == 1 && size_y == 1) + writePixel(x + i, y + j, bg); + else + writeFillRect(x + i * size_x, y + j * size_y, size_x, size_y, bg); + } + } + } + if (bg != color) { // If opaque, draw vertical line for last column + if (size_x == 1 && size_y == 1) + writeFastVLine(x + 5, y, 8, bg); + else + writeFillRect(x + 5 * size_x, y, size_x, 8 * size_y, bg); + } + endWrite(); + + } else { // Custom font + + // Character is assumed previously filtered by write() to eliminate + // newlines, returns, non-printable characters, etc. Calling + // drawChar() directly with 'bad' characters of font may cause mayhem! + + c -= (uint8_t)pgm_read_byte(&gfxFont->first); + GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c); + uint8_t *bitmap = pgm_read_bitmap_ptr(gfxFont); + + uint16_t bo = pgm_read_word(&glyph->bitmapOffset); + uint8_t w = pgm_read_byte(&glyph->width), h = pgm_read_byte(&glyph->height); + int8_t xo = pgm_read_byte(&glyph->xOffset), + yo = pgm_read_byte(&glyph->yOffset); + uint8_t xx, yy, bits = 0, bit = 0; + int16_t xo16 = 0, yo16 = 0; + + if (size_x > 1 || size_y > 1) { + xo16 = xo; + yo16 = yo; + } + + // Todo: Add character clipping here + + // NOTE: THERE IS NO 'BACKGROUND' COLOR OPTION ON CUSTOM FONTS. + // THIS IS ON PURPOSE AND BY DESIGN. The background color feature + // has typically been used with the 'classic' font to overwrite old + // screen contents with new data. This ONLY works because the + // characters are a uniform size; it's not a sensible thing to do with + // proportionally-spaced fonts with glyphs of varying sizes (and that + // may overlap). To replace previously-drawn text when using a custom + // font, use the getTextBounds() function to determine the smallest + // rectangle encompassing a string, erase the area with fillRect(), + // then draw new text. This WILL infortunately 'blink' the text, but + // is unavoidable. Drawing 'background' pixels will NOT fix this, + // only creates a new set of problems. Have an idea to work around + // this (a canvas object type for MCUs that can afford the RAM and + // displays supporting setAddrWindow() and pushColors()), but haven't + // implemented this yet. + + startWrite(); + for (yy = 0; yy < h; yy++) { + for (xx = 0; xx < w; xx++) { + if (!(bit++ & 7)) { + bits = pgm_read_byte(&bitmap[bo++]); + } + if (bits & 0x80) { + if (size_x == 1 && size_y == 1) { + writePixel(x + xo + xx, y + yo + yy, color); + } else { + writeFillRect(x + (xo16 + xx) * size_x, y + (yo16 + yy) * size_y, + size_x, size_y, color); + } + } + bits <<= 1; + } + } + endWrite(); + + } // End classic vs custom font +} +/**************************************************************************/ +/*! + @brief Print one byte/character of data, used to support print() + @param c The 8-bit ascii character to write +*/ +/**************************************************************************/ +size_t Adafruit_GFX::write(uint8_t c) { + if (!gfxFont) { // 'Classic' built-in font + + if (c == '\n') { // Newline? + cursor_x = 0; // Reset x to zero, + cursor_y += textsize_y * 8; // advance y one line + } else if (c != '\r') { // Ignore carriage returns + if (wrap && ((cursor_x + textsize_x * 6) > _width)) { // Off right? + cursor_x = 0; // Reset x to zero, + cursor_y += textsize_y * 8; // advance y one line + } + drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize_x, + textsize_y); + cursor_x += textsize_x * 6; // Advance x one char + } + + } else { // Custom font + + if (c == '\n') { + cursor_x = 0; + cursor_y += + (int16_t)textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } else if (c != '\r') { + uint8_t first = pgm_read_byte(&gfxFont->first); + if ((c >= first) && (c <= (uint8_t)pgm_read_byte(&gfxFont->last))) { + GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first); + uint8_t w = pgm_read_byte(&glyph->width), + h = pgm_read_byte(&glyph->height); + if ((w > 0) && (h > 0)) { // Is there an associated bitmap? + int16_t xo = (int8_t)pgm_read_byte(&glyph->xOffset); // sic + if (wrap && ((cursor_x + textsize_x * (xo + w)) > _width)) { + cursor_x = 0; + cursor_y += (int16_t)textsize_y * + (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } + drawChar(cursor_x, cursor_y, c, textcolor, textbgcolor, textsize_x, + textsize_y); + } + cursor_x += + (uint8_t)pgm_read_byte(&glyph->xAdvance) * (int16_t)textsize_x; + } + } + } + return 1; +} + +/**************************************************************************/ +/*! + @brief Set text 'magnification' size. Each increase in s makes 1 pixel + that much bigger. + @param s Desired text size. 1 is default 6x8, 2 is 12x16, 3 is 18x24, etc +*/ +/**************************************************************************/ +void Adafruit_GFX::setTextSize(uint8_t s) { setTextSize(s, s); } + +/**************************************************************************/ +/*! + @brief Set text 'magnification' size. Each increase in s makes 1 pixel + that much bigger. + @param s_x Desired text width magnification level in X-axis. 1 is default + @param s_y Desired text width magnification level in Y-axis. 1 is default +*/ +/**************************************************************************/ +void Adafruit_GFX::setTextSize(uint8_t s_x, uint8_t s_y) { + textsize_x = (s_x > 0) ? s_x : 1; + textsize_y = (s_y > 0) ? s_y : 1; +} + +/**************************************************************************/ +/*! + @brief Set rotation setting for display + @param x 0 thru 3 corresponding to 4 cardinal rotations +*/ +/**************************************************************************/ +void Adafruit_GFX::setRotation(uint8_t x) { + rotation = (x & 3); + switch (rotation) { + case 0: + case 2: + _width = WIDTH; + _height = HEIGHT; + break; + case 1: + case 3: + _width = HEIGHT; + _height = WIDTH; + break; + } +} + +/**************************************************************************/ +/*! + @brief Set the font to display when print()ing, either custom or default + @param f The GFXfont object, if NULL use built in 6x8 font +*/ +/**************************************************************************/ +void Adafruit_GFX::setFont(const GFXfont *f) { + if (f) { // Font struct pointer passed in? + if (!gfxFont) { // And no current font struct? + // Switching from classic to new font behavior. + // Move cursor pos down 6 pixels so it's on baseline. + cursor_y += 6; + } + } else if (gfxFont) { // NULL passed. Current font struct defined? + // Switching from new to classic font behavior. + // Move cursor pos up 6 pixels so it's at top-left of char. + cursor_y -= 6; + } + gfxFont = (GFXfont *)f; +} + +/**************************************************************************/ +/*! + @brief Helper to determine size of a character with current font/size. + Broke this out as it's used by both the PROGMEM- and RAM-resident + getTextBounds() functions. + @param c The ascii character in question + @param x Pointer to x location of character + @param y Pointer to y location of character + @param minx Minimum clipping value for X + @param miny Minimum clipping value for Y + @param maxx Maximum clipping value for X + @param maxy Maximum clipping value for Y +*/ +/**************************************************************************/ +void Adafruit_GFX::charBounds(unsigned char c, int16_t *x, int16_t *y, + int16_t *minx, int16_t *miny, int16_t *maxx, + int16_t *maxy) { + + if (gfxFont) { + + if (c == '\n') { // Newline? + *x = 0; // Reset x to zero, advance y by one line + *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } else if (c != '\r') { // Not a carriage return; is normal char + uint8_t first = pgm_read_byte(&gfxFont->first), + last = pgm_read_byte(&gfxFont->last); + if ((c >= first) && (c <= last)) { // Char present in this font? + GFXglyph *glyph = pgm_read_glyph_ptr(gfxFont, c - first); + uint8_t gw = pgm_read_byte(&glyph->width), + gh = pgm_read_byte(&glyph->height), + xa = pgm_read_byte(&glyph->xAdvance); + int8_t xo = pgm_read_byte(&glyph->xOffset), + yo = pgm_read_byte(&glyph->yOffset); + if (wrap && ((*x + (((int16_t)xo + gw) * textsize_x)) > _width)) { + *x = 0; // Reset x to zero, advance y by one line + *y += textsize_y * (uint8_t)pgm_read_byte(&gfxFont->yAdvance); + } + int16_t tsx = (int16_t)textsize_x, tsy = (int16_t)textsize_y, + x1 = *x + xo * tsx, y1 = *y + yo * tsy, x2 = x1 + gw * tsx - 1, + y2 = y1 + gh * tsy - 1; + if (x1 < *minx) + *minx = x1; + if (y1 < *miny) + *miny = y1; + if (x2 > *maxx) + *maxx = x2; + if (y2 > *maxy) + *maxy = y2; + *x += xa * tsx; + } + } + + } else { // Default font + + if (c == '\n') { // Newline? + *x = 0; // Reset x to zero, + *y += textsize_y * 8; // advance y one line + // min/max x/y unchaged -- that waits for next 'normal' character + } else if (c != '\r') { // Normal char; ignore carriage returns + if (wrap && ((*x + textsize_x * 6) > _width)) { // Off right? + *x = 0; // Reset x to zero, + *y += textsize_y * 8; // advance y one line + } + int x2 = *x + textsize_x * 6 - 1, // Lower-right pixel of char + y2 = *y + textsize_y * 8 - 1; + if (x2 > *maxx) + *maxx = x2; // Track max x, y + if (y2 > *maxy) + *maxy = y2; + if (*x < *minx) + *minx = *x; // Track min x, y + if (*y < *miny) + *miny = *y; + *x += textsize_x * 6; // Advance x one char + } + } +} + +/**************************************************************************/ +/*! + @brief Helper to determine size of a string with current font/size. Pass + string and a cursor position, returns UL corner and W,H. + @param str The ascii string to measure + @param x The current cursor X + @param y The current cursor Y + @param x1 The boundary X coordinate, set by function + @param y1 The boundary Y coordinate, set by function + @param w The boundary width, set by function + @param h The boundary height, set by function +*/ +/**************************************************************************/ +void Adafruit_GFX::getTextBounds(const char *str, int16_t x, int16_t y, + int16_t *x1, int16_t *y1, uint16_t *w, + uint16_t *h) { + uint8_t c; // Current character + + *x1 = x; + *y1 = y; + *w = *h = 0; + + int16_t minx = _width, miny = _height, maxx = -1, maxy = -1; + + while ((c = *str++)) + charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy); + + if (maxx >= minx) { + *x1 = minx; + *w = maxx - minx + 1; + } + if (maxy >= miny) { + *y1 = miny; + *h = maxy - miny + 1; + } +} + +/**************************************************************************/ +/*! + @brief Helper to determine size of a string with current font/size. Pass + string and a cursor position, returns UL corner and W,H. + @param str The ascii string to measure (as an arduino String() class) + @param x The current cursor X + @param y The current cursor Y + @param x1 The boundary X coordinate, set by function + @param y1 The boundary Y coordinate, set by function + @param w The boundary width, set by function + @param h The boundary height, set by function +*/ +/**************************************************************************/ +void Adafruit_GFX::getTextBounds(const String &str, int16_t x, int16_t y, + int16_t *x1, int16_t *y1, uint16_t *w, + uint16_t *h) { + if (str.length() != 0) { + getTextBounds(const_cast(str.c_str()), x, y, x1, y1, w, h); + } +} + +/**************************************************************************/ +/*! + @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. + @param str The flash-memory ascii string to measure + @param x The current cursor X + @param y The current cursor Y + @param x1 The boundary X coordinate, set by function + @param y1 The boundary Y coordinate, set by function + @param w The boundary width, set by function + @param h The boundary height, set by function +*/ +/**************************************************************************/ +void Adafruit_GFX::getTextBounds(const __FlashStringHelper *str, int16_t x, + int16_t y, int16_t *x1, int16_t *y1, + uint16_t *w, uint16_t *h) { + uint8_t *s = (uint8_t *)str, c; + + *x1 = x; + *y1 = y; + *w = *h = 0; + + int16_t minx = _width, miny = _height, maxx = -1, maxy = -1; + + while ((c = pgm_read_byte(s++))) + charBounds(c, &x, &y, &minx, &miny, &maxx, &maxy); + + if (maxx >= minx) { + *x1 = minx; + *w = maxx - minx + 1; + } + if (maxy >= miny) { + *y1 = miny; + *h = maxy - miny + 1; + } +} + +/**************************************************************************/ +/*! + @brief Invert the display (ideally using built-in hardware command) + @param i True if you want to invert, false to make 'normal' +*/ +/**************************************************************************/ +void Adafruit_GFX::invertDisplay(bool i) { + // Do nothing, must be subclassed if supported by hardware +} + +/***************************************************************************/ + +/**************************************************************************/ +/*! + @brief Create a simple drawn button UI element +*/ +/**************************************************************************/ +Adafruit_GFX_Button::Adafruit_GFX_Button(void) { _gfx = 0; } + +/**************************************************************************/ +/*! + @brief Initialize button with our desired color/size/settings + @param gfx Pointer to our display so we can draw to it! + @param x The X coordinate of the center of the button + @param y The Y coordinate of the center of the button + @param w Width of the buttton + @param h Height of the buttton + @param outline Color of the outline (16-bit 5-6-5 standard) + @param fill Color of the button fill (16-bit 5-6-5 standard) + @param textcolor Color of the button label (16-bit 5-6-5 standard) + @param label Ascii string of the text inside the button + @param textsize The font magnification of the label text +*/ +/**************************************************************************/ +// Classic initButton() function: pass center & size +void Adafruit_GFX_Button::initButton(Adafruit_GFX *gfx, int16_t x, int16_t y, + uint16_t w, uint16_t h, uint16_t outline, + uint16_t fill, uint16_t textcolor, + char *label, uint8_t textsize) { + // Tweak arguments and pass to the newer initButtonUL() function... + initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill, textcolor, + label, textsize); +} + +/**************************************************************************/ +/*! + @brief Initialize button with our desired color/size/settings + @param gfx Pointer to our display so we can draw to it! + @param x The X coordinate of the center of the button + @param y The Y coordinate of the center of the button + @param w Width of the buttton + @param h Height of the buttton + @param outline Color of the outline (16-bit 5-6-5 standard) + @param fill Color of the button fill (16-bit 5-6-5 standard) + @param textcolor Color of the button label (16-bit 5-6-5 standard) + @param label Ascii string of the text inside the button + @param textsize_x The font magnification in X-axis of the label text + @param textsize_y The font magnification in Y-axis of the label text +*/ +/**************************************************************************/ +// Classic initButton() function: pass center & size +void Adafruit_GFX_Button::initButton(Adafruit_GFX *gfx, int16_t x, int16_t y, + uint16_t w, uint16_t h, uint16_t outline, + uint16_t fill, uint16_t textcolor, + char *label, uint8_t textsize_x, + uint8_t textsize_y) { + // Tweak arguments and pass to the newer initButtonUL() function... + initButtonUL(gfx, x - (w / 2), y - (h / 2), w, h, outline, fill, textcolor, + label, textsize_x, textsize_y); +} + +/**************************************************************************/ +/*! + @brief Initialize button with our desired color/size/settings, with + upper-left coordinates + @param gfx Pointer to our display so we can draw to it! + @param x1 The X coordinate of the Upper-Left corner of the button + @param y1 The Y coordinate of the Upper-Left corner of the button + @param w Width of the buttton + @param h Height of the buttton + @param outline Color of the outline (16-bit 5-6-5 standard) + @param fill Color of the button fill (16-bit 5-6-5 standard) + @param textcolor Color of the button label (16-bit 5-6-5 standard) + @param label Ascii string of the text inside the button + @param textsize The font magnification of the label text +*/ +/**************************************************************************/ +void Adafruit_GFX_Button::initButtonUL(Adafruit_GFX *gfx, int16_t x1, + int16_t y1, uint16_t w, uint16_t h, + uint16_t outline, uint16_t fill, + uint16_t textcolor, char *label, + uint8_t textsize) { + initButtonUL(gfx, x1, y1, w, h, outline, fill, textcolor, label, textsize, + textsize); +} + +/**************************************************************************/ +/*! + @brief Initialize button with our desired color/size/settings, with + upper-left coordinates + @param gfx Pointer to our display so we can draw to it! + @param x1 The X coordinate of the Upper-Left corner of the button + @param y1 The Y coordinate of the Upper-Left corner of the button + @param w Width of the buttton + @param h Height of the buttton + @param outline Color of the outline (16-bit 5-6-5 standard) + @param fill Color of the button fill (16-bit 5-6-5 standard) + @param textcolor Color of the button label (16-bit 5-6-5 standard) + @param label Ascii string of the text inside the button + @param textsize_x The font magnification in X-axis of the label text + @param textsize_y The font magnification in Y-axis of the label text +*/ +/**************************************************************************/ +void Adafruit_GFX_Button::initButtonUL(Adafruit_GFX *gfx, int16_t x1, + int16_t y1, uint16_t w, uint16_t h, + uint16_t outline, uint16_t fill, + uint16_t textcolor, char *label, + uint8_t textsize_x, uint8_t textsize_y) { + _x1 = x1; + _y1 = y1; + _w = w; + _h = h; + _outlinecolor = outline; + _fillcolor = fill; + _textcolor = textcolor; + _textsize_x = textsize_x; + _textsize_y = textsize_y; + _gfx = gfx; + strncpy(_label, label, 9); +} + +/**************************************************************************/ +/*! + @brief Draw the button on the screen + @param inverted Whether to draw with fill/text swapped to indicate + 'pressed' +*/ +/**************************************************************************/ +void Adafruit_GFX_Button::drawButton(bool inverted) { + uint16_t fill, outline, text; + + if (!inverted) { + fill = _fillcolor; + outline = _outlinecolor; + text = _textcolor; + } else { + fill = _textcolor; + outline = _outlinecolor; + text = _fillcolor; + } + + uint8_t r = min(_w, _h) / 4; // Corner radius + _gfx->fillRoundRect(_x1, _y1, _w, _h, r, fill); + _gfx->drawRoundRect(_x1, _y1, _w, _h, r, outline); + + _gfx->setCursor(_x1 + (_w / 2) - (strlen(_label) * 3 * _textsize_x), + _y1 + (_h / 2) - (4 * _textsize_y)); + _gfx->setTextColor(text); + _gfx->setTextSize(_textsize_x, _textsize_y); + _gfx->print(_label); +} + +/**************************************************************************/ +/*! + @brief Helper to let us know if a coordinate is within the bounds of the + button + @param x The X coordinate to check + @param y The Y coordinate to check + @returns True if within button graphics outline +*/ +/**************************************************************************/ +bool Adafruit_GFX_Button::contains(int16_t x, int16_t y) { + return ((x >= _x1) && (x < (int16_t)(_x1 + _w)) && (y >= _y1) && + (y < (int16_t)(_y1 + _h))); +} + +/**************************************************************************/ +/*! + @brief Query whether the button was pressed since we last checked state + @returns True if was not-pressed before, now is. +*/ +/**************************************************************************/ +bool Adafruit_GFX_Button::justPressed() { return (currstate && !laststate); } + +/**************************************************************************/ +/*! + @brief Query whether the button was released since we last checked state + @returns True if was pressed before, now is not. +*/ +/**************************************************************************/ +bool Adafruit_GFX_Button::justReleased() { return (!currstate && laststate); } + +// ------------------------------------------------------------------------- + +// GFXcanvas1, GFXcanvas8 and GFXcanvas16 (currently a WIP, don't get too +// comfy with the implementation) provide 1-, 8- and 16-bit offscreen +// canvases, the address of which can be passed to drawBitmap() or +// pushColors() (the latter appears only in a couple of GFX-subclassed TFT +// libraries at this time). This is here mostly to help with the recently- +// added proportionally-spaced fonts; adds a way to refresh a section of the +// screen without a massive flickering clear-and-redraw...but maybe you'll +// find other uses too. VERY RAM-intensive, since the buffer is in MCU +// memory and not the display driver...GXFcanvas1 might be minimally useful +// on an Uno-class board, but this and the others are much more likely to +// require at least a Mega or various recent ARM-type boards (recommended, +// as the text+bitmap draw can be pokey). GFXcanvas1 requires 1 bit per +// pixel (rounded up to nearest byte per scanline), GFXcanvas8 is 1 byte +// per pixel (no scanline pad), and GFXcanvas16 uses 2 bytes per pixel (no +// scanline pad). +// NOT EXTENSIVELY TESTED YET. MAY CONTAIN WORST BUGS KNOWN TO HUMANKIND. + +#ifdef __AVR__ +// Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR +const uint8_t PROGMEM GFXcanvas1::GFXsetBit[] = {0x80, 0x40, 0x20, 0x10, + 0x08, 0x04, 0x02, 0x01}; +const uint8_t PROGMEM GFXcanvas1::GFXclrBit[] = {0x7F, 0xBF, 0xDF, 0xEF, + 0xF7, 0xFB, 0xFD, 0xFE}; +#endif + +/**************************************************************************/ +/*! + @brief Instatiate a GFX 1-bit canvas context for graphics + @param w Display width, in pixels + @param h Display height, in pixels +*/ +/**************************************************************************/ +GFXcanvas1::GFXcanvas1(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) { + uint16_t bytes = ((w + 7) / 8) * h; + if ((buffer = (uint8_t *)malloc(bytes))) { + memset(buffer, 0, bytes); + } +} + +/**************************************************************************/ +/*! + @brief Delete the canvas, free memory +*/ +/**************************************************************************/ +GFXcanvas1::~GFXcanvas1(void) { + if (buffer) + free(buffer); +} + +/**************************************************************************/ +/*! + @brief Draw a pixel to the canvas framebuffer + @param x x coordinate + @param y y coordinate + @param color Binary (on or off) color to fill with +*/ +/**************************************************************************/ +void GFXcanvas1::drawPixel(int16_t x, int16_t y, uint16_t color) { + if (buffer) { + if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) + return; + + int16_t t; + switch (rotation) { + case 1: + t = x; + x = WIDTH - 1 - y; + y = t; + break; + case 2: + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + break; + case 3: + t = x; + x = y; + y = HEIGHT - 1 - t; + break; + } + + uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)]; +#ifdef __AVR__ + if (color) + *ptr |= pgm_read_byte(&GFXsetBit[x & 7]); + else + *ptr &= pgm_read_byte(&GFXclrBit[x & 7]); +#else + if (color) + *ptr |= 0x80 >> (x & 7); + else + *ptr &= ~(0x80 >> (x & 7)); +#endif + } +} + +/**********************************************************************/ +/*! + @brief Get the pixel color value at a given coordinate + @param x x coordinate + @param y y coordinate + @returns The desired pixel's binary color value, either 0x1 (on) or 0x0 + (off) +*/ +/**********************************************************************/ +bool GFXcanvas1::getPixel(int16_t x, int16_t y) const { + int16_t t; + switch (rotation) { + case 1: + t = x; + x = WIDTH - 1 - y; + y = t; + break; + case 2: + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + break; + case 3: + t = x; + x = y; + y = HEIGHT - 1 - t; + break; + } + return getRawPixel(x, y); +} + +/**********************************************************************/ +/*! + @brief Get the pixel color value at a given, unrotated coordinate. + This method is intended for hardware drivers to get pixel value + in physical coordinates. + @param x x coordinate + @param y y coordinate + @returns The desired pixel's binary color value, either 0x1 (on) or 0x0 + (off) +*/ +/**********************************************************************/ +bool GFXcanvas1::getRawPixel(int16_t x, int16_t y) const { + if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT)) + return 0; + if (this->getBuffer()) { + uint8_t *buffer = this->getBuffer(); + uint8_t *ptr = &buffer[(x / 8) + y * ((WIDTH + 7) / 8)]; + +#ifdef __AVR__ + return ((*ptr) & pgm_read_byte(&GFXsetBit[x & 7])) != 0; +#else + return ((*ptr) & (0x80 >> (x & 7))) != 0; +#endif + } + return 0; +} + +/**************************************************************************/ +/*! + @brief Fill the framebuffer completely with one color + @param color Binary (on or off) color to fill with +*/ +/**************************************************************************/ +void GFXcanvas1::fillScreen(uint16_t color) { + if (buffer) { + uint16_t bytes = ((WIDTH + 7) / 8) * HEIGHT; + memset(buffer, color ? 0xFF : 0x00, bytes); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized vertical line drawing + @param x Line horizontal start point + @param y Line vertical start point + @param h length of vertical line to be drawn, including first point + @param color Binary (on or off) color to fill with +*/ +/**************************************************************************/ +void GFXcanvas1::drawFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) { + return; + } + + if (y + h > height()) { + h = height() - y; + } else if (h < 0) { + // convert negative heights to their postive equivalent + h *= -1; + y -= h - 1; + if (y < 0) { + h += y; + y = 0; + } + } + + if (getRotation() == 0) { + drawFastRawVLine(x, y, h, color); + } else if (getRotation() == 1) { + int16_t t = x; + x = WIDTH - 1 - y; + y = t; + x -= h - 1; + drawFastRawHLine(x, y, h, color); + } else if (getRotation() == 2) { + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + + y -= h - 1; + drawFastRawVLine(x, y, h, color); + } else if (getRotation() == 3) { + int16_t t = x; + x = y; + y = HEIGHT - 1 - t; + drawFastRawHLine(x, y, h, color); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized horizontal line drawing + @param x Line horizontal start point + @param y Line vertical start point + @param w length of horizontal line to be drawn, including first point + @param color Binary (on or off) color to fill with +*/ +/**************************************************************************/ +void GFXcanvas1::drawFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) { + return; + } + + if (x + w > width()) { + w = width() - x; + } else if (w < 0) { + // convert negative widths to their postive equivalent + w *= -1; + x -= w - 1; + if (x < 0) { + w += x; + x = 0; + } + } + + if (getRotation() == 0) { + drawFastRawHLine(x, y, w, color); + } else if (getRotation() == 1) { + int16_t t = x; + x = WIDTH - 1 - y; + y = t; + drawFastRawVLine(x, y, w, color); + } else if (getRotation() == 2) { + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + + x -= w - 1; + drawFastRawHLine(x, y, w, color); + } else if (getRotation() == 3) { + int16_t t = x; + x = y; + y = HEIGHT - 1 - t; + y -= w - 1; + drawFastRawVLine(x, y, w, color); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized vertical line drawing into the raw canvas buffer + @param x Line horizontal start point + @param y Line vertical start point + @param h length of vertical line to be drawn, including first point + @param color Binary (on or off) color to fill with +*/ +/**************************************************************************/ +void GFXcanvas1::drawFastRawVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + // x & y already in raw (rotation 0) coordinates, no need to transform. + int16_t row_bytes = ((WIDTH + 7) / 8); + uint8_t *buffer = this->getBuffer(); + uint8_t *ptr = &buffer[(x / 8) + y * row_bytes]; + + if (color > 0) { +#ifdef __AVR__ + uint8_t bit_mask = pgm_read_byte(&GFXsetBit[x & 7]); +#else + uint8_t bit_mask = (0x80 >> (x & 7)); +#endif + for (int16_t i = 0; i < h; i++) { + *ptr |= bit_mask; + ptr += row_bytes; + } + } else { +#ifdef __AVR__ + uint8_t bit_mask = pgm_read_byte(&GFXclrBit[x & 7]); +#else + uint8_t bit_mask = ~(0x80 >> (x & 7)); +#endif + for (int16_t i = 0; i < h; i++) { + *ptr &= bit_mask; + ptr += row_bytes; + } + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized horizontal line drawing into the raw canvas buffer + @param x Line horizontal start point + @param y Line vertical start point + @param w length of horizontal line to be drawn, including first point + @param color Binary (on or off) color to fill with +*/ +/**************************************************************************/ +void GFXcanvas1::drawFastRawHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + // x & y already in raw (rotation 0) coordinates, no need to transform. + int16_t rowBytes = ((WIDTH + 7) / 8); + uint8_t *buffer = this->getBuffer(); + uint8_t *ptr = &buffer[(x / 8) + y * rowBytes]; + size_t remainingWidthBits = w; + + // check to see if first byte needs to be partially filled + if ((x & 7) > 0) { + // create bit mask for first byte + uint8_t startByteBitMask = 0x00; + for (int8_t i = (x & 7); ((i < 8) && (remainingWidthBits > 0)); i++) { +#ifdef __AVR__ + startByteBitMask |= pgm_read_byte(&GFXsetBit[i]); +#else + startByteBitMask |= (0x80 >> i); +#endif + remainingWidthBits--; + } + if (color > 0) { + *ptr |= startByteBitMask; + } else { + *ptr &= ~startByteBitMask; + } + + ptr++; + } + + // do the next remainingWidthBits bits + if (remainingWidthBits > 0) { + size_t remainingWholeBytes = remainingWidthBits / 8; + size_t lastByteBits = remainingWidthBits % 8; + uint8_t wholeByteColor = color > 0 ? 0xFF : 0x00; + + memset(ptr, wholeByteColor, remainingWholeBytes); + + if (lastByteBits > 0) { + uint8_t lastByteBitMask = 0x00; + for (int8_t i = 0; i < lastByteBits; i++) { +#ifdef __AVR__ + lastByteBitMask |= pgm_read_byte(&GFXsetBit[i]); +#else + lastByteBitMask |= (0x80 >> i); +#endif + } + ptr += remainingWholeBytes; + + if (color > 0) { + *ptr |= lastByteBitMask; + } else { + *ptr &= ~lastByteBitMask; + } + } + } +} + +/**************************************************************************/ +/*! + @brief Instatiate a GFX 8-bit canvas context for graphics + @param w Display width, in pixels + @param h Display height, in pixels +*/ +/**************************************************************************/ +GFXcanvas8::GFXcanvas8(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) { + uint32_t bytes = w * h; + if ((buffer = (uint8_t *)malloc(bytes))) { + memset(buffer, 0, bytes); + } +} + +/**************************************************************************/ +/*! + @brief Delete the canvas, free memory +*/ +/**************************************************************************/ +GFXcanvas8::~GFXcanvas8(void) { + if (buffer) + free(buffer); +} + +/**************************************************************************/ +/*! + @brief Draw a pixel to the canvas framebuffer + @param x x coordinate + @param y y coordinate + @param color 8-bit Color to fill with. Only lower byte of uint16_t is used. +*/ +/**************************************************************************/ +void GFXcanvas8::drawPixel(int16_t x, int16_t y, uint16_t color) { + if (buffer) { + if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) + return; + + int16_t t; + switch (rotation) { + case 1: + t = x; + x = WIDTH - 1 - y; + y = t; + break; + case 2: + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + break; + case 3: + t = x; + x = y; + y = HEIGHT - 1 - t; + break; + } + + buffer[x + y * WIDTH] = color; + } +} + +/**********************************************************************/ +/*! + @brief Get the pixel color value at a given coordinate + @param x x coordinate + @param y y coordinate + @returns The desired pixel's 8-bit color value +*/ +/**********************************************************************/ +uint8_t GFXcanvas8::getPixel(int16_t x, int16_t y) const { + int16_t t; + switch (rotation) { + case 1: + t = x; + x = WIDTH - 1 - y; + y = t; + break; + case 2: + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + break; + case 3: + t = x; + x = y; + y = HEIGHT - 1 - t; + break; + } + return getRawPixel(x, y); +} + +/**********************************************************************/ +/*! + @brief Get the pixel color value at a given, unrotated coordinate. + This method is intended for hardware drivers to get pixel value + in physical coordinates. + @param x x coordinate + @param y y coordinate + @returns The desired pixel's 8-bit color value +*/ +/**********************************************************************/ +uint8_t GFXcanvas8::getRawPixel(int16_t x, int16_t y) const { + if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT)) + return 0; + if (buffer) { + return buffer[x + y * WIDTH]; + } + return 0; +} + +/**************************************************************************/ +/*! + @brief Fill the framebuffer completely with one color + @param color 8-bit Color to fill with. Only lower byte of uint16_t is used. +*/ +/**************************************************************************/ +void GFXcanvas8::fillScreen(uint16_t color) { + if (buffer) { + memset(buffer, color, WIDTH * HEIGHT); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized vertical line drawing + @param x Line horizontal start point + @param y Line vertical start point + @param h length of vertical line to be drawn, including first point + @param color 8-bit Color to fill with. Only lower byte of uint16_t is + used. +*/ +/**************************************************************************/ +void GFXcanvas8::drawFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) { + return; + } + + if (y + h > height()) { + h = height() - y; + } else if (h < 0) { + // convert negative heights to their postive equivalent + h *= -1; + y -= h - 1; + if (y < 0) { + h += y; + y = 0; + } + } + + if (getRotation() == 0) { + drawFastRawVLine(x, y, h, color); + } else if (getRotation() == 1) { + int16_t t = x; + x = WIDTH - 1 - y; + y = t; + x -= h - 1; + drawFastRawHLine(x, y, h, color); + } else if (getRotation() == 2) { + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + + y -= h - 1; + drawFastRawVLine(x, y, h, color); + } else if (getRotation() == 3) { + int16_t t = x; + x = y; + y = HEIGHT - 1 - t; + drawFastRawHLine(x, y, h, color); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized horizontal line drawing + @param x Line horizontal start point + @param y Line vertical start point + @param w length of horizontal line to be drawn, including first point + @param color 8-bit Color to fill with. Only lower byte of uint16_t is + used. +*/ +/**************************************************************************/ +void GFXcanvas8::drawFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) { + return; + } + + if (x + w > width()) { + w = width() - x; + } else if (w < 0) { + // convert negative widths to their postive equivalent + w *= -1; + x -= w - 1; + if (x < 0) { + w += x; + x = 0; + } + } + + if (getRotation() == 0) { + drawFastRawHLine(x, y, w, color); + } else if (getRotation() == 1) { + int16_t t = x; + x = WIDTH - 1 - y; + y = t; + drawFastRawVLine(x, y, w, color); + } else if (getRotation() == 2) { + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + + x -= w - 1; + drawFastRawHLine(x, y, w, color); + } else if (getRotation() == 3) { + int16_t t = x; + x = y; + y = HEIGHT - 1 - t; + y -= w - 1; + drawFastRawVLine(x, y, w, color); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized vertical line drawing into the raw canvas buffer + @param x Line horizontal start point + @param y Line vertical start point + @param h length of vertical line to be drawn, including first point + @param color 8-bit Color to fill with. Only lower byte of uint16_t is + used. +*/ +/**************************************************************************/ +void GFXcanvas8::drawFastRawVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + // x & y already in raw (rotation 0) coordinates, no need to transform. + uint8_t *buffer_ptr = buffer + y * WIDTH + x; + for (int16_t i = 0; i < h; i++) { + (*buffer_ptr) = color; + buffer_ptr += WIDTH; + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized horizontal line drawing into the raw canvas buffer + @param x Line horizontal start point + @param y Line vertical start point + @param w length of horizontal line to be drawn, including first point + @param color 8-bit Color to fill with. Only lower byte of uint16_t is + used. +*/ +/**************************************************************************/ +void GFXcanvas8::drawFastRawHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + // x & y already in raw (rotation 0) coordinates, no need to transform. + memset(buffer + y * WIDTH + x, color, w); +} + +/**************************************************************************/ +/*! + @brief Instatiate a GFX 16-bit canvas context for graphics + @param w Display width, in pixels + @param h Display height, in pixels +*/ +/**************************************************************************/ +GFXcanvas16::GFXcanvas16(uint16_t w, uint16_t h) : Adafruit_GFX(w, h) { + uint32_t bytes = w * h * 2; + if ((buffer = (uint16_t *)malloc(bytes))) { + memset(buffer, 0, bytes); + } +} + +/**************************************************************************/ +/*! + @brief Delete the canvas, free memory +*/ +/**************************************************************************/ +GFXcanvas16::~GFXcanvas16(void) { + if (buffer) + free(buffer); +} + +/**************************************************************************/ +/*! + @brief Draw a pixel to the canvas framebuffer + @param x x coordinate + @param y y coordinate + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void GFXcanvas16::drawPixel(int16_t x, int16_t y, uint16_t color) { + if (buffer) { + if ((x < 0) || (y < 0) || (x >= _width) || (y >= _height)) + return; + + int16_t t; + switch (rotation) { + case 1: + t = x; + x = WIDTH - 1 - y; + y = t; + break; + case 2: + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + break; + case 3: + t = x; + x = y; + y = HEIGHT - 1 - t; + break; + } + + buffer[x + y * WIDTH] = color; + } +} + +/**********************************************************************/ +/*! + @brief Get the pixel color value at a given coordinate + @param x x coordinate + @param y y coordinate + @returns The desired pixel's 16-bit 5-6-5 color value +*/ +/**********************************************************************/ +uint16_t GFXcanvas16::getPixel(int16_t x, int16_t y) const { + int16_t t; + switch (rotation) { + case 1: + t = x; + x = WIDTH - 1 - y; + y = t; + break; + case 2: + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + break; + case 3: + t = x; + x = y; + y = HEIGHT - 1 - t; + break; + } + return getRawPixel(x, y); +} + +/**********************************************************************/ +/*! + @brief Get the pixel color value at a given, unrotated coordinate. + This method is intended for hardware drivers to get pixel value + in physical coordinates. + @param x x coordinate + @param y y coordinate + @returns The desired pixel's 16-bit 5-6-5 color value +*/ +/**********************************************************************/ +uint16_t GFXcanvas16::getRawPixel(int16_t x, int16_t y) const { + if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT)) + return 0; + if (buffer) { + return buffer[x + y * WIDTH]; + } + return 0; +} + +/**************************************************************************/ +/*! + @brief Fill the framebuffer completely with one color + @param color 16-bit 5-6-5 Color to fill with +*/ +/**************************************************************************/ +void GFXcanvas16::fillScreen(uint16_t color) { + if (buffer) { + uint8_t hi = color >> 8, lo = color & 0xFF; + if (hi == lo) { + memset(buffer, lo, WIDTH * HEIGHT * 2); + } else { + uint32_t i, pixels = WIDTH * HEIGHT; + for (i = 0; i < pixels; i++) + buffer[i] = color; + } + } +} + +/**************************************************************************/ +/*! + @brief Reverses the "endian-ness" of each 16-bit pixel within the + canvas; little-endian to big-endian, or big-endian to little. + Most microcontrollers (such as SAMD) are little-endian, while + most displays tend toward big-endianness. All the drawing + functions (including RGB bitmap drawing) take care of this + automatically, but some specialized code (usually involving + DMA) can benefit from having pixel data already in the + display-native order. Note that this does NOT convert to a + SPECIFIC endian-ness, it just flips the bytes within each word. +*/ +/**************************************************************************/ +void GFXcanvas16::byteSwap(void) { + if (buffer) { + uint32_t i, pixels = WIDTH * HEIGHT; + for (i = 0; i < pixels; i++) + buffer[i] = __builtin_bswap16(buffer[i]); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized vertical line drawing + @param x Line horizontal start point + @param y Line vertical start point + @param h length of vertical line to be drawn, including first point + @param color color 16-bit 5-6-5 Color to draw line with +*/ +/**************************************************************************/ +void GFXcanvas16::drawFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) { + return; + } + + if (y + h > height()) { + h = height() - y; + } else if (h < 0) { + // convert negative heights to their postive equivalent + h *= -1; + y -= h - 1; + if (y < 0) { + h += y; + y = 0; + } + } + + if (getRotation() == 0) { + drawFastRawVLine(x, y, h, color); + } else if (getRotation() == 1) { + int16_t t = x; + x = WIDTH - 1 - y; + y = t; + x -= h - 1; + drawFastRawHLine(x, y, h, color); + } else if (getRotation() == 2) { + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + + y -= h - 1; + drawFastRawVLine(x, y, h, color); + } else if (getRotation() == 3) { + int16_t t = x; + x = y; + y = HEIGHT - 1 - t; + drawFastRawHLine(x, y, h, color); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized horizontal line drawing + @param x Line horizontal start point + @param y Line vertical start point + @param w length of horizontal line to be drawn, including first point + @param color color 16-bit 5-6-5 Color to draw line with +*/ +/**************************************************************************/ +void GFXcanvas16::drawFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + if ((x < 0) || (x >= width()) || (y < 0) || (y >= height())) { + return; + } + + if (x + w > width()) { + w = width() - x; + } else if (w < 0) { + // convert negative widths to their postive equivalent + w *= -1; + x -= w - 1; + if (x < 0) { + w += x; + x = 0; + } + } + + if (getRotation() == 0) { + drawFastRawHLine(x, y, w, color); + } else if (getRotation() == 1) { + int16_t t = x; + x = WIDTH - 1 - y; + y = t; + drawFastRawVLine(x, y, w, color); + } else if (getRotation() == 2) { + x = WIDTH - 1 - x; + y = HEIGHT - 1 - y; + + x -= w - 1; + drawFastRawHLine(x, y, w, color); + } else if (getRotation() == 3) { + int16_t t = x; + x = y; + y = HEIGHT - 1 - t; + y -= w - 1; + drawFastRawVLine(x, y, w, color); + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized vertical line drawing into the raw canvas buffer + @param x Line horizontal start point + @param y Line vertical start point + @param h length of vertical line to be drawn, including first point + @param color color 16-bit 5-6-5 Color to draw line with +*/ +/**************************************************************************/ +void GFXcanvas16::drawFastRawVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + // x & y already in raw (rotation 0) coordinates, no need to transform. + uint16_t *buffer_ptr = buffer + y * WIDTH + x; + for (int16_t i = 0; i < h; i++) { + (*buffer_ptr) = color; + buffer_ptr += WIDTH; + } +} + +/**************************************************************************/ +/*! + @brief Speed optimized horizontal line drawing into the raw canvas buffer + @param x Line horizontal start point + @param y Line vertical start point + @param w length of horizontal line to be drawn, including first point + @param color color 16-bit 5-6-5 Color to draw line with +*/ +/**************************************************************************/ +void GFXcanvas16::drawFastRawHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + // x & y already in raw (rotation 0) coordinates, no need to transform. + size_t buffer_index = y * WIDTH + x; + for (int16_t i = buffer_index; i < buffer_index + w; i++) { + buffer[i] = color; + } +} diff --git a/src/libs/Adafruit-GFX-Library/Adafruit_GFX.h b/src/libs/Adafruit-GFX-Library/Adafruit_GFX.h new file mode 100644 index 0000000..0877562 --- /dev/null +++ b/src/libs/Adafruit-GFX-Library/Adafruit_GFX.h @@ -0,0 +1,403 @@ +#ifndef _ADAFRUIT_GFX_H +#define _ADAFRUIT_GFX_H + +#if ARDUINO >= 100 +#include "Arduino.h" +#include "Print.h" +#else +#include "WProgram.h" +#endif +#include "gfxfont.h" + +/// A generic graphics superclass that can handle all sorts of drawing. At a +/// minimum you can subclass and provide drawPixel(). At a maximum you can do a +/// ton of overriding to optimize. Used for any/all Adafruit displays! +class Adafruit_GFX : public Print +{ + + public: + Adafruit_GFX(int16_t w, int16_t h); // Constructor + + /**********************************************************************/ + /*! + @brief Draw to the screen/framebuffer/etc. + Must be overridden in subclass. + @param x X coordinate in pixels + @param y Y coordinate in pixels + @param color 16-bit pixel color. + */ + /**********************************************************************/ + virtual void drawPixel(int16_t x, int16_t y, uint16_t color) = 0; + + // TRANSACTION API / CORE DRAW API + // These MAY be overridden by the subclass to provide device-specific + // optimized code. Otherwise 'generic' versions are used. + virtual void startWrite(void); + virtual void writePixel(int16_t x, int16_t y, uint16_t color); + virtual void writeFillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + virtual void writeFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + virtual void writeFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + virtual void writeLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); + virtual void endWrite(void); + + // CONTROL API + // These MAY be overridden by the subclass to provide device-specific + // optimized code. Otherwise 'generic' versions are used. + virtual void setRotation(uint8_t r); + virtual void invertDisplay(bool i); + + // BASIC DRAW API + // These MAY be overridden by the subclass to provide device-specific + // optimized code. Otherwise 'generic' versions are used. + + // It's good to implement those, even if using transaction API + virtual void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + virtual void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + virtual void fillRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + virtual void fillScreen(uint16_t color); + // Optional and probably not necessary to change + virtual void drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, uint16_t color); + virtual void drawRect(int16_t x, int16_t y, int16_t w, int16_t h, uint16_t color); + + // These exist only with Adafruit_GFX (no subclass overrides) + void drawCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color); + void drawCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, uint16_t color); + void fillCircle(int16_t x0, int16_t y0, int16_t r, uint16_t color); + void fillCircleHelper(int16_t x0, int16_t y0, int16_t r, uint8_t cornername, int16_t delta, uint16_t color); + void drawTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color); + void fillTriangle(int16_t x0, int16_t y0, int16_t x1, int16_t y1, int16_t x2, int16_t y2, uint16_t color); + void drawRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color); + void fillRoundRect(int16_t x0, int16_t y0, int16_t w, int16_t h, int16_t radius, uint16_t color); + void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color); + void drawBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color, uint16_t bg); + void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color); + void drawBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h, uint16_t color, uint16_t bg); + void drawXBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h, uint16_t color); + void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[], int16_t w, int16_t h); + void drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, int16_t w, int16_t h); + void drawGrayscaleBitmap(int16_t x, int16_t y, const uint8_t bitmap[], const uint8_t mask[], int16_t w, int16_t h); + void drawGrayscaleBitmap(int16_t x, int16_t y, uint8_t *bitmap, uint8_t *mask, int16_t w, int16_t h); + void drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], int16_t w, int16_t h); + void drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, int16_t w, int16_t h); + void drawRGBBitmap(int16_t x, int16_t y, const uint16_t bitmap[], const uint8_t mask[], int16_t w, int16_t h); + void drawRGBBitmap(int16_t x, int16_t y, uint16_t *bitmap, uint8_t *mask, int16_t w, int16_t h); + void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size); + void drawChar(int16_t x, int16_t y, unsigned char c, uint16_t color, uint16_t bg, uint8_t size_x, uint8_t size_y); + void getTextBounds(const char *string, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); + void getTextBounds(const __FlashStringHelper *s, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, + uint16_t *h); + void getTextBounds(const String &str, int16_t x, int16_t y, int16_t *x1, int16_t *y1, uint16_t *w, uint16_t *h); + void setTextSize(uint8_t s); + void setTextSize(uint8_t sx, uint8_t sy); + void setFont(const GFXfont *f = NULL); + + /**********************************************************************/ + /*! + @brief Set text cursor location + @param x X coordinate in pixels + @param y Y coordinate in pixels + */ + /**********************************************************************/ + void setCursor(int16_t x, int16_t y) + { + cursor_x = x; + cursor_y = y; + } + + /**********************************************************************/ + /*! + @brief Set text font color with transparant background + @param c 16-bit 5-6-5 Color to draw text with + @note For 'transparent' background, background and foreground + are set to same color rather than using a separate flag. + */ + /**********************************************************************/ + void setTextColor(uint16_t c) + { + textcolor = textbgcolor = c; + } + + /**********************************************************************/ + /*! + @brief Set text font color with custom background color + @param c 16-bit 5-6-5 Color to draw text with + @param bg 16-bit 5-6-5 Color to draw background/fill with + */ + /**********************************************************************/ + void setTextColor(uint16_t c, uint16_t bg) + { + textcolor = c; + textbgcolor = bg; + } + + /**********************************************************************/ + /*! + @brief Set whether text that is too long for the screen width should + automatically wrap around to the next line (else clip right). + @param w true for wrapping, false for clipping + */ + /**********************************************************************/ + void setTextWrap(bool w) + { + wrap = w; + } + + /**********************************************************************/ + /*! + @brief Enable (or disable) Code Page 437-compatible charset. + There was an error in glcdfont.c for the longest time -- one + character (#176, the 'light shade' block) was missing -- this + threw off the index of every character that followed it. + But a TON of code has been written with the erroneous + character indices. By default, the library uses the original + 'wrong' behavior and old sketches will still work. Pass + 'true' to this function to use correct CP437 character values + in your code. + @param x true = enable (new behavior), false = disable (old behavior) + */ + /**********************************************************************/ + void cp437(bool x = true) + { + _cp437 = x; + } + + using Print::write; +#if ARDUINO >= 100 + virtual size_t write(uint8_t); +#else + virtual void write(uint8_t); +#endif + + /************************************************************************/ + /*! + @brief Get width of the display, accounting for current rotation + @returns Width in pixels + */ + /************************************************************************/ + int16_t width(void) const + { + return _width; + }; + + /************************************************************************/ + /*! + @brief Get height of the display, accounting for current rotation + @returns Height in pixels + */ + /************************************************************************/ + int16_t height(void) const + { + return _height; + } + + /************************************************************************/ + /*! + @brief Get rotation setting for display + @returns 0 thru 3 corresponding to 4 cardinal rotations + */ + /************************************************************************/ + uint8_t getRotation(void) const + { + return rotation; + } + + // get current cursor position (get rotation safe maximum values, + // using: width() for x, height() for y) + /************************************************************************/ + /*! + @brief Get text cursor X location + @returns X coordinate in pixels + */ + /************************************************************************/ + int16_t getCursorX(void) const + { + return cursor_x; + } + + /************************************************************************/ + /*! + @brief Get text cursor Y location + @returns Y coordinate in pixels + */ + /************************************************************************/ + int16_t getCursorY(void) const + { + return cursor_y; + }; + + protected: + void charBounds(unsigned char c, int16_t *x, int16_t *y, int16_t *minx, int16_t *miny, int16_t *maxx, + int16_t *maxy); + int16_t WIDTH; ///< This is the 'raw' display width - never changes + int16_t HEIGHT; ///< This is the 'raw' display height - never changes + int16_t _width; ///< Display width as modified by current rotation + int16_t _height; ///< Display height as modified by current rotation + int16_t cursor_x; ///< x location to start print()ing text + int16_t cursor_y; ///< y location to start print()ing text + uint16_t textcolor; ///< 16-bit background color for print() + uint16_t textbgcolor; ///< 16-bit text color for print() + uint8_t textsize_x; ///< Desired magnification in X-axis of text to print() + uint8_t textsize_y; ///< Desired magnification in Y-axis of text to print() + uint8_t rotation; ///< Display rotation (0 thru 3) + bool wrap; ///< If set, 'wrap' text at right edge of display + bool _cp437; ///< If set, use correct CP437 charset (default is off) + GFXfont *gfxFont; ///< Pointer to special font +}; + +/// A simple drawn button UI element +class Adafruit_GFX_Button +{ + + public: + Adafruit_GFX_Button(void); + // "Classic" initButton() uses center & size + void initButton(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t outline, uint16_t fill, + uint16_t textcolor, char *label, uint8_t textsize); + void initButton(Adafruit_GFX *gfx, int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t outline, uint16_t fill, + uint16_t textcolor, char *label, uint8_t textsize_x, uint8_t textsize_y); + // New/alt initButton() uses upper-left corner & size + void initButtonUL(Adafruit_GFX *gfx, int16_t x1, int16_t y1, uint16_t w, uint16_t h, uint16_t outline, + uint16_t fill, uint16_t textcolor, char *label, uint8_t textsize); + void initButtonUL(Adafruit_GFX *gfx, int16_t x1, int16_t y1, uint16_t w, uint16_t h, uint16_t outline, + uint16_t fill, uint16_t textcolor, char *label, uint8_t textsize_x, uint8_t textsize_y); + void drawButton(bool inverted = false); + bool contains(int16_t x, int16_t y); + + /**********************************************************************/ + /*! + @brief Sets button state, should be done by some touch function + @param p True for pressed, false for not. + */ + /**********************************************************************/ + void press(bool p) + { + laststate = currstate; + currstate = p; + } + + bool justPressed(); + bool justReleased(); + + /**********************************************************************/ + /*! + @brief Query whether the button is currently pressed + @returns True if pressed + */ + /**********************************************************************/ + bool isPressed(void) + { + return currstate; + }; + + private: + Adafruit_GFX *_gfx; + int16_t _x1, _y1; // Coordinates of top-left corner + uint16_t _w, _h; + uint8_t _textsize_x; + uint8_t _textsize_y; + uint16_t _outlinecolor, _fillcolor, _textcolor; + char _label[10]; + + bool currstate, laststate; +}; + +/// A GFX 1-bit canvas context for graphics +class GFXcanvas1 : public Adafruit_GFX +{ + public: + GFXcanvas1(uint16_t w, uint16_t h); + ~GFXcanvas1(void); + void drawPixel(int16_t x, int16_t y, uint16_t color); + void fillScreen(uint16_t color); + void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + bool getPixel(int16_t x, int16_t y) const; + /**********************************************************************/ + /*! + @brief Get a pointer to the internal buffer memory + @returns A pointer to the allocated buffer + */ + /**********************************************************************/ + uint8_t *getBuffer(void) const + { + return buffer; + } + + protected: + bool getRawPixel(int16_t x, int16_t y) const; + void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + + private: + uint8_t *buffer; + +#ifdef __AVR__ + // Bitmask tables of 0x80>>X and ~(0x80>>X), because X>>Y is slow on AVR + static const uint8_t PROGMEM GFXsetBit[], GFXclrBit[]; +#endif +}; + +/// A GFX 8-bit canvas context for graphics +class GFXcanvas8 : public Adafruit_GFX +{ + public: + GFXcanvas8(uint16_t w, uint16_t h); + ~GFXcanvas8(void); + void drawPixel(int16_t x, int16_t y, uint16_t color); + void fillScreen(uint16_t color); + void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + uint8_t getPixel(int16_t x, int16_t y) const; + /**********************************************************************/ + /*! + @brief Get a pointer to the internal buffer memory + @returns A pointer to the allocated buffer + */ + /**********************************************************************/ + uint8_t *getBuffer(void) const + { + return buffer; + } + + protected: + uint8_t getRawPixel(int16_t x, int16_t y) const; + void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + + private: + uint8_t *buffer; +}; + +/// A GFX 16-bit canvas context for graphics +class GFXcanvas16 : public Adafruit_GFX +{ + public: + GFXcanvas16(uint16_t w, uint16_t h); + ~GFXcanvas16(void); + void drawPixel(int16_t x, int16_t y, uint16_t color); + void fillScreen(uint16_t color); + void byteSwap(void); + void drawFastVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + uint16_t getPixel(int16_t x, int16_t y) const; + /**********************************************************************/ + /*! + @brief Get a pointer to the internal buffer memory + @returns A pointer to the allocated buffer + */ + /**********************************************************************/ + uint16_t *getBuffer(void) const + { + return buffer; + } + + protected: + uint16_t getRawPixel(int16_t x, int16_t y) const; + void drawFastRawVLine(int16_t x, int16_t y, int16_t h, uint16_t color); + void drawFastRawHLine(int16_t x, int16_t y, int16_t w, uint16_t color); + + private: + uint16_t *buffer; +}; + +#endif // _ADAFRUIT_GFX_H diff --git a/src/libs/GFXFont/gfxfont.h b/src/libs/Adafruit-GFX-Library/gfxfont.h similarity index 100% rename from src/libs/GFXFont/gfxfont.h rename to src/libs/Adafruit-GFX-Library/gfxfont.h diff --git a/src/libs/GFXFont/glcdfont.c b/src/libs/Adafruit-GFX-Library/glcdfont.c similarity index 100% rename from src/libs/GFXFont/glcdfont.c rename to src/libs/Adafruit-GFX-Library/glcdfont.c