diff options
| author | Tectu <joel@unormal.org> | 2012-10-30 01:27:06 -0700 | 
|---|---|---|
| committer | Tectu <joel@unormal.org> | 2012-10-30 01:27:06 -0700 | 
| commit | 377f80d0cae500e49d103aafe7e1532ba8d40ca0 (patch) | |
| tree | a78f9434ae3b7a91ede62e8e1622be6eba015b11 /src | |
| parent | a55da05d2e0de3aad7cf7b1c12700a141e9e88b2 (diff) | |
| parent | d3b4c499ab0267dbcad3d5972bb0317fdba9043e (diff) | |
| download | uGFX-377f80d0cae500e49d103aafe7e1532ba8d40ca0.tar.gz uGFX-377f80d0cae500e49d103aafe7e1532ba8d40ca0.tar.bz2 uGFX-377f80d0cae500e49d103aafe7e1532ba8d40ca0.zip  | |
Merge pull request #12 from inmarket/master
GDISP fixes and new routines. Many GWIN changes.
Diffstat (limited to 'src')
| -rw-r--r-- | src/gdisp.c | 444 | ||||
| -rw-r--r-- | src/gwin.c | 752 | 
2 files changed, 752 insertions, 444 deletions
diff --git a/src/gdisp.c b/src/gdisp.c index 82130b7c..5a3aff13 100644 --- a/src/gdisp.c +++ b/src/gdisp.c @@ -494,220 +494,124 @@  	}
  #endif
 -#if GDISP_NEED_ARC || defined(__DOXYGEN__)
 -
 -#include "math.h"
 +#if (GDISP_NEED_ARC && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__)
 +	/*
 +	 * @brief	Draw an arc.
 +	 * @pre		The GDISP must be in powerOn or powerSleep mode.
 +	 *
 +	 * @param[in] x0,y0		The center point
 +	 * @param[in] radius	The radius of the arc
 +	 * @param[in] start		The start angle (0 to 360)
 +	 * @param[in] end		The end angle (0 to 360)
 +	 * @param[in] color		The color of the arc
 +	 *
 +	 * @api
 +	 */
 +	void gdispDrawArc(coord_t x, coord_t y, coord_t radius, uint16_t start, uint16_t end, color_t color) {
 +		chMtxLock(&gdispMutex);
 +		GDISP_LLD(drawarc)(x, y, radius, start, end, color);
 +		chMtxUnlock();
 +	}
 +#elif GDISP_NEED_ARC && GDISP_NEED_ASYNC
 +	void gdispDrawArc(coord_t x, coord_t y, coord_t radius, uint16_t start, uint16_t end, color_t color) {
 +		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_DRAWARC);
 +		p->drawarc.x = x;
 +		p->drawarc.y = y;
 +		p->drawarc.radius = radius;
 +		p->drawarc.start = start;
 +		p->drawarc.end = end;
 +		p->drawarc.color = color;
 +		chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
 +	}
 +#endif
 -/*
 - * @brief				Internal helper function for gdispDrawArc()
 - *
 - * @note				DO NOT USE DIRECTLY!
 - *
 - * @param[in] x, y		The middle point of the arc
 - * @param[in] start		The start angle of the arc
 - * @param[in] end		The end angle of the arc
 - * @param[in] radius	The radius of the arc
 - * @param[in] color		The color in which the arc will be drawn
 - *
 - * @notapi
 - */
 -void _draw_arc(coord_t x, coord_t y, uint16_t start, uint16_t end, uint16_t radius, color_t color) {
 -    if(start > 0 && start <= 180) {
 -        float x_maxI = x + radius*cos(start*M_PI/180);
 -        float x_minI;
 -
 -        if (end > 180)
 -            x_minI = x - radius;
 -        else
 -            x_minI = x + radius*cos(end*M_PI/180);
 -
 -        int a = 0;
 -        int b = radius;
 -        int P = 1 - radius;
 -
 -        do { 
 -            if(x-a <= x_maxI && x-a >= x_minI)
 -                gdispDrawPixel(x-a, y+b, color);
 -            if(x+a <= x_maxI && x+a >= x_minI)
 -                gdispDrawPixel(x+a, y+b, color);
 -            if(x-b <= x_maxI && x-b >= x_minI)
 -                gdispDrawPixel(x-b, y+a, color);
 -            if(x+b <= x_maxI && x+b >= x_minI)
 -                gdispDrawPixel(x+b, y+a, color);
 -
 -            if (P < 0) {
 -                P = P + 3 + 2*a;
 -                a = a + 1;
 -            } else {
 -                P = P + 5 + 2*(a - b);
 -                a = a + 1;
 -                b = b - 1;
 -            }
 -        } while(a <= b);
 -    }
 -
 -    if (end > 180 && end <= 360) {
 -        float x_maxII = x+radius*cos(end*M_PI/180);
 -        float x_minII;
 -
 -        if(start <= 180)
 -            x_minII = x - radius;
 -        else
 -            x_minII = x+radius*cos(start*M_PI/180);
 -
 -        int a = 0;
 -        int b = radius;
 -        int P = 1 - radius;
 -
 -        do {
 -            if(x-a <= x_maxII && x-a >= x_minII)
 -                gdispDrawPixel(x-a, y-b, color);
 -            if(x+a <= x_maxII && x+a >= x_minII)
 -                gdispDrawPixel(x+a, y-b, color);
 -            if(x-b <= x_maxII && x-b >= x_minII)
 -                gdispDrawPixel(x-b, y-a, color);
 -            if(x+b <= x_maxII && x+b >= x_minII)
 -                gdispDrawPixel(x+b, y-a, color);
 -
 -            if (P < 0) {
 -                P = P + 3 + 2*a;
 -                a = a + 1;
 -            } else {
 -                P = P + 5 + 2*(a - b);
 -                a = a + 1;
 -                b = b - 1;
 -            }
 -        } while (a <= b);
 -    }
 -}
 +#if (GDISP_NEED_ARC && GDISP_NEED_MULTITHREAD) || defined(__DOXYGEN__)
 +	/*
 +	 * @brief	Draw a filled arc.
 +	 * @pre		The GDISP must be in powerOn or powerSleep mode.
 +	 * @note				Not very efficient currently - does lots of overdrawing
 +	 *
 +	 * @param[in] x0,y0		The center point
 +	 * @param[in] radius	The radius of the arc
 +	 * @param[in] start		The start angle (0 to 360)
 +	 * @param[in] end		The end angle (0 to 360)
 +	 * @param[in] color		The color of the arc
 +	 *
 +	 * @api
 +	 */
 +	void gdispFillArc(coord_t x, coord_t y, coord_t radius, uint16_t start, uint16_t end, color_t color) {
 +		chMtxLock(&gdispMutex);
 +		GDISP_LLD(fillarc)(x, y, radius, start, end, color);
 +		chMtxUnlock();
 +	}
 +#elif GDISP_NEED_ARC && GDISP_NEED_ASYNC
 +	void gdispFillArc(coord_t x, coord_t y, coord_t radius, uint16_t start, uint16_t end, color_t color) {
 +		gdisp_lld_msg_t *p = gdispAllocMsg(GDISP_LLD_MSG_FILLARC);
 +		p->fillarc.x = x;
 +		p->fillarc.y = y;
 +		p->fillarc.radius = radius;
 +		p->fillarc.start = start;
 +		p->fillarc.end = end;
 +		p->fillarc.color = color;
 +		chMBPost(&gdispMailbox, (msg_t)p, TIME_INFINITE);
 +	}
 +#endif
 -/*
 - * @brief	Draw an arc.
 - * @pre		The GDISP must be in powerOn or powerSleep mode.
 +#if GDISP_NEED_ARC || defined(__DOXYGEN__)
 +/**
 + * @brief   Draw a rectangular box with rounded corners
 + * @pre     The GDISP unit must be in powerOn or powerSleep mode.
   *
 - * @param[in] x0,y0		The center point
 - * @param[in] radius	The radius of the arc
 - * @param[in] start		The start angle (0 to 360)
 - * @param[in] end		The end angle (0 to 360)
 - * @param[in] color		The color of the arc
 + * @param[in] x,y		The start position
 + * @param[in] cx,cy		The size of the box (outside dimensions)
 + * @param[in] radius	The radius of the rounded corners
 + * @param[in] color		The color to use
   *
   * @api
   */
 -void gdispDrawArc(coord_t x, coord_t y, coord_t radius, uint16_t start, uint16_t end, color_t color) {
 -	if(end < start) {
 -        _draw_arc(x, y, start, 360, radius, color);
 -        _draw_arc(x, y, 0, end, radius, color);
 -    } else {
 -        _draw_arc(x, y, start, end, radius, color);
 +void gdispDrawRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) {
 +	if (2*radius > cx || 2*radius > cy) {
 +		gdispDrawBox(x, y, cx, cy, color);
 +		return;
  	}
 +	gdispDrawArc(x+radius, y+radius, radius, 90, 180, color);
 +	gdispDrawLine(x+radius+1, y, x+cx-2-radius, y, color);
 +	gdispDrawArc(x+cx-1-radius, y+radius, radius, 0, 90, color);
 +	gdispDrawLine(x+cx-1, y+radius+1, x+cx-1, y+cy-2-radius, color);
 +	gdispDrawArc(x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color);
 +	gdispDrawLine(x+radius+1, y+cy-1, x+cx-2-radius, y+cy-1, color);
 +	gdispDrawArc(x+radius, y+cy-1-radius, radius, 180, 270, color);
 +	gdispDrawLine(x, y+radius+1, x, y+cy-2-radius, color);
  }
  #endif
  #if GDISP_NEED_ARC || defined(__DOXYGEN__)
 -/*
 - * @brief				Internal helper function for gdispFillArc()
 - *
 - * @note				DO NOT USE DIRECTLY!
 - * @note				Not very efficient currently - does lots of overdrawing
 - *
 - * @param[in] x, y		The middle point of the arc
 - * @param[in] start		The start angle of the arc
 - * @param[in] end		The end angle of the arc
 - * @param[in] radius	The radius of the arc
 - * @param[in] color		The color in which the arc will be drawn
 - *
 - * @notapi
 - */
 -void _fill_arc(coord_t x, coord_t y, uint16_t start, uint16_t end, uint16_t radius, color_t color) {
 -    if(start > 0 && start <= 180) {
 -        float x_maxI = x + radius*cos(start*M_PI/180);
 -        float x_minI;
 -
 -        if (end > 180)
 -            x_minI = x - radius;
 -        else
 -            x_minI = x + radius*cos(end*M_PI/180);
 -
 -        int a = 0;
 -        int b = radius;
 -        int P = 1 - radius;
 -
 -        do {
 -            if(x-a <= x_maxI && x-a >= x_minI)
 -                gdispDrawLine(x, y, x-a, y+b, color);
 -            if(x+a <= x_maxI && x+a >= x_minI)
 -            	gdispDrawLine(x, y, x+a, y+b, color);
 -            if(x-b <= x_maxI && x-b >= x_minI)
 -            	gdispDrawLine(x, y, x-b, y+a, color);
 -            if(x+b <= x_maxI && x+b >= x_minI)
 -            	gdispDrawLine(x, y, x+b, y+a, color);
 -
 -            if (P < 0) {
 -                P = P + 3 + 2*a;
 -                a = a + 1;
 -            } else {
 -                P = P + 5 + 2*(a - b);
 -                a = a + 1;
 -                b = b - 1;
 -            }
 -        } while(a <= b);
 -    }
 -
 -    if (end > 180 && end <= 360) {
 -        float x_maxII = x+radius*cos(end*M_PI/180);
 -        float x_minII;
 -
 -        if(start <= 180)
 -            x_minII = x - radius;
 -        else
 -            x_minII = x+radius*cos(start*M_PI/180);
 -
 -        int a = 0;
 -        int b = radius;
 -        int P = 1 - radius;
 -
 -        do {
 -            if(x-a <= x_maxII && x-a >= x_minII)
 -            	gdispDrawLine(x, y, x-a, y-b, color);
 -            if(x+a <= x_maxII && x+a >= x_minII)
 -            	gdispDrawLine(x, y, x+a, y-b, color);
 -            if(x-b <= x_maxII && x-b >= x_minII)
 -            	gdispDrawLine(x, y, x-b, y-a, color);
 -            if(x+b <= x_maxII && x+b >= x_minII)
 -            	gdispDrawLine(x, y, x+b, y-a, color);
 -
 -            if (P < 0) {
 -                P = P + 3 + 2*a;
 -                a = a + 1;
 -            } else {
 -                P = P + 5 + 2*(a - b);
 -                a = a + 1;
 -                b = b - 1;
 -            }
 -        } while (a <= b);
 -    }
 -}
 -
 -/*
 - * @brief	Draw a filled arc.
 - * @pre		The GDISP must be in powerOn or powerSleep mode.
 - * @note				Not very efficient currently - does lots of overdrawing
 +/**
 + * @brief   Draw a filled rectangular box with rounded corners
 + * @pre     The GDISP unit must be in powerOn or powerSleep mode.
   *
 - * @param[in] x0,y0		The center point
 - * @param[in] radius	The radius of the arc
 - * @param[in] start		The start angle (0 to 360)
 - * @param[in] end		The end angle (0 to 360)
 - * @param[in] color		The color of the arc
 + * @param[in] x,y		The start position
 + * @param[in] cx,cy		The size of the box (outside dimensions)
 + * @param[in] radius	The radius of the rounded corners
 + * @param[in] color		The color to use
   *
   * @api
   */
 -void gdispFillArc(coord_t x, coord_t y, coord_t radius, uint16_t start, uint16_t end, color_t color) {
 -	if(end < start) {
 -        _fill_arc(x, y, start, 360, radius, color);
 -        _fill_arc(x, y, 0, end, radius, color);
 -    } else {
 -        _fill_arc(x, y, start, end, radius, color);
 +void gdispFillRoundedBox(coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t radius, color_t color) {
 +	coord_t radius2;
 +
 +	radius2 = radius*2;
 +	if (radius2 > cx || radius2 > cy) {
 +		gdispFillArea(x, y, cx, cy, color);
 +		return;
  	}
 +	gdispFillArc(x+radius, y+radius, radius, 90, 180, color);
 +	gdispFillArea(x+radius+1, y, cx-radius2, radius, color);
 +	gdispFillArc(x+cx-1-radius, y+radius, radius, 0, 90, color);
 +	gdispFillArc(x+cx-1-radius, y+cy-1-radius, radius, 270, 360, color);
 +	gdispFillArea(x+radius+1, y+cy-radius, cx-radius2, radius, color);
 +	gdispFillArc(x+radius, y+cy-1-radius, radius, 180, 270, color);
 +	gdispFillArea(x, y+radius, cx, cy-radius2, color);
  }
  #endif
 @@ -877,10 +781,9 @@ void gdispFillArc(coord_t x, coord_t y, coord_t radius, uint16_t start, uint16_t   * @brief   Draw a rectangular box.
   * @pre     The GDISP unit must be in powerOn or powerSleep mode.
   *
 - * @param[in] x0,y0   The start position
 - * @param[in] cx,cy   The size of the box (outside dimensions)
 - * @param[in] color   The color to use
 - * @param[in] filled  Should the box should be filled
 + * @param[in] x,y		The start position
 + * @param[in] cx,cy		The size of the box (outside dimensions)
 + * @param[in] color		The color to use
   *
   * @api
   */
 @@ -928,6 +831,8 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {  		char		c;
  		int			first;
 +		if (!str) return;
 +		
  		first = 1;
  		p = font->charPadding * font->xscale;
  		while(*str) {
 @@ -969,6 +874,8 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {  		char		c;
  		int			first;
 +		if (!str) return;
 +		
  		first = 1;
  		h = font->height * font->yscale;
  		p = font->charPadding * font->xscale;
 @@ -998,6 +905,137 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {  	/**
  	 * @brief   Draw a text string verticly centered within the specified box.
  	 * @pre     The GDISP unit must be in powerOn or powerSleep mode.
 +	 *
 +	 * @param[in] x,y     The position for the text (need to define top-right or base-line - check code)
 +	 * @param[in] str     The string to draw
 +	 * @param[in] color   The color to use
 +	 * @param[in] justify Justify the text left, center or right within the box
 +	 *
 +	 * @api
 +	 */
 +	void gdispDrawStringBox(coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, font_t font, color_t color, justify_t justify) {
 +		/* No mutex required as we only call high level functions which have their own mutex */
 +		coord_t		w, h, p, ypos, xpos;
 +		char		c;
 +		int			first;
 +		const char *rstr;
 +		
 +		if (!str) str = "";
 +
 +		h = font->height * font->yscale;
 +		p = font->charPadding * font->xscale;
 +
 +		/* Oops - font too large for the area */
 +		if (h > cy) return;
 +
 +		/* See if we need to fill above the font */
 +		ypos = (cy - h + 1)/2;
 +		if (ypos > 0) {
 +			y += ypos;
 +			cy -= ypos;
 +		}
 +		
 +		/* See if we need to fill below the font */
 +		ypos = cy - h;
 +		if (ypos > 0)
 +			cy -= ypos;
 +		
 +		/* get the start of the printable string and the xpos */
 +		switch(justify) {
 +		case justifyCenter:
 +			/* Get the length of the entire string */
 +			w = gdispGetStringWidth(str, font);
 +			if (w <= cx)
 +				xpos = x + (cx - w)/2;
 +			else {
 +				/* Calculate how much of the string we need to get rid of */
 +				ypos = (w - cx)/2;
 +				xpos = 0;
 +				first = 1;
 +				while(*str) {
 +					/* Get the next printable character */
 +					c = *str++;
 +					w = _getCharWidth(font, c) * font->xscale;
 +					if (!w) continue;
 +					
 +					/* Handle inter-character padding */
 +					if (p) {
 +						if (!first) {
 +							xpos += p;
 +							if (xpos > ypos) break;
 +						} else
 +							first = 0;
 +					}
 +
 +					/* Print the character */
 +					xpos += w;
 +					if (xpos > ypos) break;
 +				}
 +				xpos = ypos - xpos + x;
 +			}
 +			break;
 +		case justifyRight:
 +			/* Find the end of the string */
 +			for(rstr = str; *str; str++);
 +			xpos = x+cx - 2;
 +			first = 1;
 +			for(str--; str >= rstr; str--) {
 +				/* Get the next printable character */
 +				c = *str;
 +				w = _getCharWidth(font, c) * font->xscale;
 +				if (!w) continue;
 +				
 +				/* Handle inter-character padding */
 +				if (p) {
 +					if (!first) {
 +						if (xpos - p < x) break;
 +						xpos -= p;
 +					} else
 +						first = 0;
 +				}
 +
 +				/* Print the character */
 +				if (xpos - w < x) break;
 +				xpos -= w;
 +			}
 +			str++;
 +			break;
 +		case justifyLeft:
 +			/* Fall through */
 +		default:
 +			xpos = x+1;
 +			break;
 +		}
 +		
 +		/* Print characters until we run out of room */
 +		first = 1;
 +		while(*str) {
 +			/* Get the next printable character */
 +			c = *str++;
 +			w = _getCharWidth(font, c) * font->xscale;
 +			if (!w) continue;
 +			
 +			/* Handle inter-character padding */
 +			if (p) {
 +				if (!first) {
 +					if (xpos + p > x+cx) break;
 +					xpos += p;
 +				} else
 +					first = 0;
 +			}
 +
 +			/* Print the character */
 +			if (xpos + w > x+cx) break;
 +			gdispDrawChar(xpos, y, c, font, color);
 +			xpos += w;
 +		}
 +	}
 +#endif
 +	
 +#if GDISP_NEED_TEXT || defined(__DOXYGEN__)
 +	/**
 +	 * @brief   Draw a text string verticly centered within the specified box. The box background is filled with the specified background color.
 +	 * @pre     The GDISP unit must be in powerOn or powerSleep mode.
  	 * @note    The entire box is filled
  	 *
  	 * @param[in] x,y     The position for the text (need to define top-right or base-line - check code)
 @@ -1015,6 +1053,8 @@ void gdispDrawBox(coord_t x, coord_t y, coord_t cx, coord_t cy, color_t color) {  		int			first;
  		const char *rstr;
 +		if (!str) str = "";
 +
  		h = font->height * font->yscale;
  		p = font->charPadding * font->xscale;
 @@ -34,75 +34,34 @@  #if GFX_USE_GWIN || defined(__DOXYGEN__)
 -/*===========================================================================*/
 -/* Driver local definitions.                                                 */
 -/*===========================================================================*/
 +#include <string.h>
 -/*===========================================================================*/
 -/* Driver exported variables.                                                */
 -/*===========================================================================*/
 +#define GWIN_FLG_DYNAMIC				0x0001
 +#define GWIN_FIRST_CONTROL_FLAG			0x0002
 +#define GBTN_FLG_ALLOCTXT				(GWIN_FIRST_CONTROL_FLAG<<0)
 -/*===========================================================================*/
 -/* Driver local variables.                                                   */
 -/*===========================================================================*/
 -
 -/*===========================================================================*/
 -/* Driver local functions.                                                   */
 -/*===========================================================================*/
 -
 -#if GDISP_NEED_TEXT
 -/*
 - * Stream interface implementation. The interface is write only
 - */
 -static size_t GWinStreamWrite(void *ip, const uint8_t *bp, size_t n) { gwinPutCharArray((GWindow *)ip, (const char *)bp, n); return RDY_OK; }
 -static size_t GWinStreamRead(void *ip, uint8_t *bp, size_t n) {	(void)ip; (void)bp; (void)n; return 0; }
 -static msg_t GWinStreamPut(void *ip, uint8_t b) { gwinPutChar((GWindow *)ip, (char)b); return RDY_OK; }
 -static msg_t GWinStreamGet(void *ip) {(void)ip; return RDY_OK; }
 -static msg_t GWinStreamPutTimed(void *ip, uint8_t b, systime_t time) { (void)time; gwinPutChar((GWindow *)ip, (char)b); return RDY_OK; }
 -static msg_t GWinStreamGetTimed(void *ip, systime_t timeout) { (void)ip; (void)timeout; return RDY_OK; }
 -static size_t GWinStreamWriteTimed(void *ip, const uint8_t *bp, size_t n, systime_t time) { (void)time; gwinPutCharArray((GWindow *)ip, (const char *)bp, n); return RDY_OK; }
 -static size_t GWinStreamReadTimed(void *ip, uint8_t *bp, size_t n, systime_t time) { (void)ip; (void)bp; (void)n; (void)time; return 0; }
 -
 -static const struct GWindowVMT vmt = {
 -	GWinStreamWrite,
 -	GWinStreamRead,
 -	GWinStreamPut,
 -	GWinStreamGet,
 -	GWinStreamPutTimed,
 -	GWinStreamGetTimed,
 -	GWinStreamWriteTimed,
 -	GWinStreamReadTimed
 -};
 -#endif
 -
 -/*===========================================================================*/
 -/* High Level Driver Routines.                                               */
 -/*===========================================================================*/
 -
 -/**
 - * @brief   Initialise a window.
 - * @return  FALSE if there is no resultant drawing area, otherwise TRUE.
 - *
 - * @param[in] gw      The window to initialise
 - * @param[in] x,y     The screen co-ordinates for the bottom left corner of the window
 - * @param[in] width   The width of the window
 - * @param[in] height  The height of the window
 - * @note			  The drawing color gets set to White and the background drawing color to Black.
 - * @note			  No default font is set so make sure to set one before drawing any text.
 - * @note			  The dimensions and position may be changed to fit on the real screen.
 - *
 - * @api
 - */
 -bool_t gwinInit(GWindow *gw, coord_t x, coord_t y, coord_t width, coord_t height) {
 +// Initialise a window creating it dynamicly if required.
 +static GHandle gwinInit(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size) {
  	coord_t	w, h;
 +	// Check the window size against the screen size
  	w = gdispGetWidth();
  	h = gdispGetHeight();
  	if (x < 0) { width += x; x = 0; }
  	if (y < 0) { height += y; y = 0; }
 -	if (x >= w || y >= h) return FALSE;
 +	if (x >= w || y >= h) return 0;
  	if (x+width > w) width = w - x;
  	if (y+height > h) height = h - y;
 +	
 +	// Allocate the structure if necessary
 +	if (!gw) {
 +		if (!(gw = (GWindowObject *)malloc(size)))
 +			return 0;
 +		gw->flags = GWIN_FLG_DYNAMIC;
 +	} else
 +		gw->flags = 0;
 +	
 +	// Initialise all basic fields (except the type)
  	gw->x = x;
  	gw->y = y;
  	gw->width = width;
 @@ -110,231 +69,278 @@ bool_t gwinInit(GWindow *gw, coord_t x, coord_t y, coord_t width, coord_t height  	gw->color = White;
  	gw->bgcolor = Black;
  #if GDISP_NEED_TEXT
 -	gw->txt.font = 0;
 -	gw->txt.fy = 0;
 -	gw->txt.fp = 0;
 -	gw->txt.cx = 0;
 -	gw->txt.cy = 0;
 -	gw->txt.vmt = &vmt;
 +	gw->font = 0;
 +#endif
 +	return (GHandle)gw;
 +}
 +
 +/**
 + * @brief   Create a basic window.
 + * @return  NULL if there is no resultant drawing area, otherwise a window handle.
 + *
 + * @param[in] gw		The window structure to initialise. If this is NULL the structure is dynamically allocated.
 + * @param[in] x,y		The screen co-ordinates for the bottom left corner of the window
 + * @param[in] width		The width of the window
 + * @param[in] height	The height of the window
 + * @note				The default drawing color gets set to White and the background drawing color to Black.
 + * @note				No default font is set so make sure to set one before drawing any text.
 + * @note				The dimensions and position may be changed to fit on the real screen.
 + * @note				The window is not automatically cleared on creation. You must do that by calling gwinClear() (possibly after changing your background color)
 + *
 + * @api
 + */
 +GHandle gwinCreateWindow(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_t height) {
 +	if (!(gw = (GWindowObject *)gwinInit((GWindowObject *)gw, x, y, width, height, sizeof(GWindowObject))))
 +		return 0;
 +	gw->type = GW_WINDOW;
 +	return (GHandle)gw;
 +}
 +
 +/**
 + * @brief   Destroy a window (of any type). Releases any dynamicly allocated memory.
 + *
 + * @param[in] gh		The window handle
 + *
 + * @api
 + */
 +void gwinDestroyWindow(GHandle gh) {
 +	// Clean up any type specific dynamic memory allocations
 +	switch(gh->type) {
 +#if GWIN_NEED_BUTTON
 +	case GW_BUTTON:
 +		if ((gh->flags & GBTN_FLG_ALLOCTXT)) {
 +			gh->flags &= ~GBTN_FLG_ALLOCTXT;		// To be sure, to be sure
 +			free((char *)((GButtonObject *)gh)->txt);
 +		}
 +		break;
  #endif
 -	return TRUE;
 +	default:
 +		break;
 +	}
 +
 +	// Clean up the structure
 +	if (gh->flags & GWIN_FLG_DYNAMIC) {
 +		gh->flags = 0;							// To be sure, to be sure
 +		free(gh);
 +	}
  }
  #if GDISP_NEED_TEXT
  /**
   * @brief   Set the current font for this window.
 - * @pre		The window must be initialised.
   *
 - * @param[in] gw      The window
 - * @param[in] font    The font to use for text functions
 + * @param[in] gh		The window handle
 + * @param[in] font		The font to use for text functions
   *
   * @api
   */
 -void gwinSetFont(GWindow *gw, font_t font) {
 -	gw->txt.font = font;
 -	gw->txt.fy = gdispGetFontMetric(font, fontHeight);
 -	gw->txt.fp = gdispGetFontMetric(font, fontCharPadding);
 +void gwinSetFont(GHandle gh, font_t font) {
 +	gh->font = font;
 +#if GWIN_NEED_CONSOLE
 +	if (font && gh->type == GW_CONSOLE) {
 +		((GConsoleObject *)gh)->fy = gdispGetFontMetric(font, fontHeight);
 +		((GConsoleObject *)gh)->fp = gdispGetFontMetric(font, fontCharPadding);
 +	}
 +#endif
  }
  #endif
  /**
   * @brief   Clear the window
 - * @pre		The window must be initialised.
   * @note	Uses the current background color to clear the window
   *
 - * @param[in] gw      The window
 + * @param[in] gh		The window handle
   *
   * @api
   */
 -void gwinClear(GWindow *gw) {
 -	gdispFillArea(gw->x, gw->y, gw->width, gw->height, gw->bgcolor);
 +void gwinClear(GHandle gh) {
 +	#if GDISP_SET_CLIP
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
 +	#endif
 +	gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
  }
  /**
   * @brief   Set a pixel in the window
 - * @pre		The window must be initialised.
   * @note	Uses the current foreground color to set the pixel
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] gw      The window
 + * @param[in] gh		The window handle
   *
   * @api
   */
 -void gwinDrawPixel(GWindow *gw, coord_t x, coord_t y) {
 +void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) {
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispDrawPixel(gw->x+x, gw->y+y, gw->color);
 +	gdispDrawPixel(gh->x+x, gh->y+y, gh->color);
  }
  /**
   * @brief   Draw a line in the window
 - * @pre		The window must be initialised.
   * @note	Uses the current foreground color to draw the line
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] gw      The window
 + * @param[in] gh		The window handle
   * @param[in] x0,y0		The start position
   * @param[in] x1,y1 	The end position
   *
   * @api
   */
 -void gwinDrawLine(GWindow *gw, coord_t x0, coord_t y0, coord_t x1, coord_t y1) {
 +void gwinDrawLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1) {
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispDrawLine(gw->x+x0, gw->y+y0, gw->x+x1, gw->y+y1, gw->color);
 +	gdispDrawLine(gh->x+x0, gh->y+y0, gh->x+x1, gh->y+y1, gh->color);
  }
  /**
   * @brief   Draw a box in the window
 - * @pre		The window must be initialised.
   * @note	Uses the current foreground color to draw the box
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] gw      The window
 - * @param[in] x,y     The start position
 - * @param[in] cx,cy   The size of the box (outside dimensions)
 + * @param[in] gh		The window handle
 + * @param[in] x,y		The start position
 + * @param[in] cx,cy		The size of the box (outside dimensions)
   *
   * @api
   */
 -void gwinDrawBox(GWindow *gw, coord_t x, coord_t y, coord_t cx, coord_t cy) {
 +void gwinDrawBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) {
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispDrawBox(gw->x+x, gw->y+y, cx, cy, gw->color);
 +	gdispDrawBox(gh->x+x, gh->y+y, cx, cy, gh->color);
  }
  /**
   * @brief   Fill an rectangular area in the window
 - * @pre		The window must be initialised.
   * @note	Uses the current foreground color to fill the box
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] gw      The window
 - * @param[in] x,y     The start position
 - * @param[in] cx,cy   The size of the box (outside dimensions)
 + * @param[in] gh		The window handle
 + * @param[in] x,y		The start position
 + * @param[in] cx,cy		The size of the box (outside dimensions)
   *
   * @api
   */
 -void gwinFillArea(GWindow *gw, coord_t x, coord_t y, coord_t cx, coord_t cy) {
 +void gwinFillArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) {
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispFillArea(gw->x+x, gw->y+y, cx, cy, gw->color);
 +	gdispFillArea(gh->x+x, gh->y+y, cx, cy, gh->color);
  }
  /**
   * @brief   Fill an area in the window using the supplied bitmap.
   * @details The bitmap is in the pixel format specified by the low level driver
 - * @pre		The window must be initialised.
   * @note	If GDISP_NEED_ASYNC is defined then the buffer must be static
   * 			or at least retained until this call has finished the blit. You can
   * 			tell when all graphics drawing is finished by @p gdispIsBusy() going FALSE.
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] x, y     The start filled area
 - * @param[in] cx, cy   The width and height to be filled
 - * @param[in] srcx, srcy   The bitmap position to start the fill from
 - * @param[in] srccx    The width of a line in the bitmap.
 - * @param[in] buffer   The pixels to use to fill the area.
 + * @param[in] gh		The window handle
 + * @param[in] x, y		The start filled area
 + * @param[in] cx, cy	The width and height to be filled
 + * @param[in] srcx, srcy	The bitmap position to start the fill from
 + * @param[in] srccx		The width of a line in the bitmap.
 + * @param[in] buffer	The pixels to use to fill the area.
   *
   * @api
   */
 -void gwinBlitArea(GWindow *gw, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) {
 +void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) {
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispBlitAreaEx(gw->x+x, gw->y+y, cx, cy, srcx, srcy, srccx, buffer);
 +	gdispBlitAreaEx(gh->x+x, gh->y+y, cx, cy, srcx, srcy, srccx, buffer);
  }
  #if GDISP_NEED_CIRCLE
  /**
   * @brief   Draw a circle in the window.
 - * @pre		The window must be initialised.
   * @note	Uses the current foreground color to draw the circle
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] x, y    The center of the circle
 - * @param[in] radius  The radius of the circle
 + * @param[in] gh		The window handle
 + * @param[in] x, y		The center of the circle
 + * @param[in] radius	The radius of the circle
   *
   * @api
   */
 -void gwinDrawCircle(GWindow *gw, coord_t x, coord_t y, coord_t radius) {
 +void gwinDrawCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) {
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispDrawCircle(gw->x+x, gw->y+y, radius, gw->color);
 +	gdispDrawCircle(gh->x+x, gh->y+y, radius, gh->color);
  }
  #endif
  #if GDISP_NEED_CIRCLE
  /**
   * @brief   Draw a filled circle in the window.
 - * @pre		The window must be initialised.
   * @note	Uses the current foreground color to draw the filled circle
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] x, y    The center of the circle
 - * @param[in] radius  The radius of the circle
 + * @param[in] gh		The window handle
 + * @param[in] x, y		The center of the circle
 + * @param[in] radius	The radius of the circle
   *
   * @api
   */
 -void gwinFillCircle(GWindow *gw, coord_t x, coord_t y, coord_t radius) {
 +void gwinFillCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) {
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispFillCircle(gw->x+x, gw->y+y, radius, gw->color);
 +	gdispFillCircle(gh->x+x, gh->y+y, radius, gh->color);
  }
  #endif
  #if GDISP_NEED_ELLIPSE
  /**
   * @brief   Draw an ellipse.
 - * @pre		The window must be initialised.
   * @note	Uses the current foreground color to draw the ellipse
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] x,y     The center of the ellipse
 - * @param[in] a,b     The dimensions of the ellipse
 + * @param[in] gh		The window handle
 + * @param[in] x,y		The center of the ellipse
 + * @param[in] a,b		The dimensions of the ellipse
   *
   * @api
   */
 -void gwinDrawEllipse(GWindow *gw, coord_t x, coord_t y, coord_t a, coord_t b) {
 +void gwinDrawEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) {
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispDrawEllipse(gw->x+x, gw->y+y, a, b, gw->color);
 +	gdispDrawEllipse(gh->x+x, gh->y+y, a, b, gh->color);
  }
  #endif
  #if GDISP_NEED_ELLIPSE
  /**
   * @brief   Draw an filled ellipse.
 - * @pre		The window must be initialised.
   * @note	Uses the current foreground color to draw the filled ellipse
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] x,y     The center of the ellipse
 - * @param[in] a,b     The dimensions of the ellipse
 + * @param[in] gh		The window handle
 + * @param[in] x,y		The center of the ellipse
 + * @param[in] a,b		The dimensions of the ellipse
   *
   * @api
   */
 -void gwinFillEllipse(GWindow *gw, coord_t x, coord_t y, coord_t a, coord_t b) {
 +void gwinFillEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) {
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispFillEllipse(gw->x+x, gw->y+y, a, b, gw->color);
 +	gdispFillEllipse(gh->x+x, gh->y+y, a, b, gh->color);
  }
  #endif
  #if GDISP_NEED_ARC
  /*
   * @brief	Draw an arc in the window.
 - * @pre		The window must be initialised.
   * @note	Uses the current foreground color to draw the arc
   * @note	May leave GDISP clipping to this window's dimensions
   *
 + * @param[in] gh		The window handle
   * @param[in] x,y		The center point
   * @param[in] radius	The radius of the arc
   * @param[in] start		The start angle (0 to 360)
 @@ -342,21 +348,21 @@ void gwinFillEllipse(GWindow *gw, coord_t x, coord_t y, coord_t a, coord_t b) {   *
   * @api
   */
 -void gwinDrawArc(GWindow *gw, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) {
 +void gwinDrawArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) {
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispDrawArc(gw->x+x, gw->y+y, radius, startangle, endangle, gw->color);
 +	gdispDrawArc(gh->x+x, gh->y+y, radius, startangle, endangle, gh->color);
  }
  #endif
  #if GDISP_NEED_ARC
  /*
   * @brief	Draw a filled arc in the window.
 - * @pre		The window must be initialised.
   * @note	Uses the current foreground color to draw the filled arc
   * @note	May leave GDISP clipping to this window's dimensions
   *
 + * @param[in] gh		The window handle
   * @param[in] x,y		The center point
   * @param[in] radius	The radius of the arc
   * @param[in] start		The start angle (0 to 360)
 @@ -364,255 +370,517 @@ void gwinDrawArc(GWindow *gw, coord_t x, coord_t y, coord_t radius, coord_t star   *
   * @api
   */
 -void gwinFillArc(GWindow *gw, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) {
 +void gwinFillArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) {
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispFillArc(gw->x+x, gw->y+y, radius, startangle, endangle, gw->color);
 +	gdispFillArc(gh->x+x, gh->y+y, radius, startangle, endangle, gh->color);
  }
  #endif
  #if GDISP_NEED_PIXELREAD
  /**
   * @brief   Get the color of a pixel in the window.
 - * @pre		The window must be initialised.
   * @return  The color of the pixel.
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] x,y     The position in the window
 + * @param[in] gh		The window handle
 + * @param[in] x,y		The position in the window
   *
   * @api
   */
 -color_t gwinGetPixelColor(GWindow *gw, coord_t x, coord_t y) {
 +color_t gwinGetPixelColor(GHandle gh, coord_t x, coord_t y) {
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	return gdispGetPixelColor(gw->x+x, gw->y+y);
 +	return gdispGetPixelColor(gh->x+x, gh->y+y);
  }
  #endif
 -#if GDISP_NEED_SCROLL
 +#if GDISP_NEED_TEXT
  /**
 - * @brief   Scroll vertically a section of the window.
 - * @pre		The window must be initialised.
 - * @note    If lines is >= cy, it is equivelent to a area fill with the current background drawing color.
 + * @brief   Draw a text character at the specified position in the window.
 + * @pre		The font must have been set.
 + * @note	Uses the current foreground color to draw the character
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] lines    The number of lines to scroll (Can be positive or negative)
 + * @param[in] gh		The window handle
 + * @param[in] x,y		The position for the text
 + * @param[in] c			The character to draw
   *
   * @api
   */
 -void gwinVerticalScroll(GWindow *gw, int lines) {
 +void gwinDrawChar(GHandle gh, coord_t x, coord_t y, char c) {
 +	if (!gh->font) return;
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispVerticalScroll(gw->x, gw->y, gw->width, gw->height, lines, gw->bgcolor);
 +	gdispDrawChar(gh->x+x, gh->y+y, c, gh->font, gh->color);
  }
  #endif
  #if GDISP_NEED_TEXT
  /**
 - * @brief   Draw a text character at the specified position in the window.
 - * @pre		The window must be initialised.
 + * @brief   Draw a text character with a filled background at the specified position in the window.
   * @pre		The font must have been set.
 - * @note	Uses the current foreground color to draw the character
 + * @note	Uses the current foreground color to draw the character and fills the background using the background drawing color
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] x,y     The position for the text
 - * @param[in] c       The character to draw
 + * @param[in] gh		The window handle
 + * @param[in] x,y		The position for the text
 + * @param[in] c			The character to draw
   *
   * @api
   */
 -void gwinDrawChar(GWindow *gw, coord_t x, coord_t y, char c) {
 -	if (!gw->txt.font) return;
 +void gwinFillChar(GHandle gh, coord_t x, coord_t y, char c) {
 +	if (!gh->font) return;
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispDrawChar(gw->x+x, gw->y+y, c, gw->txt.font, gw->color);
 +	gdispFillChar(gh->x+x, gh->y+y, c, gh->font, gh->color, gh->bgcolor);
  }
  #endif
  #if GDISP_NEED_TEXT
  /**
 - * @brief   Draw a text character with a filled background at the specified position in the window.
 - * @pre		The window must be initialised.
 + * @brief   Draw a text string in the window
   * @pre		The font must have been set.
 - * @note	Uses the current foreground color to draw the character and fills the background using the background drawing color
 + * @note	Uses the current foreground color to draw the character
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] x,y     The position for the text
 - * @param[in] c       The character to draw
 + * @param[in] gh		The window handle
 + * @param[in] x,y		The position for the text
 + * @param[in] str		The string to draw
   *
   * @api
   */
 -void gwinFillChar(GWindow *gw, coord_t x, coord_t y, char c) {
 -	if (!gw->txt.font) return;
 +void gwinDrawString(GHandle gh, coord_t x, coord_t y, const char *str) {
 +	if (!gh->font) return;
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispFillChar(gw->x+x, gw->y+y, c, gw->txt.font, gw->color, gw->bgcolor);
 +	gdispDrawString(gh->x+x, gh->y+y, str, gh->font, gh->color);
  }
  #endif
  #if GDISP_NEED_TEXT
  /**
 - * @brief   Draw a text string in the window
 - * @pre		The window must be initialised.
 + * @brief   Draw a text string with a filled background in the window
   * @pre		The font must have been set.
 - * @note	Uses the current foreground color to draw the character
 + * @note	Uses the current foreground color to draw the character and fills the background using the background drawing color
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] x,y     The position for the text
 - * @param[in] str     The string to draw
 + * @param[in] gh		The window handle
 + * @param[in] x,y		The position for the text
 + * @param[in] str		The string to draw
   *
   * @api
   */
 -void gwinDrawString(GWindow *gw, coord_t x, coord_t y, const char *str) {
 -	if (!gw->txt.font) return;
 +void gwinFillString(GHandle gh, coord_t x, coord_t y, const char *str) {
 +	if (!gh->font) return;
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispDrawString(gw->x+x, gw->y+y, str, gw->txt.font, gw->color);
 +	gdispFillString(gh->x+x, gh->y+y, str, gh->font, gh->color, gh->bgcolor);
  }
  #endif
  #if GDISP_NEED_TEXT
  /**
 - * @brief   Draw a text string with a filled background in the window
 - * @pre		The window must be initialised.
 + * @brief   Draw a text string verticly centered within the specified box.
   * @pre		The font must have been set.
 - * @note	Uses the current foreground color to draw the character and fills the background using the background drawing color
 + * @note	Uses the current foreground color to draw the character.
 + * @note    The specified box does not need to align with the window box
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] x,y     The position for the text
 - * @param[in] str     The string to draw
 + * @param[in] gh		The window handle
 + * @param[in] x,y		The position for the text (need to define top-right or base-line - check code)
 + * @param[in] str		The string to draw
 + * @param[in] justify	Justify the text left, center or right within the box
   *
   * @api
   */
 -void gwinFillString(GWindow *gw, coord_t x, coord_t y, const char *str) {
 -	if (!gw->txt.font) return;
 +void gwinDrawStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) {
 +	if (!gh->font) return;
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispFillString(gw->x+x, gw->y+y, str, gw->txt.font, gw->color, gw->bgcolor);
 +	gdispDrawStringBox(gh->x+x, gh->y+y, cx, cy, str, gh->font, gh->color, justify);
  }
  #endif
  #if GDISP_NEED_TEXT
  /**
 - * @brief   Draw a text string verticly centered within the specified box.
 - * @pre		The window must be initialised.
 + * @brief   Draw a text string verticly centered within the specified filled box.
   * @pre		The font must have been set.
   * @note	Uses the current foreground color to draw the character and fills the background using the background drawing color
   * @note    The entire box is filled. Note this box does not need to align with the window box
   * @note	May leave GDISP clipping to this window's dimensions
   *
 - * @param[in] x,y     The position for the text (need to define top-right or base-line - check code)
 - * @param[in] str     The string to draw
 - * @param[in] justify Justify the text left, center or right within the box
 + * @param[in] gh		The window handle
 + * @param[in] x,y		The position for the text (need to define top-right or base-line - check code)
 + * @param[in] str		The string to draw
 + * @param[in] justify	Justify the text left, center or right within the box
   *
   * @api
   */
 -void gwinBoxString(GWindow *gw, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) {
 -	if (!gw->txt.font) return;
 +void gwinFillStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) {
 +	if (!gh->font) return;
  	#if GDISP_SET_CLIP
 -		gdispSetClip(gw->x, gw->y+y, gw->width, gw->height);
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
  	#endif
 -	gdispFillStringBox(gw->x+x, gw->y+y, cx, cy, str, gw->txt.font, gw->color, gw->bgcolor, justify);
 +	gdispFillStringBox(gh->x+x, gh->y+y, cx, cy, str, gh->font, gh->color, gh->bgcolor, justify);
  }
  #endif
 -#if GDISP_NEED_TEXT
 +/*------------------------------------------------------------------------------------------------------------------------*/
 +
 +#if GWIN_NEED_CONSOLE
 +
 +/*
 + * Stream interface implementation. The interface is write only
 + */
 +
 +#define Stream2GWindow(ip)		((GHandle)(((char *)(ip)) - (size_t)(&(((GConsoleObject *)0)->stream))))
 +
 +static size_t GWinStreamWrite(void *ip, const uint8_t *bp, size_t n) { gwinPutCharArray(Stream2GWindow(ip), (const char *)bp, n); return RDY_OK; }
 +static size_t GWinStreamRead(void *ip, uint8_t *bp, size_t n) {	(void)ip; (void)bp; (void)n; return 0; }
 +static msg_t GWinStreamPut(void *ip, uint8_t b) { gwinPutChar(Stream2GWindow(ip), (char)b); return RDY_OK; }
 +static msg_t GWinStreamGet(void *ip) {(void)ip; return RDY_OK; }
 +static msg_t GWinStreamPutTimed(void *ip, uint8_t b, systime_t time) { (void)time; gwinPutChar(Stream2GWindow(ip), (char)b); return RDY_OK; }
 +static msg_t GWinStreamGetTimed(void *ip, systime_t timeout) { (void)ip; (void)timeout; return RDY_OK; }
 +static size_t GWinStreamWriteTimed(void *ip, const uint8_t *bp, size_t n, systime_t time) { (void)time; gwinPutCharArray(Stream2GWindow(ip), (const char *)bp, n); return RDY_OK; }
 +static size_t GWinStreamReadTimed(void *ip, uint8_t *bp, size_t n, systime_t time) { (void)ip; (void)bp; (void)n; (void)time; return 0; }
 +
 +struct GConsoleWindowVMT_t {
 +	_base_asynchronous_channel_methods
 +};
 +
 +static const struct GConsoleWindowVMT_t GWindowConsoleVMT = {
 +	GWinStreamWrite,
 +	GWinStreamRead,
 +	GWinStreamPut,
 +	GWinStreamGet,
 +	GWinStreamPutTimed,
 +	GWinStreamGetTimed,
 +	GWinStreamWriteTimed,
 +	GWinStreamReadTimed
 +};
 +
 +/**
 + * @brief   Create a console window.
 + * @details	A console window allows text to be written using chprintf() (and the console functions defined here).
 + * @brief	Text in a console window supports newlines and will wrap text as required.
 + * @return  NULL if there is no resultant drawing area, otherwise a window handle.
 + *
 + * @param[in] gc		The GConsoleObject structure to initialise. If this is NULL the structure is dynamically allocated.
 + * @param[in] x,y		The screen co-ordinates for the bottom left corner of the window
 + * @param[in] width		The width of the window
 + * @param[in] height	The height of the window
 + * @param[in] font		The font to use
 + * @note				The console is not automatically cleared on creation. You must do that by calling gwinClear() (possibly after changing your background color)
 + * @note				If the dispay does not support scrolling, the window will be cleared when the bottom line is reached.
 + * @note				The default drawing color gets set to White and the background drawing color to Black.
 + * @note				The dimensions and position may be changed to fit on the real screen.
 + *
 + * @api
 + */
 +GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t width, coord_t height, font_t font) {
 +	if (!(gc = (GConsoleObject *)gwinInit((GWindowObject *)gc, x, y, width, height, sizeof(GConsoleObject))))
 +		return 0;
 +	gc->gwin.type = GW_CONSOLE;
 +	gwinSetFont(&gc->gwin, font);
 +	gc->stream.vmt = &GWindowConsoleVMT;
 +	gc->cx = 0;
 +	gc->cy = 0;
 +	return (GHandle)gc;
 +}
 +
 +/**
 + * @brief   Get a stream from a console window suitable for use with chprintf().
 + * @return	The stream handle or NULL if this is not a console window.
 + *
 + * @param[in] gh	The window handle (must be a console window)
 + *
 + * @api
 + */
 +BaseSequentialStream *gwinGetConsoleStream(GHandle gh) {
 +	if (gh->type != GW_CONSOLE)
 +		return 0;
 +	return (BaseSequentialStream *)&(((GConsoleObject *)(gh))->stream);
 +}
 +
  /**
   * @brief   Put a character at the cursor position in the window.
 - * @pre		The window must be initialised.
 - * @pre		The font must have been set.
   * @note	Uses the current foreground color to draw the character and fills the background using the background drawing color
   *
 - * @param[in] c     The character to draw
 + * @param[in] gh	The window handle (must be a console window)
 + * @param[in] c		The character to draw
   *
   * @api
   */
 -void gwinPutChar(GWindow *gw, char c) {
 -	uint8_t width;
 +void gwinPutChar(GHandle gh, char c) {
 +	uint8_t			width;
 +	#define gcw		((GConsoleObject *)gh)
 -	if (!gw->txt.font) return;
 +	if (gh->type != GW_CONSOLE || !gh->font) return;
 +	#if GDISP_SET_CLIP
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
 +	#endif
 +	
  	if (c == '\n') {
  		/* clear the text at the end of the line */
 -		if (gw->txt.cx < gw->width)
 -			gdispFillArea(gw->x + gw->txt.cx, gw->y + gw->txt.cy, gw->width - gw->txt.cx, gw->txt.fy, gw->bgcolor);
 -		gw->txt.cx = 0;
 -		gw->txt.cy += gw->txt.fy;
 +		if (gcw->cx < gh->width)
 +			gdispFillArea(gh->x + gcw->cx, gh->y + gcw->cy, gh->width - gcw->cx, gcw->fy, gh->bgcolor);
 +		gcw->cx = 0;
 +		gcw->cy += gcw->fy;
  	} else if (c == '\r') {
 -		// gw->cx = 0;
 +		// gcw->cx = 0;
  	} else {
 -		width = gdispGetCharWidth(c, gw->txt.font) + gw->txt.fp;
 -		if (gw->txt.cx + width >= gw->width) {
 +		width = gdispGetCharWidth(c, gh->font) + gcw->fp;
 +		if (gcw->cx + width >= gh->width) {
  			/* clear the text at the end of the line */
 -			if (gw->txt.cy + gw->txt.fy <= gw->height)
 -				gdispFillArea(gw->x + gw->txt.cx, gw->y + gw->txt.cy, gw->width - (gw->txt.cx + width), gw->txt.fy, gw->bgcolor);
 -			gw->txt.cx = 0;
 -			gw->txt.cy += gw->txt.fy;
 +			if (gcw->cy + gcw->fy <= gh->height)
 +				gdispFillArea(gh->x + gcw->cx, gh->y + gcw->cy, gh->width - (gcw->cx + width), gcw->fy, gh->bgcolor);
 +			gcw->cx = 0;
 +			gcw->cy += gcw->fy;
  		}
 -		if (gw->txt.cy + gw->txt.fy > gw->height) {
 +		if (gcw->cy + gcw->fy > gh->height) {
  #if GDISP_NEED_SCROLL
  			/* scroll the console */
 -			gdispVerticalScroll(gw->x, gw->y, gw->width, gw->height, gw->txt.fy, gw->bgcolor);
 +			gdispVerticalScroll(gh->x, gh->y, gh->width, gh->height, gcw->fy, gh->bgcolor);
  			/* reset the cursor to the start of the last line */
 -			gw->txt.cx = 0;
 -			gw->txt.cy = (((int16_t)(gw->height/gw->txt.fy))-1)*gw->txt.fy;
 +			gcw->cx = 0;
 +			gcw->cy = (((coord_t)(gh->height/gcw->fy))-1)*gcw->fy;
  #else
  			/* clear the console */
 -			gdispFillArea(gw->x, gw->y, gw->width, gw->height, gw->bgcolor);
 +			gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor);
  			/* reset the cursor to the top of the window */
 -			gw->txt.cx = 0;
 -			gw->txt.cy = 0;
 +			gcw->cx = 0;
 +			gcw->cy = 0;
  #endif
  		}
 -		gdispDrawChar(gw->x + gw->txt.cx, gw->y + gw->txt.cy, c, gw->txt.font, gw->color);
 +		gdispDrawChar(gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, gh->color);
  		/* update cursor */
 -		gw->txt.cx += width;
 +		gcw->cx += width;
  	}
 +	#undef gcw
  }
 -#endif
 -#if GDISP_NEED_TEXT
  /**
   * @brief   Put a string at the cursor position in the window. It will wrap lines as required.
 - * @pre		The window must be initialised.
 - * @pre		The font must have been set.
   * @note	Uses the current foreground color to draw the string and fills the background using the background drawing color
   *
 - * @param[in] str     The string to draw
 + * @param[in] gh	The window handle (must be a console window)
 + * @param[in] str	The string to draw
   *
   * @api
   */
 -void gwinPutString(GWindow *gw, const char *str) {
 +void gwinPutString(GHandle gh, const char *str) {
  	while(*str)
 -		gwinPutChar(gw, *str++);
 +		gwinPutChar(gh, *str++);
  }
 -#endif
 -#if GDISP_NEED_TEXT
  /**
   * @brief   Put the character array at the cursor position in the window. It will wrap lines as required.
 - * @pre		The window must be initialised.
 - * @pre		The font must have been set.
   * @note	Uses the current foreground color to draw the string and fills the background using the background drawing color
   *
 - * @param[in] str     The string to draw
 - * @param[in] n       The number of characters to draw
 + * @param[in] gh	The window handle (must be a console window)
 + * @param[in] str	The string to draw
 + * @param[in] n		The number of characters to draw
   *
   * @api
   */
 -void gwinPutCharArray(GWindow *gw, const char *str, size_t n) {
 +void gwinPutCharArray(GHandle gh, const char *str, size_t n) {
  	while(n--)
 -		gwinPutChar(gw, *str++);
 +		gwinPutChar(gh, *str++);
 +}
 +#endif
 +
 +/*------------------------------------------------------------------------------------------------------------------------*/
 +
 +#if GWIN_NEED_BUTTON
 +
 +static const GButtonStyle GButtonDefaultStyle = {
 +	GBTN_3D,
 +	HTML2COLOR(0x404040),		// color_up_edge;
 +	HTML2COLOR(0xE0E0E0),		// color_up_fill;
 +	HTML2COLOR(0x000000),		// color_up_txt;
 +	HTML2COLOR(0x404040),		// color_dn_edge;
 +	HTML2COLOR(0x808080),		// color_dn_fill;
 +	HTML2COLOR(0x404040),		// color_dn_txt;
 +	};
 +
 +/**
 + * @brief   Create a button window.
 + * @return  NULL if there is no resultant drawing area, otherwise a window handle.
 + *
 + * @param[in] gb		The GConsoleWindow structure to initialise
 + * @param[in] x,y		The screen co-ordinates for the bottom left corner of the window
 + * @param[in] width		The width of the window
 + * @param[in] height	The height of the window
 + * @param[in] font		The font to use
 + * @param[in] type		The type of button
 + * @note				The drawing color gets set to White and the background drawing color to Black.
 + * @note				The dimensions and position may be changed to fit on the real screen.
 + * @note				The button is not automatically drawn. Call gwinButtonDraw() after changing the button style or setting the text.
 + *
 + * @api
 + */
 +GHandle gwinCreateButton(GButtonObject *gb, coord_t x, coord_t y, coord_t width, coord_t height, font_t font, GButtonType type) {
 +	if (!(gb = (GButtonObject *)gwinInit((GWindowObject *)gb, x, y, width, height, sizeof(GButtonObject))))
 +		return 0;
 +	gb->gwin.type = GW_BUTTON;
 +	gwinSetFont(&gb->gwin, font);
 +	gwinSetButtonStyle(&gb->gwin, &GButtonDefaultStyle);
 +	gb->type = type;
 +	gb->state = GBTN_UP;
 +	gb->txt = "";
 +	gb->callback = 0;
 +	gb->inputsrc = 0;
 +	return (GHandle)gb;
  }
 +
 +/**
 + * @brief   Set the style of a button.
 + * @details	The button style is defined by its shape and colours.
 + *
 + * @param[in] gh		The window handle (must be a button window)
 + * @param[in] style		The button style to set.
 + * @note				The button is not automatically redrawn. Call gwinButtonDraw() after changing the button style
 + *
 + * @api
 + */
 +void gwinSetButtonStyle(GHandle gh, const GButtonStyle *style) {
 +	#define gbw		((GButtonObject *)gh)
 +	if (gh->type != GW_BUTTON)
 +		return;
 +	
 +	gbw->style.shape = style->shape;
 +	gbw->style.color_up_edge = style->color_up_edge;
 +	gbw->style.color_up_fill = style->color_up_fill;
 +	gbw->style.color_dn_edge = style->color_dn_edge;
 +	gbw->style.color_dn_fill = style->color_dn_fill;
 +	gbw->style.color_up_txt = style->color_up_txt;
 +	gbw->style.color_dn_txt = style->color_dn_txt;
 +	#undef gbw
 +}
 +
 +/**
 + * @brief   Set the text of a button.
 + *
 + * @param[in] gh		The window handle (must be a button window)
 + * @param[in] txt		The button text to set. This must be a constant string unless useAlloc is set.
 + * @param[in] useAlloc	If TRUE the string specified will be copied into dynamically allocated memory.
 + * @note				The button is not automatically redrawn. Call gwinButtonDraw() after changing the button text.
 + *
 + * @api
 + */
 +void gwinSetButtonText(GHandle gh, const char *txt, bool_t useAlloc) {
 +	#define gbw		((GButtonObject *)gh)
 +	if (gh->type != GW_BUTTON)
 +		return;
 +
 +	// Dispose of the old string
 +	if ((gh->flags & GBTN_FLG_ALLOCTXT)) {
 +		gh->flags &= ~GBTN_FLG_ALLOCTXT;
 +		if (gbw->txt) {
 +			free((char *)gbw->txt);
 +			gbw->txt = "";
 +		}
 +	}
 +	// Alloc the new text if required
 +	if (txt && useAlloc) {
 +		char *str;
 +		
 +		if ((str = (char *)malloc(strlen(txt)+1))) {
 +			gh->flags |= GBTN_FLG_ALLOCTXT;
 +			strcpy(str, txt);
 +		}
 +		txt = (const char *)str;
 +	}
 +	
 +	gbw->txt = txt ? txt : "";
 +	#undef gbw
 +}
 +
 +/**
 + * @brief   Redraw the button.
 + *
 + * @param[in] gh		The window handle (must be a button window)
 + *
 + * @api
 + */
 +void gwinButtonDraw(GHandle gh) {
 +	color_t			cedge;
 +	color_t			cfill;
 +	color_t			ctxt;
 +	const char *	txt;
 +	#define gbw		((GButtonObject *)gh)
 +	#define RND_CNR_SIZE	5
 +	
 +	if (gh->type != GW_BUTTON)
 +		return;
 +
 +	#if GDISP_SET_CLIP
 +		gdispSetClip(gh->x, gh->y, gh->width, gh->height);
 +	#endif
 +	
 +	// Get the text (safely)
 +	txt = gh->font && gbw->txt ? gbw->txt : "";
 +	
 +	// Determine the colors to use
 +	switch(gbw->state) {
 +	case GBTN_DOWN:
 +		cedge = gbw->style.color_dn_edge;
 +		cfill = gbw->style.color_dn_fill;
 +		ctxt = gbw->style.color_dn_txt;
 +		break;
 +	case GBTN_UP:	default:
 +		cedge = gbw->style.color_up_edge;
 +		cfill = gbw->style.color_up_fill;
 +		ctxt = gbw->style.color_up_txt;
 +		break;
 +	}
 +	
 +	// Draw according to the shape specified.
 +	switch(gbw->style.shape) {
 +#if GDISP_NEED_ARC
 +	case GBTN_ROUNDED:
 +		if (gh->width >= 2*RND_CNR_SIZE+10) {
 +			gdispFillRoundedBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, RND_CNR_SIZE-1, cfill);
 +			gdispDrawStringBox(gh->x+1, gh->y+RND_CNR_SIZE, gh->width-2, gh->height-(2*RND_CNR_SIZE), txt, gh->font, ctxt, justifyCenter);
 +			gdispDrawRoundedBox(gh->x, gh->y, gh->width, gh->height, RND_CNR_SIZE, cedge);
 +			break;
 +		}
 +		/* Fall Through */
 +#endif
 +	case GBTN_SQUARE:
 +		gdispFillStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, ctxt, cfill, justifyCenter);
 +		gdispDrawBox(gh->x, gh->y, gh->width, gh->height, cedge);
 +		break;
 +#if GDISP_NEED_ELLIPSE
 +	case GBTN_ELLIPSE:
 +		gdispFillEllipse(gh->x+1, gh->y+1, gh->width/2-1, gh->height/2-1, cfill);
 +		gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, ctxt, justifyCenter);
 +		gdispDrawEllipse(gh->x, gh->y, gh->width/2, gh->height/2, cedge);
 +		break;
 +#endif
 +	case GBTN_3D:	default:
 +		gdispFillStringBox(gh->x, gh->y, gh->width-1, gh->height-1, txt, gh->font, ctxt, cfill, justifyCenter);
 +		gdispDrawLine(gh->x+gh->width-1, gh->y, gh->x+gh->width-1, gh->y+gh->height-1, cedge);
 +		gdispDrawLine(gh->x, gh->y+gh->height-1, gh->x+gh->width-2, gh->y+gh->height-1, cedge);
 +		break;
 +	}
 +	#undef gbw
 +}
 +
 +//void gwinSetButtonCallback(GHandle gh, ????);
 +//void gwinSetButtonInput(GHandle gh, ????);
  #endif
  #endif /* GFX_USE_GWIN */
  | 
