warzone2100/lib/widget/widget.c

1772 lines
39 KiB
C

/*
This file is part of Warzone 2100.
Copyright (C) 1999-2004 Eidos Interactive
Copyright (C) 2005-2007 Warzone Resurrection Project
Warzone 2100 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.
Warzone 2100 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 Warzone 2100; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/** @file
* The main interface functions to the widget library
*/
#include "lib/framework/frame.h"
#include "lib/framework/frameint.h"
#include "lib/ivis_common/textdraw.h"
#include "widget.h"
#include "widgint.h"
#include "form.h"
#include "label.h"
#include "button.h"
#include "editbox.h"
#include "bar.h"
#include "slider.h"
#include "tip.h"
static BOOL bWidgetsActive = true;
/* The widget the mouse is over this update */
static WIDGET *psMouseOverWidget = NULL;
static UDWORD pressed, released;
static WIDGET_AUDIOCALLBACK AudioCallback = NULL;
static SWORD HilightAudioID = -1;
static SWORD ClickedAudioID = -1;
/* Function prototypes */
void widgHiLite(WIDGET *psWidget, W_CONTEXT *psContext);
void widgHiLiteLost(WIDGET *psWidget, W_CONTEXT *psContext);
static void widgClicked(WIDGET *psWidget, UDWORD key, W_CONTEXT *psContext);
static void widgReleased(WIDGET *psWidget, UDWORD key, W_CONTEXT *psContext);
static void widgRun(WIDGET *psWidget, W_CONTEXT *psContext);
static void widgDisplayForm(W_FORM *psForm, UDWORD xOffset, UDWORD yOffset);
/* Buffer to return strings in */
static char aStringRetBuffer[WIDG_MAXSTR];
/* Initialise the widget module */
bool widgInitialise()
{
tipInitialise();
return true;
}
// Reset the widgets.
//
void widgReset(void)
{
tipInitialise();
}
/* Shut down the widget module */
void widgShutDown(void)
{
}
/* Create an empty widget screen */
W_SCREEN* widgCreateScreen()
{
W_FORM *psForm;
W_FORMINIT sInit;
W_SCREEN* psScreen = (W_SCREEN *)malloc(sizeof(W_SCREEN));
if (psScreen == NULL)
{
debug(LOG_ERROR, "widgCreateScreen: Out of memory");
abort();
return NULL;
}
memset(&sInit, 0, sizeof(W_FORMINIT));
sInit.id = 0;
sInit.style = WFORM_PLAIN | WFORM_INVISIBLE;
sInit.x = 0;
sInit.y = 0;
sInit.width = (UWORD)(screenWidth - 1);
sInit.height = (UWORD)(screenHeight - 1);
psForm = formCreate(&sInit);
if (psForm == NULL)
{
free(psScreen);
return NULL;
}
psScreen->psForm = (WIDGET *)psForm;
psScreen->psFocus = NULL;
psScreen->TipFontID = font_regular;
return psScreen;
}
/* Release a list of widgets */
void widgReleaseWidgetList(WIDGET *psWidgets)
{
WIDGET *psCurr, *psNext;
for(psCurr = psWidgets; psCurr; psCurr = psNext)
{
psNext = psCurr->psNext;
// the mouse can't be over it anymore
if (psMouseOverWidget && psMouseOverWidget->id == psCurr->id)
{
psMouseOverWidget = NULL;
}
switch(psCurr->type)
{
case WIDG_FORM:
formFree((W_FORM *)psCurr);
break;
case WIDG_LABEL:
labelFree((W_LABEL *)psCurr);
break;
case WIDG_BUTTON:
buttonFree((W_BUTTON *)psCurr);
break;
case WIDG_EDITBOX:
editBoxFree((W_EDITBOX *)psCurr);
break;
case WIDG_BARGRAPH:
barGraphFree((W_BARGRAPH *)psCurr);
break;
case WIDG_SLIDER:
sliderFree((W_SLIDER *)psCurr);
break;
default:
ASSERT(!"Unknown widget type", "Unknown widget type");
break;
}
}
}
/* Release a screen and all its associated data */
void widgReleaseScreen(W_SCREEN *psScreen)
{
ASSERT( psScreen != NULL,
"widgReleaseScreen: Invalid screen pointer" );
formFree((W_FORM *)psScreen->psForm);
free(psScreen);
}
/* Release a widget */
static void widgRelease(WIDGET *psWidget)
{
switch(psWidget->type)
{
case WIDG_FORM:
formFree((W_FORM *)psWidget);
break;
case WIDG_LABEL:
labelFree((W_LABEL *)psWidget);
break;
case WIDG_BUTTON:
buttonFree((W_BUTTON *)psWidget);
break;
case WIDG_EDITBOX:
editBoxFree((W_EDITBOX *)psWidget);
break;
case WIDG_BARGRAPH:
barGraphFree((W_BARGRAPH *)psWidget);
break;
case WIDG_SLIDER:
sliderFree((W_SLIDER *)psWidget);
break;
default:
ASSERT(!"Unknown widget type", "Unknown widget type");
break;
}
}
/* Check whether an ID has been used on a form */
static BOOL widgCheckIDForm(W_FORM *psForm, UDWORD id)
{
WIDGET *psCurr;
W_FORMGETALL sGetAll;
/* Check the widgets on the form */
formInitGetAllWidgets(psForm, &sGetAll);
psCurr = formGetAllWidgets(&sGetAll);
while (psCurr != NULL)
{
if (psCurr->id == id)
{
return true;
}
if (psCurr->type == WIDG_FORM)
{
/* Another form so recurse */
if (widgCheckIDForm((W_FORM *)psCurr, id))
{
return true;
}
}
psCurr = psCurr->psNext;
if (!psCurr)
{
/* Got to the end of this list see if there is another */
psCurr = formGetAllWidgets(&sGetAll);
}
}
return false;
}
#if 0
/* Check whether an ID number has been used on a screen */
static BOOL widgCheckID(W_SCREEN *psScreen, UDWORD id)
{
return widgCheckIDForm((W_FORM *)psScreen->psForm, id);
}
#endif
/* Set the tool tip font for a screen */
void widgSetTipFont(W_SCREEN *psScreen, enum iV_fonts FontID)
{
ASSERT( psScreen != NULL,
"widgSetTipFont: Invalid screen pointer" );
psScreen->TipFontID = FontID;
}
/* Add a form to the widget screen */
BOOL widgAddForm(W_SCREEN *psScreen, const W_FORMINIT* psInit)
{
W_FORM *psParent, *psForm;
ASSERT( psScreen != NULL,
"widgAddForm: Invalid screen pointer" );
if (widgCheckIDForm((W_FORM *)psScreen->psForm,psInit->id))
{
ASSERT( false, "widgAddForm: ID number has already been used (%d)", psInit->id );
return false;
}
/* Find the form to add the widget to */
if (psInit->formID == 0)
{
/* Add to the base form */
psParent = (W_FORM *)psScreen->psForm;
}
else
{
psParent = (W_FORM *)widgGetFromID(psScreen, psInit->formID);
if (!psParent || psParent->type != WIDG_FORM)
{
ASSERT( false,
"widgAddForm: Could not find parent form from formID" );
return false;
}
}
/* Create the form structure */
psForm = formCreate(psInit);
if (psForm == NULL
/* Add it to the screen */
|| !formAddWidget(psParent, (WIDGET *)psForm, (W_INIT *)psInit))
{
return false;
}
return true;
}
/* Add a label to the widget screen */
BOOL widgAddLabel(W_SCREEN *psScreen, const W_LABINIT* psInit)
{
W_LABEL *psLabel;
W_FORM *psForm;
ASSERT( psScreen != NULL,
"widgAddLabel: Invalid screen pointer" );
if (widgCheckIDForm((W_FORM *)psScreen->psForm,psInit->id))
{
ASSERT( false, "widgAddLabel: ID number has already been used (%d)", psInit->id );
return false;
}
/* Find the form to put the button on */
if (psInit->formID == 0)
{
psForm = (W_FORM *)psScreen->psForm;
}
else
{
psForm = (W_FORM *)widgGetFromID(psScreen, psInit->formID);
if (psForm == NULL || psForm->type != WIDG_FORM)
{
ASSERT( false,
"widgAddLabel: Could not find parent form from formID" );
return false;
}
}
/* Create the button structure */
psLabel = labelCreate(psInit);
if (psInit == NULL
/* Add it to the form */
|| !formAddWidget(psForm, (WIDGET *)psLabel, (W_INIT *)psInit))
{
return false;
}
return true;
}
/* Add a button to the widget screen */
BOOL widgAddButton(W_SCREEN *psScreen, const W_BUTINIT* psInit)
{
W_BUTTON *psButton;
W_FORM *psForm;
ASSERT( psScreen != NULL,
"widgAddButton: Invalid screen pointer" );
if (widgCheckIDForm((W_FORM *)psScreen->psForm,psInit->id))
{
ASSERT( false, "widgAddButton: ID number has already been used(%d)", psInit->id );
return false;
}
/* Find the form to put the button on */
if (psInit->formID == 0)
{
psForm = (W_FORM *)psScreen->psForm;
}
else
{
psForm = (W_FORM *)widgGetFromID(psScreen, psInit->formID);
if (psForm == NULL || psForm->type != WIDG_FORM)
{
ASSERT( false,
"widgAddButton: Could not find parent form from formID" );
return false;
}
}
/* Create the button structure */
psButton = buttonCreate(psInit);
if (psButton == NULL
/* Add it to the form */
|| !formAddWidget(psForm, (WIDGET *)psButton, (W_INIT *)psInit))
{
return false;
}
return true;
}
/* Add an edit box to the widget screen */
BOOL widgAddEditBox(W_SCREEN *psScreen, const W_EDBINIT* psInit)
{
W_EDITBOX *psEdBox;
W_FORM *psForm;
ASSERT( psScreen != NULL,
"widgAddEditBox: Invalid screen pointer" );
if (widgCheckIDForm((W_FORM *)psScreen->psForm,psInit->id))
{
ASSERT( false, "widgAddEditBox: ID number has already been used (%d)", psInit->id );
return false;
}
/* Find the form to put the edit box on */
if (psInit->formID == 0)
{
psForm = (W_FORM *)psScreen->psForm;
}
else
{
psForm = (W_FORM *)widgGetFromID(psScreen, psInit->formID);
if (!psForm || psForm->type != WIDG_FORM)
{
ASSERT( false,
"widgAddEditBox: Could not find parent form from formID" );
return false;
}
}
/* Create the edit box structure */
psEdBox = editBoxCreate(psInit);
if (psEdBox == NULL
/* Add it to the form */
|| !formAddWidget(psForm, (WIDGET *)psEdBox, (W_INIT *)psInit))
{
return false;
}
return true;
}
/* Add a bar graph to the widget screen */
BOOL widgAddBarGraph(W_SCREEN *psScreen, const W_BARINIT* psInit)
{
W_BARGRAPH *psBarGraph;
W_FORM *psForm;
ASSERT( psScreen != NULL,
"widgAddEditBox: Invalid screen pointer" );
if (widgCheckIDForm((W_FORM *)psScreen->psForm,psInit->id))
{
ASSERT( false, "widgAddBarGraph: ID number has already been used (%d)", psInit->id );
return false;
}
/* Find the form to put the bar graph on */
if (psInit->formID == 0)
{
psForm = (W_FORM *)psScreen->psForm;
}
else
{
psForm = (W_FORM *)widgGetFromID(psScreen, psInit->formID);
if (!psForm || psForm->type != WIDG_FORM)
{
ASSERT( false,
"widgAddBarGraph: Could not find parent form from formID" );
return false;
}
}
/* Create the bar graph structure */
psBarGraph = barGraphCreate(psInit);
if (psBarGraph == NULL
/* Add it to the form */
|| !formAddWidget(psForm, (WIDGET *)psBarGraph, (W_INIT *)psInit))
{
return false;
}
return true;
}
/* Add a slider to a form */
BOOL widgAddSlider(W_SCREEN *psScreen, const W_SLDINIT* psInit)
{
W_SLIDER *psSlider;
W_FORM *psForm;
ASSERT( psScreen != NULL,
"widgAddEditBox: Invalid screen pointer" );
if (widgCheckIDForm((W_FORM *)psScreen->psForm, psInit->id))
{
ASSERT(false, "widgSlider: ID number has already been used (%d)", psInit->id);
return false;
}
/* Find the form to put the slider on */
if (psInit->formID == 0)
{
psForm = (W_FORM *)psScreen->psForm;
}
else
{
psForm = (W_FORM *)widgGetFromID(psScreen, psInit->formID);
if (!psForm
|| psForm->type != WIDG_FORM)
{
ASSERT(false, "widgAddSlider: Could not find parent form from formID");
return false;
}
}
/* Create the slider structure */
psSlider = sliderCreate(psInit);
if (psSlider == NULL
/* Add it to the form */
|| !formAddWidget(psForm, (WIDGET *)psSlider, (W_INIT *)psInit))
{
return false;
}
return true;
}
/* Delete a widget from a form */
static BOOL widgDeleteFromForm(W_FORM *psForm, UDWORD id, W_CONTEXT *psContext)
{
WIDGET *psPrev = NULL, *psCurr, *psNext;
W_TABFORM *psTabForm;
UDWORD minor,major;
W_MAJORTAB *psMajor;
W_MINORTAB *psMinor;
W_CONTEXT sNewContext;
/* Clear the last hilite if necessary */
if ((psForm->psLastHiLite != NULL) && (psForm->psLastHiLite->id == id))
{
widgHiLiteLost(psForm->psLastHiLite, psContext);
psForm->psLastHiLite = NULL;
}
if (psForm->style & WFORM_TABBED)
{
psTabForm = (W_TABFORM *)psForm;
ASSERT( psTabForm != NULL,
"widgDeleteFromForm: Invalid form pointer" );
/* loop through all the tabs */
psMajor = psTabForm->asMajor;
for(major=0; major < psTabForm->numMajor; major++)
{
psMinor = psMajor->asMinor;
for(minor=0; minor < psMajor->numMinor; minor++)
{
if (psMinor->psWidgets && psMinor->psWidgets->id == id)
{
/* The widget is the first on this tab */
psNext = psMinor->psWidgets->psNext;
widgRelease(psMinor->psWidgets);
psMinor->psWidgets = psNext;
return true;
}
else
{
for(psCurr = psMinor->psWidgets; psCurr; psCurr = psCurr->psNext)
{
if (psCurr->id == id)
{
psPrev->psNext = psCurr->psNext;
widgRelease(psCurr);
return true;
}
if (psCurr->type == WIDG_FORM)
{
/* Recurse down to other form */
sNewContext.psScreen = psContext->psScreen;
sNewContext.psForm = (W_FORM *)psCurr;
sNewContext.xOffset = psContext->xOffset - psCurr->x;
sNewContext.yOffset = psContext->yOffset - psCurr->y;
sNewContext.mx = psContext->mx - psCurr->x;
sNewContext.my = psContext->my - psCurr->y;
if (widgDeleteFromForm((W_FORM *)psCurr, id, &sNewContext))
{
return true;
}
}
psPrev = psCurr;
}
}
psMinor++;
}
psMajor++;
}
}
else
{
ASSERT( psForm != NULL,
"widgDeleteFromForm: Invalid form pointer" );
/* Delete from a normal form */
if (psForm->psWidgets && psForm->psWidgets->id == id)
{
/* The widget is the first in the list */
psNext = psForm->psWidgets->psNext;
widgRelease(psForm->psWidgets);
psForm->psWidgets = psNext;
return true;
}
else
{
/* Search the rest of the list */
for(psCurr = psForm->psWidgets; psCurr; psCurr = psCurr->psNext)
{
if (psCurr->id == id)
{
psPrev->psNext = psCurr->psNext;
widgRelease(psCurr);
return true;
}
if (psCurr->type == WIDG_FORM)
{
/* Recurse down to other form */
sNewContext.psScreen = psContext->psScreen;
sNewContext.psForm = (W_FORM *)psCurr;
sNewContext.xOffset = psContext->xOffset - psCurr->x;
sNewContext.yOffset = psContext->yOffset - psCurr->y;
sNewContext.mx = psContext->mx - psCurr->x;
sNewContext.my = psContext->my - psCurr->y;
if (widgDeleteFromForm((W_FORM *)psCurr, id, &sNewContext))
{
return true;
}
}
psPrev = psCurr;
}
}
}
return false;
}
/* Delete a widget from the screen */
void widgDelete(W_SCREEN *psScreen, UDWORD id)
{
W_CONTEXT sContext;
ASSERT( psScreen != NULL,
"widgDelete: Invalid screen pointer" );
/* Clear the keyboard focus if necessary */
if ((psScreen->psFocus != NULL) && (psScreen->psFocus->id == id))
{
screenClearFocus(psScreen);
}
// the mouse can't be over it anymore
if (psMouseOverWidget && psMouseOverWidget->id == id)
{
psMouseOverWidget = NULL;
}
/* Set up the initial context */
sContext.psScreen = psScreen;
sContext.psForm = (W_FORM *)psScreen->psForm;
sContext.xOffset = 0;
sContext.yOffset = 0;
sContext.mx = mouseX();
sContext.my = mouseY();
(void)widgDeleteFromForm((W_FORM *)psScreen->psForm, id, &sContext);
}
/* Initialise a form and all it's widgets */
static void widgStartForm(W_FORM *psForm)
{
WIDGET *psCurr;
W_FORMGETALL sGetAll;
/* Initialise this form */
formInitialise(psForm);
/*Initialise the widgets on the form */
formInitGetAllWidgets(psForm, &sGetAll);
psCurr = formGetAllWidgets(&sGetAll);
while (psCurr != NULL)
{
switch (psCurr->type)
{
case WIDG_FORM:
widgStartForm((W_FORM *)psCurr);
break;
case WIDG_LABEL:
break;
case WIDG_BUTTON:
buttonInitialise((W_BUTTON *)psCurr);
break;
case WIDG_EDITBOX:
editBoxInitialise((W_EDITBOX *)psCurr);
break;
case WIDG_BARGRAPH:
break;
case WIDG_SLIDER:
sliderInitialise((W_SLIDER *)psCurr);
break;
default:
ASSERT(!"Unknown widget type", "Unknown widget type");
break;
}
psCurr = psCurr->psNext;
if (!psCurr)
{
/* Got to the end of this list see if there is another */
psCurr = formGetAllWidgets(&sGetAll);
}
}
}
/* Initialise the set of widgets that make up a screen */
void widgStartScreen(W_SCREEN *psScreen)
{
psScreen->psFocus = NULL;
widgStartForm((W_FORM *)psScreen->psForm);
}
/* Clean up after a screen has been run */
void widgEndScreen(W_SCREEN *psScreen)
{
(void)psScreen;
}
/* Find a widget on a form from it's id number */
static WIDGET *widgFormGetFromID(W_FORM *psForm, UDWORD id)
{
WIDGET *psCurr, *psFound;
W_FORMGETALL sGetAll;
/* See if the form matches the ID */
if (psForm->id == id)
{
return (WIDGET *)psForm;
}
/* Now search the widgets on the form */
psFound = NULL;
formInitGetAllWidgets(psForm,&sGetAll);
psCurr = formGetAllWidgets(&sGetAll);
while (psCurr && !psFound)
{
if (psCurr->id == id)
{
psFound = psCurr;
}
else if (psCurr->type == WIDG_FORM)
{
psFound = widgFormGetFromID((W_FORM *)psCurr, id);
}
psCurr = psCurr->psNext;
if (!psCurr)
{
/* Got to the end of this list see if there is another */
psCurr = formGetAllWidgets(&sGetAll);
}
}
return psFound;
}
/* Find a widget in a screen from its ID number */
WIDGET *widgGetFromID(W_SCREEN *psScreen, UDWORD id)
{
ASSERT( psScreen != NULL,
"widgGetFromID: Invalid screen pointer" );
return widgFormGetFromID((W_FORM *)psScreen->psForm, id);
}
/* Hide a widget */
void widgHide(W_SCREEN *psScreen, UDWORD id)
{
WIDGET *psWidget;
psWidget = widgGetFromID(psScreen, id);
ASSERT( psWidget != NULL,
"widgHide: couldn't find widget from id" );
if (psWidget)
{
psWidget->style |= WIDG_HIDDEN;
}
}
/* Reveal a widget */
void widgReveal(W_SCREEN *psScreen, UDWORD id)
{
WIDGET *psWidget;
psWidget = widgGetFromID(psScreen, id);
ASSERT( psWidget != NULL,
"widgReveal: couldn't find widget from id" );
if (psWidget)
{
psWidget->style &= ~WIDG_HIDDEN;
}
}
/* Get the current position of a widget */
void widgGetPos(W_SCREEN *psScreen, UDWORD id, SWORD *pX, SWORD *pY)
{
WIDGET *psWidget;
/* Find the widget */
psWidget = widgGetFromID(psScreen, id);
if (psWidget != NULL)
{
*pX = psWidget->x;
*pY = psWidget->y;
}
else
{
ASSERT(!"Couldn't find widget by ID", "Couldn't find widget by ID");
*pX = 0;
*pY = 0;
}
}
/* Return the ID of the widget the mouse was over this frame */
UDWORD widgGetMouseOver(W_SCREEN *psScreen)
{
/* Don't actually need the screen parameter at the moment - but it might be
handy if psMouseOverWidget needs to stop being a static and moves into
the screen structure */
(void)psScreen;
if (psMouseOverWidget == NULL)
{
return 0;
}
return psMouseOverWidget->id;
}
/* Return the user data for a widget */
void *widgGetUserData(W_SCREEN *psScreen, UDWORD id)
{
WIDGET *psWidget;
psWidget = widgGetFromID(psScreen, id);
if (psWidget)
{
return psWidget->pUserData;
}
return NULL;
}
/* Return the user data for a widget */
UDWORD widgGetUserData2(W_SCREEN *psScreen, UDWORD id)
{
WIDGET *psWidget;
psWidget = widgGetFromID(psScreen, id);
if (psWidget)
{
return psWidget->UserData;
}
return 0;
}
/* Set user data for a widget */
void widgSetUserData(W_SCREEN *psScreen, UDWORD id,void *UserData)
{
WIDGET *psWidget;
psWidget = widgGetFromID(psScreen, id);
if (psWidget)
{
psWidget->pUserData = UserData;
}
}
/* Set user data for a widget */
void widgSetUserData2(W_SCREEN *psScreen, UDWORD id,UDWORD UserData)
{
WIDGET *psWidget;
psWidget = widgGetFromID(psScreen, id);
if (psWidget)
{
psWidget->UserData = UserData;
}
}
/* Return the user data for the returned widget */
void *widgGetLastUserData(W_SCREEN *psScreen)
{
assert(psScreen != NULL);
if (psScreen->psRetWidget)
{
return psScreen->psRetWidget->pUserData;
}
return NULL;
}
/* Set tip string for a widget */
void widgSetTip( W_SCREEN *psScreen, UDWORD id, const char *pTip )
{
WIDGET *psWidget = widgGetFromID(psScreen, id);
if (!psWidget)
return;
widgSetTipText(psWidget, pTip);
}
void widgSetTipText(WIDGET* psWidget, const char* pTip)
{
ASSERT(psWidget != NULL, "invalid widget pointer");
switch (psWidget->type)
{
case WIDG_FORM:
if (psWidget->style & WFORM_CLICKABLE)
{
((W_CLICKFORM *) psWidget)->pTip = pTip;
}
else if (psWidget->style & WFORM_TABBED)
{
ASSERT(!"tabbed forms don't have a tip", "widgSetTip: tabbed forms do not have a tip");
}
else
{
ASSERT(!"plain forms don't have a tip", "widgSetTip: plain forms do not have a tip");
}
break;
case WIDG_LABEL:
((W_LABEL *) psWidget)->pTip = pTip;
break;
case WIDG_BUTTON:
((W_BUTTON *) psWidget)->pTip = pTip;
break;
case WIDG_BARGRAPH:
((W_BARGRAPH *) psWidget)->pTip = pTip;
break;
case WIDG_SLIDER:
((W_SLIDER *) psWidget)->pTip = pTip;
break;
case WIDG_EDITBOX:
ASSERT(!"wrong widget type", "widgSetTip: edit boxes do not have a tip");
break;
default:
ASSERT(!"Unknown widget type", "Unknown widget type");
break;
}
}
/* Return which key was used to press the last returned widget */
UDWORD widgGetButtonKey(W_SCREEN *psScreen)
{
/* Don't actually need the screen parameter at the moment - but it might be
handy if released needs to stop being a static and moves into
the screen structure */
(void)psScreen;
return released;
}
/* Get a button or clickable form's state */
UDWORD widgGetButtonState(W_SCREEN *psScreen, UDWORD id)
{
WIDGET *psWidget;
/* Get the button */
psWidget = widgGetFromID(psScreen, id);
if (psWidget == NULL)
{
ASSERT(!"Couldn't find widget by ID", "Couldn't find button or clickable widget by ID");
}
else if (psWidget->type == WIDG_BUTTON)
{
return buttonGetState((W_BUTTON *)psWidget);
}
else if ((psWidget->type == WIDG_FORM) && (psWidget->style & WFORM_CLICKABLE))
{
return formGetClickState((W_CLICKFORM *)psWidget);
}
else
{
ASSERT(!"Couldn't find widget by ID", "Couldn't find button or clickable widget by ID");
}
return 0;
}
void widgSetButtonFlash(W_SCREEN *psScreen, UDWORD id)
{
WIDGET *psWidget;
/* Get the button */
psWidget = widgGetFromID(psScreen, id);
if (psWidget == NULL)
{
ASSERT(!"Couldn't find widget by ID", "Couldn't find button or clickable widget by ID");
}
else if (psWidget->type == WIDG_BUTTON)
{
buttonSetFlash((W_BUTTON *)psWidget);
}
else if ((psWidget->type == WIDG_FORM) && (psWidget->style & WFORM_CLICKABLE))
{
formSetFlash((W_FORM *)psWidget);
}
else if ((psWidget->type == WIDG_EDITBOX))
{
// editBoxSetState((W_EDITBOX *)psWidget, state);
}
else
{
ASSERT(!"Couldn't find widget by ID", "Couldn't find button or clickable widget by ID");
}
}
void widgClearButtonFlash(W_SCREEN *psScreen, UDWORD id)
{
WIDGET *psWidget;
/* Get the button */
psWidget = widgGetFromID(psScreen, id);
if (psWidget == NULL)
{
ASSERT(!"Couldn't find widget by ID", "Couldn't find button or clickable widget by ID");
}
else if (psWidget->type == WIDG_BUTTON)
{
buttonClearFlash((W_BUTTON *)psWidget);
}
else if ((psWidget->type == WIDG_FORM) && (psWidget->style & WFORM_CLICKABLE))
{
formClearFlash((W_FORM *)psWidget);
}
else if ((psWidget->type == WIDG_EDITBOX))
{
}
else
{
ASSERT(!"Couldn't find widget by ID", "Couldn't find button or clickable widget by ID");
}
}
/* Set a button or clickable form's state */
void widgSetButtonState(W_SCREEN *psScreen, UDWORD id, UDWORD state)
{
WIDGET *psWidget;
/* Get the button */
psWidget = widgGetFromID(psScreen, id);
if (psWidget == NULL)
{
ASSERT(!"Couldn't find widget by ID", "Couldn't find button or clickable widget by ID");
}
else if (psWidget->type == WIDG_BUTTON)
{
buttonSetState((W_BUTTON *)psWidget, state);
}
else if ((psWidget->type == WIDG_FORM) && (psWidget->style & WFORM_CLICKABLE))
{
formSetClickState((W_CLICKFORM *)psWidget, state);
}
else if ((psWidget->type == WIDG_EDITBOX))
{
editBoxSetState((W_EDITBOX *)psWidget, state);
}
else
{
ASSERT(!"Couldn't find widget by ID", "Couldn't find button or clickable widget by ID");
}
}
/* Return a pointer to a buffer containing the current string of a widget.
* NOTE: The string must be copied out of the buffer
*/
const char *widgGetString(W_SCREEN *psScreen, UDWORD id)
{
const WIDGET *psWidget = widgGetFromID(psScreen, id);
ASSERT( psScreen != NULL, "widgGetString: Invalid screen pointer" );
/* Get the widget */
if (psWidget != NULL)
{
switch (psWidget->type)
{
case WIDG_FORM:
ASSERT( false, "widgGetString: Forms do not have a string" );
aStringRetBuffer[0] = '\0';
break;
case WIDG_LABEL:
sstrcpy(aStringRetBuffer, ((W_LABEL *)psWidget)->aText);
break;
case WIDG_BUTTON:
if (((W_BUTTON *)psWidget)->pText)
{
sstrcpy(aStringRetBuffer, ((W_BUTTON *)psWidget)->pText);
}
else
{
aStringRetBuffer[0] = '\0';
}
break;
case WIDG_EDITBOX:
sstrcpy(aStringRetBuffer, ((W_EDITBOX *)psWidget)->aText);
break;
case WIDG_BARGRAPH:
ASSERT( false, "widgGetString: Bar Graphs do not have a string" );
aStringRetBuffer[0] = '\0';
break;
case WIDG_SLIDER:
ASSERT( false, "widgGetString: Sliders do not have a string" );
aStringRetBuffer[0] = '\0';
break;
default:
ASSERT(!"Unknown widget type", "Unknown widget type");
aStringRetBuffer[0] = '\0';
break;
}
}
else
{
ASSERT(!"Couldn't find widget by ID", "widgGetString: couldn't find widget by ID");
aStringRetBuffer[0] = '\0';
}
return aStringRetBuffer;
}
/* Set the text in a widget */
void widgSetString(W_SCREEN *psScreen, UDWORD id, const char *pText)
{
WIDGET *psWidget;
ASSERT( psScreen != NULL,
"widgSetString: Invalid screen pointer" );
/* Get the widget */
psWidget = widgGetFromID(psScreen, id);
if (psWidget == NULL)
{
debug(LOG_ERROR, "widgSetString: couldn't get widget from id");
return;
}
switch (psWidget->type)
{
case WIDG_FORM:
ASSERT( false, "widgSetString: forms do not have a string" );
break;
case WIDG_LABEL:
sstrcpy(((W_LABEL *)psWidget)->aText, pText);
break;
case WIDG_BUTTON:
((W_BUTTON *)psWidget)->pText = pText;
break;
case WIDG_EDITBOX:
if (psScreen->psFocus == psWidget)
{
screenClearFocus(psScreen);
}
editBoxSetString((W_EDITBOX *)psWidget, pText);
break;
case WIDG_BARGRAPH:
ASSERT( !"wrong widget type", "widgGetString: Bar graphs do not have a string" );
break;
case WIDG_SLIDER:
ASSERT( !"wrong widget type", "widgGetString: Sliders do not have a string" );
break;
default:
ASSERT(!"Unknown widget type", "Unknown widget type");
break;
}
}
/* Call any callbacks for the widgets on a form */
static void widgProcessCallbacks(W_CONTEXT *psContext)
{
WIDGET *psCurr;
W_CONTEXT sFormContext, sWidgContext;
SDWORD xOrigin, yOrigin;
W_FORMGETALL sFormCtl;
/* Initialise the form context */
sFormContext.psScreen = psContext->psScreen;
/* Initialise widget context */
formGetOrigin(psContext->psForm, &xOrigin, &yOrigin);
sWidgContext.psScreen = psContext->psScreen;
sWidgContext.psForm = psContext->psForm;
sWidgContext.mx = psContext->mx - xOrigin;
sWidgContext.my = psContext->my - yOrigin;
sWidgContext.xOffset = psContext->xOffset + xOrigin;
sWidgContext.yOffset = psContext->yOffset + yOrigin;
/* Go through all the widgets on the form */
formInitGetAllWidgets(psContext->psForm, &sFormCtl);
psCurr = formGetAllWidgets(&sFormCtl);
while (psCurr)
{
for(;psCurr; psCurr = psCurr->psNext)
{
/* Skip any hidden widgets */
/* Not sure if we want to skip hidden widgets or not ....
if (psCurr->style & WIDG_HIDDEN)
{
continue;
}*/
/* Call the callback */
if (psCurr->callback)
{
psCurr->callback(psCurr, &sWidgContext);
}
/* and then recurse */
if (psCurr->type == WIDG_FORM)
{
sFormContext.psForm = (W_FORM *)psCurr;
sFormContext.mx = sWidgContext.mx - psCurr->x;
sFormContext.my = sWidgContext.my - psCurr->y;
sFormContext.xOffset = sWidgContext.xOffset + psCurr->x;
sFormContext.yOffset = sWidgContext.yOffset + psCurr->y;
widgProcessCallbacks(&sFormContext);
}
}
/* See if the form has any more widgets on it */
psCurr = formGetAllWidgets(&sFormCtl);
}
}
/* Process all the widgets on a form.
* mx and my are the coords of the mouse relative to the form origin.
*/
static void widgProcessForm(W_CONTEXT *psContext)
{
WIDGET *psCurr, *psOver;
SDWORD mx,my, omx,omy, xOffset,yOffset, xOrigin,yOrigin;
W_FORM *psForm;
W_CONTEXT sFormContext, sWidgContext;
/* Note current form */
psForm = psContext->psForm;
// if(psForm->disableChildren == true) {
// return;
// }
/* Note the current mouse position */
mx = psContext->mx;
my = psContext->my;
/* Note the current offset */
xOffset = psContext->xOffset;
yOffset = psContext->yOffset;
/* Initialise the form context */
sFormContext.psScreen = psContext->psScreen;
/* Initialise widget context */
formGetOrigin(psForm, &xOrigin, &yOrigin);
sWidgContext.psScreen = psContext->psScreen;
sWidgContext.psForm = psForm;
sWidgContext.mx = mx - xOrigin;
sWidgContext.my = my - yOrigin;
sWidgContext.xOffset = xOffset + xOrigin;
sWidgContext.yOffset = yOffset + yOrigin;
/* Process the form's widgets */
psOver = NULL;
for(psCurr = formGetWidgets(psForm); psCurr; psCurr = psCurr->psNext)
{
/* Skip any hidden widgets */
if (psCurr->style & WIDG_HIDDEN)
{
continue;
}
if (psCurr->type == WIDG_FORM)
{
/* Found a sub form, so set up the context */
sFormContext.psForm = (W_FORM *)psCurr;
sFormContext.mx = mx - psCurr->x - xOrigin;
sFormContext.my = my - psCurr->y - yOrigin;
sFormContext.xOffset = xOffset + psCurr->x + xOrigin;
sFormContext.yOffset = yOffset + psCurr->y + yOrigin;
/* Process it */
widgProcessForm(&sFormContext);
}
else
{
/* Run the widget */
widgRun(psCurr, &sWidgContext);
}
}
/* Now check for mouse clicks */
omx = mx - xOrigin;
omy = my - yOrigin;
if (mx >= 0 && mx <= psForm->width &&
my >= 0 && my <= psForm->height)
{
/* Update for the origin */
/* Mouse is over the form - is it over any of the widgets */
for(psCurr = formGetWidgets(psForm); psCurr; psCurr = psCurr->psNext)
{
/* Skip any hidden widgets */
if (psCurr->style & WIDG_HIDDEN)
{
continue;
}
if (omx >= psCurr->x &&
omy >= psCurr->y &&
omx <= psCurr->x + psCurr->width &&
omy <= psCurr->y + psCurr->height)
{
/* Note the widget the mouse is over */
if (!psMouseOverWidget)
{
psMouseOverWidget = (WIDGET *)psCurr;
}
psOver = psCurr;
/* Don't check the widgets if it is a clickable form */
if (!(psForm->style & WFORM_CLICKABLE))
{
if (pressed != WKEY_NONE && psCurr->type != WIDG_FORM)
{
/* Tell the widget it has been clicked */
widgClicked(psCurr, pressed, &sWidgContext);
}
if (released != WKEY_NONE && psCurr->type != WIDG_FORM)
{
/* Tell the widget the mouse button has gone up */
widgReleased(psCurr, released, &sWidgContext);
}
}
}
}
/* Note that the mouse is over this form */
if (!psMouseOverWidget)
{
psMouseOverWidget = (WIDGET *)psForm;
}
/* Only send the Clicked or Released messages if a widget didn't get the message */
if (pressed != WKEY_NONE &&
(psOver == NULL || (psForm->style & WFORM_CLICKABLE)))
{
/* Tell the form it has been clicked */
widgClicked((WIDGET *)psForm, pressed, psContext);
}
if (released != WKEY_NONE &&
(psOver == NULL || (psForm->style & WFORM_CLICKABLE)))
{
/* Tell the form the mouse button has gone up */
widgReleased((WIDGET *)psForm, released, psContext);
}
}
/* See if the mouse has moved onto or off a widget */
if (psForm->psLastHiLite != psOver)
{
if (psOver != NULL)
{
widgHiLite(psOver, &sWidgContext);
}
if (psForm->psLastHiLite != NULL)
{
widgHiLiteLost(psForm->psLastHiLite, &sWidgContext);
}
psForm->psLastHiLite = psOver;
}
/* Run this form */
widgRun((WIDGET *)psForm, psContext);
}
/* Execute a set of widgets for one cycle.
* Return the id of the widget that was activated, or 0 for none.
*/
UDWORD widgRunScreen(W_SCREEN *psScreen)
{
W_CONTEXT sContext;
psScreen->psRetWidget = NULL;
// Note which keys have been pressed
pressed = WKEY_NONE;
if(getWidgetsStatus())
{
if (mousePressed(MOUSE_LMB))
{
pressed = WKEY_PRIMARY;
}
else if (mousePressed(MOUSE_RMB))
{
pressed = WKEY_SECONDARY;
}
released = WKEY_NONE;
if (mouseReleased(MOUSE_LMB))
{
released = WKEY_PRIMARY;
}
else if (mouseReleased(MOUSE_RMB))
{
released = WKEY_SECONDARY;
}
}
/* Initialise the context */
sContext.psScreen = psScreen;
sContext.psForm = (W_FORM *)psScreen->psForm;
sContext.xOffset = 0;
sContext.yOffset = 0;
sContext.mx = mouseX();
sContext.my = mouseY();
psMouseOverWidget = NULL;
/* Process the screen's widgets */
widgProcessForm(&sContext);
/* Process any user callback functions */
widgProcessCallbacks(&sContext);
/* Return the ID of a pressed button or finished edit box if any */
return psScreen->psRetWidget ? psScreen->psRetWidget->id : 0;
}
/* Set the id number for widgRunScreen to return */
void widgSetReturn(W_SCREEN* psScreen, WIDGET *psWidget)
{
psScreen->psRetWidget = psWidget;
}
/* Display the widgets on a form */
static void widgDisplayForm(W_FORM *psForm, UDWORD xOffset, UDWORD yOffset)
{
WIDGET *psCurr = NULL;
SDWORD xOrigin = 0, yOrigin = 0;
/* Display the form */
psForm->display( (WIDGET *)psForm, xOffset, yOffset, psForm->aColours );
if(psForm->disableChildren == true) {
return;
}
/* Update the offset from the current form's position */
formGetOrigin(psForm, &xOrigin, &yOrigin);
xOffset += psForm->x + xOrigin;
yOffset += psForm->y + yOrigin;
/* If this is a clickable form, the widgets on it have to move when it's down */
if(!(psForm->style & WFORM_NOCLICKMOVE)) {
if ((psForm->style & WFORM_CLICKABLE) &&
(((W_CLICKFORM *)psForm)->state &
(WCLICK_DOWN | WCLICK_LOCKED | WCLICK_CLICKLOCK)))
{
xOffset += 1;
yOffset += 1;
}
}
/* Display the widgets on the form */
for(psCurr = formGetWidgets(psForm); psCurr; psCurr = psCurr->psNext)
{
/* Skip any hidden widgets */
if (psCurr->style & WIDG_HIDDEN)
{
continue;
}
if (psCurr->type == WIDG_FORM)
{
widgDisplayForm((W_FORM *)psCurr, xOffset, yOffset);
}
else
{
psCurr->display(psCurr, xOffset, yOffset, psForm->aColours);
}
}
}
/* Display the screen's widgets in their current state
* (Call after calling widgRunScreen, this allows the input
* processing to be seperated from the display of the widgets).
*/
void widgDisplayScreen(W_SCREEN *psScreen)
{
/* Display the widgets */
widgDisplayForm((W_FORM *)psScreen->psForm, 0,0);
/* Display the tool tip if there is one */
tipDisplay();
}
/* Call the correct function for loss of focus */
static void widgFocusLost(W_SCREEN* psScreen, WIDGET *psWidget)
{
switch (psWidget->type)
{
case WIDG_FORM:
break;
case WIDG_LABEL:
break;
case WIDG_BUTTON:
break;
case WIDG_EDITBOX:
editBoxFocusLost(psScreen, (W_EDITBOX *)psWidget);
break;
case WIDG_BARGRAPH:
break;
case WIDG_SLIDER:
break;
default:
ASSERT(!"Unknown widget type", "Unknown widget type");
break;
}
}
/* Set the keyboard focus for the screen */
void screenSetFocus(W_SCREEN *psScreen, WIDGET *psWidget)
{
if (psScreen->psFocus != NULL)
{
widgFocusLost(psScreen, psScreen->psFocus);
}
psScreen->psFocus = psWidget;
}
/* Clear the keyboard focus */
void screenClearFocus(W_SCREEN *psScreen)
{
if (psScreen->psFocus != NULL)
{
widgFocusLost(psScreen, psScreen->psFocus);
psScreen->psFocus = NULL;
}
}
/* Call the correct function for mouse over */
void widgHiLite(WIDGET *psWidget, W_CONTEXT *psContext)
{
(void)psContext;
switch (psWidget->type)
{
case WIDG_FORM:
formHiLite((W_FORM *)psWidget, psContext);
break;
case WIDG_LABEL:
labelHiLite((W_LABEL *)psWidget, psContext);
break;
case WIDG_BUTTON:
buttonHiLite((W_BUTTON *)psWidget, psContext);
break;
case WIDG_EDITBOX:
editBoxHiLite((W_EDITBOX *)psWidget);
break;
case WIDG_BARGRAPH:
barGraphHiLite((W_BARGRAPH *)psWidget, psContext);
break;
case WIDG_SLIDER:
sliderHiLite((W_SLIDER *)psWidget);
break;
default:
ASSERT(!"Unknown widget type", "Unknown widget type");
break;
}
}
/* Call the correct function for mouse moving off */
void widgHiLiteLost(WIDGET *psWidget, W_CONTEXT *psContext)
{
(void)psContext;
switch (psWidget->type)
{
case WIDG_FORM:
formHiLiteLost((W_FORM *)psWidget, psContext);
break;
case WIDG_LABEL:
labelHiLiteLost((W_LABEL *)psWidget);
break;
case WIDG_BUTTON:
buttonHiLiteLost((W_BUTTON *)psWidget);
break;
case WIDG_EDITBOX:
editBoxHiLiteLost((W_EDITBOX *)psWidget);
break;
case WIDG_BARGRAPH:
barGraphHiLiteLost((W_BARGRAPH *)psWidget);
break;
case WIDG_SLIDER:
sliderHiLiteLost((W_SLIDER *)psWidget);
break;
default:
ASSERT(!"Unknown widget type", "Unknown widget type");
break;
}
}
/* Call the correct function for mouse pressed */
static void widgClicked(WIDGET *psWidget, UDWORD key, W_CONTEXT *psContext)
{
switch (psWidget->type)
{
case WIDG_FORM:
formClicked((W_FORM *)psWidget, key);
break;
case WIDG_LABEL:
break;
case WIDG_BUTTON:
buttonClicked((W_BUTTON *)psWidget, key);
break;
case WIDG_EDITBOX:
editBoxClicked((W_EDITBOX *)psWidget, psContext);
break;
case WIDG_BARGRAPH:
break;
case WIDG_SLIDER:
sliderClicked((W_SLIDER *)psWidget, psContext);
break;
default:
ASSERT(!"Unknown widget type", "Unknown widget type");
break;
}
}
/* Call the correct function for mouse released */
static void widgReleased(WIDGET *psWidget, UDWORD key, W_CONTEXT *psContext)
{
switch (psWidget->type)
{
case WIDG_FORM:
formReleased((W_FORM *)psWidget, key, psContext);
break;
case WIDG_LABEL:
break;
case WIDG_BUTTON:
buttonReleased(psContext->psScreen, (W_BUTTON *)psWidget, key);
break;
case WIDG_EDITBOX:
editBoxReleased((W_EDITBOX *)psWidget);
break;
case WIDG_BARGRAPH:
break;
case WIDG_SLIDER:
sliderReleased((W_SLIDER *)psWidget);
break;
default:
ASSERT(!"Unknown widget type", "Unknown widget type");
break;
}
}
/* Call the correct function to run a widget */
static void widgRun(WIDGET *psWidget, W_CONTEXT *psContext)
{
switch (psWidget->type)
{
case WIDG_FORM:
formRun((W_FORM *)psWidget, psContext);
break;
case WIDG_LABEL:
break;
case WIDG_BUTTON:
buttonRun((W_BUTTON *)psWidget);
break;
case WIDG_EDITBOX:
editBoxRun((W_EDITBOX *)psWidget, psContext);
break;
case WIDG_BARGRAPH:
break;
case WIDG_SLIDER:
sliderRun((W_SLIDER *)psWidget, psContext);
break;
default:
ASSERT(!"Unknown widget type", "Unknown widget type");
break;
}
}
void WidgSetAudio(WIDGET_AUDIOCALLBACK Callback,SWORD HilightID,SWORD ClickedID)
{
AudioCallback = Callback;
HilightAudioID = HilightID;
ClickedAudioID = ClickedID;
}
WIDGET_AUDIOCALLBACK WidgGetAudioCallback(void)
{
return AudioCallback;
}
SWORD WidgGetHilightAudioID(void)
{
return HilightAudioID;
}
SWORD WidgGetClickedAudioID(void)
{
return ClickedAudioID;
}
void setWidgetsStatus(BOOL var)
{
bWidgetsActive = var;
}
BOOL getWidgetsStatus( void )
{
return(bWidgetsActive);
}