brewpanel/sdlgui.c

Sat, 25 Apr 2020 20:31:31 +0200

author
Michiel Broek <mbroek@mbse.eu>
date
Sat, 25 Apr 2020 20:31:31 +0200
changeset 605
e00f8ff4de9a
parent 443
6b80a37fdf8d
child 637
21e542c15832
permissions
-rw-r--r--

Version 0.9.8. Added extra path to the fonts for Debian buster. Changed the PID to work on Proportional on Measurement. Added loops so that it looks like the PID is running at 100 mSec intervals.

/*****************************************************************************
 * 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