mirror of
https://github.com/1dot13/source.git
synced 2026-07-22 13:40:22 +02:00
git-svn-id: https://ja2svn.mooo.com/source/ja2/trunk/GameSource/ja2_v1.13/Build@3172 3b4a5df2-a311-0410-b5c6-a8a6f20db521
1746 lines
46 KiB
C++
1746 lines
46 KiB
C++
|
|
//=================================================================================================
|
|
// MouseSystem.c
|
|
//
|
|
// Routines for handling prioritized mouse regions. The system as setup below allows the use of
|
|
// callback functions for each region, as well as allowing a different cursor to be defined for
|
|
// each region.
|
|
//
|
|
// Written by Bret Rowdon, Jan 30 '97
|
|
// Re-Written by Kris Morness, since...
|
|
//
|
|
//=================================================================================================
|
|
|
|
#ifdef JA2_PRECOMPILED_HEADERS
|
|
#include "JA2 SGP ALL.H"
|
|
#elif defined( WIZ8_PRECOMPILED_HEADERS )
|
|
#include "WIZ8 SGP ALL.H"
|
|
#else
|
|
#include "types.h"
|
|
#include <windows.h>
|
|
#include <stdio.h>
|
|
#include <memory.h>
|
|
#include "debug.h"
|
|
#include "input.h"
|
|
#include "memman.h"
|
|
#include "line.h"
|
|
#if (defined( JA2 ) || defined( UTIL ))
|
|
#include "video.h"
|
|
#define BASE_REGION_FLAGS (MSYS_REGION_ENABLED | MSYS_SET_CURSOR)
|
|
#else
|
|
#include "video2.h"
|
|
#define BASE_REGION_FLAGS MSYS_REGION_ENABLED // Wiz doesn't ever want MSYS_SET_CURSOR to be on...
|
|
#endif
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
#include "render dirty.h"
|
|
#include "Font Control.h"
|
|
#endif
|
|
#include "english.h"
|
|
// Include mouse system defs and macros
|
|
#include "mousesystem.h"
|
|
#include "Cursor Control.h"
|
|
#include "Button System.h"
|
|
#endif
|
|
|
|
#ifdef JA2_PRECOMPILED_HEADERS
|
|
#define BASE_REGION_FLAGS (MSYS_REGION_ENABLED | MSYS_SET_CURSOR)
|
|
#elif defined( WIZ8_PRECOMPILED_HEADERS )
|
|
#define BASE_REGION_FLAGS MSYS_REGION_ENABLED // Wiz doesn't ever want MSYS_SET_CURSOR to be on...
|
|
#endif
|
|
|
|
|
|
|
|
//Kris: Nov 31, 1999 -- Added support for double clicking
|
|
//
|
|
//Max double click delay (in milliseconds) to be considered a double click
|
|
#define MSYS_DOUBLECLICK_DELAY 400
|
|
//
|
|
//Records and stores the last place the user clicked. These values are compared to the current
|
|
//click to determine if a double click event has been detected.
|
|
MOUSE_REGION *gpRegionLastLButtonDown = NULL;
|
|
MOUSE_REGION *gpRegionLastLButtonUp = NULL;
|
|
UINT32 guiRegionLastLButtonDownTime = 0;
|
|
|
|
|
|
|
|
|
|
extern void ReleaseAnchorMode(); //private function used here (implemented in Button System.c)
|
|
|
|
// number of lines in height help text will be
|
|
INT16 GetNumberOfLinesInHeight( const STR16 pStringA );
|
|
INT16 GetWidthOfString( const STR16 pStringA );
|
|
void DisplayHelpTokenizedString( const STR16 pStringA, INT16 sX, INT16 sY );
|
|
|
|
|
|
|
|
INT32 MSYS_ScanForID=FALSE;
|
|
INT32 MSYS_CurrentID=MSYS_ID_SYSTEM;
|
|
|
|
INT16 MSYS_CurrentMX=0;
|
|
INT16 MSYS_CurrentMY=0;
|
|
INT16 MSYS_CurrentButtons=0;
|
|
INT16 MSYS_Action=0;
|
|
|
|
BOOLEAN MSYS_SystemInitialized=FALSE;
|
|
BOOLEAN MSYS_UseMouseHandlerHook=FALSE;
|
|
|
|
BOOLEAN MSYS_Mouse_Grabbed=FALSE;
|
|
MOUSE_REGION *MSYS_GrabRegion = NULL;
|
|
|
|
UINT16 gusClickedIDNumber;
|
|
BOOLEAN gfClickedModeOn = FALSE;
|
|
|
|
MOUSE_REGION *MSYS_RegList = NULL;
|
|
|
|
MOUSE_REGION *MSYS_PrevRegion = NULL;
|
|
MOUSE_REGION *MSYS_CurrRegion = NULL;
|
|
|
|
//When set, the fast help text will be instantaneous, if consecutive regions with help text are
|
|
//hilighted. It is set, whenever the timer for the first help button expires, and the mode is
|
|
//cleared as soon as the cursor moves into no region or a region with no helptext.
|
|
BOOLEAN gfPersistantFastHelpMode;
|
|
|
|
INT16 gsFastHelpDelay = 600; // In timer ticks
|
|
BOOLEAN gfShowFastHelp = TRUE;
|
|
|
|
// help text is done, now execute callback, if there is one
|
|
void ExecuteMouseHelpEndCallBack( MOUSE_REGION *region );
|
|
|
|
|
|
|
|
//Kris:
|
|
//NOTE: This doesn't really need to be here, however, it is a good indication that
|
|
//when an error appears here, that you need to go below to the init code and initialize the
|
|
//values there as well. That's the only reason why I left this here.
|
|
MOUSE_REGION MSYS_SystemBaseRegion = {
|
|
MSYS_ID_SYSTEM, MSYS_PRIORITY_SYSTEM, BASE_REGION_FLAGS,
|
|
-32767, -32767, 32767, 32767, 0, 0, 0, 0, 0, 0,
|
|
MSYS_NO_CALLBACK, MSYS_NO_CALLBACK, { 0,0,0,0 },
|
|
0, 0, -1, MSYS_NO_CALLBACK, NULL, NULL };
|
|
|
|
BOOLEAN gfRefreshUpdate = FALSE;
|
|
|
|
//Kris: December 3, 1997
|
|
//Special internal debugging utilities that will ensure that you don't attempt to delete
|
|
//an already deleted region. It will also ensure that you don't create an identical region
|
|
//that already exists.
|
|
//TO REMOVE ALL DEBUG FUNCTIONALITY: simply comment out MOUSESYSTEM_DEBUGGING definition
|
|
#ifdef JA2
|
|
#ifdef _DEBUG
|
|
#ifndef BOUNDS_CHECKER
|
|
#define MOUSESYSTEM_DEBUGGING
|
|
#endif
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef MOUSESYSTEM_DEBUGGING
|
|
extern BOOLEAN gfIgnoreShutdownAssertions;
|
|
#endif
|
|
|
|
//======================================================================================================
|
|
// MSYS_Init
|
|
//
|
|
// Initialize the mouse system.
|
|
//
|
|
INT32 MSYS_Init(void)
|
|
{
|
|
RegisterDebugTopic(TOPIC_MOUSE_SYSTEM, "Mouse Region System");
|
|
|
|
#ifdef MOUSESYSTEM_DEBUGGING
|
|
gfIgnoreShutdownAssertions = FALSE;
|
|
#endif
|
|
if(MSYS_RegList!=NULL)
|
|
MSYS_TrashRegList();
|
|
|
|
MSYS_CurrentID = MSYS_ID_SYSTEM;
|
|
MSYS_ScanForID = FALSE;
|
|
|
|
MSYS_CurrentMX = 0;
|
|
MSYS_CurrentMY = 0;
|
|
MSYS_CurrentButtons = 0;
|
|
MSYS_Action=MSYS_NO_ACTION;
|
|
|
|
MSYS_PrevRegion = NULL;
|
|
MSYS_SystemInitialized = TRUE;
|
|
MSYS_UseMouseHandlerHook = FALSE;
|
|
|
|
MSYS_Mouse_Grabbed=FALSE;
|
|
MSYS_GrabRegion = NULL;
|
|
|
|
// Setup the system's background region
|
|
MSYS_SystemBaseRegion.IDNumber = MSYS_ID_SYSTEM;
|
|
MSYS_SystemBaseRegion.PriorityLevel = MSYS_PRIORITY_SYSTEM;
|
|
MSYS_SystemBaseRegion.uiFlags = BASE_REGION_FLAGS;
|
|
MSYS_SystemBaseRegion.RegionTopLeftX = -32767;
|
|
MSYS_SystemBaseRegion.RegionTopLeftY = -32767;
|
|
MSYS_SystemBaseRegion.RegionBottomRightX = 32767;
|
|
MSYS_SystemBaseRegion.RegionBottomRightY = 32767;
|
|
MSYS_SystemBaseRegion.MouseXPos = 0;
|
|
MSYS_SystemBaseRegion.MouseYPos = 0;
|
|
MSYS_SystemBaseRegion.RelativeXPos = 0;
|
|
MSYS_SystemBaseRegion.RelativeYPos = 0;
|
|
MSYS_SystemBaseRegion.ButtonState = 0;
|
|
MSYS_SystemBaseRegion.Cursor = 0;
|
|
MSYS_SystemBaseRegion.UserData[0] = 0;
|
|
MSYS_SystemBaseRegion.UserData[1] = 0;
|
|
MSYS_SystemBaseRegion.UserData[2] = 0;
|
|
MSYS_SystemBaseRegion.UserData[3] = 0;
|
|
MSYS_SystemBaseRegion.MovementCallback = MSYS_NO_CALLBACK;
|
|
MSYS_SystemBaseRegion.ButtonCallback = MSYS_NO_CALLBACK;
|
|
|
|
MSYS_SystemBaseRegion.FastHelpTimer = 0;
|
|
MSYS_SystemBaseRegion.FastHelpText = 0;
|
|
MSYS_SystemBaseRegion.FastHelpRect = -1;
|
|
|
|
MSYS_SystemBaseRegion.next = NULL;
|
|
MSYS_SystemBaseRegion.prev = NULL;
|
|
|
|
// Add the base region to the list
|
|
MSYS_AddRegionToList(&MSYS_SystemBaseRegion);
|
|
|
|
#ifdef _MOUSE_SYSTEM_HOOK_
|
|
MSYS_UseMouseHandlerHook = TRUE;
|
|
#endif
|
|
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
//======================================================================================================
|
|
// MSYS_Shutdown
|
|
//
|
|
// De-inits the "mousesystem" mouse region handling code.
|
|
//
|
|
void MSYS_Shutdown(void)
|
|
{
|
|
#ifdef MOUSESYSTEM_DEBUGGING
|
|
gfIgnoreShutdownAssertions = TRUE;
|
|
#endif
|
|
MSYS_SystemInitialized = FALSE;
|
|
MSYS_UseMouseHandlerHook = FALSE;
|
|
MSYS_TrashRegList();
|
|
UnRegisterDebugTopic(TOPIC_MOUSE_SYSTEM, "Mouse Region System");
|
|
}
|
|
|
|
|
|
|
|
//======================================================================================================
|
|
// MSYS_SGP_Mouse_Handler_Hook
|
|
//
|
|
// Hook to the SGP's mouse handler
|
|
//
|
|
void MSYS_SGP_Mouse_Handler_Hook(UINT16 Type,UINT16 Xcoord, UINT16 Ycoord, BOOLEAN LeftButton, BOOLEAN RightButton)
|
|
{
|
|
// If the mouse system isn't initialized, get out o' here
|
|
if(!MSYS_SystemInitialized)
|
|
return;
|
|
|
|
// If we're not using the handler stuff, ignore this call
|
|
if(!MSYS_UseMouseHandlerHook)
|
|
return;
|
|
|
|
MSYS_Action=MSYS_NO_ACTION;
|
|
switch(Type)
|
|
{
|
|
case LEFT_BUTTON_DOWN:
|
|
case LEFT_BUTTON_UP:
|
|
case RIGHT_BUTTON_DOWN:
|
|
case RIGHT_BUTTON_UP:
|
|
//MSYS_Action|=MSYS_DO_BUTTONS;
|
|
if(Type == LEFT_BUTTON_DOWN)
|
|
MSYS_Action |= MSYS_DO_LBUTTON_DWN;
|
|
else if(Type == LEFT_BUTTON_UP)
|
|
{
|
|
MSYS_Action |= MSYS_DO_LBUTTON_UP;
|
|
//Kris:
|
|
//Used only if applicable. This is used for that special button that is locked with the
|
|
//mouse press -- just like windows. When you release the button, the previous state
|
|
//of the button is restored if you released the mouse outside of it's boundaries. If
|
|
//you release inside of the button, the action is selected -- but later in the code.
|
|
//NOTE: It has to be here, because the mouse can be released anywhere regardless of
|
|
//regions, buttons, etc.
|
|
#ifdef JA2
|
|
ReleaseAnchorMode();
|
|
#endif
|
|
}
|
|
else if(Type == RIGHT_BUTTON_DOWN)
|
|
MSYS_Action |= MSYS_DO_RBUTTON_DWN;
|
|
else if(Type == RIGHT_BUTTON_UP)
|
|
MSYS_Action |= MSYS_DO_RBUTTON_UP;
|
|
|
|
if(LeftButton)
|
|
MSYS_CurrentButtons|=MSYS_LEFT_BUTTON;
|
|
else
|
|
MSYS_CurrentButtons&=(~MSYS_LEFT_BUTTON);
|
|
|
|
if(RightButton)
|
|
MSYS_CurrentButtons|=MSYS_RIGHT_BUTTON;
|
|
else
|
|
MSYS_CurrentButtons&=(~MSYS_RIGHT_BUTTON);
|
|
|
|
if((Xcoord != MSYS_CurrentMX) || (Ycoord != MSYS_CurrentMY))
|
|
{
|
|
MSYS_Action|=MSYS_DO_MOVE;
|
|
MSYS_CurrentMX = Xcoord;
|
|
MSYS_CurrentMY = Ycoord;
|
|
}
|
|
|
|
MSYS_UpdateMouseRegion();
|
|
break;
|
|
|
|
// ATE: Checks here for mouse button repeats.....
|
|
// Call mouse region with new reason
|
|
case LEFT_BUTTON_REPEAT:
|
|
case RIGHT_BUTTON_REPEAT:
|
|
|
|
if(Type == LEFT_BUTTON_REPEAT)
|
|
MSYS_Action |= MSYS_DO_LBUTTON_REPEAT;
|
|
else if(Type == RIGHT_BUTTON_REPEAT)
|
|
MSYS_Action |= MSYS_DO_RBUTTON_REPEAT;
|
|
|
|
if((Xcoord != MSYS_CurrentMX) || (Ycoord != MSYS_CurrentMY))
|
|
{
|
|
MSYS_Action|=MSYS_DO_MOVE;
|
|
MSYS_CurrentMX = Xcoord;
|
|
MSYS_CurrentMY = Ycoord;
|
|
}
|
|
|
|
MSYS_UpdateMouseRegion();
|
|
break;
|
|
|
|
case MOUSE_POS:
|
|
if((Xcoord != MSYS_CurrentMX) || (Ycoord != MSYS_CurrentMY) || gfRefreshUpdate )
|
|
{
|
|
MSYS_Action|=MSYS_DO_MOVE;
|
|
MSYS_CurrentMX = Xcoord;
|
|
MSYS_CurrentMY = Ycoord;
|
|
|
|
gfRefreshUpdate = FALSE;
|
|
|
|
MSYS_UpdateMouseRegion();
|
|
}
|
|
break;
|
|
|
|
default:
|
|
DbgMessage(TOPIC_MOUSE_SYSTEM, DBG_LEVEL_0, "ERROR -- MSYS 2 SGP Mouse Hook got bad type");
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//======================================================================================================
|
|
// MSYS_GetNewID
|
|
//
|
|
// Returns a unique ID number for region nodes. If no new ID numbers can be found, the MAX value
|
|
// is returned.
|
|
//
|
|
INT32 MSYS_GetNewID(void)
|
|
{
|
|
INT32 retID;
|
|
INT32 Current,found,done;
|
|
MOUSE_REGION *node;
|
|
|
|
retID = MSYS_CurrentID;
|
|
MSYS_CurrentID++;
|
|
|
|
// Crapy scan for an unused ID
|
|
if((MSYS_CurrentID >= MSYS_ID_MAX) || MSYS_ScanForID)
|
|
{
|
|
MSYS_ScanForID = TRUE;
|
|
Current = MSYS_ID_BASE;
|
|
done=found=FALSE;
|
|
while(!done)
|
|
{
|
|
found=FALSE;
|
|
node=MSYS_RegList;
|
|
while(node!=NULL && !found)
|
|
{
|
|
if(node->IDNumber == Current)
|
|
found=TRUE;
|
|
}
|
|
|
|
if(found && Current < MSYS_ID_MAX) // Current ID is in use, and their are more to scan
|
|
Current++;
|
|
else
|
|
{
|
|
done=TRUE; // Got an ID to use.
|
|
if(found)
|
|
Current=MSYS_ID_MAX; // Ooops, ran out of IDs, use MAX value!
|
|
}
|
|
}
|
|
MSYS_CurrentID = Current;
|
|
}
|
|
|
|
return(retID);
|
|
}
|
|
|
|
|
|
|
|
//======================================================================================================
|
|
// MSYS_TrashRegList
|
|
//
|
|
// Deletes the entire region list.
|
|
//
|
|
void MSYS_TrashRegList(void)
|
|
{
|
|
while( MSYS_RegList )
|
|
{
|
|
if( MSYS_RegList->uiFlags & MSYS_REGION_EXISTS )
|
|
{
|
|
MSYS_RemoveRegion(MSYS_RegList);
|
|
}
|
|
else
|
|
{
|
|
MSYS_RegList = MSYS_RegList->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//======================================================================================================
|
|
// MSYS_AddRegionToList
|
|
//
|
|
// Add a region struct to the current list. The list is sorted by priority levels. If two entries
|
|
// have the same priority level, then the latest to enter the list gets the higher priority.
|
|
//
|
|
void MSYS_AddRegionToList(MOUSE_REGION *region)
|
|
{
|
|
MOUSE_REGION *curr;
|
|
INT32 done;
|
|
|
|
|
|
// If region seems to already be in list, delete it so we can
|
|
// re-insert the region.
|
|
if( region->next || region->prev )
|
|
{ // if it wasn't actually there, then call does nothing!
|
|
MSYS_DeleteRegionFromList(region);
|
|
}
|
|
|
|
// Set an ID number!
|
|
region->IDNumber = (UINT16)MSYS_GetNewID();
|
|
|
|
region->next = NULL;
|
|
region->prev = NULL;
|
|
|
|
if( !MSYS_RegList )
|
|
{ // Null list, so add it straight up.
|
|
MSYS_RegList = region;
|
|
}
|
|
else
|
|
{
|
|
// Walk down list until we find place to insert (or at end of list)
|
|
curr=MSYS_RegList;
|
|
done=FALSE;
|
|
while((curr->next != NULL) && !done)
|
|
{
|
|
if(curr->PriorityLevel <= region->PriorityLevel)
|
|
done=TRUE;
|
|
else
|
|
curr = curr->next;
|
|
}
|
|
|
|
if(curr->PriorityLevel > region->PriorityLevel)
|
|
{
|
|
// Add after curr node
|
|
region->next = curr->next;
|
|
curr->next = region;
|
|
region->prev = curr;
|
|
if(region->next != NULL)
|
|
region->next->prev = region;
|
|
}
|
|
else
|
|
{
|
|
// Add before curr node
|
|
region->next = curr;
|
|
region->prev = curr->prev;
|
|
|
|
curr->prev = region;
|
|
if(region->prev != NULL)
|
|
region->prev->next = region;
|
|
|
|
if(MSYS_RegList==curr) // Make sure if adding at start, to adjust the list pointer
|
|
MSYS_RegList=region;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//======================================================================================================
|
|
// MSYS_RegionInList
|
|
//
|
|
// Scan region list for presence of a node with the same region ID number
|
|
//
|
|
INT32 MSYS_RegionInList( MOUSE_REGION *region )
|
|
{
|
|
MOUSE_REGION *Current;
|
|
INT32 found;
|
|
|
|
found = FALSE;
|
|
Current = MSYS_RegList;
|
|
while( Current && !found )
|
|
{
|
|
if(Current->IDNumber == region->IDNumber)
|
|
found=TRUE;
|
|
Current = Current->next;
|
|
}
|
|
return(found);
|
|
}
|
|
|
|
|
|
|
|
//======================================================================================================
|
|
// MSYS_DeleteRegionFromList
|
|
//
|
|
// Removes a region from the current list.
|
|
//
|
|
void MSYS_DeleteRegionFromList(MOUSE_REGION *region)
|
|
{
|
|
// If no list present, there's nothin' to do.
|
|
if( !MSYS_RegList )
|
|
return;
|
|
|
|
// Check if region in list
|
|
if(!MSYS_RegionInList(region))
|
|
return;
|
|
|
|
// Remove a node from the list
|
|
if(MSYS_RegList == region)
|
|
{ // First node on list, adjust main pointer.
|
|
MSYS_RegList = region->next;
|
|
if(MSYS_RegList!=NULL)
|
|
MSYS_RegList->prev = NULL;
|
|
region->next = region->prev = NULL;
|
|
}
|
|
else
|
|
{
|
|
if(region->prev)
|
|
region->prev->next = region->next;
|
|
// If not last node in list, adjust following node's->prev entry.
|
|
if( region->next )
|
|
region->next->prev = region->prev;
|
|
region->prev = region->next = NULL;
|
|
}
|
|
|
|
// Did we delete a grabbed region?
|
|
if(MSYS_Mouse_Grabbed)
|
|
{
|
|
if(MSYS_GrabRegion == region)
|
|
{
|
|
MSYS_Mouse_Grabbed = FALSE;
|
|
MSYS_GrabRegion = NULL;
|
|
}
|
|
}
|
|
|
|
// Is only the system background region remaining?
|
|
if(MSYS_RegList == &MSYS_SystemBaseRegion)
|
|
{
|
|
// Yup, so let's reset the ID values!
|
|
MSYS_CurrentID = MSYS_ID_BASE;
|
|
MSYS_ScanForID = FALSE;
|
|
}
|
|
else if(MSYS_RegList == NULL)
|
|
{
|
|
// Ack, we actually emptied the list, so let's reset for re-init possibilities
|
|
MSYS_CurrentID = MSYS_ID_SYSTEM;
|
|
MSYS_ScanForID = FALSE;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//======================================================================================================
|
|
// MSYS_UpdateMouseRegion
|
|
//
|
|
// Searches the list for the highest priority region and updates it's info. It also dispatches
|
|
// the callback functions
|
|
//
|
|
void MSYS_UpdateMouseRegion(void)
|
|
{
|
|
INT32 found;
|
|
UINT32 ButtonReason;
|
|
MOUSE_REGION *pTempRegion;
|
|
BOOLEAN fFound=FALSE;
|
|
found=FALSE;
|
|
|
|
// WANNE: Error handling Bugfix by birdflu (to avoid Stack Overflow)
|
|
if(guiCurrentScreen == ERROR_SCREEN)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Check previous region!
|
|
if(MSYS_Mouse_Grabbed)
|
|
{
|
|
MSYS_CurrRegion = MSYS_GrabRegion;
|
|
found = TRUE;
|
|
}
|
|
if(!found)
|
|
MSYS_CurrRegion = MSYS_RegList;
|
|
|
|
while( !found && MSYS_CurrRegion )
|
|
{
|
|
if( MSYS_CurrRegion->uiFlags & (MSYS_REGION_ENABLED | MSYS_ALLOW_DISABLED_FASTHELP) &&
|
|
(MSYS_CurrRegion->RegionTopLeftX <= MSYS_CurrentMX) && // Check boundaries
|
|
(MSYS_CurrRegion->RegionTopLeftY <= MSYS_CurrentMY) &&
|
|
(MSYS_CurrRegion->RegionBottomRightX >= MSYS_CurrentMX) &&
|
|
(MSYS_CurrRegion->RegionBottomRightY >= MSYS_CurrentMY))
|
|
{
|
|
// We got the right region. We don't need to check for priorities 'cause
|
|
// the whole list is sorted the right way!
|
|
found=TRUE;
|
|
}
|
|
else
|
|
MSYS_CurrRegion = MSYS_CurrRegion->next;
|
|
}
|
|
|
|
if( MSYS_PrevRegion )
|
|
{
|
|
MSYS_PrevRegion->uiFlags &= (~MSYS_MOUSE_IN_AREA);
|
|
|
|
if ( MSYS_PrevRegion != MSYS_CurrRegion )
|
|
{
|
|
//Remove the help text for the previous region if one is currently being displayed.
|
|
if( MSYS_PrevRegion->FastHelpText )
|
|
{
|
|
//ExecuteMouseHelpEndCallBack( MSYS_PrevRegion );
|
|
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
if( MSYS_PrevRegion->uiFlags & MSYS_GOT_BACKGROUND )
|
|
FreeBackgroundRectPending( MSYS_PrevRegion->FastHelpRect );
|
|
#endif
|
|
MSYS_PrevRegion->uiFlags &= (~MSYS_GOT_BACKGROUND);
|
|
MSYS_PrevRegion->uiFlags &= (~MSYS_FASTHELP_RESET);
|
|
|
|
#ifndef UTIL
|
|
// dirty buttons, need a re-render
|
|
//DEF: Nov 30 98
|
|
// PausedMarkButtonsDirty( );
|
|
#endif
|
|
|
|
//if( region->uiFlags & MSYS_REGION_ENABLED )
|
|
// region->uiFlags |= BUTTON_DIRTY;
|
|
#ifndef JA2
|
|
VideoRemoveToolTip();
|
|
#endif
|
|
}
|
|
|
|
if (MSYS_CurrRegion)
|
|
MSYS_CurrRegion->FastHelpTimer = gsFastHelpDelay;
|
|
|
|
// Force a callbacks to happen on previous region to indicate that
|
|
// the mouse has left the old region
|
|
if ( MSYS_PrevRegion->uiFlags & MSYS_MOVE_CALLBACK && MSYS_PrevRegion->uiFlags & MSYS_REGION_ENABLED )
|
|
(*(MSYS_PrevRegion->MovementCallback))(MSYS_PrevRegion,MSYS_CALLBACK_REASON_LOST_MOUSE);
|
|
}
|
|
}
|
|
|
|
// If a region was found in the list, update it's data
|
|
if(found)
|
|
{
|
|
if(MSYS_CurrRegion != MSYS_PrevRegion)
|
|
{
|
|
//Kris -- October 27, 1997
|
|
//Implemented gain mouse region
|
|
if ( MSYS_CurrRegion->uiFlags & MSYS_MOVE_CALLBACK )
|
|
{
|
|
if( MSYS_CurrRegion->FastHelpText && !( MSYS_CurrRegion->uiFlags & MSYS_FASTHELP_RESET ) )
|
|
{
|
|
//ExecuteMouseHelpEndCallBack( MSYS_CurrRegion );
|
|
MSYS_CurrRegion->FastHelpTimer = gsFastHelpDelay;
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
if( MSYS_CurrRegion->uiFlags & MSYS_GOT_BACKGROUND )
|
|
FreeBackgroundRectPending( MSYS_CurrRegion->FastHelpRect );
|
|
#endif
|
|
MSYS_CurrRegion->uiFlags &= (~MSYS_GOT_BACKGROUND);
|
|
MSYS_CurrRegion->uiFlags |= MSYS_FASTHELP_RESET;
|
|
|
|
#ifndef JA2
|
|
VideoRemoveToolTip();
|
|
#endif
|
|
|
|
//if( b->uiFlags & BUTTON_ENABLED )
|
|
// b->uiFlags |= BUTTON_DIRTY;
|
|
}
|
|
if( MSYS_CurrRegion->uiFlags & MSYS_REGION_ENABLED )
|
|
{
|
|
(*(MSYS_CurrRegion->MovementCallback))(MSYS_CurrRegion,MSYS_CALLBACK_REASON_GAIN_MOUSE);
|
|
}
|
|
}
|
|
|
|
// if the cursor is set and is not set to no cursor
|
|
if( MSYS_CurrRegion->uiFlags & MSYS_REGION_ENABLED &&
|
|
MSYS_CurrRegion->uiFlags & MSYS_SET_CURSOR &&
|
|
MSYS_CurrRegion->Cursor != MSYS_NO_CURSOR )
|
|
{
|
|
MSYS_SetCurrentCursor(MSYS_CurrRegion->Cursor);
|
|
}
|
|
else
|
|
{
|
|
// Addition Oct 10/1997 Carter, patch for mouse cursor
|
|
// start at region and find another region encompassing
|
|
pTempRegion=MSYS_CurrRegion->next;
|
|
while((pTempRegion!=NULL)&&(!fFound))
|
|
{
|
|
if((pTempRegion->uiFlags & MSYS_REGION_ENABLED) &&
|
|
(pTempRegion->RegionTopLeftX <= MSYS_CurrentMX) &&
|
|
(pTempRegion->RegionTopLeftY <= MSYS_CurrentMY) &&
|
|
(pTempRegion->RegionBottomRightX >= MSYS_CurrentMX) &&
|
|
(pTempRegion->RegionBottomRightY >= MSYS_CurrentMY)&&(pTempRegion->uiFlags & MSYS_SET_CURSOR))
|
|
{
|
|
fFound=TRUE;
|
|
if( pTempRegion->Cursor != MSYS_NO_CURSOR )
|
|
{
|
|
MSYS_SetCurrentCursor(pTempRegion->Cursor);
|
|
}
|
|
}
|
|
pTempRegion=pTempRegion->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
// OK, if we do not have a button down, any button is game!
|
|
if ( !gfClickedModeOn || ( gfClickedModeOn && gusClickedIDNumber == MSYS_CurrRegion->IDNumber ) )
|
|
{
|
|
MSYS_CurrRegion->uiFlags |= MSYS_MOUSE_IN_AREA;
|
|
|
|
MSYS_CurrRegion->MouseXPos = MSYS_CurrentMX;
|
|
MSYS_CurrRegion->MouseYPos = MSYS_CurrentMY;
|
|
MSYS_CurrRegion->RelativeXPos = MSYS_CurrentMX - MSYS_CurrRegion->RegionTopLeftX;
|
|
MSYS_CurrRegion->RelativeYPos = MSYS_CurrentMY - MSYS_CurrRegion->RegionTopLeftY;
|
|
|
|
MSYS_CurrRegion->ButtonState = MSYS_CurrentButtons;
|
|
|
|
if( MSYS_CurrRegion->uiFlags & MSYS_REGION_ENABLED &&
|
|
MSYS_CurrRegion->uiFlags & MSYS_MOVE_CALLBACK && MSYS_Action & MSYS_DO_MOVE )
|
|
{
|
|
(*(MSYS_CurrRegion->MovementCallback))(MSYS_CurrRegion,MSYS_CALLBACK_REASON_MOVE);
|
|
}
|
|
|
|
//ExecuteMouseHelpEndCallBack( MSYS_CurrRegion );
|
|
//MSYS_CurrRegion->FastHelpTimer = gsFastHelpDelay;
|
|
|
|
MSYS_Action &= (~MSYS_DO_MOVE);
|
|
|
|
if((MSYS_CurrRegion->uiFlags & MSYS_BUTTON_CALLBACK) && (MSYS_Action & MSYS_DO_BUTTONS))
|
|
{
|
|
if( MSYS_CurrRegion->uiFlags & MSYS_REGION_ENABLED )
|
|
{
|
|
ButtonReason=MSYS_CALLBACK_REASON_NONE;
|
|
if(MSYS_Action & MSYS_DO_LBUTTON_DWN)
|
|
{
|
|
ButtonReason|=MSYS_CALLBACK_REASON_LBUTTON_DWN;
|
|
gfClickedModeOn = TRUE;
|
|
// Set global ID
|
|
gusClickedIDNumber = MSYS_CurrRegion->IDNumber;
|
|
}
|
|
|
|
if(MSYS_Action & MSYS_DO_LBUTTON_UP )
|
|
{
|
|
ButtonReason|=MSYS_CALLBACK_REASON_LBUTTON_UP;
|
|
gfClickedModeOn = FALSE;
|
|
}
|
|
|
|
if(MSYS_Action & MSYS_DO_RBUTTON_DWN)
|
|
{
|
|
ButtonReason|=MSYS_CALLBACK_REASON_RBUTTON_DWN;
|
|
gfClickedModeOn = TRUE;
|
|
// Set global ID
|
|
gusClickedIDNumber = MSYS_CurrRegion->IDNumber;
|
|
}
|
|
|
|
if(MSYS_Action & MSYS_DO_RBUTTON_UP )
|
|
{
|
|
ButtonReason|=MSYS_CALLBACK_REASON_RBUTTON_UP;
|
|
gfClickedModeOn = FALSE;
|
|
}
|
|
|
|
// ATE: Added repeat resons....
|
|
if(MSYS_Action & MSYS_DO_LBUTTON_REPEAT )
|
|
{
|
|
ButtonReason|=MSYS_CALLBACK_REASON_LBUTTON_REPEAT;
|
|
}
|
|
|
|
if(MSYS_Action & MSYS_DO_RBUTTON_REPEAT )
|
|
{
|
|
ButtonReason|=MSYS_CALLBACK_REASON_RBUTTON_REPEAT;
|
|
}
|
|
|
|
if( ButtonReason != MSYS_CALLBACK_REASON_NONE )
|
|
{
|
|
if( MSYS_CurrRegion->uiFlags & MSYS_FASTHELP )
|
|
{
|
|
// Button was clicked so remove any FastHelp text
|
|
MSYS_CurrRegion->uiFlags &= (~MSYS_FASTHELP);
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
if( MSYS_CurrRegion->uiFlags & MSYS_GOT_BACKGROUND )
|
|
FreeBackgroundRectPending( MSYS_CurrRegion->FastHelpRect );
|
|
#endif
|
|
MSYS_CurrRegion->uiFlags &= (~MSYS_GOT_BACKGROUND);
|
|
|
|
//ExecuteMouseHelpEndCallBack( MSYS_CurrRegion );
|
|
MSYS_CurrRegion->FastHelpTimer = gsFastHelpDelay;
|
|
MSYS_CurrRegion->uiFlags &= (~MSYS_FASTHELP_RESET);
|
|
|
|
//if( b->uiFlags & BUTTON_ENABLED )
|
|
// b->uiFlags |= BUTTON_DIRTY;
|
|
#ifndef JA2
|
|
VideoRemoveToolTip();
|
|
#endif
|
|
}
|
|
|
|
//Kris: Nov 31, 1999 -- Added support for double click events.
|
|
//This is where double clicks are checked and passed down.
|
|
if( ButtonReason == MSYS_CALLBACK_REASON_LBUTTON_DWN )
|
|
{
|
|
UINT32 uiCurrTime = GetClock();
|
|
if( gpRegionLastLButtonDown == MSYS_CurrRegion &&
|
|
gpRegionLastLButtonUp == MSYS_CurrRegion &&
|
|
uiCurrTime <= guiRegionLastLButtonDownTime + MSYS_DOUBLECLICK_DELAY )
|
|
{ //Sequential left click on same button within the maximum time allowed for a double click
|
|
//Double click check succeeded, set flag and reset double click globals.
|
|
ButtonReason |= MSYS_CALLBACK_REASON_LBUTTON_DOUBLECLICK;
|
|
gpRegionLastLButtonDown = NULL;
|
|
gpRegionLastLButtonUp = NULL;
|
|
guiRegionLastLButtonDownTime = 0;
|
|
}
|
|
else
|
|
{ //First click, record time and region pointer (to check if 2nd click detected later)
|
|
gpRegionLastLButtonDown = MSYS_CurrRegion;
|
|
guiRegionLastLButtonDownTime = GetClock();
|
|
}
|
|
}
|
|
else if( ButtonReason == MSYS_CALLBACK_REASON_LBUTTON_UP )
|
|
{
|
|
UINT32 uiCurrTime = GetClock();
|
|
if( gpRegionLastLButtonDown == MSYS_CurrRegion &&
|
|
uiCurrTime <= guiRegionLastLButtonDownTime + MSYS_DOUBLECLICK_DELAY )
|
|
{ //Double click is Left down, then left up, then left down. We have just detected the left up here (step 2).
|
|
gpRegionLastLButtonUp = MSYS_CurrRegion;
|
|
}
|
|
else
|
|
{ //User released mouse outside of current button, so kill any chance of a double click happening.
|
|
gpRegionLastLButtonDown = NULL;
|
|
gpRegionLastLButtonUp = NULL;
|
|
guiRegionLastLButtonDownTime = 0;
|
|
}
|
|
}
|
|
|
|
(*(MSYS_CurrRegion->ButtonCallback))(MSYS_CurrRegion,ButtonReason);
|
|
}
|
|
}
|
|
}
|
|
|
|
MSYS_Action &= (~MSYS_DO_BUTTONS);
|
|
}
|
|
else if( MSYS_CurrRegion->uiFlags & MSYS_REGION_ENABLED )
|
|
{
|
|
// OK here, if we have release a button, UNSET LOCK wherever you are....
|
|
// Just don't give this button the message....
|
|
if(MSYS_Action & MSYS_DO_RBUTTON_UP )
|
|
{
|
|
gfClickedModeOn = FALSE;
|
|
}
|
|
if(MSYS_Action & MSYS_DO_LBUTTON_UP )
|
|
{
|
|
gfClickedModeOn = FALSE;
|
|
}
|
|
|
|
// OK, you still want move messages however....
|
|
MSYS_CurrRegion->uiFlags |= MSYS_MOUSE_IN_AREA;
|
|
MSYS_CurrRegion->MouseXPos = MSYS_CurrentMX;
|
|
MSYS_CurrRegion->MouseYPos = MSYS_CurrentMY;
|
|
MSYS_CurrRegion->RelativeXPos = MSYS_CurrentMX - MSYS_CurrRegion->RegionTopLeftX;
|
|
MSYS_CurrRegion->RelativeYPos = MSYS_CurrentMY - MSYS_CurrRegion->RegionTopLeftY;
|
|
|
|
if((MSYS_CurrRegion->uiFlags & MSYS_MOVE_CALLBACK) && (MSYS_Action & MSYS_DO_MOVE))
|
|
{
|
|
(*(MSYS_CurrRegion->MovementCallback))(MSYS_CurrRegion,MSYS_CALLBACK_REASON_MOVE);
|
|
}
|
|
|
|
MSYS_Action &= (~MSYS_DO_MOVE);
|
|
}
|
|
MSYS_PrevRegion = MSYS_CurrRegion;
|
|
}
|
|
else
|
|
MSYS_PrevRegion = NULL;
|
|
}
|
|
|
|
|
|
|
|
//=================================================================================================
|
|
// MSYS_DefineRegion
|
|
//
|
|
// Inits a MOUSE_REGION structure for use with the mouse system
|
|
//
|
|
void MSYS_DefineRegion(MOUSE_REGION *region,UINT16 tlx,UINT16 tly,UINT16 brx,UINT16 bry,INT8 priority,
|
|
UINT16 crsr,MOUSE_CALLBACK movecallback,MOUSE_CALLBACK buttoncallback)
|
|
{
|
|
#ifdef MOUSESYSTEM_DEBUGGING
|
|
if( region->uiFlags & MSYS_REGION_EXISTS )
|
|
AssertMsg( 0, "Attempting to define a region that already exists." );
|
|
#endif
|
|
|
|
region->IDNumber = MSYS_ID_BASE;
|
|
|
|
if(priority == MSYS_PRIORITY_AUTO)
|
|
priority = MSYS_PRIORITY_BASE;
|
|
else if(priority <= MSYS_PRIORITY_LOWEST)
|
|
priority = MSYS_PRIORITY_LOWEST;
|
|
else if(priority >= MSYS_PRIORITY_HIGHEST)
|
|
priority = MSYS_PRIORITY_HIGHEST;
|
|
|
|
region->PriorityLevel = priority;
|
|
|
|
region->uiFlags = MSYS_NO_FLAGS;
|
|
|
|
region->MovementCallback = movecallback;
|
|
if(movecallback != MSYS_NO_CALLBACK)
|
|
region->uiFlags |= MSYS_MOVE_CALLBACK;
|
|
|
|
region->ButtonCallback = buttoncallback;
|
|
if(buttoncallback != MSYS_NO_CALLBACK)
|
|
region->uiFlags |= MSYS_BUTTON_CALLBACK;
|
|
|
|
region->Cursor = crsr;
|
|
if(crsr != MSYS_NO_CURSOR)
|
|
region->uiFlags |= MSYS_SET_CURSOR;
|
|
|
|
region->RegionTopLeftX = tlx;
|
|
region->RegionTopLeftY = tly;
|
|
region->RegionBottomRightX = brx;
|
|
region->RegionBottomRightY = bry;
|
|
|
|
region->MouseXPos = 0;
|
|
region->MouseYPos = 0;
|
|
region->RelativeXPos = 0;
|
|
region->RelativeYPos = 0;
|
|
region->ButtonState = 0;
|
|
|
|
//Init fasthelp
|
|
region->FastHelpText = NULL;
|
|
region->FastHelpTimer = 0;
|
|
|
|
region->next = NULL;
|
|
region->prev = NULL;
|
|
region->HelpDoneCallback = NULL;
|
|
|
|
//Add region to system list
|
|
MSYS_AddRegionToList(region);
|
|
region->uiFlags|= MSYS_REGION_ENABLED | MSYS_REGION_EXISTS;
|
|
|
|
|
|
// Dirty our update flag
|
|
gfRefreshUpdate = TRUE;
|
|
}
|
|
|
|
|
|
|
|
//=================================================================================================
|
|
// MSYS_ChangeRegionCursor
|
|
//
|
|
void MSYS_ChangeRegionCursor(MOUSE_REGION *region,UINT16 crsr)
|
|
{
|
|
region->uiFlags &= (~MSYS_SET_CURSOR);
|
|
region->Cursor = crsr;
|
|
if(crsr != MSYS_NO_CURSOR)
|
|
{
|
|
region->uiFlags |= MSYS_SET_CURSOR;
|
|
|
|
// If we are not in the region, donot update!
|
|
if ( !( region->uiFlags & MSYS_MOUSE_IN_AREA ) )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// Update cursor
|
|
MSYS_SetCurrentCursor( crsr );
|
|
}
|
|
}
|
|
|
|
|
|
|
|
//=================================================================================================
|
|
// MSYS_AddRegion
|
|
//
|
|
// Adds a defined mouse region to the system list. Once inserted, it enables the region then
|
|
// calls the callback functions, if any, for initialization.
|
|
//
|
|
INT32 MSYS_AddRegion(MOUSE_REGION *region)
|
|
{
|
|
return(1);
|
|
}
|
|
|
|
|
|
|
|
//=================================================================================================
|
|
// MSYS_RemoveRegion
|
|
//
|
|
// Removes a region from the list, disables it, then calls the callback functions for
|
|
// de-initialization.
|
|
//
|
|
void MSYS_RemoveRegion(MOUSE_REGION *region)
|
|
{
|
|
if( !region )
|
|
{
|
|
#ifdef MOUSESYSTEM_DEBUGGING
|
|
if( gfIgnoreShutdownAssertions )
|
|
#endif
|
|
return;
|
|
AssertMsg( 0, "Attempting to remove a NULL region.");
|
|
}
|
|
//CHRISL: Obviously, we should never run this function if a region hasn't been setup, but a failsafe would be nice
|
|
if(!(region->uiFlags & MSYS_REGION_EXISTS))
|
|
return;
|
|
|
|
#ifdef MOUSESYSTEM_DEBUGGING
|
|
if( !(region->uiFlags & MSYS_REGION_EXISTS) )
|
|
AssertMsg( 0, "Attempting to remove an already removed region." );
|
|
#endif
|
|
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
if( region->uiFlags & MSYS_HAS_BACKRECT )
|
|
{
|
|
FreeBackgroundRectPending( region->FastHelpRect );
|
|
region->uiFlags &= (~MSYS_HAS_BACKRECT);
|
|
|
|
|
|
}
|
|
#endif
|
|
|
|
// Get rid of the FastHelp text (if applicable)
|
|
if( region->FastHelpText )
|
|
{
|
|
#ifndef JA2
|
|
if(region->uiFlags & MSYS_FASTHELP)
|
|
VideoRemoveToolTip();
|
|
#endif
|
|
MemFree( region->FastHelpText );
|
|
}
|
|
region->FastHelpText = NULL;
|
|
|
|
MSYS_DeleteRegionFromList(region);
|
|
|
|
//if the previous region is the one that we are deleting, reset the previous region
|
|
if ( MSYS_PrevRegion == region )
|
|
MSYS_PrevRegion = NULL;
|
|
//if the current region is the one that we are deleting, then clear it.
|
|
if( MSYS_CurrRegion == region )
|
|
MSYS_CurrRegion = NULL;
|
|
|
|
//dirty our update flag
|
|
gfRefreshUpdate = TRUE;
|
|
|
|
// Check if this is a locked region, and unlock if so
|
|
if ( gfClickedModeOn )
|
|
{
|
|
// Set global ID
|
|
if ( gusClickedIDNumber == region->IDNumber )
|
|
{
|
|
gfClickedModeOn = FALSE;
|
|
}
|
|
}
|
|
|
|
//clear all internal values (including the region exists flag)
|
|
memset( region, 0, sizeof( MOUSE_REGION ) );
|
|
}
|
|
|
|
|
|
|
|
//=================================================================================================
|
|
// MSYS_EnableRegion
|
|
//
|
|
// Enables a mouse region.
|
|
//
|
|
void MSYS_EnableRegion(MOUSE_REGION *region)
|
|
{
|
|
region->uiFlags |= MSYS_REGION_ENABLED;
|
|
}
|
|
|
|
|
|
|
|
//=================================================================================================
|
|
// MSYS_DisableRegion
|
|
//
|
|
// Disables a mouse region without removing it from the system list.
|
|
//
|
|
void MSYS_DisableRegion(MOUSE_REGION *region)
|
|
{
|
|
region->uiFlags &= (~MSYS_REGION_ENABLED);
|
|
}
|
|
|
|
|
|
//=================================================================================================
|
|
// MSYS_SetCurrentCursor
|
|
//
|
|
// Sets the mouse cursor to the regions defined value.
|
|
//
|
|
void MSYS_SetCurrentCursor(UINT16 Cursor)
|
|
{
|
|
TRYCATCH_RETHROW(SetCurrentCursorFromDatabase( Cursor ), "Could not set Cursor");
|
|
}
|
|
|
|
|
|
|
|
//=================================================================================================
|
|
// MSYS_ChangeRegionPriority
|
|
//
|
|
// Set the priority of a mouse region
|
|
//
|
|
void MSYS_ChangeRegionPriority(MOUSE_REGION *region,INT8 priority)
|
|
{
|
|
if(priority==MSYS_PRIORITY_AUTO)
|
|
priority=MSYS_PRIORITY_NORMAL;
|
|
|
|
region->PriorityLevel = priority;
|
|
}
|
|
|
|
|
|
|
|
//=================================================================================================
|
|
// MSYS_SetRegionUserData
|
|
//
|
|
// Sets one of the four user data entries in a mouse region
|
|
//
|
|
void MSYS_SetRegionUserData(MOUSE_REGION *region,INT32 index,INT32 userdata)
|
|
{
|
|
if(index < 0 || index > 3)
|
|
{
|
|
CHAR8 str[80];
|
|
#ifdef MOUSESYSTEM_DEBUGGING
|
|
if( gfIgnoreShutdownAssertions )
|
|
#endif
|
|
return;
|
|
sprintf( str, "Attempting MSYS_SetRegionUserData() with out of range index %d.", index );
|
|
AssertMsg( 0, str );
|
|
}
|
|
region->UserData[index]=userdata;
|
|
}
|
|
|
|
|
|
|
|
//=================================================================================================
|
|
// MSYS_GetRegionUserData
|
|
//
|
|
// Retrieves one of the four user data entries in a mouse region
|
|
//
|
|
INT32 MSYS_GetRegionUserData(MOUSE_REGION *region,INT32 index)
|
|
{
|
|
if(index < 0 || index > 3)
|
|
{
|
|
CHAR8 str[80];
|
|
#ifdef MOUSESYSTEM_DEBUGGING
|
|
if( gfIgnoreShutdownAssertions )
|
|
#endif
|
|
return 0;
|
|
sprintf( str, "Attempting MSYS_GetRegionUserData() with out of range index %d", index );
|
|
AssertMsg( 0, str );
|
|
}
|
|
return(region->UserData[index]);
|
|
}
|
|
|
|
|
|
|
|
//=================================================================================================
|
|
// MSYS_GrabMouse
|
|
//
|
|
// Assigns all mouse activity to a region, effectively blocking any other region from having
|
|
// control.
|
|
//
|
|
INT32 MSYS_GrabMouse(MOUSE_REGION *region)
|
|
{
|
|
if(!MSYS_RegionInList(region))
|
|
return(MSYS_REGION_NOT_IN_LIST);
|
|
|
|
if(MSYS_Mouse_Grabbed == TRUE)
|
|
return(MSYS_ALREADY_GRABBED);
|
|
|
|
MSYS_Mouse_Grabbed = TRUE;
|
|
MSYS_GrabRegion = region;
|
|
return(MSYS_GRABBED_OK);
|
|
}
|
|
|
|
|
|
|
|
//=================================================================================================
|
|
// MSYS_ReleaseMouse
|
|
//
|
|
// Releases a previously grabbed mouse region
|
|
//
|
|
void MSYS_ReleaseMouse(MOUSE_REGION *region)
|
|
{
|
|
if(MSYS_GrabRegion != region)
|
|
return;
|
|
|
|
if(MSYS_Mouse_Grabbed == TRUE)
|
|
{
|
|
MSYS_Mouse_Grabbed = FALSE;
|
|
MSYS_GrabRegion = NULL;
|
|
MSYS_UpdateMouseRegion();
|
|
}
|
|
}
|
|
|
|
|
|
/* ==================================================================================
|
|
MSYS_MoveMouseRegionTo( MOUSE_REGION *region, INT16 sX, INT16 sY)
|
|
|
|
Moves a Mouse region to X Y on the screen
|
|
|
|
*/
|
|
|
|
void MSYS_MoveMouseRegionTo( MOUSE_REGION *region, INT16 sX, INT16 sY)
|
|
{
|
|
|
|
INT16 sWidth;
|
|
INT16 sHeight;
|
|
|
|
|
|
sWidth = region->RegionBottomRightX - region->RegionTopLeftX;
|
|
sHeight = region->RegionBottomRightY - region->RegionTopLeftY;
|
|
|
|
|
|
// move top left
|
|
region->RegionTopLeftX = sX;
|
|
region->RegionTopLeftY = sY;
|
|
|
|
// now move bottom right based on topleft + width or height
|
|
region->RegionBottomRightX = sX + sWidth;
|
|
region->RegionBottomRightY = sY + sHeight;
|
|
|
|
return;
|
|
}
|
|
|
|
/* ==================================================================================
|
|
MSYS_MoveMouseRegionBy( MOUSE_REGION *region, INT16 sDeltaX, INT16 sDeltaY)
|
|
|
|
Moves a Mouse region by sDeltaX sDeltaY on the screen
|
|
|
|
*/
|
|
|
|
void MSYS_MoveMouseRegionBy( MOUSE_REGION *region, INT16 sDeltaX, INT16 sDeltaY)
|
|
{
|
|
|
|
// move top left
|
|
region->RegionTopLeftX = region->RegionTopLeftX + sDeltaX;
|
|
region->RegionTopLeftY = region->RegionTopLeftY + sDeltaY;
|
|
|
|
// now move bottom right
|
|
region->RegionBottomRightX = region->RegionBottomRightX + sDeltaX;
|
|
region->RegionBottomRightY = region->RegionBottomRightY + sDeltaY;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
// This function will force a re-evaluation of mouse regions
|
|
// Usually used to force change of mouse cursor if panels switch, etc
|
|
void RefreshMouseRegions( )
|
|
{
|
|
MSYS_Action|=MSYS_DO_MOVE;
|
|
|
|
MSYS_UpdateMouseRegion( );
|
|
|
|
}
|
|
|
|
void SetRegionFastHelpText( MOUSE_REGION *region, const STR16 szText )
|
|
{
|
|
Assert( region );
|
|
|
|
if( region->FastHelpText )
|
|
MemFree( region->FastHelpText );
|
|
|
|
region->FastHelpText = NULL;
|
|
// region->FastHelpTimer = 0;
|
|
if( !(region->uiFlags & MSYS_REGION_EXISTS) )
|
|
{
|
|
return;
|
|
//AssertMsg( 0, String( "Attempting to set fast help text, \"%S\" to an inactive region.", szText ) );
|
|
}
|
|
|
|
if( !szText || !wcslen( szText ) )
|
|
return; //blank (or clear)
|
|
|
|
// Allocate memory for the button's FastHelp text string...
|
|
region->FastHelpText = (STR16) MemAlloc( (wcslen( szText ) + 1) * sizeof(CHAR16) );
|
|
Assert( region->FastHelpText );
|
|
|
|
wcscpy( region->FastHelpText, szText );
|
|
|
|
// ATE: We could be replacing already existing, active text
|
|
// so let's remove the region so it be rebuilt...
|
|
|
|
#ifdef JA2
|
|
if ( guiCurrentScreen != MAP_SCREEN )
|
|
{
|
|
#endif
|
|
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
if( region->uiFlags & MSYS_GOT_BACKGROUND )
|
|
FreeBackgroundRectPending( region->FastHelpRect );
|
|
#endif
|
|
|
|
region->uiFlags &= (~MSYS_GOT_BACKGROUND);
|
|
region->uiFlags &= (~MSYS_FASTHELP_RESET);
|
|
|
|
#ifdef JA2
|
|
}
|
|
#endif
|
|
|
|
//region->FastHelpTimer = gsFastHelpDelay;
|
|
}
|
|
|
|
INT16 GetNumberOfLinesInHeight( const STR16 pStringA )
|
|
{
|
|
STR16 pToken;
|
|
INT16 sCounter = 0;
|
|
CHAR16 pString[ 4096 ];
|
|
|
|
wcscpy( pString, pStringA );
|
|
|
|
// tokenize
|
|
pToken = wcstok( pString, L"\n" );
|
|
|
|
while( pToken != NULL )
|
|
{
|
|
// WANNE: Fix by Headrock
|
|
if ( (sCounter+1) * (GetFontHeight(FONT10ARIAL)+1) > (SCREEN_HEIGHT - 10) )
|
|
{
|
|
break;
|
|
}
|
|
pToken = wcstok( NULL, L"\n" );
|
|
sCounter++;
|
|
|
|
/*pToken = wcstok( NULL, L"\n" );
|
|
sCounter++;*/
|
|
}
|
|
|
|
return( sCounter );
|
|
}
|
|
|
|
|
|
|
|
#ifdef _JA2_RENDER_DIRTY
|
|
//=============================================================================
|
|
// DisplayFastHelp
|
|
//
|
|
//
|
|
void DisplayFastHelp( MOUSE_REGION *region )
|
|
{
|
|
UINT16 usFillColor;
|
|
INT32 iX,iY,iW,iH;
|
|
|
|
if ( region->uiFlags & MSYS_FASTHELP )
|
|
{
|
|
usFillColor = Get16BPPColor(FROMRGB(250, 240, 188));
|
|
|
|
iW = (INT32)GetWidthOfString( region->FastHelpText ) + 10;
|
|
iH = (INT32)( GetNumberOfLinesInHeight( region->FastHelpText ) * (GetFontHeight(FONT10ARIAL)+1) + 8 );
|
|
|
|
iX = (INT32)region->RegionTopLeftX + 10;
|
|
|
|
if (iX < 0)
|
|
iX = 0;
|
|
|
|
if ( (iX + iW) >= SCREEN_WIDTH )
|
|
iX = (SCREEN_WIDTH - iW - 4);
|
|
|
|
iY = (INT32)region->RegionTopLeftY - (iH * 3 / 4);
|
|
if (iY < 0)
|
|
iY = 0;
|
|
|
|
if ( (iY + iH) >= SCREEN_HEIGHT )
|
|
iY = (SCREEN_HEIGHT - iH - 15);
|
|
|
|
if ( !(region->uiFlags & MSYS_GOT_BACKGROUND) )
|
|
{
|
|
region->FastHelpRect = RegisterBackgroundRect(BGND_FLAG_PERMANENT | BGND_FLAG_SAVERECT, NULL, (INT16)iX, (INT16)iY,
|
|
(INT16)(iX + iW), (INT16)(iY + iH) );
|
|
region->uiFlags |= MSYS_GOT_BACKGROUND;
|
|
region->uiFlags |= MSYS_HAS_BACKRECT;
|
|
}
|
|
else
|
|
{
|
|
UINT8 *pDestBuf;
|
|
UINT32 uiDestPitchBYTES;
|
|
pDestBuf = LockVideoSurface( FRAME_BUFFER, &uiDestPitchBYTES );
|
|
SetClippingRegionAndImageWidth( uiDestPitchBYTES, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT );
|
|
RectangleDraw( TRUE, iX + 1, iY + 1, iX + iW - 1, iY + iH - 1, Get16BPPColor( FROMRGB( 65, 57, 15 ) ), pDestBuf );
|
|
RectangleDraw( TRUE, iX, iY, iX + iW - 2, iY + iH - 2, Get16BPPColor( FROMRGB( 227, 198, 88 ) ), pDestBuf );
|
|
UnLockVideoSurface( FRAME_BUFFER );
|
|
ShadowVideoSurfaceRect( FRAME_BUFFER, iX + 2, iY + 2, iX + iW - 3, iY + iH - 3 );
|
|
ShadowVideoSurfaceRect( FRAME_BUFFER, iX + 2, iY + 2, iX + iW - 3, iY + iH - 3 );
|
|
|
|
SetFont( FONT10ARIAL );
|
|
SetFontShadow( FONT_NEARBLACK );
|
|
DisplayHelpTokenizedString( region->FastHelpText ,( INT16 )( iX + 5 ), ( INT16 )( iY + 5 ) );
|
|
InvalidateRegion( iX, iY, (iX + iW) , (iY + iH) );
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
INT16 GetWidthOfString( const STR16 pStringA )
|
|
{
|
|
CHAR16 pString[ 4096 ];
|
|
STR16 pToken;
|
|
INT16 sWidth = 0;
|
|
wcscpy( pString, pStringA );
|
|
|
|
// tokenize
|
|
pToken = wcstok( pString, L"\n" );
|
|
|
|
while( pToken != NULL )
|
|
{
|
|
if( sWidth < StringPixLength( pToken, FONT10ARIAL ) )
|
|
{
|
|
sWidth = StringPixLength( pToken, FONT10ARIAL );
|
|
}
|
|
|
|
pToken = wcstok( NULL, L"\n" );
|
|
}
|
|
|
|
return( sWidth );
|
|
|
|
}
|
|
|
|
void DisplayHelpTokenizedString( const STR16 pStringA, INT16 sX, INT16 sY )
|
|
{
|
|
STR16 pToken;
|
|
INT32 iCounter = 0, i;
|
|
UINT32 uiCursorXPos;
|
|
CHAR16 pString[ 4096 ];
|
|
INT32 iLength;
|
|
|
|
wcscpy( pString, pStringA );
|
|
|
|
// tokenize
|
|
pToken = wcstok( pString, L"\n" );
|
|
|
|
while( pToken != NULL )
|
|
{
|
|
// WANNE: Fix by Headrock
|
|
if ( (iCounter+2) * (GetFontHeight(FONT10ARIAL)+1) > (SCREEN_HEIGHT - 10) )
|
|
{
|
|
mprintf( sX, sY + iCounter * (GetFontHeight(FONT10ARIAL)+1), L"..." );
|
|
break;
|
|
}
|
|
iLength = (INT32)wcslen( pToken );
|
|
|
|
//iLength = (INT32)wcslen( pToken );
|
|
for( i = 0; i < iLength; i++ )
|
|
{
|
|
uiCursorXPos = StringPixLengthArgFastHelp( FONT10ARIAL, FONT10ARIALBOLD, i, pToken );
|
|
if( pToken[ i ] == '|' )
|
|
{
|
|
i++;
|
|
SetFont( FONT10ARIALBOLD );
|
|
SetFontForeground( 146 );
|
|
}
|
|
else
|
|
{
|
|
SetFont( FONT10ARIAL );
|
|
SetFontForeground( FONT_BEIGE );
|
|
}
|
|
mprintf( sX + uiCursorXPos, sY + iCounter * (GetFontHeight(FONT10ARIAL)+1), L"%c", pToken[ i ] );
|
|
}
|
|
pToken = wcstok( NULL, L"\n" );
|
|
iCounter++;
|
|
}
|
|
SetFontDestBuffer( FRAME_BUFFER, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, FALSE );
|
|
}
|
|
|
|
void RenderFastHelp()
|
|
{
|
|
static INT32 iLastClock;
|
|
INT32 iTimeDifferential, iCurrentClock;
|
|
|
|
if( !gfRenderHilights )
|
|
return;
|
|
|
|
iCurrentClock = GetClock();
|
|
iTimeDifferential = iCurrentClock - iLastClock;
|
|
if (iTimeDifferential < 0)
|
|
iTimeDifferential += 0x7fffffff;
|
|
iLastClock = iCurrentClock;
|
|
|
|
if( MSYS_CurrRegion && MSYS_CurrRegion->FastHelpText )
|
|
{
|
|
if( !MSYS_CurrRegion->FastHelpTimer )
|
|
{
|
|
if( MSYS_CurrRegion->uiFlags & ( MSYS_ALLOW_DISABLED_FASTHELP | MSYS_REGION_ENABLED ) )
|
|
{
|
|
if( MSYS_CurrRegion->uiFlags & MSYS_MOUSE_IN_AREA )
|
|
MSYS_CurrRegion->uiFlags |= MSYS_FASTHELP;
|
|
else
|
|
{
|
|
MSYS_CurrRegion->uiFlags &= ( ~( MSYS_FASTHELP | MSYS_FASTHELP_RESET ) );
|
|
}
|
|
//Do I really need this?
|
|
//MSYS_CurrRegion->uiFlags |= REGION_DIRTY;
|
|
DisplayFastHelp( MSYS_CurrRegion );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( MSYS_CurrRegion->uiFlags & ( MSYS_ALLOW_DISABLED_FASTHELP | MSYS_REGION_ENABLED ) )
|
|
{
|
|
if ( MSYS_CurrRegion->uiFlags & MSYS_MOUSE_IN_AREA &&
|
|
!MSYS_CurrRegion->ButtonState)// & (MSYS_LEFT_BUTTON|MSYS_RIGHT_BUTTON)) )
|
|
{
|
|
MSYS_CurrRegion->FastHelpTimer -= (INT16)max( iTimeDifferential, 0 );
|
|
|
|
if( MSYS_CurrRegion->FastHelpTimer < 0 )
|
|
{
|
|
MSYS_CurrRegion->FastHelpTimer = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
|
|
// **********Wiz8 Versions**************************************************************************
|
|
|
|
INT16 GetWidthOfString( const STR16 pStringA )
|
|
{
|
|
CHAR16 pString[ 512 ];
|
|
STR16 pToken;
|
|
INT16 sWidth = 0;
|
|
wcscpy( pString, pStringA );
|
|
|
|
// tokenize
|
|
pToken = wcstok( pString, L"\n" );
|
|
|
|
while( pToken != NULL )
|
|
{
|
|
if( sWidth < StringPixLength( pToken, ghTinyMonoFont ) )
|
|
{
|
|
sWidth = StringPixLength( pToken, ghTinyMonoFont );
|
|
}
|
|
|
|
pToken = wcstok( NULL, L"\n" );
|
|
}
|
|
|
|
return( sWidth );
|
|
|
|
}
|
|
|
|
void DisplayFastHelp( MOUSE_REGION *region )
|
|
{
|
|
INT32 iX,iY,iW,iH;
|
|
|
|
if ( region->uiFlags & MSYS_FASTHELP )
|
|
{
|
|
VideoToolTip(region->FastHelpText);
|
|
|
|
iW = VideoGetToolTipWidth();
|
|
iH = VideoGetToolTipHeight();
|
|
|
|
iX = (INT32)region->RegionTopLeftX + 10;
|
|
|
|
if (iX < 0)
|
|
iX = 0;
|
|
|
|
if ( (iX + iW) >= SCREEN_WIDTH )
|
|
iX = (SCREEN_WIDTH - iW - 4);
|
|
|
|
iY = (INT32)region->RegionTopLeftY - (iH * 3 / 4);
|
|
if (iY < 0)
|
|
iY = 0;
|
|
|
|
if ( (iY + iH) >= SCREEN_HEIGHT )
|
|
iY = (SCREEN_HEIGHT - iH - 15);
|
|
|
|
VideoPositionToolTip(iX, iY);
|
|
}
|
|
}
|
|
|
|
void DisplayHelpTokenizedString( const STR16 pStringA, INT16 sX, INT16 sY )
|
|
{
|
|
STR16 pToken;
|
|
INT32 iCounter = 0, i;
|
|
UINT32 uiCursorXPos;
|
|
CHAR16 pString[ 512 ];
|
|
INT32 iLength;
|
|
|
|
wcscpy( pString, pStringA );
|
|
|
|
// tokenize
|
|
pToken = wcstok( pString, L"\n" );
|
|
|
|
while( pToken != NULL )
|
|
{
|
|
iLength = (INT32)wcslen( pToken );
|
|
for( i = 0; i < iLength; i++ )
|
|
{
|
|
uiCursorXPos = StringPixLengthArgFastHelp( ghTinyMonoFont, ghTinyMonoFont, i, pToken );
|
|
if( pToken[ i ] == '|' )
|
|
{
|
|
i++;
|
|
SetFont(ghTinyMonoFont);
|
|
SetFontForeground( 2 );
|
|
}
|
|
else
|
|
{
|
|
SetFont( ghTinyMonoFont );
|
|
SetFontForeground( 2 );
|
|
}
|
|
mprintf( sX + uiCursorXPos, sY + iCounter * (GetFontHeight(ghTinyMonoFont)+1), L"%c", pToken[ i ] );
|
|
}
|
|
pToken = wcstok( NULL, L"\n" );
|
|
iCounter++;
|
|
}
|
|
}
|
|
|
|
void RenderFastHelp()
|
|
{
|
|
static INT32 iLastClock;
|
|
INT32 iTimeDifferential, iCurrentClock;
|
|
|
|
if( !gfRenderHilights )
|
|
return;
|
|
|
|
iCurrentClock = GetClock();
|
|
iTimeDifferential = iCurrentClock - iLastClock;
|
|
if (iTimeDifferential < 0)
|
|
iTimeDifferential += 0x7fffffff;
|
|
iLastClock = iCurrentClock;
|
|
|
|
if( MSYS_CurrRegion && MSYS_CurrRegion->FastHelpText && gfShowFastHelp )
|
|
{
|
|
if( !MSYS_CurrRegion->FastHelpTimer )
|
|
{
|
|
if( MSYS_CurrRegion->uiFlags & ( MSYS_ALLOW_DISABLED_FASTHELP | MSYS_REGION_ENABLED ) )
|
|
{
|
|
if( MSYS_CurrRegion->uiFlags & MSYS_MOUSE_IN_AREA )
|
|
{
|
|
MSYS_CurrRegion->uiFlags |= MSYS_FASTHELP;
|
|
DisplayFastHelp( MSYS_CurrRegion );
|
|
}
|
|
else
|
|
{
|
|
MSYS_CurrRegion->uiFlags &= ( ~( MSYS_FASTHELP | MSYS_FASTHELP_RESET ) );
|
|
VideoRemoveToolTip();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if( MSYS_CurrRegion->uiFlags & ( MSYS_ALLOW_DISABLED_FASTHELP | MSYS_REGION_ENABLED ) )
|
|
{
|
|
if ( MSYS_CurrRegion->uiFlags & MSYS_MOUSE_IN_AREA &&
|
|
!MSYS_CurrRegion->ButtonState)// & (MSYS_LEFT_BUTTON|MSYS_RIGHT_BUTTON)) )
|
|
{
|
|
MSYS_CurrRegion->FastHelpTimer -= (INT16)max( iTimeDifferential, 0 );
|
|
|
|
if( MSYS_CurrRegion->FastHelpTimer < 0 )
|
|
{
|
|
MSYS_CurrRegion->FastHelpTimer = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif
|
|
|
|
BOOLEAN SetRegionSavedRect( MOUSE_REGION *region)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
void FreeRegionSavedRect( MOUSE_REGION *region )
|
|
{
|
|
|
|
}
|
|
|
|
void MSYS_AllowDisabledRegionFastHelp( MOUSE_REGION *region, BOOLEAN fAllow )
|
|
{
|
|
if( fAllow )
|
|
{
|
|
region->uiFlags |= MSYS_ALLOW_DISABLED_FASTHELP;
|
|
}
|
|
else
|
|
{
|
|
region->uiFlags &= ~MSYS_ALLOW_DISABLED_FASTHELP;
|
|
}
|
|
}
|
|
|
|
// new stuff to allow mouse callbacks when help text finishes displaying
|
|
|
|
void SetRegionHelpEndCallback( MOUSE_REGION *region, MOUSE_HELPTEXT_DONE_CALLBACK CallbackFxn )
|
|
{
|
|
// make sure region is non null
|
|
if( region == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// now set the region help text
|
|
region->HelpDoneCallback = CallbackFxn;
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void ExecuteMouseHelpEndCallBack( MOUSE_REGION *region )
|
|
{
|
|
if( region == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
if( region->FastHelpTimer )
|
|
{
|
|
return;
|
|
}
|
|
// check if callback is non null
|
|
if( region->HelpDoneCallback == NULL )
|
|
{
|
|
return;
|
|
}
|
|
|
|
// we have a callback, excecute
|
|
// ATE: Disable these!
|
|
//( *( region->HelpDoneCallback ) )( );
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
void SetFastHelpDelay( INT16 sFastHelpDelay )
|
|
{
|
|
gsFastHelpDelay = sFastHelpDelay;
|
|
}
|
|
|
|
void EnableMouseFastHelp( void )
|
|
{
|
|
gfShowFastHelp = TRUE;
|
|
}
|
|
|
|
void DisableMouseFastHelp( void )
|
|
{
|
|
gfShowFastHelp = FALSE;
|
|
}
|
|
|
|
void ResetClickedMode(void)
|
|
{
|
|
gfClickedModeOn = FALSE;
|
|
}
|
|
|
|
// arynn : render mouse regions : mouse region list iteration initial
|
|
MOUSE_REGION *get_first_entry_in_MSYS_RegList(void)
|
|
{
|
|
return MSYS_RegList;
|
|
}
|
|
|
|
// arynn : render mouse regions : mouse region list iteration
|
|
MOUSE_REGION *get_next_entry_in_MSYS_RegList(MOUSE_REGION *current_region)
|
|
{
|
|
return current_region->next;
|
|
}
|