#include "UTFT.h"
#include <util/delay.h>
#include <stdlib.h>
static void myseek(FILE*f,int dist) {
if (f->flags&__SSTR) { // mine! Do fast access
f->len+=(int)dist;
}//else fseek(f,dist,SEEK_CUR);
}
static word mygetw(FILE*f) {
word w;
if (f->flags&__SSTR) { // mine! Do fast access
word*p=(word*)f->len;
if (f->flags&__SPGM) w=pgm_read_word(p);
else w=*p;
++p;
f->len=(int)p;
}else{ // not mine! Use function pointer
w=fgetc(f)&0xFF;
w|=fgetc(f)<<8;
}
return w;
}
/********************
* Basic LCD access *
********************/
void UTFT::writeB(byte b) {
#if DISP_TRANSFER==16
writeW(b); // always 16-bit
#elif DISP_TRANSFER==1
for (byte m=0x80; m; m>>=1) {
if (VL & 0x80) DISP_SDA(1); else DISP_SDA(0);
DISP_SCL(0);
DISP_SCL(1);
}
#else
DISP_OUT(b);
DISP_WR(0);
DISP_WR(1);
#endif
}
void UTFT::writeW(word w) {
#if DISP_TRANSFER<16
writeB(w>>8);
writeB(w);
#elif defined(DISP_ALE)
DISP_OUT(w>>8);
DISP_ALE(1);
DISP_ALE(0);
DISP_OUT(w);
DISP_WR(0);
DISP_WR(1);
#else
DISP_OUT(w);
DISP_WR(0);
DISP_WR(1);
#endif
}
void UTFT::fillW(word w, int r1, int r2) {
#ifdef __MPS430__ // 16-bit optimized loops
if (r1<r2) SWAP(r1,r2); // ensure more inner loop executions
if (!r2) return;
#define DO do {int r=r1; do // two nested loops
#define WHILE while (--r);} while(--r2)
#else // 8-bit optimized loops
unsigned long rep=(unsigned long)(word)r1*(word)r2;
if (!rep) return;
byte rep0=byte(rep);
byte rep1=byte(rep>>8);
byte rep2=byte(rep>>16); // 24 bits are sufficient here
if (rep0) rep1++;
if (rep1) rep2++;
#define DO do do do // three nested loops
#define WHILE while (--rep0); while(--rep1); while(--rep2)
#endif
#if DISP_TRANSFER==16
DISP_OUT(w);
DO{
DISP_WR(0);
DISP_WR(1);
}WHILE;
#elif DISP_TRANSFER==8
if (w>>8==(w&0xFF)) {
DISP_OUT(w);
DO{
DISP_WR(0);
DISP_WR(1);
DISP_WR(0);
DISP_WR(1);
}WHILE;
}else{
DO{
DISP_OUT(w>>8);
DISP_WR(0);
DISP_WR(1);
DISP_OUT(w);
DISP_WR(0);
DISP_WR(1);
}WHILE;
}
#else
DO setPixel(w); WHILE;
#endif
#undef DO
#undef WHILE
}
void UTFT::writeCW(byte b,word w) {
writeC(b);
writeW(w);
}
/*************************************
* Hardware-dependent initialization *
*************************************/
void UTFT::InitLCD(byte orientation) {
orient=orientation;
flags=0;
align=0;
clrClip();
clrOrg();
//clrScale();
DISP_INIT();
#ifdef DISP_DDR
DISP_DDR(1); // data port is output port
#endif
#ifdef DISP_RST
DISP_RST(1);
_delay_ms(5);
DISP_RST(0);
_delay_ms(15);
DISP_RST(1);
_delay_ms(15);
#endif
DISP_CS(0);
#ifdef DISP_ILI9325D
static const struct {byte a;word b;} pairs[] PROGMEM={
{0xE5,0x78F0}, // set SRAM internal timing
{0x01,0}, // set Driver Output Control, bit 8 reflects X counting
{0x02,0x0200}, // set 1 line inversion
{0x03,0x1030},
{0x04,0}, // Resize register
// {0x08,0x0207}, // set the back porch and front porch
// {0x09,0}, // set non-display area refresh cycle ISC[3:0]
// {0x0A,0}, // FMARK function
// {0x0C,0}, // RGB interface setting
// {0x0D,0}, // Frame marker Position
// {0x0F,0}, // RGB interface polarity
//*************Power On sequence ****************//
{0x10,0}, // SAP, BT[3:0], AP, DSTB, SLP, STB
{0x11,0x0007}, // DC1[2:0], DC0[2:0], VC[2:0]
{0x12,0}, // VREG1OUT voltage
{0x13,0}, // VDV[4:0] for VCOM amplitude
{0x07,0x0001},
{0xFF,200}, // Dis-charge capacitor power voltage
{0x10,0x1690}, // SAP, BT[3:0], AP, DSTB, SLP, STB
{0x11,0x0227}, // Set DC1[2:0], DC0[2:0], VC[2:0]
{0xFF,50},
{0x12,0x000D},
{0xFF,50},
{0x13,0x1200}, // VDV[4:0] for VCOM amplitude
{0x29,0x000A}, // 04 VCM[5:0] for VCOMH
// {0x2B,0x000D}, // Set Frame Rate
{0xFF,50},
// ----------- Adjust the Gamma Curve ----------//
{0x30,0},
{0x31,0x0700},
{0x32,0x0707},
{0x35,0},
{0x36,0x000F},
{0x37,0x0707},
{0x38,0x0007},
{0x39,0},
{0x3C,0},
{0x3D,0x0F00},
//------------------ Set GRAM area ---------------//
{0xFE,0},
{0x60,0x2700}, // Gate Scan Line, bit 15 reflects Y counting
{0x61,0x0003}, // NDL,VLE, REV
// {0x6A,0}, // set scrolling line
//-------------- Partial Display Control ---------//
// {0x80,0},
// {0x81,0},
// {0x82,0},
// {0x83,0},
// {0x84,0},
// {0x85,0},
//-------------- Panel Control -------------------//
{0x90,0x0010},
{0x92,0},
{0x07,0x0133}}; // 262K color and display ON
for (char*z=(char*)pairs; z<(char*)pairs+sizeof pairs;) {
byte a=pgm_read_byte(z++);
word b=pgm_read_word(z); z+=2;
switch (a) {
case 1: b|=orient<<7&0x0100; break; //bit 8 reflects X counting
case 0xFF: _delay_ms(200); continue;
case 0xFE: unsetWindow(); continue;
case 0x60: b|=orient<<13&0x8000; break; // bit 15 reflects Y counting
}
writeCW(a,b);
}
#elif defined(DISP_ILI9341)
writeC(0x3A);
writeB(0x55); // RGB16
writeC(0x11); //Exit Sleep
_delay_ms(120);
writeC(0x29); //Display on
writeC(0x36); // Memory Access Control
writeB(0x48); // MY=0, MX=0, MV=0, ML=0, BGR=1, MH=0
writeC(0x2c);
#else
#error Add code here!
#endif
DISP_CS(1);
setColor(COLOR_BLACK);
setBackColor(COLOR_WHITE);
}
void UTFT::lcdOff() {
#ifdef DISP_PCF8833
DISP_CS(0);
writeC(0x28);
DISP_CS(1);
#elif defined(DISP_CPLD)
DISP_CS(0);
writeCW(0x01,0x0000);
writeC(0x0F);
DISP_CS(1);
#endif
}
void UTFT::lcdOn() {
#ifdef DISP_PCF8833
DISP_CS(0);
writeC(0x29);
DISP_CS(1);
#elif defined(DISP_CPLD)
DISP_CS(0);
writeCW(0x01,0x0010);
writeC(0x0F);
DISP_CS(1);
#endif
}
void UTFT::setContrast(char c) {
#ifdef DISP_PCF8833
DISP_CS(0);
if (c>64) c=64;
writeC(0x25);
writeB(c);
DISP_CS(1);
#endif
}
void UTFT::setBrightness(byte br) {
#ifdef DISP_CPLD
DISP_CS(0);
if (br>16) br=16;
writeCW(0x01,br);
writeC(0x0F);
DISP_CS(1);
#endif
}
void UTFT::setDisplayPage(byte page) {
#ifdef DISP_CPLD
DISP_CS(0);
if (page>7) page=7;
writeCW(0x04,page);
writeC(0x0F);
DISP_CS(1);
#endif
}
void UTFT::setWritePage(byte page) {
#ifdef DISP_CPLD
DISP_CS(0);
if (page>7) page=7;
writeCW(0x05,page);
writeC(0x0F);
DISP_CS(1);
#endif
}
// UTF-8 string processing helpers
// No error checking!
// 2-byte UTF-8 (110x xxxx 10xx xxxx)
// 3-byte UTF-8 (1110 xxxx 10xx xxxx 10xx xxxx)
wchar_t UTFT::take_wchar(const char*&s) {
wchar_t ret=*s++;
if (ret&0x80) {
if (ret&0x20) {
ret=ret<<12|(*s++&0x3F)<<6;
}else ret=ret<<6&0x07C0;
ret|=*s++&0x3F;
}
return ret;
}
wchar_t UTFT::take_wchar(const __FlashStringHelper*&h) {
const char*&s=reinterpret_cast<const char*&>(h);
wchar_t ret=pgm_read_byte(s++);
if (ret&0x80) {
if (ret&0x20) {
ret=ret<<12|(pgm_read_byte(s++)&0x3F)<<6;
}else ret=ret<<6&0x07C0;
ret|=pgm_read_byte(s++)&0x3F;
}
return ret;
}
/**********************************************
* Speed-optimized setpixel + bitblt routines *
**********************************************/
void UTFT::setXY(int X, int Y, bool swap) {
#if defined(DISP_ILI9325D)
writeCW(0x20^swap,X);
writeCW(0x21^swap,Y);
writeC(0x22); // prepare pixel value output
#elif defined(DISP_ILI9341)
writeCW(0x2A,X);
writeW(R);
writeCW(0x2B,Y);
writeW(Y);
writeC(0x2C); //write
#else
#error Add code here!
#endif
}
void UTFT::setWindow(byte o) {
byte ori=orient&1;
#if defined(DISP_ILI9325D)
if (o&0x80) {
if (ori) o=o&0xF9 | o<<1&4 | o>>1&2; // irgendwie müssen die Bits getauscht werden, hm...
writeCW(0x03,0x1030^(o&7^ori)<<3);
}
if (o&0x40) {
ori<<=1;
writeCW(0x50^ori,L);
writeCW(0x52^ori,T);
writeCW(0x51^ori,R);
writeCW(0x53^ori,B);
ori>>=1;
}
if (o&0x10) setXY(X,Y,ori); // set pixel address
#elif defined(DISP_ILI9341)
if (o&0x80) {
writeC(0x36);
writeB((o^ori)<<5|0x08|orient&0x04|orient<<3&0x10);
}
if (o&0x40) {
writeCW(0x2A,L); //column
writeW(R);
writeCW(0x2B,T); //page
writeW(B);
writeC(0x2C); //write
}else if (o&0x10) setXY(X,Y,ori); // set pixel address
#else
#error Add code here!
#endif
}
void UTFT::scroll(int v) {
DISP_CS(0);
#if defined(DISP_ILI9325D)
writeCW(0x6A,v);
#elif defined(DISP_ILI9341)
writeCW(0x37,v);
#else
#error Add code here!
#endif
DISP_CS(1);
}
void UTFT::setPixel() {
if (clipOk()) {setWindow(0x30); writeW(fc);}
}
// Skips unset pixels for transparent bitblt:
// Calculates the new horizontal and vertical GRAM address
// x and y are _reversed_ _source_ coordinates
void UTFT::advance(int x,int y) {
byte o=orient>>3;
if (o&1) {
x-=H;
y-=W;
if (o&2) x+=B; else x=T-x;
if (o&4) y+=R; else y=L-y;
}else{
x-=W; // W-x = current positive x, therefore, x is now 0 or negative
y-=H;
if (o&2) x+=R; else x=L-x;
if (o&4) y+=B; else y=T-y;
}
#ifdef DISP_SETXY
setXY(x,y,(o^orient)&1); // don't touch current position here!!
#else
#endif
}
void UTFT::advance() {
byte o=orient;
if (o&0x40) Y=o&0x80?(Y<<1)-YE:YE; // escapement: advance current position
else X=o&0x80?(X<<1)-XE:XE;
}
// Schwarzweiß-Version, vom Flash-Speicher, MSBfirst
// startbit = 0..7 (0 = MSB, 7 = LSB)
// Can work with very dense bitmaps (for bitmap fonts!)
// startbit is not limited to 0..7, can be any bit number
void UTFT::bitblt(const byte*data, int bitsperline, int startbit) {
if (clipX() && clipY()) {
int x=XC;
int y=YC;
if (orient&8) SWAP(x,y);
startbit+=y*bitsperline+x;
data+=startbit>>3; // correct source address
startbit&=7;
x=W;
y=H;
if (orient&8) SWAP(x,y);
bitsperline-=x; // now: bits at end of line to skip
bool skip=false;
DISP_CS(0);
setWindow(0xF0|orient>>3&7); // make clipped window current
do{
byte b=pgm_read_byte(data); // load first byte (possible multiple times!)
byte m=1<<(~startbit&7); // make first bit mask
for (int xx=x;;) {
if (flags&TRANS) {
if (b&m) {
if (skip) advance(xx,y); // set new address only at non-contiguous pixels (for more speed)
skip=false;
writeW(fc); // set pixel to foreground color at X/Y
}else skip=true;
}else writeW(b&m?fc:bc); // set pixel (always)
startbit++; // track bit where we are
if (!--xx) break; // end of line
m>>=1; // next bit in mask
if (!m) { // if emptied...
b=pgm_read_byte(++data); // load next byte
m=0x80; // set next mask bit (MSB)
startbit-=8; // should be 0
}
}
startbit+=bitsperline; // startbit can be 0..8 inclusive(!) at loop exit
data+=startbit>>3; // prepate for next line
startbit&=7;
#ifndef DISP_SETXY
skip=true;
#endif
}while(--y);
unsetWindow();
DISP_CS(1);
}//else drawCircle(100,100,80);
advance();
}
// HiColor-Version, vom Massenspeicher (Live-JPG-Dekompressor?)
void UTFT::bitblt(FILE*f, int wordsperline) {
if (clipX() && clipY()) {
int x=XC;
int y=YC;
if (x||y) {
if (orient&8) SWAP(x,y);
myseek(f,y*wordsperline+x<<1); // correct source pointer
}
x=W;
y=H;
if (orient&8) SWAP(x,y);
wordsperline-=x; // now: skip words at end (should be >=0!)
wordsperline<<=1; // now: skip bytes at end
bool skip=false;
DISP_CS(0);
setWindow(0xF0|orient>>3&7); // make clipped window current
do{ // iterate over source's y (lines)
int xx=x;
do{ // iterate over source's x (pixels)
word w=mygetw(f); // cannot handle EOF here
if (flags&TRANS) {
if (w==bc) skip=true;
else{
if (skip) advance(xx,y); // set new address _only_ at non-contiguous pixels (for more speed)
skip=false;
goto w;
}
}else w: writeW(w); // set pixel (always)
}while(--xx);
if (wordsperline) myseek(f,wordsperline); // next line
}while(--y);
unsetWindow();
DISP_CS(1);
}//else drawCircle(120,120,80);
advance();
}
void UTFT::bitblt(const word*w, int wordsperline) {
FILE f;
fdev_setup_stream(&f,0,0,_FDEV_SETUP_READ|__SSTR|__SPGM);
f.len=(int)w;
bitblt(&f,wordsperline);
}
/*********************************
* Hardware-independent graphics *
*********************************/
/*==== clipping ====*/
void UTFT::setClip(int l, int t, int r, int b) {
if (flags&MOVE) {
l+=XO; t+=YO; r+=XO; b+=YO;
flags&=~MOVE;
}
if (l<0) l=0;
if (t<0) t=0;
int e=getDisplayXSize()-1;
if (r>e) r=e;
e=getDisplayYSize()-1;
if (b>e) b=e;
clip.L=l; clip.T=t; clip.R=r; clip.B=b;
}
bool UTFT::clipX() {
int o=clip.L-L;
XC=0;
if (o>0) {L=clip.L; XC=o;}
if (R>clip.R) R=clip.R;
return (W=R-L+1)>0; // new width, return true when not empty
}
bool UTFT::clipOk() const{ // checks point inside clipping area
return clip.L<=X && X<=clip.R && clip.T<=Y && Y<=clip.B;
}
/*==== position calculation ====*/
void UTFT::setOrg(int x, int y) {
if (flags&MOVE) {
XO+=x; YO+=y;
flags&=~MOVE; // one-time flag!
}else XO=x, YO=y;
}
void UTFT::gotoXY(int x,int y) {
if (flags&MOVE) {
X+=x;
Y+=y;
flags&=~MOVE; // one-time flag!
}else X=x+XO, Y=y+YO;
}
void UTFT::targetXY(int x,int y) {
if (flags&MOVE) {
XE=X+x;
YE=Y+y;
flags&=~MOVE; // one-time flag!
}else XE=x+XO, YE=y+YO;
}
void UTFT::calcRectX() {
int w=XE-X;
R=(w<0?(L=XE)+(W=-w):(L=X)+(W=w))-1; // W never negative
}
// remove a limiting bitblt window; CS must be 0
void UTFT::unsetWindow() {
L=clip.L; T=clip.T; R=clip.R; B=clip.B;
#ifdef DISP_SETXY
setWindow(0xC0);
#endif
}
/*==== points and lines ====*/
void UTFT::drawPixel() {
DISP_CS(0);
setPixel();
DISP_CS(1);
}
void UTFT::lineTo(int x, int y) {
targetXY(x,y);
calcRect(); // calculate W and H
if (!W) {
R=L; B+=flags&ENDPIX; goto fr;
}else if (!H) {
B=T; R+=flags&ENDPIX; fr:
fillRect(); // clip and draw
X=XE;
Y=YE;
}else{
int xs=XE<X?-1:1;
int ys=YE<Y?-1:1;
int err=W-H;
DISP_CS(0);
for(;X!=XE || Y!=YE;) {
setPixel(); // clip and draw using DISPLAY X/Y coordinate
int e2=err<<1;
if (e2+H>0) err-=H, X+=xs;
if (e2<W) err+=W, Y+=ys;
}
if (flags&ENDPIX) setPixel();
DISP_CS(1);
}
}
/*==== outline figures ====*/
void UTFT::drawRect(int x1, int y1, int x2, int y2) {
if (x1>x2) {int t=x1;x1=x2;x2=t;}
if (y1>y2) {int t=y1;y1=x2;y2=t;}
flags&=~MOVE;
drawHLine(x1,y1,x2-x1);
drawHLine(x1,y2,x2-x1);
drawVLine(x1,y1,y2-y1);
drawVLine(x2,y1,y2-y1);
}
void UTFT::drawRoundRect(int x1, int y1, int x2, int y2, int) {
if (x1>x2) {int t=x1;x1=x2;x2=t;}
if (y1>y2) {int t=y1;y1=y2;y2=t;}
if ((x2-x1)>4 && (y2-y1)>4) {
drawPixel(x1+1,y1+1);
drawPixel(x2-1,y1+1);
drawPixel(x1+1,y2-1);
drawPixel(x2-1,y2-1);
drawHLine(x1+2, y1, x2-x1-4);
drawHLine(x1+2, y2, x2-x1-4);
drawVLine(x1, y1+2, y2-y1-4);
drawVLine(x2, y1+2, y2-y1-4);
}
}
void UTFT::drawCircle(int x, int y, int radius) {
int f = 1 - radius;
int ddF_x = 1;
int ddF_y = -2 * radius;
int x1 = 0;
int y1 = radius;
DISP_CS(0);
flags&=~MOVE;
setPixel(x,y+radius);
setPixel(x,y-radius);
setPixel(x+radius,y);
setPixel(x-radius,y);
while(x1 < y1) {
if (f>=0) {
y1--;
ddF_y += 2;
f += ddF_y;
}
x1++;
ddF_x += 2;
f += ddF_x;
setPixel(x+x1,y+y1);
setPixel(x-x1,y+y1);
setPixel(x+x1,y-y1);
setPixel(x-x1,y-y1);
setPixel(x+y1,y+x1);
setPixel(x-y1,y+x1);
setPixel(x+y1,y-x1);
setPixel(x-y1,y-x1);
}
DISP_CS(1);
}
void UTFT::drawPoly(const POINT*p,int n) {
gotoXY(p[n-1].x,p[n-1].y);
for (int i=0; i<n; i++) lineTo(p[i].x,p[i].y);
}
/*==== filled figures ====*/
void UTFT::fillRect() {
if (clipX() && clipY()) {
DISP_CS(0);
setWindow(0xF0); // no specific fill direction
fillW(fc,W,H);
unsetWindow();
DISP_CS(1);
}
}
void UTFT::fillRoundRect(int x1, int y1, int x2, int y2, int) {
if (x1>x2) SWAP(x1,x2);
if (y1>y2) SWAP(y1,y2);
if ((x2-x1)>4 && (y2-y1)>4) {
for (int i=0; i<((y2-y1)/2)+1; i++) {
switch(i) {
case 0:
drawHLine(x1+2, y1+i, x2-x1-4);
drawHLine(x1+2, y2-i, x2-x1-4);
break;
case 1:
drawHLine(x1+1, y1+i, x2-x1-2);
drawHLine(x1+1, y2-i, x2-x1-2);
break;
default:
drawHLine(x1, y1+i, x2-x1);
drawHLine(x1, y2-i, x2-x1);
}
}
}
}
void UTFT::fillCircle(int x, int y, int radius) {
flags&=~MOVE;
for (int y1=-radius; y1<=0; y1++)
for (int x1=-radius; x1<=0; x1++)
if (x1*x1+y1*y1 <= radius*radius) {
drawHLine(x+x1, y+y1, 2*(-x1));
drawHLine(x+x1, y-y1, 2*(-x1));
break;
}
}
void UTFT::fillScr(word color) {
DISP_CS(0);
unsetWindow();
setXY(L,T,orient);
fillW(color,DISP_X_SIZE,DISP_Y_SIZE);
DISP_CS(1);
}
/*==== character output ====*/
const wchar_t*wcschr_P(const wchar_t*p,wchar_t c) {
for(;;p++) {
wchar_t v=pgm_read_word(p);
if (v==c) return p;
if (!v) return 0;
}
}
static wchar_t uni2cp1252(wchar_t c) {
// Generiert die Kodepositionen 0x80..0x9F
static const PROGMEM wchar_t codes[]=
L"€ ‚ƒ„…†‡ˆ‰Š‹Œ Ž "
L" ‘’“”•–—˜™š›œ žŸ";
if (c>128) {
const wchar_t*p=wcschr_P(codes,c);
if (p) c=0x80+p-codes;
}
return c;
}
void UTFT::print(wchar_t c) {
if (flags&COOKED) {
if (c=='\n') {
byte o=orient;
o^=o>>3; // include font rotation and character direction
o^=o>>5&6; // include string escapement
if (o&1) { // rotated screen ^ rotated font
Y=YO;
if (o&2) X-=cfont.cy; else X+=cfont.cy;
}else{
X=XO;
if (o&4) Y-=cfont.cy; else Y+=cfont.cy;
}
return;
}
}
c=uni2cp1252(c);
if (c<cfont.first || c>=cfont.first+cfont.count) c='?';
c-=cfont.first;
int bitsperline=0;
int startbit=0;
char cx=cfont.cx;
char cy=cfont.cy;
const byte*addr=cfont.bits;
if (cx<=0) { // propotional font
char w=0;
if (cx==-16) {
for (wchar_t i=0;i<cfont.count;i++) {
byte n=pgm_read_byte(addr++); // width of this character
if (i==c) {
startbit=bitsperline; // take that snapshot
w=n;
}
bitsperline+=n; // sum all widths
}
}else{
for (wchar_t i=0;;) {
byte b=pgm_read_byte(addr++);
for (byte m=0; m<2; m++) {
byte n=(b&15)-cx; // width of this character
if (i==c) {
startbit=bitsperline; // take that snapshot
w=n;
}
bitsperline+=n; // sum the widths
b>>=4;
if (++i==cfont.count) goto exi;
}
}
}
exi: cx=w;
deb1=w;
deb2=bitsperline;
}else{
bitsperline=cfont.cx+7&~7;
addr+=(byte)c*((byte)bitsperline>>3)*cy;
}
if (orient&8) SWAP(cx,cy); // rotate target character cell (more precisely, flip on main diagonal)
if (orient&16) cx=-cx; // reflect character cell towards left
if (orient&32) cy=-cy; // reflect character cell towards top
targetWH(cx,cy);
calcRect(); // generate character cell
bitblt(addr,bitsperline,startbit);
}
void UTFT::realign(int textlen) {
if (align&0x0F) { // horizontal
if (align&2) textlen>>=1; // zentrieren
if (orient&8) { // TODO: Operationen prüfen/korrigieren
if (orient&0x20) Y+=textlen; else Y-=textlen;
}else{
if (orient&0x10) X+=textlen; else X-=textlen;
}
}
}
void UTFT::print(const char *s) {
realign(align&0x0F?getTextExtent(s):0);
for(;;) {
wchar_t c=take_wchar(s);
if (!c) break;
print(c);
}
}
void UTFT::print(const __FlashStringHelper*s) {
realign(align&0x0F?getTextExtent(s):0);
for(;;) {
wchar_t c=take_wchar(s);
if (!c) break;
print(c);
}
}
int UTFT::getTextExtent(wchar_t c) {
int ext=cfont.cx;
if (ext>0) return ext; // return constant for monospaced font
if (c<cfont.first || c+cfont.first>=cfont.count) c='?';
c-=cfont.first;
if (ext==-16) { // Byte-Angaben
return pgm_read_byte(cfont.bits+c);
}else{ // Nibble-Angaben
byte b=pgm_read_byte(cfont.bits+(c>>1));
if (c&1) b>>=4; // use high nibble
return (b&15)-ext; // "add" the minimum character width
}
}
int UTFT::getTextExtent(const char *s) {
int ext=0;
for(;;) {
wchar_t c=take_wchar(s);
if (!c) break;
ext+=getTextExtent(c);
}
return ext;
}
int UTFT::getTextExtent(const __FlashStringHelper*s) {
int ext=0;
for(;;) {
wchar_t c=take_wchar(s);
if (!c) break;
ext+=getTextExtent(c);
}
return ext;
}
#ifdef DISP_PRINTF
int UTFT::sendByte(char b, FILE*f) {
return reinterpret_cast<UTFT*>(f->get)->print(b),0;
}
void UTFT::vprintf(const char*fmt,va_list args) {
FILE f;
fdev_setup_stream(&f,sendByte,reinterpret_cast<int(*)(FILE*)>(this),_FDEV_SETUP_WRITE);
vfprintf(&f,fmt,args);
}
void UTFT::printf(const char*fmt,...) {
va_list va;
va_start(va,fmt);
vprintf(fmt,va);
va_end(va);
}
void UTFT::vprintf(const __FlashStringHelper*fmt,va_list args) {
FILE f;
fdev_setup_stream(&f,sendByte,reinterpret_cast<int(*)(FILE*)>(this),_FDEV_SETUP_WRITE);
vfprintf_P(&f,reinterpret_cast<const char*>(fmt),args);
}
void UTFT::printf(const __FlashStringHelper*fmt,...) {
va_list va;
va_start(va,fmt);
vprintf(fmt,va);
va_end(va);
}
#endif
void UTFT::setFont(const byte*font) {
cfont.cx=pgm_read_byte(font++);
cfont.cy=pgm_read_byte(font++);
cfont.first=pgm_read_byte(font++);
cfont.count=pgm_read_byte(font++);
cfont.bits=font;
}
Vorgefundene Kodierung: UTF-8 | 0
|