brewpanel/sdlgui.c

Wed, 12 May 2021 21:17:59 +0200

author
Michiel Broek
date
Wed, 12 May 2021 21:17:59 +0200
changeset 611
732d482f47c8
parent 605
e00f8ff4de9a
child 637
21e542c15832
permissions
-rw-r--r--

Improved logging if wiringpi failed.

/*****************************************************************************
 * Copyright (C) 2015-2020
 *   
 * Michiel Broek <mbroek at mbse dot eu>
 *
 * This file is part of the mbsePi-apps emulator
 *
 * The gui code is based on the gui from the emulator ARAnyM,
 * Copyright (c) 2004 Petr Stehlik of ARAnyM dev team
 *
 * This progrm is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation; either version 2, or (at your option) any
 * later version.
 *
 * mbsePi-apps is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with mbsePi-apps; see the file COPYING.  If not, write to the Free
 * Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
 *****************************************************************************/

#include "brewpanel.h"
#include "sdlgui.h"
#include "sockio.h"

#ifdef HAVE_SDL_SDL_H

#include "lcdfont10x16.h"


static SDL_Surface	*pSdlGuiScrn;            	/* Pointer to the actual main SDL screen surface 	*/
static SDL_Surface	*pFontGfx = NULL;        	/* The LCD font graphics 				*/
static SDL_Surface	*pBgSurface;			/* Pointer to the application SDL screen surface	*/
static SDL_Rect		dlgrect, bgrect;
static int		fontwidth, fontheight;		/* Width & height of the actual font 			*/
TTF_Font                *pFont = NULL;			/* TTF font for buttons etc.				*/
static Uint32		LCDbg0 = 0;			/* LCD background dark					*/
static Uint32		LCDbg1 = 0;			/* LCD background light					*/

extern int		my_shutdown;
extern int		debug;


/*-----------------------------------------------------------------------*/
/*
 * Load an 1 plane XBM into a 8 planes SDL_Surface.
 */
static SDL_Surface *SDLGui_LoadXBM(int w, int h, const char *pXbmBits)
{
    SDL_Surface	*bitmap;
    Uint8 	*dstbits;
    const Uint8 *srcbits;
    int		x, y, srcpitch, mask;

    srcbits = (Uint8 *)pXbmBits;

    /* Allocate the bitmap */
    if ((bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0)) == NULL) {
	syslog(LOG_NOTICE, "Failed to allocate bitmap: %s", SDL_GetError());
	return NULL;
    }

    srcpitch = ((w + 7) / 8);
    dstbits = (Uint8 *)bitmap->pixels;
    mask = 1;

    /* Copy the pixels */
    for (y = 0 ; y < h ; y++) {
	for (x = 0 ; x < w ; x++) {
	    dstbits[x] = (srcbits[x / 8] & mask) ? 1 : 0;
	    mask <<= 1;
	    mask |= (mask >> 8);
	    mask &= 0xFF;
	}
	dstbits += bitmap->pitch;
	srcbits += srcpitch;
    }

    return bitmap;
}



/*
 * Initialize the GUI.
 */
int SDLGui_Init(void)
{
    char	*Pt = NULL;

    SDL_Color blackWhiteColors[2] = {{255, 255, 255, 0}, {53, 59, 61, 0}};

    /* 
     * Initialize the LCD font graphics: 
     */
    pFontGfx = SDLGui_LoadXBM(lcdfont10x16_width, lcdfont10x16_height, lcdfont10x16_bits);
    if (pFontGfx == NULL) {
	syslog(LOG_NOTICE, "Error: Can not init font graphics!");
	return -1;
    }

    /* Set color palette of the LCD font graphics: */
    SDL_SetColors(pFontGfx, blackWhiteColors, 0, 2);

    /* Set font color 0 as transparent: */
    SDL_SetColorKey(pFontGfx, (SDL_SRCCOLORKEY|SDL_RLEACCEL), 0);

    if (TTF_Init() == -1) {
	syslog(LOG_NOTICE, "Could not init SDL_ttf");
	return -1;
    }

    /*
     * Load TTF font for the dialogs
     */
    Pt = calloc(1024, sizeof(char));
    sprintf(Pt, "%s", "/usr/share/fonts/TTF/DejaVuSans.ttf");
    if ((pFont = TTF_OpenFont(Pt, 14 )) == NULL) {
	sprintf(Pt, "%s", "/usr/share/fonts/truetype/ttf-dejavu/DejaVuSans.ttf");
	if ((pFont = TTF_OpenFont(Pt, 14 )) == NULL) {
	    sprintf(Pt, "%s", "/usr/share/fonts/truetype/freefont/DejaVuSans.ttf");
	    if ((pFont = TTF_OpenFont(Pt, 14 )) == NULL) {
		sprintf(Pt, "%s", "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf");
		if ((pFont = TTF_OpenFont(Pt, 14 )) == NULL) {
		    syslog(LOG_NOTICE, "Could not load DejaVuSans.ttf");
		    return -1;
		}
	    }
	}
    }
    syslog(LOG_NOTICE, "Using ttf font: %s\n", Pt);
    free(Pt);
    Pt = NULL;

    return 0;
}



/*
 * Uninitialize the GUI.
 */
int SDLGui_UnInit(void)
{
    if (pFont)
    	TTF_CloseFont(pFont);
    pFont = NULL;

    if (pFontGfx)
	SDL_FreeSurface(pFontGfx);
    pFontGfx = NULL;

    return 0;
}



/*
 * Inform the SDL-GUI about the actual SDL_Surface screen pointer and
 * prepare the font to suit the actual resolution.
 */
int SDLGui_SetScreen(SDL_Surface *pScrn)
{
    pSdlGuiScrn = pScrn;

    if (pFontGfx == NULL) {
	syslog(LOG_NOTICE, "Error: A problem with the font occured!");
	return -1;
    }

    /* Get the font width and height: */
    fontwidth = pFontGfx->w/16;
    fontheight = pFontGfx->h/16;
    
    return 0;
}



/*
 * Center a dialog so that it appears in the middle of the screen.
 * Note: We only store the coordinates in the root box of the dialog,
 * all other objects in the dialog are positioned relatively to this one.
 */
void SDLGui_CenterDlg(SGOBJ *dlg)
{
    dlg[0].x = (pSdlGuiScrn->w/1-dlg[0].w)/2;
    dlg[0].y = (pSdlGuiScrn->h/1-dlg[0].h)/2;
}



/*
 * Draw a text string using TTF
 */
static void SDLGui_TTF(int x, int y, const char *txt)
{
    SDL_Rect    	offset;
    SDL_Color		textColor = { 0, 0, 0 };
    SDL_Surface*	message = NULL;

    message = TTF_RenderText_Solid(pFont, txt, textColor);
    offset.x = x;
    offset.y = y;
    SDL_BlitSurface(message, NULL, pSdlGuiScrn, &offset);
    SDL_FreeSurface(message);
    message = NULL;
}



/*
 * Draw a dialog TTF text object.
 */
static void SDLGui_DrawTTF(const SGOBJ *tdlg, int objnum)
{
    int         x, y;

    x = (tdlg[0].x + tdlg[objnum].x);
    y = (tdlg[0].y + tdlg[objnum].y);
    SDLGui_TTF(x, y, tdlg[objnum].txt);
}



/*
 * Draw the cursor
 */
void SDLGui_Cursor(SGOBJ *dlg, int fd, int x, int y, int on, int blink)
{
    SDL_Rect	dr;
    Uint32      color = SDL_MapRGB(pSdlGuiScrn->format, 53, 59, 61);

    if (on) {
    	dr.x = x;
    	dr.y = y + fontheight - 2;
    	dr.w = fontwidth;
    	dr.h = 2;

    	SDL_FillRect(pSdlGuiScrn, &dr, color);
    	SDL_UpdateRect(pSdlGuiScrn, x, y, fontwidth, fontheight);
    }
}



void SDLGui_CGChar(SGOBJ *dlg, int fd, int x, int y, Uint8 data[8])
{
    int		i, j, x1, x2, y1, y2, dstpitch = 0;
    SDL_Rect	sr, dr;
    Uint32	bg;
    Uint8	*dstbits = NULL, mask;
    SDL_Surface	*CGchar;
    SDL_Color	blackWhiteColors[2] = {{255, 255, 255, 0}, {53, 59, 61, 0}};

    CGchar = SDL_CreateRGBSurface(SDL_SWSURFACE, 10, 16, 8, 0, 0, 0, 0);
    if (CGchar == NULL) {
	fprintf(stderr, "SDLGui_CGChar Can not init font graphics!\n");
	return;
    }
    dstbits = (Uint8 *)CGchar->pixels;
    dstpitch = CGchar->pitch;
    mask = 0x10;
    i = j = 0;

    /*
     * Create a bitmap with the character pixels
     */
    for (y1 = 0; y1 < 8; y1++) {
	for (y2 = 0; y2 < 2; y2++) {
	    j = 0;
	    for (x1 = 0; x1 < 5; x1++) {
		for (x2 = 0; x2 < 2; x2++) {
		    dstbits[j] = (data[i] & mask) ? 1 : 0;
		    j++;
		}
		mask >>= 1;
		if (! mask)
		    mask = 0x10;
	    }
	    dstbits += dstpitch;
	}
	i++;
    }

    SDL_SetColors(CGchar, blackWhiteColors, 0, 2);
    SDL_SetColorKey(CGchar, (SDL_SRCCOLORKEY|SDL_RLEACCEL), 0);
    bg = LCDbg0;

    sr.x = sr.y = 0;
    dr.x = x;
    dr.y = y;
    sr.w = dr.w = fontwidth;
    sr.h = dr.h = fontheight;

    SDL_FillRect(pSdlGuiScrn, &dr, bg);
    SDL_BlitSurface(CGchar, &sr, pSdlGuiScrn, &dr);
    SDL_UpdateRect(pSdlGuiScrn, x, y, fontwidth, fontheight);
    SDL_FreeSurface(CGchar);
}



/*
 * Draw a text character
 */
void SDLGui_Char(SGOBJ *dlg, int fd, int x, int y, Uint8 c)
{
    SDL_Rect    sr, dr;
    Uint32	bg;

//    if (dlg[1].state & SG_SELECTED) {
//	bg = LCDbg1;
//    } else {
	bg = LCDbg0;
//    }

    sr.x=fontwidth*(c%16);
    sr.y=fontheight*(c/16);
    sr.w=fontwidth;
    sr.h=fontheight;
    dr.x=x;
    dr.y=y;
    dr.w=fontwidth;
    dr.h=fontheight;

    SDL_FillRect(pSdlGuiScrn, &dr, bg);
    SDL_BlitSurface(pFontGfx, &sr, pSdlGuiScrn, &dr);
    SDL_UpdateRect(pSdlGuiScrn, x, y, fontwidth, fontheight);
}



/*
 * Draw a text string.
 */
static void SDLGui_Text(int x, int y, const char *txt)
{
    int		i;
    Uint8	c;
    SDL_Rect	sr, dr;

    for (i=0; txt[i]!=0; i++) {
	c = txt[i] & 0xff;
	sr.x=fontwidth*(c%16);
	sr.y=fontheight*(c/16);
	sr.w=fontwidth;
	sr.h=fontheight;
	dr.x=x+i*(fontwidth+2);
	dr.y=y;
	dr.w=fontwidth;
	dr.h=fontheight;
	SDL_BlitSurface(pFontGfx, &sr, pSdlGuiScrn, &dr);
    }
}



/*
 * Draw a dialog text object.
 */
static void SDLGui_DrawText(const SGOBJ *tdlg, int objnum)
{
    int		x, y;

    x = (tdlg[0].x + tdlg[objnum].x);
    y = (tdlg[0].y + tdlg[objnum].y);
    SDLGui_Text(x, y, tdlg[objnum].txt);
}



/*
 * Draw a dialog LCD object.
 */
void SDLGui_DrawLCD(SGOBJ *bdlg, int objnum)
{
    SDL_Rect    rect;
    int         x, y, w, h, offset, border = 4;
    Uint32	bc  = SDL_MapRGB(pSdlGuiScrn->format, 32, 32, 32);
    Uint32      bg;

    LCDbg0 = SDL_MapRGB(pSdlGuiScrn->format, 94,147, 69);
    LCDbg1 = SDL_MapRGB(pSdlGuiScrn->format,156,235,  4);
    /*
     * Width and height are given in character columns and rows,
     * so calculate the display size in pixels.
     */
    w = bdlg[objnum].w * (fontwidth + 2) + 10;
    h = bdlg[objnum].h * (fontheight + 2) + 4;

    if (bdlg[objnum].x == -1) {
	/*
	 * Auto center
	 */
	x = (bdlg[0].w - w) / 2;
    } else {
    	x = bdlg[objnum].x;
    }
    y = bdlg[objnum].y;
    if (objnum > 0) {           /* Since the root object is a box, too, */
	/* we have to look for it now here and only */
	x += bdlg[0].x;         /* add its absolute coordinates if we need to */
	y += bdlg[0].y;
    }

//    if (bdlg[objnum].state & SG_SELECTED) {
//	bg = LCDbg1;
//    } else {
	bg = LCDbg0;
//    }

    /* The root box should be bigger than the screen, so we disable the offset there: */
    if (objnum != 0)
	offset = border;
    else
	offset = 0;

    /* Draw background: */
    rect.x = x;
    rect.y = y;
    rect.w = w;
    rect.h = h;
    SDL_FillRect(pSdlGuiScrn, &rect, bg);

    /* Draw upper border: */
    rect.x = x - offset;
    rect.y = y - offset;
    rect.w = w + offset + offset;
    rect.h = border;
    SDL_FillRect(pSdlGuiScrn, &rect, bc);

    /* Draw left border: */
    rect.x = x - offset;
    rect.y = y;
    rect.w = border;
    rect.h = h;
    SDL_FillRect(pSdlGuiScrn, &rect, bc);

    /* Draw bottom border: */
    rect.x = x - offset;
    rect.y = y + h - border + offset;
    rect.w = w + offset + offset;
    rect.h = border;
    SDL_FillRect(pSdlGuiScrn, &rect, bc);

    /* Draw right border: */
    rect.x = x + w - border + offset;
    rect.y = y;
    rect.w = border;
    rect.h = h;
    SDL_FillRect(pSdlGuiScrn, &rect, bc);
}



/*
 * Draw a dialog box object.
 */
static void SDLGui_DrawBox(const SGOBJ *bdlg, int objnum)
{
    SDL_Rect	rect;
    int		x, y, w, h, offset, shade = 2;
    Uint32	grey = SDL_MapRGB(pSdlGuiScrn->format,192,192,192);
    Uint32	upleftc, downrightc;

    x = bdlg[objnum].x;
    y = bdlg[objnum].y;
    if (objnum > 0) {		/* Since the root object is a box, too, */
	/* we have to look for it now here and only */
	x += bdlg[0].x;		/* add its absolute coordinates if we need to */
	y += bdlg[0].y;
    }
    w = bdlg[objnum].w;
    h = bdlg[objnum].h;

    if (bdlg[objnum].state & SG_SELECTED) {
	upleftc = SDL_MapRGB(pSdlGuiScrn->format,128,128,128);
	downrightc = SDL_MapRGB(pSdlGuiScrn->format,255,255,255);
    } else {
	upleftc = SDL_MapRGB(pSdlGuiScrn->format,255,255,255);
	downrightc = SDL_MapRGB(pSdlGuiScrn->format,128,128,128);
    }

    /* The root box should be bigger than the screen, so we disable the offset there: */
    if (objnum != 0)
	offset = shade;
    else
	offset = 0;

    /* Draw background: */
    rect.x = x;
    rect.y = y;
    rect.w = w;
    rect.h = h;
    SDL_FillRect(pSdlGuiScrn, &rect, grey);

    /* Draw upper border: */
    rect.x = x;
    rect.y = y - offset;
    rect.w = w;
    rect.h = shade;
    SDL_FillRect(pSdlGuiScrn, &rect, upleftc);

    /* Draw left border: */
    rect.x = x - offset;
    rect.y = y;
    rect.w = shade;
    rect.h = h;
    SDL_FillRect(pSdlGuiScrn, &rect, upleftc);

    /* Draw bottom border: */
    rect.x = x;
    rect.y = y + h - shade + offset;
    rect.w = w;
    rect.h = shade;
    SDL_FillRect(pSdlGuiScrn, &rect, downrightc);

    /* Draw right border: */
    rect.x = x + w - shade + offset;
    rect.y = y;
    rect.w = shade;
    rect.h = h;
    SDL_FillRect(pSdlGuiScrn, &rect, downrightc);
}



/*
 * Draw a normal button.
 */
static void SDLGui_DrawButton(const SGOBJ *bdlg, int objnum)
{
    int		x, y, w, h;

    SDLGui_DrawBox(bdlg, objnum);
    /*
     * Use bold text and get outer dimensions of the text
     */
    TTF_SetFontStyle(pFont, TTF_STYLE_BOLD);
    TTF_SizeText(pFont, bdlg[objnum].txt, &w, &h);
    x = bdlg[0].x + bdlg[objnum].x + (bdlg[objnum].w - w) / 2;
    y = bdlg[0].y + bdlg[objnum].y + (bdlg[objnum].h - h) / 2;

    if (bdlg[objnum].state & SG_SELECTED) {
	x += 1;
	y += 1;
    }

    if ((bdlg[objnum].flags & SG_HIDE) == 0)
	SDLGui_TTF(x, y, bdlg[objnum].txt);
    TTF_SetFontStyle(pFont, TTF_STYLE_NORMAL);
}



/*
 * SDL_Surface 32-bit circle-fill algorithm without using trig
 *
 * While I humbly call this "Celdecea's Method", odds are that the 
 * procedure has already been documented somewhere long ago.  All of
 * the circle-fill examples I came across utilized trig functions or
 * scanning neighbor pixels.  This algorithm identifies the width of
 * a semi-circle at each pixel height and draws a scan-line covering
 * that width.  
 *
 * The code is not optimized but very fast, owing to the fact that it
 * alters pixels in the provided surface directly rather than through
 * function calls.
 */
void SDLGui_fill_circle(SDL_Surface *surface, int cx, int cy, int radius, Uint32 pixel)
{
    /*
     * Note that there is more to altering the bitrate of this 
     * method than just changing this value.  See how pixels are
     * altered at the following web page for tips:
     * http://www.libsdl.org/intro.en/usingvideo.html
     */
    static const int	BPP = 4;
    double 		r = (double)radius;
    double		dy;

    for (dy = 1; dy <= r; dy += 1.0) {
	/*
	 * This loop is unrolled a bit, only iterating through half of the
	 * height of the circle.  The result is used to draw a scan line and
	 * its mirror image below it.
	 *
	 * The following formula has been simplified from our original.  We
	 * are using half of the width of the circle because we are provided
	 * with a center and we need left/right coordinates.
	 */
	double dx = floor(sqrt((2.0 * r * dy) - (dy * dy)));
	int x = cx - dx;

	// Grab a pointer to the left-most pixel for each half of the circle
	Uint8 *target_pixel_a = (Uint8 *)surface->pixels + ((int)(cy + r - dy)) * surface->pitch + x * BPP;
	Uint8 *target_pixel_b = (Uint8 *)surface->pixels + ((int)(cy - r + dy)) * surface->pitch + x * BPP;

	for (; x <= cx + dx; x++) {
	    *(Uint32 *)target_pixel_a = pixel;
	    *(Uint32 *)target_pixel_b = pixel;
	    target_pixel_a += BPP;
	    target_pixel_b += BPP;
	}
    }
}



static void SDLGUI_DrawLEDRed(const SGOBJ *bdlg, int objnum)
{
    Uint32	color;

    if (bdlg[objnum].state & SG_SELECTED) {
	color = SDL_MapRGB(pSdlGuiScrn->format, 255, 64, 0);
    } else {
	color = SDL_MapRGB(pSdlGuiScrn->format, 128, 16, 0);
    }
    SDLGui_fill_circle(pSdlGuiScrn, bdlg[objnum].x, bdlg[objnum].y, bdlg[objnum].w, color);
}



static void SDLGUI_DrawLEDBlue(const SGOBJ *bdlg, int objnum)
{
    Uint32      color;

    if (bdlg[objnum].state & SG_SELECTED) {
	color = SDL_MapRGB(pSdlGuiScrn->format, 64, 160, 255);
    } else {
	color = SDL_MapRGB(pSdlGuiScrn->format, 16, 48, 112);
    }
    SDLGui_fill_circle(pSdlGuiScrn, bdlg[objnum].x, bdlg[objnum].y, bdlg[objnum].w, color);
}



static void SDLGUI_DrawLEDGreen(const SGOBJ *bdlg, int objnum)
{
    Uint32      color;

    if (bdlg[objnum].state & SG_SELECTED) {
	color = SDL_MapRGB(pSdlGuiScrn->format, 80, 240, 0);
    } else {
	color = SDL_MapRGB(pSdlGuiScrn->format, 32, 112, 0);
    }
    SDLGui_fill_circle(pSdlGuiScrn, bdlg[objnum].x, bdlg[objnum].y, bdlg[objnum].w, color);
}



static void SDLGUI_DrawLEDYellow(const SGOBJ *bdlg, int objnum)
{
    Uint32      color;

    if (bdlg[objnum].state & SG_SELECTED) {
	color = SDL_MapRGB(pSdlGuiScrn->format, 255, 255, 0);
    } else {
	color = SDL_MapRGB(pSdlGuiScrn->format, 160, 144, 0);
    }
    SDLGui_fill_circle(pSdlGuiScrn, bdlg[objnum].x, bdlg[objnum].y, bdlg[objnum].w, color);
}



void SDLGui_LED(SGOBJ *dlg, int fd, int LED, int on)
{
    int	i;

    for (i = 0; dlg[i].type != -1; i++) {
	if (dlg[i].type == LED) {
	    if (debug)
		fprintf(stdout, "SDLGui_LED LED=%d on=%d\n", LED, on);
	    if (on) {
		dlg[i].state |= SG_SELECTED;
	    } else {
		dlg[i].state &= ~SG_SELECTED;
	    }
	    switch (dlg[i].type) {
		case SGLEDRED:
				SDLGUI_DrawLEDRed(dlg, i);
				break;
		case SGLEDBLUE:
				SDLGUI_DrawLEDBlue(dlg, i);
				break;
		case SGLEDGREEN:
				SDLGUI_DrawLEDGreen(dlg, i);
				break;
		case SGLEDYELLOW:
				SDLGUI_DrawLEDYellow(dlg, i);
				break;
	    }
	    SDL_UpdateRect(pSdlGuiScrn, dlg[i].x - dlg[i].w, dlg[i].y - dlg[i].w, dlg[i].w * 2, dlg[i].w * 2);
	}
    }
}



/*
 * Draw a whole dialog.
 */
void SDLGui_DrawDialog(SGOBJ *dlg)
{
    int i;
	
    for (i = 0; dlg[i].type != -1; i++) {
	switch (dlg[i].type) {
	    case SGBOX:
			SDLGui_DrawBox(dlg, i);
			break;
	    case SGLCD:
			SDLGui_DrawLCD(dlg, i);
			break;
	    case SGTEXT:
			SDLGui_DrawText(dlg, i);
			break;
	    case SGTTF:
			SDLGui_DrawTTF(dlg, i);
			break;
	    case SGBUTTON:
			SDLGui_DrawButton(dlg, i);
			break;
	    case SGLEDRED:
			SDLGUI_DrawLEDRed(dlg, i);
			break;
	    case SGLEDBLUE:
			SDLGUI_DrawLEDBlue(dlg, i);
			break;
	    case SGLEDGREEN:
			SDLGUI_DrawLEDGreen(dlg, i);
			break;
	    case SGLEDYELLOW:
			SDLGUI_DrawLEDYellow(dlg, i);
			break;
	}
    }

    SDL_UpdateRect(pSdlGuiScrn, 0,0,0,0);
}



/*
 * Search an object at a certain position.
 */
static int SDLGui_FindObj(const SGOBJ *dlg, int fx, int fy)
{
    int		len, i, ob = -1, xpos, ypos;

    len = 0;
    while (dlg[len].type != -1)
	len++;

    xpos = fx;
    ypos = fy;
    /* Now search for the object: */
    for (i = len; i >= 0; i--) {
	if (xpos >= dlg[0].x + dlg[i].x && ypos >= dlg[0].y + dlg[i].y && 
	    xpos < dlg[0].x + dlg[i].x + dlg[i].w && ypos < dlg[0].y + dlg[i].y + dlg[i].h) {
	    ob = i;
	    break;
	}
    }
	
    return ob;
}



/*
 * Show dialog.
 */
int SDLGui_DoDialogInit(SGOBJ *dlg)
{
    if ((pSdlGuiScrn->h < dlg[0].h) && (pSdlGuiScrn->w < dlg[0].w)) {
	syslog(LOG_NOTICE, "Screen size too small for dialog!");
	return SDLGUI_ERROR;
    }

    dlgrect.x = dlg[0].x;
    dlgrect.y = dlg[0].y;
    dlgrect.w = dlg[0].w;
    dlgrect.h = dlg[0].h;

    bgrect.x = bgrect.y = 0;
    bgrect.w = dlgrect.w;
    bgrect.h = dlgrect.h;

    /*
     * Save background
     */
    pBgSurface = SDL_CreateRGBSurface(SDL_SWSURFACE, dlgrect.w, dlgrect.h, pSdlGuiScrn->format->BitsPerPixel,
	                                  pSdlGuiScrn->format->Rmask, pSdlGuiScrn->format->Gmask, pSdlGuiScrn->format->Bmask, pSdlGuiScrn->format->Amask);
    if (pSdlGuiScrn->format->palette != NULL) {
	SDL_SetColors(pBgSurface, pSdlGuiScrn->format->palette->colors, 0, pSdlGuiScrn->format->palette->ncolors-1);
    }

    if (pBgSurface != NULL) {
	SDL_BlitSurface(pSdlGuiScrn,  &dlgrect, pBgSurface, &bgrect);
    } else {
	syslog(LOG_NOTICE, "SDLGUI_DoDialog: CreateRGBSurface failed: %s", SDL_GetError());
    }

    /* (Re-)draw the dialog */
    SDLGui_DrawDialog(dlg);
    return 0;
}



/*
 * Process a dialog. Returns the button number that has been pressed
 */
int SDLGui_DoDialogLoop(SGOBJ *dlg)
{
    int         obj = 0, retbutton = 0;
    SDL_Event   sdlEvent;

    /* The main loop */
    while (retbutton == 0 && !my_shutdown) {

	/*
	 * Poll network for data
	 */
	socket_recv(dlg);

	if (SDL_PollEvent(&sdlEvent) == 1) { /* Wait for events */
	    switch (sdlEvent.type) {
		case SDL_QUIT:
				retbutton = SDLGUI_QUIT;
				break;

		case SDL_MOUSEBUTTONDOWN:
				if (sdlEvent.button.button != SDL_BUTTON_LEFT) {
				    /* Not left mouse button -> unsupported event */
				    break;
				}
				/* It was the left button: Find the object under the mouse cursor */
				obj = SDLGui_FindObj(dlg, sdlEvent.button.x, sdlEvent.button.y);
				if (obj > 0) {
				    if (dlg[obj].type == SGBUTTON) {
					dlg[obj].state |= SG_SELECTED;
					SDLGui_DrawButton(dlg, obj);
					SDL_UpdateRect(pSdlGuiScrn, dlg[0].x + dlg[obj].x - 2, dlg[0].y + dlg[obj].y - 2, dlg[obj].w + 4, dlg[obj].h + 4);
					retbutton = obj + 1000;
				    }
				}
				break;

		 case SDL_MOUSEBUTTONUP:
				if (sdlEvent.button.button != SDL_BUTTON_LEFT) {
				    /* Not left mouse button -> unsupported event */
				    break;
				}
				/* It was the left button: Find the object under the mouse cursor */
				obj = SDLGui_FindObj(dlg, sdlEvent.button.x, sdlEvent.button.y);
				if (obj > 0) {
				    if (dlg[obj].type == SGBUTTON) {
					dlg[obj].state &= ~SG_SELECTED;
					SDLGui_DrawButton(dlg, obj);
					SDL_UpdateRect(pSdlGuiScrn, dlg[0].x + dlg[obj].x - 2, dlg[0].y + dlg[obj].y - 2, dlg[obj].w + 4, dlg[obj].h + 4);
					retbutton = obj;
				    }
				}
				break;

		 case SDL_MOUSEMOTION:
				break;

		 case SDL_KEYDOWN:                     /* Key pressed */
				break;
	    }
	} else {
	    SDL_Delay(1);
	}
    }

    if (retbutton == SDLGUI_QUIT)
	my_shutdown = TRUE;

    return retbutton;
}



void SDLGui_DoDialogEnd(void)
{
    /* Restore background */
    if (pBgSurface) {
	SDL_BlitSurface(pBgSurface, &bgrect, pSdlGuiScrn,  &dlgrect);
	SDL_FreeSurface(pBgSurface);
    }
}



/*
 * Initialize a LCD object. Set the coordinates and dimenstions. Return index.
 */
int  SDLGui_LCDinit(SGOBJ *dlg, int *x, int *y, int *w, int *h, int *cols, int *rows, int lcdindex)
{
    int		i, index;

    /*
     * Search the LCD display
     */
    *x = *y = *w = *h = *cols = *rows = i = index = 0;
    for (;;) {
	if (dlg[i].type == -1) {
	    syslog(LOG_NOTICE, "SDLGui_LCDinit() lcdindex=%d not found", lcdindex);
	    return -1;
	}
	if (dlg[i].type == SGLCD) {
	    if (index == lcdindex)
		break;
	    index++;
	}
	i++;
    }
    if (debug)
    	fprintf(stdout, "SDLGui_LCDinit=%d LCD=%dx%d %dx%d\n", i, dlg[i].x, dlg[i].y, dlg[i].w, dlg[i].h);

    *cols = dlg[i].w;
    *rows = dlg[i].h;
    *w = dlg[i].w * (fontwidth + 2) + 10;
    *h = dlg[i].h * (fontheight + 2) + 4;
    if (dlg[i].x == -1) {
	*x = (dlg[0].w - *w) / 2;
    } else {
	*x = dlg[i].x;
    }
    *y = dlg[i].y;

    return lcdindex;
}


#endif

mercurial