/*==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 . 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 #include "hsTimer.h" #include "hsTypes.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 fModifiers; UInt8 fButtonState; hsBool fHaveInterestingCursor; UInt32 fCurrentCursor; virtual hsBool IHandleCtrlCmd( plCtrlCmd *cmd ); virtual hsBool IControlCodeEnabled( ControlEventCode code ); public: pfGameUIInputInterface( pfGameGUIMgr * const mgr ); virtual UInt32 GetPriorityLevel( void ) const { return kGUISystemPriority; } virtual hsBool InterpretInputEvent( plInputEventMsg *pMsg ); virtual UInt32 GetCurrentCursorID( void ) const; virtual hsScalar 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 ; iGetName(), mod->GetName()) ) { 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 ; iGetName(), name) ) { alreadyLoaded = true; break; } } if (!alreadyLoaded) { pfDialogNameSetKey* pDNSK = TRACKED_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 = TRACKED_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( TRACKED_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( TRACKED_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 = TRACKED_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 pfGameGUIMgr::GetDlgRenderMods( void ) const { std::vector 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 = TRACKED_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 = TRACKED_NEW pfGameUIInputInterface( this ); plInputIfaceMgrMsg *msg = TRACKED_NEW plInputIfaceMgrMsg( plInputIfaceMgrMsg::kAddInterface ); msg->SetIFace( fInputConfig ); plgDispatch::MsgSend( msg ); } else { plInputIfaceMgrMsg *msg = TRACKED_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, hsScalar mouseX, hsScalar mouseY, UInt8 modifiers, UInt32 *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 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( char key, UInt8 modifiers ) { pfGUIDialogMod *dlg; 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 ); handled |= fGUIManager->IHandleKeyPress( plKeyboardDevice::KeyEventToChar( pKeyMsg ), 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())) { 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 pfGameUIInputInterface::GetCurrentCursorID( void ) const { if( fCurrentCursor == 0 ) { if ( pfGameGUIMgr::GetInstance() ) return pfGameGUIMgr::GetInstance()->GetDefaultCursor(); else return kCursorUp; } return fCurrentCursor; } hsScalar 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 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 tagID ) { return dlg->GetControlFromTag( tagID ); } //// GetNumTags ////////////////////////////////////////////////////////////// UInt32 pfGameGUIMgr::GetNumTags( void ) { UInt32 count; for( count = 0; gGUITags[ count ].fID != 0; count++ ); return count; } //// GetTag ////////////////////////////////////////////////////////////////// pfGUITag *pfGameGUIMgr::GetTag( UInt32 tagIndex ) { UInt32 count; for( count = 0; gGUITags[ count ].fID != 0; count++ ); hsAssert( tagIndex < count, "Bad index to GetTag()" ); return &gGUITags[ tagIndex ]; } UInt32 pfGameGUIMgr::GetHighestTag( void ) { UInt32 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(hsScalar aspectratio) { hsScalar oldAspectRatio = fAspectRatio; // don't allow the aspectratio below 4:3 hsScalar 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(); } } }