mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
UTIL is never used, and JA2 is always used. assumption being we'll never make 1.13 for Wizardry 8. video2.h doesn't exist, which prevented me from deleting it.
4404 lines
122 KiB
C++
4404 lines
122 KiB
C++
/***********************************************************************************************
|
|
Button System.c
|
|
|
|
Rewritten mostly by Kris Morness
|
|
***********************************************************************************************/
|
|
|
|
#include "types.h"
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <memory.h>
|
|
#include "debug.h"
|
|
#include "input.h"
|
|
#include "memman.h"
|
|
#include "english.h"
|
|
#include "vobject.h"
|
|
#include "vobject_blitters.h"
|
|
#include "soundman.h"
|
|
#include "Button System.h"
|
|
#include "line.h"
|
|
#include <stdarg.h>
|
|
#include "WordWrap.h"
|
|
#include "video.h"
|
|
#include "Button Sound Control.h"
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
#include "Font Control.h"
|
|
#include "Render Dirty.h"
|
|
#include "utilities.h"
|
|
#endif
|
|
#include <vector>
|
|
|
|
|
|
//ATE: Added to let Wiz default creating mouse regions with no cursor, JA2 default to a cursor ( first one )
|
|
#define MSYS_STARTING_CURSORVAL 0
|
|
#define COLOR_DKGREY 136
|
|
|
|
|
|
#define MAX_GENERIC_PICS 40
|
|
#define MAX_BUTTON_ICONS 40
|
|
|
|
|
|
#define GUI_BTN_NONE 0
|
|
#define GUI_BTN_DUPLICATE_VOBJ 1
|
|
#define GUI_BTN_EXTERNAL_VOBJ 2
|
|
|
|
|
|
CHAR8 str[128];
|
|
|
|
//Kris: December 2, 1997
|
|
//Special internal debugging utilities that will ensure that you don't attempt to delete
|
|
//an already deleted button, or it's images, etc. It will also ensure that you don't create
|
|
//the same button that already exists.
|
|
//TO REMOVE ALL DEBUG FUNCTIONALITY: simply comment out BUTTONSYSTEM_DEBUGGING definition
|
|
#ifdef _DEBUG
|
|
#define BUTTONSYSTEM_DEBUGGING
|
|
#endif
|
|
|
|
#ifdef BUTTONSYSTEM_DEBUGGING
|
|
BOOLEAN gfIgnoreShutdownAssertions; // symbol already declared globally in mousesystem.cpp (jonathanl)
|
|
//Called immediately before assigning the button to the button list.
|
|
void AssertFailIfIdenticalButtonAttributesFound( GUI_BUTTON *b )
|
|
{
|
|
INT32 x;
|
|
GUI_BUTTON *c;
|
|
for( x = 0; x < MAX_BUTTONS; x++ )
|
|
{
|
|
c = ButtonList[ x ];
|
|
if( !c ) continue;
|
|
if( c->uiFlags & BUTTON_DELETION_PENDING ) continue;
|
|
if( c->UserData[3] == 0xffffffff ) continue;
|
|
if( b->Area.PriorityLevel != c->Area.PriorityLevel ) continue;
|
|
if( b->Area.RegionTopLeftX != c->Area.RegionTopLeftX ) continue;
|
|
if( b->Area.RegionTopLeftY != c->Area.RegionTopLeftY ) continue;
|
|
if( b->Area.RegionBottomRightX != c->Area.RegionBottomRightX ) continue;
|
|
if( b->Area.RegionBottomRightY != c->Area.RegionBottomRightY ) continue;
|
|
if( b->ClickCallback != c->ClickCallback ) continue;
|
|
if( b->MoveCallback != c->MoveCallback ) continue;
|
|
if( b->XLoc != c->XLoc ) continue;
|
|
if( b->YLoc != c->YLoc ) continue;
|
|
//if we get this far, it is reasonably safe to assume that the newly created
|
|
//button already exists. Placing a break point on the following assert will
|
|
//allow the coder to easily isolate the case!
|
|
sprintf( str, "Attempting to create a button that has already been created (existing buttonID %d).", c->IDNum );
|
|
AssertMsg( 0, str );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//Kris:
|
|
//These are the variables used for the anchoring of a particular button.
|
|
//When you click on a button, it get's anchored, until you release the mouse button.
|
|
//When you move around, you don't want to select other buttons, even when you release
|
|
//it. This follows the Windows 95 convention.
|
|
GUI_BUTTON *gpAnchoredButton;
|
|
GUI_BUTTON *gpPrevAnchoredButton;
|
|
BOOLEAN gfAnchoredState;
|
|
void ReleaseAnchorMode();
|
|
|
|
INT8 gbDisabledButtonStyle;
|
|
void DrawHatchOnButton( GUI_BUTTON *b );
|
|
void DrawShadeOnButton( GUI_BUTTON *b );
|
|
void DrawDefaultOnButton( GUI_BUTTON *b );
|
|
|
|
GUI_BUTTON *gpCurrentFastHelpButton;
|
|
|
|
BOOLEAN gfRenderHilights = TRUE;
|
|
|
|
//BUTTON_PICS ButtonPictures[MAX_BUTTON_PICS];
|
|
std::vector<BUTTON_PICS> ButtonPictures(MAX_BUTTON_PICS);
|
|
INT32 ButtonPicsLoaded;
|
|
|
|
UINT32 ButtonDestBuffer = BACKBUFFER;
|
|
UINT32 ButtonDestPitch = 640*2;
|
|
UINT32 ButtonDestBPP = 16;
|
|
|
|
//GUI_BUTTON *ButtonList[MAX_BUTTONS];
|
|
std::vector<GUI_BUTTON *> ButtonList(MAX_BUTTONS);
|
|
|
|
INT32 ButtonsInList=0;
|
|
|
|
UINT16 GetWidthOfButtonPic( UINT16 usButtonPicID, INT32 iSlot )
|
|
{
|
|
return ButtonPictures[ usButtonPicID ].vobj->pETRLEObject[ iSlot ].usWidth;
|
|
}
|
|
|
|
UINT16 GetHeightOfButtonPic( UINT16 usButtonPicID, INT32 iSlot )
|
|
{
|
|
return ButtonPictures[ usButtonPicID ].vobj->pETRLEObject[ iSlot ].usHeight;
|
|
}
|
|
|
|
HVOBJECT GenericButtonGrayed[MAX_GENERIC_PICS];
|
|
HVOBJECT GenericButtonOffNormal[MAX_GENERIC_PICS];
|
|
HVOBJECT GenericButtonOffHilite[MAX_GENERIC_PICS];
|
|
HVOBJECT GenericButtonOnNormal[MAX_GENERIC_PICS];
|
|
HVOBJECT GenericButtonOnHilite[MAX_GENERIC_PICS];
|
|
HVOBJECT GenericButtonBackground[MAX_GENERIC_PICS];
|
|
UINT16 GenericButtonFillColors[MAX_GENERIC_PICS];
|
|
UINT16 GenericButtonBackgroundIndex[MAX_GENERIC_PICS];
|
|
INT16 GenericButtonOffsetX[MAX_GENERIC_PICS];
|
|
INT16 GenericButtonOffsetY[MAX_GENERIC_PICS];
|
|
|
|
HVOBJECT GenericButtonIcons[MAX_BUTTON_ICONS];
|
|
|
|
// flag to state we wish to render buttons on the one after the next pass through render buttons
|
|
BOOLEAN fPausedMarkButtonsDirtyFlag = FALSE;
|
|
BOOLEAN fDisableHelpTextRestoreFlag = FALSE;
|
|
|
|
BOOLEAN gfDelayButtonDeletion = FALSE;
|
|
BOOLEAN gfPendingButtonDeletion = FALSE;
|
|
void RemoveButtonsMarkedForDeletion();
|
|
|
|
extern MOUSE_REGION *MSYS_PrevRegion;
|
|
extern MOUSE_REGION *MSYS_CurrRegion;
|
|
|
|
//=============================================================================
|
|
// FindFreeButtonSlot
|
|
//
|
|
// Finds an available slot for loading button pictures
|
|
//
|
|
INT32 FindFreeButtonSlot(void)
|
|
{
|
|
int slot;
|
|
|
|
// Are there any slots available?
|
|
if(ButtonPicsLoaded >= MAX_BUTTON_PICS)
|
|
return(BUTTON_NO_SLOT);
|
|
|
|
// Search for a slot
|
|
for(slot=0;slot<MAX_BUTTON_PICS;slot++)
|
|
{
|
|
if(ButtonPictures[slot].vobj==NULL)
|
|
return(slot);
|
|
}
|
|
|
|
return(BUTTON_NO_SLOT);
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// LoadButtonImage
|
|
//
|
|
// Load images for use with QuickButtons.
|
|
//
|
|
INT32 LoadButtonImage(const STR8 filename, INT32 Grayed, INT32 OffNormal, INT32 OffHilite, INT32 OnNormal, INT32 OnHilite)
|
|
{
|
|
VOBJECT_DESC vo_desc;
|
|
UINT32 UseSlot;
|
|
ETRLEObject *pTrav;
|
|
UINT32 MaxHeight,MaxWidth,ThisHeight,ThisWidth;
|
|
UINT32 MemBefore,MemAfter,MemUsed;
|
|
|
|
AssertMsg(filename!=BUTTON_NO_FILENAME, "Attempting to LoadButtonImage() with null filename." );
|
|
AssertMsg(strlen(filename), "Attempting to LoadButtonImage() with empty filename string." );
|
|
|
|
// is there ANY file to open?
|
|
if((Grayed == BUTTON_NO_IMAGE) && (OffNormal == BUTTON_NO_IMAGE) && (OffHilite == BUTTON_NO_IMAGE) &&
|
|
(OnNormal == BUTTON_NO_IMAGE) && (OnHilite == BUTTON_NO_IMAGE))
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("No button pictures selected for %s",filename));
|
|
return(-1);
|
|
}
|
|
|
|
// Get a button image slot
|
|
if((UseSlot=FindFreeButtonSlot()) == BUTTON_NO_SLOT)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("Out of button image slots for %s",filename));
|
|
return(-1);
|
|
}
|
|
|
|
// Load the image
|
|
vo_desc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
|
|
strcpy(vo_desc.ImageFile, filename);
|
|
|
|
MemBefore = MemGetFree();
|
|
if((ButtonPictures[UseSlot].vobj = CreateVideoObject(&vo_desc)) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("Couldn't create VOBJECT for %s",filename));
|
|
return(-1);
|
|
}
|
|
MemAfter = MemGetFree();
|
|
MemUsed = MemBefore-MemAfter;
|
|
|
|
// Init the QuickButton image structure with indexes to use
|
|
ButtonPictures[UseSlot].Grayed=Grayed;
|
|
ButtonPictures[UseSlot].OffNormal=OffNormal;
|
|
ButtonPictures[UseSlot].OffHilite=OffHilite;
|
|
ButtonPictures[UseSlot].OnNormal=OnNormal;
|
|
ButtonPictures[UseSlot].OnHilite=OnHilite;
|
|
ButtonPictures[UseSlot].fFlags = GUI_BTN_NONE;
|
|
|
|
// Fit the button size to the largest image in the set
|
|
MaxWidth=MaxHeight=0;
|
|
if(Grayed != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[Grayed]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
if(OffNormal != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[OffNormal]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
if(OffHilite != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[OffHilite]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
if(OnNormal != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[OnNormal]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
if(OnHilite != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[OnHilite]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
// Set the width and height for this image set
|
|
ButtonPictures[UseSlot].MaxHeight=MaxHeight;
|
|
ButtonPictures[UseSlot].MaxWidth=MaxWidth;
|
|
|
|
// return the image slot number
|
|
ButtonPicsLoaded++;
|
|
return(UseSlot);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
// UseLoadedButtonImage
|
|
//
|
|
// Uses a previously loaded quick button image for use with QuickButtons.
|
|
// The function simply duplicates the vobj!
|
|
//
|
|
INT32 UseLoadedButtonImage(INT32 LoadedImg, INT32 Grayed, INT32 OffNormal, INT32 OffHilite, INT32 OnNormal, INT32 OnHilite)
|
|
{
|
|
UINT32 UseSlot;
|
|
ETRLEObject *pTrav;
|
|
UINT32 MaxHeight,MaxWidth,ThisHeight,ThisWidth;
|
|
|
|
|
|
// Is button image index given valid?
|
|
if( ButtonPictures[LoadedImg].vobj == NULL )
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("Invalid button picture handle given for pre-loaded button image %d",LoadedImg));
|
|
return(-1);
|
|
}
|
|
|
|
// Is button image an external vobject?
|
|
if( ButtonPictures[LoadedImg].fFlags & GUI_BTN_EXTERNAL_VOBJ )
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("Invalid button picture handle given (%d), cannot use external images as duplicates.",LoadedImg));
|
|
return(-1);
|
|
}
|
|
|
|
// is there ANY file to open?
|
|
if((Grayed == BUTTON_NO_IMAGE) && (OffNormal == BUTTON_NO_IMAGE) && (OffHilite == BUTTON_NO_IMAGE) &&
|
|
(OnNormal == BUTTON_NO_IMAGE) && (OnHilite == BUTTON_NO_IMAGE))
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("No button pictures selected for pre-loaded button image %d",LoadedImg));
|
|
return(-1);
|
|
}
|
|
|
|
// Get a button image slot
|
|
if((UseSlot=FindFreeButtonSlot()) == BUTTON_NO_SLOT)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("Out of button image slots for pre-loaded button image %d",LoadedImg));
|
|
return(-1);
|
|
}
|
|
|
|
// Init the QuickButton image structure with indexes to use
|
|
ButtonPictures[UseSlot].vobj = ButtonPictures[LoadedImg].vobj;
|
|
ButtonPictures[UseSlot].Grayed=Grayed;
|
|
ButtonPictures[UseSlot].OffNormal=OffNormal;
|
|
ButtonPictures[UseSlot].OffHilite=OffHilite;
|
|
ButtonPictures[UseSlot].OnNormal=OnNormal;
|
|
ButtonPictures[UseSlot].OnHilite=OnHilite;
|
|
ButtonPictures[UseSlot].fFlags = GUI_BTN_DUPLICATE_VOBJ;
|
|
|
|
// Fit the button size to the largest image in the set
|
|
MaxWidth=MaxHeight=0;
|
|
if(Grayed != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[Grayed]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
if(OffNormal != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[OffNormal]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
if(OffHilite != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[OffHilite]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
if(OnNormal != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[OnNormal]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
if(OnHilite != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[OnHilite]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
// Set the width and height for this image set
|
|
ButtonPictures[UseSlot].MaxHeight=MaxHeight;
|
|
ButtonPictures[UseSlot].MaxWidth=MaxWidth;
|
|
|
|
// return the image slot number
|
|
ButtonPicsLoaded++;
|
|
return(UseSlot);
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// UseVObjAsButtonImage
|
|
//
|
|
// Uses a previously loaded VObject for use with QuickButtons.
|
|
// The function simply duplicates the vobj pointer and uses that.
|
|
//
|
|
// **** NOTE ****
|
|
// The image isn't unloaded with a call to UnloadButtonImage. The internal
|
|
// structures are simply removed from the button image list. It's up to
|
|
// the user to actually unload the image.
|
|
//
|
|
INT32 UseVObjAsButtonImage(HVOBJECT hVObject, INT32 Grayed, INT32 OffNormal, INT32 OffHilite, INT32 OnNormal, INT32 OnHilite)
|
|
{
|
|
UINT32 UseSlot;
|
|
ETRLEObject *pTrav;
|
|
UINT32 MaxHeight,MaxWidth,ThisHeight,ThisWidth;
|
|
|
|
|
|
// Is button image index given valid?
|
|
if( hVObject == NULL )
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("UseVObjAsButtonImage: Invalid VObject image given"));
|
|
return(-1);
|
|
}
|
|
|
|
// is there ANY file to open?
|
|
if((Grayed == BUTTON_NO_IMAGE) && (OffNormal == BUTTON_NO_IMAGE) && (OffHilite == BUTTON_NO_IMAGE) &&
|
|
(OnNormal == BUTTON_NO_IMAGE) && (OnHilite == BUTTON_NO_IMAGE))
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("UseVObjAsButtonImage: No button pictures indexes selected for VObject"));
|
|
return(-1);
|
|
}
|
|
|
|
// Get a button image slot
|
|
if((UseSlot=FindFreeButtonSlot()) == BUTTON_NO_SLOT)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("UseVObjAsButtonImage: Out of button image slots for VObject"));
|
|
return(-1);
|
|
}
|
|
|
|
// Init the QuickButton image structure with indexes to use
|
|
ButtonPictures[UseSlot].vobj = hVObject;
|
|
ButtonPictures[UseSlot].Grayed=Grayed;
|
|
ButtonPictures[UseSlot].OffNormal=OffNormal;
|
|
ButtonPictures[UseSlot].OffHilite=OffHilite;
|
|
ButtonPictures[UseSlot].OnNormal=OnNormal;
|
|
ButtonPictures[UseSlot].OnHilite=OnHilite;
|
|
ButtonPictures[UseSlot].fFlags = GUI_BTN_EXTERNAL_VOBJ;
|
|
|
|
// Fit the button size to the largest image in the set
|
|
MaxWidth=MaxHeight=0;
|
|
if(Grayed != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[Grayed]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
if(OffNormal != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[OffNormal]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
if(OffHilite != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[OffHilite]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
if(OnNormal != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[OnNormal]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
if(OnHilite != BUTTON_NO_IMAGE)
|
|
{
|
|
pTrav = &(ButtonPictures[UseSlot].vobj->pETRLEObject[OnHilite]);
|
|
ThisHeight = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
ThisWidth = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
if(MaxWidth<ThisWidth)
|
|
MaxWidth=ThisWidth;
|
|
if(MaxHeight<ThisHeight)
|
|
MaxHeight=ThisHeight;
|
|
}
|
|
|
|
// Set the width and height for this image set
|
|
ButtonPictures[UseSlot].MaxHeight=MaxHeight;
|
|
ButtonPictures[UseSlot].MaxWidth=MaxWidth;
|
|
|
|
// return the image slot number
|
|
ButtonPicsLoaded++;
|
|
return(UseSlot);
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// SetButtonDestBuffer
|
|
//
|
|
// Sets the destination buffer for all button blits.
|
|
//
|
|
BOOLEAN SetButtonDestBuffer(UINT32 DestBuffer)
|
|
{
|
|
if(DestBuffer != BUTTON_USE_DEFAULT)
|
|
ButtonDestBuffer = DestBuffer;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
//Removes a QuickButton image from the system.
|
|
void UnloadButtonImage(INT32 Index)
|
|
{
|
|
INT32 x;
|
|
BOOLEAN fDone;
|
|
|
|
if( Index < 0 || Index >= MAX_BUTTON_PICS )
|
|
{
|
|
sprintf( str, "Attempting to UnloadButtonImage with out of range index %d.", Index );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
if( !ButtonPictures[ Index ].vobj )
|
|
{
|
|
#ifdef BUTTONSYSTEM_DEBUGGING
|
|
if( gfIgnoreShutdownAssertions )
|
|
#endif
|
|
return;
|
|
AssertMsg( 0, "Attempting to UnloadButtonImage that has a null vobj (already deleted).");
|
|
}
|
|
|
|
// If this is a duplicated button image, then don't trash the vobject
|
|
if(ButtonPictures[Index].fFlags & GUI_BTN_DUPLICATE_VOBJ || ButtonPictures[Index].fFlags & GUI_BTN_EXTERNAL_VOBJ)
|
|
{
|
|
ButtonPictures[Index].vobj = NULL;
|
|
ButtonPicsLoaded--;
|
|
}
|
|
else
|
|
{
|
|
// Deleting a non-duplicate, so see if any dups present. if so, then
|
|
// convert one of them to an original!
|
|
|
|
fDone = FALSE;
|
|
for( x = 0; x < MAX_BUTTON_PICS && !fDone; x++ )
|
|
{
|
|
if( (x != Index) && (ButtonPictures[x].vobj == ButtonPictures[Index].vobj) )
|
|
{
|
|
if ( ButtonPictures[x].fFlags & GUI_BTN_DUPLICATE_VOBJ )
|
|
{
|
|
// If we got here, then we got a duplicate object of the one we
|
|
// want to delete, so convert it to an original!
|
|
ButtonPictures[x].fFlags &= (~GUI_BTN_DUPLICATE_VOBJ);
|
|
|
|
// Now remove this button, but not it's vobject
|
|
ButtonPictures[Index].vobj = NULL;
|
|
|
|
fDone = TRUE;
|
|
ButtonPicsLoaded--;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If image slot isn't empty, delete the image
|
|
if(ButtonPictures[Index].vobj != NULL)
|
|
{
|
|
DeleteVideoObject(ButtonPictures[Index].vobj);
|
|
ButtonPictures[Index].vobj = NULL;
|
|
ButtonPicsLoaded--;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// EnableButton
|
|
//
|
|
// Enables an already created button.
|
|
//
|
|
BOOLEAN EnableButton( INT32 iButtonID )
|
|
{
|
|
GUI_BUTTON *b;
|
|
UINT32 OldState;
|
|
|
|
if( iButtonID < 0 || iButtonID >= MAX_BUTTONS )
|
|
{
|
|
sprintf( str, "Attempting to EnableButton with out of range buttonID %d.", iButtonID );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
b = ButtonList[ iButtonID ];
|
|
|
|
// If button exists, set the ENABLED flag
|
|
if( b )
|
|
{
|
|
OldState = b->uiFlags & BUTTON_ENABLED;
|
|
b->uiFlags |= ( BUTTON_ENABLED | BUTTON_DIRTY );
|
|
}
|
|
else
|
|
OldState = 0;
|
|
|
|
|
|
// Return previous ENABLED state of this button
|
|
return((OldState==BUTTON_ENABLED)?TRUE:FALSE);
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// DisableButton
|
|
//
|
|
// Disables a button. The button remains in the system list, and can be
|
|
// reactivated by calling EnableButton.
|
|
//
|
|
// Diabled buttons will appear "grayed out" on the screen (unless the
|
|
// graphics for such are not available).
|
|
//
|
|
BOOLEAN DisableButton(INT32 iButtonID )
|
|
{
|
|
GUI_BUTTON *b;
|
|
UINT32 OldState;
|
|
|
|
if( iButtonID < 0 || iButtonID >= MAX_BUTTONS )
|
|
{
|
|
sprintf( str, "Attempting to DisableButton with out of range buttonID %d.", iButtonID );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
b = ButtonList[ iButtonID ];
|
|
|
|
// If button exists, reset the ENABLED flag
|
|
if( b )
|
|
{
|
|
OldState = b->uiFlags & BUTTON_ENABLED;
|
|
b->uiFlags &= (~BUTTON_ENABLED);
|
|
b->uiFlags |= BUTTON_DIRTY;
|
|
}
|
|
else
|
|
OldState = 0;
|
|
|
|
// Return previous ENABLED state of button
|
|
return((OldState==BUTTON_ENABLED)?TRUE:FALSE);
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// InitializeButtonImageManager
|
|
//
|
|
// Initializes the button image sub-system. This function is called by
|
|
// InitButtonSystem.
|
|
//
|
|
BOOLEAN InitializeButtonImageManager(INT32 DefaultBuffer, INT32 DefaultPitch, INT32 DefaultBPP)
|
|
{
|
|
VOBJECT_DESC vo_desc;
|
|
UINT8 Pix;
|
|
int x;
|
|
|
|
// Set up the default settings
|
|
if(DefaultBuffer != BUTTON_USE_DEFAULT)
|
|
ButtonDestBuffer = (UINT32)DefaultBuffer;
|
|
else
|
|
ButtonDestBuffer = FRAME_BUFFER;
|
|
|
|
if(DefaultPitch != BUTTON_USE_DEFAULT)
|
|
ButtonDestPitch = (UINT32)DefaultPitch;
|
|
else
|
|
ButtonDestPitch = 640*2;
|
|
|
|
if(DefaultBPP != BUTTON_USE_DEFAULT)
|
|
ButtonDestBPP = (UINT32)DefaultBPP;
|
|
else
|
|
ButtonDestBPP = 16;
|
|
|
|
// Blank out all QuickButton images
|
|
for(x=0;x<MAX_BUTTON_PICS;x++)
|
|
{
|
|
ButtonPictures[x].vobj=NULL;
|
|
ButtonPictures[x].Grayed = -1;
|
|
ButtonPictures[x].OffNormal = -1;
|
|
ButtonPictures[x].OffHilite = -1;
|
|
ButtonPictures[x].OnNormal = -1;
|
|
ButtonPictures[x].OnHilite = -1;
|
|
}
|
|
ButtonPicsLoaded = 0;
|
|
|
|
// Blank out all Generic button data
|
|
for(x=0;x<MAX_GENERIC_PICS;x++)
|
|
{
|
|
GenericButtonGrayed[x]=NULL;
|
|
GenericButtonOffNormal[x]=NULL;
|
|
GenericButtonOffHilite[x]=NULL;
|
|
GenericButtonOnNormal[x]=NULL;
|
|
GenericButtonOnHilite[x]=NULL;
|
|
GenericButtonBackground[x]=NULL;
|
|
GenericButtonBackgroundIndex[x]=0;
|
|
GenericButtonFillColors[x]=0;
|
|
GenericButtonBackgroundIndex[x]=0;
|
|
GenericButtonOffsetX[x]=0;
|
|
GenericButtonOffsetY[x]=0;
|
|
}
|
|
|
|
// Blank out all icon images
|
|
for(x=0;x<MAX_BUTTON_ICONS;x++)
|
|
GenericButtonIcons[x]=NULL;
|
|
|
|
// Load the default generic button images
|
|
vo_desc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
|
|
strcpy(vo_desc.ImageFile, DEFAULT_GENERIC_BUTTON_OFF);
|
|
|
|
if((GenericButtonOffNormal[0] = CreateVideoObject(&vo_desc)) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, "Couldn't create VOBJECT for "DEFAULT_GENERIC_BUTTON_OFF);
|
|
return(FALSE);
|
|
}
|
|
|
|
vo_desc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
|
|
strcpy(vo_desc.ImageFile, DEFAULT_GENERIC_BUTTON_ON);
|
|
|
|
if((GenericButtonOnNormal[0] = CreateVideoObject(&vo_desc)) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, "Couldn't create VOBJECT for "DEFAULT_GENERIC_BUTTON_ON);
|
|
return(FALSE);
|
|
}
|
|
|
|
// Load up the off hilite and on hilite images. We won't check for errors because if the file
|
|
// doesn't exists, the system simply ignores that file. These are only here as extra images, they
|
|
// aren't required for operation (only OFF Normal and ON Normal are required).
|
|
vo_desc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
|
|
strcpy(vo_desc.ImageFile, DEFAULT_GENERIC_BUTTON_OFF_HI);
|
|
GenericButtonOffHilite[0] = CreateVideoObject(&vo_desc);
|
|
|
|
vo_desc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
|
|
strcpy(vo_desc.ImageFile, DEFAULT_GENERIC_BUTTON_ON_HI);
|
|
GenericButtonOnHilite[0] = CreateVideoObject(&vo_desc);
|
|
|
|
Pix=0;
|
|
if(!GetETRLEPixelValue(&Pix,GenericButtonOffNormal[0],8,0,0))
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, "Couldn't get generic button's background pixel value");
|
|
return(FALSE);
|
|
}
|
|
|
|
if(GETPIXELDEPTH()==16)
|
|
GenericButtonFillColors[0]=GenericButtonOffNormal[0]->p16BPPPalette[Pix];
|
|
else if(GETPIXELDEPTH()==8)
|
|
GenericButtonFillColors[0]=COLOR_DKGREY;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// FindFreeGenericSlot
|
|
//
|
|
// Finds the next available slot for generic (TEXT and/or ICONIC) buttons.
|
|
//
|
|
INT16 FindFreeGenericSlot(void)
|
|
{
|
|
INT16 slot,x;
|
|
|
|
slot=BUTTON_NO_SLOT;
|
|
for(x=0;x<MAX_GENERIC_PICS && slot<0;x++)
|
|
{
|
|
if(GenericButtonOffNormal[x]==NULL)
|
|
slot=x;
|
|
}
|
|
|
|
return(slot);
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// FindFreeIconSlot
|
|
//
|
|
// Finds the next available slot for button icon images.
|
|
//
|
|
INT16 FindFreeIconSlot(void)
|
|
{
|
|
INT16 slot,x;
|
|
|
|
slot=BUTTON_NO_SLOT;
|
|
for(x=0;x<MAX_BUTTON_ICONS && slot<0;x++)
|
|
{
|
|
if(GenericButtonIcons[x]==NULL)
|
|
slot=x;
|
|
}
|
|
|
|
return(slot);
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// LoadGenericButtonIcon
|
|
//
|
|
// Loads an image file for use as a button icon.
|
|
//
|
|
INT16 LoadGenericButtonIcon(const STR8 filename)
|
|
{
|
|
INT16 ImgSlot;
|
|
VOBJECT_DESC vo_desc;
|
|
|
|
AssertMsg(filename != BUTTON_NO_FILENAME, "Attempting to LoadGenericButtonIcon() with null filename.");
|
|
|
|
// Get slot for icon image
|
|
if((ImgSlot=FindFreeIconSlot()) == BUTTON_NO_SLOT)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, "LoadGenericButtonIcon: Out of generic button icon slots");
|
|
return(-1);
|
|
}
|
|
|
|
// Load the icon
|
|
vo_desc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
|
|
strcpy(vo_desc.ImageFile, filename);
|
|
|
|
if((GenericButtonIcons[ImgSlot] = CreateVideoObject(&vo_desc)) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("LoadGenericButtonIcon: Couldn't create VOBJECT for %s",filename));
|
|
return(-1);
|
|
}
|
|
|
|
// Return the slot number
|
|
return(ImgSlot);
|
|
}
|
|
|
|
//=============================================================================
|
|
// UnloadGenericButtonIcon
|
|
//
|
|
// Removes a button icon graphic from the system
|
|
//
|
|
BOOLEAN UnloadGenericButtonIcon(INT16 GenImg)
|
|
{
|
|
if( GenImg < 0 || GenImg >= MAX_BUTTON_ICONS )
|
|
{
|
|
sprintf( str, "Attempting to UnloadGenericButtonIcon with out of range index %d.", GenImg );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
if( !GenericButtonIcons[ GenImg ] )
|
|
{
|
|
#ifdef BUTTONSYSTEM_DEBUGGING
|
|
if( gfIgnoreShutdownAssertions )
|
|
#endif
|
|
return FALSE;
|
|
AssertMsg( 0, "Attempting to UnloadGenericButtonIcon that has no icon (already deleted)." );
|
|
}
|
|
// If an icon is present in the slot, remove it.
|
|
DeleteVideoObject(GenericButtonIcons[GenImg]);
|
|
GenericButtonIcons[GenImg]=NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// UnloadGenericButtonImage
|
|
//
|
|
// Removes the images associated with a generic button. Except the icon
|
|
// image of iconic buttons. See above.
|
|
//
|
|
BOOLEAN UnloadGenericButtonImage(INT16 GenImg)
|
|
{
|
|
BOOLEAN fDeletedSomething = FALSE;
|
|
if( GenImg < 0 || GenImg >= MAX_GENERIC_PICS )
|
|
{
|
|
sprintf( str, "Attempting to UnloadGenericButtonImage with out of range index %d.", GenImg );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
// For each possible image type in a generic button, check if it's
|
|
// present, and if so, remove it.
|
|
if(GenericButtonGrayed[GenImg]!=NULL)
|
|
{
|
|
DeleteVideoObject(GenericButtonGrayed[GenImg]);
|
|
GenericButtonGrayed[GenImg]=NULL;
|
|
fDeletedSomething = TRUE;
|
|
}
|
|
|
|
if(GenericButtonOffNormal[GenImg]!=NULL)
|
|
{
|
|
DeleteVideoObject(GenericButtonOffNormal[GenImg]);
|
|
GenericButtonOffNormal[GenImg]=NULL;
|
|
fDeletedSomething = TRUE;
|
|
}
|
|
|
|
if(GenericButtonOffHilite[GenImg]!=NULL)
|
|
{
|
|
DeleteVideoObject(GenericButtonOffHilite[GenImg]);
|
|
GenericButtonOffHilite[GenImg]=NULL;
|
|
fDeletedSomething = TRUE;
|
|
}
|
|
|
|
if(GenericButtonOnNormal[GenImg]!=NULL)
|
|
{
|
|
DeleteVideoObject(GenericButtonOnNormal[GenImg]);
|
|
GenericButtonOnNormal[GenImg]=NULL;
|
|
fDeletedSomething = TRUE;
|
|
}
|
|
|
|
if(GenericButtonOnHilite[GenImg]!=NULL)
|
|
{
|
|
DeleteVideoObject(GenericButtonOnHilite[GenImg]);
|
|
GenericButtonOnHilite[GenImg]=NULL;
|
|
fDeletedSomething = TRUE;
|
|
}
|
|
|
|
if(GenericButtonBackground[GenImg]!=NULL)
|
|
{
|
|
DeleteVideoObject(GenericButtonBackground[GenImg]);
|
|
GenericButtonBackground[GenImg]=NULL;
|
|
fDeletedSomething = TRUE;
|
|
}
|
|
|
|
#ifdef BUTTONSYSTEM_DEBUGGING
|
|
if( !gfIgnoreShutdownAssertions && !fDeletedSomething )
|
|
AssertMsg( 0, "Attempting to UnloadGenericButtonImage that has no images (already deleted)." );
|
|
#endif
|
|
|
|
// Reset the remaining variables
|
|
GenericButtonFillColors[GenImg]=0;
|
|
GenericButtonBackgroundIndex[GenImg]=0;
|
|
GenericButtonOffsetX[GenImg]=0;
|
|
GenericButtonOffsetY[GenImg]=0;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// LoadGenericButtonImages
|
|
//
|
|
// Loads the image files required for displaying a generic button.
|
|
//
|
|
INT16 LoadGenericButtonImages(STR8 GrayName,STR8 OffNormName,STR8 OffHiliteName,STR8 OnNormName,STR8 OnHiliteName, STR8 BkGrndName,INT16 Index,INT16 OffsetX, INT16 OffsetY)
|
|
{
|
|
INT16 ImgSlot;
|
|
VOBJECT_DESC vo_desc;
|
|
UINT8 Pix;
|
|
|
|
// if the images for Off-Normal and On-Normal don't exist, abort call
|
|
if((OffNormName == BUTTON_NO_FILENAME) || (OnNormName == BUTTON_NO_FILENAME))
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, "LoadGenericButtonImages: No filenames for OFFNORMAL and/or ONNORMAL images");
|
|
return(-1);
|
|
}
|
|
|
|
// Get a slot number for these images
|
|
if((ImgSlot=FindFreeGenericSlot()) == -1)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, "LoadGenericButtonImages: Out of generic button slots");
|
|
return(-1);
|
|
}
|
|
|
|
// Load the image for the Off-Normal button state (required)
|
|
vo_desc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
|
|
strcpy(vo_desc.ImageFile, OffNormName);
|
|
|
|
if((GenericButtonOffNormal[ImgSlot] = CreateVideoObject(&vo_desc)) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("LoadGenericButtonImages: Couldn't create VOBJECT for %s",OffNormName));
|
|
return(-1);
|
|
}
|
|
|
|
// Load the image for the On-Normal button state (required)
|
|
vo_desc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
|
|
strcpy(vo_desc.ImageFile, OnNormName);
|
|
|
|
if((GenericButtonOnNormal[ImgSlot] = CreateVideoObject(&vo_desc)) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("LoadGenericButtonImages: Couldn't create VOBJECT for %s",OnNormName));
|
|
return(-1);
|
|
}
|
|
|
|
// For the optional button state images, see if a filename was given, and
|
|
// if so, load it.
|
|
|
|
if(GrayName != BUTTON_NO_FILENAME)
|
|
{
|
|
vo_desc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
|
|
strcpy(vo_desc.ImageFile, GrayName);
|
|
|
|
if((GenericButtonGrayed[ImgSlot] = CreateVideoObject(&vo_desc)) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("LoadGenericButtonImages: Couldn't create VOBJECT for %s",GrayName));
|
|
return(-1);
|
|
}
|
|
}
|
|
else
|
|
GenericButtonGrayed[ImgSlot] = NULL;
|
|
|
|
if(OffHiliteName != BUTTON_NO_FILENAME)
|
|
{
|
|
vo_desc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
|
|
strcpy(vo_desc.ImageFile, OffHiliteName);
|
|
|
|
if((GenericButtonOffHilite[ImgSlot] = CreateVideoObject(&vo_desc)) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("LoadGenericButtonImages: Couldn't create VOBJECT for %s",OffHiliteName));
|
|
return(-1);
|
|
}
|
|
}
|
|
else
|
|
GenericButtonOffHilite[ImgSlot] = NULL;
|
|
|
|
if(OnHiliteName != BUTTON_NO_FILENAME)
|
|
{
|
|
vo_desc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
|
|
strcpy(vo_desc.ImageFile, OnHiliteName);
|
|
|
|
if((GenericButtonOnHilite[ImgSlot] = CreateVideoObject(&vo_desc)) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("LoadGenericButtonImages: Couldn't create VOBJECT for %s",OnHiliteName));
|
|
return(-1);
|
|
}
|
|
}
|
|
else
|
|
GenericButtonOnHilite[ImgSlot] = NULL;
|
|
|
|
if(BkGrndName != BUTTON_NO_FILENAME)
|
|
{
|
|
vo_desc.fCreateFlags = VOBJECT_CREATE_FROMFILE;
|
|
strcpy(vo_desc.ImageFile, BkGrndName);
|
|
|
|
if((GenericButtonBackground[ImgSlot] = CreateVideoObject(&vo_desc)) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, String("LoadGenericButtonImages: Couldn't create VOBJECT for %s",BkGrndName));
|
|
return(-1);
|
|
}
|
|
}
|
|
else
|
|
GenericButtonBackground[ImgSlot] = NULL;
|
|
|
|
GenericButtonBackgroundIndex[ImgSlot]=Index;
|
|
|
|
// Get the background fill color from the last (9th) sub-image in the
|
|
// Off-Normal image.
|
|
Pix=0;
|
|
if(!GetETRLEPixelValue(&Pix,GenericButtonOffNormal[ImgSlot],8,0,0))
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER, DBG_LEVEL_0, "LoadGenericButtonImages: Couldn't get generic button's background pixel value");
|
|
return(-1);
|
|
}
|
|
|
|
GenericButtonFillColors[ImgSlot]=GenericButtonOffNormal[ImgSlot]->p16BPPPalette[Pix];
|
|
|
|
// Set the button's background image adjustement offsets
|
|
GenericButtonOffsetX[ImgSlot]=OffsetX;
|
|
GenericButtonOffsetY[ImgSlot]=OffsetY;
|
|
|
|
// Return the slot number used.
|
|
return(ImgSlot);
|
|
}
|
|
|
|
|
|
//=============================================================================
|
|
// ShutdownButtonImageManager
|
|
//
|
|
// Cleans up, and shuts down the button image manager sub-system.
|
|
//
|
|
// This function is called by ShutdownButtonSystem.
|
|
//
|
|
void ShutdownButtonImageManager(void)
|
|
{
|
|
int x;
|
|
|
|
#ifdef BUTTONSYSTEM_DEBUGGING
|
|
gfIgnoreShutdownAssertions = TRUE;
|
|
#endif
|
|
|
|
// Remove all QuickButton images
|
|
for(x=0;x<MAX_BUTTON_PICS;x++)
|
|
UnloadButtonImage(x);
|
|
|
|
// Remove all GenericButton images
|
|
for(x=0;x<MAX_GENERIC_PICS;x++)
|
|
{
|
|
if(GenericButtonGrayed[x]!=NULL)
|
|
{
|
|
DeleteVideoObject(GenericButtonGrayed[x]);
|
|
GenericButtonGrayed[x]=NULL;
|
|
}
|
|
|
|
if(GenericButtonOffNormal[x]!=NULL)
|
|
{
|
|
DeleteVideoObject(GenericButtonOffNormal[x]);
|
|
GenericButtonOffNormal[x]=NULL;
|
|
}
|
|
|
|
if(GenericButtonOffHilite[x]!=NULL)
|
|
{
|
|
DeleteVideoObject(GenericButtonOffHilite[x]);
|
|
GenericButtonOffHilite[x]=NULL;
|
|
}
|
|
|
|
if(GenericButtonOnNormal[x]!=NULL)
|
|
{
|
|
DeleteVideoObject(GenericButtonOnNormal[x]);
|
|
GenericButtonOnNormal[x]=NULL;
|
|
}
|
|
|
|
if(GenericButtonOnHilite[x]!=NULL)
|
|
{
|
|
DeleteVideoObject(GenericButtonOnHilite[x]);
|
|
GenericButtonOnHilite[x]=NULL;
|
|
}
|
|
|
|
if(GenericButtonBackground[x]!=NULL)
|
|
{
|
|
DeleteVideoObject(GenericButtonBackground[x]);
|
|
GenericButtonBackground[x]=NULL;
|
|
}
|
|
|
|
GenericButtonFillColors[x]=0;
|
|
GenericButtonBackgroundIndex[x]=0;
|
|
GenericButtonOffsetX[x]=0;
|
|
GenericButtonOffsetY[x]=0;
|
|
}
|
|
|
|
// Remove all button icons
|
|
for(x=0;x<MAX_BUTTON_ICONS;x++)
|
|
{
|
|
if(GenericButtonIcons[x]!=NULL)
|
|
GenericButtonIcons[x]=NULL;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// InitButtonSystem
|
|
//
|
|
// Initializes the GUI button system for use. Must be called before using
|
|
// any other button functions.
|
|
//
|
|
BOOLEAN InitButtonSystem(void)
|
|
{
|
|
INT32 x;
|
|
|
|
#ifdef BUTTONSYSTEM_DEBUGGING
|
|
gfIgnoreShutdownAssertions = FALSE;
|
|
#endif
|
|
|
|
RegisterDebugTopic(TOPIC_BUTTON_HANDLER,"Button System & Button Image Manager");
|
|
|
|
// Clear out button list
|
|
for(x=0;x<MAX_BUTTONS;x++)
|
|
{
|
|
ButtonList[x]=NULL;
|
|
}
|
|
|
|
// Initialize the button image manager sub-system
|
|
if(InitializeButtonImageManager(-1,-1,-1) == FALSE)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"Failed button image manager init\n");
|
|
return(FALSE);
|
|
}
|
|
|
|
ButtonsInList = 0;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// ShutdownButtonSystem
|
|
//
|
|
// Shuts down and cleans up the GUI button system. Must be called before
|
|
// exiting the program. Button functions should not be used after calling
|
|
// this function.
|
|
//
|
|
void ShutdownButtonSystem(void)
|
|
{
|
|
int x;
|
|
|
|
// Kill off all buttons in the system
|
|
for(x=0;x<MAX_BUTTONS;x++)
|
|
{
|
|
if(ButtonList[x]!=NULL)
|
|
RemoveButton(x);
|
|
}
|
|
// Shutdown the button image manager sub-system
|
|
ShutdownButtonImageManager();
|
|
|
|
UnRegisterDebugTopic(TOPIC_BUTTON_HANDLER,"Button System & Button Image Manager");
|
|
}
|
|
|
|
void RemoveButtonsMarkedForDeletion()
|
|
{
|
|
INT32 i;
|
|
for( i = 0; i < MAX_BUTTONS; i++ )
|
|
{
|
|
if( ButtonList[ i ] && ButtonList[ i ]->uiFlags & BUTTON_DELETION_PENDING )
|
|
{
|
|
RemoveButton( i );
|
|
}
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
// RemoveButton
|
|
//
|
|
// Removes a button from the system's list. All memory associated with the
|
|
// button is released.
|
|
//
|
|
void RemoveButton(INT32 iButtonID)
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
if( iButtonID < 0 || iButtonID >= MAX_BUTTONS )
|
|
{
|
|
sprintf( str, "Attempting to RemoveButton with out of range buttonID %d.", iButtonID );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
b = ButtonList[ iButtonID ];
|
|
|
|
// If button exists...
|
|
if( !b )
|
|
{
|
|
#ifdef BUTTONSYSTEM_DEBUGGING
|
|
if( gfIgnoreShutdownAssertions )
|
|
#endif
|
|
return;
|
|
sprintf(str, "Attempting to remove a button that has already been deleted. ButtonID %d", iButtonID);
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
//If we happen to be in the middle of a callback, and attempt to delete a button,
|
|
//like deleting a node during list processing, then we delay it till after the callback
|
|
//is completed.
|
|
if( gfDelayButtonDeletion )
|
|
{
|
|
b->uiFlags |= BUTTON_DELETION_PENDING;
|
|
gfPendingButtonDeletion = TRUE;
|
|
return;
|
|
}
|
|
|
|
//Kris:
|
|
if( b->uiFlags & BUTTON_SELFDELETE_IMAGE )
|
|
{ //checkboxes and simple create buttons have their own graphics associated with them,
|
|
//and it is handled internally. We delete it here. This provides the advantage of less
|
|
//micromanagement, but with the disadvantage of wasting more memory if you have lots of
|
|
//buttons using the same graphics.
|
|
UnloadButtonImage( b->ImageNum );
|
|
}
|
|
|
|
// ...kill it!!!
|
|
MSYS_RemoveRegion(&b->Area);
|
|
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
if ( b->uiFlags & BUTTON_SAVEBACKGROUND )
|
|
{
|
|
FreeBackgroundRectPending(b->BackRect);
|
|
}
|
|
#endif
|
|
|
|
// Get rid of the text string
|
|
if (b->string != NULL)
|
|
MemFree( b->string );
|
|
|
|
if( b == gpAnchoredButton )
|
|
gpAnchoredButton = NULL;
|
|
if( b == gpPrevAnchoredButton )
|
|
gpPrevAnchoredButton = NULL;
|
|
|
|
MemFree(b);
|
|
b=NULL;
|
|
ButtonList[ iButtonID ] = NULL;
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// GetNextButtonNumber
|
|
//
|
|
// Finds the next available button slot.
|
|
//
|
|
INT32 GetNextButtonNumber(void)
|
|
{
|
|
INT32 x;
|
|
|
|
for(x=0;x<MAX_BUTTONS;x++)
|
|
{
|
|
if(ButtonList[x] == NULL)
|
|
return(x);
|
|
}
|
|
|
|
return(BUTTON_NO_SLOT);
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// ResizeButton
|
|
//
|
|
// Changes the size of a generic button.
|
|
//
|
|
// QuickButtons cannot be resized, therefore this function ignores the
|
|
// call if a QuickButton is given.
|
|
//
|
|
void ResizeButton(INT32 iButtonID,INT16 w, INT16 h)
|
|
{
|
|
GUI_BUTTON *b;
|
|
INT32 xloc,yloc;
|
|
|
|
if( iButtonID < 0 || iButtonID >= MAX_BUTTONS )
|
|
{
|
|
sprintf( str, "Attempting to resize button with out of range buttonID %d.", iButtonID );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
// if button size is too small, adjust it.
|
|
if(w<4)
|
|
w=4;
|
|
if(h<3)
|
|
h=3;
|
|
|
|
b = ButtonList[ iButtonID ];
|
|
|
|
if( !b )
|
|
{
|
|
sprintf( str, "Attempting to resize deleted button with buttonID %d", iButtonID );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
// If this is a QuickButton, ignore this call
|
|
if((b->uiFlags & BUTTON_TYPES) == BUTTON_QUICK)
|
|
return;
|
|
|
|
// Get current button screen location
|
|
xloc=b->XLoc;
|
|
yloc=b->YLoc;
|
|
|
|
// Set the new MOUSE_REGION area values to reflect change in size.
|
|
b->Area.RegionTopLeftX=(UINT16)xloc;
|
|
b->Area.RegionTopLeftY=(UINT16)yloc;
|
|
b->Area.RegionBottomRightX=(UINT16)(xloc+w);
|
|
b->Area.RegionBottomRightY=(UINT16)(yloc+h);
|
|
b->uiFlags |= BUTTON_DIRTY;
|
|
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
if ( b->uiFlags & BUTTON_SAVEBACKGROUND )
|
|
{
|
|
FreeBackgroundRectPending(b->BackRect);
|
|
b->BackRect = RegisterBackgroundRect(BGND_FLAG_PERMANENT | BGND_FLAG_SAVERECT, NULL,
|
|
(INT16)xloc, (INT16)yloc, (INT16)(xloc+w), (INT16)(yloc+h) );
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// SetButtonPosition
|
|
//
|
|
// Sets the position of a button on the screen. The position is relative
|
|
// to the top left corner of the button.
|
|
//
|
|
void SetButtonPosition( INT32 iButtonID ,INT16 x, INT16 y)
|
|
{
|
|
GUI_BUTTON *b;
|
|
INT32 xloc,yloc,w,h;
|
|
|
|
if( iButtonID < 0 || iButtonID >= MAX_BUTTONS )
|
|
{
|
|
sprintf( str, "Attempting to set button position with out of range buttonID %d.", iButtonID );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
b=ButtonList[ iButtonID ];
|
|
|
|
if( !b )
|
|
{
|
|
sprintf( str, "Attempting to set button position with buttonID %d", iButtonID );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
// Get new screen position
|
|
xloc=(INT16)x;
|
|
yloc=(INT16)y;
|
|
// Compute current width and height of this button
|
|
w = b->Area.RegionBottomRightX - b->Area.RegionTopLeftX;
|
|
h = b->Area.RegionBottomRightY - b->Area.RegionTopLeftY;
|
|
|
|
// Set button to new location
|
|
b->XLoc=x;
|
|
b->YLoc=y;
|
|
// Set the buttons MOUSE_REGION to appropriate area
|
|
b->Area.RegionTopLeftX=(UINT16)xloc;
|
|
b->Area.RegionTopLeftY=(UINT16)yloc;
|
|
b->Area.RegionBottomRightX=(UINT16)(xloc+w);
|
|
b->Area.RegionBottomRightY=(UINT16)(yloc+h);
|
|
b->uiFlags |= BUTTON_DIRTY;
|
|
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
if ( b->uiFlags & BUTTON_SAVEBACKGROUND )
|
|
{
|
|
FreeBackgroundRectPending(b->BackRect);
|
|
b->BackRect = RegisterBackgroundRect(BGND_FLAG_PERMANENT | BGND_FLAG_SAVERECT, NULL,
|
|
(INT16)xloc, (INT16)yloc, (INT16)(xloc+w), (INT16)(yloc+h) );
|
|
}
|
|
#endif
|
|
|
|
}
|
|
|
|
//=============================================================================
|
|
// SetButtonIcon
|
|
//
|
|
// Sets the icon to be displayed on a IconicButton.
|
|
//
|
|
// Calling this function with a button type other than Iconic has no effect.
|
|
//
|
|
INT32 SetButtonIcon( INT32 iButtonID, INT16 Icon, INT16 IconIndex )
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
if( iButtonID < 0 || iButtonID >= MAX_BUTTONS )
|
|
{
|
|
sprintf( str, "Attempting to set button icon with out of range buttonID %d.", iButtonID );
|
|
AssertMsg( 0, str );
|
|
return -1;
|
|
}
|
|
if( Icon < 0 || Icon >= MAX_BUTTON_ICONS )
|
|
{
|
|
sprintf( str, "Attempting to set button[%d] icon with out of range icon index %d.", iButtonID, Icon );
|
|
AssertMsg( 0, str );
|
|
return -1;
|
|
}
|
|
|
|
b = ButtonList[ iButtonID ];
|
|
|
|
if( !b )
|
|
{
|
|
sprintf( str, "Attempting to set deleted button icon with buttonID %d", iButtonID );
|
|
AssertMsg( 0, str );
|
|
return -1;
|
|
}
|
|
|
|
// If button isn't an icon button, ignore this call
|
|
if(((b->uiFlags & BUTTON_TYPES) == BUTTON_QUICK) ||
|
|
((b->uiFlags & BUTTON_TYPES) == BUTTON_HOT_SPOT) ||
|
|
((b->uiFlags & BUTTON_TYPES) == BUTTON_GENERIC))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
// Set the icon number and index to use for this button
|
|
b->iIconID = Icon;
|
|
b->usIconIndex = IconIndex;
|
|
|
|
return Icon;
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// CreateIconButton
|
|
//
|
|
// Creates an Iconic type button.
|
|
//
|
|
INT32 CreateIconButton(INT16 Icon,INT16 IconIndex,INT16 GenImg,INT16 xloc,INT16 yloc,INT16 w,INT16 h,INT32 Type,INT16 Priority,GUI_CALLBACK MoveCallback,GUI_CALLBACK ClickCallback)
|
|
{
|
|
GUI_BUTTON *b;
|
|
INT32 ButtonNum;
|
|
INT32 BType,x;
|
|
|
|
if( xloc < 0 || yloc < 0 )
|
|
{
|
|
sprintf( str, "Attempting to CreateIconButton with invalid position of %d,%d", xloc, yloc );
|
|
AssertMsg( 0, str );
|
|
}
|
|
if( GenImg < -1 || GenImg >= MAX_GENERIC_PICS )
|
|
{
|
|
sprintf( str, "Attempting to CreateIconButton with out of range iconID %d.", GenImg );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
// if button size is too small, adjust it.
|
|
if(w<4)
|
|
w=4;
|
|
if(h<3)
|
|
h=3;
|
|
|
|
// Strip off any extraneous bits from button type
|
|
BType = Type & ( BUTTON_TYPE_MASK | BUTTON_NEWTOGGLE );
|
|
|
|
// Get a button number (slot) for this new button
|
|
if((ButtonNum = GetNextButtonNumber()) == BUTTON_NO_SLOT)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"CreateIconButton: No more button slots");
|
|
return(-1);
|
|
}
|
|
|
|
// Allocate memory for the GUI_BUTTON structure
|
|
if((b=(GUI_BUTTON *)MemAlloc(sizeof(GUI_BUTTON))) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"CreateIconButton: Can't alloc mem for button struct");
|
|
return(-1);
|
|
}
|
|
|
|
memset(b, 0, sizeof(GUI_BUTTON));
|
|
|
|
// Init the values in the struct
|
|
b->uiFlags = BUTTON_DIRTY;
|
|
b->uiOldFlags = 0;
|
|
b->IDNum = ButtonNum;
|
|
b->XLoc = xloc;
|
|
b->YLoc = yloc;
|
|
|
|
if(GenImg<0)
|
|
b->ImageNum = 0;
|
|
else
|
|
b->ImageNum = GenImg;
|
|
|
|
for(x=0;x<4;x++)
|
|
b->UserData[x] = 0;
|
|
b->Group = -1;
|
|
|
|
b->bDefaultStatus = DEFAULT_STATUS_NONE;
|
|
b->bDisabledStyle = DISABLED_STYLE_DEFAULT;
|
|
//Init text
|
|
b->string = NULL;
|
|
b->usFont = 0;
|
|
b->fMultiColor=FALSE;
|
|
b->sForeColor = 0;
|
|
b->sWrappedWidth = -1;
|
|
b->sShadowColor = -1;
|
|
b->sForeColorDown = -1;
|
|
b->sShadowColorDown = -1;
|
|
b->sForeColorHilited = -1;
|
|
b->sShadowColorHilited = -1;
|
|
b->bJustification = BUTTON_TEXT_CENTER;
|
|
b->bTextXOffset = -1;
|
|
b->bTextYOffset = -1;
|
|
b->bTextXSubOffSet = 0;
|
|
b->bTextYSubOffSet = 0;
|
|
b->fShiftText = TRUE;
|
|
//Init icon
|
|
b->iIconID = Icon;
|
|
b->usIconIndex = IconIndex;
|
|
b->bIconXOffset = -1;
|
|
b->bIconYOffset = -1;
|
|
b->fShiftImage = TRUE;
|
|
|
|
// Set the click callback function (if any)
|
|
if(ClickCallback != BUTTON_NO_CALLBACK)
|
|
{
|
|
b->ClickCallback = ClickCallback;
|
|
BType |= BUTTON_CLICK_CALLBACK;
|
|
}
|
|
else
|
|
b->ClickCallback = BUTTON_NO_CALLBACK;
|
|
|
|
// Set the move callback function (if any)
|
|
if(MoveCallback != BUTTON_NO_CALLBACK)
|
|
{
|
|
b->MoveCallback = MoveCallback;
|
|
BType |= BUTTON_MOVE_CALLBACK;
|
|
}
|
|
else
|
|
b->MoveCallback = BUTTON_NO_CALLBACK;
|
|
|
|
// Define a mouse region for this button
|
|
MSYS_DefineRegion(&b->Area, (UINT16)xloc, (UINT16)yloc, (UINT16)(xloc+w), (UINT16)(yloc+h),
|
|
(INT8)Priority, MSYS_STARTING_CURSORVAL, (MOUSE_CALLBACK)QuickButtonCallbackMMove, (MOUSE_CALLBACK)QuickButtonCallbackMButn);
|
|
|
|
// Link the mouse region to this button (for callback purposes)
|
|
MSYS_SetRegionUserData(&b->Area,0,ButtonNum);
|
|
|
|
// Set this button's flags
|
|
b->uiFlags |= ( BUTTON_ENABLED | BType | BUTTON_GENERIC );
|
|
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
b->BackRect = -1;
|
|
#endif
|
|
|
|
// Add button to the button list
|
|
#ifdef BUTTONSYSTEM_DEBUGGING
|
|
AssertFailIfIdenticalButtonAttributesFound( b );
|
|
#endif
|
|
ButtonList[ButtonNum]=b;
|
|
|
|
SpecifyButtonSoundScheme( b->IDNum, BUTTON_SOUND_SCHEME_GENERIC );
|
|
|
|
// return this button's slot number
|
|
return(ButtonNum);
|
|
}
|
|
|
|
//Creates a generic button with text on it.
|
|
INT32 CreateTextButton(STR16 string, UINT32 uiFont, INT16 sForeColor, INT16 sShadowColor, INT16 GenImg, INT16 xloc, INT16 yloc, INT16 w, INT16 h, INT32 Type, INT16 Priority,GUI_CALLBACK MoveCallback, GUI_CALLBACK ClickCallback)
|
|
{
|
|
GUI_BUTTON *b;
|
|
INT32 ButtonNum;
|
|
INT32 BType,x;
|
|
|
|
if( xloc < 0 || yloc < 0 )
|
|
{
|
|
sprintf( str, "Attempting to CreateTextButton with invalid position of %d,%d", xloc, yloc );
|
|
AssertMsg( 0, str );
|
|
}
|
|
if( GenImg < -1 || GenImg >= MAX_GENERIC_PICS )
|
|
{
|
|
sprintf( str, "Attempting to CreateTextButton with out of range iconID %d.", GenImg );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
// if button size is too small, adjust it.
|
|
if(w<4)
|
|
w=4;
|
|
if(h<3)
|
|
h=3;
|
|
|
|
// Strip off any extraneous bits from button type
|
|
BType = Type & ( BUTTON_TYPE_MASK | BUTTON_NEWTOGGLE );
|
|
|
|
// Get a button number for this new button
|
|
if((ButtonNum = GetNextButtonNumber()) == BUTTON_NO_SLOT)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"CreateTextButton: No more button slots");
|
|
return(-1);
|
|
}
|
|
|
|
// Allocate memory for a GUI_BUTTON structure
|
|
if((b=(GUI_BUTTON *)MemAlloc(sizeof(GUI_BUTTON))) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"CreateTextButton: Can't alloc mem for button struct");
|
|
return(-1);
|
|
}
|
|
|
|
memset(b, 0, sizeof(GUI_BUTTON));
|
|
|
|
// Allocate memory for the button's text string...
|
|
b->string = NULL;
|
|
if ( string && wcslen( string ) )
|
|
{
|
|
b->string = (STR16) MemAlloc( (wcslen(string)+1)*sizeof(CHAR16) );
|
|
AssertMsg( b->string, "Out of memory error: Couldn't allocate string in CreateTextButton." );
|
|
wcscpy( b->string, string );
|
|
}
|
|
|
|
// Init the button structure variables
|
|
b->uiFlags = BUTTON_DIRTY;
|
|
b->uiOldFlags = 0;
|
|
b->IDNum = ButtonNum;
|
|
b->XLoc = xloc;
|
|
b->YLoc = yloc;
|
|
|
|
if(GenImg<0)
|
|
b->ImageNum = 0;
|
|
else
|
|
b->ImageNum = GenImg;
|
|
|
|
for(x=0;x<4;x++)
|
|
b->UserData[x] = 0;
|
|
b->Group = -1;
|
|
b->bDefaultStatus = DEFAULT_STATUS_NONE;
|
|
b->bDisabledStyle = DISABLED_STYLE_DEFAULT;
|
|
//Init string
|
|
b->usFont = (UINT16)uiFont;
|
|
b->fMultiColor=FALSE;
|
|
b->sForeColor = sForeColor;
|
|
b->sWrappedWidth = -1;
|
|
b->sShadowColor = sShadowColor;
|
|
b->sForeColorDown = -1;
|
|
b->sShadowColorDown = -1;
|
|
b->sForeColorHilited = -1;
|
|
b->sShadowColorHilited = -1;
|
|
b->bJustification = BUTTON_TEXT_CENTER;
|
|
b->bTextXOffset = -1;
|
|
b->bTextYOffset = -1;
|
|
b->bTextXSubOffSet = 0;
|
|
b->bTextYSubOffSet = 0;
|
|
b->fShiftText = TRUE;
|
|
//Init icon
|
|
b->iIconID = -1;
|
|
b->usIconIndex = -1;
|
|
b->bIconXOffset = -1;
|
|
b->bIconYOffset = -1;
|
|
b->fShiftImage = TRUE;
|
|
|
|
// Set the button click callback function (if any)
|
|
if(ClickCallback != BUTTON_NO_CALLBACK)
|
|
{
|
|
b->ClickCallback = ClickCallback;
|
|
BType |= BUTTON_CLICK_CALLBACK;
|
|
}
|
|
else
|
|
b->ClickCallback = BUTTON_NO_CALLBACK;
|
|
|
|
// Set the button's mouse movement callback function (if any)
|
|
if(MoveCallback != BUTTON_NO_CALLBACK)
|
|
{
|
|
b->MoveCallback = MoveCallback;
|
|
BType |= BUTTON_MOVE_CALLBACK;
|
|
}
|
|
else
|
|
b->MoveCallback = BUTTON_NO_CALLBACK;
|
|
|
|
// Define a MOUSE_REGION for this button
|
|
MSYS_DefineRegion(&b->Area, (UINT16)xloc, (UINT16)yloc, (UINT16)(xloc+w), (UINT16)(yloc+h),
|
|
(INT8)Priority, MSYS_STARTING_CURSORVAL, (MOUSE_CALLBACK)QuickButtonCallbackMMove, (MOUSE_CALLBACK)QuickButtonCallbackMButn);
|
|
|
|
// Link the MOUSE_REGION to this button
|
|
MSYS_SetRegionUserData(&b->Area,0,ButtonNum);
|
|
|
|
// Set the flags for this button
|
|
b->uiFlags |= ( BUTTON_ENABLED | BType | BUTTON_GENERIC);
|
|
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
b->BackRect = -1;
|
|
#endif
|
|
|
|
// Add this button to the button list
|
|
#ifdef BUTTONSYSTEM_DEBUGGING
|
|
AssertFailIfIdenticalButtonAttributesFound( b );
|
|
#endif
|
|
ButtonList[ButtonNum]=b;
|
|
|
|
SpecifyButtonSoundScheme( b->IDNum, BUTTON_SOUND_SCHEME_GENERIC );
|
|
|
|
// return the slot number
|
|
return(ButtonNum);
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// CreateHotSpot
|
|
//
|
|
// Creates a button like HotSpot. HotSpots have no graphics associated with
|
|
// them.
|
|
//
|
|
INT32 CreateHotSpot(INT16 xloc, INT16 yloc, INT16 Width, INT16 Height,INT16 Priority,GUI_CALLBACK MoveCallback,GUI_CALLBACK ClickCallback)
|
|
{
|
|
GUI_BUTTON *b;
|
|
INT32 ButtonNum;
|
|
INT16 BType,x;
|
|
|
|
if( xloc < 0 || yloc < 0 || Width < 0 || Height < 0 )
|
|
{
|
|
sprintf( str, "Attempting to CreateHotSpot with invalid coordinates: %d,%d, width: %d, and height: %d.",
|
|
xloc, yloc, Width, Height );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
BType=0;
|
|
|
|
// Get a button number for this hotspot
|
|
if((ButtonNum = GetNextButtonNumber()) == BUTTON_NO_SLOT)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"CreateHotSpot: No more button slots");
|
|
return(-1);
|
|
}
|
|
|
|
// Allocate memory for the GUI_BUTTON structure
|
|
if((b=(GUI_BUTTON *)MemAlloc(sizeof(GUI_BUTTON))) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"CreateHotSpot: Can't alloc mem for button struct");
|
|
return(-1);
|
|
}
|
|
|
|
memset(b, 0, sizeof(GUI_BUTTON));
|
|
|
|
// Init the structure values
|
|
b->uiFlags = 0;
|
|
b->uiOldFlags = 0;
|
|
b->IDNum = ButtonNum;
|
|
b->XLoc = xloc;
|
|
b->YLoc = yloc;
|
|
b->ImageNum = 0xffffffff;
|
|
for(x=0;x<4;x++)
|
|
b->UserData[x] = 0;
|
|
b->Group = -1;
|
|
b->string = NULL;
|
|
|
|
// Set the hotspot click callback function (if any)
|
|
if(ClickCallback != BUTTON_NO_CALLBACK)
|
|
{
|
|
b->ClickCallback = ClickCallback;
|
|
BType |= BUTTON_CLICK_CALLBACK;
|
|
}
|
|
else
|
|
b->ClickCallback = BUTTON_NO_CALLBACK;
|
|
|
|
// Set the hotspot's mouse movement callback function (if any)
|
|
if(MoveCallback != BUTTON_NO_CALLBACK)
|
|
{
|
|
b->MoveCallback = MoveCallback;
|
|
BType |= BUTTON_MOVE_CALLBACK;
|
|
}
|
|
else
|
|
b->MoveCallback = BUTTON_NO_CALLBACK;
|
|
|
|
// define a MOUSE_REGION for this hotspot
|
|
MSYS_DefineRegion(&b->Area,(UINT16)xloc,(UINT16)yloc,(UINT16)(xloc+Width),(UINT16)(yloc+Height),
|
|
(INT8)Priority, MSYS_STARTING_CURSORVAL, (MOUSE_CALLBACK)QuickButtonCallbackMMove, (MOUSE_CALLBACK)QuickButtonCallbackMButn);
|
|
|
|
// Link the MOUSE_REGION to this hotspot
|
|
MSYS_SetRegionUserData(&b->Area,0,ButtonNum);
|
|
|
|
// Set the flags entry for this hotspot
|
|
b->uiFlags |= (BUTTON_ENABLED|BType|BUTTON_HOT_SPOT);
|
|
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
b->BackRect = -1;
|
|
#endif
|
|
|
|
// Add this button (hotspot) to the button list
|
|
#ifdef BUTTONSYSTEM_DEBUGGING
|
|
AssertFailIfIdenticalButtonAttributesFound( b );
|
|
#endif
|
|
ButtonList[ButtonNum]=b;
|
|
|
|
SpecifyButtonSoundScheme( b->IDNum, BUTTON_SOUND_SCHEME_GENERIC );
|
|
|
|
// return the button slot number
|
|
return(ButtonNum);
|
|
}
|
|
|
|
|
|
|
|
// ============================================================================
|
|
// Addition Oct15/97, Carter
|
|
// SetButtonCursor
|
|
// will simply set the cursor for the mouse region the button occupies
|
|
BOOLEAN SetButtonCursor(INT32 iBtnId, UINT16 crsr)
|
|
{
|
|
GUI_BUTTON *b;
|
|
b = ButtonList[iBtnId];
|
|
if (!b)
|
|
return FALSE;
|
|
b->Area.Cursor = crsr;
|
|
return TRUE;
|
|
}
|
|
|
|
//=============================================================================
|
|
// QuickCreateButton
|
|
//
|
|
// Creates a QuickButton. QuickButtons only have graphics associated with
|
|
// them. They cannot be re-sized, nor can the graphic be changed.
|
|
//
|
|
INT32 QuickCreateButton(UINT32 Image,INT16 xloc,INT16 yloc,INT32 Type,INT16 Priority,GUI_CALLBACK MoveCallback,GUI_CALLBACK ClickCallback)
|
|
{
|
|
GUI_BUTTON *b;
|
|
INT32 ButtonNum;
|
|
INT32 BType,x;
|
|
|
|
if( xloc < 0 || yloc < 0 )
|
|
{
|
|
sprintf( str, "Attempting to QuickCreateButton with invalid position of %d,%d", xloc, yloc );
|
|
AssertMsg( 0, str );
|
|
}
|
|
if( Image < 0 || Image >= MAX_BUTTON_PICS )
|
|
{
|
|
sprintf( str, "Attempting to QuickCreateButton with out of range ImageID %d.", Image );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
// Strip off any extraneous bits from button type
|
|
BType = Type & ( BUTTON_TYPE_MASK | BUTTON_NEWTOGGLE );
|
|
|
|
// Is there a QuickButton image in the given image slot?
|
|
if(ButtonPictures[Image].vobj == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"QuickCreateButton: Invalid button image number");
|
|
return(-1);
|
|
}
|
|
|
|
// Get a new button number
|
|
if((ButtonNum = GetNextButtonNumber()) == BUTTON_NO_SLOT)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"QuickCreateButton: No more button slots");
|
|
return(-1);
|
|
}
|
|
|
|
// Allocate memory for a GUI_BUTTON structure
|
|
if((b=(GUI_BUTTON *)MemAlloc(sizeof(GUI_BUTTON))) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"QuickCreateButton: Can't alloc mem for button struct");
|
|
return(-1);
|
|
}
|
|
|
|
memset(b, 0, sizeof(GUI_BUTTON));
|
|
|
|
// Set the values for this buttn
|
|
b->uiFlags = BUTTON_DIRTY;
|
|
b->uiOldFlags = 0;
|
|
|
|
// Set someflags if of s certain type....
|
|
if ( Type & BUTTON_NEWTOGGLE )
|
|
{
|
|
b->uiFlags |= BUTTON_NEWTOGGLE;
|
|
}
|
|
|
|
// shadow style
|
|
b->bDefaultStatus = DEFAULT_STATUS_NONE;
|
|
b->bDisabledStyle = DISABLED_STYLE_DEFAULT;
|
|
|
|
b->Group = -1;
|
|
//Init string
|
|
b->string = NULL;
|
|
b->usFont = 0;
|
|
b->fMultiColor=FALSE;
|
|
b->sForeColor = 0;
|
|
b->sWrappedWidth = -1;
|
|
b->sShadowColor = -1;
|
|
b->sForeColorDown = -1;
|
|
b->sShadowColorDown = -1;
|
|
b->sForeColorHilited = -1;
|
|
b->sShadowColorHilited = -1;
|
|
b->bJustification = BUTTON_TEXT_CENTER;
|
|
b->bTextXOffset = -1;
|
|
b->bTextYOffset = -1;
|
|
b->bTextXSubOffSet = 0;
|
|
b->bTextYSubOffSet = 0;
|
|
b->fShiftText = TRUE;
|
|
//Init icon
|
|
b->iIconID = -1;
|
|
b->usIconIndex = -1;
|
|
b->bIconXOffset = -1;
|
|
b->bIconYOffset = -1;
|
|
b->fShiftImage = TRUE;
|
|
//Init quickbutton
|
|
b->IDNum = ButtonNum;
|
|
b->ImageNum = Image;
|
|
for(x=0;x<4;x++)
|
|
b->UserData[x] = 0;
|
|
|
|
b->XLoc = xloc;
|
|
b->YLoc = yloc;
|
|
|
|
b->ubToggleButtonOldState = 0;
|
|
b->ubToggleButtonActivated = FALSE;
|
|
|
|
// Set the button click callback function (if any)
|
|
if(ClickCallback != BUTTON_NO_CALLBACK)
|
|
{
|
|
b->ClickCallback = ClickCallback;
|
|
BType |= BUTTON_CLICK_CALLBACK;
|
|
}
|
|
else
|
|
b->ClickCallback = BUTTON_NO_CALLBACK;
|
|
|
|
// Set the button's mouse movement callback function (if any)
|
|
if(MoveCallback != BUTTON_NO_CALLBACK)
|
|
{
|
|
b->MoveCallback = MoveCallback;
|
|
BType |= BUTTON_MOVE_CALLBACK;
|
|
}
|
|
else
|
|
b->MoveCallback = BUTTON_NO_CALLBACK;
|
|
|
|
memset( &b->Area, 0, sizeof( MOUSE_REGION ) );
|
|
// Define a MOUSE_REGION for this QuickButton
|
|
MSYS_DefineRegion(&b->Area,(UINT16)xloc,(UINT16)yloc,
|
|
(UINT16)(xloc+(INT16)ButtonPictures[Image].MaxWidth),
|
|
(UINT16)(yloc+(INT16)ButtonPictures[Image].MaxHeight),
|
|
(INT8)Priority, MSYS_STARTING_CURSORVAL,
|
|
(MOUSE_CALLBACK)QuickButtonCallbackMMove,
|
|
(MOUSE_CALLBACK)QuickButtonCallbackMButn);
|
|
|
|
// Link the MOUSE_REGION with this QuickButton
|
|
MSYS_SetRegionUserData(&b->Area,0,ButtonNum);
|
|
|
|
// Set the flags for this button
|
|
b->uiFlags |= BUTTON_ENABLED | BType | BUTTON_QUICK;
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
b->BackRect = -1;
|
|
#endif
|
|
|
|
// Add this QuickButton to the button list
|
|
#ifdef BUTTONSYSTEM_DEBUGGING
|
|
AssertFailIfIdenticalButtonAttributesFound( b );
|
|
#endif
|
|
ButtonList[ButtonNum]=b;
|
|
|
|
SpecifyButtonSoundScheme( b->IDNum, BUTTON_SOUND_SCHEME_GENERIC );
|
|
|
|
// return the button number (slot)
|
|
return(ButtonNum);
|
|
}
|
|
|
|
//A hybrid of QuickCreateButton. Takes a lot less parameters, but makes more assumptions. It self manages the
|
|
//loading, and deleting of the image. The size of the image determines the size of the button. It also uses
|
|
//the default move callback which emulates Win95. Finally, it sets the priority to normal. The function you
|
|
//choose also determines the type of button (toggle, notoggle, or newtoggle)
|
|
INT32 CreateEasyNoToggleButton ( INT32 x, INT32 y, const STR8 filename, GUI_CALLBACK ClickCallback )
|
|
{
|
|
return CreateSimpleButton( x, y, filename, BUTTON_NO_TOGGLE, MSYS_PRIORITY_NORMAL, ClickCallback );
|
|
}
|
|
|
|
INT32 CreateEasyToggleButton ( INT32 x, INT32 y, const STR8 filename, GUI_CALLBACK ClickCallback )
|
|
{
|
|
return CreateSimpleButton( x, y, filename, BUTTON_TOGGLE, MSYS_PRIORITY_NORMAL, ClickCallback );
|
|
}
|
|
|
|
INT32 CreateEasyNewToggleButton( INT32 x, INT32 y, const STR8 filename, GUI_CALLBACK ClickCallback )
|
|
{
|
|
return CreateSimpleButton( x, y, filename, BUTTON_NEWTOGGLE, MSYS_PRIORITY_NORMAL, ClickCallback );
|
|
}
|
|
|
|
//Same as above, but accepts specify toggle type
|
|
INT32 CreateEasyButton( INT32 x, INT32 y, const STR8 filename, INT32 Type, GUI_CALLBACK ClickCallback)
|
|
{
|
|
return CreateSimpleButton( x, y, filename, Type, MSYS_PRIORITY_NORMAL, ClickCallback );
|
|
}
|
|
|
|
//Same as above, but accepts priority specification.
|
|
INT32 CreateSimpleButton( INT32 x, INT32 y, const STR8 filename, INT32 Type, INT16 Priority, GUI_CALLBACK ClickCallback )
|
|
{
|
|
INT32 ButPic,ButNum;
|
|
|
|
if( !filename || !strlen(filename) )
|
|
AssertMsg( 0, "Attempting to CreateSimpleButton with null filename." );
|
|
|
|
if( ( ButPic = LoadButtonImage( filename, -1, 1, 2, 3, 4 ) ) == -1)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"Can't load button image");
|
|
return( -1 );
|
|
}
|
|
|
|
ButNum = (INT16)QuickCreateButton( ButPic, (INT16)x,(INT16)y, Type, Priority, DEFAULT_MOVE_CALLBACK, ClickCallback);
|
|
|
|
AssertMsg( ButNum != -1, "Failed to CreateSimpleButton." );
|
|
|
|
ButtonList[ ButNum ]->uiFlags |= BUTTON_SELFDELETE_IMAGE;
|
|
|
|
SpecifyDisabledButtonStyle( ButNum, DISABLED_STYLE_SHADED );
|
|
|
|
return( ButNum );
|
|
}
|
|
|
|
INT32 CreateIconAndTextButton( INT32 Image, const STR16 string, UINT32 uiFont,
|
|
INT16 sForeColor, INT16 sShadowColor,
|
|
INT16 sForeColorDown, INT16 sShadowColorDown,
|
|
INT8 bJustification,
|
|
INT16 xloc, INT16 yloc, INT32 Type, INT16 Priority,
|
|
GUI_CALLBACK MoveCallback,GUI_CALLBACK ClickCallback)
|
|
{
|
|
GUI_BUTTON *b;
|
|
INT32 iButtonID;
|
|
INT32 BType,x;
|
|
|
|
if( xloc < 0 || yloc < 0 )
|
|
{
|
|
sprintf( str, "Attempting to CreateIconAndTextButton with invalid position of %d,%d", xloc, yloc );
|
|
AssertMsg( 0, str );
|
|
}
|
|
if( Image < 0 || Image >= MAX_BUTTON_PICS )
|
|
{
|
|
sprintf( str, "Attemting to CreateIconAndTextButton with out of range ImageID %d.", Image );
|
|
AssertMsg( 0, str );
|
|
}
|
|
|
|
// Strip off any extraneous bits from button type
|
|
BType = Type & ( BUTTON_TYPE_MASK | BUTTON_NEWTOGGLE | BUTTON_16BPPCOLOURTEXT );
|
|
|
|
// Is there a QuickButton image in the given image slot?
|
|
if(ButtonPictures[Image].vobj == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"QuickCreateButton: Invalid button image number");
|
|
return(-1);
|
|
}
|
|
|
|
// Get a new button number
|
|
if((iButtonID = GetNextButtonNumber()) == BUTTON_NO_SLOT)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"QuickCreateButton: No more button slots");
|
|
return(-1);
|
|
}
|
|
|
|
// Allocate memory for a GUI_BUTTON structure
|
|
if((b=(GUI_BUTTON *)MemAlloc(sizeof(GUI_BUTTON))) == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"QuickCreateButton: Can't alloc mem for button struct");
|
|
return(-1);
|
|
}
|
|
|
|
memset(b, 0, sizeof(GUI_BUTTON));
|
|
|
|
// Set the values for this button
|
|
b->uiFlags = BUTTON_DIRTY;
|
|
b->uiOldFlags = 0;
|
|
b->IDNum = iButtonID;
|
|
b->XLoc = xloc;
|
|
b->YLoc = yloc;
|
|
b->ImageNum = Image;
|
|
for(x=0;x<4;x++)
|
|
b->UserData[x] = 0;
|
|
b->Group = -1;
|
|
b->bDefaultStatus = DEFAULT_STATUS_NONE;
|
|
b->bDisabledStyle = DISABLED_STYLE_DEFAULT;
|
|
|
|
// Allocate memory for the button's text string...
|
|
b->string = NULL;
|
|
if ( string )
|
|
{
|
|
b->string = (STR16) MemAlloc( (wcslen(string)+1)*sizeof(CHAR16) );
|
|
AssertMsg( b->string, "Out of memory error: Couldn't allocate string in CreateIconAndTextButton." );
|
|
wcscpy( b->string, string );
|
|
}
|
|
|
|
b->bJustification = bJustification;
|
|
b->usFont = (UINT16)uiFont;
|
|
b->fMultiColor=FALSE;
|
|
b->sForeColor = sForeColor;
|
|
b->sWrappedWidth = -1;
|
|
b->sShadowColor = sShadowColor;
|
|
b->sForeColorDown = sForeColorDown;
|
|
b->sShadowColorDown = sShadowColorDown;
|
|
b->sForeColorHilited = -1;
|
|
b->sShadowColorHilited = -1;
|
|
b->bTextXOffset = -1;
|
|
b->bTextYOffset = -1;
|
|
b->bTextXSubOffSet = 0;
|
|
b->bTextYSubOffSet = 0;
|
|
b->fShiftText = TRUE;
|
|
|
|
b->iIconID = -1;
|
|
b->usIconIndex = 0;
|
|
|
|
// Set the button click callback function (if any)
|
|
if(ClickCallback != BUTTON_NO_CALLBACK)
|
|
{
|
|
b->ClickCallback = ClickCallback;
|
|
BType |= BUTTON_CLICK_CALLBACK;
|
|
}
|
|
else
|
|
b->ClickCallback = BUTTON_NO_CALLBACK;
|
|
|
|
// Set the button's mouse movement callback function (if any)
|
|
if(MoveCallback != BUTTON_NO_CALLBACK)
|
|
{
|
|
b->MoveCallback = MoveCallback;
|
|
BType |= BUTTON_MOVE_CALLBACK;
|
|
}
|
|
else
|
|
b->MoveCallback = BUTTON_NO_CALLBACK;
|
|
|
|
// Define a MOUSE_REGION for this QuickButton
|
|
MSYS_DefineRegion(&b->Area,(UINT16)xloc,(UINT16)yloc,
|
|
(UINT16)(xloc+(INT16)ButtonPictures[Image].MaxWidth),
|
|
(UINT16)(yloc+(INT16)ButtonPictures[Image].MaxHeight),
|
|
(INT8)Priority, MSYS_STARTING_CURSORVAL,
|
|
(MOUSE_CALLBACK)QuickButtonCallbackMMove,
|
|
(MOUSE_CALLBACK)QuickButtonCallbackMButn);
|
|
|
|
// Link the MOUSE_REGION with this QuickButton
|
|
MSYS_SetRegionUserData(&b->Area,0,iButtonID);
|
|
|
|
// Set the flags for this button
|
|
b->uiFlags |= ( BUTTON_ENABLED | BType | BUTTON_QUICK );
|
|
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
b->BackRect = -1;
|
|
#endif
|
|
|
|
// Add this QuickButton to the button list
|
|
#ifdef BUTTONSYSTEM_DEBUGGING
|
|
AssertFailIfIdenticalButtonAttributesFound( b );
|
|
#endif
|
|
ButtonList[iButtonID]=b;
|
|
|
|
SpecifyButtonSoundScheme( b->IDNum, BUTTON_SOUND_SCHEME_GENERIC );
|
|
|
|
// return the button number (slot)
|
|
return(iButtonID);
|
|
}
|
|
|
|
//New functions
|
|
void SpecifyButtonText( INT32 iButtonID, STR16 string )
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
|
|
b = ButtonList[ iButtonID ];
|
|
|
|
//free the previous strings memory if applicable
|
|
if( b->string )
|
|
MemFree( b->string );
|
|
b->string = NULL;
|
|
|
|
if( string && wcslen( string ) )
|
|
{
|
|
//allocate memory for the new string
|
|
b->string = (STR16) MemAlloc( (wcslen(string)+1)*sizeof(CHAR16) );
|
|
Assert( b->string );
|
|
//copy the string to the button
|
|
wcscpy( b->string, string );
|
|
b->uiFlags |= BUTTON_DIRTY;
|
|
}
|
|
}
|
|
|
|
void SpecifyButtonMultiColorFont(INT32 iButtonID, BOOLEAN fMultiColor)
|
|
{
|
|
GUI_BUTTON *b;
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
b->fMultiColor = fMultiColor;
|
|
b->uiFlags |= BUTTON_DIRTY ;
|
|
}
|
|
|
|
void SpecifyButtonFont( INT32 iButtonID, UINT32 uiFont )
|
|
{
|
|
GUI_BUTTON *b;
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
b->usFont = (UINT16)uiFont;
|
|
b->uiFlags |= BUTTON_DIRTY ;
|
|
}
|
|
|
|
void SpecifyButtonUpTextColors( INT32 iButtonID, INT16 sForeColor, INT16 sShadowColor )
|
|
{
|
|
GUI_BUTTON *b;
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
b->sForeColor = sForeColor;
|
|
b->sShadowColor = sShadowColor;
|
|
b->uiFlags |= BUTTON_DIRTY ;
|
|
}
|
|
|
|
void SpecifyButtonDownTextColors( INT32 iButtonID, INT16 sForeColorDown, INT16 sShadowColorDown )
|
|
{
|
|
GUI_BUTTON *b;
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
b->sForeColorDown = sForeColorDown;
|
|
b->sShadowColorDown = sShadowColorDown;
|
|
b->uiFlags |= BUTTON_DIRTY ;
|
|
}
|
|
|
|
void SpecifyButtonHilitedTextColors( INT32 iButtonID, INT16 sForeColorHilited, INT16 sShadowColorHilited )
|
|
{
|
|
GUI_BUTTON *b;
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
b->sForeColorHilited = sForeColorHilited;
|
|
b->sShadowColorHilited = sShadowColorHilited;
|
|
b->uiFlags |= BUTTON_DIRTY ;
|
|
}
|
|
|
|
void SpecifyButtonTextJustification( INT32 iButtonID, INT8 bJustification )
|
|
{
|
|
GUI_BUTTON *b;
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
//Range check: if invalid, then set it to center justified.
|
|
if( bJustification < BUTTON_TEXT_LEFT || bJustification > BUTTON_TEXT_RIGHT )
|
|
bJustification = BUTTON_TEXT_CENTER;
|
|
b->bJustification = bJustification;
|
|
b->uiFlags |= BUTTON_DIRTY ;
|
|
}
|
|
|
|
void SpecifyFullButtonTextAttributes( INT32 iButtonID, STR16 string, INT32 uiFont,
|
|
INT16 sForeColor, INT16 sShadowColor,
|
|
INT16 sForeColorDown, INT16 sShadowColorDown, INT8 bJustification )
|
|
{
|
|
GUI_BUTTON *b;
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
//Copy over information
|
|
SpecifyButtonText( iButtonID, string );
|
|
b->usFont = (UINT16)uiFont;
|
|
b->sForeColor = sForeColor;
|
|
b->sShadowColor = sShadowColor;
|
|
b->sForeColorDown = sForeColorDown;
|
|
b->sShadowColorDown = sShadowColorDown;
|
|
//Range check: if invalid, then set it to center justified.
|
|
if( bJustification < BUTTON_TEXT_LEFT || bJustification > BUTTON_TEXT_RIGHT )
|
|
bJustification = BUTTON_TEXT_CENTER;
|
|
b->bJustification = bJustification;
|
|
b->uiFlags |= BUTTON_DIRTY ;
|
|
}
|
|
|
|
void SpecifyGeneralButtonTextAttributes( INT32 iButtonID, STR16 string, INT32 uiFont,
|
|
INT16 sForeColor, INT16 sShadowColor )
|
|
{
|
|
GUI_BUTTON *b;
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
//Copy over information
|
|
SpecifyButtonText( iButtonID, string );
|
|
b->usFont = (UINT16)uiFont;
|
|
b->sForeColor = sForeColor;
|
|
b->sShadowColor = sShadowColor;
|
|
b->uiFlags |= BUTTON_DIRTY ;
|
|
}
|
|
|
|
void SpecifyButtonTextOffsets( INT32 iButtonID, INT8 bTextXOffset, INT8 bTextYOffset, BOOLEAN fShiftText )
|
|
{
|
|
GUI_BUTTON *b;
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
//Copy over information
|
|
b->bTextXOffset = bTextXOffset;
|
|
b->bTextYOffset = bTextYOffset;
|
|
b->fShiftText = fShiftText;
|
|
}
|
|
|
|
void SpecifyButtonTextSubOffsets( INT32 iButtonID, INT8 bTextXOffset, INT8 bTextYOffset, BOOLEAN fShiftText )
|
|
{
|
|
GUI_BUTTON *b;
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
//Copy over information
|
|
b->bTextXSubOffSet = bTextXOffset;
|
|
b->bTextYSubOffSet = bTextYOffset;
|
|
b->fShiftText = fShiftText;
|
|
}
|
|
|
|
|
|
void SpecifyButtonTextWrappedWidth(INT32 iButtonID, INT16 sWrappedWidth)
|
|
{
|
|
GUI_BUTTON *b;
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
|
|
b->sWrappedWidth = sWrappedWidth;
|
|
}
|
|
|
|
void SpecifyDisabledButtonStyle( INT32 iButtonID, INT8 bStyle )
|
|
{
|
|
GUI_BUTTON *b;
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
|
|
Assert( bStyle >= DISABLED_STYLE_NONE && bStyle <= DISABLED_STYLE_SHADED );
|
|
|
|
b->bDisabledStyle = bStyle;
|
|
}
|
|
|
|
|
|
//Note: Text is always on top
|
|
//If fShiftImage is true, then the image will shift down one pixel and right one pixel
|
|
//just like the text does.
|
|
BOOLEAN SpecifyButtonIcon( INT32 iButtonID, INT32 iVideoObjectID, UINT16 usVideoObjectIndex,
|
|
INT8 bXOffset, INT8 bYOffset, BOOLEAN fShiftImage )
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
|
|
b->iIconID = iVideoObjectID;
|
|
b->usIconIndex = usVideoObjectIndex;
|
|
|
|
if( b->iIconID == -1 )
|
|
return FALSE;
|
|
|
|
b->bIconXOffset = bXOffset;
|
|
b->bIconYOffset = bYOffset;
|
|
b->fShiftImage = TRUE;
|
|
|
|
b->uiFlags |= BUTTON_DIRTY;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
//OJW - 20081224
|
|
BOOLEAN SpecifyButtonImage( INT32 iButtonID, UINT32 iButtonImageID)
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
|
|
// Is there a QuickButton image in the given image slot?
|
|
if(ButtonPictures[iButtonImageID].vobj == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"QuickCreateButton: Invalid button image number");
|
|
return false;
|
|
}
|
|
|
|
b->ImageNum = iButtonImageID;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOLEAN SpecifyButtonImage( GUI_BUTTON *b, UINT32 iButtonImageID)
|
|
{
|
|
Assert( b );
|
|
|
|
// Is there a QuickButton image in the given image slot?
|
|
if(ButtonPictures[iButtonImageID].vobj == NULL)
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"QuickCreateButton: Invalid button image number");
|
|
return false;
|
|
}
|
|
|
|
b->ImageNum = iButtonImageID;
|
|
|
|
return TRUE;
|
|
}
|
|
void RemoveTextFromButton( INT32 iButtonID )
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
//Init string
|
|
if( b->string )
|
|
MemFree( b->string );
|
|
b->string = NULL;
|
|
b->usFont = 0;
|
|
b->sForeColor = 0;
|
|
b->sWrappedWidth = -1;
|
|
b->sShadowColor = -1;
|
|
b->sForeColorDown = -1;
|
|
b->sShadowColorDown = -1;
|
|
b->sForeColorHilited = -1;
|
|
b->sShadowColorHilited = -1;
|
|
b->bJustification = BUTTON_TEXT_CENTER;
|
|
b->bTextXOffset = -1;
|
|
b->bTextYOffset = -1;
|
|
b->bTextXSubOffSet = 0;
|
|
b->bTextYSubOffSet = 0;
|
|
b->fShiftText = TRUE;
|
|
}
|
|
|
|
void RemoveIconFromButton( INT32 iButtonID )
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
//Clear icon
|
|
b->iIconID = -1;
|
|
b->usIconIndex = -1;
|
|
b->bIconXOffset = -1;
|
|
b->bIconYOffset = -1;
|
|
b->fShiftImage = TRUE;
|
|
}
|
|
|
|
void AllowDisabledButtonFastHelp( INT32 iButtonID, BOOLEAN fAllow )
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS );
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
|
|
b->Area.uiFlags |= MSYS_ALLOW_DISABLED_FASTHELP;
|
|
}
|
|
|
|
//=============================================================================
|
|
// SetButtonFastHelpText
|
|
//
|
|
// Set the text that will be displayed as the FastHelp
|
|
//
|
|
void SetButtonFastHelpText(INT32 iButton, STR16 Text)
|
|
{
|
|
GUI_BUTTON *b;
|
|
if(iButton<0 || iButton>MAX_BUTTONS)
|
|
return;
|
|
b = ButtonList[iButton];
|
|
AssertMsg( b, "Called SetButtonFastHelpText() with a non-existant button." );
|
|
SetRegionFastHelpText( &b->Area, Text );
|
|
}
|
|
|
|
void SetBtnHelpEndCallback( INT32 iButton, MOUSE_HELPTEXT_DONE_CALLBACK CallbackFxn )
|
|
{
|
|
GUI_BUTTON *b;
|
|
if(iButton<0 || iButton>MAX_BUTTONS)
|
|
return;
|
|
b = ButtonList[iButton];
|
|
AssertMsg( b, "Called SetBtnHelpEndCallback() with a non-existant button." );
|
|
|
|
SetRegionHelpEndCallback( &b->Area, CallbackFxn );
|
|
}
|
|
|
|
//=============================================================================
|
|
// QuickButtonCallbackMMove
|
|
//
|
|
// Dispatches all button callbacks for mouse movement. This function gets
|
|
// called by the Mouse System. *DO NOT CALL DIRECTLY*
|
|
//
|
|
void QuickButtonCallbackMMove(MOUSE_REGION *reg,INT32 reason)
|
|
{
|
|
GUI_BUTTON *b;
|
|
INT32 iButtonID;
|
|
|
|
|
|
Assert(reg != NULL);
|
|
|
|
iButtonID = MSYS_GetRegionUserData(reg,0);
|
|
|
|
sprintf( str, "QuickButtonCallbackMMove: Mouse Region #%d (%d,%d to %d,%d) has invalid buttonID %d",
|
|
reg->IDNumber, reg->RegionTopLeftX, reg->RegionTopLeftY, reg->RegionBottomRightX, reg->RegionBottomRightY, iButtonID );
|
|
|
|
AssertMsg( iButtonID >= 0, str );
|
|
AssertMsg( iButtonID < MAX_BUTTONS, str );
|
|
|
|
b = ButtonList[ iButtonID ];
|
|
|
|
AssertMsg( b != NULL, str );
|
|
|
|
if( !b )
|
|
return; //This is getting called when Adding new regions...
|
|
|
|
|
|
if( b->uiFlags & BUTTON_ENABLED &&
|
|
reason & (MSYS_CALLBACK_REASON_LOST_MOUSE | MSYS_CALLBACK_REASON_GAIN_MOUSE) )
|
|
{
|
|
b->uiFlags |= BUTTON_DIRTY;
|
|
}
|
|
|
|
// Mouse moved on the button, so reset it's timer to maximum.
|
|
if( b->Area.uiFlags & MSYS_CALLBACK_REASON_GAIN_MOUSE )
|
|
{
|
|
//check for sound playing stuff
|
|
if( b->ubSoundSchemeID )
|
|
{
|
|
if( &b->Area == MSYS_PrevRegion && !gpAnchoredButton )
|
|
{
|
|
if( b->uiFlags & BUTTON_ENABLED )
|
|
{
|
|
PlayButtonSound( iButtonID, BUTTON_SOUND_MOVED_ONTO );
|
|
}
|
|
else
|
|
{
|
|
PlayButtonSound( iButtonID, BUTTON_SOUND_DISABLED_MOVED_ONTO );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//Check if we should play a sound
|
|
if( b->ubSoundSchemeID )
|
|
{
|
|
if( b->uiFlags & BUTTON_ENABLED )
|
|
{
|
|
if( &b->Area == MSYS_PrevRegion && !gpAnchoredButton )
|
|
{
|
|
PlayButtonSound( iButtonID, BUTTON_SOUND_MOVED_OFF_OF );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
PlayButtonSound( iButtonID, BUTTON_SOUND_DISABLED_MOVED_OFF_OF );
|
|
}
|
|
}
|
|
}
|
|
|
|
// ATE: New stuff for toggle buttons that work with new Win95 paridigm
|
|
if ( ( b->uiFlags & BUTTON_NEWTOGGLE ) )
|
|
{
|
|
if(reason & MSYS_CALLBACK_REASON_LOST_MOUSE )
|
|
{
|
|
if ( b->ubToggleButtonActivated )
|
|
{
|
|
b->ubToggleButtonActivated = FALSE;
|
|
|
|
if ( !b->ubToggleButtonOldState )
|
|
{
|
|
b->uiFlags &= (~BUTTON_CLICKED_ON );
|
|
}
|
|
else
|
|
{
|
|
b->uiFlags |= BUTTON_CLICKED_ON;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// If this button is enabled and there is a callback function associated with it,
|
|
// call the callback function.
|
|
if((b->uiFlags & BUTTON_ENABLED) && (b->uiFlags & BUTTON_MOVE_CALLBACK))
|
|
(b->MoveCallback)(b,reason);
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// QuickButtonCallbackMButn
|
|
//
|
|
// Dispatches all button callbacks for button presses. This function is
|
|
// called by the Mouse System. *DO NOT CALL DIRECTLY*
|
|
//
|
|
void QuickButtonCallbackMButn( MOUSE_REGION *reg, INT32 reason )
|
|
{
|
|
GUI_BUTTON *b;
|
|
INT32 iButtonID;
|
|
BOOLEAN MouseBtnDown;
|
|
BOOLEAN StateBefore,StateAfter;
|
|
|
|
|
|
Assert(reg != NULL);
|
|
|
|
iButtonID = MSYS_GetRegionUserData(reg,0);
|
|
|
|
sprintf( str, "QuickButtonCallbackMButn: Mouse Region #%d (%d,%d to %d,%d) has invalid buttonID %d",
|
|
reg->IDNumber, reg->RegionTopLeftX, reg->RegionTopLeftY, reg->RegionBottomRightX, reg->RegionBottomRightY, iButtonID );
|
|
|
|
AssertMsg( iButtonID >= 0, str );
|
|
AssertMsg( iButtonID < MAX_BUTTONS, str );
|
|
|
|
b = ButtonList[ iButtonID ];
|
|
|
|
AssertMsg( b != NULL, str );
|
|
|
|
if( !b )
|
|
return;
|
|
|
|
|
|
if( reason & (MSYS_CALLBACK_REASON_LBUTTON_DWN | MSYS_CALLBACK_REASON_RBUTTON_DWN) )
|
|
MouseBtnDown = TRUE;
|
|
else
|
|
MouseBtnDown = FALSE;
|
|
|
|
StateBefore = (b->uiFlags & BUTTON_CLICKED_ON) ? (TRUE) : (FALSE);
|
|
|
|
// ATE: New stuff for toggle buttons that work with new Win95 paridigm
|
|
if( b->uiFlags & BUTTON_NEWTOGGLE && b->uiFlags & BUTTON_ENABLED )
|
|
{
|
|
if(reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
|
|
{
|
|
if ( !b->ubToggleButtonActivated )
|
|
{
|
|
if ( !(b->uiFlags & BUTTON_CLICKED_ON ) )
|
|
{
|
|
b->ubToggleButtonOldState = FALSE;
|
|
b->uiFlags |= BUTTON_CLICKED_ON;
|
|
}
|
|
else
|
|
{
|
|
b->ubToggleButtonOldState = TRUE;
|
|
b->uiFlags &= (~BUTTON_CLICKED_ON);
|
|
}
|
|
b->ubToggleButtonActivated = TRUE;
|
|
}
|
|
}
|
|
else if (reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
|
|
{
|
|
b->ubToggleButtonActivated = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
//Kris:
|
|
//Set the anchored button incase the user moves mouse off region while still holding
|
|
//down the button, but only if the button is up. In Win95, buttons that are already
|
|
//down, and anchored never change state, unless you release the mouse in the button area.
|
|
|
|
if( b->MoveCallback == DEFAULT_MOVE_CALLBACK && b->uiFlags & BUTTON_ENABLED )
|
|
{
|
|
if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
|
|
{
|
|
gpAnchoredButton = b;
|
|
gfAnchoredState = StateBefore;
|
|
b->uiFlags |= BUTTON_CLICKED_ON;
|
|
}
|
|
else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP && b->uiFlags & BUTTON_NO_TOGGLE )
|
|
{
|
|
b->uiFlags &= (~BUTTON_CLICKED_ON);
|
|
}
|
|
}
|
|
else if( b->uiFlags & BUTTON_CHECKBOX && b->uiFlags & BUTTON_ENABLED )//dnl ch77 131113
|
|
{
|
|
if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
|
|
{ //the check box button gets anchored, though it doesn't actually use the anchoring move callback.
|
|
//The effect is different, we don't want to toggle the button state, but we do want to anchor this
|
|
//button so that we don't effect any other buttons while we move the mouse around in anchor mode.
|
|
gpAnchoredButton = b;
|
|
gfAnchoredState = StateBefore;
|
|
|
|
//Trick the before state of the button to be different so the sound will play properly as checkbox buttons
|
|
//are processed differently.
|
|
StateBefore = (b->uiFlags & BUTTON_CLICKED_ON) ? FALSE : TRUE;
|
|
StateAfter = !StateBefore;
|
|
}
|
|
else if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
|
|
{
|
|
b->uiFlags ^= BUTTON_CLICKED_ON; //toggle the checkbox state upon release inside button area.
|
|
//Trick the before state of the button to be different so the sound will play properly as checkbox buttons
|
|
//are processed differently.
|
|
StateBefore = (b->uiFlags & BUTTON_CLICKED_ON) ? FALSE : TRUE;
|
|
StateAfter = !StateBefore;
|
|
}
|
|
}
|
|
|
|
// Should we play a sound if clicked on while disabled?
|
|
if( b->ubSoundSchemeID && !(b->uiFlags & BUTTON_ENABLED) && MouseBtnDown )
|
|
{
|
|
PlayButtonSound( iButtonID, BUTTON_SOUND_DISABLED_CLICK );
|
|
}
|
|
|
|
// If this button is disabled, and no callbacks allowed when disabled
|
|
// callback
|
|
if(!(b->uiFlags & BUTTON_ENABLED) && !(b->uiFlags & BUTTON_ALLOW_DISABLED_CALLBACK))
|
|
return;
|
|
|
|
// Button not enabled but allowed to use callback, then do that!
|
|
if(!(b->uiFlags & BUTTON_ENABLED) && (b->uiFlags & BUTTON_ALLOW_DISABLED_CALLBACK))
|
|
{
|
|
if( b->uiFlags & BUTTON_CLICK_CALLBACK )
|
|
{
|
|
(b->ClickCallback)(b, reason | BUTTON_DISABLED_CALLBACK );
|
|
}
|
|
return;
|
|
}
|
|
|
|
// If there is a callback function with this button, call it
|
|
if(b->uiFlags & BUTTON_CLICK_CALLBACK)
|
|
{
|
|
//Kris: January 6, 1998
|
|
//Added these checks to avoid a case where it was possible to process a leftbuttonup message when
|
|
//the button wasn't anchored, and should have been.
|
|
gfDelayButtonDeletion = TRUE;
|
|
if( !(reason & MSYS_CALLBACK_REASON_LBUTTON_UP) || b->MoveCallback != DEFAULT_MOVE_CALLBACK ||
|
|
b->MoveCallback == DEFAULT_MOVE_CALLBACK && gpPrevAnchoredButton == b )
|
|
(b->ClickCallback)(b,reason);
|
|
gfDelayButtonDeletion = FALSE;
|
|
}
|
|
else if((reason & MSYS_CALLBACK_REASON_LBUTTON_DWN) && !(b->uiFlags & BUTTON_IGNORE_CLICKS))
|
|
{
|
|
// Otherwise, do default action with this button.
|
|
b->uiFlags^=BUTTON_CLICKED_ON;
|
|
}
|
|
|
|
if( b->uiFlags & BUTTON_CHECKBOX )
|
|
{
|
|
StateAfter = (b->uiFlags & BUTTON_CLICKED_ON) ? (TRUE) : (FALSE);
|
|
}
|
|
else
|
|
{
|
|
StateAfter = !( reason & MSYS_CALLBACK_REASON_LBUTTON_UP );
|
|
}
|
|
|
|
// Play sounds for this enabled button (disabled sounds have already been done)
|
|
if( b->ubSoundSchemeID && b->uiFlags & BUTTON_ENABLED )
|
|
{
|
|
if( reason & MSYS_CALLBACK_REASON_LBUTTON_UP )
|
|
{
|
|
if( b->ubSoundSchemeID && StateBefore && !StateAfter )
|
|
{
|
|
PlayButtonSound( iButtonID, BUTTON_SOUND_CLICKED_OFF );
|
|
}
|
|
}
|
|
else if( reason & MSYS_CALLBACK_REASON_LBUTTON_DWN )
|
|
{
|
|
if( b->ubSoundSchemeID && !StateBefore && StateAfter)
|
|
{
|
|
PlayButtonSound( iButtonID, BUTTON_SOUND_CLICKED_ON );
|
|
}
|
|
}
|
|
}
|
|
|
|
if( StateBefore != StateAfter )
|
|
{
|
|
InvalidateRegion(b->Area.RegionTopLeftX, b->Area.RegionTopLeftY, b->Area.RegionBottomRightX, b->Area.RegionBottomRightY);
|
|
}
|
|
|
|
if( gfPendingButtonDeletion )
|
|
{
|
|
RemoveButtonsMarkedForDeletion();
|
|
}
|
|
}
|
|
|
|
void RenderButtons(void)
|
|
{
|
|
INT32 iButtonID;
|
|
BOOLEAN fOldButtonDown, fOldEnabled;
|
|
GUI_BUTTON *b;
|
|
|
|
SaveFontSettings();
|
|
for(iButtonID=0;iButtonID<MAX_BUTTONS;iButtonID++)
|
|
{
|
|
// If the button exists, and it's not owned by another object, draw it
|
|
//Kris: and make sure that the button isn't hidden.
|
|
b = ButtonList[iButtonID];
|
|
if( b && b->Area.uiFlags & MSYS_REGION_ENABLED )
|
|
{
|
|
// Check for buttonchanged status
|
|
fOldButtonDown = (BOOLEAN)(b->uiFlags & BUTTON_CLICKED_ON);
|
|
|
|
if ( fOldButtonDown != ( b->uiOldFlags & BUTTON_CLICKED_ON ) )
|
|
{
|
|
//Something is different, set dirty!
|
|
b->uiFlags |= BUTTON_DIRTY;
|
|
}
|
|
|
|
// Check for button dirty flags
|
|
fOldEnabled = (BOOLEAN)(b->uiFlags & BUTTON_ENABLED);
|
|
|
|
if ( fOldEnabled != ( b->uiOldFlags & BUTTON_ENABLED ) )
|
|
{
|
|
//Something is different, set dirty!
|
|
b->uiFlags |= BUTTON_DIRTY;
|
|
}
|
|
|
|
// If we ABSOLUTELY want to render every frame....
|
|
if ( b->uiFlags & BUTTON_SAVEBACKGROUND )
|
|
{
|
|
b->uiFlags |= BUTTON_DIRTY;
|
|
}
|
|
|
|
// Set old flags
|
|
b->uiOldFlags = b->uiFlags;
|
|
|
|
if ( b->uiFlags & BUTTON_FORCE_UNDIRTY )
|
|
{
|
|
b->uiFlags &= ~( BUTTON_DIRTY );
|
|
b->uiFlags &= ~( BUTTON_FORCE_UNDIRTY );
|
|
}
|
|
|
|
// Check if we need to update!
|
|
if ( b->uiFlags & BUTTON_DIRTY )
|
|
{
|
|
// Turn off dirty flag
|
|
b->uiFlags &= (~BUTTON_DIRTY);
|
|
DrawButtonFromPtr(b);
|
|
|
|
InvalidateRegion(b->Area.RegionTopLeftX, b->Area.RegionTopLeftY, b->Area.RegionBottomRightX, b->Area.RegionBottomRightY);
|
|
//#else
|
|
// InvalidateRegion(b->Area.RegionTopLeftX, b->Area.RegionTopLeftY, b->Area.RegionBottomRightX, b->Area.RegionBottomRightY, FALSE);
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
// check if we want to render 1 frame later?
|
|
if( ( fPausedMarkButtonsDirtyFlag == TRUE ) && ( fDisableHelpTextRestoreFlag == FALSE ) )
|
|
{
|
|
fPausedMarkButtonsDirtyFlag = FALSE;
|
|
MarkButtonsDirty( );
|
|
}
|
|
|
|
RestoreFontSettings();
|
|
}
|
|
|
|
//*****************************************************************************
|
|
// MarkAButtonDirty
|
|
//
|
|
void MarkAButtonDirty( INT32 iButtonNum )
|
|
{
|
|
// surgical dirtying->marks a user specified button dirty, without dirty the whole lot of them
|
|
|
|
|
|
// If the button exists, and it's not owned by another object, draw it
|
|
if( ButtonList[ iButtonNum ] )
|
|
{
|
|
// Turn on dirty flag
|
|
ButtonList[ iButtonNum ]->uiFlags |= BUTTON_DIRTY;
|
|
}
|
|
|
|
}
|
|
|
|
//=============================================================================
|
|
// MarkButtonsDirty
|
|
//
|
|
void MarkButtonsDirty( void )
|
|
{
|
|
INT32 x;
|
|
for(x=0;x<MAX_BUTTONS;x++)
|
|
{
|
|
// If the button exists, and it's not owned by another object, draw it
|
|
if( ButtonList[x] )
|
|
{
|
|
// Turn on dirty flag
|
|
ButtonList[x]->uiFlags |= BUTTON_DIRTY;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void UnMarkButtonDirty( INT32 iButtonIndex )
|
|
{
|
|
if ( ButtonList[ iButtonIndex ] )
|
|
{
|
|
ButtonList[ iButtonIndex ]->uiFlags &= ~( BUTTON_DIRTY );
|
|
}
|
|
}
|
|
|
|
void UnmarkButtonsDirty( void )
|
|
{
|
|
INT32 x;
|
|
for(x=0;x<MAX_BUTTONS;x++)
|
|
{
|
|
// If the button exists, and it's not owned by another object, draw it
|
|
if( ButtonList[x] )
|
|
{
|
|
UnMarkButtonDirty( x );
|
|
}
|
|
}
|
|
}
|
|
|
|
void ForceButtonUnDirty( INT32 iButtonIndex )
|
|
{
|
|
ButtonList[ iButtonIndex ]->uiFlags &= ~( BUTTON_DIRTY );
|
|
ButtonList[ iButtonIndex ]->uiFlags |= BUTTON_FORCE_UNDIRTY;
|
|
}
|
|
|
|
//=============================================================================
|
|
// PauseMarkButtonsDirty
|
|
//
|
|
|
|
void PausedMarkButtonsDirty( void )
|
|
{
|
|
// set flag for frame after the next rendering of buttons
|
|
fPausedMarkButtonsDirtyFlag = TRUE;
|
|
|
|
return;
|
|
}
|
|
|
|
//=============================================================================
|
|
// DrawButton
|
|
//
|
|
// Draws a single button on the screen.
|
|
//
|
|
BOOLEAN DrawButton(INT32 iButtonID )
|
|
{
|
|
// Fail if button handle out of range
|
|
if( iButtonID < 0 || iButtonID > MAX_BUTTONS )
|
|
return FALSE;
|
|
|
|
// Fail if button handle is invalid
|
|
if( !ButtonList[ iButtonID ] )
|
|
return FALSE;
|
|
|
|
if( ButtonList[ iButtonID ]->string )
|
|
SaveFontSettings();
|
|
// Draw this button
|
|
if( ButtonList[ iButtonID ]->Area.uiFlags & MSYS_REGION_ENABLED )
|
|
{
|
|
DrawButtonFromPtr( ButtonList[ iButtonID ] );
|
|
}
|
|
|
|
if( ButtonList[ iButtonID ]->string )
|
|
RestoreFontSettings();
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// DrawButtonFromPtr
|
|
//
|
|
// Given a pointer to a GUI_BUTTON structure, draws the button on the
|
|
// screen.
|
|
//
|
|
void DrawButtonFromPtr(GUI_BUTTON *b)
|
|
{
|
|
Assert( b );
|
|
// Draw the appropriate button according to button type
|
|
gbDisabledButtonStyle = DISABLED_STYLE_NONE;
|
|
switch(b->uiFlags & BUTTON_TYPES)
|
|
{
|
|
case BUTTON_QUICK:
|
|
DrawQuickButton(b);
|
|
break;
|
|
case BUTTON_GENERIC:
|
|
DrawGenericButton(b);
|
|
break;
|
|
case BUTTON_HOT_SPOT:
|
|
if(b->uiFlags & BUTTON_NO_TOGGLE)
|
|
b->uiFlags &= (~BUTTON_CLICKED_ON);
|
|
return; //hotspots don't have text, but if you want to, change this to a break!
|
|
case BUTTON_CHECKBOX:
|
|
DrawCheckBoxButton(b);
|
|
break;
|
|
}
|
|
//If button has an icon, overlay it on current button.
|
|
if( b->iIconID != -1 )
|
|
DrawIconOnButton( b );
|
|
//If button has text, draw it now
|
|
if( b->string )
|
|
DrawTextOnButton( b );
|
|
//If the button is disabled, and a style has been calculated, then
|
|
//draw the style last.
|
|
switch( gbDisabledButtonStyle )
|
|
{
|
|
case DISABLED_STYLE_HATCHED:
|
|
DrawHatchOnButton( b );
|
|
break;
|
|
case DISABLED_STYLE_SHADED:
|
|
DrawShadeOnButton( b );
|
|
break;
|
|
}
|
|
if( b->bDefaultStatus )
|
|
{
|
|
DrawDefaultOnButton( b );
|
|
}
|
|
}
|
|
|
|
//=============================================================================
|
|
// DrawQuickButton
|
|
//
|
|
// Draws a QuickButton type button on the screen.
|
|
//
|
|
void DrawQuickButton(GUI_BUTTON *b)
|
|
{
|
|
INT32 UseImage;
|
|
UseImage=0;
|
|
// Is button Enabled, or diabled but no "Grayed" image associated with this QuickButton?
|
|
if(b->uiFlags & BUTTON_ENABLED )
|
|
{
|
|
// Is the button's state ON?
|
|
if(b->uiFlags & BUTTON_CLICKED_ON)
|
|
{
|
|
// Is the mouse over this area, and we have a hilite image?
|
|
if((b->Area.uiFlags & MSYS_MOUSE_IN_AREA) && gfRenderHilights &&
|
|
(ButtonPictures[b->ImageNum].OnHilite != -1))
|
|
UseImage = ButtonPictures[b->ImageNum].OnHilite; // Use On-Hilite image
|
|
else if(ButtonPictures[b->ImageNum].OnNormal != -1)
|
|
UseImage = ButtonPictures[b->ImageNum].OnNormal; // Use On-Normal image
|
|
}
|
|
else
|
|
{
|
|
// Is the mouse over the button, and do we have hilite image?
|
|
if((b->Area.uiFlags & MSYS_MOUSE_IN_AREA) && gfRenderHilights &&
|
|
(ButtonPictures[b->ImageNum].OffHilite != -1))
|
|
UseImage = ButtonPictures[b->ImageNum].OffHilite; // Use Off-Hilite image
|
|
else if(ButtonPictures[b->ImageNum].OffNormal != -1)
|
|
UseImage = ButtonPictures[b->ImageNum].OffNormal; // Use Off-Normal image
|
|
}
|
|
}
|
|
else if( ButtonPictures[b->ImageNum].Grayed != -1)
|
|
{ // Button is diabled so use the "Grayed-out" image
|
|
UseImage = ButtonPictures[b->ImageNum].Grayed;
|
|
}
|
|
else
|
|
{
|
|
UseImage = ButtonPictures[b->ImageNum].OffNormal;
|
|
switch( b->bDisabledStyle )
|
|
{
|
|
case DISABLED_STYLE_DEFAULT:
|
|
gbDisabledButtonStyle = b->string ? DISABLED_STYLE_SHADED : DISABLED_STYLE_HATCHED;
|
|
break;
|
|
case DISABLED_STYLE_HATCHED:
|
|
case DISABLED_STYLE_SHADED:
|
|
gbDisabledButtonStyle = b->bDisabledStyle;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Display the button image
|
|
BltVideoObject(ButtonDestBuffer, ButtonPictures[b->ImageNum].vobj,
|
|
(UINT16)UseImage, b->XLoc, b->YLoc,
|
|
VO_BLT_SRCTRANSPARENCY, NULL);
|
|
}
|
|
|
|
void DrawHatchOnButton( GUI_BUTTON *b )
|
|
{
|
|
UINT8 *pDestBuf;
|
|
UINT32 uiDestPitchBYTES;
|
|
SGPRect ClipRect;
|
|
ClipRect.iLeft = b->Area.RegionTopLeftX;
|
|
ClipRect.iRight = b->Area.RegionBottomRightX - 1;
|
|
ClipRect.iTop = b->Area.RegionTopLeftY;
|
|
ClipRect.iBottom = b->Area.RegionBottomRightY - 1;
|
|
pDestBuf = LockVideoSurface( ButtonDestBuffer, &uiDestPitchBYTES );
|
|
Blt16BPPBufferHatchRect( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect );
|
|
UnLockVideoSurface( ButtonDestBuffer );
|
|
}
|
|
|
|
void DrawShadeOnButton( GUI_BUTTON *b )
|
|
{
|
|
UINT8 *pDestBuf;
|
|
UINT32 uiDestPitchBYTES;
|
|
SGPRect ClipRect;
|
|
ClipRect.iLeft = b->Area.RegionTopLeftX;
|
|
ClipRect.iRight = b->Area.RegionBottomRightX-1;
|
|
ClipRect.iTop = b->Area.RegionTopLeftY;
|
|
ClipRect.iBottom = b->Area.RegionBottomRightY-1;
|
|
pDestBuf = LockVideoSurface( ButtonDestBuffer, &uiDestPitchBYTES );
|
|
Blt16BPPBufferShadowRect( (UINT16*)pDestBuf, uiDestPitchBYTES, &ClipRect );
|
|
UnLockVideoSurface( ButtonDestBuffer );
|
|
}
|
|
|
|
void DrawDefaultOnButton( GUI_BUTTON *b )
|
|
{
|
|
UINT8 *pDestBuf;
|
|
UINT32 uiDestPitchBYTES;
|
|
pDestBuf = LockVideoSurface( ButtonDestBuffer, &uiDestPitchBYTES );
|
|
SetClippingRegionAndImageWidth( uiDestPitchBYTES, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
|
|
if( b->bDefaultStatus == DEFAULT_STATUS_DARKBORDER || b->bDefaultStatus == DEFAULT_STATUS_WINDOWS95 )
|
|
{
|
|
//left (one thick)
|
|
LineDraw( TRUE, b->Area.RegionTopLeftX-1, b->Area.RegionTopLeftY-1, b->Area.RegionTopLeftX-1, b->Area.RegionBottomRightY+1, 0, pDestBuf );
|
|
//top (one thick)
|
|
LineDraw( TRUE, b->Area.RegionTopLeftX-1, b->Area.RegionTopLeftY-1, b->Area.RegionBottomRightX+1, b->Area.RegionTopLeftY-1, 0, pDestBuf );
|
|
//right (two thick)
|
|
LineDraw( TRUE, b->Area.RegionBottomRightX, b->Area.RegionTopLeftY-1, b->Area.RegionBottomRightX, b->Area.RegionBottomRightY+1, 0, pDestBuf );
|
|
LineDraw( TRUE, b->Area.RegionBottomRightX+1, b->Area.RegionTopLeftY-1, b->Area.RegionBottomRightX+1, b->Area.RegionBottomRightY+1, 0, pDestBuf );
|
|
//bottom (two thick)
|
|
LineDraw( TRUE, b->Area.RegionTopLeftX-1, b->Area.RegionBottomRightY, b->Area.RegionBottomRightX+1, b->Area.RegionBottomRightY, 0, pDestBuf );
|
|
LineDraw( TRUE, b->Area.RegionTopLeftX-1, b->Area.RegionBottomRightY+1, b->Area.RegionBottomRightX+1, b->Area.RegionBottomRightY+1, 0, pDestBuf );
|
|
InvalidateRegion( b->Area.RegionTopLeftX-1, b->Area.RegionTopLeftY-1, b->Area.RegionBottomRightX+1, b->Area.RegionBottomRightY+1 );
|
|
}
|
|
if( b->bDefaultStatus == DEFAULT_STATUS_DOTTEDINTERIOR || b->bDefaultStatus == DEFAULT_STATUS_WINDOWS95 )
|
|
{ //Draw an internal dotted rectangle.
|
|
|
|
}
|
|
UnLockVideoSurface( ButtonDestBuffer );
|
|
}
|
|
|
|
void DrawCheckBoxButtonOn( INT32 iButtonID )
|
|
{
|
|
GUI_BUTTON *b;
|
|
BOOLEAN fLeftButtonState = gfLeftButtonState;
|
|
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS);
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
|
|
gfLeftButtonState = TRUE;
|
|
b->Area.uiFlags |= MSYS_MOUSE_IN_AREA;
|
|
|
|
DrawButton( iButtonID );
|
|
|
|
gfLeftButtonState = fLeftButtonState;
|
|
}
|
|
|
|
void DrawCheckBoxButtonOff( INT32 iButtonID )
|
|
{
|
|
GUI_BUTTON *b;
|
|
BOOLEAN fLeftButtonState = gfLeftButtonState;
|
|
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS);
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
|
|
gfLeftButtonState = FALSE;
|
|
b->Area.uiFlags |= MSYS_MOUSE_IN_AREA;
|
|
|
|
DrawButton( iButtonID );
|
|
|
|
gfLeftButtonState = fLeftButtonState;
|
|
}
|
|
|
|
|
|
void DrawCheckBoxButton( GUI_BUTTON *b )
|
|
{
|
|
INT32 UseImage;
|
|
|
|
UseImage=0;
|
|
// Is button Enabled, or diabled but no "Grayed" image associated with this QuickButton?
|
|
if( b->uiFlags & BUTTON_ENABLED )
|
|
{
|
|
// Is the button's state ON?
|
|
if(b->uiFlags & BUTTON_CLICKED_ON)
|
|
{
|
|
// Is the mouse over this area, and we have a hilite image?
|
|
if( b->Area.uiFlags & MSYS_MOUSE_IN_AREA && gfRenderHilights &&
|
|
gfLeftButtonState &&
|
|
ButtonPictures[b->ImageNum].OnHilite != -1 )
|
|
UseImage = ButtonPictures[b->ImageNum].OnHilite; // Use On-Hilite image
|
|
else if(ButtonPictures[b->ImageNum].OnNormal != -1)
|
|
UseImage = ButtonPictures[b->ImageNum].OnNormal; // Use On-Normal image
|
|
}
|
|
else
|
|
{
|
|
// Is the mouse over the button, and do we have hilite image?
|
|
if( b->Area.uiFlags & MSYS_MOUSE_IN_AREA && gfRenderHilights &&
|
|
gfLeftButtonState &&
|
|
ButtonPictures[b->ImageNum].OffHilite != -1 )
|
|
UseImage = ButtonPictures[b->ImageNum].OffHilite; // Use Off-Hilite image
|
|
else if(ButtonPictures[b->ImageNum].OffNormal != -1)
|
|
UseImage = ButtonPictures[b->ImageNum].OffNormal; // Use Off-Normal image
|
|
}
|
|
}
|
|
else if( ButtonPictures[b->ImageNum].Grayed != -1 )
|
|
{ // Button is disabled so use the "Grayed-out" image
|
|
UseImage = ButtonPictures[b->ImageNum].Grayed;
|
|
}
|
|
else //use the disabled style
|
|
{
|
|
if( b->uiFlags & BUTTON_CLICKED_ON )
|
|
UseImage = ButtonPictures[b->ImageNum].OnHilite;
|
|
else
|
|
UseImage = ButtonPictures[b->ImageNum].OffHilite;
|
|
switch( b->bDisabledStyle )
|
|
{
|
|
case DISABLED_STYLE_DEFAULT:
|
|
gbDisabledButtonStyle = DISABLED_STYLE_HATCHED;
|
|
break;
|
|
case DISABLED_STYLE_HATCHED:
|
|
case DISABLED_STYLE_SHADED:
|
|
gbDisabledButtonStyle = b->bDisabledStyle;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Display the button image
|
|
BltVideoObject(ButtonDestBuffer, ButtonPictures[b->ImageNum].vobj,
|
|
(UINT16)UseImage, b->XLoc, b->YLoc,
|
|
VO_BLT_SRCTRANSPARENCY, NULL);
|
|
}
|
|
|
|
void DrawIconOnButton(GUI_BUTTON *b)
|
|
{
|
|
INT32 xp,yp,width,height,IconX,IconY;
|
|
INT32 IconW,IconH;
|
|
SGPRect NewClip,OldClip;
|
|
ETRLEObject *pTrav;
|
|
HVOBJECT hvObject = NULL;
|
|
|
|
// If there's an actual icon on this button, try to show it.
|
|
if(b->iIconID >= 0)
|
|
{
|
|
// Get width and height of button area
|
|
width = b->Area.RegionBottomRightX - b->Area.RegionTopLeftX;
|
|
height = b->Area.RegionBottomRightY - b->Area.RegionTopLeftY;
|
|
|
|
// Compute viewable area (inside borders)
|
|
NewClip.iLeft = b->XLoc + 3;
|
|
NewClip.iRight = b->XLoc + width - 3;
|
|
NewClip.iTop = b->YLoc + 2;
|
|
NewClip.iBottom = b->YLoc + height - 2;
|
|
|
|
// Get Icon's blit start coordinates
|
|
IconX = NewClip.iLeft;
|
|
IconY = NewClip.iTop;
|
|
|
|
// Get current clip area
|
|
GetClippingRect(&OldClip);
|
|
|
|
// Clip button's viewable area coords to screen
|
|
if(NewClip.iLeft < OldClip.iLeft)
|
|
NewClip.iLeft = OldClip.iLeft;
|
|
|
|
// Is button right off the right side of the screen?
|
|
if(NewClip.iLeft > OldClip.iRight)
|
|
return;
|
|
|
|
if(NewClip.iRight > OldClip.iRight)
|
|
NewClip.iRight = OldClip.iRight;
|
|
|
|
// Is button completely off the left side of the screen?
|
|
if(NewClip.iRight < OldClip.iLeft)
|
|
return;
|
|
|
|
if(NewClip.iTop < OldClip.iTop)
|
|
NewClip.iTop = OldClip.iTop;
|
|
|
|
// Are we right off the bottom of the screen?
|
|
if(NewClip.iTop > OldClip.iBottom)
|
|
return;
|
|
|
|
if(NewClip.iBottom > OldClip.iBottom)
|
|
NewClip.iBottom = OldClip.iBottom;
|
|
|
|
// Are we off the top?
|
|
if(NewClip.iBottom < OldClip.iTop)
|
|
return;
|
|
|
|
// Did we clip the viewable area out of existance?
|
|
if((NewClip.iRight <= NewClip.iLeft) || (NewClip.iBottom <= NewClip.iTop))
|
|
return;
|
|
|
|
// Get the width and height of the icon itself
|
|
if( b->uiFlags & BUTTON_GENERIC )
|
|
pTrav = &(GenericButtonIcons[b->iIconID]->pETRLEObject[b->usIconIndex]);
|
|
else
|
|
{
|
|
GetVideoObject( &hvObject, b->iIconID );
|
|
pTrav = &(hvObject->pETRLEObject[b->usIconIndex] );
|
|
}
|
|
IconH = (UINT32)(pTrav->usHeight+pTrav->sOffsetY);
|
|
IconW = (UINT32)(pTrav->usWidth+pTrav->sOffsetX);
|
|
|
|
// Compute coordinates for centering the icon on the button or
|
|
// use the offset system.
|
|
if( b->bIconXOffset == -1 )
|
|
xp = (((width-6)-IconW) / 2) + IconX;
|
|
else
|
|
xp = b->Area.RegionTopLeftX + b->bIconXOffset;
|
|
if( b->bIconYOffset == -1 )
|
|
yp = (((height-4)-IconH) / 2) + IconY;
|
|
else
|
|
yp = b->Area.RegionTopLeftY + b->bIconYOffset;
|
|
|
|
// Was the button clicked on? if so, move the image slightly for the illusion
|
|
// that the image moved into the screen.
|
|
if( b->uiFlags & BUTTON_CLICKED_ON && b->fShiftImage )
|
|
{
|
|
xp++;
|
|
yp++;
|
|
}
|
|
|
|
// Set the clipping rectangle to the viewable area of the button
|
|
SetClippingRect(&NewClip);
|
|
// Blit the icon
|
|
if( b->uiFlags & BUTTON_GENERIC )
|
|
BltVideoObject( ButtonDestBuffer,GenericButtonIcons[b->iIconID], b->usIconIndex, (INT16)xp, (INT16)yp,
|
|
VO_BLT_SRCTRANSPARENCY, NULL);
|
|
else
|
|
BltVideoObject( ButtonDestBuffer, hvObject, b->usIconIndex, (INT16)xp, (INT16)yp,
|
|
VO_BLT_SRCTRANSPARENCY, NULL );
|
|
// Restore previous clip region
|
|
SetClippingRect(&OldClip);
|
|
}
|
|
}
|
|
|
|
|
|
//If a button has text attached to it, then it'll draw it last.
|
|
void DrawTextOnButton(GUI_BUTTON *b)
|
|
{
|
|
INT32 xp,yp,width,height,TextX,TextY;
|
|
SGPRect NewClip,OldClip;
|
|
INT16 sForeColor;
|
|
|
|
// If this button actually has a string to print
|
|
if( b->string )
|
|
{
|
|
// Get the width and height of this button
|
|
width = b->Area.RegionBottomRightX - b->Area.RegionTopLeftX;
|
|
height = b->Area.RegionBottomRightY - b->Area.RegionTopLeftY;
|
|
|
|
// Compute the viewable area on this button
|
|
NewClip.iLeft = b->XLoc + 3;
|
|
NewClip.iRight = b->XLoc + width - 3;
|
|
NewClip.iTop = b->YLoc + 2;
|
|
NewClip.iBottom = b->YLoc + height - 2;
|
|
|
|
// Get the starting coordinates to print
|
|
TextX = NewClip.iLeft;
|
|
TextY = NewClip.iTop;
|
|
|
|
// Get the current clipping area
|
|
GetClippingRect(&OldClip);
|
|
|
|
// Clip the button's viewable area to the screen
|
|
if(NewClip.iLeft < OldClip.iLeft)
|
|
NewClip.iLeft = OldClip.iLeft;
|
|
|
|
// Are we off hte right side?
|
|
if(NewClip.iLeft > OldClip.iRight)
|
|
return;
|
|
|
|
if(NewClip.iRight > OldClip.iRight)
|
|
NewClip.iRight = OldClip.iRight;
|
|
|
|
// Are we off the left side?
|
|
if(NewClip.iRight < OldClip.iLeft)
|
|
return;
|
|
|
|
if(NewClip.iTop < OldClip.iTop)
|
|
NewClip.iTop = OldClip.iTop;
|
|
|
|
// Are we off the bottom of the screen?
|
|
if(NewClip.iTop > OldClip.iBottom)
|
|
return;
|
|
|
|
if(NewClip.iBottom > OldClip.iBottom)
|
|
NewClip.iBottom = OldClip.iBottom;
|
|
|
|
// Are we off the top?
|
|
if(NewClip.iBottom < OldClip.iTop)
|
|
return;
|
|
|
|
// Did we clip the viewable area out of existance?
|
|
if((NewClip.iRight <= NewClip.iLeft) || (NewClip.iBottom <= NewClip.iTop))
|
|
return;
|
|
|
|
// Set the font printing settings to the buttons viewable area
|
|
SetFontDestBuffer(ButtonDestBuffer, NewClip.iLeft,
|
|
NewClip.iTop, NewClip.iRight,
|
|
NewClip.iBottom, FALSE);
|
|
|
|
// Compute the coordinates to center the text
|
|
if( b->bTextYOffset == -1 )
|
|
yp = (((height) - GetFontHeight(b->usFont)) / 2) + TextY - 1;
|
|
else
|
|
yp = b->Area.RegionTopLeftY + b->bTextYOffset;
|
|
if( b->bTextXOffset == -1 )
|
|
{
|
|
switch( b->bJustification )
|
|
{
|
|
case BUTTON_TEXT_LEFT:
|
|
xp = TextX + 3;
|
|
break;
|
|
case BUTTON_TEXT_RIGHT:
|
|
xp = NewClip.iRight - StringPixLength(b->string, b->usFont) - 3;
|
|
break;
|
|
case BUTTON_TEXT_CENTER:
|
|
default:
|
|
xp = (((width-6)-StringPixLength(b->string,b->usFont)) / 2) + TextX;
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
xp = b->Area.RegionTopLeftX + b->bTextXOffset;
|
|
|
|
// Set the printing font to the button text font
|
|
SetFont(b->usFont);
|
|
|
|
// print the text
|
|
SetFontBackground( FONT_MCOLOR_BLACK );
|
|
SetFontForeground( (UINT8)b->sForeColor );
|
|
sForeColor = b->sForeColor;
|
|
|
|
if( b->sShadowColor != -1 )
|
|
SetFontShadow( (UINT8)b->sShadowColor );
|
|
//Override the colors if necessary.
|
|
if( b->uiFlags & BUTTON_ENABLED && b->Area.uiFlags & MSYS_MOUSE_IN_AREA && b->sForeColorHilited != -1 )
|
|
{
|
|
SetFontForeground( (UINT8)b->sForeColorHilited );
|
|
sForeColor = b->sForeColorHilited;
|
|
}
|
|
else if( b->uiFlags & BUTTON_CLICKED_ON && b->sForeColorDown != -1 )
|
|
{
|
|
SetFontForeground( (UINT8)b->sForeColorDown );
|
|
sForeColor = b->sForeColorDown;
|
|
}
|
|
|
|
if( b->uiFlags & BUTTON_ENABLED && b->Area.uiFlags & MSYS_MOUSE_IN_AREA && b->sShadowColorHilited != -1 )
|
|
{
|
|
SetFontShadow( (UINT8)b->sShadowColorHilited );
|
|
}
|
|
else if( b->uiFlags & BUTTON_CLICKED_ON && b->sShadowColorDown != -1 )
|
|
{
|
|
SetFontShadow( (UINT8)b->sShadowColorDown );
|
|
}
|
|
else if ( b->uiFlags & BUTTON_16BPPCOLOURTEXT )
|
|
{
|
|
SetRGBFontForeground( sForeColor );
|
|
|
|
if ( b->sShadowColor < 1 )
|
|
SetRGBFontShadow( 1 );
|
|
}
|
|
|
|
if( b->uiFlags & BUTTON_CLICKED_ON && b->fShiftText )
|
|
{ // Was the button clicked on? if so, move the text slightly for the illusion
|
|
// that the text moved into the screen.
|
|
xp++;
|
|
yp++;
|
|
}
|
|
if( b->sWrappedWidth != -1 )
|
|
{
|
|
UINT8 bJustified=0;
|
|
switch( b->bJustification )
|
|
{
|
|
case BUTTON_TEXT_LEFT: bJustified = LEFT_JUSTIFIED; break;
|
|
case BUTTON_TEXT_RIGHT: bJustified = RIGHT_JUSTIFIED; break;
|
|
case BUTTON_TEXT_CENTER: bJustified = CENTER_JUSTIFIED; break;
|
|
default: Assert( 0 ); break;
|
|
}
|
|
if( b->bTextXOffset == -1 )
|
|
{
|
|
//Kris:
|
|
//There needs to be recalculation of the start positions based on the
|
|
//justification and the width specified wrapped width. I was drawing a
|
|
//double lined word on the right side of the button to find it drawing way
|
|
//over to the left. I've added the necessary code for the right and center
|
|
//justification.
|
|
yp = b->Area.RegionTopLeftY + 2;
|
|
|
|
switch( b->bJustification )
|
|
{
|
|
case BUTTON_TEXT_RIGHT:
|
|
xp = b->Area.RegionBottomRightX - 3 - b->sWrappedWidth;
|
|
|
|
if( b->fShiftText && b->uiFlags & BUTTON_CLICKED_ON )
|
|
xp++, yp++;
|
|
break;
|
|
case BUTTON_TEXT_CENTER:
|
|
xp = b->Area.RegionTopLeftX + 3 + b->sWrappedWidth/2;
|
|
|
|
if( b->fShiftText && b->uiFlags & BUTTON_CLICKED_ON )
|
|
xp++, yp++;
|
|
break;
|
|
}
|
|
}
|
|
yp+= b->bTextYSubOffSet;
|
|
xp+= b->bTextXSubOffSet;
|
|
DisplayWrappedString((UINT16)xp, (UINT16)yp, b->sWrappedWidth, 1, b->usFont, (UINT8)sForeColor, b->string, FONT_MCOLOR_BLACK, FALSE, bJustified);
|
|
}
|
|
else
|
|
{
|
|
yp+= b->bTextYSubOffSet;
|
|
xp+= b->bTextXSubOffSet;
|
|
mprintf(xp, yp, b->string);
|
|
}
|
|
// Restore the old text printing settings
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//=============================================================================
|
|
// DrawGenericButton
|
|
//
|
|
// This function is called by the DrawIconicButton and DrawTextButton
|
|
// routines to draw the borders and background of the buttons.
|
|
//
|
|
void DrawGenericButton(GUI_BUTTON *b)
|
|
{
|
|
INT32 NumChunksWide,NumChunksHigh,cx,cy,width,height,hremain,wremain;
|
|
INT32 q,ImgNum,ox,oy;
|
|
INT32 iBorderHeight, iBorderWidth;
|
|
HVOBJECT BPic;
|
|
UINT32 uiDestPitchBYTES;
|
|
UINT8 *pDestBuf;
|
|
SGPRect ClipRect;
|
|
ETRLEObject *pTrav;
|
|
|
|
// Select the graphics to use depending on the current state of the button
|
|
if( b->uiFlags & BUTTON_ENABLED )
|
|
{
|
|
if ( !(b->uiFlags & BUTTON_ENABLED) && (GenericButtonGrayed[b->ImageNum]==NULL) )
|
|
BPic = GenericButtonOffNormal[b->ImageNum];
|
|
else if(b->uiFlags & BUTTON_CLICKED_ON)
|
|
{
|
|
if((b->Area.uiFlags & MSYS_MOUSE_IN_AREA) && (GenericButtonOnHilite[b->ImageNum]!=NULL) && gfRenderHilights )
|
|
BPic = GenericButtonOnHilite[b->ImageNum];
|
|
else
|
|
BPic = GenericButtonOnNormal[b->ImageNum];
|
|
}
|
|
else
|
|
{
|
|
if((b->Area.uiFlags & MSYS_MOUSE_IN_AREA) && (GenericButtonOffHilite[b->ImageNum]!=NULL) && gfRenderHilights )
|
|
BPic = GenericButtonOffHilite[b->ImageNum];
|
|
else
|
|
BPic = GenericButtonOffNormal[b->ImageNum];
|
|
}
|
|
}
|
|
else if( GenericButtonGrayed[ b->ImageNum ] )
|
|
BPic = GenericButtonGrayed[b->ImageNum];
|
|
else
|
|
{
|
|
BPic = GenericButtonOffNormal[ b->ImageNum ];
|
|
switch( b->bDisabledStyle )
|
|
{
|
|
case DISABLED_STYLE_DEFAULT:
|
|
gbDisabledButtonStyle = b->string ? DISABLED_STYLE_SHADED : DISABLED_STYLE_HATCHED;
|
|
break;
|
|
case DISABLED_STYLE_HATCHED:
|
|
case DISABLED_STYLE_SHADED:
|
|
gbDisabledButtonStyle = b->bDisabledStyle;
|
|
break;
|
|
}
|
|
}
|
|
|
|
iBorderWidth=3;
|
|
iBorderHeight=2;
|
|
pTrav=NULL;
|
|
|
|
// DB - Added this to support more flexible sizing of border images
|
|
// The 3x2 size was a bit limiting. JA2 should default to the original
|
|
// size, unchanged
|
|
|
|
|
|
// Compute the number of button "chunks" needed to be blitted
|
|
width = b->Area.RegionBottomRightX - b->Area.RegionTopLeftX;
|
|
height = b->Area.RegionBottomRightY - b->Area.RegionTopLeftY;
|
|
NumChunksWide = width / iBorderWidth;
|
|
NumChunksHigh = height / iBorderHeight;
|
|
hremain = height % iBorderHeight;
|
|
wremain = width % iBorderWidth;
|
|
|
|
cx = (b->XLoc + ((NumChunksWide-1)*iBorderWidth) + wremain);
|
|
cy = (b->YLoc + ((NumChunksHigh-1)*iBorderHeight) + hremain);
|
|
|
|
// Fill the button's area with the button's background color
|
|
ColorFillVideoSurfaceArea(ButtonDestBuffer,b->Area.RegionTopLeftX,
|
|
b->Area.RegionTopLeftY,
|
|
b->Area.RegionBottomRightX,
|
|
b->Area.RegionBottomRightY,
|
|
GenericButtonFillColors[b->ImageNum]);
|
|
|
|
// If there is a background image, fill the button's area with it
|
|
if(GenericButtonBackground[b->ImageNum]!=NULL)
|
|
{
|
|
ox=oy=0;
|
|
// if the button was clicked on, adjust the background image so that we get
|
|
// the illusion that it is sunk into the screen.
|
|
if(b->uiFlags & BUTTON_CLICKED_ON)
|
|
ox=oy=1;
|
|
|
|
// Fill the area with the image, tilling it if need be.
|
|
ImageFillVideoSurfaceArea(ButtonDestBuffer,b->Area.RegionTopLeftX+ox,
|
|
b->Area.RegionTopLeftY+oy,
|
|
b->Area.RegionBottomRightX,
|
|
b->Area.RegionBottomRightY,
|
|
GenericButtonBackground[b->ImageNum],
|
|
GenericButtonBackgroundIndex[b->ImageNum],
|
|
GenericButtonOffsetX[b->ImageNum],
|
|
GenericButtonOffsetY[b->ImageNum]);
|
|
}
|
|
|
|
// Lock the dest buffer
|
|
pDestBuf = LockVideoSurface( ButtonDestBuffer, &uiDestPitchBYTES );
|
|
|
|
GetClippingRect(&ClipRect);
|
|
|
|
// Draw the button's borders and corners (horizontally)
|
|
for(q=0;q<NumChunksWide;q++)
|
|
{
|
|
if(q==0)
|
|
ImgNum=0;
|
|
else
|
|
ImgNum=1;
|
|
|
|
if(gbPixelDepth==16)
|
|
{
|
|
Blt8BPPDataTo16BPPBufferTransparentClip( (UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
(INT32)(b->XLoc + (q*iBorderWidth)),
|
|
(INT32)b->YLoc,
|
|
(UINT16)ImgNum, &ClipRect );
|
|
}
|
|
else if(gbPixelDepth==8)
|
|
{
|
|
Blt8BPPDataTo8BPPBufferTransparentClip( (UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
(INT32)(b->XLoc + (q*iBorderWidth)),
|
|
(INT32)b->YLoc,
|
|
(UINT16)ImgNum, &ClipRect );
|
|
}
|
|
|
|
if(q==0)
|
|
ImgNum=5;
|
|
else
|
|
ImgNum=6;
|
|
|
|
if(gbPixelDepth==16)
|
|
{
|
|
Blt8BPPDataTo16BPPBufferTransparentClip( (UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
(INT32)(b->XLoc + (q*iBorderWidth)),
|
|
cy, (UINT16)ImgNum, &ClipRect );
|
|
}
|
|
else if(gbPixelDepth==8)
|
|
{
|
|
Blt8BPPDataTo8BPPBufferTransparentClip((UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
(INT32)(b->XLoc + (q*iBorderWidth)),
|
|
cy, (UINT16)ImgNum, &ClipRect );
|
|
}
|
|
|
|
}
|
|
// Blit the right side corners
|
|
if(gbPixelDepth==16)
|
|
{
|
|
Blt8BPPDataTo16BPPBufferTransparentClip( (UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
cx, (INT32)b->YLoc,
|
|
2, &ClipRect );
|
|
}
|
|
else if(gbPixelDepth==8)
|
|
{
|
|
Blt8BPPDataTo8BPPBufferTransparentClip( (UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
cx, (INT32)b->YLoc,
|
|
2, &ClipRect );
|
|
}
|
|
|
|
|
|
if(gbPixelDepth==16)
|
|
{
|
|
Blt8BPPDataTo16BPPBufferTransparentClip( (UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
cx, cy, 7, &ClipRect );
|
|
}
|
|
else if(gbPixelDepth==8)
|
|
{
|
|
Blt8BPPDataTo8BPPBufferTransparentClip( (UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
cx, cy, 7, &ClipRect );
|
|
}
|
|
// Draw the vertical members of the button's borders
|
|
NumChunksHigh--;
|
|
|
|
if(hremain!=0)
|
|
{
|
|
q=NumChunksHigh;
|
|
if(gbPixelDepth==16)
|
|
{
|
|
Blt8BPPDataTo16BPPBufferTransparentClip( (UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
(INT32)b->XLoc,
|
|
(INT32)(b->YLoc + (q*iBorderHeight) - (iBorderHeight-hremain)),
|
|
3, &ClipRect );
|
|
}
|
|
else if(gbPixelDepth==8)
|
|
{
|
|
Blt8BPPDataTo8BPPBufferTransparentClip( (UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
(INT32)b->XLoc,
|
|
(INT32)(b->YLoc + (q*iBorderHeight) - (iBorderHeight-hremain)),
|
|
3, &ClipRect );
|
|
}
|
|
|
|
if(gbPixelDepth==16)
|
|
{
|
|
Blt8BPPDataTo16BPPBufferTransparentClip( (UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
cx, (INT32)(b->YLoc + (q*iBorderHeight) - (iBorderHeight-hremain)),
|
|
4, &ClipRect );
|
|
}
|
|
else if(gbPixelDepth==8)
|
|
{
|
|
Blt8BPPDataTo8BPPBufferTransparentClip((UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
cx, (INT32)(b->YLoc + (q*iBorderHeight) - (iBorderHeight-hremain)),
|
|
4, &ClipRect );
|
|
}
|
|
}
|
|
|
|
for(q=1;q<NumChunksHigh;q++)
|
|
{
|
|
if(gbPixelDepth==16)
|
|
{
|
|
Blt8BPPDataTo16BPPBufferTransparentClip( (UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
(INT32)b->XLoc,
|
|
(INT32)(b->YLoc + (q*iBorderHeight)),
|
|
3, &ClipRect );
|
|
}
|
|
else if(gbPixelDepth==8)
|
|
{
|
|
Blt8BPPDataTo8BPPBufferTransparentClip((UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
(INT32)b->XLoc,
|
|
(INT32)(b->YLoc + (q*iBorderHeight)),
|
|
3, &ClipRect );
|
|
}
|
|
|
|
if(gbPixelDepth==16)
|
|
{
|
|
Blt8BPPDataTo16BPPBufferTransparentClip( (UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
cx, (INT32)(b->YLoc + (q*iBorderHeight)),
|
|
4, &ClipRect );
|
|
}
|
|
else if(gbPixelDepth==8)
|
|
{
|
|
Blt8BPPDataTo8BPPBufferTransparentClip((UINT16*)pDestBuf,
|
|
uiDestPitchBYTES, BPic,
|
|
cx, (INT32)(b->YLoc + (q*iBorderHeight)),
|
|
4, &ClipRect );
|
|
}
|
|
}
|
|
|
|
// Unlock buffer
|
|
UnLockVideoSurface( ButtonDestBuffer );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=======================================================================================================
|
|
// Dialog box code
|
|
//
|
|
|
|
|
|
//=======================================================================================================
|
|
//=======================================================================================================
|
|
//
|
|
// Very preliminary stuff follows
|
|
//
|
|
//=======================================================================================================
|
|
//=======================================================================================================
|
|
|
|
|
|
|
|
typedef struct _CreateDlgInfo {
|
|
INT32 iFlags; // Holds the creation flags
|
|
|
|
INT32 iPosX; // Screen position of dialog box
|
|
INT32 iPosY;
|
|
INT32 iWidth; // Dimensions of dialog box (if needed)
|
|
INT32 iHeight;
|
|
|
|
INT32 iAreaWidth; // Dimensions of area the dialog box will be
|
|
INT32 iAreaHeight; // placed (for auto-sizing and auto-placement
|
|
INT32 iAreaOffsetX; // only)
|
|
INT32 iAreaOffsetY;
|
|
|
|
UINT16 *zDlgText; // Text to be displayed (if any)
|
|
INT32 iTextFont; // Font to be used for text (if any)
|
|
UINT16 usTextCols; // Font colors (for mono fonts only)
|
|
|
|
INT32 iTextAreaX; // Area in dialog box where text is to be
|
|
INT32 iTextAreaY; // put (for non-auto placed text)
|
|
INT32 iTextAreaWidth;
|
|
INT32 iTextAreaHeight;
|
|
|
|
HVOBJECT hBackImg; // Background pic for dialog box (if any)
|
|
INT32 iBackImgIndex; // Sub-image index to use for image
|
|
INT32 iBackOffsetX; // Offset on dialog box where to put image
|
|
INT32 iBackOffsetY;
|
|
|
|
HVOBJECT hIconImg; // Icon image pic and index.
|
|
INT32 iIconImgIndex;
|
|
INT32 iIconPosX;
|
|
INT32 iIconPosY;
|
|
|
|
INT32 iBtnTypes;
|
|
|
|
INT32 iOkPosX; // Ok button info
|
|
INT32 iOkPosY;
|
|
INT32 iOkWidth;
|
|
INT32 iOkHeight;
|
|
INT32 iOkImg;
|
|
|
|
INT32 iCnclPosX; // Cancel button info
|
|
INT32 iCnclPosY;
|
|
INT32 iCnclWidth;
|
|
INT32 iCnclHeight;
|
|
INT32 iCnclImg;
|
|
} CreateDlgInfo;
|
|
|
|
#define DLG_RESTRICT_MOUSE 1
|
|
#define DLG_OK_BUTTON 2
|
|
#define DLG_CANCEL_BUTTON 4
|
|
#define DLG_AUTOSIZE 8
|
|
#define DLG_RECREATE 16
|
|
#define DLG_AUTOPOSITION 32
|
|
#define DLG_TEXT_IN_AREA 64
|
|
#define DLG_USE_BKGRND_IMAGE 128
|
|
#define DLG_USE_BORDERS 256
|
|
#define DLG_USE_BTN_HOTSPOTS 512
|
|
#define DLG_USE_MONO_FONTS 1024
|
|
#define DLG_IS_ACTIVE 2048
|
|
|
|
#define DLG_MANUAL_RENDER 0
|
|
#define DLG_START_RENDER 1
|
|
#define DLG_STOP_RENDER 2
|
|
#define DLG_AUTO_RENDER 3
|
|
|
|
#define DLG_GET_STATUS 0
|
|
#define DLG_WAIT_FOR_RESPONSE 1
|
|
|
|
#define DLG_STATUS_NONE 0
|
|
#define DLG_STATUS_OK 1
|
|
#define DLG_STATUS_CANCEL 2
|
|
#define DLG_STATUS_PENDING 3
|
|
|
|
#define DLG_CLEARALL 0
|
|
#define DLG_POSITION 1
|
|
#define DLG_AREA 2
|
|
#define DLG_TEXT 3
|
|
#define DLG_TEXTAREA 4
|
|
#define DLG_BACKPIC 5
|
|
#define DLG_ICON 6
|
|
#define DLG_OKBUTTON 7
|
|
#define DLG_CANCELBUTTON 8
|
|
#define DLG_OPTIONS 9
|
|
#define DLG_SIZE 10
|
|
|
|
|
|
BOOLEAN SetDialogAttributes( CreateDlgInfo *pDlgInfo, INT32 iAttrib, ... )
|
|
{
|
|
va_list arg;
|
|
INT32 iFont,iFontOptions;
|
|
STR16 zString;
|
|
INT32 iX,iY,iW,iH;
|
|
INT32 iIndex;
|
|
HVOBJECT hVObj;
|
|
INT32 iButnImg;
|
|
INT32 iFlags;
|
|
UINT8 ubFGrnd,ubBGrnd;
|
|
|
|
// Set up for var args
|
|
va_start( arg, iAttrib ); // Init variable argument list
|
|
|
|
switch (iAttrib)
|
|
{
|
|
case DLG_CLEARALL:
|
|
// Check to make sure it's not enabled, if so either abort or trash it!
|
|
memset( pDlgInfo, 0, sizeof(CreateDlgInfo) );
|
|
break;
|
|
|
|
case DLG_POSITION:
|
|
// Screen X/Y position of dialog box
|
|
iFlags = va_arg( arg, INT32 );
|
|
iX = va_arg( arg, INT32 );
|
|
iY = va_arg( arg, INT32 );
|
|
|
|
iW = va_arg( arg, INT32 );
|
|
iH = va_arg( arg, INT32 );
|
|
break;
|
|
|
|
case DLG_SIZE:
|
|
// Width and height of doalog box
|
|
iFlags = va_arg( arg, INT32 );
|
|
iW = va_arg( arg, INT32 );
|
|
iH = va_arg( arg, INT32 );
|
|
break;
|
|
|
|
case DLG_AREA:
|
|
// Area where dialog box should be placed in (if not screen)
|
|
iFlags = va_arg( arg, INT32 );
|
|
iX = va_arg( arg, INT32 );
|
|
iY = va_arg( arg, INT32 );
|
|
iW = va_arg( arg, INT32 );
|
|
iH = va_arg( arg, INT32 );
|
|
break;
|
|
|
|
case DLG_TEXT:
|
|
// Set text and font for this dialog box
|
|
iFontOptions = va_arg( arg, INT32 );
|
|
|
|
iFont = va_arg( arg, INT32 );
|
|
pDlgInfo->iTextFont = iFont;
|
|
|
|
zString = va_arg( arg, STR16 );
|
|
|
|
if ( pDlgInfo->zDlgText != NULL )
|
|
MemFree( pDlgInfo->zDlgText );
|
|
|
|
if ( zString == NULL )
|
|
pDlgInfo->zDlgText = NULL;
|
|
else
|
|
{
|
|
pDlgInfo->zDlgText = NULL; // Temp
|
|
}
|
|
|
|
if ( iFontOptions & DLG_USE_MONO_FONTS )
|
|
{
|
|
ubFGrnd = va_arg( arg, UINT8 );
|
|
ubBGrnd = va_arg( arg, UINT8 );
|
|
pDlgInfo->usTextCols = ((((UINT16)ubBGrnd)<<8) | (UINT16)ubFGrnd);
|
|
}
|
|
break;
|
|
|
|
case DLG_TEXTAREA:
|
|
// Area on dialog box where the text should go!
|
|
iFlags = va_arg( arg, INT32 );
|
|
iX = va_arg( arg, INT32 );
|
|
iY = va_arg( arg, INT32 );
|
|
iW = va_arg( arg, INT32 );
|
|
iH = va_arg( arg, INT32 );
|
|
break;
|
|
|
|
case DLG_BACKPIC:
|
|
iFlags = va_arg( arg, INT32 );
|
|
hVObj = (HVOBJECT)va_arg( arg, UINT32 );
|
|
iIndex = va_arg( arg, INT32 );
|
|
iX = va_arg( arg, INT32 );
|
|
iY = va_arg( arg, INT32 );
|
|
break;
|
|
|
|
case DLG_ICON:
|
|
// Icon
|
|
iFlags = va_arg( arg, INT32 );
|
|
hVObj = (HVOBJECT)va_arg( arg, UINT32 );
|
|
iIndex = va_arg( arg, INT32 );
|
|
iX = va_arg( arg, INT32 );
|
|
iY = va_arg( arg, INT32 );
|
|
break;
|
|
|
|
case DLG_OKBUTTON:
|
|
// Ok button options
|
|
iFlags = va_arg( arg, INT32 );
|
|
iX = va_arg( arg, INT32 );
|
|
iY = va_arg( arg, INT32 );
|
|
iW = va_arg( arg, INT32 );
|
|
iH = va_arg( arg, INT32 );
|
|
iButnImg = va_arg( arg, INT32 );
|
|
break;
|
|
|
|
case DLG_CANCELBUTTON:
|
|
// Cancel button options
|
|
iFlags = va_arg( arg, INT32 );
|
|
iX = va_arg( arg, INT32 );
|
|
iY = va_arg( arg, INT32 );
|
|
iW = va_arg( arg, INT32 );
|
|
iH = va_arg( arg, INT32 );
|
|
iButnImg = va_arg( arg, INT32 );
|
|
break;
|
|
|
|
case DLG_OPTIONS:
|
|
iFlags = va_arg( arg, INT32 );
|
|
break;
|
|
}
|
|
|
|
va_end( arg ); // Must have this for proper exit
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
INT32 CreateDialogBox( CreateDlgInfo *pDlgInfo )
|
|
{
|
|
return (-1);
|
|
}
|
|
|
|
|
|
void RemoveDialogBox( void )
|
|
{
|
|
}
|
|
|
|
|
|
void DrawDialogBox( INT32 iDlgBox )
|
|
{
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------------------------------
|
|
|
|
|
|
|
|
INT32 CreateCheckBoxButton( INT16 x, INT16 y, const STR8 filename, INT16 Priority, GUI_CALLBACK ClickCallback )
|
|
{
|
|
GUI_BUTTON *b;
|
|
INT32 ButPic, iButtonID;
|
|
Assert( filename != NULL );
|
|
Assert( strlen(filename) );
|
|
if( ( ButPic = LoadButtonImage(filename,-1,0,1,2,3) ) == -1 )
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"CreateCheckBoxButton: Can't load button image");
|
|
return( -1 );
|
|
}
|
|
iButtonID = (INT16)QuickCreateButton(
|
|
(UINT32)ButPic, x, y, BUTTON_CHECKBOX, Priority,
|
|
MSYS_NO_CALLBACK, ClickCallback );
|
|
if( iButtonID == - 1 )
|
|
{
|
|
DbgMessage(TOPIC_BUTTON_HANDLER,DBG_LEVEL_0,"CreateCheckBoxButton: Can't create button");
|
|
return( -1 );
|
|
}
|
|
|
|
//change the flags so that it isn't a quick button anymore
|
|
b = ButtonList[ iButtonID ];
|
|
b->uiFlags &= ( ~BUTTON_QUICK );
|
|
b->uiFlags |= ( BUTTON_CHECKBOX | BUTTON_SELFDELETE_IMAGE);
|
|
|
|
return( iButtonID );
|
|
}
|
|
|
|
// Added Oct17, 97 Carter - kind of mindless, but might as well have it
|
|
void MSYS_SetBtnUserData(INT32 iButtonNum,INT32 index,INT32 userdata)
|
|
{
|
|
GUI_BUTTON *b;
|
|
b=ButtonList[iButtonNum];
|
|
if((index < 0) || (index > 3))
|
|
return;
|
|
if(b != NULL) b->UserData[index]=userdata;
|
|
}
|
|
|
|
INT32 MSYS_GetBtnUserData(GUI_BUTTON *b,INT32 index)
|
|
{
|
|
if(index < 0 || index > 3)
|
|
return(0);
|
|
|
|
return(b->UserData[index]);
|
|
}
|
|
|
|
|
|
//Generic Button Movement Callback to reset the mouse button if the mouse is no longer
|
|
//in the button region.
|
|
void BtnGenericMouseMoveButtonCallback(GUI_BUTTON *btn,INT32 reason)
|
|
{
|
|
//If the button isn't the anchored button, then we don't want to modify the button state.
|
|
if( btn != gpAnchoredButton )
|
|
return;
|
|
if( reason & MSYS_CALLBACK_REASON_LOST_MOUSE )
|
|
{
|
|
if( !gfAnchoredState )
|
|
{
|
|
btn->uiFlags &= (~BUTTON_CLICKED_ON );
|
|
if( btn->ubSoundSchemeID )
|
|
{
|
|
PlayButtonSound( btn->IDNum, BUTTON_SOUND_CLICKED_OFF );
|
|
}
|
|
}
|
|
|
|
InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY);
|
|
}
|
|
else if( reason & MSYS_CALLBACK_REASON_GAIN_MOUSE )
|
|
{
|
|
btn->uiFlags |= BUTTON_CLICKED_ON ;
|
|
if( btn->ubSoundSchemeID )
|
|
{
|
|
PlayButtonSound( btn->IDNum, BUTTON_SOUND_CLICKED_ON );
|
|
}
|
|
|
|
InvalidateRegion(btn->Area.RegionTopLeftX, btn->Area.RegionTopLeftY, btn->Area.RegionBottomRightX, btn->Area.RegionBottomRightY);
|
|
}
|
|
}
|
|
|
|
void ReleaseAnchorMode()
|
|
{
|
|
if( !gpAnchoredButton )
|
|
return;
|
|
|
|
if( gusMouseXPos < gpAnchoredButton->Area.RegionTopLeftX ||
|
|
gusMouseXPos > gpAnchoredButton->Area.RegionBottomRightX ||
|
|
gusMouseYPos < gpAnchoredButton->Area.RegionTopLeftY ||
|
|
gusMouseYPos > gpAnchoredButton->Area.RegionBottomRightY )
|
|
{
|
|
//released outside button area, so restore previous button state.
|
|
if( gfAnchoredState )
|
|
gpAnchoredButton->uiFlags |= BUTTON_CLICKED_ON;
|
|
else
|
|
gpAnchoredButton->uiFlags &= ( ~BUTTON_CLICKED_ON );
|
|
InvalidateRegion(gpAnchoredButton->Area.RegionTopLeftX, gpAnchoredButton->Area.RegionTopLeftY, gpAnchoredButton->Area.RegionBottomRightX, gpAnchoredButton->Area.RegionBottomRightY);
|
|
}
|
|
gpPrevAnchoredButton = gpAnchoredButton;
|
|
gpAnchoredButton = NULL;
|
|
}
|
|
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
|
|
|
|
// Used to setup a dirtysaved region for buttons
|
|
BOOLEAN SetButtonSavedRect( INT32 iButton )
|
|
{
|
|
GUI_BUTTON *b;
|
|
INT32 xloc,yloc,w,h;
|
|
|
|
Assert( iButton >=0 );
|
|
Assert( iButton <MAX_BUTTONS);
|
|
|
|
b=ButtonList[ iButton ];
|
|
|
|
xloc=b->XLoc;
|
|
yloc=b->YLoc;
|
|
w = ( b->Area.RegionBottomRightX - b->Area.RegionTopLeftX );
|
|
h = ( b->Area.RegionBottomRightY - b->Area.RegionTopLeftY );
|
|
|
|
if ( !(b->uiFlags & BUTTON_SAVEBACKGROUND ) )
|
|
{
|
|
b->uiFlags |= BUTTON_SAVEBACKGROUND;
|
|
|
|
b->BackRect = RegisterBackgroundRect(BGND_FLAG_PERMANENT | BGND_FLAG_SAVERECT, NULL,
|
|
(INT16)xloc, (INT16)yloc, (INT16)(xloc+w), (INT16)(yloc+h) );
|
|
}
|
|
|
|
return( TRUE );
|
|
}
|
|
|
|
void FreeButtonSavedRect( INT32 iButton )
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
Assert( iButton >=0 );
|
|
Assert( iButton <MAX_BUTTONS);
|
|
|
|
b=ButtonList[ iButton ];
|
|
|
|
if ( (b->uiFlags & BUTTON_SAVEBACKGROUND ) )
|
|
{
|
|
b->uiFlags &= (~BUTTON_SAVEBACKGROUND);
|
|
FreeBackgroundRectPending(b->BackRect);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
//Kris:
|
|
//Yet new logical additions to the winbart library.
|
|
void HideButton( INT32 iButtonNum )
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
Assert( iButtonNum >= 0 );
|
|
Assert( iButtonNum < MAX_BUTTONS);
|
|
|
|
b = ButtonList[ iButtonNum ];
|
|
|
|
Assert( b );
|
|
|
|
b->Area.uiFlags &= (~MSYS_REGION_ENABLED);
|
|
b->uiFlags |= BUTTON_DIRTY;
|
|
InvalidateRegion(b->Area.RegionTopLeftX, b->Area.RegionTopLeftY, b->Area.RegionBottomRightX, b->Area.RegionBottomRightY);
|
|
}
|
|
|
|
void ShowButton( INT32 iButtonNum )
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
Assert( iButtonNum >= 0 );
|
|
Assert( iButtonNum < MAX_BUTTONS);
|
|
|
|
b = ButtonList[ iButtonNum ];
|
|
|
|
Assert( b );
|
|
|
|
b->Area.uiFlags |= MSYS_REGION_ENABLED;
|
|
b->uiFlags |= BUTTON_DIRTY;
|
|
InvalidateRegion(b->Area.RegionTopLeftX, b->Area.RegionTopLeftY, b->Area.RegionBottomRightX, b->Area.RegionBottomRightY);
|
|
}
|
|
|
|
void DisableButtonHelpTextRestore( void )
|
|
{
|
|
fDisableHelpTextRestoreFlag = TRUE;
|
|
}
|
|
|
|
void EnableButtonHelpTextRestore( void )
|
|
{
|
|
fDisableHelpTextRestoreFlag = TRUE;
|
|
}
|
|
|
|
void GiveButtonDefaultStatus( INT32 iButtonID, INT32 iDefaultStatus )
|
|
{
|
|
GUI_BUTTON *b;
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS);
|
|
b = ButtonList[ iButtonID ];
|
|
//If new default status added, then this assert may need to be adjusted.
|
|
AssertMsg( iDefaultStatus >= DEFAULT_STATUS_NONE && iDefaultStatus <= DEFAULT_STATUS_WINDOWS95,
|
|
String( "Illegal button default status of %d", iDefaultStatus ) );
|
|
Assert( b );
|
|
|
|
if( b->bDefaultStatus != (INT8)iDefaultStatus )
|
|
{
|
|
b->bDefaultStatus = (INT8)iDefaultStatus;
|
|
b->uiFlags |= BUTTON_DIRTY;
|
|
}
|
|
}
|
|
|
|
void RemoveButtonDefaultStatus( INT32 iButtonID )
|
|
{
|
|
GUI_BUTTON *b;
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS);
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
|
|
if( b->bDefaultStatus )
|
|
{
|
|
b->bDefaultStatus = DEFAULT_STATUS_NONE;
|
|
b->uiFlags |= BUTTON_DIRTY;
|
|
}
|
|
}
|
|
|
|
BOOLEAN GetButtonArea(INT32 iButtonID, SGPRect *pRect)
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS);
|
|
Assert(pRect);
|
|
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
|
|
if((pRect==NULL) || (b==NULL))
|
|
return(FALSE);
|
|
|
|
pRect->iLeft=b->Area.RegionTopLeftX;
|
|
pRect->iTop=b->Area.RegionTopLeftY;
|
|
pRect->iRight=b->Area.RegionBottomRightX;
|
|
pRect->iBottom=b->Area.RegionBottomRightY;
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
INT32 GetButtonWidth(INT32 iButtonID)
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS);
|
|
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
|
|
if(b==NULL)
|
|
return(-1);
|
|
|
|
return(b->Area.RegionBottomRightX - b->Area.RegionTopLeftX);
|
|
}
|
|
|
|
INT32 GetButtonHeight(INT32 iButtonID)
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS);
|
|
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
|
|
if(b==NULL)
|
|
return(-1);
|
|
|
|
return(b->Area.RegionBottomRightY - b->Area.RegionTopLeftY);
|
|
}
|
|
|
|
INT32 GetButtonX(INT32 iButtonID)
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS);
|
|
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
|
|
if(b==NULL)
|
|
return(0);
|
|
|
|
return(b->Area.RegionTopLeftX);
|
|
}
|
|
|
|
INT32 GetButtonY(INT32 iButtonID)
|
|
{
|
|
GUI_BUTTON *b;
|
|
|
|
Assert( iButtonID >= 0 );
|
|
Assert( iButtonID < MAX_BUTTONS);
|
|
|
|
b = ButtonList[ iButtonID ];
|
|
Assert( b );
|
|
|
|
if(b==NULL)
|
|
return(0);
|
|
|
|
return(b->Area.RegionTopLeftY);
|
|
}
|