/*==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 . 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(); } } }