diff --git a/Adafruit_GFX.cpp b/src/Adafruit_GFX.cpp similarity index 60% rename from Adafruit_GFX.cpp rename to src/Adafruit_GFX.cpp index 7b9a183..b36d052 100644 --- a/Adafruit_GFX.cpp +++ b/src/Adafruit_GFX.cpp @@ -115,18 +115,18 @@ Adafruit_GFX::Adafruit_GFX(int16_t w, int16_t h) : WIDTH(w), HEIGHT(h) { textsize_x = textsize_y = 1; textcolor = textbgcolor = 0xFFFF; wrap = true; - _cp437 = false; + _cp437 = true; 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 + @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, @@ -1541,1129 +1541,3 @@ void Adafruit_GFX::invertDisplay(bool i) { // Do nothing, must be subclassed if supported by hardware (void)i; // disable -Wunused-parameter warning } - -/***************************************************************************/ - -/**************************************************************************/ -/*! - @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); - _label[9] = 0; // strncpy does not place a null at the end. - // When 'label' is >9 characters, _label is not terminated. -} - -/**************************************************************************/ -/*! - @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 (buffer) { - 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 Color to fill with -*/ -/**************************************************************************/ -void GFXcanvas1::drawFastVLine(int16_t x, int16_t y, int16_t h, - uint16_t color) { - - if (h < 0) { // Convert negative heights to positive equivalent - h *= -1; - y -= h - 1; - if (y < 0) { - h += y; - y = 0; - } - } - - // Edge rejection (no-draw if totally off canvas) - if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) { - return; - } - - if (y < 0) { // Clip top - h += y; - y = 0; - } - if (y + h > height()) { // Clip bottom - h = height() - y; - } - - 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 to fill with -*/ -/**************************************************************************/ -void GFXcanvas1::drawFastHLine(int16_t x, int16_t y, int16_t w, - uint16_t color) { - if (w < 0) { // Convert negative widths to positive equivalent - w *= -1; - x -= w - 1; - if (x < 0) { - w += x; - x = 0; - } - } - - // Edge rejection (no-draw if totally off canvas) - if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) { - return; - } - - if (x < 0) { // Clip left - w += x; - x = 0; - } - if (x + w >= width()) { // Clip right - w = width() - x; - } - - 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 *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 *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 (size_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 (h < 0) { // Convert negative heights to positive equivalent - h *= -1; - y -= h - 1; - if (y < 0) { - h += y; - y = 0; - } - } - - // Edge rejection (no-draw if totally off canvas) - if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) { - return; - } - - if (y < 0) { // Clip top - h += y; - y = 0; - } - if (y + h > height()) { // Clip bottom - h = height() - y; - } - - 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 1st 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 (w < 0) { // Convert negative widths to positive equivalent - w *= -1; - x -= w - 1; - if (x < 0) { - w += x; - x = 0; - } - } - - // Edge rejection (no-draw if totally off canvas) - if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) { - return; - } - - if (x < 0) { // Clip left - w += x; - x = 0; - } - if (x + w >= width()) { // Clip right - w = width() - x; - } - - 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 (h < 0) { // Convert negative heights to positive equivalent - h *= -1; - y -= h - 1; - if (y < 0) { - h += y; - y = 0; - } - } - - // Edge rejection (no-draw if totally off canvas) - if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) { - return; - } - - if (y < 0) { // Clip top - h += y; - y = 0; - } - if (y + h > height()) { // Clip bottom - h = height() - y; - } - - 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 1st 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 (w < 0) { // Convert negative widths to positive equivalent - w *= -1; - x -= w - 1; - if (x < 0) { - w += x; - x = 0; - } - } - - // Edge rejection (no-draw if totally off canvas) - if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) { - return; - } - - if (x < 0) { // Clip left - w += x; - x = 0; - } - if (x + w >= width()) { // Clip right - w = width() - x; - } - - 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. - uint32_t buffer_index = y * WIDTH + x; - for (uint32_t i = buffer_index; i < buffer_index + w; i++) { - buffer[i] = color; - } -} diff --git a/Adafruit_GFX.h b/src/Adafruit_GFX.h similarity index 64% rename from Adafruit_GFX.h rename to src/Adafruit_GFX.h index cd549aa..17080ba 100644 --- a/Adafruit_GFX.h +++ b/src/Adafruit_GFX.h @@ -1,5 +1,4 @@ -#ifndef _ADAFRUIT_GFX_H -#define _ADAFRUIT_GFX_H +#pragma once #if ARDUINO >= 100 #include "Arduino.h" @@ -166,15 +165,15 @@ public: /**********************************************************************/ /*! - @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. + @brief Enable or disable Code Page 437-compatible charset. + There was a bug in glcdfont.c for years -- 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 now uses the correct charset. Old code + relying on the prior 'wrong' behavior really should update any + upper char indices its using, but can still work as-is by + adding an initial call to cp437(false). @param x true = enable (new behavior), false = disable (old behavior) */ /**********************************************************************/ @@ -247,150 +246,3 @@ protected: 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/Adafruit_GFX_Button.cpp b/src/Adafruit_GFX_Button.cpp new file mode 100644 index 0000000..1bd89cb --- /dev/null +++ b/src/Adafruit_GFX_Button.cpp @@ -0,0 +1,183 @@ +#include "Adafruit_GFX_Button.h" + +/**************************************************************************/ +/*! + @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); + _label[9] = 0; // strncpy does not place a null at the end. + // When 'label' is >9 characters, _label is not terminated. +} + +/**************************************************************************/ +/*! + @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); } diff --git a/src/Adafruit_GFX_Button.h b/src/Adafruit_GFX_Button.h new file mode 100644 index 0000000..e123aec --- /dev/null +++ b/src/Adafruit_GFX_Button.h @@ -0,0 +1,61 @@ +#pragma once + +#include "Adafruit_GFX.h" + +/// 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; +}; diff --git a/Adafruit_GrayOLED.cpp b/src/Adafruit_GrayOLED.cpp similarity index 99% rename from Adafruit_GrayOLED.cpp rename to src/Adafruit_GrayOLED.cpp index f487861..35e68f3 100644 --- a/Adafruit_GrayOLED.cpp +++ b/src/Adafruit_GrayOLED.cpp @@ -18,7 +18,6 @@ #if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all #include "Adafruit_GrayOLED.h" -#include // SOME DEFINES AND STATIC VARIABLES USED INTERNALLY ----------------------- @@ -418,4 +417,4 @@ void Adafruit_GrayOLED::setContrast(uint8_t level) { oled_commandList(cmd, 2); } -#endif /* ATTIN85 not supported */ +#endif // end !__AVR_ATtiny85__ diff --git a/Adafruit_GrayOLED.h b/src/Adafruit_GrayOLED.h similarity index 96% rename from Adafruit_GrayOLED.h rename to src/Adafruit_GrayOLED.h index 8ec7b23..c95dcb3 100644 --- a/Adafruit_GrayOLED.h +++ b/src/Adafruit_GrayOLED.h @@ -21,12 +21,11 @@ * */ -#ifndef _Adafruit_GRAYOLED_H_ -#define _Adafruit_GRAYOLED_H_ +#pragma once #if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all -#include +#include "Adafruit_GFX.h" #include #include #include @@ -97,4 +96,3 @@ private: }; #endif // end __AVR_ATtiny85__ -#endif // _Adafruit_GrayOLED_H_ diff --git a/Adafruit_SPITFT.cpp b/src/Adafruit_SPITFT.cpp similarity index 100% rename from Adafruit_SPITFT.cpp rename to src/Adafruit_SPITFT.cpp diff --git a/Adafruit_SPITFT.h b/src/Adafruit_SPITFT.h similarity index 99% rename from Adafruit_SPITFT.h rename to src/Adafruit_SPITFT.h index 8064a74..3746d82 100644 --- a/Adafruit_SPITFT.h +++ b/src/Adafruit_SPITFT.h @@ -17,8 +17,7 @@ * BSD license, all text here must be included in any redistribution. */ -#ifndef _ADAFRUIT_SPITFT_H_ -#define _ADAFRUIT_SPITFT_H_ +#pragma once #if !defined(__AVR_ATtiny85__) // Not for ATtiny, at all @@ -527,4 +526,3 @@ protected: }; #endif // end __AVR_ATtiny85__ -#endif // end _ADAFRUIT_SPITFT_H_ diff --git a/Adafruit_SPITFT_Macros.h b/src/Adafruit_SPITFT_Macros.h similarity index 100% rename from Adafruit_SPITFT_Macros.h rename to src/Adafruit_SPITFT_Macros.h diff --git a/src/GFXcanvas1.cpp b/src/GFXcanvas1.cpp new file mode 100644 index 0000000..94a1468 --- /dev/null +++ b/src/GFXcanvas1.cpp @@ -0,0 +1,359 @@ +#include "GFXcanvas1.h" + +// 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 + } +} + +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); +} + +bool GFXcanvas1::getRawPixel(int16_t x, int16_t y) const { + if ((x < 0) || (y < 0) || (x >= WIDTH) || (y >= HEIGHT)) + return 0; + if (buffer) { + 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 Color to fill with +*/ +/**************************************************************************/ +void GFXcanvas1::drawFastVLine(int16_t x, int16_t y, int16_t h, + uint16_t color) { + + if (h < 0) { // Convert negative heights to positive equivalent + h *= -1; + y -= h - 1; + if (y < 0) { + h += y; + y = 0; + } + } + + // Edge rejection (no-draw if totally off canvas) + if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) { + return; + } + + if (y < 0) { // Clip top + h += y; + y = 0; + } + if (y + h > height()) { // Clip bottom + h = height() - y; + } + + 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 to fill with +*/ +/**************************************************************************/ +void GFXcanvas1::drawFastHLine(int16_t x, int16_t y, int16_t w, + uint16_t color) { + if (w < 0) { // Convert negative widths to positive equivalent + w *= -1; + x -= w - 1; + if (x < 0) { + w += x; + x = 0; + } + } + + // Edge rejection (no-draw if totally off canvas) + if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) { + return; + } + + if (x < 0) { // Clip left + w += x; + x = 0; + } + if (x + w >= width()) { // Clip right + w = width() - x; + } + + 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 *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 *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 (size_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; + } + } + } +} diff --git a/src/GFXcanvas1.h b/src/GFXcanvas1.h new file mode 100644 index 0000000..00cf80b --- /dev/null +++ b/src/GFXcanvas1.h @@ -0,0 +1,47 @@ +#pragma once + +#include "Adafruit_GFX.h" + +/// 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); + /*! + @brief Get the pixel color value at a given coordinate + @param x x coordinate + @param y y coordinate + @returns The pixel's binary color value, either 0x1 (on) or 0x0 (off) + */ + 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: + /*! + @brief Get the pixel color value at a given, unrotated coordinate. + This method is intended for hardware drivers to get pixel value + in native physical coordinates. + @param x x coordinate + @param y y coordinate + @returns The pixel's binary color value, either 0x1 (on) or 0x0 (off) + */ + 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 +}; diff --git a/src/GFXcanvas16.cpp b/src/GFXcanvas16.cpp new file mode 100644 index 0000000..07f8986 --- /dev/null +++ b/src/GFXcanvas16.cpp @@ -0,0 +1,295 @@ +#include "GFXcanvas16.h" + +/**************************************************************************/ +/*! + @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 (h < 0) { // Convert negative heights to positive equivalent + h *= -1; + y -= h - 1; + if (y < 0) { + h += y; + y = 0; + } + } + + // Edge rejection (no-draw if totally off canvas) + if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) { + return; + } + + if (y < 0) { // Clip top + h += y; + y = 0; + } + if (y + h > height()) { // Clip bottom + h = height() - y; + } + + 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 1st 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 (w < 0) { // Convert negative widths to positive equivalent + w *= -1; + x -= w - 1; + if (x < 0) { + w += x; + x = 0; + } + } + + // Edge rejection (no-draw if totally off canvas) + if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) { + return; + } + + if (x < 0) { // Clip left + w += x; + x = 0; + } + if (x + w >= width()) { // Clip right + w = width() - x; + } + + 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. + uint32_t buffer_index = y * WIDTH + x; + for (uint32_t i = buffer_index; i < buffer_index + w; i++) { + buffer[i] = color; + } +} diff --git a/src/GFXcanvas16.h b/src/GFXcanvas16.h new file mode 100644 index 0000000..5db5b3e --- /dev/null +++ b/src/GFXcanvas16.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Adafruit_GFX.h" + +/// 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; +}; diff --git a/src/GFXcanvas8.cpp b/src/GFXcanvas8.cpp new file mode 100644 index 0000000..14c9877 --- /dev/null +++ b/src/GFXcanvas8.cpp @@ -0,0 +1,269 @@ +#include "GFXcanvas8.h" + +/**************************************************************************/ +/*! + @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 (h < 0) { // Convert negative heights to positive equivalent + h *= -1; + y -= h - 1; + if (y < 0) { + h += y; + y = 0; + } + } + + // Edge rejection (no-draw if totally off canvas) + if ((x < 0) || (x >= width()) || (y >= height()) || ((y + h - 1) < 0)) { + return; + } + + if (y < 0) { // Clip top + h += y; + y = 0; + } + if (y + h > height()) { // Clip bottom + h = height() - y; + } + + 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 1st 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 (w < 0) { // Convert negative widths to positive equivalent + w *= -1; + x -= w - 1; + if (x < 0) { + w += x; + x = 0; + } + } + + // Edge rejection (no-draw if totally off canvas) + if ((y < 0) || (y >= height()) || (x >= width()) || ((x + w - 1) < 0)) { + return; + } + + if (x < 0) { // Clip left + w += x; + x = 0; + } + if (x + w >= width()) { // Clip right + w = width() - x; + } + + 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); +} diff --git a/src/GFXcanvas8.h b/src/GFXcanvas8.h new file mode 100644 index 0000000..d315411 --- /dev/null +++ b/src/GFXcanvas8.h @@ -0,0 +1,30 @@ +#pragma once + +#include "Adafruit_GFX.h" + +/// 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; +}; diff --git a/gfxfont.h b/src/gfxfont.h similarity index 94% rename from gfxfont.h rename to src/gfxfont.h index 175bad6..48e513c 100644 --- a/gfxfont.h +++ b/src/gfxfont.h @@ -4,8 +4,7 @@ // file and pass address of GFXfont struct to setFont(). Pass NULL to // revert to 'classic' fixed-space bitmap font. -#ifndef _GFXFONT_H_ -#define _GFXFONT_H_ +#pragma once /// Font data stored PER GLYPH typedef struct { @@ -25,5 +24,3 @@ typedef struct { uint16_t last; ///< ASCII extents (last char) uint8_t yAdvance; ///< Newline distance (y axis) } GFXfont; - -#endif // _GFXFONT_H_ diff --git a/glcdfont.c b/src/glcdfont.c similarity index 99% rename from glcdfont.c rename to src/glcdfont.c index 535da3a..60fb76e 100644 --- a/glcdfont.c +++ b/src/glcdfont.c @@ -1,8 +1,7 @@ // This is the 'classic' fixed-space bitmap font for Adafruit_GFX since 1.0. // See gfxfont.h for newer custom bitmap font info. -#ifndef FONT5X7_H -#define FONT5X7_H +#pragma once #ifdef __AVR__ #include @@ -139,5 +138,3 @@ static const unsigned char font[] PROGMEM = { static inline void avoid_unused_const_variable_compiler_warning(void) { (void)font; } - -#endif // FONT5X7_H