You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

964 lines
31 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGameGUIMgr //
// //
//// History /////////////////////////////////////////////////////////////////
// //
// 11.13.2001 mcn - Created //
// //
//////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include "hsTimer.h"
#include "HeadSpin.h"
#include "pfGameGUIMgr.h"
#include "pfGUIDialogMod.h"
#include "pfGUIDialogHandlers.h"
#include "pfGUIDialogNotifyProc.h"
#include "pfGUIControlMod.h"
#include "pfGUIPopUpMenu.h"
#include "pfMessage/pfGameGUIMsg.h"
#include "plMessage/plInputEventMsg.h"
#include "plMessage/plInputIfaceMgrMsg.h"
#include "pnMessage/plClientMsg.h"
#include "pnNetCommon/plSynchedObject.h"
#include "plInputCore/plInputInterface.h"
#include "plInputCore/plInputDevice.h"
#include "plInputCore/plInputInterfaceMgr.h"
#include "pnInputCore/plKeyMap.h"
#include "pnKeyedObject/plFixedKey.h"
#include "pnSceneObject/plSceneObject.h" // So we can get the target sceneNode of a dialog
#include "plMessage/plConsoleMsg.h"
#include "plgDispatch.h"
#include "plResMgr/plKeyFinder.h"
#include "pfGUITagDefs.h"
//////////////////////////////////////////////////////////////////////////////
//// pfGameUIInputInterface Definition ///////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
class pfGameUIInputInterface : public plInputInterface
{
protected:
pfGameGUIMgr * const fGUIManager;
uint8_t fModifiers;
uint8_t fButtonState;
hsBool fHaveInterestingCursor;
uint32_t fCurrentCursor;
virtual hsBool IHandleCtrlCmd( plCtrlCmd *cmd );
virtual hsBool IControlCodeEnabled( ControlEventCode code );
public:
pfGameUIInputInterface( pfGameGUIMgr * const mgr );
virtual uint32_t GetPriorityLevel( void ) const { return kGUISystemPriority; }
virtual hsBool InterpretInputEvent( plInputEventMsg *pMsg );
virtual uint32_t GetCurrentCursorID( void ) const;
virtual float GetCurrentCursorOpacity( void ) const;
virtual hsBool HasInterestingCursorID( void ) const { return fHaveInterestingCursor; }
virtual hsBool SwitchInterpretOrder( void ) const { return true; }
virtual void RestoreDefaultKeyMappings( void )
{
if( fControlMap != nil )
{
fControlMap->UnmapAllBindings();
fControlMap->BindKey( KEY_BACKSPACE, B_CONTROL_EXIT_GUI_MODE, plKeyMap::kFirstAlways );
fControlMap->BindKey( KEY_ESCAPE, B_CONTROL_EXIT_GUI_MODE, plKeyMap::kSecondAlways );
}
}
};
//////////////////////////////////////////////////////////////////////////////
//// pfGameGUIMgr Functions //////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
pfGameGUIMgr *pfGameGUIMgr::fInstance = nil;
//// Constructor & Destructor ////////////////////////////////////////////////
pfGameGUIMgr::pfGameGUIMgr()
{
fActivated = false;
fInputCtlIndex = 0;
fActiveDialogs = nil;
fInputConfig = nil;
fInstance = this;
fDefaultCursor = plInputInterface::kCursorUp;
fCursorOpacity = 1.f;
fAspectRatio = 0;
}
pfGameGUIMgr::~pfGameGUIMgr()
{
int i;
// the GUIMgr is dead!
fInstance = nil;
for( i = 0; i < fDialogs.GetCount(); i++ )
UnloadDialog( fDialogs[ i ] );
for( i = 0; i < fDialogToSetKeyOf.GetCount(); i++ )
delete fDialogToSetKeyOf[i];
if( fActivated )
IActivateGUI( false );
delete fInputConfig;
}
//// Init ////////////////////////////////////////////////////////////////////
hsBool pfGameGUIMgr::Init( void )
{
return true;
}
//// Draw ////////////////////////////////////////////////////////////////////
void pfGameGUIMgr::Draw( plPipeline *p )
{
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGameGUIMgr::MsgReceive( plMessage* pMsg )
{
pfGameGUIMsg *guiMsg = pfGameGUIMsg::ConvertNoRef( pMsg );
if( guiMsg != nil )
{
if( guiMsg->GetCommand() == pfGameGUIMsg::kLoadDialog )
LoadDialog( guiMsg->GetString(), nil, guiMsg->GetAge() );
else if( guiMsg->GetCommand() == pfGameGUIMsg::kShowDialog )
IShowDialog( guiMsg->GetString() );
else if( guiMsg->GetCommand() == pfGameGUIMsg::kHideDialog )
IHideDialog( guiMsg->GetString() );
return true;
}
plGenRefMsg *refMsg = plGenRefMsg::ConvertNoRef( pMsg );
if( refMsg != nil )
{
if( refMsg->fType == kDlgModRef )
{
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest ) )
{
IAddDlgToList( refMsg->GetRef() );
}
else if( refMsg->GetContext() & plRefMsg::kOnReplace )
{
IRemoveDlgFromList( refMsg->GetOldRef() );
IAddDlgToList( refMsg->GetRef() );
}
else if( refMsg->GetContext() & ( plRefMsg::kOnRemove | plRefMsg::kOnDestroy ) )
{
IRemoveDlgFromList( refMsg->GetRef() );
}
}
return true;
}
return hsKeyedObject::MsgReceive( pMsg );
}
//// IAddDlgToList ///////////////////////////////////////////////////////////
void pfGameGUIMgr::IAddDlgToList( hsKeyedObject *obj )
{
int i;
if( fDialogs.Find( (pfGUIDialogMod *)obj ) == fDialogs.kMissingIndex )
{
pfGUIDialogMod *mod = pfGUIDialogMod::ConvertNoRef( obj );
if( mod != nil )
{
mod->UpdateAspectRatio(); // adding a new dialog, make sure the correct aspect ratio is set
fDialogs.Append( mod );
// check to see if it is the dialog we are waiting for to be loaded
for ( i=0 ; i<fDialogToSetKeyOf.Count() ; i++ )
{
if ( strcmp(fDialogToSetKeyOf[i]->GetName(), mod->GetName()) == 0 )
{
SetDialogToNotify(mod,fDialogToSetKeyOf[i]->GetKey());
// now remove this entry... we did it
delete fDialogToSetKeyOf[i];
fDialogToSetKeyOf.Remove(i);
// that's all the damage we can do for now...
break;
}
}
}
}
/* // It's now officially "loaded"; take it off the pending list
for( i = 0; i < fDlgsPendingLoad.GetCount(); i++ )
{
if( stricmp( fDlgsPendingLoad[ i ]->GetName(), ( (pfGUIDialogMod *)obj )->GetName() ) == 0 )
{
// Here it is
delete fDlgsPendingLoad[ i ];
fDlgsPendingLoad.Remove( i );
break;
}
}
*/
}
//// IRemoveDlgFromList //////////////////////////////////////////////////////
void pfGameGUIMgr::IRemoveDlgFromList( hsKeyedObject *obj )
{
int idx = fDialogs.Find( (pfGUIDialogMod *)obj );
if( idx != fDialogs.kMissingIndex )
{
pfGUIDialogMod *mod = pfGUIDialogMod::ConvertNoRef( obj );
hsAssert( mod != nil, "Non-dialog sent to gameGUIMgr::IRemoveDlg()" );
if( mod != nil )
{
if( mod->IsEnabled() )
{
mod->SetEnabled( false );
mod->Unlink();
if( fActiveDialogs == nil )
IActivateGUI( false );
}
// Needed?
// GetKey()->Release( mod->GetKey() );
fDialogs.Remove( idx );
}
}
// It's now officially "unloaded"; take it off the pending list
/* int i;
for( i = 0; i < fDlgsPendingUnload.GetCount(); i++ )
{
if( stricmp( fDlgsPendingUnload[ i ]->GetName(), ( (pfGUIDialogMod *)obj )->GetName() ) == 0 )
{
// Here it is
delete fDlgsPendingUnload[ i ];
fDlgsPendingUnload.Remove( i );
break;
}
}
*/
}
//// LoadDialog //////////////////////////////////////////////////////////////
void pfGameGUIMgr::LoadDialog( const char *name, plKey recvrKey, const char *ageName )
{
// see if they want to set the receiver key once the dialog is loaded
if ( recvrKey != nil )
{
// first see if we are loading a dialog that is already being loaded
bool alreadyLoaded = false;
int i;
for ( i=0 ; i<fDialogToSetKeyOf.Count() ; i++ )
{
if ( strcmp(fDialogToSetKeyOf[i]->GetName(), name) == 0 )
{
alreadyLoaded = true;
break;
}
}
if (!alreadyLoaded)
{
pfDialogNameSetKey* pDNSK = new pfDialogNameSetKey(name,recvrKey);
fDialogToSetKeyOf.Append(pDNSK);
}
}
hsStatusMessageF("\nLoading Dialog %s %s ... %f\n", name, ( ageName != nil ) ? ageName : "GUI", hsTimer::GetSeconds() );
plKey clientKey = hsgResMgr::ResMgr()->FindKey( kClient_KEY );
plClientMsg *msg = new plClientMsg( plClientMsg::kLoadRoomHold );
msg->AddReceiver( clientKey );
msg->AddRoomLoc(plKeyFinder::Instance().FindLocation(ageName ? ageName : "GUI", name));
msg->Send();
// Now add this dialog to a list of pending loads (will remove it once it's fully loaded)
// fDlgsPendingLoad.Append( new pfDialogNameSetKey( name, nil ) );
}
//// IShowDialog /////////////////////////////////////////////////////////////
void pfGameGUIMgr::IShowDialog( const char *name )
{
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
if( stricmp( fDialogs[ i ]->GetName(), name ) == 0 )
{
ShowDialog( fDialogs[ i ] );
fDialogs[i]->RefreshAllControls();
break;
}
}
}
//// IHideDialog /////////////////////////////////////////////////////////////
void pfGameGUIMgr::IHideDialog( const char *name )
{
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
if( stricmp( fDialogs[ i ]->GetName(), name ) == 0 )
{
HideDialog( fDialogs[ i ] );
break;
}
}
}
//// ShowDialog //////////////////////////////////////////////////////////////
void pfGameGUIMgr::ShowDialog( pfGUIDialogMod *dlg, bool resetClickables /* = true */ )
{
if ( resetClickables )
plInputInterfaceMgr::GetInstance()->ResetClickableState();
if( !dlg->IsEnabled() )
{
dlg->SetEnabled( true );
// Add to active list
if( fActiveDialogs == nil )
IActivateGUI( true );
dlg->LinkToList( &fActiveDialogs );
return;
}
}
//// HideDialog //////////////////////////////////////////////////////////////
void pfGameGUIMgr::HideDialog( pfGUIDialogMod *dlg )
{
if( dlg->IsEnabled() )
{
dlg->SetEnabled( false );
dlg->Unlink();
if( fActiveDialogs == nil )
IActivateGUI( false );
}
}
//// UnloadDialog ////////////////////////////////////////////////////////////
// Destroy the dialog and all the things associated with it. Fun fun.
void pfGameGUIMgr::UnloadDialog( const char *name )
{
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
if( stricmp( fDialogs[ i ]->GetName(), name ) == 0 )
{
UnloadDialog( fDialogs[ i ] );
break;
}
}
}
void pfGameGUIMgr::UnloadDialog( pfGUIDialogMod *dlg )
{
// IRemoveDlgFromList( dlg );
// Add the name to our list of dialogs pending unload
// fDlgsPendingUnload.Append( new pfDialogNameSetKey( dlg->GetName(), nil ) );
plKey sceneNodeKey = dlg->GetSceneNodeKey();
if( sceneNodeKey == nil )
{
hsStatusMessageF( "Warning: Unable to grab sceneNodeKey to unload dialog %s; searching for it...", dlg->GetName() );
sceneNodeKey = plKeyFinder::Instance().FindSceneNodeKey( dlg->GetKey()->GetUoid().GetLocation() );
}
// if( dlg->GetTarget() )
if( sceneNodeKey != nil )
{
plKey clientKey = hsgResMgr::ResMgr()->FindKey( kClient_KEY );
plClientMsg *msg = new plClientMsg( plClientMsg::kUnloadRoom );
msg->AddReceiver( clientKey );
// msg->SetProgressBarSuppression( true );
msg->AddRoomLoc(sceneNodeKey->GetUoid().GetLocation());
msg->Send();
}
// GetKey()->Release( dlg->GetKey() );
}
//// IsDialogLoaded ////// see if the dialog is in our list of loaded dialogs
hsBool pfGameGUIMgr::IsDialogLoaded( const char *name )
{
// search through all the dialogs we've loaded
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
if( stricmp( fDialogs[ i ]->GetName(), name ) == 0 )
{
// found 'em
return true;
}
}
// nota
return false;
}
pfGUIPopUpMenu *pfGameGUIMgr::FindPopUpMenu( const char *name )
{
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
pfGUIPopUpMenu *menu = pfGUIPopUpMenu::ConvertNoRef( fDialogs[ i ] );
if( menu != nil && stricmp( menu->GetName(), name ) == 0 )
return menu;
}
return nil;
}
std::vector<plPostEffectMod*> pfGameGUIMgr::GetDlgRenderMods( void ) const
{
std::vector<plPostEffectMod*> retVal;
pfGUIDialogMod* curDialog = fActiveDialogs;
while (curDialog)
{
retVal.push_back(curDialog->GetRenderMod());
curDialog = curDialog->GetNext();
}
return retVal;
}
///// SetDialogToNotify - based on name
// This will Set the handler to a Notify Handler that will send a GUINotifyMsg to the receiver
//
void pfGameGUIMgr::SetDialogToNotify(const char *name, plKey recvrKey)
{
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
if( stricmp( fDialogs[ i ]->GetName(), name ) == 0 )
{
SetDialogToNotify( fDialogs[ i ], recvrKey );
break;
}
}
}
///// SetDialogToNotify - pfGUIDialogMod*
// This will Set the handler to a Notify Handler that will send a GUINotifyMsg to the receiver
//
void pfGameGUIMgr::SetDialogToNotify(pfGUIDialogMod *dlg, plKey recvrKey)
{
pfGUIDialogNotifyProc* handler = new pfGUIDialogNotifyProc(recvrKey);
dlg->SetHandler(handler);
handler->OnInit();
}
//// IActivateGUI ////////////////////////////////////////////////////////////
// "Activates" the GUI manager. This means enabling the drawing of GUI
// elements on the screen as well as rerouting input to us.
void pfGameGUIMgr::IActivateGUI( hsBool activate )
{
if( fActivated == activate )
return;
if( activate )
{
fInputConfig = new pfGameUIInputInterface( this );
plInputIfaceMgrMsg *msg = new plInputIfaceMgrMsg( plInputIfaceMgrMsg::kAddInterface );
msg->SetIFace( fInputConfig );
plgDispatch::MsgSend( msg );
}
else
{
plInputIfaceMgrMsg *msg = new plInputIfaceMgrMsg( plInputIfaceMgrMsg::kRemoveInterface );
msg->SetIFace( fInputConfig );
plgDispatch::MsgSend( msg );
hsRefCnt_SafeUnRef( fInputConfig );
fInputConfig = nil;
}
fActivated = activate;
}
//// IHandleMouse ////////////////////////////////////////////////////////////
// Distributes mouse events to the dialogs currently active
hsBool pfGameGUIMgr::IHandleMouse( EventType event, float mouseX, float mouseY, uint8_t modifiers, uint32_t *desiredCursor )
{
pfGUIDialogMod *dlg;
// Update interesting things first, no matter what, for ALL dialogs
hsBool modalPresent = false;
for( dlg = fActiveDialogs; dlg != nil; dlg = dlg->GetNext() )
{
dlg->UpdateInterestingThings( mouseX, mouseY, modifiers, modalPresent );
if (dlg->HasFlag( pfGUIDialogMod::kModal ))
modalPresent = true;
}
for( dlg = fActiveDialogs; dlg != nil; dlg = dlg->GetNext() )
{
if( dlg->HandleMouseEvent( event, mouseX, mouseY, modifiers ) ||
( dlg->HasFlag( pfGUIDialogMod::kModal ) && event != pfGameGUIMgr::kMouseUp ) )
{
// If this dialog handled it, also get the cursor it wants
*desiredCursor = dlg->GetDesiredCursor();
return true;
}
}
return false;
}
//// IHandleKeyEvt ///////////////////////////////////////////////////////////
// Distributes mouse events to the dialogs currently active
hsBool pfGameGUIMgr::IHandleKeyEvt( EventType event, plKeyDef key, uint8_t modifiers )
{
pfGUIDialogMod *dlg;
for( dlg = fActiveDialogs; dlg != nil; dlg = dlg->GetNext() )
{
if( dlg->HandleKeyEvent( event, key, modifiers ) )
return true;
}
return false;
}
//// IHandleKeyPress /////////////////////////////////////////////////////////
// Like IHandleKeyPress, but takes in a char for distributing actual
// characters typed.
hsBool pfGameGUIMgr::IHandleKeyPress( wchar_t key, uint8_t modifiers )
{
pfGUIDialogMod *dlg;
// Really... Don't handle any nil keypresses
if (key == nil)
return false;
for( dlg = fActiveDialogs; dlg != nil; dlg = dlg->GetNext() )
{
if( dlg->HandleKeyPress( key, modifiers ) )
return true;
}
return false;
}
//// IModalBlocking //////////////////////////////////////////////////////////
// Looks at the chain of active dialogs and determines if there's any modals
// blocking input. Returns true if so.
hsBool pfGameGUIMgr::IModalBlocking( void )
{
return ( IGetTopModal() != nil ) ? true : false;
}
//// IGetTopModal ////////////////////////////////////////////////////////////
// Returns the topmost (visible) modal dialog, nil if none.
pfGUIDialogMod *pfGameGUIMgr::IGetTopModal( void ) const
{
pfGUIDialogMod *dlg;
for( dlg = fActiveDialogs; dlg != nil; dlg = dlg->GetNext() )
{
if( dlg->HasFlag( pfGUIDialogMod::kModal ) )
return dlg;
}
return nil;
}
//////////////////////////////////////////////////////////////////////////////
//// Control Config Class ////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
pfGameUIInputInterface::pfGameUIInputInterface( pfGameGUIMgr * const mgr ) : plInputInterface(), fGUIManager( mgr )
{
fModifiers = pfGameGUIMgr::kNoModifiers;
fButtonState = 0;
fHaveInterestingCursor = false;
SetEnabled( true ); // Always enabled
fCurrentCursor = kCursorUp;
// Add our control codes to our control map. Do NOT add the key bindings yet.
// Note: HERE is where you specify the actions for each command, i.e. net propagate and so forth.
// This part basically declares us master of the bindings for these commands.
// IF YOU ARE LOOKING TO CHANGE THE DEFAULT KEY BINDINGS, DO NOT LOOK HERE. GO TO
// RestoreDefaultKeyMappings()!!!!
fControlMap->AddCode( B_CONTROL_EXIT_GUI_MODE, kControlFlagNormal | kControlFlagNoRepeat );
// IF YOU ARE LOOKING TO CHANGE THE DEFAULT KEY BINDINGS, DO NOT LOOK HERE. GO TO
// RestoreDefaultKeyMappings()!!!!
}
hsBool pfGameUIInputInterface::IControlCodeEnabled( ControlEventCode code )
{
if( code == B_CONTROL_EXIT_GUI_MODE )
{
// Disable the exitGUIMode key binding if we don't have a modal dialog up or if
// the cursor is inside an edit or multiline edit control
if( !fGUIManager->IModalBlocking() )
return false;
pfGUIDialogMod *dlg = fGUIManager->IGetTopModal();
if( dlg != nil )
{
pfGUIControlMod *ctrl = dlg->GetFocus();
if( ctrl != nil && ctrl->HasFlag( pfGUIControlMod::kTakesSpecialKeys ) )
return false;
}
}
return true; // Enable all other codes
}
hsBool pfGameUIInputInterface::IHandleCtrlCmd( plCtrlCmd *cmd )
{
if( cmd->fControlCode == B_CONTROL_EXIT_GUI_MODE )
{
if( cmd->fControlActivated )
{
pfGUIDialogMod *dlg = fGUIManager->IGetTopModal();
if( dlg != nil && dlg->GetHandler() != nil )
dlg->GetHandler()->OnControlEvent( pfGUIDialogProc::kExitMode );
}
return true;
}
return false;
}
hsBool pfGameUIInputInterface::InterpretInputEvent( plInputEventMsg *pMsg )
{
hsBool handled = false;
/// The in-game UI has to do far more complicated control handling, so we just overload this entirely
plKeyEventMsg *pKeyMsg = plKeyEventMsg::ConvertNoRef( pMsg );
if( pKeyMsg )
{
// By default, we don't want the modifier keys treated as "handled", 'cause
// we want the other interfaces to get them as well (unless we have a modal
// as the top dialog).
if( pKeyMsg->GetKeyCode() == KEY_SHIFT )
{
if( pKeyMsg->GetKeyDown() )
fModifiers |= pfGameGUIMgr::kShiftDown;
else
fModifiers &= ~pfGameGUIMgr::kShiftDown;
}
else if( pKeyMsg->GetKeyCode() == KEY_CTRL )
{
if( pKeyMsg->GetKeyDown() )
fModifiers |= pfGameGUIMgr::kCtrlDown;
else
fModifiers &= ~pfGameGUIMgr::kCtrlDown;
}
else if( pKeyMsg->GetKeyCode() == KEY_CAPSLOCK )
{
if( pKeyMsg->GetKeyDown() )
fModifiers |= pfGameGUIMgr::kCapsDown;
else
fModifiers &= ~pfGameGUIMgr::kCapsDown;
}
else
{
// Sometimes I can't explain why Mathew does some of the things he does.
// I going to replace his modifier flags (which I don't know why he thought he had to have his own)
// with the ones that are in the keymsg since they seem to be more accurate!
fModifiers = 0;
if ( pKeyMsg->GetShiftKeyDown() )
fModifiers |= pfGameGUIMgr::kShiftDown;
if ( pKeyMsg->GetCtrlKeyDown() )
fModifiers |= pfGameGUIMgr::kCtrlDown;
if ( pKeyMsg->GetCapsLockKeyDown() )
fModifiers |= pfGameGUIMgr::kCapsDown;
if( pKeyMsg->GetKeyDown() )
{
if( !pKeyMsg->GetRepeat() )
handled = fGUIManager->IHandleKeyEvt( pfGameGUIMgr::kKeyDown, pKeyMsg->GetKeyCode(), fModifiers );
else
handled = fGUIManager->IHandleKeyEvt( pfGameGUIMgr::kKeyRepeat, pKeyMsg->GetKeyCode(), fModifiers );
if (pKeyMsg->GetKeyChar())
handled |= fGUIManager->IHandleKeyPress( pKeyMsg->GetKeyChar(), fModifiers );
}
else
handled = fGUIManager->IHandleKeyEvt( pfGameGUIMgr::kKeyUp, pKeyMsg->GetKeyCode(), fModifiers );
}
// We need to do early interception of a screenshot request, since they want
// us to be able to take screen shots while in a modal GUI... whee
// Also, this should only be run if the dialog didn't handle the command in
// the first place (taking screenshots while the user is typing would be
// awkward) and we must do it on key down because the key binding routines
// also trigger on key-down and we don't want to be taking screen shots when
// the user re-binds the screenshot command.
// HACK HACK HACK
if ((!handled) && (pKeyMsg->GetKeyDown()) && !pKeyMsg->GetKeyChar())
{
const plKeyBinding* keymap = plInputInterfaceMgr::GetInstance()->FindBindingByConsoleCmd("Game.KITakePicture");
if (keymap)
{
unsigned keyFlags = 0;
if (pKeyMsg->GetCtrlKeyDown())
keyFlags |= plKeyCombo::kCtrl;
if (pKeyMsg->GetShiftKeyDown())
keyFlags |= plKeyCombo::kShift;
plKeyCombo combo(pKeyMsg->GetKeyCode(), keyFlags);
if ((keymap->GetKey1().IsSatisfiedBy(combo)) || (keymap->GetKey2().IsSatisfiedBy(combo)))
{
// tell the KI to take the shot
plConsoleMsg * consoleMsg = NEWZERO(plConsoleMsg);
consoleMsg->SetCmd(plConsoleMsg::kExecuteLine);
consoleMsg->SetString("Game.KITakePicture");
consoleMsg->Send(nil, true);
}
}
}
bool modal = fGUIManager->IModalBlocking();
return handled || modal; // we "handle" it if we are modal, even if it didn't do anything
}
plMouseEventMsg *pMouseMsg = plMouseEventMsg::ConvertNoRef( pMsg );
if( pMouseMsg && fManager->IsClickEnabled() )
{
if( pMouseMsg->GetButton() == kLeftButtonDown )
{
handled = fGUIManager->IHandleMouse( pfGameGUIMgr::kMouseDown, pMouseMsg->GetXPos(), pMouseMsg->GetYPos(), fModifiers, &fCurrentCursor );
if (handled)
fButtonState |= kLeftButtonDown;
}
else if( pMouseMsg->GetButton() == kLeftButtonUp )
{
handled = fGUIManager->IHandleMouse( pfGameGUIMgr::kMouseUp, pMouseMsg->GetXPos(), pMouseMsg->GetYPos(), fModifiers, &fCurrentCursor );
if ((handled) || (fButtonState & kLeftButtonDown)) // even if we didn't handle the mouse up, if we think the button is still down, we should clear our flag
fButtonState &= ~kLeftButtonDown;
}
else if( pMouseMsg->GetButton() == kLeftButtonDblClk )
handled = fGUIManager->IHandleMouse( pfGameGUIMgr::kMouseDblClick, pMouseMsg->GetXPos(), pMouseMsg->GetYPos(), fModifiers, &fCurrentCursor );
else if( fButtonState & kLeftButtonDown )
handled = fGUIManager->IHandleMouse( pfGameGUIMgr::kMouseDrag, pMouseMsg->GetXPos(), pMouseMsg->GetYPos(), fModifiers, &fCurrentCursor );
else
handled = fGUIManager->IHandleMouse( pfGameGUIMgr::kMouseMove, pMouseMsg->GetXPos(), pMouseMsg->GetYPos(), fModifiers, &fCurrentCursor );
fHaveInterestingCursor = handled;
return handled;
}
return false;
}
uint32_t pfGameUIInputInterface::GetCurrentCursorID( void ) const
{
if( fCurrentCursor == 0 )
{
if ( pfGameGUIMgr::GetInstance() )
return pfGameGUIMgr::GetInstance()->GetDefaultCursor();
else
return kCursorUp;
}
return fCurrentCursor;
}
float pfGameUIInputInterface::GetCurrentCursorOpacity( void ) const
{
if ( pfGameGUIMgr::GetInstance() )
return pfGameGUIMgr::GetInstance()->GetCursorOpacity();
else
return 1.f;
}
//////////////////////////////////////////////////////////////////////////////
//// Tag Stuff ///////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
extern pfGUITag gGUITags[]; // From pfGUITagDefs.cpp
//// GetDialogFromTag ////////////////////////////////////////////////////////
pfGUIDialogMod *pfGameGUIMgr::GetDialogFromTag( uint32_t tagID )
{
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
if( fDialogs[ i ]->GetTagID() == tagID )
return fDialogs[ i ];
}
return nil;
}
//// GetDialogFromString ////////////////////////////////////////////////////////
pfGUIDialogMod *pfGameGUIMgr::GetDialogFromString( const char *name )
{
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
if( stricmp( fDialogs[ i ]->GetName(), name ) == 0 )
return fDialogs[ i ];
}
return nil;
}
//// GetControlFromTag ///////////////////////////////////////////////////////
pfGUIControlMod *pfGameGUIMgr::GetControlFromTag( pfGUIDialogMod *dlg, uint32_t tagID )
{
return dlg->GetControlFromTag( tagID );
}
//// GetNumTags //////////////////////////////////////////////////////////////
uint32_t pfGameGUIMgr::GetNumTags( void )
{
uint32_t count;
for( count = 0; gGUITags[ count ].fID != 0; count++ );
return count;
}
//// GetTag //////////////////////////////////////////////////////////////////
pfGUITag *pfGameGUIMgr::GetTag( uint32_t tagIndex )
{
uint32_t count;
for( count = 0; gGUITags[ count ].fID != 0; count++ );
hsAssert( tagIndex < count, "Bad index to GetTag()" );
return &gGUITags[ tagIndex ];
}
uint32_t pfGameGUIMgr::GetHighestTag( void )
{
uint32_t i, id = 1;
for( i = 0; gGUITags[ i ].fID != 0; i++ )
{
if( id < gGUITags[ i ].fID )
id = gGUITags[ i ].fID;
}
return id;
}
void pfGameGUIMgr::SetAspectRatio(float aspectratio)
{
float oldAspectRatio = fAspectRatio;
// don't allow the aspectratio below 4:3
float fourThree = 4.0f/3.0f;
fAspectRatio = aspectratio < fourThree ? fourThree : aspectratio;
if (fAspectRatio != oldAspectRatio)
{
// need to tell dialogs to update
int i;
for (i = 0; i < fDialogs.GetCount(); i++)
{
if (fDialogs[i])
fDialogs[i]->UpdateAspectRatio();
}
}
}