diff options
author | mrwastl <mrwastl@users.sourceforge.net> | 2011-05-01 22:22:32 +0200 |
---|---|---|
committer | mrwastl <mrwastl@users.sourceforge.net> | 2011-05-01 22:22:32 +0200 |
commit | 46e597df44402086edd010b69702c2de52b75fc8 (patch) | |
tree | fa9528f19f951b765b071c239b09547cf69bd169 | |
parent | 57729cf285b058d192a60bd7fce1b2d29bdd9650 (diff) | |
download | graphlcd-base-46e597df44402086edd010b69702c2de52b75fc8.tar.gz graphlcd-base-46e597df44402086edd010b69702c2de52b75fc8.tar.bz2 |
initial upload to branch 'touchcol'. see file 'HISTORY' for changes
50 files changed, 2011 insertions, 616 deletions
@@ -1,6 +1,57 @@ GraphLCD base package Revision History -------------------------------------- +2011-05-01: branch touchcol, first commit +- glcddrivers changes / enhancements: + - support for colour bitmap data + - support for colours either by using pre-defined colour names or 0xRRGGBB / 0xAARRGGBB (though no alpha channel is supported yet) + - adapted/added methods SetScreen(), SetPixel()-methods in base-class and driver-classes for new colour enabled bitmap data + - added support for events (supported for now: simple touch events) + - added support for requesting and setting driver features + - added GetBackgroundColor(), GetForegroundColor() -> gets default back/foreground colour + - fixed compiler warnings (missing parameters in printf(), ...) + - dm140glnk: bugfix: changed type for vendor and product to 'signed' + - serdisp: + - added support for touch events + - cut support for serdisplib version < 1.95 (-> simplifies code) + - added basic support for GPIs (eg. enable/disable touchpad) + - rotate only when graphlcd-setup says so + - UTF8 should work fine but is not tested very well yet + - vdr 1.3.x should be supported as well but support for it is deprecated and will be removed (-> cleaner code) +- glcdskin changes / enhancements: + - improved update policies (update only display regions that require update) - w/o this displays like l4m320t would be unusable w/ graphlcd. + - new objects / attributes / features for skins: + - increased skin version to 1.1, version info is now verified before loading a skin + - objects can now trigger actions (eg. when touching an object it may trigger a VDR 'Key'-event) + - 'scrolltext' is deprecated and is now an aliases for 'text' + - new object 'button' + - new attribute 'valign': vertical alignment + - attribute 'bgcolor': sets background colour for object (whereas 'color' sets foreground colour) + - new attributes 'alttext' and 'altcondition' for object 'text' (if 'altcondition' is true, 'alttext' is evaluated and used) + - scrolling/looping attributes for 'text': 'loop', 'scrollmode', 'scrollspeed', 'scrolltime' + - new attribute 'default' for variables: + shortcut for <variable id="name" value="value1" condition="somecondition"/> <variable id="name" value="value2"/>: + <variable id="name" value="value1" condition="somecondition" default="value2"/> + this will actually be stored in two variable entries (exactly as in the first version) + - new entity 'condblock': combines variables that use the same condition + <variable id="id1" condition="condition1" value="val1"/> + <variable id="id1" value="valdefault1"/> + <variable id="id2" condition="condition1" value="val2"/> + <variable id="id2" value="valdefault2"/> + can now be simplified to + <condblock condition="condition1"> + <variable id="id1" value="val1" default="valdefault1"/> + <variable id="id2" value="val2" default="valdefault2"/> + </condblock> + attention: variable-definitions in a condblock must not contain condition-attributes. + - XML parser: + - parser method XmlParse() optionally may pass an error string + - text-objects may now contain combinations of tokens, constants, and variables + - evaluation of variables in text-objects is now delayed from parsing time to runtime + - attention: 'condblock' and attributes 'alttext', 'altcondition' are case studies for now and may be removed +- all changes/modifications/improvements that i've missed in this list + + 2010-04-23: version 0.1.6_1 - added additional wiring for GU256x64-372 driver (thanks to mentox, http://www.vdr-portal.de/board/thread.php?postid=895721#post895721) @@ -0,0 +1,18 @@ +TODO: +- add missing objects like textbox, scrollbar +- add special objects for external data so that other plugins can draw text and bitmaps on an area of the display that will be defined in the skin. This could be used p.e. for a spectrum analyzer or displaying id3 tags. +- add service interface for external data objects +- DOCUMENTATION, DOCUMENTATION, DOCUMENTATION +- fix all the small bugs that were introduced +- all the stuff I forgot :-) + +- all tools (convpic, ...) are probably not functional yet +- support for loading colour BMPs and other formats + + +DONE/SOLVED/PARTIALLY SOLVED: +- add dynamic behaviour to objects like scrolling and blinking (done, but w/o blinking) +- make skin variables more dynamic, p.e. evaluate positions while displaying, not only during skin loading. This should make it easier to support several display sizes with one skin (done for text-objects, but not for attributes) + + +this TODO is initially based on the plans of andreas regel. diff --git a/glcddrivers/dm140gink.c b/glcddrivers/dm140gink.c index c7efdba..87e29c2 100644 --- a/glcddrivers/dm140gink.c +++ b/glcddrivers/dm140gink.c @@ -92,7 +92,7 @@ int cDriverDM140GINK::SendReport(const char *cbuf, size_t size) //************************************************************** if((err = ioctl(fd, HIDIOCSUSAGE, &uref)) < 0) { - syslog(LOG_INFO, "%s: Error with sending the USAGE ioctl %d,0x%02X;size:%d\n", config->name.c_str(), i, (int)buf[i],size); + syslog(LOG_INFO, "%s: Error with sending the USAGE ioctl %d,0x%02X;size:%d\n", config->name.c_str(), (int)i, (int)buf[i], (int)size); return err; } uref.usage_code = 0xffa10006; //unused? @@ -130,8 +130,8 @@ int cDriverDM140GINK::Init() if (height <= 0) height = 16; - vendor = 0x040b; - product = 0x7001; + signed short vendor = 0x040b; + signed short product = 0x7001; for (unsigned int i = 0; i < config->options.size(); i++) { @@ -254,7 +254,7 @@ int cDriverDM140GINK::CheckSetup() return 0; } -void cDriverDM140GINK::SetPixel(int x, int y) +void cDriverDM140GINK::SetPixel(int x, int y, uint32_t data) { if (x >= width || y >= height) return; @@ -282,7 +282,7 @@ void cDriverDM140GINK::Set8Pixels(int x, int y, unsigned char data) for (int n = 0; n < 8; ++n) { if (data & (0x80 >> n)) // if bit is set - SetPixel(x + n, y); + SetPixel(x + n, y, GLCD::cColor::White); } } diff --git a/glcddrivers/dm140gink.h b/glcddrivers/dm140gink.h index 526263a..8686ad9 100644 --- a/glcddrivers/dm140gink.h +++ b/glcddrivers/dm140gink.h @@ -38,7 +38,7 @@ private: int SendReport(const char *buf, size_t size); int CheckSetup(); - void SetPixel(int x, int y); + void SetPixel(int x, int y, uint32_t data); public: cDriverDM140GINK(cDriverConfig * config); diff --git a/glcddrivers/driver.c b/glcddrivers/driver.c index b1b6286..056f8bc 100644 --- a/glcddrivers/driver.c +++ b/glcddrivers/driver.c @@ -9,7 +9,8 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net> */ #include "common.h" @@ -19,13 +20,18 @@ namespace GLCD { +cSimpleTouchEvent::cSimpleTouchEvent() : x(0), y(0), touch(0) +{ +} + cDriver::cDriver() : width(0), height(0) { } -void cDriver::SetScreen(const unsigned char * data, int wid, int hgt, int lineSize) +//void cDriver::SetScreen(const unsigned char * data, int wid, int hgt, int lineSize) +void cDriver::SetScreen(const uint32_t * data, int wid, int hgt) { int x, y; @@ -34,11 +40,19 @@ void cDriver::SetScreen(const unsigned char * data, int wid, int hgt, int lineSi if (hgt > height) hgt = height; - Clear(); + //Clear(); if (data) { for (y = 0; y < hgt; y++) { + for (x = 0; x < wid; x++) + { +// printf("%s:%s(%d) - %03d * %03d (linesize %02d), %08x\n", __FILE__, __FUNCTION__, __LINE__, x, y, lineSize, data[y * lineSize + x]); + SetPixel(x, y, data[y * wid + x]); + } + } + } +/* for (x = 0; x < (wid / 8); x++) { Set8Pixels(x * 8, y, data[y * lineSize + x]); @@ -48,7 +62,7 @@ void cDriver::SetScreen(const unsigned char * data, int wid, int hgt, int lineSi Set8Pixels((wid / 8) * 8, y, data[y * lineSize + wid / 8] & bitmaskl[wid % 8 - 1]); } } - } +*/ } } // end of namespace diff --git a/glcddrivers/driver.h b/glcddrivers/driver.h index 1d82eaa..babb71a 100644 --- a/glcddrivers/driver.h +++ b/glcddrivers/driver.h @@ -9,22 +9,43 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net> */ #ifndef _GLCDDRIVERS_DRIVER_H_ #define _GLCDDRIVERS_DRIVER_H_ #include <stdint.h> +#include "../glcdgraphics/bitmap.h" + +// for strcasecmp +#include <strings.h> namespace GLCD { +class cGLCDEvent { +public: + virtual ~cGLCDEvent() {} +}; + +class cSimpleTouchEvent : public cGLCDEvent { +public: + int x; + int y; + int touch; + cSimpleTouchEvent(); +}; + + class cDriver { protected: int width; int height; + + virtual bool GetDriverFeature (const std::string & Feature, int & value) { return false; } public: cDriver(); virtual ~cDriver() {} @@ -36,11 +57,55 @@ public: virtual int DeInit() { return 0; } virtual void Clear() {} + virtual void SetPixel(int x, int y, uint32_t data) {} virtual void Set8Pixels(int x, int y, unsigned char data) {} - virtual void SetScreen(const unsigned char * data, int width, int height, int lineSize); +// virtual void SetScreen(const unsigned char * data, int width, int height, int lineSize); + virtual void SetScreen(const uint32_t *data, int width, int height); virtual void Refresh(bool refreshAll = false) {} virtual void SetBrightness(unsigned int percent) {} + + virtual GLCD::cColor GetBackgroundColor(void) { return GLCD::cColor(GLCD::cColor::White); } + + virtual bool SetFeature (const std::string & Feature, int value) { return false; } + + GLCD::cColor GetForegroundColor(void) { + return GLCD::cColor(GetBackgroundColor()).Invert(); + } + + // not to be overridden, override GetDriverFeature() instead + // the following feature names (case insensitive!) are guaranteed to give results: + // 'depth' colour depth, default: 1 + // 'ismonochrome' is lcd a monochrome display?, default: true (1) + // the following feature names are pre-defined but default to false (0) + // 'isgreyscale', 'isgrayscale' is lcd a greyscale display? + // 'iscolour', 'iscolor' is lcd a colour display? + // 'touch', 'touchscreen' is a touchscreen supported and available? + bool GetFeature (const std::string & Feature, int & value) { + if (GetDriverFeature(Feature, value)) { + return true; + } else if (strcasecmp(Feature.c_str(), "depth") == 0) { + value = 1; + return true; + } else if (strcasecmp(Feature.c_str(), "ismonochrome") == 0) { + value = 1; // true == 1, false == 0 + return true; + } else if (strcasecmp(Feature.c_str(), "isgreyscale") == 0 || strcasecmp(Feature.c_str(), "isgrayscale") == 0) { + value = 0; // true == 1, false == 0 + return true; + } else if (strcasecmp(Feature.c_str(), "iscolour") == 0 || strcasecmp(Feature.c_str(), "iscolor") == 0) { + value = 0; // true == 1, false == 0 + return true; + } else if (strcasecmp(Feature.c_str(), "touch") == 0 || strcasecmp(Feature.c_str(), "touchscreen") == 0) { + value = 0; // true == 1, false == 0 + return true; + } + value = 0; + return false; + } + + virtual cGLCDEvent * GetEvent(void) { return NULL; } + }; } // end of namespace diff --git a/glcddrivers/framebuffer.c b/glcddrivers/framebuffer.c index ef96cde..10ed9fd 100644 --- a/glcddrivers/framebuffer.c +++ b/glcddrivers/framebuffer.c @@ -150,7 +150,7 @@ int cDriverFramebuffer::CheckSetup() return 0; } -void cDriverFramebuffer::SetPixel(int x, int y) +void cDriverFramebuffer::SetPixel(int x, int y, uint32_t data) { int location; int outcol; @@ -239,7 +239,7 @@ void cDriverFramebuffer::Set8Pixels(int x, int y, unsigned char data) for (n = 0; n < 8; ++n) { if (data & (0x80 >> n)) // if bit is set - SetPixel(x + n, y); + SetPixel(x + n, y, GLCD::cColor::White); } } diff --git a/glcddrivers/framebuffer.h b/glcddrivers/framebuffer.h index 79d1d77..12e307c 100644 --- a/glcddrivers/framebuffer.h +++ b/glcddrivers/framebuffer.h @@ -37,7 +37,7 @@ private: int zoom; int CheckSetup(); - void SetPixel(int x, int y); + void SetPixel(int x, int y, uint32_t data); public: cDriverFramebuffer(cDriverConfig * config); diff --git a/glcddrivers/g15daemon.c b/glcddrivers/g15daemon.c index 91f08c9..28c5569 100644 --- a/glcddrivers/g15daemon.c +++ b/glcddrivers/g15daemon.c @@ -33,7 +33,7 @@ #define G15_HEIGHT 43 -static int g15_send(int sock, char *buf, int len) +static int g15_send(int sock, const char *buf, int len) { int total = 0; int retval = 0; @@ -180,7 +180,7 @@ int cDriverG15daemon::CheckSetup() return 0; } -void cDriverG15daemon::SetPixel(int x, int y) +void cDriverG15daemon::SetPixel(int x, int y, uint32_t data) { if (x >= width || y >= height) return; @@ -208,7 +208,7 @@ void cDriverG15daemon::Set8Pixels(int x, int y, unsigned char data) for (n = 0; n < 8; ++n) { if (data & (0x80 >> n)) // if bit is set - SetPixel(x + n, y); + SetPixel(x + n, y, GLCD::cColor::White); } } diff --git a/glcddrivers/g15daemon.h b/glcddrivers/g15daemon.h index c91ef17..33e3381 100644 --- a/glcddrivers/g15daemon.h +++ b/glcddrivers/g15daemon.h @@ -30,7 +30,7 @@ private: int zoom; int CheckSetup(); - void SetPixel(int x, int y); + void SetPixel(int x, int y, uint32_t data); public: cDriverG15daemon(cDriverConfig * config); diff --git a/glcddrivers/gu126x64D-K610A4.c b/glcddrivers/gu126x64D-K610A4.c index 711e672..049b79f 100644 --- a/glcddrivers/gu126x64D-K610A4.c +++ b/glcddrivers/gu126x64D-K610A4.c @@ -417,7 +417,7 @@ int cDriverGU126X64D_K610A4::write(unsigned char data) } // cDriverGU126X64D_K610A4::write() //----------------------------------------------------------------------------- -void cDriverGU126X64D_K610A4::setPixel(int x, int y) +void cDriverGU126X64D_K610A4::setPixel(int x, int y, uint32_t data) { if (!myDrawMem ) return; if (x >= width || x < 0) return; @@ -444,7 +444,7 @@ void cDriverGU126X64D_K610A4::Set8Pixels(int x, int y, unsigned char data) { if ((data & (0x80 >> n)) != 0) // if bit is set { - setPixel(x + n, y); + setPixel(x + n, y, GLCD::cColor::White); } // if } // for } // cDriverGU126X64D_K610A4::Set8Pixels() @@ -796,7 +796,7 @@ int cDriverGU126X64D_K610A4::cmdWriteText(const char *theText) if (isLogEnabled(LL_VFD_CMD)) { - syslog(LOG_INFO, "-%2dB: WRITE_TEXT : '%s'", strlen(theText), theText); + syslog(LOG_INFO, "-%2dB: WRITE_TEXT : '%s'", (int)strlen(theText), theText); } // if for (const char *p = theText; *p != '\0'; ++p) diff --git a/glcddrivers/gu126x64D-K610A4.h b/glcddrivers/gu126x64D-K610A4.h index 3d6c29c..439da94 100644 --- a/glcddrivers/gu126x64D-K610A4.h +++ b/glcddrivers/gu126x64D-K610A4.h @@ -68,7 +68,7 @@ public: , FONT_FIX_BIG }; - void setPixel (int x, int y); + void setPixel (int x, int y, uint32_t data); int cmdReset (); int cmdPower (bool fOn); diff --git a/glcddrivers/gu140x32f.c b/glcddrivers/gu140x32f.c index c3990a3..865d133 100644 --- a/glcddrivers/gu140x32f.c +++ b/glcddrivers/gu140x32f.c @@ -326,7 +326,7 @@ void cDriverGU140X32F::Write(unsigned char nFlags, unsigned char bData, unsigned nSleepDeInit(); } -void cDriverGU140X32F::SetPixel(int x, int y) +void cDriverGU140X32F::SetPixel(int x, int y, uint32_t data) { unsigned char c; int n; @@ -361,7 +361,7 @@ void cDriverGU140X32F::Set8Pixels(int x, int y, unsigned char data) for (n = 0; n < 8; ++n) { if (data & (0x80 >> n)) // if bit is set - SetPixel(x + n, y); + SetPixel(x + n, y, GLCD::cColor::White); } } diff --git a/glcddrivers/gu140x32f.h b/glcddrivers/gu140x32f.h index c0b87f2..4e0d1e8 100644 --- a/glcddrivers/gu140x32f.h +++ b/glcddrivers/gu140x32f.h @@ -51,7 +51,7 @@ class cDriverGU140X32F : public cDriver protected: void ClearVFDMem(); - void SetPixel(int x, int y); + void SetPixel(int x, int y, uint32_t data); void Write(unsigned char nFlags, unsigned char bData, unsigned int nMicroSecBusyTime); public: diff --git a/glcddrivers/gu256x64-372.c b/glcddrivers/gu256x64-372.c index 57ec981..41f5881 100644 --- a/glcddrivers/gu256x64-372.c +++ b/glcddrivers/gu256x64-372.c @@ -131,7 +131,7 @@ int cDriverGU256X64_372::Init() RDLO = kStandardRDLO; CDHI = kStandardCDHI; CDLO = kStandardCDLO; - syslog(LOG_DEBUG, "%s: using standard wiring\n"); + syslog(LOG_DEBUG, "%s: using standard wiring\n", config->name.c_str()); } else if (config->options[i].value == kWiringWindows) { @@ -141,7 +141,7 @@ int cDriverGU256X64_372::Init() RDLO = kWindowsRDLO; CDHI = kWindowsCDHI; CDLO = kWindowsCDLO; - syslog(LOG_DEBUG, "%s: using windows wiring\n"); + syslog(LOG_DEBUG, "%s: using windows wiring\n", config->name.c_str()); } else { @@ -345,7 +345,7 @@ void cDriverGU256X64_372::GU256X64Data(unsigned char data) nSleep(100 + (100 * config->adjustTiming) - m_nTimingAdjustCmd); } -void cDriverGU256X64_372::SetPixel(int x, int y) +void cDriverGU256X64_372::SetPixel(int x, int y, uint32_t data) { unsigned char c; @@ -378,7 +378,7 @@ void cDriverGU256X64_372::Set8Pixels(int x, int y, unsigned char data) for (n = 0; n < 8; ++n) { if (data & (0x80 >> n)) // if bit is set - SetPixel(x + n, y); + SetPixel(x + n, y, GLCD::cColor::White); } } diff --git a/glcddrivers/gu256x64-372.h b/glcddrivers/gu256x64-372.h index 7d92561..db63bcb 100644 --- a/glcddrivers/gu256x64-372.h +++ b/glcddrivers/gu256x64-372.h @@ -57,7 +57,7 @@ class cDriverGU256X64_372 : public cDriver protected: void ClearVFDMem(); - void SetPixel(int x, int y); + void SetPixel(int x, int y, uint32_t data); void GU256X64Cmd(unsigned char data); void GU256X64Data(unsigned char data); diff --git a/glcddrivers/gu256x64-3900.c b/glcddrivers/gu256x64-3900.c index d9279dc..938c01f 100644 --- a/glcddrivers/gu256x64-3900.c +++ b/glcddrivers/gu256x64-3900.c @@ -503,7 +503,7 @@ void cDriverGU256X64_3900::Write(unsigned char data) WriteParallel(data); } -void cDriverGU256X64_3900::SetPixel(int x, int y) +void cDriverGU256X64_3900::SetPixel(int x, int y, uint32_t data) { unsigned char c; @@ -536,7 +536,7 @@ void cDriverGU256X64_3900::Set8Pixels(int x, int y, unsigned char data) for (n = 0; n < 8; ++n) { if (data & (0x80 >> n)) // if bit is set - SetPixel(x + n, y); + SetPixel(x + n, y, GLCD::cColor::White); } } diff --git a/glcddrivers/gu256x64-3900.h b/glcddrivers/gu256x64-3900.h index 2201417..163bcef 100644 --- a/glcddrivers/gu256x64-3900.h +++ b/glcddrivers/gu256x64-3900.h @@ -59,7 +59,7 @@ class cDriverGU256X64_3900 : public cDriver protected: void ClearVFDMem(); - void SetPixel(int x, int y); + void SetPixel(int x, int y, uint32_t data); int InitSerialPort(); int InitParallelPort(); void InitNormalDisplay(); diff --git a/glcddrivers/image.c b/glcddrivers/image.c index 9c71006..94623c4 100644 --- a/glcddrivers/image.c +++ b/glcddrivers/image.c @@ -7,7 +7,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net> + Andreas 'randy' Weinberger */ #include <stdio.h> @@ -50,12 +52,13 @@ int cDriverImage::Init() } } - newLCD = new unsigned char[lineSize * height]; +// newLCD = new unsigned char[lineSize * height]; + newLCD = new uint32_t[width * height]; if (newLCD) - memset(newLCD, 0, lineSize * height); - oldLCD = new unsigned char[lineSize * height]; + memset(newLCD, 0, width * height); + oldLCD = new uint32_t[width * height]; if (oldLCD) - memset(oldLCD, 0, lineSize * height); + memset(oldLCD, 0, width * height); counter = 0; @@ -121,6 +124,29 @@ void cDriverImage::Set8Pixels(int x, int y, unsigned char data) } } +void cDriverImage::SetPixel(int x, int y, uint32_t data) +{ + if (x >= width || y >= height) + return; + + if ((data | 0xFF000000) != cColor::Black) { + data = cColor::White; + } + + if (!config->upsideDown) + { + // normal orientation + newLCD[y * x] |= data; + } + else + { + // upside down orientation + x = width - 1 - x; + y = height - 1 - y; + newLCD[y * x] |= ReverseBits(data); + } +} + void cDriverImage::Refresh(bool refreshAll) { int i; diff --git a/glcddrivers/image.h b/glcddrivers/image.h index 3e39e3f..75a2f33 100644 --- a/glcddrivers/image.h +++ b/glcddrivers/image.h @@ -7,7 +7,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net> + Andreas 'randy' Weinberger */ #ifndef _GLCDDRIVERS_IMAGE_H_ @@ -24,8 +26,8 @@ class cDriverConfig; class cDriverImage : public cDriver { private: - unsigned char * newLCD; - unsigned char * oldLCD; + uint32_t * newLCD; + uint32_t * oldLCD; cDriverConfig * config; cDriverConfig * oldConfig; int lineSize; @@ -41,6 +43,7 @@ public: virtual int DeInit(); virtual void Clear(); + virtual void SetPixel(int x, int y, uint32_t data); virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); }; diff --git a/glcddrivers/noritake800.c b/glcddrivers/noritake800.c index 5a386a5..971bf5e 100644 --- a/glcddrivers/noritake800.c +++ b/glcddrivers/noritake800.c @@ -404,7 +404,7 @@ void cDriverNoritake800::N800Data(unsigned char data) m_pport->WriteControl(LPT_CTL_HI_DIR | m_pWiringMaskCache[0x00]); } -void cDriverNoritake800::SetPixel(int x, int y) +void cDriverNoritake800::SetPixel(int x, int y, uint32_t data) { unsigned char c; @@ -437,7 +437,7 @@ void cDriverNoritake800::Set8Pixels(int x, int y, unsigned char data) for (n = 0; n < 8; ++n) { if (data & (0x80 >> n)) // if bit is set - SetPixel(x + n, y); + SetPixel(x + n, y, GLCD::cColor::White); } } diff --git a/glcddrivers/noritake800.h b/glcddrivers/noritake800.h index cb2dfb0..e275afe 100644 --- a/glcddrivers/noritake800.h +++ b/glcddrivers/noritake800.h @@ -80,7 +80,7 @@ public: virtual int DeInit(); virtual void Clear(); - virtual void SetPixel(int x, int y); + virtual void SetPixel(int x, int y, uint32_t data); virtual void Set8Pixels(int x, int y, unsigned char data); virtual void Refresh(bool refreshAll = false); diff --git a/glcddrivers/serdisp.c b/glcddrivers/serdisp.c index 7521105..5676bb3 100644 --- a/glcddrivers/serdisp.c +++ b/glcddrivers/serdisp.c @@ -7,7 +7,7 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2003-2010 Wolfgang Astleitner <mrwastl AT users.sourceforge.net> + * (c) 2003-2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net> */ #include <stdio.h> @@ -19,6 +19,9 @@ #include "config.h" #include "serdisp.h" +// for memcpy +#include <string.h> + #define SERDISP_VERSION(a,b) ((long)(((a) << 8) + (b))) #define SERDISP_VERSION_GET_MAJOR(_c) ((int)( (_c) >> 8 )) #define SERDISP_VERSION_GET_MINOR(_c) ((int)( (_c) & 0xFF )) @@ -32,15 +35,25 @@ #define SD_COL_BLACK 0xFF000000 #define SD_COL_WHITE 0xFFFFFFFF +// taken from serdisp_gpevents.h +#define SDGPT_SIMPLETOUCH 0x10 /* simple touch screen event, type: SDGP_evpkt_simpletouch_t */ + namespace GLCD { +static void wrapEventListener(void* dd, SDGP_event_t* recylce); + +static int simpleTouchX=0, simpleTouchY=0, simpleTouchT=0; +static bool simpleTouchChanged=false; + + cDriverSerDisp::cDriverSerDisp(cDriverConfig * config) : config(config) { oldConfig = new cDriverConfig(*config); dd = (void *) NULL; + simpleTouchChanged = false; } cDriverSerDisp::~cDriverSerDisp(void) @@ -83,95 +96,57 @@ int cDriverSerDisp::Init(void) fp_serdisp_getversioncode = (long int (*)()) dlsym(sdhnd, "serdisp_getversioncode"); if (dlerror()) { // no serdisp_getversioncode() -> version of serdisplib is < 1.95 - syslog(LOG_DEBUG, "%s: INFO: symbol serdisp_getversioncode unknown: autodetecting pre 1.95 serdisplib version (cDriver::Init)\n", - config->name.c_str()); - - fp_SDCONN_open = (void*(*)(const char*)) dlsym(sdhnd, "SDCONN_open"); - if (dlerror()) { // no SDCONN_open() -> version of serdisplib is < 1.93 - serdisp_version = SERDISP_VERSION(1,92); - syslog(LOG_DEBUG, "%s: INFO: detected serdisplib version <= 1.92 (cDriver::Init)\n", config->name.c_str()); - - fp_PP_open = (void*(*)(const char*))dlsym(sdhnd, "PP_open"); - if ( (errmsg = dlerror()) != NULL ) { // should not happen - syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "PP_open", errmsg); - return -1; - } - fp_PP_close = (void*(*)(void*))dlsym(sdhnd, "PP_close"); - if ( (errmsg = dlerror()) != NULL ) { // should not happen - syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "PP_close", errmsg); - return -1; - } - } else { - serdisp_version = SERDISP_VERSION(1,94); // no serdisp_getversioncode, but SDCONN_open: 1.93 or 1.94 - syslog(LOG_DEBUG, "%s: INFO: detected serdisplib version 1.93 or 1.94 (cDriver::Init)\n", config->name.c_str()); - - fp_serdisp_quit = (void (*)(void*)) dlsym(sdhnd, "serdisp_quit"); - if ( (errmsg = dlerror()) != NULL ) { // should not happen - syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "serdisp_quit", errmsg); - return -1; - } - } + syslog(LOG_ERR, "%s: error: serdisplib version >= 1.95 required\n", config->name.c_str()); + return -1; + } - fp_serdisp_setpixcol = (void (*)(void*, int, int, long int)) dlsym(sdhnd, "serdisp_setpixel"); - if ( (errmsg = dlerror()) != NULL ) { // should not happen - syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "serdisp_setpixel", errmsg); - return -1; - } - fg_colour = 1; /* set foreground to 'pixel on' */ + serdisp_version = fp_serdisp_getversioncode(); + syslog(LOG_DEBUG, "%s: INFO: detected serdisplib version %d.%d (cDriver::Init)\n", + config->name.c_str(), SERDISP_VERSION_GET_MAJOR(serdisp_version), SERDISP_VERSION_GET_MINOR(serdisp_version)); - } else { // serdisp version >= 1.95 - serdisp_version = fp_serdisp_getversioncode(); - syslog(LOG_DEBUG, "%s: INFO: detected serdisplib version %d.%d (cDriver::Init)\n", - config->name.c_str(), SERDISP_VERSION_GET_MAJOR(serdisp_version), SERDISP_VERSION_GET_MINOR(serdisp_version)); + fp_SDCONN_open = (void*(*)(const char*)) dlsym(sdhnd, "SDCONN_open"); + if ( (errmsg = dlerror()) != NULL ) { // should not happen + syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", + config->name.c_str(), "SDCONN_open", errmsg); + return -1; + } + fp_serdisp_quit = (void (*)(void*)) dlsym(sdhnd, "serdisp_quit"); + if ( (errmsg = dlerror()) != NULL ) { // should not happen + syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", + config->name.c_str(), "serdisp_quit", errmsg); + return -1; + } + fp_serdisp_setcolour = (void (*)(void*, int, int, long int)) dlsym(sdhnd, "serdisp_setcolour"); + if ( (errmsg = dlerror()) != NULL ) { // should not happen + syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", + config->name.c_str(), "serdisp_setcolour", errmsg); + return -1; + } + fg_colour = SD_COL_BLACK; /* set foreground colour to black */ + + if (serdisp_version >= SERDISP_VERSION(1,96) ) { + supports_options = 1; - fp_SDCONN_open = (void*(*)(const char*)) dlsym(sdhnd, "SDCONN_open"); + fp_serdisp_isoption = (int (*)(void*, const char*)) dlsym(sdhnd, "serdisp_isoption"); if ( (errmsg = dlerror()) != NULL ) { // should not happen syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "SDCONN_open", errmsg); + config->name.c_str(), "serdisp_isoption", errmsg); return -1; } - fp_serdisp_quit = (void (*)(void*)) dlsym(sdhnd, "serdisp_quit"); + fp_serdisp_setoption = (void (*)(void*, const char*, long int)) dlsym(sdhnd, "serdisp_setoption"); if ( (errmsg = dlerror()) != NULL ) { // should not happen syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "serdisp_quit", errmsg); + config->name.c_str(), "serdisp_setoption", errmsg); return -1; } - fp_serdisp_setpixcol = (void (*)(void*, int, int, long int)) dlsym(sdhnd, "serdisp_setcolour"); + fp_serdisp_getoption = (long int (*)(void*, const char*, int*)) dlsym(sdhnd, "serdisp_getoption"); if ( (errmsg = dlerror()) != NULL ) { // should not happen syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "serdisp_setcolour", errmsg); + config->name.c_str(), "serdisp_getoption", errmsg); return -1; } - fg_colour = SD_COL_BLACK; /* set foreground colour to black */ - - if (serdisp_version >= SERDISP_VERSION(1,96) ) { - supports_options = 1; - - fp_serdisp_isoption = (int (*)(void*, const char*)) dlsym(sdhnd, "serdisp_isoption"); - if ( (errmsg = dlerror()) != NULL ) { // should not happen - syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "serdisp_isoption", errmsg); - return -1; - } - fp_serdisp_setoption = (void (*)(void*, const char*, long int)) dlsym(sdhnd, "serdisp_setoption"); - if ( (errmsg = dlerror()) != NULL ) { // should not happen - syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "serdisp_setoption", errmsg); - return -1; - } - fp_serdisp_getoption = (long int (*)(void*, const char*, int*)) dlsym(sdhnd, "serdisp_getoption"); - if ( (errmsg = dlerror()) != NULL ) { // should not happen - syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", - config->name.c_str(), "serdisp_getoption", errmsg); - return -1; - } - } /* >= 1.96 */ - } + } /* >= 1.96 */ // load other symbols that will be required fp_serdisp_init = (void*(*)(void*, const char*, const char*)) dlsym(sdhnd, "serdisp_init"); @@ -230,6 +205,22 @@ int cDriverSerDisp::Init(void) return -1; } + fp_serdisp_getcolours = (int (*)(void*)) dlsym(sdhnd, "serdisp_getcolours"); + if ( (errmsg = dlerror()) != NULL ) { // should not happen + syslog(LOG_ERR, "%s: error: cannot load symbol %s. Err:%s (cDriver::Init)\n", + config->name.c_str(), "serdisp_getcolours", errmsg); + return -1; + } + + // don't care if the following functions are not available + fp_serdisp_getdepth = (int (*)(void*)) dlsym(sdhnd, "serdisp_getdepth"); + + fp_SDGPI_search = (uint8_t (*)(void*, const char*)) dlsym(sdhnd, "SDGPI_search"); + fp_SDGPI_isenabled = (int (*)(void*, uint8_t)) dlsym(sdhnd, "SDGPI_isenabled"); + fp_SDGPI_enable = (int (*)(void*, uint8_t, int)) dlsym(sdhnd, "SDGPI_enable"); + fp_SDEVLP_add_listener = (int (*)(void*, uint8_t, fp_eventlistener_t)) dlsym(sdhnd, "SDEVLP_add_listener"); + + // done loading all required symbols // setting up the display @@ -341,7 +332,8 @@ int cDriverSerDisp::Init(void) fp_serdisp_feature(dd, FEATURE_REVERSE, config->invert); } else { /* standard options */ - fp_serdisp_setoption(dd, "ROTATE", config->upsideDown); + if (config->upsideDown) + fp_serdisp_setoption(dd, "ROTATE", config->upsideDown); fp_serdisp_setoption(dd, "CONTRAST", config->contrast); fp_serdisp_setoption(dd, "BACKLIGHT", config->backlight); fp_serdisp_setoption(dd, "INVERT", config->invert); @@ -433,6 +425,7 @@ int cDriverSerDisp::CheckSetup() update = true; } +#if 0 /* driver dependend options */ if ( supports_options ) { for (unsigned int i = 0; i < config->options.size(); i++) { @@ -447,7 +440,7 @@ int cDriverSerDisp::CheckSetup() } } } - +#endif if (update) return 1; @@ -462,7 +455,7 @@ void cDriverSerDisp::Clear(void) int x,y; for (y = 0; y < fp_serdisp_getheight(dd); y++) for (x = 0; x < fp_serdisp_getwidth(dd); x++) - fp_serdisp_setpixcol(dd, x, y, bg_colour); /* >= 1.95: serdisp_setcolour(), < 1.95: serdisp_setpixel() */ + fp_serdisp_setcolour(dd, x, y, bg_colour); } } @@ -475,13 +468,50 @@ void cDriverSerDisp::Set8Pixels(int x, int y, unsigned char data) { for (i = 0; i < 8; i++) { pixel = data & (1 << i); - if (pixel) - fp_serdisp_setpixcol(dd, start + i, y, fg_colour); /* >= 1.95: serdisp_setcolour(), < 1.95: serdisp_setpixel() */ - else if (!pixel && bg_colour != -1) /* if bg_colour is set: use it if pixel is not set */ - fp_serdisp_setpixcol(dd, start + i, y, bg_colour); /* >= 1.95: serdisp_setcolour(), < 1.95: serdisp_setpixel() */ + if (pixel) { + SetPixel(start + i, y, fg_colour); + } else if (!pixel && bg_colour != -1) { /* if bg_colour is set: use it if pixel is not set */ + SetPixel(start + i, y, bg_colour); + } } } +void cDriverSerDisp::SetPixel(int x, int y, uint32_t data) +{ + fp_serdisp_setcolour(dd, x, y, data); +} + +#if 0 +// temporarily overwrite SetScreen() until problem with 'to Clear() or not to Clear()' is solved +void cDriverSerDisp::SetScreen(const unsigned char * data, int wid, int hgt, int lineSize) +{ + int x, y; + + if (wid > width) + wid = width; + if (hgt > height) + hgt = height; + + //Clear(); + if (data) + { + for (y = 0; y < hgt; y++) + { + for (x = 0; x < (wid / 8); x++) + { + Set8Pixels(x * 8, y, data[y * lineSize + x]); + } + if (width % 8) + { + Set8Pixels((wid / 8) * 8, y, data[y * lineSize + wid / 8] & bitmaskl[wid % 8 - 1]); + } + } + } else { + Clear(); + } +} +#endif + void cDriverSerDisp::Refresh(bool refreshAll) { if (CheckSetup() == 1) @@ -494,9 +524,93 @@ void cDriverSerDisp::Refresh(bool refreshAll) } void cDriverSerDisp::SetBrightness(unsigned int percent) -{ +{ if ( supports_options && (fp_serdisp_isoption(dd, "BRIGHTNESS") == 1) ) /* if == 1: option is existing AND r/w */ - fp_serdisp_setoption(dd, "BRIGHTNESS", (long)percent); + fp_serdisp_setoption(dd, "BRIGHTNESS", (long)percent); +} + +GLCD::cColor cDriverSerDisp::GetBackgroundColor(void) { + if ( supports_options && fp_serdisp_isoption(dd, "SELFEMITTING") && (fp_serdisp_getoption(dd, "SELFEMITTING", 0)) ) { + return GLCD::cColor::Black; + } + return GLCD::cColor::White; +} + + +bool cDriverSerDisp::SetFeature (const std::string & Feature, int value) +{ + if (strcasecmp(Feature.c_str(), "TOUCHSCREEN") == 0 || strcasecmp(Feature.c_str(), "TOUCH") == 0) { + if (fp_SDGPI_search && fp_SDGPI_isenabled && fp_SDGPI_enable) { + uint8_t gpid = fp_SDGPI_search(dd, Feature.c_str()); + if (gpid == 0xFF) + return false; + + int ena = fp_SDGPI_isenabled(dd, gpid); + bool enable = (value == 1) ? true : false; + if (ena == enable) { // already enabled or disabled + return true; + } else { + bool rc = (fp_SDGPI_enable(dd, gpid, ((enable) ? 1 : 0)) >= 0) ? true : false; + + if (enable && rc && fp_SDEVLP_add_listener) { + fp_SDEVLP_add_listener(dd, gpid, wrapEventListener); + } + return true; + } + } + } + return false; +} + +bool cDriverSerDisp::GetDriverFeature (const std::string & Feature, int & value) { + if (dd) { + if (strcasecmp(Feature.c_str(), "depth") == 0) { + value = fp_serdisp_getdepth(dd); + return true; + } else if (strcasecmp(Feature.c_str(), "ismonochrome") == 0) { + value = (fp_serdisp_getdepth(dd) == 1) ? 1 : 0; + return true; + } else if (strcasecmp(Feature.c_str(), "isgreyscale") == 0 || strcasecmp(Feature.c_str(), "isgrayscale") == 0) { + value = (fp_serdisp_getdepth(dd) > 1 && fp_serdisp_getdepth(dd) < 8) ? 1 : 0; + return true; + } else if (strcasecmp(Feature.c_str(), "iscolour") == 0 || strcasecmp(Feature.c_str(), "iscolor") == 0) { + value = (fp_serdisp_getdepth(dd) >= 8) ? 1 : 0; + return true; + } else if (strcasecmp(Feature.c_str(), "touch") == 0 || strcasecmp(Feature.c_str(), "touchscreen") == 0) { + if (fp_SDGPI_search && fp_SDGPI_isenabled) { + uint8_t gpid = fp_SDGPI_search(dd, Feature.c_str()); + value = (gpid != 0xFF && fp_SDGPI_isenabled(dd, gpid)) ? 1 : 0; + } + return true; + } + } + value = 0; + return false; +} + +cGLCDEvent * cDriverSerDisp::GetEvent(void) { + if (GLCD::simpleTouchChanged == false) + return NULL; + + cSimpleTouchEvent * ev = new cSimpleTouchEvent(); + + ev->x = simpleTouchX; + ev->y = simpleTouchY; + ev->touch = simpleTouchT; + simpleTouchChanged = false; + return ev; +} + +static void wrapEventListener(void* dd, SDGP_event_t* event) { + if (!event) return; + if (event->type == SDGPT_SIMPLETOUCH) { + SDGP_evpkt_simpletouch_t simpletouch; + memcpy(&simpletouch, &event->data, sizeof(SDGP_evpkt_simpletouch_t)); + simpleTouchChanged = true; + simpleTouchX = simpletouch.norm_x; + simpleTouchY = simpletouch.norm_y; + simpleTouchT = simpletouch.norm_touch; + } } } // end of namespace diff --git a/glcddrivers/serdisp.h b/glcddrivers/serdisp.h index c84874e..99ca09b 100644 --- a/glcddrivers/serdisp.h +++ b/glcddrivers/serdisp.h @@ -7,18 +7,52 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2003-2010 Wolfgang Astleitner <mrwastl AT users.sourceforge.net> + * (c) 2003-2011 Wolfgang Astleitner <mrwastl AT users.sourceforge.net> */ #ifndef _GLCDDRIVERS_SERDISP_H_ #define _GLCDDRIVERS_SERDISP_H_ #include "driver.h" - +#include <sys/time.h> namespace GLCD { +/* event-type for GPIs, GPOs, and data exchange messages. min. size: 16 byte, max size: 12 + 64) */ +typedef struct SDGP_event_s { /* 16 to 78 bytes */ + /* byte 0 */ + uint8_t type; /* one of SDGPT_* */ + uint8_t cmdid; /* command-ID (one of SD_CMD_*) */ + uint8_t devid; /* device ID, 0 == local */ + uint8_t subid; /* gp-ID or page-ID */ + /* byte 4 */ + struct timeval timestamp; /* timestamp (8 bytes) */ + /* byte 12 */ + union { + int32_t value; /* if single value event: value */ + struct { /* if streaming event or package: */ + uint16_t length; /* length of stream if known or 0 if some stop tag is used */ + uint8_t word_size; /* stream elements are bytes/chars (0 or 1), shorts (2), or longs (4) */ + uint8_t _reserved; /* reserved for later use */ + }; + uint8_t data[64]; /* if data-package type: max. 64 byte payload */ + }; +} SDGP_event_t; + +/* event-payload-type for simple touchscreen events (no multitouch or similar) */ +typedef struct SDGP_evpkt_simpletouch_s { /* 16 bytes */ + /* 12 bytes */ + int16_t raw_x; /* raw coordinate X */ + int16_t raw_y; /* raw coordinate Y */ + int16_t raw_touch; /* raw touch value */ + int16_t norm_x; /* normalised coordinate X (norm_x <= dd->width) */ + int16_t norm_y; /* normalised coordinate Y (norm_y <= dd->height) */ + int16_t norm_touch; /* normalised touch value */ +} SDGP_evpkt_simpletouch_t; + +typedef void (*fp_eventlistener_t) (void* dd, SDGP_event_t* recylce); + class cDriverConfig; class cDriverSerDisp : public cDriver @@ -49,18 +83,29 @@ private: void (*fp_serdisp_rewrite) (void* dd); void (*fp_serdisp_update) (void* dd); void (*fp_serdisp_clearbuffer) (void* dd); - void (*fp_serdisp_setpixcol) (void* dd, int x, int y, long colour); // serdisp_setpixel or serdisp_setcolour + void (*fp_serdisp_setcolour) (void* dd, int x, int y, long colour); int (*fp_serdisp_feature) (void* dd, int feature, int value); int (*fp_serdisp_isoption) (void* dd, const char* optionname); void (*fp_serdisp_setoption) (void* dd, const char* optionname, long value); long (*fp_serdisp_getoption) (void* dd, const char* optionname, int* typesize); int (*fp_serdisp_getwidth) (void* dd); int (*fp_serdisp_getheight) (void* dd); + int (*fp_serdisp_getcolours) (void* dd); + int (*fp_serdisp_getdepth) (void* dd); void (*fp_serdisp_quit) (void* dd); void (*fp_serdisp_close) (void* dd); + uint8_t (*fp_SDGPI_search) (void* dd, const char* gpname); + int (*fp_SDGPI_isenabled) (void* dd, uint8_t gpid); + int (*fp_SDGPI_enable) (void* dd, uint8_t gpid, int enable); + int (*fp_SDEVLP_add_listener) (void* dd, uint8_t gpid, fp_eventlistener_t eventlistener ); int CheckSetup(); + void eventListener (void* dd, SDGP_event_t* recycle); + +protected: + virtual bool GetDriverFeature (const std::string & Feature, int & value); + public: cDriverSerDisp(cDriverConfig * config); @@ -70,11 +115,22 @@ public: virtual int DeInit(); virtual void Clear(); + virtual void SetPixel(int x, int y, uint32_t data); virtual void Set8Pixels(int x, int y, unsigned char data); +#if 0 + virtual void SetScreen(const unsigned char * data, int width, int height, int lineSize); +#endif virtual void Refresh(bool refreshAll = false); virtual void SetBrightness(unsigned int percent); + + virtual GLCD::cColor GetBackgroundColor(void); + + virtual bool SetFeature (const std::string & Feature, int value); + + virtual cGLCDEvent * GetEvent(void); + }; +} // end of namespace #endif -} // end of namespace diff --git a/glcdgraphics/bitmap.c b/glcdgraphics/bitmap.c index d5ba159..c3d617a 100644 --- a/glcdgraphics/bitmap.c +++ b/glcdgraphics/bitmap.c @@ -9,7 +9,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net> + * Andreas 'randy' Weinberger */ #include <stdio.h> @@ -25,21 +27,75 @@ namespace GLCD { + +cColor cColor::ParseColor(std::string col) { + if (col == "black") return cColor(cColor::Black); + else if (col == "white") return cColor(cColor::White); + else if (col == "red") return cColor(cColor::Red); + else if (col == "green") return cColor(cColor::Green); + else if (col == "blue") return cColor(cColor::Blue); + else if (col == "magenta") return cColor(cColor::Magenta); + else if (col == "cyan") return cColor(cColor::Cyan); + else if (col == "yellow") return cColor(cColor::Yellow); + else if (col == "transparent") return cColor(cColor::Transparent); + else if (col.substr(0, 2) == "0x" || col.substr(0, 2) == "0X") { + if (col.length() <= 2 || col.length() > 10) + return cColor(cColor::ERRCOL); + + char* tempptr; + const char* str = col.c_str(); + uint32_t rv = (uint32_t) strtol(str, &tempptr, 16); + + if ((str == tempptr) || (*tempptr != '\0')) + return cColor(cColor::ERRCOL); + + if (col.length() <= 8) // eg. 0xRRGGBB -> 0xFFRRGGBB + rv |= 0xFF000000; + return cColor(rv); + } + return cColor(cColor::ERRCOL); +} + +cColor cColor::Invert(void) +{ + return cColor( (uint32_t)(color ^ 0x00FFFFFF) ) ; +} + + const unsigned char bitmask[8] = {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}; const unsigned char bitmaskl[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; const unsigned char bitmaskr[8] = {0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01}; -cBitmap::cBitmap(int width, int height, unsigned char * data) +cBitmap::cBitmap(int width, int height, uint32_t * data) : width(width), height(height), - bitmap(NULL) + bitmap(NULL), + ismonochrome(false) { - // lines are byte aligned - lineSize = (width + 7) / 8; +#ifdef DEBUG + printf("%s:%s(%d) cBitmap Size %03d * %03d\n", __FILE__, __FUNCTION__, __LINE__, width, height); +#endif - bitmap = new unsigned char[lineSize * height]; - if (data) - memcpy(bitmap, data, lineSize * height); + bitmap = new uint32_t[width * height]; + if (data) { + memcpy(bitmap, data, width * height * sizeof(uint32_t)); + } + backgroundColor = cColor::White; +} + + +cBitmap::cBitmap(int width, int height, uint32_t initcol) +: width(width), + height(height), + bitmap(NULL), + ismonochrome(false) +{ +#ifdef DEBUG + printf("%s:%s(%d) cBitmap Size %03d * %03d\n", __FILE__, __FUNCTION__, __LINE__, width, height); +#endif + + bitmap = new uint32_t[width * height]; + Clear(initcol); } cBitmap::cBitmap(const cBitmap & b) @@ -47,9 +103,12 @@ cBitmap::cBitmap(const cBitmap & b) width = b.width; height = b.height; lineSize = b.lineSize; - bitmap = new unsigned char[lineSize * height]; - if (b.bitmap) - memcpy(bitmap, b.bitmap, lineSize * height); + backgroundColor = b.backgroundColor; + ismonochrome = b.ismonochrome; + bitmap = new uint32_t[b.width * b.height]; + if (b.bitmap) { + memcpy(bitmap, b.bitmap, b.width * b.height * sizeof(uint32_t)); + } } cBitmap::~cBitmap() @@ -57,35 +116,41 @@ cBitmap::~cBitmap() delete[] bitmap; } -void cBitmap::Clear() +void cBitmap::Clear(uint32_t initcol) { - memset(bitmap, 0, lineSize * height); +#ifdef DEBUG + printf("%s:%s(%d) %03d * %03d (color %08x)\n", __FILE__, __FUNCTION__, __LINE__, width, height, color); +#endif + uint32_t col = (initcol == cColor::Transparent) ? backgroundColor : initcol; + for (int i = 0; i < width * height; i++) + bitmap[i] = col; + backgroundColor = col; } void cBitmap::Invert() { int i; - for (i = 0; i < lineSize * height; i++) + for (i = 0; i < width * height; i++) { - bitmap[i] ^= 0xFF; + bitmap[i] ^= 0xFFFFFF; } } -void cBitmap::DrawPixel(int x, int y, eColor color) +void cBitmap::DrawPixel(int x, int y, uint32_t color) { if (x < 0 || x > width - 1) return; if (y < 0 || y > height - 1) return; - unsigned char c = 0x80 >> (x % 8); - if (color == clrBlack) - bitmap[lineSize * y + x / 8] |= c; + if (color != GLCD::cColor::Transparent) + bitmap[x + (width * y)] = cColor::AlignAlpha(color); else - bitmap[lineSize * y + x / 8] &= ~c; + bitmap[x + (width * y)] = cColor::AlignAlpha(backgroundColor); } +/* void cBitmap::Draw8Pixels(int x, int y, unsigned char pixels, eColor color) { if (x < 0 || x > width - 1) @@ -98,12 +163,15 @@ void cBitmap::Draw8Pixels(int x, int y, unsigned char pixels, eColor color) else bitmap[lineSize * y + x / 8] &= ~pixels; } +*/ -void cBitmap::DrawLine(int x1, int y1, int x2, int y2, eColor color) +void cBitmap::DrawLine(int x1, int y1, int x2, int y2, uint32_t color) { int d, sx, sy, dx, dy; unsigned int ax, ay; + color = cColor::AlignAlpha(color); + dx = x2 - x1; ax = abs(dx) << 1; if (dx < 0) @@ -151,43 +219,43 @@ void cBitmap::DrawLine(int x1, int y1, int x2, int y2, eColor color) } } -void cBitmap::DrawHLine(int x1, int y, int x2, eColor color) +void cBitmap::DrawHLine(int x1, int y, int x2, uint32_t color) { - sort(x1,x2); +#ifdef DEBUG + printf("%s:%s(%d) %03d -> %03d, %03d (color %08x)\n", __FILE__, __FUNCTION__, __LINE__, x1, x2, y, color); +#endif + color = cColor::AlignAlpha(color); - if (x1 / 8 == x2 / 8) - { - // start and end in the same byte - Draw8Pixels(x1, y, bitmaskr[x1 % 8] & bitmaskl[x2 % 8], color); - } - else - { - // start and end in different bytes - Draw8Pixels(x1, y, bitmaskr[x1 % 8], color); - x1 = ((x1 + 8) / 8) * 8; - while (x1 < (x2 / 8) * 8) - { - Draw8Pixels(x1, y, 0xff, color); - x1 += 8; - } - Draw8Pixels(x2, y, bitmaskl[x2 % 8], color); - } + sort(x1,x2); + while (x1 <= x2) { + DrawPixel(x1, y, color); + x1++; + }; } -void cBitmap::DrawVLine(int x, int y1, int y2, eColor color) +void cBitmap::DrawVLine(int x, int y1, int y2, uint32_t color) { - int y; +#ifdef DEBUG + printf("%s:%s(%d) %03d, %03d -> %03d (color %08x)\n", __FILE__, __FUNCTION__, __LINE__, x, y1, y2, color); +#endif + color = cColor::AlignAlpha(color); sort(y1,y2); - - for (y = y1; y <= y2; y++) - DrawPixel(x, y, color); + while (y1 <= y2) { + DrawPixel(x, y1, color); + y1++; + } } -void cBitmap::DrawRectangle(int x1, int y1, int x2, int y2, eColor color, bool filled) +void cBitmap::DrawRectangle(int x1, int y1, int x2, int y2, uint32_t color, bool filled) { +#ifdef DEBUG + printf("%s:%s(%d) %03d * %03d -> %03d * %03d (color %08x)\n", __FILE__, __FUNCTION__, __LINE__, x1, y1, x2, y2, color); +#endif int y; + color = cColor::AlignAlpha(color); + sort(x1,x2); sort(y1,y2); @@ -207,8 +275,13 @@ void cBitmap::DrawRectangle(int x1, int y1, int x2, int y2, eColor color, bool f } } -void cBitmap::DrawRoundRectangle(int x1, int y1, int x2, int y2, eColor color, bool filled, int type) +void cBitmap::DrawRoundRectangle(int x1, int y1, int x2, int y2, uint32_t color, bool filled, int type) { +#ifdef DEBUG + printf("%s:%s(%d) %03d * %03d -> %03d * %03d (color %08x)\n", __FILE__, __FUNCTION__, __LINE__, x1, y1, x2, y2, color); +#endif + color = cColor::AlignAlpha(color); + sort(x1,x2); sort(y1,y2); @@ -230,10 +303,14 @@ void cBitmap::DrawRoundRectangle(int x1, int y1, int x2, int y2, eColor color, b if (type == 4) { // round the ugly fat box... - DrawPixel(x1 + 1, y1 + 1, color == clrWhite ? clrBlack : clrWhite); - DrawPixel(x1 + 1, y2 - 1, color == clrWhite ? clrBlack : clrWhite); - DrawPixel(x2 - 1, y1 + 1, color == clrWhite ? clrBlack : clrWhite); - DrawPixel(x2 - 1, y2 - 1, color == clrWhite ? clrBlack : clrWhite); +// DrawPixel(x1 + 1, y1 + 1, color == clrWhite ? clrBlack : clrWhite); +// DrawPixel(x1 + 1, y2 - 1, color == clrWhite ? clrBlack : clrWhite); +// DrawPixel(x2 - 1, y1 + 1, color == clrWhite ? clrBlack : clrWhite); +// DrawPixel(x2 - 1, y2 - 1, color == clrWhite ? clrBlack : clrWhite); + DrawPixel(x1 + 1, y1 + 1, backgroundColor); + DrawPixel(x1 + 1, y2 - 1, backgroundColor); + DrawPixel(x2 - 1, y1 + 1, backgroundColor); + DrawPixel(x2 - 1, y2 - 1, backgroundColor); } } else @@ -256,8 +333,13 @@ void cBitmap::DrawRoundRectangle(int x1, int y1, int x2, int y2, eColor color, b } } -void cBitmap::DrawEllipse(int x1, int y1, int x2, int y2, eColor color, bool filled, int quadrants) +void cBitmap::DrawEllipse(int x1, int y1, int x2, int y2, uint32_t color, bool filled, int quadrants) { +#ifdef DEBUG + printf("%s:%s(%d) %03d * %03d -> %03d * %03d (color %08x)\n", __FILE__, __FUNCTION__, __LINE__, x1, y1, x2, y2, color); +#endif + color = cColor::AlignAlpha(color); + // Algorithm based on http://homepage.smc.edu/kennedy_john/BELIPSE.PDF int rx = x2 - x1; int ry = y2 - y1; @@ -397,8 +479,13 @@ void cBitmap::DrawEllipse(int x1, int y1, int x2, int y2, eColor color, bool fil } } -void cBitmap::DrawSlope(int x1, int y1, int x2, int y2, eColor color, int type) +void cBitmap::DrawSlope(int x1, int y1, int x2, int y2, uint32_t color, int type) { +#ifdef DEBUG + printf("%s:%s(%d) %03d * %03d -> %03d * %03d\n", __FILE__, __FUNCTION__, __LINE__, x1, y1, x2, y2); +#endif + color = cColor::AlignAlpha(color); + bool upper = type & 0x01; bool falling = type & 0x02; bool vertical = type & 0x04; @@ -410,7 +497,7 @@ void cBitmap::DrawSlope(int x1, int y1, int x2, int y2, eColor color, int type) if (falling) c = -c; int x = int((x2 - x1 + 1) * c / 2); - if (upper && !falling || !upper && falling) + if ((upper && !falling) || (!upper && falling)) DrawRectangle(x1, y, (x1 + x2) / 2 + x, y, color, true); else DrawRectangle((x1 + x2) / 2 + x, y, x2, y, color, true); @@ -432,83 +519,56 @@ void cBitmap::DrawSlope(int x1, int y1, int x2, int y2, eColor color, int type) } } -void cBitmap::DrawBitmap(int x, int y, const cBitmap & bitmap, eColor color) +void cBitmap::DrawBitmap(int x, int y, const cBitmap & bitmap, uint32_t color, uint32_t bgcolor) { - unsigned char cl = 0; - int xt, yt; - const unsigned char * data = bitmap.Data(); - unsigned short temp; - int h, w; +#ifdef DEBUG + printf("%s:%s(%d) '%03d' x '%03d' \n", __FILE__, __FUNCTION__, __LINE__, x, y); +#endif + color = cColor::AlignAlpha(color); + bgcolor = cColor::AlignAlpha(bgcolor); - w = bitmap.Width(); - h = bitmap.Height(); + uint32_t cl = 0; + const uint32_t * data = bitmap.Data(); + bool ismonochrome = bitmap.IsMonochrome(); + + int xt, yt; if (data) { - if (!(x % 8)) - { - // Bitmap is byte alligned (0,8,16,...) - for (yt = 0; yt < h; yt++) - { - for (xt = 0; xt < (w / 8); xt++) - { - cl = *data; - Draw8Pixels(x + (xt * 8), y + yt, cl, color); - data++; - } - if (w % 8) - { - cl = *data; - Draw8Pixels(x + ((w / 8) * 8), y + yt, cl & bitmaskl[w % 8 - 1], color); - data++; - } - } - } - else + for (yt = 0; yt < bitmap.Height(); yt++) { - // Bitmap is not byte alligned - for (yt = 0; yt < h; yt++) - { - temp = 0; - for (xt = 0; xt < (w + (x % 8)) / 8; xt++) - { - cl = *(data + yt * ((w + 7) / 8) + xt); - temp = temp | ((unsigned short) cl << (8 - (x % 8))); - cl = (temp & 0xff00) >> 8; - if (!xt) - { - // first byte - Draw8Pixels(x - (x % 8) + (xt * 8), y + yt, cl & bitmaskr[x % 8], color); - } - else - { - // not the first byte - Draw8Pixels(x - (x % 8) + (xt * 8), y + yt, cl, color); - } - temp <<= 8; - } - if ((w + (x % 8) + 7) / 8 != (w + (x % 8)) / 8) - { - // print the rest - cl = *(data + (yt + 1) * ((w + 7) / 8) - 1); - temp = temp | ((unsigned short) cl << (8 - (x % 8))); - cl = (temp & 0xff00) >> 8; - Draw8Pixels(x - (x % 8) + (((w + (x % 8)) / 8) * 8), y + yt, cl & bitmaskl[(w + x) % 8 - 1], color); - } + for (xt = 0; xt < bitmap.Width(); xt++) + { + cl = data[(yt * bitmap.Width())+xt]; + if (ismonochrome) { + DrawPixel(xt+x, yt+y, (cl == cColor::Black) ? color : bgcolor); + } else { + DrawPixel(xt+x, yt+y, cl); } - } + } + } } } int cBitmap::DrawText(int x, int y, int xmax, const std::string & text, const cFont * font, - eColor color, bool proportional, int skipPixels) + uint32_t color, uint32_t bgcolor, bool proportional, int skipPixels) { +#ifdef DEBUG + printf("%s:%s(%d) text '%s', color '%08x'/'%08x'\n", __FILE__, __FUNCTION__, __LINE__, text.c_str(), color, bgcolor); +#endif int xt; int yt; int i; - char c; + uint32_t c; + uint32_t c0; + uint32_t c1; + uint32_t c2; + uint32_t c3; int start; + color = cColor::AlignAlpha(color); + bgcolor = cColor::AlignAlpha(bgcolor); + clip(x, 0, width - 1); clip(y, 0, height - 1); @@ -544,9 +604,41 @@ int cBitmap::DrawText(int x, int y, int xmax, const std::string & text, const cF } } } - for (i = start; i < (int) text.length(); i++) + + i = start; + while (i < (int) text.length()) +// for (i = start; i < (int) text.length(); i++) { c = text[i]; + + if ( font->IsUTF8() ) { + c0 = text[i]; + c1 = (i+1 < (int)text.length()) ? text[i+1] : 0; + c2 = (i+2 < (int)text.length()) ? text[i+2] : 0; + c3 = (i+3 < (int)text.length()) ? text[i+3] : 0; + c0 &=0xff; c1 &=0xff; c2 &=0xff; c3 &=0xff; + + if( c0 >= 0xc2 && c0 <= 0xdf && c1 >= 0x80 && c1 <= 0xbf ) { + //2 byte UTF-8 sequence found + i+=1; + c = ((c0&0x1f)<<6) | (c1&0x3f); + } else if ((c0 == 0xE0 && c1 >= 0xA0 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf) + || (c0 >= 0xE1 && c1 <= 0xEC && c1 >= 0x80 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf) + || (c0 == 0xED && c1 >= 0x80 && c1 <= 0x9f && c2 >= 0x80 && c2 <= 0xbf) + || (c0 >= 0xEE && c0 <= 0xEF && c1 >= 0x80 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf) ) { + //3 byte UTF-8 sequence found + c = ((c0&0x0f)<<4) | ((c1&0x3f)<<6) | (c2&0x3f); + i+=2; + } else if ( (c0 == 0xF0 && c1 >= 0x90 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf && c3 >= 0x80 && c3 <= 0xbf) + || (c0 >= 0xF1 && c0 >= 0xF3 && c1 >= 0x80 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf && + c3 >= 0x80 && c3 <= 0xbf) + || (c0 == 0xF4 && c1 >= 0x80 && c1 <= 0x8f && c2 >= 0x80 && c2 <= 0xbf && c3 >= 0x80 && c3 <= 0xbf) ) { + //4 byte UTF-8 sequence found + c = ((c0&0x07)<<2) | ((c1&0x3f)<<4) | ((c2&0x3f)<<6) | (c3&0x3f); + i+=3; + } + } + if (xt > xmax) { i = text.length(); @@ -557,13 +649,13 @@ int cBitmap::DrawText(int x, int y, int xmax, const std::string & text, const cF { if (skipPixels > 0) { - DrawCharacter(xt, yt, xmax, c, font, color, skipPixels); + DrawCharacter(xt, yt, xmax, c, font, color, bgcolor, skipPixels); xt += font->TotalWidth() - skipPixels; skipPixels = 0; } else { - DrawCharacter(xt, yt, xmax, c, font, color); + DrawCharacter(xt, yt, xmax, c, font, color, bgcolor); xt += font->TotalWidth(); } } @@ -571,12 +663,12 @@ int cBitmap::DrawText(int x, int y, int xmax, const std::string & text, const cF { if (skipPixels > 0) { - xt += DrawCharacter(xt, yt, xmax, c, font, color, skipPixels); + xt += DrawCharacter(xt, yt, xmax, c, font, color, bgcolor, skipPixels); skipPixels = 0; } else { - xt += DrawCharacter(xt, yt, xmax, c, font, color); + xt += DrawCharacter(xt, yt, xmax, c, font, color, bgcolor); } if (xt <= xmax) { @@ -584,15 +676,26 @@ int cBitmap::DrawText(int x, int y, int xmax, const std::string & text, const cF } } } + i++; } } return xt; } -int cBitmap::DrawCharacter(int x, int y, int xmax, char c, const cFont * font, - eColor color, int skipPixels) +int cBitmap::DrawCharacter(int x, int y, int xmax, uint32_t c, const cFont * font, + uint32_t color, uint32_t bgcolor, int skipPixels) { +#ifdef DEBUG + printf("%s:%s(%d) %03d * %03d char '%c' color '%08x' bgcolor '%08x'\n", __FILE__, __FUNCTION__, __LINE__, x, y, c, color, bgcolor); +#endif const cBitmap * charBitmap; + cBitmap * drawBitmap; + + color = cColor::AlignAlpha(color); + bgcolor = cColor::AlignAlpha(bgcolor); + + uint32_t dot = 0; + int xt, yt; clip(x, 0, width - 1); clip(y, 0, height - 1); @@ -600,32 +703,43 @@ int cBitmap::DrawCharacter(int x, int y, int xmax, char c, const cFont * font, charBitmap = font->GetCharacter(c); if (charBitmap) { - cBitmap * drawBitmap = charBitmap->SubBitmap(skipPixels, 0, xmax - x + skipPixels, charBitmap->Height() - 1); - if (drawBitmap) - DrawBitmap(x, y, *drawBitmap, color); - delete drawBitmap; + drawBitmap = new cBitmap(charBitmap->Width()-skipPixels,charBitmap->Height()); + drawBitmap->Clear(bgcolor); + if (drawBitmap) { + for (xt=0;xt<charBitmap->Width();xt++) { + for (yt=0;yt<charBitmap->Height();yt++) { + dot = charBitmap->GetPixel(xt+skipPixels,yt); + if ((dot | 0xFF000000) == cColor::Black) { // todo: does not work with antialising? + drawBitmap->DrawPixel(xt, yt, color); + } else { + drawBitmap->DrawPixel(xt, yt, bgcolor); + } + } + } + DrawBitmap(x, y, *drawBitmap); + delete drawBitmap; + } return charBitmap->Width() - skipPixels; } return 0; } -unsigned char cBitmap::GetPixel(int x, int y) const +uint32_t cBitmap::GetPixel(int x, int y) const { - unsigned char value; - - value = bitmap[y * lineSize + x / 8]; - value = (value >> (7 - (x % 8))) & 1; + uint32_t value; + value = bitmap[y * width + x]; return value; } cBitmap * cBitmap::SubBitmap(int x1, int y1, int x2, int y2) const { +#ifdef DEBUG + printf("%s:%s(%d) %03d * %03d / %03d * %03d\n", __FILE__, __FUNCTION__, __LINE__, x1, y1, x2, y2); +#endif int w, h; int xt, yt; cBitmap * bmp; - unsigned char cl; - unsigned char * data; - unsigned short temp; + uint32_t cl; sort(x1,x2); sort(y1,y2); @@ -642,62 +756,23 @@ cBitmap * cBitmap::SubBitmap(int x1, int y1, int x2, int y2) const if (!bmp || !bmp->Data()) return NULL; bmp->Clear(); - if (x1 % 8 == 0) - { - // Bitmap is byte alligned (0,8,16,...) - for (yt = 0; yt < h; yt++) - { - data = &bitmap[(y1 + yt) * lineSize + x1 / 8]; - for (xt = 0; xt < (w / 8) * 8; xt += 8) - { - cl = *data; - bmp->Draw8Pixels(xt, yt, cl, clrBlack); - data++; - } - if (w % 8 != 0) - { - cl = *data; - bmp->Draw8Pixels(xt, yt, cl & bitmaskl[w % 8 - 1], clrBlack); - } - } - } - else + + for (yt = 0; yt < h; yt++) { - // Bitmap is not byte alligned - for (yt = 0; yt < h; yt++) - { - temp = 0; - data = &bitmap[(y1 + yt) * lineSize + x1 / 8]; - for (xt = 0; xt <= ((w / 8)) * 8; xt += 8) - { - cl = *data; - temp = temp | ((unsigned short) cl << (x1 % 8)); - cl = (temp & 0xff00) >> 8; - if (xt > 0) - { - bmp->Draw8Pixels(xt - 8, yt, cl, clrBlack); - } - temp <<= 8; - data++; - } - if (w % 8 != 0) - { - // print the rest - if (8 - (x1 % 8) < w % 8) - { - cl = *data; - temp = temp | ((unsigned short) cl << (x1 % 8)); - } - cl = (temp & 0xff00) >> 8; - bmp->Draw8Pixels(xt - 8, yt, cl & bitmaskl[(w % 8) - 1], clrBlack); - } - } + for (xt = 0; xt < w; xt++) + { + cl = bitmap[(w*yt+y1)+xt+x1]; + bmp->DrawPixel(xt,yt, cl); + } } return bmp; } bool cBitmap::LoadPBM(const std::string & fileName) { +#ifdef DEBUG + printf("%s:%s(%d)\n", __FILE__, __FUNCTION__, __LINE__); +#endif FILE * pbmFile; char str[32]; int i; @@ -776,10 +851,8 @@ bool cBitmap::LoadPBM(const std::string & fileName) delete[] bitmap; width = w; height = h; - // lines are byte aligned - lineSize = (width + 7) / 8; - bitmap = new unsigned char[lineSize * height]; - fread(bitmap, lineSize * height, 1, pbmFile); + bitmap = new uint32_t [width * height]; + fread(bitmap, width * height, 1, pbmFile); fclose(pbmFile); return true; @@ -787,6 +860,9 @@ bool cBitmap::LoadPBM(const std::string & fileName) void cBitmap::SavePBM(const std::string & fileName) { +#ifdef DEBUG + printf("%s:%s(%d)\n", __FILE__, __FUNCTION__, __LINE__); +#endif int i; char str[32]; FILE * fp; diff --git a/glcdgraphics/bitmap.h b/glcdgraphics/bitmap.h index b6446a0..d87745d 100644 --- a/glcdgraphics/bitmap.h +++ b/glcdgraphics/bitmap.h @@ -9,22 +9,70 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net> + * Andreas 'randy' Weinberger */ #ifndef _GLCDGRAPHICS_BITMAP_H_ #define _GLCDGRAPHICS_BITMAP_H_ #include <string> +#include <inttypes.h> + +// graphlcd-base uses ARGB bitmaps instead of 1bit ones +#define GRAPHLCD_CBITMAP_ARGB namespace GLCD { +#if 0 enum eColor { - clrBlack, - clrWhite + clrTransparent, + clrGray50, + clrBlack, + clrRed, + clrGreen, + clrYellow, + clrMagenta, + clrBlue, + clrCyan, + clrWhite }; +#endif + + +class cColor +{ +public: + uint32_t color; + + cColor(uint32_t col) { color = col; } + cColor(const cColor & col) { color = col.color; } + + static const uint32_t Black = 0xFF000000; + static const uint32_t White = 0xFFFFFFFF; + static const uint32_t Red = 0xFFFF0000; + static const uint32_t Green = 0xFF00FF00; + static const uint32_t Blue = 0xFF0000FF; + static const uint32_t Magenta = 0xFFFF00FF; + static const uint32_t Cyan = 0xFF00FFFF; + static const uint32_t Yellow = 0xFFFFFF00; + static const uint32_t Transparent = 0x00FFFFFF; + static const uint32_t ERRCOL = 0x00000000; + + operator uint32_t(void) { return color; } + + uint32_t GetColor (void) { return color; } + void SetColor (uint32_t col) { color = col; } + + cColor Invert (void); + + static cColor ParseColor (std::string col); + static uint32_t AlignAlpha (uint32_t col) { return (col & 0xFF000000) ? col : (col | 0xFF000000); } +}; + class cFont; @@ -34,37 +82,54 @@ protected: int width; int height; int lineSize; - unsigned char * bitmap; + uint32_t * bitmap; + bool ismonochrome; + + uint32_t backgroundColor; public: - cBitmap(int width, int height, unsigned char * data = NULL); + cBitmap(int width, int height, uint32_t * data = NULL); + cBitmap(int width, int height, uint32_t initcol); cBitmap(const cBitmap & b); ~cBitmap(); int Width() const { return width; } int Height() const { return height; } int LineSize() const { return lineSize; } - const unsigned char * Data() const { return bitmap; } + const uint32_t * Data() const { return bitmap; } - void Clear(); + void Clear(uint32_t initcol = cColor::Transparent); void Invert(); - void DrawPixel(int x, int y, eColor color); - void Draw8Pixels(int x, int y, unsigned char pixels, eColor color); - void DrawLine(int x1, int y1, int x2, int y2, eColor color); - void DrawHLine(int x1, int y, int x2, eColor color); - void DrawVLine(int x, int y1, int y2, eColor color); - void DrawRectangle(int x1, int y1, int x2, int y2, eColor color, bool filled); - void DrawRoundRectangle(int x1, int y1, int x2, int y2, eColor color, bool filled, int size); - void DrawEllipse(int x1, int y1, int x2, int y2, eColor color, bool filled, int quadrants); - void DrawSlope(int x1, int y1, int x2, int y2, eColor color, int type); - void DrawBitmap(int x, int y, const cBitmap & bitmap, eColor color); + void DrawPixel(int x, int y, uint32_t color); + void DrawLine(int x1, int y1, int x2, int y2, uint32_t color); + void DrawHLine(int x1, int y, int x2, uint32_t color); + void DrawVLine(int x, int y1, int y2, uint32_t color); + void DrawRectangle(int x1, int y1, int x2, int y2, uint32_t color, bool filled); + void DrawRoundRectangle(int x1, int y1, int x2, int y2, uint32_t color, bool filled, int size); + void DrawEllipse(int x1, int y1, int x2, int y2, uint32_t color, bool filled, int quadrants); + void DrawSlope(int x1, int y1, int x2, int y2, uint32_t color, int type); + void DrawBitmap(int x, int y, const cBitmap & bitmap, uint32_t color = cColor::White, uint32_t bgcolor = cColor::Black); int DrawText(int x, int y, int xmax, const std::string & text, const cFont * font, - eColor color = clrBlack, bool proportional = true, int skipPixels = 0); - int DrawCharacter(int x, int y, int xmax, char c, const cFont * font, - eColor color = clrBlack, int skipPixels = 0); + uint32_t color = cColor::White, uint32_t bgcolor = cColor::Black, bool proportional = true, int skipPixels = 0); + int DrawCharacter(int x, int y, int xmax, uint32_t c, const cFont * font, + uint32_t color = cColor::White, uint32_t bgcolor = cColor::Black, int skipPixels = 0); cBitmap * SubBitmap(int x1, int y1, int x2, int y2) const; - unsigned char GetPixel(int x, int y) const; + uint32_t GetPixel(int x, int y) const; + + void SetMonochrome(bool mono) { ismonochrome = mono; } + bool IsMonochrome(void) const { return ismonochrome; } + +#if 0 + int DrawText(int x, int y, int xmax, const std::string & text, const cFont * font, + uint32_t color, bool proportional = true, int skipPixels = 0) { + return DrawText(x, y, xmax, text, font, color, cColor::Black, proportional, skipPixels); + } + int DrawCharacter(int x, int y, int xmax, char c, const cFont * font, + uint32_t color, int skipPixels = 0) { + return DrawCharacter(x, y, xmax, c, font, color, cColor::Black, skipPixels); + } +#endif bool LoadPBM(const std::string & fileName); void SavePBM(const std::string & fileName); diff --git a/glcdgraphics/font.c b/glcdgraphics/font.c index 1735cf2..116d88b 100644 --- a/glcdgraphics/font.c +++ b/glcdgraphics/font.c @@ -9,7 +9,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net> + * Andreas 'randy' Weinberger */ #include <stdio.h> @@ -55,6 +57,64 @@ static const uint32_t kCharHeaderSize = 4; //}; //#pragma pack() +#ifdef HAVE_FREETYPE2 + +class cBitmapCache +{ +private: +protected: + cBitmapCache *next; // next bitmap + cBitmap *ptr; + uint32_t charcode; +public: + cBitmapCache(); + ~cBitmapCache(); + + void PushBack(uint32_t ch, cBitmap *bitmap); + cBitmap *GetBitmap(uint32_t ch) const; +}; + +cBitmapCache::cBitmapCache() +: next(NULL), + ptr(NULL), + charcode(0) +{ +} + +cBitmapCache::~cBitmapCache() +{ + delete ptr; + delete next; +} + +void cBitmapCache::PushBack(uint32_t ch, cBitmap *bitmap) +{ + if (!ptr) + { + charcode = ch; + ptr = bitmap; + } + else if (!next) + { + next = new cBitmapCache(); + next->ptr = bitmap; + next->charcode = ch; + } else + next->PushBack(ch, bitmap); +} + +cBitmap *cBitmapCache::GetBitmap(uint32_t ch) const +{ + if (ptr && charcode==ch) + return ptr; + else if (next) + return next->GetBitmap(ch); + else + return NULL; +} + +#endif + cFont::cFont() { Init(); @@ -65,10 +125,12 @@ cFont::~cFont() Unload(); } -bool cFont::LoadFNT(const std::string & fileName) +bool cFont::LoadFNT(const std::string & fileName, const std::string & encoding) { // cleanup if we already had a loaded font Unload(); + fontType = 1; //original fonts + isutf8 = (encoding == "UTF-8"); FILE * fontFile; int i; @@ -88,6 +150,7 @@ bool cFont::LoadFNT(const std::string & fileName) buffer[3] != kFontFileSign[3]) { fclose(fontFile); + syslog(LOG_ERR, "cFont::LoadFNT(): Cannot open file: %s - not the correct fileheader.\n",fileName.c_str()); return false; } @@ -105,11 +168,31 @@ bool cFont::LoadFNT(const std::string & fileName) character = chdr[0] | (chdr[1] << 8); charWidth = chdr[2] | (chdr[3] << 8); fread(buffer, fontHeight * ((charWidth + 7) / 8), 1, fontFile); - if (characters[character]) - delete characters[character]; - characters[character] = new cBitmap(charWidth, fontHeight, buffer); - if (characters[character]->Width() > maxWidth) - maxWidth = characters[character]->Width(); +#ifdef DEBUG + printf ("fontHeight %0d - charWidth %0d - character %0d - bytes %0d\n", fontHeight, charWidth, character,fontHeight * ((charWidth + 7) / 8)); +#endif + + int y; int loop; + int num = 0; + uint dot; uint b; + cBitmap * charBitmap = new cBitmap(charWidth, fontHeight); + charBitmap->Clear(); + for (num=0; num<fontHeight * ((charWidth + 7) / 8);num++) { + y = (charWidth + 7) / 8; + for (loop=0;loop<((charWidth + 7) / 8); loop++) { + for (b=0;b<charWidth;b++) { + dot=buffer[num+loop] & (0x80 >> b); + if (dot) { + charBitmap->DrawPixel(b+((loop*8)),num/y,cColor::Black); + } + } + } + num=num+y-1; + } + SetCharacter(character, charBitmap); + + if (charWidth > maxWidth) + maxWidth = charWidth; } fclose(fontFile); @@ -169,7 +252,8 @@ bool cFont::SaveFNT(const std::string & fileName) const chdr[2] = (uint8_t) characters[i]->Width(); chdr[3] = (uint8_t) (characters[i]->Width() >> 8); fwrite(chdr, kCharHeaderSize, 1, fontFile); - fwrite(characters[i]->Data(), totalHeight * characters[i]->LineSize(), 1, fontFile); +// fwrite(characters[i]->Data(), totalHeight * characters[i]->LineSize(), 1, fontFile); + fwrite(characters[i]->Data(), totalHeight * characters[i]->Width(), 1, fontFile); } } @@ -185,6 +269,9 @@ bool cFont::LoadFT2(const std::string & fileName, const std::string & encoding, { // cleanup if we already had a loaded font Unload(); + fontType = 2; // ft2 fonts + isutf8 = (encoding == "UTF-8"); + #ifdef HAVE_FREETYPE2 if (access(fileName.c_str(), F_OK) != 0) { @@ -194,7 +281,6 @@ bool cFont::LoadFT2(const std::string & fileName, const std::string & encoding, // file exists FT_Library library; FT_Face face; - FT_GlyphSlot slot; int error = FT_Init_FreeType(&library); if (error) @@ -223,36 +309,11 @@ bool cFont::LoadFT2(const std::string & fileName, const std::string & encoding, return false; } - // set slot - slot = face->glyph; - // set Size FT_Set_Char_Size(face, 0, size * 64, 0, 0); - wchar_t utf_buff[256]; - if (dingBats) - { -/* - FT_CharMap charmap = 0; - for (int n = 0; n < face->num_charmaps; n++) - { - if (face->charmaps[n]->platform_id == 3 && - face->charmaps[n]->encoding_id == 0) - { - charmap = face->charmaps[n]; - //break; - } - } - if (charmap) - syslog(LOG_ERR, "cFont::LoadFT2: platform_id: %d, encoding_id: %d", charmap->platform_id, charmap->encoding_id); - error = FT_Set_Charmap(_face, charmap); - if (error) - { - syslog(LOG_ERR, "cFont::LoadFT2: FT_Select_Charmap encoding not supported: %d", charmap->encoding_id); - } -*/ - } - else + // generate lookup table for encoding conversions (encoding != UTF8) + if (! (isutf8 || dingBats) ) { iconv_t cd; if ((cd = iconv_open("WCHAR_T", encoding.c_str())) == (iconv_t) -1) @@ -276,87 +337,26 @@ bool cFont::LoadFT2(const std::string & fileName, const std::string & encoding, in_buff = (char *) &char_buff; out_buff = (char *) &wchar_buff; count = iconv(cd, &in_buff, &in_len, &out_buff, &out_len); - if ((size_t) -1 == count) - { - utf_buff[c] = 0; - } - utf_buff[c] = wchar_buff; + iconv_lut[c] = ((size_t) -1 == count) ? (wchar_t)'?' : wchar_buff; } iconv_close(cd); + } else { + // don't leave LUT uninitialised + for (int c = 0; c < 256; c++) + iconv_lut[c] = (wchar_t)c; } // get some global parameters - totalHeight = (face->size->metrics.ascender >> 6) - (face->size->metrics.descender >> 6); - totalWidth = face->size->metrics.max_advance >> 6; - totalAscent = face->size->metrics.ascender >> 6; - lineHeight = face->size->metrics.height >> 6; - spaceBetween = 0; -#if 0 - syslog(LOG_DEBUG, "cFont::LoadFT2: totalHeight = %d", totalHeight); - syslog(LOG_DEBUG, "cFont::LoadFT2: totalWidth = %d", totalWidth); - syslog(LOG_DEBUG, "cFont::LoadFT2: totalAscent = %d", totalAscent); - syslog(LOG_DEBUG, "cFont::LoadFT2: lineHeight = %d", lineHeight); - syslog(LOG_DEBUG, "cFont::LoadFT2: spaceBetween = %d", spaceBetween); -#endif - // render glyphs for ASCII codes 0 to 255 in our bitmap class - FT_UInt glyph_index; - int num_char; - - for (num_char = 0; num_char < 256; num_char++) - { - if (dingBats) - { - //Get FT char index & load the char - error = FT_Load_Char(face, num_char, FT_LOAD_DEFAULT); - } - else - { - //Get FT char index - glyph_index = FT_Get_Char_Index(face, utf_buff[num_char]); - //Load the char - error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); - } - if (error) - { - syslog(LOG_ERR, "cFont::LoadFT2: ERROR when calling FT_Load_Glyph: %x", error); - } + SetTotalHeight( (face->size->metrics.ascender >> 6) - (face->size->metrics.descender >> 6) ); + SetTotalWidth ( face->size->metrics.max_advance >> 6 ); + SetTotalAscent( face->size->metrics.ascender >> 6 ); + SetLineHeight ( face->size->metrics.height >> 6 ); + SetSpaceBetween( 0 ); - // convert to a mono bitmap - error = FT_Render_Glyph(face->glyph, FT_RENDER_MODE_MONO); - if (error) - { - syslog(LOG_ERR, "cFont::LoadFT2: ERROR when calling FT_Render_Glyph: %x", error); - } + ft2_library = library; + ft2_face = face; - // now, fill our pixel data - cBitmap * charBitmap = new cBitmap(face->glyph->advance.x >> 6, totalHeight); - charBitmap->Clear(); - unsigned char * bufPtr = face->glyph->bitmap.buffer; - unsigned char pixel; - for (int y = 0; y < face->glyph->bitmap.rows; y++) - { - for (int x = 0; x < face->glyph->bitmap.width; x++) - { - pixel = (bufPtr[x / 8] >> (7 - x % 8)) & 1; - if (pixel) - charBitmap->DrawPixel((face->glyph->metrics.horiBearingX >> 6) + x, - (face->size->metrics.ascender >> 6) - (face->glyph->metrics.horiBearingY >> 6) + y, - GLCD::clrBlack); - } - bufPtr += face->glyph->bitmap.pitch; - } - SetCharacter((char) num_char, charBitmap); - } - error = FT_Done_Face(face); - if (error) - { - syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_Face(..) returned (%d)", error); - } - error = FT_Done_FreeType(library); - if (error) - { - syslog(LOG_ERR, "cFont::LoadFT2: FT_Done_FreeType(..) returned (%d)", error); - } + characters_cache=new cBitmapCache(); return true; #else syslog(LOG_ERR, "cFont::LoadFT2: glcdgraphics was compiled without FreeType2 support!!!"); @@ -364,28 +364,18 @@ bool cFont::LoadFT2(const std::string & fileName, const std::string & encoding, #endif } -int cFont::Width(char ch) const +int cFont::Width(uint32_t ch) const { - if (characters[(unsigned char) ch]) - return characters[(unsigned char) ch]->Width(); + const cBitmap *bitmap = GetCharacter(ch); + if (bitmap) + return bitmap->Width(); else return 0; } int cFont::Width(const std::string & str) const { - unsigned int i; - int sum = 0; - - for (i = 0; i < str.length(); i++) - { - sum += Width(str[i]); - } - if (str.length() > 1) - { - sum += spaceBetween * (str.length() - 1); - } - return sum; + return Width(str, (unsigned int) str.length()); } int cFont::Width(const std::string & str, unsigned int len) const @@ -393,21 +383,56 @@ int cFont::Width(const std::string & str, unsigned int len) const unsigned int i; int sum = 0; - for (i = 0; i < str.length() && i < len; i++) - { - sum += Width(str[i]); - } - if (std::min(str.length(), (size_t) len) > 1) + uint32_t c,c0,c1,c2,c3; + + i = 0; +// for (i = 0; i < (unsigned int)str.length() && symcount < len; i++) + while (i < (unsigned int)str.length() && i < len) { - sum += spaceBetween * (std::min(str.length(), (size_t) len) - 1); + if (isutf8) { + c = str[i]; + c0 = str[i]; + c1 = (i+1 < (unsigned int)str.length()) ? str[i+1] : 0; + c2 = (i+2 < (unsigned int)str.length()) ? str[i+2] : 0; + c3 = (i+3 < (unsigned int)str.length()) ? str[i+3] : 0; + c0 &=0xff; c1 &=0xff; c2 &=0xff; c3 &=0xff; + + if( c0 >= 0xc2 && c0 <= 0xdf && c1 >= 0x80 && c1 <= 0xbf ){ + //2 byte UTF-8 sequence found + i+=1; + c = ((c0&0x1f)<<6) | (c1&0x3f); + }else if( (c0 == 0xE0 && c1 >= 0xA0 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf) + || (c0 >= 0xE1 && c1 <= 0xEC && c1 >= 0x80 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf) + || (c0 == 0xED && c1 >= 0x80 && c1 <= 0x9f && c2 >= 0x80 && c2 <= 0xbf) + || (c0 >= 0xEE && c0 <= 0xEF && c1 >= 0x80 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf) ){ + //3 byte UTF-8 sequence found + c = ((c0&0x0f)<<4) | ((c1&0x3f)<<6) | (c2&0x3f); + i+=2; + }else if( (c0 == 0xF0 && c1 >= 0x90 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf && c3 >= 0x80 && c3 <= 0xbf) + || (c0 >= 0xF1 && c0 >= 0xF3 && c1 >= 0x80 && c1 <= 0xbf && c2 >= 0x80 && c2 <= 0xbf && c3 >= 0x80 && c3 <= 0xbf) + || (c0 == 0xF4 && c1 >= 0x80 && c1 <= 0x8f && c2 >= 0x80 && c2 <= 0xbf && c3 >= 0x80 && c3 <= 0xbf) ){ + //4 byte UTF-8 sequence found + c = ((c0&0x07)<<2) | ((c1&0x3f)<<4) | ((c2&0x3f)<<6) | (c3&0x3f); + i+=3; + } + sum += Width(c); + } else { + sum += Width(str[i]); + } + i++; } + + if (i > 1) + sum += spaceBetween * (i - 1); + return sum; } -int cFont::Height(char ch) const +int cFont::Height(uint32_t ch) const { - if (characters[(unsigned char) ch]) - return characters[(unsigned char) ch]->Height(); + const cBitmap *bitmap = GetCharacter(ch); + if (bitmap) + return bitmap->Height(); else return 0; } @@ -432,13 +457,83 @@ int cFont::Height(const std::string & str, unsigned int len) const return sum; } -const cBitmap * cFont::GetCharacter(char ch) const +const cBitmap * cFont::GetCharacter(uint32_t ch) const { +#ifdef HAVE_FREETYPE2 + if ( fontType == 2 ) { + //lookup in cache + cBitmap *ptr=characters_cache->GetBitmap(ch); + if (ptr) + return ptr; + + FT_Face face = (FT_Face) ft2_face; + FT_UInt glyph_index; + //Get FT char index + if (isutf8) { + glyph_index = FT_Get_Char_Index(face, ch); + } else { + glyph_index = FT_Get_Char_Index(face, iconv_lut[(unsigned char)ch]); + } + + //Load the char + int error = FT_Load_Glyph(face, glyph_index, FT_LOAD_DEFAULT); + if (error) + { + syslog(LOG_ERR, "cFont::LoadFT2: ERROR when calling FT_Load_Glyph: %x", error); + return NULL; + } + + FT_Render_Mode rmode = FT_RENDER_MODE_MONO; +#if ( (FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 1 && FREETYPE_PATCH >= 7) || (FREETYPE_MAJOR == 2 && FREETYPE_MINOR == 2 && FREETYPE_PATCH <= 1) ) + if (ch == 32) rmode = FT_RENDER_MODE_NORMAL; +#endif + + // convert to a mono bitmap + error = FT_Render_Glyph(face->glyph, rmode); + if (error) + { + syslog(LOG_ERR, "cFont::LoadFT2: ERROR when calling FT_Render_Glyph: %x", error); + return NULL; + } else { + // now, fill our pixel data + cBitmap *charBitmap = new cBitmap(face->glyph->advance.x >> 6, TotalHeight()); + charBitmap->Clear(); + unsigned char * bufPtr = face->glyph->bitmap.buffer; + unsigned char pixel; + for (int y = 0; y < face->glyph->bitmap.rows; y++) + { + for (int x = 0; x < face->glyph->bitmap.width; x++) + { + pixel = (bufPtr[x / 8] >> (7 - x % 8)) & 1; + if (pixel) + charBitmap->DrawPixel((face->glyph->metrics.horiBearingX >> 6) + x, + (face->size->metrics.ascender >> 6) - (face->glyph->metrics.horiBearingY >> 6) + y, + /*GLCD::clrBlack*/ cColor::Black); + } + bufPtr += face->glyph->bitmap.pitch; + } + + // adjust maxwidth if necessary + //if (totalWidth < charBitmap->Width()) + // totalWidth = charBitmap->Width(); + + characters_cache->PushBack(ch, charBitmap); + return charBitmap; + } + return NULL; // if any + } // else +#endif return characters[(unsigned char) ch]; } void cFont::SetCharacter(char ch, cBitmap * bitmapChar) { +#ifdef HAVE_FREETYPE2 + if ( fontType == 2 ) { + syslog(LOG_ERR, "cFont::SetCharacter: is not supported with FreeType2 fonts!!!"); + return; + } +#endif // adjust maxwidth if necessary if (totalWidth < bitmapChar->Width()) totalWidth = bitmapChar->Width(); @@ -462,6 +557,12 @@ void cFont::Init() { characters[i] = NULL; } +#ifdef HAVE_FREETYPE2 + ft2_library = NULL; + ft2_face = NULL; + characters_cache = NULL; +#endif + fontType = 1; } void cFont::Unload() @@ -474,6 +575,13 @@ void cFont::Unload() delete characters[i]; } } +#ifdef HAVE_FREETYPE2 + delete characters_cache; + if (ft2_face) + FT_Done_Face((FT_Face)ft2_face); + if (ft2_library) + FT_Done_FreeType((FT_Library)ft2_library); +#endif // re-init Init(); } diff --git a/glcdgraphics/font.h b/glcdgraphics/font.h index b36d5ac..1315123 100644 --- a/glcdgraphics/font.h +++ b/glcdgraphics/font.h @@ -9,7 +9,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net> + * Andreas 'randy' Weinberger */ #ifndef _GLCDGRAPHICS_FONT_H_ @@ -23,6 +25,8 @@ namespace GLCD { +class cBitmapCache; + class cFont { private: @@ -33,6 +37,14 @@ private: int lineHeight; cBitmap * characters[256]; + int fontType; //original or FT2 font, 1-original, 2-ft2 + + bool isutf8; + wchar_t iconv_lut[256]; // lookup table needed if encoding != UTF-8 + + cBitmapCache *characters_cache; + void *ft2_library; //FT_Library + void *ft2_face; //FT_Face protected: void Init(); void Unload(); @@ -40,7 +52,7 @@ public: cFont(); ~cFont(); - bool LoadFNT(const std::string & fileName); + bool LoadFNT(const std::string & fileName, const std::string & encoding = "UTF-8"); bool SaveFNT(const std::string & fileName) const; bool LoadFT2(const std::string & fileName, const std::string & encoding, int size, bool dingBats = false); @@ -56,18 +68,19 @@ public: void SetSpaceBetween(int width) { spaceBetween = width; }; void SetLineHeight(int height) { lineHeight = height; }; - int Width(char ch) const; + int Width(uint32_t ch) const; int Width(const std::string & str) const; int Width(const std::string & str, unsigned int len) const; - int Height(char ch) const; + int Height(uint32_t ch) const; int Height(const std::string & str) const; int Height(const std::string & str, unsigned int len) const; - const cBitmap * GetCharacter(char ch) const; + const cBitmap * GetCharacter(uint32_t ch) const; void SetCharacter(char ch, cBitmap * bitmapChar); void WrapText(int Width, int Height, std::string & Text, std::vector <std::string> & Lines, int * TextWidth = NULL) const; + bool IsUTF8(void) const { return isutf8; } }; } // end of namespace diff --git a/glcdgraphics/glcd.c b/glcdgraphics/glcd.c index e79b6b8..30449b9 100644 --- a/glcdgraphics/glcd.c +++ b/glcdgraphics/glcd.c @@ -9,7 +9,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net> + * Andreas 'randy' Weinberger */ #include <stdio.h> @@ -163,30 +165,53 @@ bool cGLCDFile::Load(cImage & image, const string & fileName) image.SetWidth(width); image.SetHeight(height); image.SetDelay(delay); - unsigned char * bmpdata = new unsigned char[height * ((width + 7) / 8)]; - if (bmpdata) + unsigned char * bmpdata_raw = new unsigned char[height * ((width + 7) / 8)]; + uint32_t * bmpdata = new uint32_t[height * width]; + if (bmpdata && bmpdata_raw) { for (unsigned int n = 0; n < count; n++) { - if (fread(bmpdata, height * ((width + 7) / 8), 1, fp) != 1) + if (fread(bmpdata_raw, height * ((width + 7) / 8), 1, fp) != 1) { delete[] bmpdata; fclose(fp); image.Clear(); return false; } - image.AddBitmap(new cBitmap(width, height, bmpdata)); + int colsize = (width+7)/8; + for (int j = 0; j < height; j++) { + for (int i = 0; i < width; i++) { + if ( bmpdata_raw[j*colsize + (i>>3)] & (1 << (7-(i%8))) ) { + bmpdata[j*width+i] = cColor::Black; + } else { + bmpdata[j*width+i] = cColor::White; + } + } + } +#ifdef DEBUG + printf("%s:%s(%d) - filename: '%s', count %d\n", __FILE__, __FUNCTION__, __LINE__, fileName.c_str(), n); +#endif + cBitmap * b = new cBitmap(width, height, bmpdata); + b->SetMonochrome(true); + //image.AddBitmap(new cBitmap(width, height, bmpdata)); + image.AddBitmap(b); } delete[] bmpdata; } else { syslog(LOG_ERR, "glcdgraphics: malloc failed (cGLCDFile::Load)."); + if (bmpdata) + delete[] bmpdata; + if (bmpdata_raw) + delete[] bmpdata_raw; fclose(fp); image.Clear(); return false; } fclose(fp); + if (bmpdata_raw) + delete[] bmpdata_raw; syslog(LOG_DEBUG, "glcdgraphics: image %s loaded.", fileName.c_str()); return true; @@ -260,7 +285,8 @@ bool cGLCDFile::Save(cImage & image, const string & fileName) { if (bitmap->Width() == width && bitmap->Height() == height) { - if (fwrite(bitmap->Data(), height * ((width + 7) / 8), 1, fp) != 1) +// if (fwrite(bitmap->Data(), height * ((width + 7) / 8), 1, fp) != 1) + if (fwrite(bitmap->Data(), height * width, 1, fp) != 1) { fclose(fp); return false; diff --git a/glcdgraphics/pbm.c b/glcdgraphics/pbm.c index 2bca3ef..18b2ee3 100644 --- a/glcdgraphics/pbm.c +++ b/glcdgraphics/pbm.c @@ -6,7 +6,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2006 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2006-2010 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net> + * Andreas 'randy' Weinberger */ #include <stdio.h> @@ -113,18 +115,35 @@ bool cPBMFile::Load(cImage & image, const std::string & fileName) image.SetWidth(w); image.SetHeight(h); image.SetDelay(100); - unsigned char * bmpdata = new unsigned char[h * ((w + 7) / 8)]; - if (bmpdata) + + unsigned char * bmpdata_raw = new unsigned char[h * ((w + 7) / 8)]; + uint32_t * bmpdata = new uint32_t[h * w]; + if (bmpdata && bmpdata_raw) { - if (fread(bmpdata, h * ((w + 7) / 8), 1, pbmFile) != 1) - { + if (fread(bmpdata_raw, h * ((w + 7) / 8), 1, pbmFile) != 1) + { + delete[] bmpdata; + fclose(pbmFile); + image.Clear(); + return false; + } + int colsize = (w+7)/8; + for (int j = 0; j < h; j++) { + for (int i = 0; i < w; i++) { + if ( bmpdata_raw[j*colsize + (i>>3)] & (1 << (7-(i%8))) ) { + bmpdata[j*w+i] = cColor::Black; + } else { + bmpdata[j*w+i] = cColor::White; + } + } + } + delete [] bmpdata_raw; + + cBitmap * b = new cBitmap(w, h, bmpdata); + b->SetMonochrome(true); + //image.AddBitmap(new cBitmap(width, height, bmpdata)); + image.AddBitmap(b); delete[] bmpdata; - fclose(pbmFile); - image.Clear(); - return false; - } - image.AddBitmap(new cBitmap(w, h, bmpdata)); - delete[] bmpdata; } else { @@ -154,7 +173,8 @@ bool cPBMFile::Save(cImage & image, const std::string & fileName) { sprintf(str, "P4\n%d %d\n", bitmap->Width(), bitmap->Height()); fwrite(str, strlen(str), 1, fp); - fwrite(bitmap->Data(), bitmap->LineSize() * bitmap->Height(), 1, fp); +// fwrite(bitmap->Data(), bitmap->LineSize() * bitmap->Height(), 1, fp); + fwrite(bitmap->Data(), bitmap->Width() * bitmap->Height(), 1, fp); } fclose(fp); } @@ -175,7 +195,8 @@ bool cPBMFile::Save(cImage & image, const std::string & fileName) { sprintf(str, "P4\n%d %d\n", bitmap->Width(), bitmap->Height()); fwrite(str, strlen(str), 1, fp); - fwrite(bitmap->Data(), bitmap->LineSize() * bitmap->Height(), 1, fp); +// fwrite(bitmap->Data(), bitmap->LineSize() * bitmap->Height(), 1, fp); + fwrite(bitmap->Data(), bitmap->Width() * bitmap->Height(), 1, fp); } fclose(fp); } diff --git a/glcdskin/config.c b/glcdskin/config.c index 518218e..c733427 100644 --- a/glcdskin/config.c +++ b/glcdskin/config.c @@ -1,6 +1,8 @@ #include "config.h" #include "type.h" +#include <sys/time.h> + namespace GLCD { @@ -39,4 +41,13 @@ int cSkinConfig::GetTabPosition(int Index, int MaxWidth, const cFont & Font) return 0; } +uint64_t cSkinConfig::Now(void) +{ + struct timeval tv; + + gettimeofday(&tv, 0); + return (uint64_t)(tv.tv_sec * 1000 + tv.tv_usec / 1000); +} + + } // end of namespace diff --git a/glcdskin/config.h b/glcdskin/config.h index f6c8af9..eede1cc 100644 --- a/glcdskin/config.h +++ b/glcdskin/config.h @@ -15,6 +15,9 @@ #include <string> +#include <stdint.h> + +#include "../glcddrivers/driver.h" namespace GLCD { @@ -22,6 +25,7 @@ namespace GLCD class cType; class cFont; struct tSkinToken; +class cDriver; class cSkinConfig { @@ -35,6 +39,8 @@ public: virtual cType GetToken(const tSkinToken & Token); virtual int GetTokenId(const std::string & Name); virtual int GetTabPosition(int Index, int MaxWidth, const cFont & Font); + virtual uint64_t Now(void); + virtual cDriver * GetDriver(void) const { return NULL; } }; } // end of namespace diff --git a/glcdskin/display.c b/glcdskin/display.c index b92fea5..6f7a673 100644 --- a/glcdskin/display.c +++ b/glcdskin/display.c @@ -28,6 +28,32 @@ void cSkinDisplay::Render(cBitmap * screen) } +bool cSkinDisplay::NeedsUpdate(uint64_t CurrentTime) +{ + for (uint32_t i = 0; i < NumObjects(); ++i) { + if ( GetObject(i)->NeedsUpdate(CurrentTime) ) { + return true; + } + } + return false; +} + + +std::string cSkinDisplay::CheckAction(cGLCDEvent * ev) { + std::string rv = ""; + + if (!ev) + return ""; + + for (uint32_t i = 0; i < NumObjects(); ++i) { + if ( (rv = GetObject(i)->CheckAction(ev) ) != "" ) { + return rv; + } + } + return ""; +} + + cSkinDisplays::cSkinDisplays(void) { } diff --git a/glcdskin/display.h b/glcdskin/display.h index af50179..ec0ee8b 100644 --- a/glcdskin/display.h +++ b/glcdskin/display.h @@ -43,6 +43,10 @@ public: cSkinObject * GetObject(uint32_t n) const { return mObjects[n]; } void Render(cBitmap * screen); + + bool NeedsUpdate(uint64_t CurrentTime); + + std::string CheckAction(cGLCDEvent * ev); }; class cSkinDisplays: public std::vector<cSkinDisplay *> diff --git a/glcdskin/function.c b/glcdskin/function.c index 8582ad5..0fe39b3 100644 --- a/glcdskin/function.c +++ b/glcdskin/function.c @@ -33,6 +33,7 @@ static const char * Internals[] = "FontTextHeight", "ImageWidth", "ImageHeight", + "QueryFeature", NULL }; @@ -247,6 +248,10 @@ bool cSkinFunction::Parse(const std::string & Text) params = 1; break; + case funQueryFeature: + params = 1; + break; + default: break; } @@ -443,6 +448,15 @@ cType cSkinFunction::Evaluate(void) const case funImageHeight: return FunImage(mType, mParams[0]->Evaluate()); + case funQueryFeature: { + int value; + if (mSkin->Config().GetDriver()->GetFeature((const std::string)(mParams[0]->Evaluate()), value)) { + return (value) ? true : false; + } else { + return false; + } + } + default: //Dprintf("unknown function code\n"); syslog(LOG_ERR, "ERROR: Unknown function code called (this shouldn't happen)"); diff --git a/glcdskin/function.h b/glcdskin/function.h index 4b3732f..890d81f 100644 --- a/glcdskin/function.h +++ b/glcdskin/function.h @@ -70,7 +70,9 @@ public: funFontTextHeight, funImageWidth, - funImageHeight + funImageHeight, + + funQueryFeature }; private: diff --git a/glcdskin/object.c b/glcdskin/object.c index c79fa59..3a8162e 100644 --- a/glcdskin/object.c +++ b/glcdskin/object.c @@ -4,6 +4,8 @@ #include "cache.h" #include "function.h" +#include <typeinfo> + namespace GLCD { @@ -19,9 +21,11 @@ static const std::string ObjectNames[] = "text", "scrolltext", "scrollbar", + "button", "block", "list", - "item" + "item", + "condblock" }; cSkinObject::cSkinObject(cSkinDisplay * Parent) @@ -30,12 +34,14 @@ cSkinObject::cSkinObject(cSkinDisplay * Parent) mType((eType) __COUNT_OBJECT__), mPos1(0, 0), mPos2(-1, -1), - mColor(GLCD::clrBlack), + mColor(cColor(cColor::Black)), + mBackgroundColor(cColor(cColor::Transparent)), mFilled(false), mRadius(0), mArc(0), mDirection(0), mAlign(taLeft), + mVerticalAlign(tvaTop), mMultiline(false), mPath(this, false), mCurrent(this, false), @@ -43,8 +49,23 @@ cSkinObject::cSkinObject(cSkinDisplay * Parent) mFont(this, false), mText(this, false), mCondition(NULL), + mLastChange(0), + mChangeDelay(-1), // delay between two images frames: -1: not animated / don't care + mStoredImagePath(""), + mImageFrameId(0), // start with 1st frame + mScrollLoopMode(-1), // scroll (text) or loop (image) mode: default (-1) + mScrollLoopReached(false), // if scroll/loop == once: already looped once? + mScrollSpeed(0), // scroll speed: default (0) + mScrollTime(0), // scroll time interval: default (0) + mScrollOffset(0), // scroll offset (pixels) + mCurrText(""), // current text (for checks if text has changed) + mAltText(""), // alternative text source for text-objects + mAltCondition(NULL), // condition when alternative sources are used + mAction(""), // action (e.g. touchscreen action) mObjects(NULL) { + mColor = Parent->Skin()->Config().GetDriver()->GetForegroundColor(); + mBackgroundColor = Parent->Skin()->Config().GetDriver()->GetBackgroundColor(); } cSkinObject::cSkinObject(const cSkinObject & Src) @@ -54,11 +75,13 @@ cSkinObject::cSkinObject(const cSkinObject & Src) mPos1(Src.mPos1), mPos2(Src.mPos2), mColor(Src.mColor), + mBackgroundColor(Src.mBackgroundColor), mFilled(Src.mFilled), mRadius(Src.mRadius), mArc(Src.mArc), mDirection(Src.mDirection), mAlign(Src.mAlign), + mVerticalAlign(Src.mVerticalAlign), mMultiline(Src.mMultiline), mPath(Src.mPath), mCurrent(Src.mCurrent), @@ -66,6 +89,19 @@ cSkinObject::cSkinObject(const cSkinObject & Src) mFont(Src.mFont), mText(Src.mText), mCondition(Src.mCondition), + mLastChange(0), + mChangeDelay(-1), + mStoredImagePath(Src.mStoredImagePath), + mImageFrameId(0), + mScrollLoopMode(Src.mScrollLoopMode), + mScrollLoopReached(Src.mScrollLoopReached), + mScrollSpeed(Src.mScrollSpeed), + mScrollTime(Src.mScrollTime), + mScrollOffset(Src.mScrollOffset), + mCurrText(Src.mCurrText), + mAltText(Src.mAltText), + mAltCondition(Src.mAltCondition), + mAction(Src.mAction), mObjects(NULL) { if (Src.mObjects) @@ -90,15 +126,17 @@ bool cSkinObject::ParseType(const std::string & Text) return false; } -bool cSkinObject::ParseColor(const std::string & Text) +bool cSkinObject::ParseColor(const std::string & Text, cColor & ParamColor) { - if (Text == "white") - mColor = GLCD::clrWhite; - else if (Text == "black") - mColor = GLCD::clrBlack; - else - return false; - return true; + std::string text = (std::string) Text; + if (text[0] == '#') { + cSkinVariable * variable = mSkin->GetVariable(text.substr(1)); + if (variable) { + text = variable->Value().String(); + } + } + ParamColor = cColor::ParseColor(text); + return (ParamColor == cColor::ERRCOL) ? false : true; } bool cSkinObject::ParseCondition(const std::string & Text) @@ -126,6 +164,19 @@ bool cSkinObject::ParseAlignment(const std::string & Text) return true; } +bool cSkinObject::ParseVerticalAlignment(const std::string & Text) +{ + if (Text == "top") + mVerticalAlign = tvaTop; + else if (Text == "middle") + mVerticalAlign = tvaMiddle; + else if (Text == "bottom") + mVerticalAlign = tvaBottom; + else + return false; + return true; +} + bool cSkinObject::ParseIntParam(const std::string &Text, int & Param) { if (isalpha(Text[0]) || Text[0] == '#') @@ -181,6 +232,63 @@ bool cSkinObject::ParseFontFace(const std::string & Text) return mFont.Parse(Text); } + +bool cSkinObject::ParseScrollLoopMode(const std::string & Text) +{ + if (Text == "never") + mScrollLoopMode = 0; + else if (Text == "once") + mScrollLoopMode = 1; + else if (Text == "always") + mScrollLoopMode = 2; + else + return false; + return true; +} + +bool cSkinObject::ParseScrollSpeed(const std::string & Text) +{ + int val; + if (!ParseIntParam(Text, val)) + return false; + + if (val < 0 || val > 10) + return false; + + mScrollSpeed = val; + return true; +} + +bool cSkinObject::ParseScrollTime(const std::string & Text) +{ + int val; + if (!ParseIntParam(Text, val)) + return false; + + if (val < 0 || val > 2000) + return false; + + if (val > 0 && val < 100) + val = 100; + + mScrollTime = val; + return true; +} + + +bool cSkinObject::ParseAltCondition(const std::string & Text) +{ + cSkinFunction *result = new cSkinFunction(this); + if (result->Parse(Text)) + { + delete mAltCondition; + mAltCondition = result; + return true; + } + return false; +} + + void cSkinObject::SetListIndex(int MaxItems, int Index) { mText.SetListIndex(MaxItems, Index); @@ -211,22 +319,65 @@ tSize cSkinObject::Size(void) const void cSkinObject::Render(GLCD::cBitmap * screen) { + uint64_t timestamp; + if (mCondition != NULL && !mCondition->Evaluate()) return; + timestamp = mSkin->Config().Now(); + switch (Type()) { case cSkinObject::image: { cImageCache * cache = mSkin->ImageCache(); - GLCD::cImage * image = cache->Get(mPath.Evaluate()); + int currScrollLoopMode = 2; //default if not configured in the skin: always + + cType evalPath = mPath.Evaluate(); + std::string currPath = evalPath; + + if (currPath != mStoredImagePath) { + mImageFrameId = 0; + mStoredImagePath = currPath; + mScrollLoopReached = false; + mLastChange = timestamp; + mChangeDelay = -1; + } + + GLCD::cImage * image = cache->Get(evalPath); if (image) { - const GLCD::cBitmap * bitmap = image->GetBitmap(); + int framecount = image->Count(); + + const GLCD::cBitmap * bitmap = image->GetBitmap(mImageFrameId); + if (bitmap) { - screen->DrawBitmap(Pos().x, Pos().y, *bitmap, mColor); + if (mColor == cColor::ERRCOL) + screen->DrawBitmap(Pos().x, Pos().y, *bitmap); + else + screen->DrawBitmap(Pos().x, Pos().y, *bitmap, mColor, mBackgroundColor); + } + + if (mScrollLoopMode != -1) // if == -1: currScrollLoopMode already contains correct value + currScrollLoopMode = mScrollLoopMode; + + if (framecount > 1 && currScrollLoopMode > 0 && !mScrollLoopReached) { + mChangeDelay = image->Delay(); + + if ( (uint32_t)(timestamp - mLastChange) >= (uint32_t)mChangeDelay) { + + if (currScrollLoopMode == 1 && mImageFrameId+1 == framecount) { + mScrollLoopReached = true; // stop looping and switch to 1st frame + } + + mImageFrameId = (mImageFrameId+1) % framecount; + mLastChange = timestamp; + } } + + if (mLastChange == 0) + mLastChange = timestamp; } break; } @@ -301,16 +452,76 @@ void cSkinObject::Render(GLCD::cBitmap * screen) } case cSkinObject::text: + case cSkinObject::scrolltext: { cSkinFont * skinFont = mSkin->GetFont(mFont.Evaluate()); + int currScrollLoopMode = 1; // default values if no setup default values available + int currScrollSpeed = 8; + int currScrollTime = 500; + + // get default values from derived config-class if available + tSkinToken token = tSkinToken(); + token.Id = mSkin->Config().GetTokenId("ScrollMode"); + if (token.Id >= 0) { + cType t = mSkin->Config().GetToken(token); + currScrollLoopMode = (int)(t); + } + token.Id = mSkin->Config().GetTokenId("ScrollSpeed"); + if (token.Id >= 0) { + cType t = mSkin->Config().GetToken(token); + currScrollSpeed = (int)(t); + } + token.Id = mSkin->Config().GetTokenId("ScrollTime"); + if (token.Id >= 0) { + cType t = mSkin->Config().GetToken(token); + currScrollTime = (int)(t); + } + if (skinFont) { const cFont * font = skinFont->Font(); - std::string text = mText.Evaluate(); + std::string text = ""; + + // is an alternative text defined + alternative condition defined and true? + if (mAltCondition != NULL && mAltCondition->Evaluate() && (mAltText.size() != 0)) { + cSkinString *result = new cSkinString(this, false); + + if (result->Parse(mAltText)) { + text = (std::string) result->Evaluate(); + } + delete result; + } else { // nope: use the original text + text = (std::string) mText.Evaluate(); + } + + if (! (text == mCurrText) ) { + mScrollOffset = 0; + mCurrText = text; + mScrollLoopReached = false; + mLastChange = timestamp; + } + if (mMultiline) { + // scrolling in multiline not supported at the moment + mScrollLoopReached = true; // avoid check in NeedsUpdate() + std::vector <std::string> lines; font->WrapText(Size().w, Size().h, text, lines); + + // vertical alignment, calculate y offset + int yoff = 0; + int diff = Size().h - lines.size() * font->LineHeight(); + switch (mVerticalAlign) { + case tvaMiddle: + yoff = (diff > 0) ? diff >> 1 : 0; + break; + case tvaBottom: + yoff = (diff > 0) ? diff : 0; + break; + default: yoff = 0; + } + for (size_t i = 0; i < lines.size(); i++) { int w = font->Width(lines[i]); @@ -326,14 +537,30 @@ void cSkinObject::Render(GLCD::cBitmap * screen) x += (Size().w - w) / 2; } } - screen->DrawText(x, Pos().y + i * font->LineHeight(), x + Size().w - 1, lines[i], font, mColor); + screen->DrawText(x, yoff + Pos().y + i * font->LineHeight(), x + Size().w - 1, lines[i], font, mColor, mBackgroundColor); } } else { + // vertical alignment, calculate y offset + int yoff = 0; + int diff = Size().h - font->LineHeight(); + switch (mVerticalAlign) { + case tvaMiddle: + yoff = (diff > 0) ? diff >> 1 : 0; + break; + case tvaBottom: + yoff = (diff > 0) ? diff : 0; + break; + default: yoff = 0; + } + if (text.find('\t') != std::string::npos && mSkin->Config().GetTabPosition(0, Size().w, *font) > 0) { + // scrolling in texts with tabulators not supported at the moment + mScrollLoopReached = true; // avoid check in NeedsUpdate() + std::string::size_type pos1; std::string::size_type pos2; std::string str; @@ -348,7 +575,7 @@ void cSkinObject::Render(GLCD::cBitmap * screen) { str = text.substr(pos1, pos2 - pos1); tabWidth = mSkin->Config().GetTabPosition(tab, Size().w, *font); - screen->DrawText(x, Pos().y, x + tabWidth - 1, str, font, mColor); + screen->DrawText(x, yoff + Pos().y, x + tabWidth - 1, str, font, mColor, mBackgroundColor); pos1 = pos2 + 1; pos2 = text.find('\t', pos1); tabWidth += font->Width(' '); @@ -357,14 +584,18 @@ void cSkinObject::Render(GLCD::cBitmap * screen) tab++; } str = text.substr(pos1); - screen->DrawText(x, Pos().y, x + w - 1, str, font, mColor); + screen->DrawText(x, yoff + Pos().y, x + w - 1, str, font, mColor, mBackgroundColor); } else { int w = font->Width(text); int x = Pos().x; + bool updateScroll = false; + if (w < Size().w) { + mScrollLoopReached = true; // avoid check in NeedsUpdate() + if (mAlign == taRight) { x += Size().w - w; @@ -373,18 +604,105 @@ void cSkinObject::Render(GLCD::cBitmap * screen) { x += (Size().w - w) / 2; } + } else { + + if (mScrollLoopMode != -1) // if == -1: currScrollLoopMode already contains correct value + currScrollLoopMode = mScrollLoopMode; + + if (mScrollSpeed > 0) + currScrollSpeed = mScrollSpeed; + + if (mScrollTime > 0) + currScrollTime = mScrollTime; + + if (currScrollLoopMode > 0 && (!mScrollLoopReached || mScrollOffset) && + ((uint32_t)(timestamp-mLastChange) >= (uint32_t)currScrollTime) + ) + { + if (mScrollLoopReached) + mScrollOffset = 0; + else + updateScroll = true; + } + + } + + if (mScrollOffset) { + int corr_scrolloffset = mScrollOffset; + /* object update before scrolltime? use previous offset to avoid 'stumbling' scrolling */ + if ((uint32_t)(timestamp-mLastChange) < (uint32_t)currScrollTime) { + corr_scrolloffset -= currScrollSpeed; + if (corr_scrolloffset < 0) + corr_scrolloffset = 0; + } + w += font->Width(" "); + std::string textdoubled = text + " " + text; + screen->DrawText(x, yoff + Pos().y, x + Size().w - 1, textdoubled, font, mColor, mBackgroundColor, true, corr_scrolloffset); + } else { + screen->DrawText(x, yoff + Pos().y, x + Size().w - 1, text, font, mColor, mBackgroundColor, true, mScrollOffset); + } + + if (updateScroll) { + mScrollOffset += currScrollSpeed; + + if ( x + Size().w + mScrollOffset >= (w+Size().w - font->Width(" "))) { + if (currScrollLoopMode == 1) + // reset mScrollOffset in next step (else: string not redrawn when scroll done) + mScrollLoopReached = true; + else + mScrollOffset= 0; + } + updateScroll = false; + mLastChange = timestamp; } - screen->DrawText(x, Pos().y, x + Size().w - 1, text, font, mColor); } } } break; } - case cSkinObject::scrolltext: +// case cSkinObject::scrolltext: //DrawScrolltext(Object->Pos(), Object->Size(), Object->Fg(), Object->Text(), Object->Font(), // Object->Align()); +// break; + + case cSkinObject::button: + { + cSkinFont * skinFont = mSkin->GetFont(mFont.Evaluate()); + + if (mBackgroundColor == mColor || mBackgroundColor == cColor::Transparent) + mBackgroundColor = cColor(mColor).Invert(); + + if (mRadius == 0) + screen->DrawRectangle(Pos().x, Pos().y, Pos().x + Size().w - 1, Pos().y + Size().h - 1, mBackgroundColor, true); + else + screen->DrawRoundRectangle(Pos().x, Pos().y, Pos().x + Size().w - 1, Pos().y + Size().h - 1, mBackgroundColor, true, mRadius); + + if (skinFont) + { + const cFont * font = skinFont->Font(); + std::string text = ""; + + text = (std::string) mText.Evaluate(); + + if (! (text == mCurrText) ) { + mCurrText = text; + } + std::vector <std::string> lines; + font->WrapText(Size().w, Size().h, text, lines); + + // always use middle vertical alignment for buttons + int diff = Size().h - lines.size() * font->LineHeight(); + int yoff = (diff > 0) ? diff >> 1 : 0; + + int w = font->Width(text); + int x = Pos().x; + if (w < Size().w) // always center alignment for buttons + x += (Size().w - w) / 2; + screen->DrawText(x, yoff + Pos().y, x + Size().w - 1, text, font, mColor, mBackgroundColor); + } break; + } case cSkinObject::scrollbar: //DrawScrollbar(Object->Pos(), Object->Size(), Object->Bg(), Object->Fg()); @@ -430,6 +748,152 @@ void cSkinObject::Render(GLCD::cBitmap * screen) } } +bool cSkinObject::NeedsUpdate(uint64_t CurrentTime) +{ + if (mCondition != NULL && !mCondition->Evaluate()) + return false; + + switch (Type()) + { + case cSkinObject::image: + { + int currScrollLoopMode = 2; + + if (mScrollLoopMode != -1) + currScrollLoopMode = mScrollLoopMode; + + if ( mChangeDelay > 0 && currScrollLoopMode > 0 && !mScrollLoopReached && + ( (uint32_t)(CurrentTime-mLastChange) >= (uint32_t)mChangeDelay) + ) + { + return true; + } + return false; + break; + } + case cSkinObject::text: + case cSkinObject::scrolltext: + //case cSkinObject::button: + { + int currScrollLoopMode = 1; // default values if no setup default values available + int currScrollTime = 500; + + std::string text = ""; + + // is an alternative text defined + alternative condition defined and true? + if (mAltCondition != NULL && mAltCondition->Evaluate() && (mAltText.size() != 0)) { + cSkinString *result = new cSkinString(this, false); + + if (result->Parse(mAltText)) { + text = (std::string) result->Evaluate(); + } + delete result; + } else { // nope: use the original text + text = (std::string) mText.Evaluate(); + } + + // get default values from derived config-class if available + tSkinToken token = tSkinToken(); + token.Id = mSkin->Config().GetTokenId("ScrollMode"); + if (token.Id >= 0) { + cType t = mSkin->Config().GetToken(token); + currScrollLoopMode = (int)(t); + } + token.Id = mSkin->Config().GetTokenId("ScrollTime"); + if (token.Id >= 0) { + cType t = mSkin->Config().GetToken(token); + currScrollTime = (int)(t); + } + + if (mScrollLoopMode != -1) // if == -1: currScrollLoopMode already contains correct value + currScrollLoopMode = mScrollLoopMode; + + if (mScrollTime > 0) + currScrollTime = mScrollTime; + + if ( (text != mCurrText) || + ( (currScrollLoopMode > 0) && (!mScrollLoopReached || mScrollOffset) && + ((uint32_t)(CurrentTime-mLastChange) >= (uint32_t)currScrollTime) + ) + ) + { + return true; + } + return false; + break; + } + case cSkinObject::progress: + return false; + break; + case cSkinObject::block: + { + for (uint32_t i = 0; i < NumObjects(); i++) { + if ( GetObject(i)->NeedsUpdate(CurrentTime) ) { + return true; + } + } + return false; + break; + } + default: // all other elements are static ones + return false; + } + return false; +} + + +std::string cSkinObject::CheckAction(cGLCDEvent * ev) +{ + if (mCondition != NULL && !mCondition->Evaluate()) + return ""; + + switch (Type()) + { + case cSkinObject::image: + case cSkinObject::text: + case cSkinObject::scrolltext: + case cSkinObject::progress: + case cSkinObject::rectangle: + case cSkinObject::ellipse: + case cSkinObject::slope: + case cSkinObject::button: + case cSkinObject::item: + { + if (mAction == "") + return ""; + + if (ev && (typeid(*ev) == typeid(cSimpleTouchEvent))) { + cSimpleTouchEvent * stev = (cSimpleTouchEvent*)ev; + // check if touch event is in bounding box of object + // uses > and < -1 instead of >= and < -0 for better results + if ( (stev->x > Pos().x) && (stev->x < (Pos().x+Size().w -1)) && + (stev->y > Pos().y) && (stev->y < (Pos().y+Size().h -1)) + ) + { + return mAction; + } + } + return ""; + break; + } + case cSkinObject::block: + { + std::string rv = ""; + for (uint32_t i = 0; i < NumObjects(); i++) { + if ( (rv = GetObject(i)->CheckAction(ev)) != "" ) { + return rv; + } + } + return ""; + break; + } + default: + return ""; + } + return ""; +} + + cSkinObjects::cSkinObjects(void) { } diff --git a/glcdskin/object.h b/glcdskin/object.h index f164747..81fb139 100644 --- a/glcdskin/object.h +++ b/glcdskin/object.h @@ -24,6 +24,8 @@ #include "type.h" #include "string.h" +#include <glcddrivers/driver.h> + namespace GLCD { @@ -51,6 +53,13 @@ enum eTextAlignment taRight }; +enum eTextVerticalAlignment +{ + tvaTop, + tvaMiddle, + tvaBottom +}; + class cSkinObject { friend bool StartElem(const std::string & name, std::map<std::string,std::string> & attrs); @@ -70,6 +79,7 @@ public: text, scrolltext, scrollbar, + button, block, list, item, @@ -77,17 +87,19 @@ public: }; private: - cSkinDisplay * mDisplay; + cSkinDisplay * mDisplay; // parent display cSkin * mSkin; - eType mType; + eType mType; // type of object, one of enum eType tPoint mPos1; tPoint mPos2; - eColor mColor; + cColor mColor; + cColor mBackgroundColor; bool mFilled; int mRadius; int mArc; int mDirection; eTextAlignment mAlign; + eTextVerticalAlignment mVerticalAlign; bool mMultiline; cSkinString mPath; cSkinString mCurrent; @@ -96,7 +108,26 @@ private: cSkinString mText; cSkinFunction * mCondition; - cSkinObjects * mObjects; // used for block objects such as <list> + uint64_t mLastChange; // timestamp: last change in dynamic object (scroll, frame change, ...) + int mChangeDelay; // delay between two changes (frame change, scrolling, ...) + // special values: -2: no further looping (mScrollLoopMode == 'once') + // -1: not set (ie: not an animated image) + + std::string mStoredImagePath; // stored image path + int mImageFrameId; // frame ID of image + + int mScrollLoopMode; // scroll (text) or loop (image) mode: -1: default, 0: never, 1: once, 2: always + bool mScrollLoopReached; // if scroll/loop == once: already looped once? + int mScrollSpeed; // scroll speed: 0: default, [1 - 10]: speed + int mScrollTime; // scroll time interval: 0: default, [100 - 2000]: time interval + int mScrollOffset; // scroll offset (pixels) + std::string mCurrText; // current text (for checks if text has changed) + + std::string mAltText; // alternative text source for text-objects + cSkinFunction * mAltCondition; // condition when alternative sources are used + std::string mAction; // action attached to this object + + cSkinObjects * mObjects; // used for block objects such as <list> public: cSkinObject(cSkinDisplay * parent); @@ -104,19 +135,26 @@ public: ~cSkinObject(); bool ParseType(const std::string &Text); - bool ParseColor(const std::string &Text); + bool ParseColor(const std::string &Text, cColor & ParamColor); bool ParseCondition(const std::string &Text); bool ParseAlignment(const std::string &Text); + bool ParseVerticalAlignment(const std::string &Text); bool ParseFontFace(const std::string &Text); bool ParseIntParam(const std::string &Text, int & Param); bool ParseWidth(const std::string &Text); bool ParseHeight(const std::string &Text); + bool ParseScrollLoopMode(const std::string & Text); // parse scroll mode ([never|once|always]) + bool ParseScrollSpeed(const std::string & Text); // parse scroll speed + bool ParseScrollTime(const std::string & Text); // parse scroll time interval + + bool ParseAltCondition(const std::string &Text); // parse condition for alternative use (eg. alternative sources) + void SetListIndex(int MaxItems, int Index); eType Type(void) const { return mType; } cSkinFunction * Condition(void) const { return mCondition; } - cSkinDisplay * Display(void) const { return mDisplay; } + cSkinDisplay * Display(void) const { return mDisplay; } cSkin * Skin(void) const { return mSkin; } const std::string & TypeName(void) const; @@ -127,6 +165,12 @@ public: cSkinObject * GetObject(uint32_t Index) const; void Render(cBitmap * screen); + + // check if update is required for dynamic objects (image, text, progress, pane) + // false: no update required, true: update required + bool NeedsUpdate(uint64_t CurrentTime); + + std::string CheckAction(cGLCDEvent * ev); }; class cSkinObjects: public std::vector<cSkinObject *> diff --git a/glcdskin/parser.c b/glcdskin/parser.c index b137a5f..31b3106 100644 --- a/glcdskin/parser.c +++ b/glcdskin/parser.c @@ -24,20 +24,20 @@ namespace GLCD { #define TAG_ERR_REMAIN(_context) do { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Unexpected tag %s within %s", \ - name.c_str(), _context); \ + errorDetail = "Unexpected tag "+name+" within "+ _context; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } while (0) #define TAG_ERR_CHILD(_context) do { \ - syslog(LOG_ERR, "ERROR: Text2Skin: No child tag %s expected within %s", \ - name.c_str(), _context); \ + errorDetail = "No child tag "+name+" expected within "+ _context; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } while (0) #define TAG_ERR_END(_context) do { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Unexpected closing tag for %s within %s", \ - name.c_str(), _context); \ + errorDetail = "Unexpected closing tag for "+name+" within "+ _context; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } while (0) @@ -49,8 +49,8 @@ namespace GLCD #define ATTRIB_MAN_STRING(_attr,_target) \ ATTRIB_OPT_STRING(_attr,_target) \ else { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+ name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } @@ -59,8 +59,8 @@ namespace GLCD char *_e; const char *_t = attrs[_attr].c_str(); \ long _l = strtol(_t, &_e, 10); \ if (_e ==_t || *_e != '\0') { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Invalid numeric value \"%s\" in attribute %s", \ - _t, _attr); \ + errorDetail = "Invalid numeric value \""+ (std::string)_t +"\" in attribute "+ (std::string)_attr; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } else \ _target = _l; \ @@ -69,8 +69,8 @@ namespace GLCD #define ATTRIB_MAN_NUMBER(_attr,_target) \ ATTRIB_OPT_NUMBER(_attr,_target) \ else { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } @@ -81,8 +81,8 @@ namespace GLCD else if (attrs[_attr] == "no") \ _target = false; \ else { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Invalid boolean value \"%s\" in attribute %s", \ - attrs[_attr].c_str(), _attr); \ + errorDetail = "Invalid boolean value \""+ attrs[_attr] +"\" in attribute "+ _attr; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } \ } @@ -90,16 +90,16 @@ namespace GLCD #define ATTRIB_MAN_BOOL(_attr,_target) \ ATTRIB_OPT_BOOL(_attr,_target) \ else { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } #define ATTRIB_OPT_FUNC(_attr,_func) \ if (attrs.find(_attr) != attrs.end()) { \ if (!_func(attrs[_attr])) { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Unexpected value %s for attribute %s", \ - attrs[_attr].c_str(), _attr); \ + errorDetail = "Unexpected value \""+ attrs[_attr] +"\" for attribute "+ (std::string)_attr; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } \ } @@ -107,16 +107,16 @@ namespace GLCD #define ATTRIB_MAN_FUNC(_attr,_func) \ ATTRIB_OPT_FUNC(_attr,_func) \ else { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } #define ATTRIB_OPT_FUNC_PARAM(_attr,_func,_param) \ if (attrs.find(_attr) != attrs.end()) { \ if (!_func(attrs[_attr],_param)) { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Unexpected value %s for attribute %s", \ - attrs[_attr].c_str(), _attr); \ + errorDetail = "Unexpected value "+ attrs[_attr] +" for attribute "+ (std::string)_attr; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } \ } @@ -124,8 +124,8 @@ namespace GLCD #define ATTRIB_MAN_FUNC_PARAM(_attr,_func,_param) \ ATTRIB_OPT_FUNC_PARAM(_attr,_func,_param) \ else { \ - syslog(LOG_ERR, "ERROR: Text2Skin: Mandatory attribute %s missing in tag %s", \ - _attr, name.c_str()); \ + errorDetail = "Mandatory attribute "+ (std::string)_attr +" missing in tag "+name; \ + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); \ return false; \ } @@ -133,31 +133,93 @@ static std::vector<std::string> context; static cSkin * skin = NULL; static cSkinFont * font = NULL; static cSkinVariable * variable = NULL; +static cSkinVariable * variable_default = NULL; static cSkinDisplay * display = NULL; static std::vector <cSkinObject *> parents; static cSkinObject * object = NULL; static uint32_t oindex = 0; +static std::string errorDetail = ""; +static std::string condblock_cond = ""; + + +static bool CheckSkinVersion(const std::string & version) { + float currv; + char* ecptr = NULL; + const char* verscstr = version.c_str(); + currv = strtof(verscstr, &ecptr); + if ( (*ecptr != '\0') || (ecptr == NULL) /*|| (ecptr != verscstr)*/ || + ((int)(GLCDSKIN_SKIN_VERSION * 100.0) < (int)(currv * 100.0)) + ) + { + return false; + } + return true; +} + + bool StartElem(const std::string & name, std::map<std::string,std::string> & attrs) { //printf("start element: %s\n", name.c_str()); - +// if (context.size() > 0) fprintf(stderr, "context: %s\n", context[context.size() - 1].c_str()); if (context.size() == 0) { if (name == "skin") { ATTRIB_MAN_STRING("version", skin->version); ATTRIB_MAN_STRING("name", skin->title); + ATTRIB_OPT_FUNC("enable", skin->ParseEnable); + + if (! CheckSkinVersion(skin->version) ) { + errorDetail = "skin version '"+ skin->version +"' not supported."; + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); + return false; + } } else TAG_ERR_REMAIN("document"); } + else if (name == "condblock") + { + int i = context.size() - 1; + while (i >= 0) { + if (context[i] == "condblock") { + errorDetail = "'condblock' must not be nested in another 'condblock'."; + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); + return false; + } + i--; + } + ATTRIB_MAN_STRING("condition", condblock_cond); + } else if (name == "variable") { variable = new cSkinVariable(skin); ATTRIB_MAN_STRING("id", variable->mId); ATTRIB_MAN_FUNC("value", variable->ParseValue); - ATTRIB_OPT_FUNC("condition", variable->ParseCondition); + if (context[context.size() - 1] == "condblock") { + if (attrs.find("condition") != attrs.end()) { + errorDetail = "variable \""+variable->mId+"\" must not contain a condition when context = 'condblock'."; + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); + return false; + } else { + if (! variable->ParseCondition(condblock_cond)) { + errorDetail = "Unexpected value \""+ attrs["condition"] +"\" for attribute "+ (std::string)"condition"; + syslog(LOG_ERR, "ERROR: graphlcd/skin: %s", errorDetail.c_str()); + return false; + } + } + } else { + ATTRIB_OPT_FUNC("condition", variable->ParseCondition); + } + // if a 'default' value is set, create a second variable w/o condition: will be used if condition is not true + // as variables all have global scope (no matter where defined) and will always be sought from the start of the array, + // the default variable will be inserted _after_ the variable containing the condition. + if (attrs.find("default") != attrs.end()) { + variable_default = new cSkinVariable(skin); + ATTRIB_MAN_STRING("id", variable_default->mId); + ATTRIB_MAN_FUNC("default", variable_default->ParseValue); + } } else if (context[context.size() - 1] == "skin") { @@ -196,6 +258,7 @@ bool StartElem(const std::string & name, std::map<std::string,std::string> & att ATTRIB_OPT_FUNC("width", object->ParseWidth); ATTRIB_OPT_FUNC("height", object->ParseHeight); ATTRIB_OPT_FUNC("condition", object->ParseCondition); + ATTRIB_OPT_STRING("action", object->mAction); if (name == "image") { @@ -203,57 +266,57 @@ bool StartElem(const std::string & name, std::map<std::string,std::string> & att ATTRIB_OPT_FUNC_PARAM("y", object->ParseIntParam, object->mPos1.y); ATTRIB_OPT_FUNC_PARAM("x", object->ParseIntParam, object->mPos2.x); ATTRIB_OPT_FUNC_PARAM("y", object->ParseIntParam, object->mPos2.y); - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); + ATTRIB_OPT_FUNC_PARAM("bgcolor", object->ParseColor, object->mBackgroundColor); ATTRIB_MAN_FUNC("path", object->mPath.Parse); + ATTRIB_OPT_FUNC("loop", object->ParseScrollLoopMode); } else if (name == "text" || name == "scrolltext") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); + ATTRIB_OPT_FUNC_PARAM("bgcolor", object->ParseColor, object->mBackgroundColor); ATTRIB_OPT_FUNC("align", object->ParseAlignment); + ATTRIB_OPT_FUNC("valign", object->ParseVerticalAlignment); ATTRIB_OPT_FUNC("font", object->ParseFontFace); ATTRIB_OPT_BOOL("multiline", object->mMultiline); -#if 0 - if (name == "blink") - { - ATTRIB_OPT_NUMBER("delay", object->mDelay); - - if (object->mDelay == 0) - object->mDelay = 1000; - } - else if (name == "marquee") - { - ATTRIB_OPT_NUMBER("delay", object->mDelay); - - if (object->mDelay == 0) - object->mDelay = 500; - } -#endif + ATTRIB_OPT_FUNC("scrollmode", object->ParseScrollLoopMode); + ATTRIB_OPT_FUNC("scrollspeed", object->ParseScrollSpeed); + ATTRIB_OPT_FUNC("scrolltime", object->ParseScrollTime); + ATTRIB_OPT_STRING("alttext", object->mAltText); + ATTRIB_OPT_FUNC("altcondition", object->ParseAltCondition); + } + else if (name == "button") + { + ATTRIB_OPT_FUNC_PARAM("labelcolor", object->ParseColor, object->mColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mBackgroundColor); + ATTRIB_OPT_FUNC("font", object->ParseFontFace); + ATTRIB_OPT_NUMBER("radius", object->mRadius); } else if (name == "pixel") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); } else if (name == "line") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); } else if (name == "rectangle") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); ATTRIB_OPT_BOOL("filled", object->mFilled); ATTRIB_OPT_NUMBER("radius", object->mRadius); } else if (name == "ellipse" || name == "slope") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); ATTRIB_OPT_BOOL("filled", object->mFilled); ATTRIB_OPT_NUMBER("arc", object->mArc); } else if (name == "progress" || name == "scrollbar") { - ATTRIB_OPT_FUNC("color", object->ParseColor); + ATTRIB_OPT_FUNC_PARAM("color", object->ParseColor, object->mColor); ATTRIB_OPT_NUMBER("direction", object->mDirection); ATTRIB_OPT_FUNC("current", object->mCurrent.Parse); ATTRIB_OPT_FUNC("total", object->mTotal.Parse); @@ -284,7 +347,8 @@ bool CharData(const std::string & text) //printf("context: %s\n", context[context.size() - 1].c_str()); if (context[context.size() - 1] == "text" - || context[context.size() - 1] == "scrolltext") + || context[context.size() - 1] == "scrolltext" + || context[context.size() - 1] == "button") { if (!object->mText.Parse(text)) return false; @@ -307,7 +371,13 @@ bool EndElem(const std::string & name) else if (name == "variable") { skin->mVariables.push_back(variable); +//fprintf(stderr, " variable '%s', value: %s\n", variable->mId.c_str(), ((std::string)variable->Value()).c_str()); variable = NULL; + if (variable_default != NULL) { + skin->mVariables.push_back(variable_default); +//fprintf(stderr, " variable default '%s', value: %s\n", variable_default->mId.c_str(), ((std::string)variable_default->Value()).c_str()); + variable_default = NULL; + } } else if (name == "display") { @@ -320,7 +390,7 @@ bool EndElem(const std::string & name) { if (object == NULL) { - printf("rotating parent to object\n"); + //printf("rotating parent to object\n"); object = parents[parents.size() - 1]; parents.pop_back(); } @@ -343,7 +413,7 @@ bool EndElem(const std::string & name) #endif if (parents.size() > 0) { - printf("pushing to parent\n"); + //printf("pushing to parent\n"); cSkinObject *parent = parents[parents.size() - 1]; if (parent->mObjects == NULL) parent->mObjects = new cSkinObjects(); @@ -360,7 +430,7 @@ bool EndElem(const std::string & name) return true; } -cSkin * XmlParse(cSkinConfig & Config, const std::string & Name, const std::string & fileName) +cSkin * XmlParse(cSkinConfig & Config, const std::string & Name, const std::string & fileName, std::string & errorString) { skin = new cSkin(Config, Name); context.clear(); @@ -371,7 +441,13 @@ cSkin * XmlParse(cSkinConfig & Config, const std::string & Name, const std::stri xml.SetCDataCB(CharData); if (xml.Parse() != 0) { - syslog(LOG_ERR, "ERROR: Text2Skin: Parse error in %s, line %d", fileName.c_str(), xml.LineNr()); + char buff[8]; + snprintf(buff, 7, "%d", xml.LineNr()); + syslog(LOG_ERR, "ERROR: graphlcd/skin: Parse error in %s, line %d", fileName.c_str(), xml.LineNr()); + // shorter version outgoing errorString (eg. displaying errorString on the display) + errorString = "Parse error in skin "+Name+", line "+buff; + if (errorDetail != "") + errorString += ":\n"+errorDetail; delete skin; skin = NULL; delete display; @@ -383,6 +459,7 @@ cSkin * XmlParse(cSkinConfig & Config, const std::string & Name, const std::stri cSkin * result = skin; skin = NULL; + errorString = ""; return result; } diff --git a/glcdskin/parser.h b/glcdskin/parser.h index d7d7f63..f8b2a2e 100644 --- a/glcdskin/parser.h +++ b/glcdskin/parser.h @@ -16,13 +16,22 @@ #include <string> +#define GLCDSKIN_SKIN_VERSION 1.1 + + namespace GLCD { class cSkin; class cSkinConfig; -cSkin * XmlParse(cSkinConfig & Config, const std::string & name, const std::string & fileName); +cSkin * XmlParse(cSkinConfig & Config, const std::string & name, const std::string & fileName, std::string & errorString); + +// provide old function for compatibility +cSkin * XmlParse(cSkinConfig & Config, const std::string & name, const std::string & fileName) +{ std::string errorString = ""; + return XmlParse(Config, name, fileName, errorString); +} } // end of namespace diff --git a/glcdskin/skin.c b/glcdskin/skin.c index a7facdd..c4e8e4b 100644 --- a/glcdskin/skin.c +++ b/glcdskin/skin.c @@ -79,4 +79,16 @@ cSkinVariable * cSkin::GetVariable(const std::string & Id) } +bool cSkin::ParseEnable(const std::string & Text) +{ + cDriver * driver = config.GetDriver(); + + if (!driver) + return false; + + driver->SetFeature(Text, 1); + return true; // always return true else loading the skin would fail if touchscreen is not available +} + + } // end of namespace diff --git a/glcdskin/skin.h b/glcdskin/skin.h index b2d8496..b13db0a 100644 --- a/glcdskin/skin.h +++ b/glcdskin/skin.h @@ -61,6 +61,16 @@ public: const tSize & BaseSize(void) const { return baseSize; } cImageCache * ImageCache(void) { return mImageCache; } + + bool ParseEnable(const std::string &Text); + +#ifdef GRAPHLCD_CBITMAP_ARGB + cColor GetBackgroundColor(void) { return config.GetDriver()->GetBackgroundColor(); } + cColor GetForegroundColor(void) { return config.GetDriver()->GetForegroundColor(); } +#else + eColor GetBackgroundColor(void) { return config.GetDriver()->GetBackgroundColor(); } + eColor GetForegroundColor(void) { return config.GetDriver()->GetForegroundColor(); } +#endif }; } // end of namespace diff --git a/glcdskin/string.c b/glcdskin/string.c index dc9d9dc..90a1670 100644 --- a/glcdskin/string.c +++ b/glcdskin/string.c @@ -85,6 +85,13 @@ void cSkinString::Reparse(void) } } + +// copied from xml.c (should be valid for parsing variable names too ...) +static bool IsTokenChar(bool start, int c) { + return isalpha(c) || c == '_' || (!start && isdigit(c)); +} + + bool cSkinString::Parse(const std::string & Text, bool Translate) { std::string trans = Translate ? mSkin->Config().Translate(Text) : Text; @@ -93,16 +100,6 @@ bool cSkinString::Parse(const std::string & Text, bool Translate) bool inAttrib = false; int offset = 0; - if (trans[0] == '#') - { - cSkinVariable * variable = mSkin->GetVariable(trans.substr(1)); - if (variable) - { - trans = (std::string) variable->Value(); - syslog(LOG_ERR, "string variable %s", trans.c_str()); - } - } - //Dprintf("parsing: %s\n", Text.c_str()); mOriginal = Text; mText = ""; @@ -120,6 +117,29 @@ bool cSkinString::Parse(const std::string & Text, bool Translate) ++ptr; continue; } + else if (*ptr == '#') { + if (inToken) { + syslog(LOG_ERR, "ERROR: Unexpected '#' in token"); + return false; + } + + mText.append(last, ptr - last); + + bool isStartChar = true; + const char * varNameStart = ptr; + ptr++; + while (*ptr && IsTokenChar(isStartChar, *ptr)) { + isStartChar = false; + ptr++; + offset++; + } + // add #VARNAME# + mText.append(varNameStart, (ptr - varNameStart)); + mText.append("#"); + offset ++; // # adds one character -> fix offset + ptr--; // we'd be at the correct position now but the for-loop does a ++ptr -> fix it by stepping back one char + last = ptr + 1; + } else if (*ptr == '{') { if (inToken) { syslog(LOG_ERR, "ERROR: Unexpected '{' in token"); @@ -179,8 +199,10 @@ bool cSkinString::Parse(const std::string & Text, bool Translate) { std::string tmp; tmp.assign(last, ptr - last); - tSkinToken token(mSkin->Config().GetTokenId(tmp), tmp, offset, ""); - mTokens.push_back(token); + if (tmp != "") { // ignore empty token + tSkinToken token(mSkin->Config().GetTokenId(tmp), tmp, offset, ""); + mTokens.push_back(token); + } } else { @@ -214,19 +236,35 @@ bool cSkinString::Parse(const std::string & Text, bool Translate) cType cSkinString::Evaluate(void) const { - std::string result; + std::string result_raw = "", result_trans = ""; int offset = 0; if (mText.length() == 0 && mTokens.size() == 1) return mSkin->Config().GetToken(mTokens[0]); for (uint32_t i = 0; i < mTokens.size(); ++i) { - result.append(mText.c_str() + offset, mTokens[i].Offset - offset); - result.append(mSkin->Config().GetToken(mTokens[i])); + result_raw.append(mText.c_str() + offset, mTokens[i].Offset - offset); + result_raw.append(mSkin->Config().GetToken(mTokens[i])); offset = mTokens[i].Offset; } - result.append(mText.c_str() + offset); - return result; + result_raw.append(mText.c_str() + offset); + + // replace variable placeholders (#VARNAME#) with corresponding values + size_t idxstart = 0, idxend = 0; + size_t pos = 0; + while ( (idxstart=result_raw.find("#", idxstart)) != std::string::npos ) { + result_trans.append(result_raw.substr(pos, idxstart-pos)); + idxend = result_raw.find("#", idxstart+1); + cSkinVariable * variable = mSkin->GetVariable(result_raw.substr(idxstart+1, idxend-idxstart-1)); + if (variable) { + result_trans.append ((std::string) variable->Value()); + // syslog(LOG_ERR, "string variable %s", trans.c_str()); + } + idxstart = idxend+1; + pos = idxstart; + } + result_trans.append(result_raw.substr(pos)); + return result_trans; } } // end of namespace diff --git a/tools/convpic/bmp.c b/tools/convpic/bmp.c index 0829302..0357988 100644 --- a/tools/convpic/bmp.c +++ b/tools/convpic/bmp.c @@ -89,7 +89,8 @@ bool cBMPFile::Load(GLCD::cImage & image, const std::string & fileName) long iSize; uint32_t x, y; uint16_t iRead; - uint8_t * bitmap = NULL; +// uint8_t * bitmap = NULL; + uint32_t *bitmap = NULL; bool bInvert = false; if (fileName.length() > 0) @@ -163,7 +164,8 @@ bool cBMPFile::Load(GLCD::cImage & image, const std::string & fileName) image.SetWidth(bmpHeader.bmpWidth); image.SetHeight(bmpHeader.bmpHeight); image.SetDelay(100); - bitmap = new unsigned char[bmpHeader.bmpHeight * ((bmpHeader.bmpWidth + 7) / 8)]; +// bitmap = new unsigned char[bmpHeader.bmpHeight * ((bmpHeader.bmpWidth + 7) / 8)]; + bitmap = new uint32_t [bmpHeader.bmpHeight * bmpHeader.bmpWidth]; if (!bitmap) { fprintf(stderr, "ERROR: cannot allocate memory\n"); @@ -260,7 +262,8 @@ bool cBMPFile::Save(const GLCD::cBitmap * bitmap, const std::string & fileName) char Dummy = 0x00; uint32_t x, y; uint16_t iWrote; - const uint8_t * bmpdata = bitmap->Data(); +// const uint8_t * bmpdata = bitmap->Data(); + const uint32_t * bmpdata = bitmap->Data(); if (bitmap && bitmap->Width() > 0 diff --git a/tools/convpic/tiff.c b/tools/convpic/tiff.c index 4b8bf0e..3eb8cad 100644 --- a/tools/convpic/tiff.c +++ b/tools/convpic/tiff.c @@ -71,7 +71,8 @@ bool cTIFFFile::Load(GLCD::cImage & image, const std::string & fileName) unsigned char fLittleEndian=0; int j; int t; - unsigned char *bitmap = NULL; +// unsigned char *bitmap = NULL; + uint32_t *bitmap = NULL; bool bInvert = false; if (fileName.length() > 0) @@ -152,7 +153,8 @@ bool cTIFFFile::Load(GLCD::cImage & image, const std::string & fileName) image.SetWidth(width); image.SetHeight(height); image.SetDelay(100); - bitmap = new unsigned char[height * ((width + 7) / 8)]; +// bitmap = new unsigned char[height * ((width + 7) / 8)]; + bitmap = new uint32_t[height * width]; if (bitmap) { if (fread(bitmap, height*((width+7)/8), 1, fIN)!=1) diff --git a/tools/convpic/tuxbox.c b/tools/convpic/tuxbox.c index 55d6e1d..9e3f558 100644 --- a/tools/convpic/tuxbox.c +++ b/tools/convpic/tuxbox.c @@ -118,15 +118,19 @@ bool cTuxBoxFile::Load(GLCD::cImage & image, const std::string & fileName) for (unsigned int n=0;n<ntohs(header.count);++n) { ret = false; - unsigned int nBmpSize = image.Height() * ((image.Width() + 7) / 8); - unsigned char *bitmap = new unsigned char[nBmpSize]; +// unsigned int nBmpSize = image.Height() * ((image.Width() + 7) / 8); + unsigned int nBmpSize = image.Height() * image.Width(); +// unsigned char *bitmap = new unsigned char[nBmpSize]; + uint32_t *bitmap = new uint32_t [nBmpSize]; if (!bitmap) { fprintf(stderr, "ERROR: malloc failed."); break; } - unsigned int nAniSize = image.Width() * ((image.Height() + 7) / 8); - unsigned char *pAni = new unsigned char[nAniSize]; +// unsigned int nAniSize = image.Width() * ((image.Height() + 7) / 8); + unsigned int nAniSize = image.Width() * image.Height(); +// unsigned char *pAni = new unsigned char[nAniSize]; + uint32_t *pAni = new uint32_t [nAniSize]; if (!pAni) { delete[] bitmap; @@ -200,7 +204,8 @@ bool cTuxBoxFile::Save(GLCD::cImage & image, const std::string & fileName) { bRet = false; unsigned int nAniSize = image.Width() * ((image.Height() + 7) / 8); - unsigned char *pAni = new unsigned char[nAniSize]; +// unsigned char *pAni = new unsigned char[nAniSize]; + uint32_t *pAni = new uint32_t [nAniSize]; if (!pAni) { fprintf(stderr, "ERROR: malloc failed."); @@ -233,7 +238,8 @@ rotate from {Byte} to {Byte} {o}[o][o][o][o][o][o][o] => [ oooooooo ] {o}[o][o][o][o][o][o][o] => [ oooooooo ] {o}[o][o][o][o][o][o][o] => [ oooooooo ]*/ -void cTuxBoxFile::vert2horz(const unsigned char* source, unsigned char* dest, int width, int height) { +//void cTuxBoxFile::vert2horz(const unsigned char* source, unsigned char* dest, int width, int height) { +void cTuxBoxFile::vert2horz(const uint32_t *source, uint32_t *dest, int width, int height) { int x, y, off; memset(dest,0,height*((width+7)/8)); @@ -261,7 +267,8 @@ rotate from {Byte} to {Byte} [ oooooooo ] => {o}[o][o][o][o][o][o][o] [ oooooooo ] => {o}[o][o][o][o][o][o][o] [ oooooooo ] => {o}[o][o][o][o][o][o][o]*/ -void cTuxBoxFile::horz2vert(const unsigned char* source, unsigned char* dest, int width, int height) { +//void cTuxBoxFile::horz2vert(const unsigned char* source, unsigned char* dest, int width, int height) { +void cTuxBoxFile::horz2vert(const uint32_t *source, uint32_t *dest, int width, int height) { int x, y, off; memset(dest,0,width*((height+7)/8)); diff --git a/tools/convpic/tuxbox.h b/tools/convpic/tuxbox.h index 1214fb5..8d19ebd 100644 --- a/tools/convpic/tuxbox.h +++ b/tools/convpic/tuxbox.h @@ -32,8 +32,10 @@ class cTuxBoxFile : public GLCD::cImageFile { private: - void vert2horz(const unsigned char* source, unsigned char* dest, int width, int height); - void horz2vert(const unsigned char* source, unsigned char* dest, int width, int height); +// void vert2horz(const unsigned char* source, unsigned char* dest, int width, int height); +// void horz2vert(const unsigned char* source, unsigned char* dest, int width, int height); + void vert2horz(const uint32_t *source, uint32_t *dest, int width, int height); + void horz2vert(const uint32_t *source, uint32_t *dest, int width, int height); public: cTuxBoxFile(); virtual ~cTuxBoxFile(); diff --git a/tools/genfont/genfont.c b/tools/genfont/genfont.c index 7553e4c..ce9698d 100644 --- a/tools/genfont/genfont.c +++ b/tools/genfont/genfont.c @@ -7,7 +7,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net> + * Andreas 'randy' Weinberger */ #include <getopt.h> @@ -142,7 +144,7 @@ int main(int argc, char *argv[]) if (charBitmap == NULL) continue; - bitmap->DrawBitmap(posX, posY, *charBitmap, GLCD::clrBlack); + bitmap->DrawBitmap(posX, posY, *charBitmap); fprintf(descFile, "%d %d ", posX, i); posX += charBitmap->Width(); if ((i % 32) == 31) diff --git a/tools/showpic/showpic.c b/tools/showpic/showpic.c index f17f361..53e5c0e 100644 --- a/tools/showpic/showpic.c +++ b/tools/showpic/showpic.c @@ -9,7 +9,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net> + * Andreas 'randy' Weinberger */ #include <stdio.h> @@ -227,7 +229,8 @@ int main(int argc, char *argv[]) while ((bitmap = image.GetBitmap()) != NULL && !stopProgramm) { - lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height(), bitmap->LineSize()); +// lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height(), bitmap->LineSize()); + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); lcd->Refresh(true); if (image.Next(0)) // Select next image diff --git a/tools/showtext/showtext.c b/tools/showtext/showtext.c index 2621db1..b156935 100644 --- a/tools/showtext/showtext.c +++ b/tools/showtext/showtext.c @@ -6,7 +6,9 @@ * This file is released under the GNU General Public License. Refer * to the COPYING file distributed with this package. * - * (c) 2004 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2004-2010 Andreas Regel <andreas.regel AT powarman.de> + * (c) 2010-2011 Wolfgang Astleitner <mrwastl AT users sourceforge net> + * Andreas 'randy' Weinberger */ #include <stdio.h> @@ -269,7 +271,8 @@ int main(int argc, char *argv[]) bitmap->DrawText(x, y, bitmap->Width() - 1, text, &font); y += font.LineHeight(); } - lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height(), bitmap->LineSize()); +// lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height(), bitmap->LineSize()); + lcd->SetScreen(bitmap->Data(), bitmap->Width(), bitmap->Height()); lcd->Refresh(true); lcd->DeInit(); |