Arduino_STM32/STM32F1/libraries/ILI9341_due_STM/ILI9341_due_gText.cpp

1937 lines
48 KiB
C++

/*
ILI9341_due_gText.cpp - Used for rendering GLCD fonts on Arduino Due
Copyright (c) 2014 Marek Buriak
The library is based on GLCD library by Bill Perry and Michael Margolis:
https://code.google.com/p/glcd-arduino
This file is part of the Arduino ILI9341_due library.
Sources for this library can be found at https://github.com/marekburiak/ILI9341_Due.
Fonts .h files can be created with GLCDFontCreator2 (not the one MikroElektronika):
https://code.google.com/p/glcd-arduino/downloads/detail?name=GLCDFontCreator2.zip&can=2&q=
ILI9341_due is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 2.1 of the License, or
(at your option) any later version.
ILI9341_due is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ILI9341_due. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ILI9341_due.h"
#include "ILI9341_due_gText.h"
//#include "..\Streaming\Streaming.h"
//extern glcd_Device GLCD; // this is the global GLCD instance, here upcast to the base glcd_Device class
// This constructor creates a text area using the entire display
// The device pointer is initialized using the global GLCD instance
// New constuctors can be added to take an exlicit glcd instance pointer
// if multiple glcd instances need to be supported
ILI9341_due_gText::ILI9341_due_gText(ILI9341_due *ili)
{
// device = (glcd_Device*)&GLCD;
_ili = ili;
_fontMode = gTextFontMode_Solid;
_fontBgColor = ILI9341_BLACK;
_fontColor = ILI9341_WHITE;
_letterSpacing = 2;
_isLastChar = false;
defineArea(0,0, _ili->width() -1, _ili->height() -1, DEFAULT_SCROLLDIR); // this should never fail
}
// This constructor creates a text area with the given coordinates
// full display area is used if any coordinate is invalid
ILI9341_due_gText::ILI9341_due_gText(ILI9341_due *ili, int16_t x1, int16_t y1, int16_t x2, int16_t y2) //, textMode mode)
{
//device = (glcd_Device*)&GLCD;
_ili = ili;
if( ! defineArea(x1,y1,x2,y2)) //,mode))
defineArea(0,0, _ili->width() -1,_ili->height() -1); //,mode); // this should never fail
}
#if INCLUDE_NOT_WORKING_YET
ILI9341_due_gText::ILI9341_due_gText(ILI9341_due *ili, predefinedArea selection) //, textMode mode)
{
//device = (glcd_Device*)&GLCD;
_ili = ili;
if( ! defineArea(selection)) //,mode))
defineArea(0,0, _ili->width() -1,_ili->height() -1,mode); // this should never fail
}
#endif
ILI9341_due_gText::ILI9341_due_gText(ILI9341_due *ili, int16_t x1, int16_t y1, int16_t columns, int16_t rows, gTextFont font) //, textMode mode)
{
//device = (glcd_Device*)&GLCD;
_ili = ili;
if( ! defineArea(x1,y1,columns,rows,font)) //, mode))
{
defineArea(0,0, _ili->width() -1,_ili->height() -1); //,mode); // this should never fail
selectFont(font);
}
}
/**
* Clear text area with the current font background color
* and home the cursor to upper left corner of the text area.
*
* @see defineArea()
*/
void ILI9341_due_gText::clearArea(uint16_t color)
{
/*
* fill the area with font background color
*/
//Serial << "clearing area from " << _area.x1 << " to " << _area.x2 << endl;
_ili->fillRect(_area.x1, _area.y1, _area.x2 - _area.x1+1, _area.y2-_area.y1+1, color);
/*glcd_Device::SetPixels(_area.x1, _area.y1,
_area.x2, _area.y2,
_fontColor == BLACK ? WHITE : BLACK);*/
/*
* put cursor at home position of text area to ensure we are always inside area.
*/
//cursorToXY(0,0);
}
/**
* Define a Text area by columns and rows
*
* @param x X coordinate of upper left corner
* @param y Y coordinate of upper left corner
* @param columns number of text columns
* @param rows number of text rows
* @param font a font definition
* @param mode constants SCROLL_DOWN and SCROLL_UP control scroll direction
*
*
* Defines a text area sized to hold columns characters across and rows characters tall.
* It is properly sized for the specified font.
*
* The area within the newly defined text area is intentionally not cleared.
*
* While intended for fixed width fonts, sizing will work for variable
* width fonts.
*
* When variable width fonts are used, the column is based on assuming a width
* of the widest character.
*
* x,y is an absolute coordinate and is relateive to the 0,0 origin of the
* display.
*
* mode is an optional parameter and defaults to normal/up scrolling
*
* @note
* Upon defining the text area, the cursor position for the text area will be set to x,y
*
* @see ClearArea()
*/
bool ILI9341_due_gText::defineArea(int16_t x, int16_t y, int16_t columns, int16_t rows, gTextFont font) //, textMode mode)
{
textMode mode = DEFAULT_SCROLLDIR;
uint16_t x2,y2;
selectFont(font);
x2 = x + columns * (pgm_read_byte(_font+GTEXT_FONT_FIXED_WIDTH)+1) -1;
y2 = y + rows * (fontHeight()+1) -1;
return defineArea(x, y, x2, y2); //, mode);
}
/**
* Define a text area by absolute coordinates
*
* @param x1 X coordinate of upper left corner
* @param y1 Y coordinate of upper left corner
* @param x2 X coordinate of lower right corner
* @param y2 Y coordinate of lower right corner
* @param mode constants SCROLL_DOWN and SCROLL_UP control scroll direction
*
* Defines a text area based on absolute coordinates.
* The pixel coordinates for the text area are inclusive so x2,y2 is the lower right
* pixel of the text area.
*
* x1,y1 and x2,y2 are an absolute coordinates and are relateive to the 0,0 origin of the
* display.
*
* The area within the newly defined text area is intentionally not cleared.
*
* mode is an optional parameter and defaults to normal/up scrolling
*
* @returns true with the given area selected if all the coordinates are valid,
* otherwise returns returns false with the area set to the full display
*
* @note
* Upon creation of the text area, the cursor position for the text area will be set to x1, y1
*
* @see ClearArea()
*
*/
bool ILI9341_due_gText::defineArea(int16_t x1, int16_t y1, int16_t x2, int16_t y2) //, textMode mode)
{
textMode mode = DEFAULT_SCROLLDIR;
//Serial << "defineArea input " << x1 << " " << y1 << " " << x2 << " " << y2 << endl;
uint8_t ret = false;
int16_t disp_width = _ili->width();
int16_t disp_height = _ili->height();
//if( (x1 >= x2)
// || (y1 >= y2)
// || (x1 >= disp_width)
// || (y1 >= disp_height)
// || (x2 >= disp_width)
// || (y2 >= disp_height)
// )
//{
// // failed sanity check so set defaults and return false
// _area.x1 = 0;
// _area.y1 = 0;
// _area.x2 = disp_width -1;
// _area.y2 = disp_height -1;
// _area.mode = DEFAULT_SCROLLDIR;
//}
//else
{
_area.x1 = x1;
_area.y1 = y1;
_area.x2 = x2;
_area.y2 = y2;
_area.mode = mode; // not yet sanity checked
ret = true;
}
//Serial << "defineArea set " << _area.x1 << " " << _area.y1 << " " << _area.x2 << " " << _area.y2 << endl;
/*
* set cursor position for the area
*/
_x = x1;
_y = y1;
_scale = 1;
#ifndef GLCD_NODEFER_SCROLL
/*
* Make sure to clear a deferred scroll operation when re defining areas.
*/
_needScroll = 0;
#endif
return ret;
}
/**
* Define a predefined generic text area
*
* @param selection a value from @ref predefinedArea
* @param mode constants SCROLL_DOWN and SCROLL_UP control scroll direction
*
* Defines a text area using a selection form a set of predefined areas.
*
* The area within the newly defined text area is intentionally not cleared.
*
* mode is an optional parameter and defaults to normal/up scrolling
*
* @return returns @em true if successful.
*
*
* @note
* Upon defining the text area, the cursor position for the text area will be set to
* the upper left coordinate of the given predefined area
*
* @see ClearArea()
* @see predefinedArea
*
*/
#if INCLUDE_NOT_WORKING_YET
bool ILI9341_due_gText::defineArea(predefinedArea selection, textMode mode)
{
int16_t x1,y1,x2,y2;
TareaToken tok;
tok.token = selection;
x1 = tok.coord.x1;
y1 = tok.coord.y1;
x2 = tok.coord.x2;
y2 = tok.coord.y2;
return defineArea(x1,y1,x2,y2, mode);
}
#endif
/*
* Scroll a pixel region up.
* Area scrolled is defined by x1,y1 through x2,y2 inclusive.
* x1,y1 is upper left corder, x2,y2 is lower right corner.
*
* color is the color to be used for the created space along the
* bottom.
*
* pixels is the *exact* pixels to scroll. 1 is 1 and 9 is 9 it is
* not 1 less or 1 more than what you want. It is *exact*.
*/
//void ILI9341_due_gText::ScrollUp(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2,
// uint8_t pixels, uint8_t color)
//{
//uint8_t dy;
//uint8_t dbyte;
//uint8_t sy;
//uint8_t sbyte;
//uint8_t col;
//
// /*
// * Scrolling up more than area height?
// */
// if(y1 + pixels > y2)
// {
// /*
// * fill the region with "whitespace" because
// * it is being totally scrolled out.
// */
// _ili->fillRect(x1, y1, x2 - x1, y2 - y1, color);
// return;
// }
//
// for(col = x1; col <= x2; col++)
// {
// dy = y1;
// GotoXY(col, dy & ~7);
// dbyte = glcd_Device::ReadData();
//
//
// /*
// * preserve bits outside/above scroll region
// */
//
// dbyte &= (_BV((dy & 7)) - 1);
//
// sy = dy + pixels;
// glcd_Device::GotoXY(col, sy & ~7);
// sbyte = glcd_Device::ReadData();
//
// while(sy <= y2)
// {
// if(sbyte & _BV(sy & 7))
// {
// dbyte |= _BV(dy & 7);
// }
//
// sy++;
// if((sy & 7) == 0)
// {
// /*
// * If we just crossed over, then we should be done.
// */
// if(sy < DISPLAY_HEIGHT)
// {
// glcd_Device::GotoXY(col, sy & ~7);
// sbyte = glcd_Device::ReadData();
// }
// }
//
// if((dy & 7) == 7)
// {
// glcd_Device::GotoXY(col, dy & ~7); // Should be able to remove this
// glcd_Device::WriteData(dbyte);
// dbyte = 0;
// }
// dy++;
// }
//
// /*
// * Handle the new area at the bottom of the region
// */
//
// for(uint8_t p = pixels; p; p--)
// {
// if(color == BLACK)
// {
// dbyte |= _BV(dy & 7);
// }
// else
// {
// dbyte &= ~_BV(dy & 7);
// }
//
// if((dy & 7) == 7)
// {
// glcd_Device::GotoXY(col, dy & ~7); // should be able to remove this.
// glcd_Device::WriteData(dbyte);
// dbyte = 0;
// }
// dy++;
// }
//
// /*
// * Flush out the final destination byte
// */
//
//
// if(dy & 7)
// {
// dy--;
//
// glcd_Device::GotoXY(col, dy & ~7);
// sbyte = glcd_Device::ReadData();
// /*
// * Preserver bits outside/below region
// */
//
// dy++;
// sbyte &= ~(_BV((dy & 7)) - 1);
// dbyte |= sbyte;
//
// glcd_Device::WriteData(dbyte);
// }
// }
//
//}
//#ifndef GLCD_NO_SCROLLDOWN
//
//void ILI9341_due_gText::ScrollDown(uint8_t x1, uint8_t y1, uint8_t x2, uint8_t y2,
// uint8_t pixels, uint8_t color)
//{
//uint8_t dy;
//uint8_t dbyte;
//uint8_t sy;
//uint8_t sbyte;
//uint8_t col;
//
// /*
// * Scrolling up more than area height?
// */
// if(y1 + pixels > y2)
// {
// /*
// * fill the region with "whitespace" because
// * it is being totally scrolled out.
// */
// glcd_Device::SetPixels(x1, y1, x2, y2, color);
// return;
// }
//
// /*
// * Process region from left to right
// */
// for(col = x1; col <= x2; col++)
// {
// dy = y2;
// glcd_Device::GotoXY(col, dy & ~7);
// dbyte = glcd_Device::ReadData();
//
// /*
// * preserve bits outside/below scroll region
// */
//
// dbyte &= ~(_BV(((dy & 7)+1)) - 1);
// sy = dy - pixels;
// glcd_Device::GotoXY(col, sy & ~7);
// sbyte = glcd_Device::ReadData();
//
// while(sy >= y1)
// {
// if(sbyte & _BV(sy & 7))
// {
// dbyte |= _BV(dy & 7);
// }
// if((dy & 7) == 0)
// {
// glcd_Device::GotoXY(col, dy & ~7); // Should be able to remove this
// glcd_Device::WriteData(dbyte);
// dbyte = 0;
// }
// dy--;
//
// if(!sy)
// break; /* if we bottomed out, we are done */
// sy--;
// if((sy & 7) == 7)
// {
// glcd_Device::GotoXY(col, sy & ~7);
// sbyte = glcd_Device::ReadData();
// }
//
// }
//
// /*
// * Handle the new area at the top of the column
// */
//
// for(uint8_t p = pixels; p; p--)
// {
// if(color == BLACK)
// {
// dbyte |= _BV(dy & 7);
// }
// else
// {
// dbyte &= ~_BV(dy & 7);
// }
//
// if((dy & 7) == 0)
// {
// glcd_Device::GotoXY(col, dy & ~7); // should be able to remove this.
// glcd_Device::WriteData(dbyte);
// dbyte = 0;
// }
// dy--;
// }
//
// dy++; /* point dy back to last destination row */
//
// /*
// * Flush out the final destination byte
// */
//
// if(dy & 7)
// {
// glcd_Device::GotoXY(col, dy & ~7);
// sbyte = glcd_Device::ReadData();
// /*
// * Preserve bits outside/above region
// */
//
// sbyte &= (_BV((dy & 7)) - 1);
// dbyte |= sbyte;
// glcd_Device::WriteData(dbyte);
// }
//
// }
//
//}
//#endif //GLCD_NO_SCROLLDOWN
/*
* Handle all special processing characters
*/
void ILI9341_due_gText::specialChar(uint8_t c)
{
if(c == '\n')
{
uint8_t height = fontHeight();
/*
* Erase all pixels remaining to edge of text area.on all wraps
* It looks better when using inverted (WHITE) text, on proportional fonts, and
* doing WHITE scroll fills.
*
*/
if(_x < _area.x2)
_ili->fillRect(_x, _y, _area.x2 - _x, height, _fontBgColor);
//glcd_Device::SetPixels(_x, _y, _area.x2, _y+height, _fontColor == BLACK ? WHITE : BLACK);
/*
* Check for scroll up vs scroll down (scrollup is normal)
*/
#ifndef GLCD_NO_SCROLLDOWN
if(_area.mode == SCROLL_UP)
#endif
{
/*
* Normal/up scroll
*/
/*
* Note this comparison and the pixel calcuation below takes into
* consideration that fonts
* are atually 1 pixel taller when rendered.
* This extra pixel is along the bottom for a "gap" between the character below.
*/
if(_y + 2*height >= _area.y2)
{
#ifndef GLCD_NODEFER_SCROLL
if(!_needScroll)
{
_needScroll = 1;
return;
}
#endif
/*
* forumula for pixels to scroll is:
* (assumes "height" is one less than rendered height)
*
* pixels = height - ((_area.y2 - _y) - height) +1;
*
* The forumala below is unchanged
* But has been re-written/simplified in hopes of better code
*
*/
uint8_t pixels = 2*height + _y - _area.y2 +1;
/*
* Scroll everything to make room
* * NOTE: (FIXME, slight "bug")
* When less than the full character height of pixels is scrolled,
* There can be an issue with the newly created empty line.
* This is because only the # of pixels scrolled will be colored.
* What it means is that if the area starts off as white and the text
* color is also white, the newly created empty text line after a scroll
* operation will not be colored BLACK for the full height of the character.
* The only way to fix this would be alter the code use a "move pixels"
* rather than a scroll pixels, and then do a clear to end line immediately
* after the move and wrap.
*
* Currently this only shows up when
* there are are less than 2xheight pixels below the current Y coordinate to
* the bottom of the text area
* and the current background of the pixels below the current text line
* matches the text color
* and a wrap was just completed.
*
* After a full row of text is printed, the issue will resolve itself.
*
*
*/
//ScrollUp(_area.x1, _area.y1, _area.x2, _area.y2, pixels, _fontBgColor);
_x = _area.x1;
_y = _area.y2 - height;
}
else
{
/*
* Room for simple wrap
*/
_x = _area.x1;
_y = _y+height+1;
}
}
#ifndef GLCD_NO_SCROLLDOWN
else
{
/*
* Reverse/Down scroll
*/
/*
* Check for Wrap vs scroll.
*
* Note this comparison and the pixel calcuation below takes into
* consideration that fonts
* are atually 1 pixel taller when rendered.
*
*/
if(_y > _area.y1 + height)
{
/*
* There is room so just do a simple wrap
*/
_x = _area.x1;
_y = _y - (height+1);
}
else
{
#ifndef GLCD_NODEFER_SCROLL
if(!_needScroll)
{
_needScroll = 1;
return;
}
#endif
/*
* Scroll down everything to make room for new line
* (assumes "height" is one less than rendered height)
*/
uint8_t pixels = height+1 - (_area.y1 - _y);
//ScrollDown(_area.x1, _area.y1, _area.x2, _area.y2, pixels, _fontBgColor);
_x = _area.x1;
_y = _area.y1;
}
}
#endif
}
}
/**
* output a character
*
* @param c the character to output
*
* If the character will not fit on the current text line
* inside the text area,
* the text position is wrapped to the next line. This might be
* the next lower or the next higher line depending on the
* scroll direction.
*
* If there is not enough room to fit a full line of new text after
* wrapping, the entire text area will be scrolled to make room for a new
* line of text. The scroll direction will be up or down
* depending on the scroll direction for the text area.
*/
int ILI9341_due_gText::putChar(uint8_t c)
{
if(_font == 0)
{
Serial.println(F("No font selected"));
return 0; // no font selected
}
/*
* check for special character processing
*/
if(c < 0x20)
{
//specialChar(c);
return 1;
}
uint16_t charWidth = 0;
uint16_t charHeight = fontHeight();
uint8_t charHeightInBytes = (charHeight+7)/8; /* calculates height in rounded up bytes */
uint8_t firstChar = pgm_read_byte(_font+GTEXT_FONT_FIRST_CHAR);
uint8_t charCount = pgm_read_byte(_font+GTEXT_FONT_CHAR_COUNT);
uint16_t index = 0;
uint8_t thielefont;
if(c < firstChar || c >= (firstChar+charCount)) {
return 0; // invalid char
}
c-= firstChar;
if( isFixedWidthFont(_font) {
thielefont = 0;
charWidth = pgm_read_byte(_font+GTEXT_FONT_FIXED_WIDTH);
index = c*charHeightInBytes*charWidth+GTEXT_FONT_WIDTH_TABLE;
}
else{
// variable width font, read width data, to get the index
thielefont = 1;
/*
* Because there is no table for the offset of where the data
* for each character glyph starts, run the table and add up all the
* widths of all the characters prior to the character we
* need to locate.
*/
for(uint8_t i=0; i<c; i++) {
index += pgm_read_byte(_font+GTEXT_FONT_WIDTH_TABLE+i);
}
/*
* Calculate the offset of where the font data
* for our character starts.
* The index value from above has to be adjusted because
* there is potentialy more than 1 byte per column in the glyph,
* when the characgter is taller than 8 bits.
* To account for this, index has to be multiplied
* by the height in bytes because there is one byte of font
* data for each vertical 8 pixels.
* The index is then adjusted to skip over the font width data
* and the font header information.
*/
index = index*charHeightInBytes+charCount+GTEXT_FONT_WIDTH_TABLE;
/*
* Finally, fetch the width of our character
*/
charWidth = pgm_read_byte(_font+GTEXT_FONT_WIDTH_TABLE+c);
}
#ifndef GLCD_NODEFER_SCROLL
/*
* check for a defered scroll
* If there is a deferred scroll,
* Fake a newline to complete it.
*/
if(_needScroll)
{
putChar('\n'); // fake a newline to cause wrap/scroll
_needScroll = 0;
}
#endif
/*
* If the character won't fit in the text area,
* fake a newline to get the text area to wrap and
* scroll if necessary.
* NOTE/WARNING: the below calculation assumes a 1 pixel pad.
* This will need to be changed if/when configurable pixel padding is supported.
*/
if(_x + charWidth > _area.x2)
{
putChar('\n'); // fake a newline to cause wrap/scroll
#ifndef GLCD_NODEFER_SCROLL
/*
* We can't defer a scroll at this point since we need to ouput
* a character right now.
*/
if(_needScroll)
{
putChar('\n'); // fake a newline to cause wrap/scroll
_needScroll = 0;
}
#endif
}
if(_fontMode == gTextFontMode_Solid)
drawSolidChar(c, index, charWidth, charHeight);
else if(_fontMode == gTextFontMode_Transparent)
drawTransparentChar(c, index, charWidth, charHeight);
// last but not least, draw the character
//glcd_Device::GotoXY(_x, _y);
/*
* Draw each column of the glyph (character) horizontally
* 8 bits (1 page) at a time.
* i.e. if a font is taller than 8 bits, draw upper 8 bits first,
* Then drop down and draw next 8 bits and so on, until done.
* This code depends on WriteData() doing writes that span LCD
* memory pages, which has issues because the font data isn't
* always a multiple of 8 bits.
*/
return 1; // valid char
}
void ILI9341_due_gText::drawSolidChar(char c, uint16_t index, uint16_t charWidth, uint16_t charHeight)
{
uint8_t bitId=0;
int16_t cx = _x;
int16_t cy = _y;
#if SPI_MODE_DMA
uint8_t* scanlineBuff = _ili->_scanlineBuffer;
uint8_t fontColorHi = highByte(_fontColor);
uint8_t fontColorLo = lowByte(_fontColor);
uint8_t fontBgColorHi = highByte(_fontBgColor);
uint8_t fontBgColorLo = lowByte(_fontBgColor);
#endif
uint8_t charHeightInBytes = (charHeight+7)/8; /* calculates height in rounded up bytes */
uint16_t lineId=0;
uint8_t numRenderBits = 8;
const uint8_t numRemainingBits = charHeight % 8;
//_ili->enableCS();
for(uint16_t j=0; j<charWidth; j++) /* each column */
{
//Serial << "Printing row" << endl;
lineId = 0;
numRenderBits = 8;
_ili->setAddrAndRW_cont(cx, cy, cx, cy+charHeight -1);
//_ili->setDCForData();
for(uint8_t i=0; i<charHeightInBytes; i++) /* each vertical byte */
{
uint16_t page = i*charWidth; // page must be 16 bit to prevent overflow
uint8_t data = pgm_read_byte(_font+index+page+j);
/*
* This funkyness is because when the character glyph is not a
* multiple of 8 in height, the residual bits in the font data
* were aligned to the incorrect end of the byte with respect
* to the GLCD. I believe that this was an initial oversight (bug)
* in Thieles font creator program. It is easily fixed
* in the font program but then creates a potential backward
* compatiblity problem.
* --- bperrybap
*/
if(charHeight > 8 && charHeight < (i+1)*8) /* is it last byte of multibyte tall font? */
{
data >>= ((i+1) << 3) - charHeight; // (i+1)*8
}
//Serial << "data:" <<data << " x:" << cx << " y:" << cy << endl;
if(i == charHeightInBytes - 1) // last byte in column
numRenderBits = numRemainingBits;
for( bitId = 0; bitId < numRenderBits; bitId++ )
{
if ( (data & 0x01) == 0 )
{
#if SPI_MODE_NORMAL | SPI_MODE_EXTENDED
_ili->writedata16_cont(_fontBgColor);
#elif SPI_MODE_DMA
scanlineBuff[lineId++] = fontBgColorHi;
scanlineBuff[lineId++] = fontBgColorLo;
#endif
}
else
{
#if SPI_MODE_NORMAL | SPI_MODE_EXTENDED
_ili->writedata16_cont(_fontColor);
#elif SPI_MODE_DMA
scanlineBuff[lineId++] = fontColorHi;
scanlineBuff[lineId++] = fontColorLo;
#endif
}
data>>=1;
}
//delay(50);
}
//Serial << endl;
cx++;
#if SPI_MODE_DMA
_ili->writeScanline_cont(charHeight); // height in px * 2 bytes per px
#endif
}
_ili->disableCS(); // to put CS line back up
_x += charWidth;
//Serial << " ending at " << _x << " lastChar " << _lastChar <<endl;
if(_letterSpacing > 0 && !_isLastChar)
{
_ili->fillRect(_x, _y, _letterSpacing, charHeight, _fontBgColor);
_x+=_letterSpacing;
}
//Serial << "letterSpacing " << _letterSpacing <<" x: " << _x <<endl;
}
void ILI9341_due_gText::drawTransparentChar(char c, uint16_t index, uint16_t charWidth, uint16_t charHeight)
{
uint8_t bitId=0;
uint8_t bit=0, lastBit=0;
int16_t cx = _x;
int16_t cy = _y;
uint16_t lineStart = 0;
uint16_t lineEnd = 0;
#if SPI_MODE_DMA
_ili->fillScanline(_fontColor); //pre-fill the scanline, we will be drawing different lenghts of it
#endif
uint8_t charHeightInBytes = (charHeight+7)/8; /* calculates height in rounded up bytes */
uint16_t lineId=0;
uint8_t numRenderBits = 8;
const uint8_t numRemainingBits = charHeight % 8;
_ili->enableCS();
for(uint8_t j=0; j<charWidth; j++) /* each column */
{
//Serial << "Printing row" << endl;
lineId = 0;
numRenderBits = 8;
for(uint8_t i=0; i<charHeightInBytes; i++) /* each vertical byte */
{
uint16_t page = i*charWidth; // page must be 16 bit to prevent overflow
uint8_t data = pgm_read_byte(_font+index+page+j);
/*
* This funkyness is because when the character glyph is not a
* multiple of 8 in height, the residual bits in the font data
* were aligned to the incorrect end of the byte with respect
* to the GLCD. I believe that this was an initial oversight (bug)
* in Thieles font creator program. It is easily fixed
* in the font program but then creates a potential backward
* compatiblity problem.
* --- bperrybap
*/
if(charHeight > 8 && charHeight < (i+1)*8) /* is it last byte of multibyte tall font? */
{
data >>= ((i+1) << 3) - charHeight; // (i+1)*8
}
//Serial << "data:" <<data << " x:" << cx << " y:" << cy << endl;
if(i == 0)
{
bit = lastBit = lineStart = 0;
}
else if(i == charHeightInBytes - 1) // last byte in column
numRenderBits = numRemainingBits;
for( bitId = 0; bitId < numRenderBits; bitId++ )
{
bit = data & 0x01;
if(bit ^ lastBit) // same as bit != lastBit
{
if(bit ^ 0x00) // if bit != 0 (so it's 1)
{
lineStart = lineEnd = i*8+bitId;
}
else
{
_ili->setAddrAndRW_cont(cx, cy+lineStart, cx, cy+lineEnd);
#if SPI_MODE_NORMAL | SPI_MODE_EXTENDED
_ili->setDCForData();
for(int p=0; p<lineEnd-lineStart+1; p++)
{
_ili->write16_cont(_fontColor);
}
#elif SPI_MODE_DMA
_ili->writeScanline_cont(lineEnd-lineStart+1);
#endif
}
lastBit = bit;
}
else if(bit ^ 0x00) // increment only if bit is 1
{
lineEnd++;
}
data>>=1;
}
if(lineEnd == charHeight - 1) // we have a line that goes all the way to the bottom
{
_ili->setAddrAndRW_cont(cx, cy+lineStart, cx, cy+lineEnd);
#if SPI_MODE_NORMAL | SPI_MODE_EXTENDED
_ili->setDCForData();
for(int p=0; p<lineEnd-lineStart+1; p++)
{
_ili->write16_cont(_fontColor);
}
#elif SPI_MODE_DMA
_ili->writeScanline_cont(lineEnd-lineStart+1);
#endif
}
//delay(25);
}
//Serial << endl;
cx++;
}
_ili->disableCS(); // to put CS line back up
_x += charWidth;
if(_letterSpacing > 0 && !_isLastChar)
{
_x+=_letterSpacing;
}
}
/**
* output a character string
*
* @param str pointer to a null terminated character string.
*
* Outputs all the characters in the string to the text area.
* See putChar() for a full description of how characters are
* written to the text area.
*/
void ILI9341_due_gText::puts(char *str)
{
while(*str)
{
if(*(str+1) == 0)
_isLastChar = true;
putChar((uint8_t)*str);
str++;
}
_isLastChar = false;
}
/**
* output a String class string
*
* @param str String class string
*
* Outputs all the characters in the string to the text area.
* See putChar() for a full description of how characters are
* written to the text area.
*
*/
void ILI9341_due_gText::puts(const String &str)
{
for (int i = 0; i < str.length(); i++)
{
write(str[i]);
}
}
/**
* output a program memory character string
*
* @param str pointer to a null terminated character string stored in program memory
*
* Outputs all the characters in the string to the text area.
* See putChar() for a full description of how characters are
* written to the text area.
*
* @see putChar()
* @see puts()
* @see drawString()
* @see drawString_P()
* @see write()
*/
void ILI9341_due_gText::puts_P(PGM_P str)
{
uint8_t c;
while((c = pgm_read_byte(str)) != 0)
{
putChar(c);
str++;
}
}
/**
* output a String class string at x,y coordinate
*
* @param str pointer to a null terminated character string
* @param x specifies the horizontal location
* @param y specifies the vertical location
*
*
* Outputs all the characters in the string to the text area.
* X & Y are zero based pixel coordinates and are relative to
* the upper left corner of the text area.
*
* See putChar() for a full description of how characters are
* written to the text area.
*/
void ILI9341_due_gText::drawString(String &str, int16_t x, int16_t y)
{
cursorToXY(x,y);
puts(str);
}
/**
* output a program memory character string at x,y coordinate
*
* @param str pointer to a null terminated character string stored in program memory
* @param x specifies the horizontal location
* @param y specifies the vertical location
*
*
* Outputs all the characters in the string to the text area.
* X & Y are zero based pixel coordinates and are relative to
* the upper left corner of the text area.
*
* See putChar() for a full description of how characters are
* written to the text area.
*/
void ILI9341_due_gText::drawString_P(PGM_P str, int16_t x, int16_t y)
{
cursorToXY(x,y);
puts_P(str);
}
/**
* output a character string at x,y coordinate
*
* @param str String class string
* @param x specifies the horizontal location
* @param y specifies the vertical location
*
*
* Outputs all the characters in the string to the text area.
* X & Y are zero based pixel coordinates and are relative to
* the upper left corner of the text area.
*
* See putChar() for a full description of how characters are
* written to the text area.
*/
void ILI9341_due_gText::drawString(char *str, int16_t x, int16_t y)
{
cursorToXY(x,y);
puts(str);
}
void ILI9341_due_gText::drawString(char *str, int16_t x, int16_t y, uint16_t pixelsClearedOnLeft, uint16_t pixelsClearedOnRight)
{
cursorToXY(x,y);
// CLEAR PIXELS ON THE LEFT
if(pixelsClearedOnLeft > 0)
_ili->fillRect(_x-pixelsClearedOnLeft, _y, pixelsClearedOnLeft, fontHeight(), _fontBgColor);
puts(str);
// CLEAR PIXELS ON THE RIGHT
if(pixelsClearedOnRight > 0)
_ili->fillRect(_x, _y, pixelsClearedOnRight, fontHeight(), _fontBgColor);
}
void ILI9341_due_gText::drawString(char *str, int16_t x, int16_t y, gTextEraseLine eraseLine)
{
cursorToXY(x,y);
// CLEAR PIXELS ON THE LEFT
if(eraseLine == gTextEraseFromBOL || eraseLine == gTextEraseFullLine)
{
uint16_t clearX1 = max(min(_x, _area.x1), _x-1024);
_ili->fillRect(clearX1, _y, _x - clearX1, fontHeight(), _fontBgColor);
}
puts(str);
// CLEAR PIXELS ON THE RIGHT
if(eraseLine == gTextEraseToEOL || eraseLine == gTextEraseFullLine)
{
uint16_t clearX2 = min(max(_x,_area.x2), _x+1024);
_ili->fillRect(_x, _y, clearX2 - _x, fontHeight(), _fontBgColor);
}
}
void ILI9341_due_gText::drawString(char *str, gTextAlign align)
{
drawStringPivotedOffseted(str, align, gTextPivotDefault, 0, 0, 0, 0);
}
void ILI9341_due_gText::drawString(char *str, gTextAlign align, gTextEraseLine eraseLine)
{
uint16_t pixelsClearedOnLeft = 0;
uint16_t pixelsClearedOnRight = 0;
if(eraseLine == gTextEraseFromBOL || eraseLine == gTextEraseFullLine)
pixelsClearedOnLeft = 1024;
if(eraseLine == gTextEraseToEOL || eraseLine == gTextEraseFullLine)
pixelsClearedOnRight = 1024;
drawStringPivotedOffseted(str, align, gTextPivotDefault, 0, 0, pixelsClearedOnLeft, pixelsClearedOnRight);
}
void ILI9341_due_gText::drawString(char *str, gTextAlign align, uint16_t pixelsClearedOnLeft, uint16_t pixelsClearedOnRight)
{
drawStringPivotedOffseted(str, align, gTextPivotDefault, 0, 0, pixelsClearedOnLeft, pixelsClearedOnRight);
}
void ILI9341_due_gText::drawStringOffseted(char *str, gTextAlign align, uint16_t offsetX, uint16_t offsetY)
{
drawStringPivotedOffseted(str, align, gTextPivotDefault,offsetX, offsetY, 0, 0);
}
void ILI9341_due_gText::drawStringOffseted(char *str, gTextAlign align, uint16_t offsetX, uint16_t offsetY, gTextEraseLine eraseLine)
{
uint16_t pixelsClearedOnLeft = 0;
uint16_t pixelsClearedOnRight = 0;
if(eraseLine == gTextEraseFromBOL || eraseLine == gTextEraseFullLine)
pixelsClearedOnLeft = 1024;
if(eraseLine == gTextEraseToEOL || eraseLine == gTextEraseFullLine)
pixelsClearedOnRight = 1024;
drawStringPivotedOffseted(str, align, gTextPivotDefault,offsetX, offsetY, pixelsClearedOnLeft, pixelsClearedOnRight);
}
void ILI9341_due_gText::drawStringOffseted(char *str, gTextAlign align, uint16_t offsetX, uint16_t offsetY, uint16_t pixelsClearedOnLeft, uint16_t pixelsClearedOnRight)
{
drawStringPivotedOffseted(str, align, gTextPivotDefault,offsetX, offsetY, pixelsClearedOnLeft, pixelsClearedOnRight);
}
void ILI9341_due_gText::drawStringPivoted(char *str, int16_t x, int16_t y, gTextPivot pivot)
{
cursorToXY(x,y);
if(pivot != gTextPivotTopLeft && pivot != gTextPivotDefault)
applyPivot(str, pivot);
puts(str);
}
void ILI9341_due_gText::drawStringPivoted(char *str, gTextAlign align, gTextPivot pivot)
{
drawStringPivotedOffseted(str, align, pivot, 0, 0, 0, 0);
}
void ILI9341_due_gText::drawStringPivoted(char *str, gTextAlign align, gTextPivot pivot, gTextEraseLine eraseLine)
{
uint16_t pixelsClearedOnLeft = 0;
uint16_t pixelsClearedOnRight = 0;
if(eraseLine == gTextEraseFromBOL || eraseLine == gTextEraseFullLine)
pixelsClearedOnLeft = 1024;
if(eraseLine == gTextEraseToEOL || eraseLine == gTextEraseFullLine)
pixelsClearedOnRight = 1024;
drawStringPivotedOffseted(str, align, pivot, 0, 0, pixelsClearedOnLeft, pixelsClearedOnRight);
}
void ILI9341_due_gText::drawStringPivoted(char *str, gTextAlign align, gTextPivot pivot, uint16_t pixelsClearedOnLeft, uint16_t pixelsClearedOnRight)
{
drawStringPivotedOffseted(str, align, pivot, 0, 0, pixelsClearedOnLeft, pixelsClearedOnRight);
}
void ILI9341_due_gText::drawStringPivotedOffseted(char *str, gTextAlign align, gTextPivot pivot, uint16_t offsetX, uint16_t offsetY)
{
drawStringPivotedOffseted(str, align, pivot, offsetX, offsetY, 0, 0);
}
void ILI9341_due_gText::drawStringPivotedOffseted(char *str, gTextAlign align, gTextPivot pivot, uint16_t offsetX, uint16_t offsetY, gTextEraseLine eraseLine)
{
uint16_t pixelsClearedOnLeft = 0;
uint16_t pixelsClearedOnRight = 0;
if(eraseLine == gTextEraseFromBOL || eraseLine == gTextEraseFullLine)
pixelsClearedOnLeft = 1024;
if(eraseLine == gTextEraseToEOL || eraseLine == gTextEraseFullLine)
pixelsClearedOnRight = 1024;
drawStringPivotedOffseted(str, align, pivot, offsetX, offsetY, pixelsClearedOnLeft, pixelsClearedOnRight);
}
void ILI9341_due_gText::drawStringPivotedOffseted(char *str, gTextAlign align, gTextPivot pivot, uint16_t offsetX, uint16_t offsetY, uint16_t pixelsClearedOnLeft, uint16_t pixelsClearedOnRight)
{
//Serial << pixelsClearedOnLeft << " " << pixelsClearedOnRight << endl;
_x = _area.x1;
_y = _area.y1;
//PIVOT
if(pivot == gTextPivotDefault)
{
switch(align)
{
case gTextAlignTopLeft: { pivot = gTextPivotTopLeft; break; }
case gTextAlignTopCenter: { pivot = gTextPivotTopCenter; break; }
case gTextAlignTopRight: { pivot = gTextPivotTopRight; break; }
case gTextAlignMiddleLeft: { pivot = gTextPivotMiddleLeft; break; }
case gTextAlignMiddleCenter: { pivot = gTextPivotMiddleCenter; break; }
case gTextAlignMiddleRight: { pivot = gTextPivotMiddleRight; break; }
case gTextAlignBottomLeft: { pivot = gTextPivotBottomLeft; break; }
case gTextAlignBottomCenter: { pivot = gTextPivotBottomCenter; break; }
case gTextAlignBottomRight: { pivot = gTextPivotBottomRight; break; }
}
}
if(pivot != gTextPivotTopLeft)
applyPivot(str, pivot);
// ALIGN
if(align != gTextAlignTopLeft)
{
switch(align)
{
case gTextAlignTopCenter:
{
_x += (_area.x2 - _area.x1)/2;
break;
}
case gTextAlignTopRight:
{
_x += _area.x2 - _area.x1;
break;
}
case gTextAlignMiddleLeft:
{
_y += (_area.y2-_area.y1)/2;
break;
}
case gTextAlignMiddleCenter:
{
_x += (_area.x2 - _area.x1)/2;
_y += (_area.y2 - _area.y1)/2;
break;
}
case gTextAlignMiddleRight:
{
_x += _area.x2 - _area.x1;
_y += (_area.y2 - _area.y1)/2;
break;
}
case gTextAlignBottomLeft:
{
_y += _area.y2 - _area.y1;
break;
}
case gTextAlignBottomCenter:
{
_x += (_area.x2 - _area.x1)/2;
_y += _area.y2 - _area.y1;
break;
}
case gTextAlignBottomRight:
{
_x += _area.x2 - _area.x1;
_y += _area.y2 - _area.y1;
break;
}
}
}
// OFFSET
_x+=offsetX;
_y+=offsetY;
// CLEAR PIXELS ON THE LEFT
if(pixelsClearedOnLeft > 0)
{
int16_t clearX1 = max(min(_x, (int16_t)_area.x1), _x-(int16_t)pixelsClearedOnLeft);
//Serial.println(clearX1);
_ili->fillRect(clearX1, _y, _x - clearX1, fontHeight(), _fontBgColor);
}
puts(str);
// CLEAR PIXELS ON THE RIGHT
if(pixelsClearedOnRight > 0)
{
int16_t clearX2 = min(max(_x, _area.x2), _x+pixelsClearedOnRight);
//Serial << "area from " << _area.x1 << " to " << _area.x2 << endl;
//Serial << "clearing on right from " << _x << " to " << clearX2 << endl;
_ili->fillRect(_x, _y, clearX2 - _x, fontHeight(), _fontBgColor);
}
}
void ILI9341_due_gText::applyPivot(char *str, gTextPivot pivot)
{
switch(pivot)
{
case gTextPivotTopCenter:
{
_x -= stringWidth(str)/2;
break;
}
case gTextPivotTopRight:
{
_x -= stringWidth(str);
break;
}
case gTextPivotMiddleLeft:
{
_y -= fontHeight()/2;
break;
}
case gTextPivotMiddleCenter:
{
_x -= stringWidth(str)/2;
_y -= fontHeight()/2;
break;
}
case gTextPivotMiddleRight:
{
_x -= stringWidth(str);
_y -= fontHeight()/2;
break;
}
case gTextPivotBottomLeft:
{
_y -= fontHeight();
break;
}
case gTextPivotBottomCenter:
{
_x -= stringWidth(str)/2;
_y -= fontHeight();
break;
}
case gTextPivotBottomRight:
{
_x -= stringWidth(str);
_y -= fontHeight();
break;
}
}
}
/**
* Positions cursor to a character based column and row.
*
* @param column specifies the horizontal position
* @param row specifies the vertical position
*
* Column and Row are zero based character positions
* and are relative the the upper left corner of the
* text area base on the size of the currently selected font.
*
* While intended for fixed width fonts, positioning will work for variable
* width fonts.
*
* When variable width fonts are used, the column is based on assuming a width
* of the widest character.
*
* @see cursorToXY()
*/
void ILI9341_due_gText::cursorTo( uint8_t column, uint8_t row)
{
if(_font == 0)
return; // no font selected
/*
* Text position is relative to current text area
*/
_x = column * (pgm_read_byte(_font+GTEXT_FONT_FIXED_WIDTH)+1) + _area.x1;
_y = row * (fontHeight()+1) + _area.y1;
#ifndef GLCD_NODEFER_SCROLL
/*
* Make sure to clear a deferred scroll operation when repositioning
*/
_needScroll = 0;
#endif
}
// Bill, I think the following would be a useful addition to the API
// Should we add a sanity check to these?
/**
* Positions cursor to a character based column on the current row.
*
* @param column specifies the horizontal position
*
* Column is a 0 based character position
* based on the size of the currently selected font.
*
* If column is negative then the column position is relative to the current cursor
* position.
*
* @warning
* While intended only for fixed width fonts, cursor repositioning will be done for variable
* width fonts.
* When variable width fonts are used, the column is based on assuming a width
* of the widest character in the font.
* Because the widest character is used for the amount of cursor movement, the amount
* of cursor movement when using relative positioning will often not be consistent with
* the number characters previously rendered. For example, if a letter "l" was written
* and the cursor was reposisitioned with a -1, the amount backed up will be much larger
* than the width of the "l".
*
*
* @see cursorToXY()
*/
void ILI9341_due_gText::cursorTo(int8_t column)
{
if(_font == 0)
return; // no font selected
/*
* Text position is relative to current text area
* negative value moves the cursor backwards
*/
if(column >= 0)
_x = column * (pgm_read_byte(_font+GTEXT_FONT_FIXED_WIDTH)+1) + _area.x1;
else
_x -= column * (pgm_read_byte(_font+GTEXT_FONT_FIXED_WIDTH)+1);
#ifndef GLCD_NODEFER_SCROLL
/*
* Make sure to clear a deferred scroll operation when repositioning
*/
_needScroll = 0;
#endif
}
/**
* Positions cursor to a X,Y position
*
* @param x specifies the horizontal location
* @param y specifies the vertical location
*
* X & Y are zero based pixel coordinates and are relative to
* the upper left corner of the text area.
*
* @see cursorTo()
*/
void ILI9341_due_gText::cursorToXY( int16_t x, int16_t y)
{
/*
* Text position is relative to current text area
*/
_x = _area.x1 + x;
_y = _area.y1 + y;
//Serial << F("cursorToXY x:") << x << F(" y:") << y << endl;
#ifndef GLCD_NODEFER_SCROLL
/*
* Make sure to clear a deferred scroll operation when repositioning
*/
_needScroll = 0;
#endif
}
/**
* Erase in Line
*
* @param type type of line erase
*
* @arg \ref eraseTO_EOL Erase from cursor to end of line
* @arg \ref eraseFROM_BOL Erase from beginning of line to cursor
* @arg \ref eraseFULL_LINE Erase entire line
*
* Erases all or part of a line of text depending on the type
* of erase specified.
*
* If type is not specified it is assumed to be \ref eraseTO_EOL
*
* The cursor position does not change.
*
* @see ClearArea()
* @see eraseLine_t
*/
void ILI9341_due_gText::eraseTextLine(uint16_t color, gTextEraseLine type)
{
int16_t x = _x;
int16_t y = _y;
int16_t height = fontHeight();
//uint8_t color = (_fontColor == BLACK) ? WHITE : BLACK;
switch(type)
{
case gTextEraseToEOL:
_ili->fillRect(x, y, _area.x2-x, height, color);
//glcd_Device::SetPixels(x, y, _area.x2, y+height, color);
break;
case gTextEraseFromBOL:
_ili->fillRect(_area.x1, y, x - _area.x1, height, color);
//glcd_Device::SetPixels(_area.x1, y, x, y+height, color);
break;
case gTextEraseFullLine:
_ili->fillRect(_area.x1, y, _area.x2 - _area.x1, height, color);
//glcd_Device::SetPixels(_area.x1, y, _area.x2, y+height, color);
break;
}
/*
* restore cursor position
*/
cursorToXY(x,y);
}
/**
* Erase Text Line
*
* @param row row # of text to earase
*
* Erases a line of text and moves the cursor
* to the begining of the line. Rows are zero based so
* the top line/row of a text area is 0.
*
* @see ClearArea()
*/
void ILI9341_due_gText::eraseTextLine(uint16_t color, uint8_t row)
{
cursorTo(0, row);
eraseTextLine(color, gTextEraseToEOL);
}
/**
* Select a Font and font color
*
* @param font a font definition
* @param color can be WHITE or BLACK and defaults to black
* @param callback optional font read routine
*
*
* Selects the font definition as the current font for the text area.
*
* All subsequent printing functions will use this font.
*
* Font definitions from included font definition files are stored in program memory
* You can have as many fonts defines as will fit in program memory up to 64k and can
* switch between them with this function.
*
* If the optional callback argument is ommitted, a default routine
* is selected that assumes that the font is in program memory (flash).
*
* @note
* When the display is initilized in normal mode, BLACK renders dark
* pixels on a white background and WHITE renders white pixels on
* black background; however, if the display is set to INVERTED mode
* all colors are inverted.
*
* @see setFontColor()
* @see SetTextMode()
*/
void ILI9341_due_gText::selectFont(gTextFont font)
{
_font = font;
}
void ILI9341_due_gText::selectFont(gTextFont font, uint16_t fontColor)
{
_font = font;
_fontColor = fontColor;
}
void ILI9341_due_gText::selectFont(gTextFont font, uint16_t fontColor, uint16_t backgroundColor)
{
_font = font;
_fontColor = fontColor;
_fontBgColor = backgroundColor;
}
/**
* Select a font color
*
* @param color can be WHITE or BLACK
*
*
* @see selectFont()
* @see SetTextMode()
*/
void ILI9341_due_gText::setFontColor(uint16_t color)
{
_fontColor = color;
}
void ILI9341_due_gText::setFontColor(uint8_t R, uint8_t G, uint8_t B)
{
_fontColor = _ili->color565(R,G,B);
}
void ILI9341_due_gText::setFontColor(uint16_t color, uint16_t backgroundColor)
{
_fontColor = color;
_fontBgColor = backgroundColor;
}
void ILI9341_due_gText::setFontColor(uint8_t R, uint8_t G, uint8_t B, uint8_t bgR, uint8_t bgG, uint8_t bgB)
{
_fontColor = _ili->color565(R,G,B);
_fontBgColor = _ili->color565(bgR,bgG,bgB);
}
void ILI9341_due_gText::setFontLetterSpacing(uint8_t letterSpacing)
{
_letterSpacing = letterSpacing;
}
void ILI9341_due_gText::setFontMode(gTextFontMode fontMode)
{
if(fontMode == gTextFontMode_Solid || fontMode == gTextFontMode_Transparent)
_fontMode = fontMode;
}
/**
* Set TextArea mode
*
* @param mode text area mode
*
* Currently mode is a scroll direction
* @arg SCROLL_UP
* @arg SCROLL_DOWN
*
* @see selectFont()
* @see setFontColor()
* @see defineArea()
*/
/*
*/
#if INLCUDE_NOT_WORKING_YET
void ILI9341_due_gText::SetTextMode(textMode mode)
{
/*
* when other modes are added the tarea.mode variable will hold a bitmask or enum for the modde and should be renamed
*/
_area.mode = mode;
}
#endif
/**
* Returns the pixel width of a character
*
* @param c character to be sized
*
* @return The width in pixels of the given character
* including any inter-character gap pixels following the character when the character is
* rendered on the display.
*
* @note The font for the character is the most recently selected font.
*
* @see StringWidth()
* @see StringWidth_P()
*/
uint16_t ILI9341_due_gText::charWidth(uint8_t c)
{
int16_t width = 0;
if(isFixedWidthFont(_font){
width = pgm_read_byte(_font+GTEXT_FONT_FIXED_WIDTH);
}
else{
// variable width font
uint8_t firstChar = pgm_read_byte(_font+GTEXT_FONT_FIRST_CHAR);
uint8_t charCount = pgm_read_byte(_font+GTEXT_FONT_CHAR_COUNT);
// read width data
if(c >= firstChar && c < (firstChar+charCount)) {
c -= firstChar;
width = pgm_read_byte(_font+GTEXT_FONT_WIDTH_TABLE+c);
//Serial << "strWidth of " << c << " : " << width << endl;
}
}
return width;
}
/**
* Returns the pixel width of a string
*
* @param str pointer to string stored in RAM
*
* @return the width in pixels of the sum of all the characters in the
* the string pointed to by str.
*
* @see charWidth()
* @see StringWidth_P()
*/
uint16_t ILI9341_due_gText::stringWidth(const char* str)
{
uint16_t width = 0;
while(*str != 0) {
width += charWidth(*str++) + _letterSpacing;
}
if(width > 0)
width -= _letterSpacing;
return width;
}
/**
* Returns the pixel width of a character
*
* @param str pointer to string stored in program memory
*
* @return the width in pixels of the sum of all the characters in the
* the string pointed to by str.
*
* @see charWidth()
* @see StringWidth()
*/
uint16_t ILI9341_due_gText::stringWidth_P(PGM_P str)
{
uint16_t width = 0;
while(pgm_read_byte(str) != 0) {
width += charWidth(pgm_read_byte(str++)) + _letterSpacing;
}
width -= _letterSpacing;
return width;
}
/**
* Returns the pixel width of a character
*
* @param str String class string
*
* @return the width in pixels of the sum of all the characters in the
* the string pointed to by str.
*
* @see charWidth()
* @see StringWidth()
*/
uint16_t ILI9341_due_gText::stringWidth_P(String &str)
{
uint16_t width = 0;
for (int i = 0; i < str.length(); i++)
{
width += charWidth(str[i]) + _letterSpacing;
}
width -= _letterSpacing;
return width;
}
/**
* Legacy function to print a number
*
* @param n is the number to print
*
*
* @see print(n)
*/
void ILI9341_due_gText::printNumber(long n)
{
uint8_t buf[10]; // prints up to 10 digits
uint8_t i=0;
if(n==0)
putChar('0');
else{
if(n < 0){
putChar('-');
n = -n;
}
while(n>0 && i <= 10){
buf[i++] = n % 10; // n % base
n /= 10; // n/= base
}
for(; i >0; i--)
putChar((char) (buf[i-1] < 10 ? '0' + buf[i-1] : 'A' + buf[i-1] - 10));
}
}
/**
* output a character to the text area
* @param c the character to output
*
* This method is needed for the Print base class
* @see putChar()
*/
size_t ILI9341_due_gText::write(uint8_t c)
{
return(putChar(c));
}
//
//#ifndef USE_ARDUINO_FLASHSTR
//// functions to store and print strings in Progmem
//// these should be removed when Arduino supports FLASH strings in the base print class
///**
//* print a flash based string
//* @param str pointer to a null terminated character string stored in program memory
//*
//* @see puts_P()
//*/
//void ILI9341_due_gText::printFlash(FLASHSTRING str)
//{
// puts_P((PGM_P) str);
//}
//
///**
//* print a flash based string
//* @param str pointer to a null terminated character string stored in program memory
//*
//* The string is output followed by a newline.
//*
//* @see puts_P()
//*/
//void ILI9341_due_gText::printFlashln(FLASHSTRING str)
//{
// printFlash(str);
// write('\n');
//}
//#endif