mirror of
https://github.com/Oibaf66/frodo-wii.git
synced 2024-11-29 23:14:23 +01:00
1477 lines
36 KiB
C++
1477 lines
36 KiB
C++
|
/*
|
||
|
* sdlgui.cpp
|
||
|
*
|
||
|
* This file is taken from the ARAnyM project which builds a new and powerful
|
||
|
* TOS/FreeMiNT compatible virtual machine running on almost any hardware.
|
||
|
*
|
||
|
* Copyright (c) 2001 Thomas Huth - taken from his hatari project
|
||
|
* Copyright (c) 2002-2005 Petr Stehlik of ARAnyM dev team (see AUTHORS)
|
||
|
*
|
||
|
* It 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 of the License, or
|
||
|
* (at your option) any later version.
|
||
|
*
|
||
|
* You should have received a copy of the GNU General Public License
|
||
|
* along with Frodo; if not, write to the Free Software
|
||
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||
|
*/
|
||
|
|
||
|
#include "sysdeps.h"
|
||
|
#include "sdlgui.h"
|
||
|
|
||
|
#include <cstdlib>
|
||
|
|
||
|
#include "font8.h"
|
||
|
|
||
|
static SDL_Surface *mainsurface = NULL;
|
||
|
#define sdlscrn mainsurface
|
||
|
|
||
|
static SDL_Surface *fontgfx=NULL;
|
||
|
static int fontwidth, fontheight; /* Height and width of the actual font */
|
||
|
|
||
|
// Stores current dialog coordinates
|
||
|
static SDL_Rect DialogRect = {0, 0, 0, 0};
|
||
|
|
||
|
// Used by SDLGui_Get[First|Next]BackgroundRect()
|
||
|
static SDL_Rect BackgroundRect = {0, 0, 0, 0};
|
||
|
static int BackgroundRectCounter;
|
||
|
enum
|
||
|
{
|
||
|
SG_BCKGND_RECT_BEGIN,
|
||
|
SG_BCKGND_RECT_TOP,
|
||
|
SG_BCKGND_RECT_LEFT,
|
||
|
SG_BCKGND_RECT_RIGHT,
|
||
|
SG_BCKGND_RECT_BOTTOM,
|
||
|
SG_BCKGND_RECT_END
|
||
|
};
|
||
|
|
||
|
SDL_Color blackc[] = {{0, 0, 0, 0}};
|
||
|
SDL_Color darkgreyc[] = {{128, 128, 128, 0}};
|
||
|
SDL_Color greyc[] = {{192, 192, 192, 0}};
|
||
|
SDL_Color whitec[] = {{255, 255, 255, 0}};
|
||
|
|
||
|
enum
|
||
|
{
|
||
|
SG_FIRST_EDITFIELD,
|
||
|
SG_PREVIOUS_EDITFIELD,
|
||
|
SG_NEXT_EDITFIELD,
|
||
|
SG_LAST_EDITFIELD
|
||
|
};
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Load an 1 plane XBM into a 8 planes SDL_Surface.
|
||
|
*/
|
||
|
static SDL_Surface *SDLGui_LoadXBM(int w, int h, Uint8 *srcbits)
|
||
|
{
|
||
|
SDL_Surface *bitmap;
|
||
|
Uint8 *dstbits;
|
||
|
int x, y, srcpitch;
|
||
|
|
||
|
/* Allocate the bitmap */
|
||
|
bitmap = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 8, 0, 0, 0, 0);
|
||
|
if ( bitmap == NULL )
|
||
|
{
|
||
|
// TODO panicbug("Couldn't allocate bitmap: %s", SDL_GetError());
|
||
|
return(NULL);
|
||
|
}
|
||
|
|
||
|
srcpitch = ((w + 7) / 8);
|
||
|
dstbits = (Uint8 *)bitmap->pixels;
|
||
|
int 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.
|
||
|
*/
|
||
|
bool SDLGui_Init(SDL_Surface *GUISurface)
|
||
|
{
|
||
|
mainsurface = GUISurface;
|
||
|
/* Load the font graphics: */
|
||
|
fontgfx = SDLGui_LoadXBM(font8_width, font8_height, font8_bits);
|
||
|
if (fontgfx == NULL)
|
||
|
{
|
||
|
// TODO panicbug("Could not create font data");
|
||
|
// TODO panicbug("ARAnyM GUI will not be available");
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
/* Set font color 0 as transparent */
|
||
|
SDL_SetColorKey(fontgfx, SDL_SRCCOLORKEY, 0);
|
||
|
|
||
|
/* Get the font width and height: */
|
||
|
fontwidth = fontgfx->w/16;
|
||
|
fontheight = fontgfx->h/16;
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Uninitialize the GUI.
|
||
|
*/
|
||
|
int SDLGui_UnInit()
|
||
|
{
|
||
|
if (fontgfx)
|
||
|
{
|
||
|
SDL_FreeSurface(fontgfx);
|
||
|
fontgfx = NULL;
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Compute real coordinates for a given object.
|
||
|
Note: centers dialog on screen.
|
||
|
*/
|
||
|
static void SDLGui_ObjCoord(SGOBJ *dlg, int objnum, SDL_Rect *rect)
|
||
|
{
|
||
|
rect->x = dlg[objnum].x * fontwidth;
|
||
|
rect->y = dlg[objnum].y * fontheight;
|
||
|
rect->w = dlg[objnum].w * fontwidth;
|
||
|
rect->h = dlg[objnum].h * fontheight;
|
||
|
|
||
|
rect->x += (sdlscrn->w - (dlg[0].w * fontwidth)) / 2;
|
||
|
rect->y += (sdlscrn->h - (dlg[0].h * fontheight)) / 2;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Compute real coordinates for a given object.
|
||
|
This one takes borders into account and give coordinates as seen by user
|
||
|
*/
|
||
|
void SDLGui_ObjFullCoord(SGOBJ *dlg, int objnum, SDL_Rect *coord)
|
||
|
{
|
||
|
SDLGui_ObjCoord(dlg, objnum, coord);
|
||
|
|
||
|
switch (dlg[objnum].type)
|
||
|
{
|
||
|
case SGBOX:
|
||
|
case SGBUTTON:
|
||
|
{
|
||
|
// Take border into account
|
||
|
int border_size;
|
||
|
|
||
|
if (dlg[objnum].flags & SG_SELECTABLE)
|
||
|
{
|
||
|
if (dlg[objnum].flags & SG_DEFAULT)
|
||
|
border_size = 4;
|
||
|
else
|
||
|
border_size = 3;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (dlg[objnum].flags & SG_BACKGROUND)
|
||
|
border_size = 6;
|
||
|
else
|
||
|
border_size = 5;
|
||
|
}
|
||
|
|
||
|
coord->x -= border_size;
|
||
|
coord->y -= border_size;
|
||
|
coord->w += (border_size * 2);
|
||
|
coord->h += (border_size * 2);
|
||
|
}
|
||
|
break;
|
||
|
case SGEDITFIELD:
|
||
|
// Allow one more pixel to the right for cursor
|
||
|
coord->w += 1;
|
||
|
// There is a line below
|
||
|
coord->h += 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Refresh display at given coordinates.
|
||
|
Unlike SDL_UpdateRect() this function can eat coords that goes beyond screen
|
||
|
boundaries.
|
||
|
"rect" will be modified to represent the area actually refreshed.
|
||
|
*/
|
||
|
void SDLGui_UpdateRect(SDL_Rect *rect)
|
||
|
{
|
||
|
if (rect->x < 0)
|
||
|
{
|
||
|
rect->w += rect->x;
|
||
|
rect->x = 0;
|
||
|
}
|
||
|
if ((rect->x + rect->w) > sdlscrn->w)
|
||
|
rect->w = (sdlscrn->w - rect->x);
|
||
|
|
||
|
if (rect->y < 0)
|
||
|
{
|
||
|
rect->h += rect->y;
|
||
|
rect->y = 0;
|
||
|
}
|
||
|
if ((rect->y + rect->h) > sdlscrn->h)
|
||
|
rect->h = (sdlscrn->h - rect->y);
|
||
|
|
||
|
if ((rect->w > 0) && (rect->h > 0))
|
||
|
SDL_UpdateRects(sdlscrn, 1, rect);
|
||
|
else
|
||
|
{
|
||
|
rect->x = 0;
|
||
|
rect->y = 0;
|
||
|
rect->w = 0;
|
||
|
rect->h = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Maps an SDL_Color to the screen format.
|
||
|
*/
|
||
|
Uint32 SDLGui_MapColor(SDL_Color *color)
|
||
|
{
|
||
|
return SDL_MapRGB(sdlscrn->format, color->r, color->g, color->b);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Refresh display to reflect an object change.
|
||
|
*/
|
||
|
void SDLGui_RefreshObj(SGOBJ *dlg, int objnum)
|
||
|
{
|
||
|
SDL_Rect coord;
|
||
|
|
||
|
SDLGui_ObjFullCoord(dlg, objnum, &coord);
|
||
|
|
||
|
screenlock();
|
||
|
SDLGui_UpdateRect(&coord);
|
||
|
screenunlock();
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Draw a text string.
|
||
|
*/
|
||
|
void SDLGui_Text(int x, int y, const char *txt, SDL_Color *col)
|
||
|
{
|
||
|
int i;
|
||
|
char c;
|
||
|
SDL_Rect sr, dr;
|
||
|
|
||
|
SDL_SetColors(fontgfx, col, 1, 1);
|
||
|
|
||
|
screenlock();
|
||
|
for (i = 0 ; txt[i] != 0 ; i++)
|
||
|
{
|
||
|
c = txt[i];
|
||
|
sr.x = fontwidth * (c % 16);
|
||
|
sr.y = fontheight * (c / 16);
|
||
|
sr.w = fontwidth;
|
||
|
sr.h = fontheight;
|
||
|
|
||
|
dr.x = x + (fontwidth * i);
|
||
|
dr.y = y;
|
||
|
dr.w = fontwidth;
|
||
|
dr.h = fontheight;
|
||
|
|
||
|
SDL_BlitSurface(fontgfx, &sr, sdlscrn, &dr);
|
||
|
}
|
||
|
screenunlock();
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Draw a dialog text object.
|
||
|
*/
|
||
|
void SDLGui_DrawText(SGOBJ *tdlg, int objnum)
|
||
|
{
|
||
|
SDL_Rect coord;
|
||
|
SDL_Color *textc, *backgroundc;
|
||
|
|
||
|
if (tdlg[objnum].state & SG_SELECTED)
|
||
|
{
|
||
|
textc = whitec;
|
||
|
backgroundc = darkgreyc;
|
||
|
}
|
||
|
else if (tdlg[objnum].state & SG_DISABLED)
|
||
|
{
|
||
|
textc = darkgreyc;
|
||
|
backgroundc = greyc;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
textc = blackc;
|
||
|
backgroundc = greyc;
|
||
|
}
|
||
|
|
||
|
SDLGui_ObjCoord(tdlg, objnum, &coord);
|
||
|
SDL_FillRect(sdlscrn, &coord, SDLGui_MapColor(backgroundc));
|
||
|
SDLGui_Text(coord.x, coord.y, tdlg[objnum].txt, textc);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Draw an edit field object.
|
||
|
*/
|
||
|
void SDLGui_DrawEditField(SGOBJ *edlg, int objnum)
|
||
|
{
|
||
|
SDL_Rect coord;
|
||
|
SDL_Color *textc;
|
||
|
|
||
|
if (edlg[objnum].state & SG_DISABLED)
|
||
|
textc = darkgreyc;
|
||
|
else
|
||
|
textc = blackc;
|
||
|
|
||
|
SDLGui_ObjCoord(edlg, objnum, &coord);
|
||
|
coord.w += 1;
|
||
|
SDL_FillRect(sdlscrn, &coord, SDLGui_MapColor(greyc));
|
||
|
SDLGui_Text(coord.x, coord.y, edlg[objnum].txt, textc);
|
||
|
|
||
|
// Draw a line below.
|
||
|
coord.y = coord.y + coord.h;
|
||
|
coord.h = 1;
|
||
|
SDL_FillRect(sdlscrn, &coord, SDLGui_MapColor(darkgreyc));
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Draw or erase cursor.
|
||
|
*/
|
||
|
void SDLGui_DrawCursor(SGOBJ *dlg, cursor_state *cursor)
|
||
|
{
|
||
|
if (cursor->object != -1)
|
||
|
{
|
||
|
SDL_Rect coord;
|
||
|
SDL_Color *cursorc;
|
||
|
|
||
|
SDLGui_DrawEditField(dlg, cursor->object);
|
||
|
|
||
|
if (cursor->blink_state)
|
||
|
cursorc = blackc;
|
||
|
else
|
||
|
cursorc = greyc;
|
||
|
|
||
|
SDLGui_ObjCoord(dlg, cursor->object, &coord);
|
||
|
coord.x += (cursor->position * fontwidth);
|
||
|
coord.w = 1;
|
||
|
SDL_FillRect(sdlscrn, &coord, SDLGui_MapColor(cursorc));
|
||
|
|
||
|
SDLGui_RefreshObj(dlg, cursor->object);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Draw a 3D effect around a given rectangle.
|
||
|
Rectangle is updated to the full size of the new object.
|
||
|
*/
|
||
|
void SDLGui_Draw3DAround(SDL_Rect *coord, SDL_Color *upleftc, SDL_Color *downrightc, SDL_Color *cornerc, int width)
|
||
|
{
|
||
|
SDL_Rect rect;
|
||
|
int i;
|
||
|
Uint32 upleftcol = SDLGui_MapColor(upleftc);
|
||
|
Uint32 downrightcol = SDLGui_MapColor(downrightc);
|
||
|
Uint32 cornercol = SDLGui_MapColor(cornerc);
|
||
|
|
||
|
screenlock();
|
||
|
|
||
|
for ( i = 1 ; i <= width ; i++)
|
||
|
{
|
||
|
rect.x = coord->x - i;
|
||
|
rect.y = coord->y - i;
|
||
|
rect.w = coord->w + (i * 2) - 1;
|
||
|
rect.h = 1;
|
||
|
SDL_FillRect(sdlscrn, &rect, upleftcol);
|
||
|
|
||
|
rect.x = coord->x - i;
|
||
|
rect.y = coord->y - i;
|
||
|
rect.w = 1;
|
||
|
rect.h = coord->h + (i * 2) - 1;
|
||
|
SDL_FillRect(sdlscrn, &rect, upleftcol);
|
||
|
|
||
|
rect.x = coord->x - i + 1;
|
||
|
rect.y = coord->y + coord->h - 1 + i;
|
||
|
rect.w = coord->w + (i * 2) - 1;
|
||
|
rect.h = 1;
|
||
|
SDL_FillRect(sdlscrn, &rect, downrightcol);
|
||
|
|
||
|
rect.x = coord->x + coord->w - 1 + i;
|
||
|
rect.y = coord->y - i + 1;
|
||
|
rect.w = 1;
|
||
|
rect.h = coord->h + (i * 2) - 1;
|
||
|
SDL_FillRect(sdlscrn, &rect, downrightcol);
|
||
|
|
||
|
rect.x = coord->x + coord->w + i - 1;
|
||
|
rect.y = coord->y - i;
|
||
|
rect.w = 1;
|
||
|
rect.h = 1;
|
||
|
SDL_FillRect(sdlscrn, &rect, cornercol);
|
||
|
|
||
|
rect.x = coord->x - i;
|
||
|
rect.y = coord->y + coord->h + i - 1;
|
||
|
rect.w = 1;
|
||
|
rect.h = 1;
|
||
|
SDL_FillRect(sdlscrn, &rect, cornercol);
|
||
|
}
|
||
|
|
||
|
screenunlock();
|
||
|
|
||
|
coord->x -= width;
|
||
|
coord->y -= width;
|
||
|
coord->w += (width * 2);
|
||
|
coord->h += (width * 2);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Draw a colored box around a given rectangle.
|
||
|
Rectangle is updated to the full size of the new object.
|
||
|
*/
|
||
|
void SDLGui_DrawBoxAround(SDL_Rect *coord, SDL_Color *color, int width)
|
||
|
{
|
||
|
SDL_Rect rect;
|
||
|
Uint32 col = SDLGui_MapColor(color);
|
||
|
|
||
|
screenlock();
|
||
|
|
||
|
rect.x = coord->x - width;
|
||
|
rect.y = coord->y - width;
|
||
|
rect.w = coord->w + (width * 2);
|
||
|
rect.h = width;
|
||
|
SDL_FillRect(sdlscrn, &rect, col);
|
||
|
|
||
|
rect.x = coord->x - width;
|
||
|
rect.y = coord->y - width;
|
||
|
rect.w = width;
|
||
|
rect.h = coord->h + (width * 2);
|
||
|
SDL_FillRect(sdlscrn, &rect, col);
|
||
|
|
||
|
rect.x = coord->x + coord->w;
|
||
|
rect.y = coord->y - width;
|
||
|
rect.w = width;
|
||
|
rect.h = coord->h + (width * 2);
|
||
|
SDL_FillRect(sdlscrn, &rect, col);
|
||
|
|
||
|
rect.x = coord->x - width;
|
||
|
rect.y = coord->y + coord->h;
|
||
|
rect.w = coord->w + (width * 2);
|
||
|
rect.h = width;
|
||
|
SDL_FillRect(sdlscrn, &rect, col);
|
||
|
|
||
|
screenunlock();
|
||
|
|
||
|
coord->x -= width;
|
||
|
coord->y -= width;
|
||
|
coord->w += (width * 2);
|
||
|
coord->h += (width * 2);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Draw a 3D box with given attributes.
|
||
|
*/
|
||
|
void SDLGui_Draw3DBox(SDL_Rect *coord,
|
||
|
SDL_Color *backgroundc,
|
||
|
SDL_Color *inboxc,
|
||
|
SDL_Color *upleftc,
|
||
|
SDL_Color *downrightc,
|
||
|
SDL_Color *outboxc,
|
||
|
int widthbackground,
|
||
|
int widthinbox,
|
||
|
int width3D1,
|
||
|
int width3D2,
|
||
|
int widthoutbox)
|
||
|
{
|
||
|
SDL_Rect rect;
|
||
|
|
||
|
screenlock();
|
||
|
|
||
|
// Draw background
|
||
|
rect.x = coord->x - widthbackground;
|
||
|
rect.y = coord->y - widthbackground;
|
||
|
rect.w = coord->w + (widthbackground * 2);
|
||
|
rect.h = coord->h + (widthbackground * 2);
|
||
|
SDL_FillRect(sdlscrn, &rect, SDLGui_MapColor(backgroundc));
|
||
|
|
||
|
screenunlock();
|
||
|
|
||
|
// Update coords
|
||
|
coord->x -= widthbackground;
|
||
|
coord->y -= widthbackground;
|
||
|
coord->w += (widthbackground * 2);
|
||
|
coord->h += (widthbackground * 2);
|
||
|
|
||
|
if (widthinbox > 0)
|
||
|
SDLGui_DrawBoxAround(coord, inboxc, widthinbox);
|
||
|
|
||
|
if (width3D1 > 0)
|
||
|
SDLGui_Draw3DAround(coord, upleftc, downrightc, backgroundc, width3D1);
|
||
|
|
||
|
if (width3D2 > 0)
|
||
|
SDLGui_Draw3DAround(coord, downrightc, upleftc, backgroundc, width3D2);
|
||
|
|
||
|
if (widthoutbox > 0)
|
||
|
SDLGui_DrawBoxAround(coord, outboxc, widthoutbox);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Draw a dialog box object.
|
||
|
*/
|
||
|
void SDLGui_DrawBox(SGOBJ *bdlg, int objnum)
|
||
|
{
|
||
|
SDL_Rect coord;
|
||
|
SDL_Color *my_blackc;
|
||
|
SDL_Color *upleftc, *downrightc;
|
||
|
|
||
|
SDLGui_ObjCoord(bdlg, objnum, &coord);
|
||
|
|
||
|
// Modify box drawing according to object state
|
||
|
if (bdlg[objnum].state & SG_DISABLED)
|
||
|
my_blackc = darkgreyc;
|
||
|
else
|
||
|
my_blackc = blackc;
|
||
|
|
||
|
if (bdlg[objnum].state & SG_SELECTED)
|
||
|
{
|
||
|
upleftc = darkgreyc;
|
||
|
downrightc = whitec;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
upleftc = whitec;
|
||
|
downrightc = darkgreyc;
|
||
|
}
|
||
|
|
||
|
// Draw box according to object flags
|
||
|
switch (bdlg[objnum].flags & (SG_SELECTABLE | SG_DEFAULT | SG_BACKGROUND))
|
||
|
{
|
||
|
case (SG_SELECTABLE | SG_DEFAULT | SG_BACKGROUND):
|
||
|
case (SG_SELECTABLE | SG_DEFAULT):
|
||
|
SDLGui_Draw3DBox(&coord,
|
||
|
greyc, NULL, upleftc, downrightc, my_blackc,
|
||
|
1, 0, 1, 0, 2);
|
||
|
break;
|
||
|
case (SG_SELECTABLE | SG_BACKGROUND):
|
||
|
case SG_SELECTABLE:
|
||
|
SDLGui_Draw3DBox(&coord,
|
||
|
greyc, NULL, upleftc, downrightc, my_blackc,
|
||
|
1, 0, 1, 0, 1);
|
||
|
break;
|
||
|
case (SG_DEFAULT | SG_BACKGROUND):
|
||
|
case SG_BACKGROUND:
|
||
|
SDLGui_Draw3DBox(&coord,
|
||
|
greyc, my_blackc, upleftc, downrightc, darkgreyc,
|
||
|
0, 2, 3, 0, 1);
|
||
|
break;
|
||
|
case SG_DEFAULT:
|
||
|
case 0:
|
||
|
SDLGui_Draw3DBox(&coord,
|
||
|
greyc, NULL, upleftc, downrightc, NULL,
|
||
|
3, 0, 1, 1, 0);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Draw a normal button.
|
||
|
*/
|
||
|
void SDLGui_DrawButton(SGOBJ *bdlg, int objnum)
|
||
|
{
|
||
|
SDL_Rect coord;
|
||
|
int x, y;
|
||
|
SDL_Color *textc;
|
||
|
|
||
|
SDLGui_ObjCoord(bdlg, objnum, &coord);
|
||
|
|
||
|
x = coord.x + ((coord.w - (strlen(bdlg[objnum].txt) * fontwidth)) / 2);
|
||
|
y = coord.y + ((coord.h - fontheight) / 2);
|
||
|
|
||
|
if (bdlg[objnum].state & SG_SELECTED)
|
||
|
{
|
||
|
x += 1;
|
||
|
y += 1;
|
||
|
}
|
||
|
|
||
|
if (bdlg[objnum].state & SG_DISABLED)
|
||
|
textc = darkgreyc;
|
||
|
else
|
||
|
textc = blackc;
|
||
|
|
||
|
SDLGui_DrawBox(bdlg, objnum);
|
||
|
SDLGui_Text(x, y, bdlg[objnum].txt, textc);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Draw a dialog check box object state.
|
||
|
*/
|
||
|
void SDLGui_DrawCheckBoxState(SGOBJ *cdlg, int objnum)
|
||
|
{
|
||
|
Uint32 grey = SDLGui_MapColor(greyc);
|
||
|
SDL_Rect coord;
|
||
|
char str[2];
|
||
|
SDL_Color *textc;
|
||
|
|
||
|
SDLGui_ObjCoord(cdlg, objnum, &coord);
|
||
|
|
||
|
if (cdlg[objnum].flags & SG_RADIO)
|
||
|
{
|
||
|
if (cdlg[objnum].state & SG_SELECTED)
|
||
|
str[0]=SGCHECKBOX_RADIO_SELECTED;
|
||
|
else
|
||
|
str[0]=SGCHECKBOX_RADIO_NORMAL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (cdlg[objnum].state & SG_SELECTED)
|
||
|
str[0]=SGCHECKBOX_SELECTED;
|
||
|
else
|
||
|
str[0]=SGCHECKBOX_NORMAL;
|
||
|
}
|
||
|
|
||
|
if (cdlg[objnum].state & SG_DISABLED)
|
||
|
textc = darkgreyc;
|
||
|
else
|
||
|
textc = blackc;
|
||
|
|
||
|
str[1]='\0';
|
||
|
|
||
|
coord.w = fontwidth;
|
||
|
coord.h = fontheight;
|
||
|
|
||
|
if (cdlg[objnum].flags & SG_BUTTON_RIGHT)
|
||
|
coord.x += ((strlen(cdlg[objnum].txt) + 1) * fontwidth);
|
||
|
|
||
|
SDL_FillRect(sdlscrn, &coord, grey);
|
||
|
SDLGui_Text(coord.x, coord.y, str, textc);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Draw a dialog check box object.
|
||
|
*/
|
||
|
void SDLGui_DrawCheckBox(SGOBJ *cdlg, int objnum)
|
||
|
{
|
||
|
SDL_Rect coord;
|
||
|
SDL_Color *textc;
|
||
|
|
||
|
SDLGui_ObjCoord(cdlg, objnum, &coord);
|
||
|
|
||
|
if (!(cdlg[objnum].flags&SG_BUTTON_RIGHT))
|
||
|
coord.x += (fontwidth * 2);
|
||
|
|
||
|
if (cdlg[objnum].state & SG_DISABLED)
|
||
|
textc = darkgreyc;
|
||
|
else
|
||
|
textc = blackc;
|
||
|
|
||
|
SDLGui_Text(coord.x, coord.y, cdlg[objnum].txt, textc);
|
||
|
SDLGui_DrawCheckBoxState(cdlg, objnum);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Draw a dialog popup button object.
|
||
|
*/
|
||
|
void SDLGui_DrawPopupButton(SGOBJ *pdlg, int objnum)
|
||
|
{
|
||
|
SDL_Rect coord;
|
||
|
const char *downstr = "\x02";
|
||
|
SDL_Color *textc;
|
||
|
|
||
|
if (pdlg[objnum].state & SG_DISABLED)
|
||
|
textc = darkgreyc;
|
||
|
else
|
||
|
textc = blackc;
|
||
|
|
||
|
SDLGui_DrawBox(pdlg, objnum);
|
||
|
|
||
|
SDLGui_ObjCoord(pdlg, objnum, &coord);
|
||
|
|
||
|
SDLGui_Text(coord.x, coord.y, pdlg[objnum].txt, textc);
|
||
|
SDLGui_Text(coord.x+coord.w-fontwidth, coord.y, downstr, textc);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Draw an object.
|
||
|
*/
|
||
|
void SDLGui_DrawObject(SGOBJ *dlg, int objnum)
|
||
|
{
|
||
|
switch (dlg[objnum].type)
|
||
|
{
|
||
|
case SGBOX:
|
||
|
SDLGui_DrawBox(dlg, objnum);
|
||
|
break;
|
||
|
case SGTEXT:
|
||
|
SDLGui_DrawText(dlg, objnum);
|
||
|
break;
|
||
|
case SGEDITFIELD:
|
||
|
SDLGui_DrawEditField(dlg, objnum);
|
||
|
break;
|
||
|
case SGBUTTON:
|
||
|
SDLGui_DrawButton(dlg, objnum);
|
||
|
break;
|
||
|
case SGCHECKBOX:
|
||
|
SDLGui_DrawCheckBox(dlg, objnum);
|
||
|
break;
|
||
|
case SGPOPUP:
|
||
|
SDLGui_DrawPopupButton(dlg, objnum);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Draw a whole dialog.
|
||
|
*/
|
||
|
void SDLGui_DrawDialog(SGOBJ *dlg)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
// Store dialog coordinates
|
||
|
SDLGui_ObjFullCoord(dlg, 0, &DialogRect);
|
||
|
|
||
|
for (i = 0 ; dlg[i].type != -1 ; i++)
|
||
|
{
|
||
|
if (dlg[i].state & SG_HIDDEN) continue;
|
||
|
SDLGui_DrawObject(dlg, i);
|
||
|
}
|
||
|
SDLGui_RefreshObj(dlg, 0);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Search default object in a dialog.
|
||
|
*/
|
||
|
int SDLGui_FindDefaultObj(SGOBJ *dlg)
|
||
|
{
|
||
|
int i = 0;
|
||
|
|
||
|
while (dlg[i].type != -1)
|
||
|
{
|
||
|
if (dlg[i].flags & SG_DEFAULT)
|
||
|
return i;
|
||
|
i++;
|
||
|
}
|
||
|
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Search an object at given coordinates.
|
||
|
*/
|
||
|
int SDLGui_FindObj(SGOBJ *dlg, int fx, int fy)
|
||
|
{
|
||
|
SDL_Rect coord;
|
||
|
int end, i;
|
||
|
int ob = -1;
|
||
|
|
||
|
// Search end object in dialog
|
||
|
i = 0;
|
||
|
while (dlg[i++].type != -1);
|
||
|
end = i;
|
||
|
|
||
|
// Now check each object
|
||
|
for (i = end-1 ; i >= 0 ; i--)
|
||
|
{
|
||
|
SDLGui_ObjFullCoord(dlg, i, &coord);
|
||
|
|
||
|
if(fx >= coord.x &&
|
||
|
fy >= coord.y &&
|
||
|
fx < (coord.x + coord.w) &&
|
||
|
fy < (coord.y + coord.h))
|
||
|
{
|
||
|
if (dlg[i].state & (SG_HIDDEN | SG_DISABLED)) continue;
|
||
|
ob = i;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ob;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
A radio object has been selected. Let's deselect any other in his group.
|
||
|
*/
|
||
|
void SDLGui_SelectRadioObject(SGOBJ *dlg, int clicked_obj)
|
||
|
{
|
||
|
int obj;
|
||
|
|
||
|
// Find first radio object in this group
|
||
|
obj = clicked_obj;
|
||
|
while (dlg[--obj].flags & SG_RADIO);
|
||
|
|
||
|
// Update state
|
||
|
while (dlg[++obj].flags & SG_RADIO)
|
||
|
{
|
||
|
// This code scan every object in the group. This allows to solve cases
|
||
|
// where multiple objects where selected in the group by clicking one.
|
||
|
if ((obj != clicked_obj) && (dlg[obj].state & SG_SELECTED))
|
||
|
{
|
||
|
// Deselect this radio button
|
||
|
dlg[obj].state &= ~SG_SELECTED;
|
||
|
SDLGui_DrawObject(dlg, obj);
|
||
|
SDLGui_RefreshObj(dlg, obj);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Update clicked object state depending on given mouse coordinates.
|
||
|
Returns true if the mouse is over the object, false otherwise.
|
||
|
*/
|
||
|
bool SDLGui_UpdateObjState(SGOBJ *dlg, int clicked_obj, int original_state,
|
||
|
int x, int y)
|
||
|
{
|
||
|
int obj;
|
||
|
|
||
|
obj = SDLGui_FindObj(dlg, x, y);
|
||
|
|
||
|
// Special case : user clicked on an already selected radio object
|
||
|
// do not modify its state.
|
||
|
// We handle it here because it allows to exit if the object is SG_EXIT or
|
||
|
// SG_TOUCHEXIT without any additional test.
|
||
|
if ((dlg[clicked_obj].flags & SG_RADIO) && (original_state & SG_SELECTED))
|
||
|
return (obj == clicked_obj);
|
||
|
|
||
|
if (((obj != clicked_obj) &&
|
||
|
(dlg[clicked_obj].state != original_state)) ||
|
||
|
((obj == clicked_obj) &&
|
||
|
(dlg[clicked_obj].state == original_state)))
|
||
|
{
|
||
|
if (dlg[clicked_obj].flags & SG_SELECTABLE)
|
||
|
{
|
||
|
dlg[clicked_obj].state ^= SG_SELECTED;
|
||
|
SDLGui_DrawObject(dlg, clicked_obj);
|
||
|
SDLGui_RefreshObj(dlg, clicked_obj);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return (obj == clicked_obj);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Search edit field in a dialog.
|
||
|
*/
|
||
|
int SDLGui_FindEditField(SGOBJ *dlg, int objnum, int mode)
|
||
|
{
|
||
|
int i, j;
|
||
|
|
||
|
switch (mode)
|
||
|
{
|
||
|
case SG_FIRST_EDITFIELD:
|
||
|
i = 0;
|
||
|
while (dlg[i].type != -1)
|
||
|
{
|
||
|
if ((dlg[i].type == SGEDITFIELD) &&
|
||
|
((dlg[i].state & (SG_HIDDEN | SG_DISABLED)) == 0))
|
||
|
return i;
|
||
|
i++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SG_PREVIOUS_EDITFIELD:
|
||
|
i = objnum - 1;
|
||
|
while (i >= 0)
|
||
|
{
|
||
|
if ((dlg[i].type == SGEDITFIELD) &&
|
||
|
((dlg[i].state & (SG_HIDDEN | SG_DISABLED)) == 0))
|
||
|
return i;
|
||
|
i--;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SG_NEXT_EDITFIELD:
|
||
|
i = objnum + 1;
|
||
|
while (dlg[i].type != -1)
|
||
|
{
|
||
|
if ((dlg[i].type == SGEDITFIELD) &&
|
||
|
((dlg[i].state & (SG_HIDDEN | SG_DISABLED)) == 0))
|
||
|
return i;
|
||
|
i++;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SG_LAST_EDITFIELD:
|
||
|
i = objnum + 1;
|
||
|
j = -1;
|
||
|
while (dlg[i].type != -1)
|
||
|
{
|
||
|
if ((dlg[i].type == SGEDITFIELD) &&
|
||
|
((dlg[i].state & (SG_HIDDEN | SG_DISABLED)) == 0))
|
||
|
j = i;
|
||
|
i++;
|
||
|
}
|
||
|
if (j != -1)
|
||
|
return j;
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return objnum;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Move cursor to another edit field.
|
||
|
*/
|
||
|
void SDLGui_MoveCursor(SGOBJ *dlg, cursor_state *cursor, int mode)
|
||
|
{
|
||
|
int new_object;
|
||
|
|
||
|
new_object = SDLGui_FindEditField(dlg, cursor->object, mode);
|
||
|
|
||
|
if (new_object != cursor->object)
|
||
|
{
|
||
|
/* Erase old cursor */
|
||
|
cursor->blink_state = false;
|
||
|
SDLGui_DrawCursor(dlg, cursor);
|
||
|
|
||
|
cursor->object = new_object;
|
||
|
cursor->position = strlen(dlg[new_object].txt);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* We stay in the same field */
|
||
|
/* Move cursor to begin or end of text depending on mode */
|
||
|
switch (mode)
|
||
|
{
|
||
|
case SG_FIRST_EDITFIELD:
|
||
|
case SG_PREVIOUS_EDITFIELD:
|
||
|
cursor->position = 0;
|
||
|
break;
|
||
|
|
||
|
case SG_NEXT_EDITFIELD:
|
||
|
case SG_LAST_EDITFIELD:
|
||
|
cursor->position = strlen(dlg[new_object].txt);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Handle mouse clicks on edit fields.
|
||
|
*/
|
||
|
void SDLGui_ClickEditField(SGOBJ *dlg, cursor_state *cursor, int clicked_obj, int x)
|
||
|
{
|
||
|
SDL_Rect coord;
|
||
|
int i, j;
|
||
|
|
||
|
/* Erase old cursor */
|
||
|
cursor->blink_state = false;
|
||
|
SDLGui_DrawCursor(dlg, cursor);
|
||
|
|
||
|
SDLGui_ObjFullCoord(dlg, clicked_obj, &coord);
|
||
|
i = (x - coord.x + (fontwidth / 2)) / fontwidth;
|
||
|
j = strlen(dlg[clicked_obj].txt);
|
||
|
|
||
|
cursor->object = clicked_obj;
|
||
|
cursor->position = MIN(i, j);
|
||
|
cursor->blink_state = true;
|
||
|
cursor->blink_counter = 0;
|
||
|
SDLGui_DrawCursor(dlg, cursor);
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Handle mouse clicks.
|
||
|
*/
|
||
|
int SDLGui_MouseClick(SGOBJ *dlg, int fx, int fy, cursor_state *cursor)
|
||
|
{
|
||
|
int clicked_obj;
|
||
|
int return_obj = -1;
|
||
|
int original_state = 0;
|
||
|
int x, y;
|
||
|
|
||
|
clicked_obj = SDLGui_FindObj(dlg, fx, fy);
|
||
|
|
||
|
if (clicked_obj >= 0)
|
||
|
{
|
||
|
original_state = dlg[clicked_obj].state;
|
||
|
SDLGui_UpdateObjState(dlg, clicked_obj, original_state, fx, fy);
|
||
|
|
||
|
if (dlg[clicked_obj].flags & SG_TOUCHEXIT)
|
||
|
{
|
||
|
return_obj = clicked_obj;
|
||
|
clicked_obj = -1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while (clicked_obj >= 0)
|
||
|
{
|
||
|
SDL_Event evnt;
|
||
|
// SDL_PumpEvents() - not necessary, the main check_event thread calls it
|
||
|
if (SDL_PeepEvents(&evnt, 1, SDL_GETEVENT, SDL_EVENTMASK(SDL_USEREVENT)))
|
||
|
{
|
||
|
switch (evnt.user.code)
|
||
|
{
|
||
|
case SDL_USEREVENT:
|
||
|
// a signal that resolution has changed
|
||
|
// Restore clicked object original state
|
||
|
dlg[clicked_obj].state = original_state;
|
||
|
|
||
|
// re-draw dialog
|
||
|
SDLGui_DrawDialog(dlg);
|
||
|
|
||
|
// Exit from mouse click handling.
|
||
|
clicked_obj = -1;
|
||
|
break;
|
||
|
|
||
|
case SDL_MOUSEBUTTONUP:
|
||
|
x = reinterpret_cast<intptr>(evnt.user.data1);
|
||
|
y = reinterpret_cast<intptr>(evnt.user.data2);
|
||
|
if (SDLGui_UpdateObjState(dlg, clicked_obj, original_state, x, y))
|
||
|
{
|
||
|
// true if mouse button is released over clicked object.
|
||
|
// If applicable, the object has been selected by
|
||
|
// SDLGui_UpdateObjState(). Let's do additional handling here.
|
||
|
|
||
|
// Exit if object is an SG_EXIT one.
|
||
|
if (dlg[clicked_obj].flags & SG_EXIT)
|
||
|
return_obj = clicked_obj;
|
||
|
|
||
|
// If it's a SG_RADIO object, deselect other objects in his group.
|
||
|
if (dlg[clicked_obj].flags & SG_RADIO)
|
||
|
SDLGui_SelectRadioObject(dlg, clicked_obj);
|
||
|
|
||
|
if (dlg[clicked_obj].type == SGEDITFIELD)
|
||
|
SDLGui_ClickEditField(dlg, cursor, clicked_obj, x);
|
||
|
}
|
||
|
|
||
|
// Exit from mouse click handling.
|
||
|
clicked_obj = -1;
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// No special event occured.
|
||
|
// Update object state according to mouse coordinates.
|
||
|
SDL_GetMouseState(&x, &y);
|
||
|
SDLGui_UpdateObjState(dlg, clicked_obj, original_state, x, y);
|
||
|
|
||
|
// Wait a little to avoid eating CPU.
|
||
|
SDL_Delay(100);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return return_obj;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Handle key press.
|
||
|
*/
|
||
|
int SDLGui_KeyPress(SGOBJ *dlg, int keysym, int mod, cursor_state *cursor)
|
||
|
{
|
||
|
int return_obj = -1;
|
||
|
int obj;
|
||
|
|
||
|
if (cursor->object != -1)
|
||
|
{
|
||
|
switch(keysym)
|
||
|
{
|
||
|
case SDLK_RETURN:
|
||
|
case SDLK_KP_ENTER:
|
||
|
break;
|
||
|
|
||
|
case SDLK_BACKSPACE:
|
||
|
if (cursor->position > 0)
|
||
|
{
|
||
|
memmove(&dlg[cursor->object].txt[cursor->position-1],
|
||
|
&dlg[cursor->object].txt[cursor->position],
|
||
|
strlen(&dlg[cursor->object].txt[cursor->position])+1);
|
||
|
cursor->position--;
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SDLK_DELETE:
|
||
|
if(cursor->position < (int)strlen(dlg[cursor->object].txt))
|
||
|
{
|
||
|
memmove(&dlg[cursor->object].txt[cursor->position],
|
||
|
&dlg[cursor->object].txt[cursor->position+1],
|
||
|
strlen(&dlg[cursor->object].txt[cursor->position+1])+1);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SDLK_LEFT:
|
||
|
if (cursor->position > 0)
|
||
|
cursor->position--;
|
||
|
break;
|
||
|
|
||
|
case SDLK_RIGHT:
|
||
|
if (cursor->position < (int)strlen(dlg[cursor->object].txt))
|
||
|
cursor->position++;
|
||
|
break;
|
||
|
|
||
|
case SDLK_DOWN:
|
||
|
SDLGui_MoveCursor(dlg, cursor, SG_NEXT_EDITFIELD);
|
||
|
break;
|
||
|
|
||
|
case SDLK_UP:
|
||
|
SDLGui_MoveCursor(dlg, cursor, SG_PREVIOUS_EDITFIELD);
|
||
|
break;
|
||
|
|
||
|
case SDLK_TAB:
|
||
|
if (mod & KMOD_SHIFT)
|
||
|
SDLGui_MoveCursor(dlg, cursor, SG_PREVIOUS_EDITFIELD);
|
||
|
else
|
||
|
SDLGui_MoveCursor(dlg, cursor, SG_NEXT_EDITFIELD);
|
||
|
break;
|
||
|
|
||
|
case SDLK_HOME:
|
||
|
if (mod & KMOD_CTRL)
|
||
|
SDLGui_MoveCursor(dlg, cursor, SG_FIRST_EDITFIELD);
|
||
|
else
|
||
|
cursor->position = 0;
|
||
|
break;
|
||
|
|
||
|
case SDLK_END:
|
||
|
if (mod & KMOD_CTRL)
|
||
|
SDLGui_MoveCursor(dlg, cursor, SG_LAST_EDITFIELD);
|
||
|
else
|
||
|
cursor->position = strlen(dlg[cursor->object].txt);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
if ((keysym >= SDLK_KP0) && (keysym <= SDLK_KP9))
|
||
|
{
|
||
|
// map numpad numbers to normal numbers
|
||
|
keysym -= (SDLK_KP0 - SDLK_0);
|
||
|
}
|
||
|
/* If it is a "good" key then insert it into the text field */
|
||
|
if ((keysym >= SDLK_SPACE) && (keysym < SDLK_KP0))
|
||
|
{
|
||
|
if (strlen(dlg[cursor->object].txt) < dlg[cursor->object].w)
|
||
|
{
|
||
|
memmove(&dlg[cursor->object].txt[cursor->position+1],
|
||
|
&dlg[cursor->object].txt[cursor->position],
|
||
|
strlen(&dlg[cursor->object].txt[cursor->position])+1);
|
||
|
if (mod & KMOD_SHIFT)
|
||
|
dlg[cursor->object].txt[cursor->position] = toupper(keysym);
|
||
|
else
|
||
|
dlg[cursor->object].txt[cursor->position] = keysym;
|
||
|
cursor->position += 1;
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
switch(keysym)
|
||
|
{
|
||
|
case SDLK_RETURN:
|
||
|
case SDLK_KP_ENTER:
|
||
|
obj = SDLGui_FindDefaultObj(dlg);
|
||
|
if (obj >= 0)
|
||
|
{
|
||
|
dlg[obj].state ^= SG_SELECTED;
|
||
|
SDLGui_DrawObject(dlg, obj);
|
||
|
SDLGui_RefreshObj(dlg, obj);
|
||
|
if (dlg[obj].flags & (SG_EXIT | SG_TOUCHEXIT))
|
||
|
{
|
||
|
return_obj = obj;
|
||
|
SDL_Delay(300);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
// Force cursor display. Should ease text input.
|
||
|
cursor->blink_state = true;
|
||
|
cursor->blink_counter = 0;
|
||
|
// Redraw current edit field...
|
||
|
SDLGui_DrawCursor(dlg, cursor);
|
||
|
|
||
|
return return_obj;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Used to update screen while GUI is opened. Return a list of rectangles that
|
||
|
covers the screen without overlaping the current dialog.
|
||
|
*/
|
||
|
SDL_Rect *SDLGui_GetFirstBackgroundRect(void)
|
||
|
{
|
||
|
// Reset counter...
|
||
|
BackgroundRectCounter = SG_BCKGND_RECT_BEGIN;
|
||
|
// And returns first rectangle
|
||
|
return SDLGui_GetNextBackgroundRect();
|
||
|
}
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Returns next rectangle to be redrawn to update screen or NULL if we reached
|
||
|
the end of the list.
|
||
|
This code is "flying dialog" ready :)
|
||
|
It will need some updating if we implement popup buttons handled by sdlgui,
|
||
|
as the popup could be higher than the root box...
|
||
|
I used some recursivity here to simplify the code.
|
||
|
*/
|
||
|
SDL_Rect *SDLGui_GetNextBackgroundRect(void)
|
||
|
{
|
||
|
SDL_Rect *return_rect = NULL;
|
||
|
|
||
|
switch (BackgroundRectCounter)
|
||
|
{
|
||
|
case SG_BCKGND_RECT_END:
|
||
|
// Nothing to do : return_rect is already initialized to NULL.
|
||
|
break;
|
||
|
|
||
|
case SG_BCKGND_RECT_BEGIN:
|
||
|
if (DialogRect.w == 0)
|
||
|
{
|
||
|
// The dialog is not drawn yet...
|
||
|
// Let's redraw the full screen.
|
||
|
BackgroundRect.x = 0;
|
||
|
BackgroundRect.y = 0;
|
||
|
BackgroundRect.w = sdlscrn->w;
|
||
|
BackgroundRect.h = sdlscrn->h;
|
||
|
return_rect = &BackgroundRect;
|
||
|
// We reached the end of the list.
|
||
|
BackgroundRectCounter = SG_BCKGND_RECT_END;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
BackgroundRectCounter = SG_BCKGND_RECT_TOP;
|
||
|
return_rect = SDLGui_GetNextBackgroundRect();
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case SG_BCKGND_RECT_TOP:
|
||
|
BackgroundRectCounter = SG_BCKGND_RECT_LEFT;
|
||
|
if (DialogRect.y > 0)
|
||
|
{
|
||
|
BackgroundRect.x = 0;
|
||
|
BackgroundRect.y = 0;
|
||
|
BackgroundRect.w = sdlscrn->w;
|
||
|
BackgroundRect.h = DialogRect.y;
|
||
|
return_rect = &BackgroundRect;
|
||
|
}
|
||
|
else
|
||
|
return_rect = SDLGui_GetNextBackgroundRect();
|
||
|
break;
|
||
|
|
||
|
case SG_BCKGND_RECT_LEFT:
|
||
|
BackgroundRectCounter = SG_BCKGND_RECT_RIGHT;
|
||
|
if (DialogRect.x > 0)
|
||
|
{
|
||
|
BackgroundRect.x = 0;
|
||
|
BackgroundRect.y = (DialogRect.y > 0) ? DialogRect.y : 0;
|
||
|
BackgroundRect.w = DialogRect.x;
|
||
|
BackgroundRect.h =
|
||
|
((DialogRect.y + DialogRect.h) < (int)sdlscrn->h) ?
|
||
|
(DialogRect.h + DialogRect.y - BackgroundRect.y) :
|
||
|
(sdlscrn->h - DialogRect.y);
|
||
|
return_rect = &BackgroundRect;
|
||
|
}
|
||
|
else
|
||
|
return_rect = SDLGui_GetNextBackgroundRect();
|
||
|
break;
|
||
|
|
||
|
case SG_BCKGND_RECT_RIGHT:
|
||
|
BackgroundRectCounter = SG_BCKGND_RECT_BOTTOM;
|
||
|
if ((DialogRect.x + DialogRect.w) < (int)sdlscrn->w)
|
||
|
{
|
||
|
BackgroundRect.x = DialogRect.x + DialogRect.w;
|
||
|
BackgroundRect.y = (DialogRect.y > 0) ? DialogRect.y : 0;
|
||
|
BackgroundRect.w = sdlscrn->w - (DialogRect.x + DialogRect.w);
|
||
|
BackgroundRect.h =
|
||
|
((DialogRect.y + DialogRect.h) < (int)sdlscrn->w) ?
|
||
|
(DialogRect.h + DialogRect.y - BackgroundRect.y) :
|
||
|
(sdlscrn->h - DialogRect.y);
|
||
|
return_rect = &BackgroundRect;
|
||
|
}
|
||
|
else
|
||
|
return_rect = SDLGui_GetNextBackgroundRect();
|
||
|
break;
|
||
|
|
||
|
case SG_BCKGND_RECT_BOTTOM:
|
||
|
BackgroundRectCounter = SG_BCKGND_RECT_END;
|
||
|
if ((DialogRect.y + DialogRect.h) < (int)sdlscrn->h)
|
||
|
{
|
||
|
// Bottom
|
||
|
BackgroundRect.x = 0;
|
||
|
BackgroundRect.y = DialogRect.y + DialogRect.h;
|
||
|
BackgroundRect.w = sdlscrn->w;
|
||
|
BackgroundRect.h = sdlscrn->h - (DialogRect.y + DialogRect.h);
|
||
|
return_rect = &BackgroundRect;
|
||
|
}
|
||
|
else
|
||
|
return_rect = SDLGui_GetNextBackgroundRect();
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return return_rect;
|
||
|
}
|
||
|
|
||
|
SDL_Event getEvent(SGOBJ *dlg, cursor_state *cursor)
|
||
|
{
|
||
|
int i = 0;
|
||
|
while(1) {
|
||
|
SDL_Event evnt;
|
||
|
// fprintf(stderr, "Debug Before Peep events\n");
|
||
|
if (SDL_PeepEvents(&evnt, 1, SDL_GETEVENT, SDL_EVENTMASK(SDL_USEREVENT)))
|
||
|
{
|
||
|
fprintf(stderr, "Debug Peep events %d\n",i++);
|
||
|
SDL_Event e;
|
||
|
switch(evnt.user.code)
|
||
|
{
|
||
|
case SDL_KEYDOWN:
|
||
|
case SDL_KEYUP:
|
||
|
e.type = evnt.user.code;
|
||
|
e.key.keysym.sym = (SDLKey)reinterpret_cast<uintptr>(evnt.user.data1);
|
||
|
e.key.keysym.mod = (SDLMod)reinterpret_cast<uintptr>(evnt.user.data2);
|
||
|
return e;
|
||
|
|
||
|
case SDL_MOUSEBUTTONDOWN:
|
||
|
case SDL_MOUSEBUTTONUP:
|
||
|
e.type = evnt.user.code;
|
||
|
if (evnt.user.code == SDL_MOUSEBUTTONDOWN)
|
||
|
fprintf(stderr, "Debug mouse down\n");
|
||
|
else
|
||
|
fprintf(stderr, "Debug mouse down\n");
|
||
|
e.button.x = reinterpret_cast<intptr>(evnt.user.data1);
|
||
|
e.button.y = reinterpret_cast<intptr>(evnt.user.data2);
|
||
|
return e;
|
||
|
|
||
|
case SDL_USEREVENT:
|
||
|
// a signal that resolution has changed
|
||
|
if (dlg != NULL)
|
||
|
SDLGui_DrawDialog(dlg); // re-draw dialog
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// No special event occured.
|
||
|
// Wait a little to avoid eating CPU.
|
||
|
SDL_Delay(50);
|
||
|
if (cursor != NULL) {
|
||
|
cursor->blink_counter++;
|
||
|
if (cursor->blink_counter >= 10) {
|
||
|
cursor->blink_counter = 0;
|
||
|
cursor->blink_state = !cursor->blink_state;
|
||
|
if (dlg != NULL)
|
||
|
SDLGui_DrawCursor(dlg, cursor);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*-----------------------------------------------------------------------*/
|
||
|
/*
|
||
|
Show and process a dialog. Returns the button number that has been
|
||
|
pressed. Does NOT handle SDL_QUIT - you must handle it before you
|
||
|
pass the input event to the SDL GUI.
|
||
|
*/
|
||
|
int SDLGui_DoDialog(SGOBJ *dlg)
|
||
|
{
|
||
|
int return_obj = -1;
|
||
|
int obj;
|
||
|
int x, y;
|
||
|
// int keysym, mod;
|
||
|
cursor_state cursor;
|
||
|
|
||
|
// Is the left mouse button still pressed? Yes -> Handle TOUCHEXIT objects here
|
||
|
bool stillPressed = (SDL_GetMouseState(&x, &y) & SDL_BUTTON(1));
|
||
|
obj = SDLGui_FindObj(dlg, x, y);
|
||
|
if (stillPressed && (obj >= 0) && (dlg[obj].flags & SG_TOUCHEXIT))
|
||
|
{
|
||
|
// Mouse button is pressed over a TOUCHEXIT Button
|
||
|
// Toogle its state before drawing anything (it has been deselected before).
|
||
|
dlg[obj].state ^= SG_SELECTED;
|
||
|
|
||
|
return_obj = obj;
|
||
|
}
|
||
|
|
||
|
cursor.object = SDLGui_FindEditField(dlg, -1, SG_FIRST_EDITFIELD);
|
||
|
cursor.position = (cursor.object != -1) ? strlen(dlg[cursor.object].txt) : 0;
|
||
|
cursor.blink_counter = 0;
|
||
|
cursor.blink_state = true;
|
||
|
|
||
|
SDLGui_DrawDialog(dlg);
|
||
|
|
||
|
/* The main loop */
|
||
|
while (return_obj < 0)
|
||
|
{
|
||
|
fprintf(stderr, "Debug SDL main loop\n");
|
||
|
SDL_Event evnt = getEvent(dlg, &cursor);
|
||
|
fprintf(stderr, "Debug SDL main loop got event\n");
|
||
|
switch(evnt.type)
|
||
|
{
|
||
|
case SDL_KEYDOWN:
|
||
|
return_obj = SDLGui_KeyPress(dlg, evnt.key.keysym.sym, evnt.key.keysym.mod, &cursor);
|
||
|
break;
|
||
|
|
||
|
case SDL_MOUSEBUTTONDOWN:
|
||
|
return_obj = SDLGui_MouseClick(dlg, evnt.button.x, evnt.button.y, &cursor);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
fprintf(stderr, "Debug SDL main loop finished\n");
|
||
|
if (dlg[return_obj].type == SGBUTTON)
|
||
|
{
|
||
|
// Deselect button...
|
||
|
// BUG: This should be caller responsibility
|
||
|
dlg[return_obj].state ^= SG_SELECTED;
|
||
|
}
|
||
|
|
||
|
return return_obj;
|
||
|
}
|