/*==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==*/ ////////////////////////////////////////////////////////////////////////////// // // // pfGUIDialogMod Definition // // // ////////////////////////////////////////////////////////////////////////////// #include "HeadSpin.h" #include "pfGameGUIMgr.h" #include "pfGUIDialogMod.h" #include "pfGUIControlMod.h" #include "pfGUIDialogHandlers.h" #include "pfGUIDialogNotifyProc.h" #include "pfGUIListElement.h" #include "plScene/plPostEffectMod.h" #include "pnMessage/plRefMsg.h" #include "pfMessage/pfGameGUIMsg.h" #include "plMessage/plAnimCmdMsg.h" #include "plScene/plSceneNode.h" #include "pnSceneObject/plSceneObject.h" #include "pnKeyedObject/plKey.h" #include "pnKeyedObject/plFixedKey.h" #include "pnSceneObject/plCoordinateInterface.h" #include "plStatusLog/plStatusLog.h" #include "plgDispatch.h" #include "hsResMgr.h" #include "plViewTransform.h" //// Constructor/Destructor ////////////////////////////////////////////////// pfGUIDialogMod::pfGUIDialogMod() : fRenderMod( nil ), fNext( nil ), fPrevPtr( nil ) { memset( fName, 0, sizeof( fName ) ); fEnabled = false; fControlOfInterest = nil; fFocusCtrl = nil; fMousedCtrl = nil; fTagID = 0; fHandler = nil; fVersion = 0; fDragMode = false; fDragReceptive = false; fDragTarget = nil; fProcReceiver = nil; fColorScheme = new pfGUIColorScheme(); } pfGUIDialogMod::~pfGUIDialogMod() { // Call the handler's destroy if there is one if( fHandler ) fHandler->OnDestroy(); // Unregister us with the Game GUI manager plUoid lu( kGameGUIMgr_KEY ); plKey mgrKey = hsgResMgr::ResMgr()->FindKey( lu ); if( mgrKey ) { plGenRefMsg *refMsg = new plGenRefMsg( mgrKey, plRefMsg::kOnRemove, 0, pfGameGUIMgr::kDlgModRef ); refMsg->SetRef( this ); plgDispatch::MsgSend( refMsg ); } SetHandler( nil ); hsRefCnt_SafeUnRef( fColorScheme ); fColorScheme = nil; } //// ScreenToWorldPoint ////////////////////////////////////////////////////// // Sometimes it just sucks not having access to the pipeline at just the // right time. void pfGUIDialogMod::ScreenToWorldPoint( float x, float y, float z, hsPoint3 &outPt ) { plViewTransform view = fRenderMod->GetViewTransform(); view.SetScreenSize( 1, 1 ); outPt = view.ScreenToWorld( hsPoint3( x, y, z ) ); } //// WorldToScreenPoint ////////////////////////////////////////////////////// // Given a point in world-space, translates it into screen coordinates // (with range 0-1, origin top-left). hsPoint3 pfGUIDialogMod::WorldToScreenPoint( const hsPoint3 &inPt ) { plViewTransform view = fRenderMod->GetViewTransform(); view.SetScreenSize( 1, 1 ); hsPoint3 tempPt = view.WorldToScreen( inPt ); tempPt.fZ = view.WorldToCamera( inPt ).fZ; return tempPt; } //// IEval /////////////////////////////////////////////////////////////////// bool pfGUIDialogMod::IEval( double secs, float del, uint32_t dirty ) { return false; } //// MsgReceive ////////////////////////////////////////////////////////////// bool pfGUIDialogMod::MsgReceive( plMessage *msg ) { plGenRefMsg *ref = plGenRefMsg::ConvertNoRef( msg ); if( ref ) { switch( ref->fType ) { case kRenderModRef: if( ref->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) ) { fRenderMod = plPostEffectMod::ConvertNoRef( ref->GetRef() ); fRenderMod->EnableLightsOnRenderRequest(); if( fEnabled ) { plAnimCmdMsg *animMsg = new plAnimCmdMsg( GetKey(), fRenderMod->GetKey(), nil ); animMsg->SetCmd( plAnimCmdMsg::kContinue ); plgDispatch::MsgSend( animMsg ); } } else if( ref->GetContext() & ( plRefMsg::kOnRemove | plRefMsg::kOnDestroy ) ) { plAnimCmdMsg *animMsg = new plAnimCmdMsg( GetKey(), fRenderMod->GetKey(), nil ); animMsg->SetCmd( plAnimCmdMsg::kStop ); plgDispatch::MsgSend( animMsg ); fRenderMod = nil; } break; case kControlRef: if( ref->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) ) { if( ref->fWhich >= fControls.GetCount() ) { hsAssert( false, "Bad index in reffing a control on a GUI dialog" ); } else { pfGUIControlMod *oldCtrl = fControls[ ref->fWhich ]; fControls[ ref->fWhich ] = pfGUIControlMod::ConvertNoRef( ref->GetRef() ); fControls[ ref->fWhich ]->ISetDialog( this ); if( oldCtrl != fControls[ ref->fWhich ] ) // They're equal on export time, when we DON'T want to be updating the bounds fControls[ ref->fWhich ]->CalcInitialBounds(); if( fControls[ ref->fWhich ]->HasFlag( pfGUIControlMod::kInheritProcFromDlg ) ) fControls[ ref->fWhich ]->ISetHandler( fHandler ); } } else if( ref->GetContext() & ( plRefMsg::kOnRemove | plRefMsg::kOnDestroy ) ) { if( ref->fWhich >= fControls.GetCount() ) { hsAssert( false, "Bad index in unreffing a control on a GUI dialog." ); } else { if( fControls[ ref->fWhich ] != nil ) fControls[ ref->fWhich ]->ISetDialog( nil ); fControls[ ref->fWhich ] = nil; } } break; } return true; } return plSingleModifier::MsgReceive( msg ); } //// AddControl ////////////////////////////////////////////////////////////// void pfGUIDialogMod::AddControl( pfGUIControlMod *ctrl ) { fControls.Append( ctrl ); ctrl->ISetDialog( this ); ctrl->CalcInitialBounds(); } //// AddControlOnExport ////////////////////////////////////////////////////// void pfGUIDialogMod::AddControlOnExport( pfGUIControlMod *ctrl ) { fControls.Append( ctrl ); hsgResMgr::ResMgr()->AddViaNotify( ctrl->GetKey(), new plGenRefMsg( GetKey(), plRefMsg::kOnCreate, fControls.GetCount() - 1, pfGUIDialogMod::kControlRef ), plRefFlags::kActiveRef ); } //// SetEnabled ////////////////////////////////////////////////////////////// void pfGUIDialogMod::SetEnabled( bool e ) { if( e == fEnabled ) return; fEnabled = e; if( fHandler != nil ) { if( fEnabled ) fHandler->OnShow(); else fHandler->OnHide(); } if ( !fEnabled ) { // if we are being hidden then there should be no controls that have interest fControlOfInterest = nil; // also we can purge the dynaText images on the controls int i; for( i = 0; i < fControls.GetCount(); i++ ) { if( fControls[ i ] == nil ) continue; fControls[ i ]->PurgeDynaTextMapImage(); } } if( fRenderMod != nil ) { plAnimCmdMsg *animMsg = new plAnimCmdMsg( GetKey(), fRenderMod->GetKey(), nil ); if( fEnabled ) { animMsg->SetCmd( plAnimCmdMsg::kContinue ); // Update the bounds on all controls that we own UpdateAllBounds(); } else animMsg->SetCmd( plAnimCmdMsg::kStop ); plgDispatch::MsgSend( animMsg ); } } //// Read/Write ////////////////////////////////////////////////////////////// void pfGUIDialogMod::Read( hsStream *s, hsResMgr *mgr ) { plSingleModifier::Read(s, mgr); mgr->ReadKeyNotifyMe( s, new plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRenderModRef ), plRefFlags::kActiveRef ); s->Read( sizeof( fName ), fName ); uint32_t i, count = s->ReadLE32(); fControls.SetCountAndZero( count ); for( i = 0; i < count; i++ ) mgr->ReadKeyNotifyMe( s, new plGenRefMsg( GetKey(), plRefMsg::kOnCreate, i, kControlRef ), plRefFlags::kActiveRef ); // Register us with the Game GUI manager plUoid lu( kGameGUIMgr_KEY ); plKey mgrKey = hsgResMgr::ResMgr()->FindKey( lu ); if( mgrKey ) { plGenRefMsg *refMsg = new plGenRefMsg( mgrKey, plRefMsg::kOnCreate, 0, pfGameGUIMgr::kDlgModRef ); hsgResMgr::ResMgr()->AddViaNotify( GetKey(), refMsg, plRefFlags::kPassiveRef ); } s->ReadLE( &fTagID ); fProcReceiver = mgr->ReadKey( s ); if( fProcReceiver != nil ) SetHandler( new pfGUIDialogNotifyProc( fProcReceiver ) ); s->ReadLE( &fVersion ); fColorScheme->Read( s ); fSceneNodeKey = mgr->ReadKey( s ); } void pfGUIDialogMod::Write( hsStream *s, hsResMgr *mgr ) { uint32_t i; plSingleModifier::Write( s, mgr ); mgr->WriteKey( s, fRenderMod->GetKey() ); s->Write( sizeof( fName ), fName ); s->WriteLE32( fControls.GetCount() ); for( i = 0; i < fControls.GetCount(); i++ ) mgr->WriteKey( s, fControls[ i ]->GetKey() ); s->WriteLE( fTagID ); mgr->WriteKey( s, fProcReceiver ); s->WriteLE( fVersion ); fColorScheme->Write( s ); mgr->WriteKey( s, fSceneNodeKey ); } plKey pfGUIDialogMod::GetSceneNodeKey( void ) { if( fSceneNodeKey != nil ) return fSceneNodeKey; // Attempt to grab it if( GetTarget() != nil && GetTarget()->GetSceneNode() != nil ) return ( fSceneNodeKey = GetTarget()->GetSceneNode() ); return nil; } //// UpdateInterestingThings ///////////////////////////////////////////////// // Really. We go through and make sure every control marked as interesting // still has the mouse inside it and vice versa. void pfGUIDialogMod::UpdateInterestingThings( float mouseX, float mouseY, uint8_t modifiers, bool modalPreset ) { int i; hsPoint3 mousePoint; mousePoint.Set( mouseX, mouseY, 0.f ); for( i = 0; i < fControls.GetCount(); i++ ) { if( fControls[ i ] == nil ) continue; // if there was a modal present and we are not modal, then everything is unInteresting! if ( modalPreset && !HasFlag(pfGUIDialogMod::kModal) ) { if( fControls[ i ]->IsInteresting() ) fControls[ i ]->SetInteresting( false ); } else { if( !fControls[ i ]->HasFlag( pfGUIControlMod::kIntangible ) && fControls[ i ]->PointInBounds( mousePoint ) || fControls[ i ] == fControlOfInterest ) { if( !fControls[ i ]->IsInteresting() ) fControls[ i ]->SetInteresting( true ); } else { if( fControls[ i ]->IsInteresting() ) fControls[ i ]->SetInteresting( false ); } } } } //// HandleMouseEvent //////////////////////////////////////////////////////// #ifdef HS_DEBUGGING // Debugging bounds rects #include "plPipeline/plDebugText.h" #endif bool pfGUIDialogMod::HandleMouseEvent( pfGameGUIMgr::EventType event, float mouseX, float mouseY, uint8_t modifiers ) { hsPoint3 mousePoint; uint32_t i; pfGUIControlMod *oldInterestingCtrl = nil; float smallestZ; #ifdef HS_DEBUGGING // Debugging bounds rects static bool showBounds = false; if( showBounds ) { uint32_t sW, sH; plDebugText::Instance().GetScreenSize(&sW,&sH); for( i = 0; i < fControls.GetCount(); i++ ) { if( fControls[ i ] == nil ) continue; if( fControls[ i ]->HasFlag( pfGUIControlMod::kIntangible ) ) continue; if( fControls[ i ]->fBoundsPoints.GetCount() > 0 ) { const hsBounds3 &bnds = fControls[ i ]->GetBounds(); plDebugText::Instance().Draw3DBorder( (uint16_t)(sW * bnds.GetMins().fX), (uint16_t)(sH * bnds.GetMins().fY), (uint16_t)(sW * bnds.GetMaxs().fX), (uint16_t)(sH * bnds.GetMaxs().fY), 0x3000ffff, 0x3000ffff ); uint32_t color = 0xffff0000; for( int j = 0; j < fControls[ i ]->fBoundsPoints.GetCount(); j++ ) { // color = 0xff000000 | ( ( j * 16 ) << 16 ); float x = sW * fControls[ i ]->fBoundsPoints[ j ].fX; float y = sH * fControls[ i ]->fBoundsPoints[ j ].fY; plDebugText::Instance().DrawRect( (uint16_t)(x - 2), (uint16_t)(y - 2), (uint16_t)(x + 2), (uint16_t)(y + 2), color ); char str[ 16 ]; snprintf(str, 16, "%d", j); plDebugText::Instance().DrawString( (uint16_t)(x + 8), (uint16_t)(y - 8), str, color ); } } else { const hsBounds3 &bnds = fControls[ i ]->GetBounds(); plDebugText::Instance().Draw3DBorder( (uint16_t)(sW * bnds.GetMins().fX), (uint16_t)(sH * bnds.GetMins().fY), (uint16_t)(sW * bnds.GetMaxs().fX), (uint16_t)(sH * bnds.GetMaxs().fY), 0x300000ff, 0x300000ff ); } } } #endif mousePoint.Set( mouseX, mouseY, 0.f ); if( fDragMode ) { IHandleDrag( mousePoint, event, modifiers ); return true; // We ALWAYS handle events if we're in drag mode } oldInterestingCtrl = fMousedCtrl; if( fControlOfInterest != nil ) { // A particular control already has interest--pass messages directly to it no matter what fMousedCtrl = fControlOfInterest; } else { for( i = 0, fMousedCtrl = nil, smallestZ = 1.e30f; i < fControls.GetCount(); i++ ) { if( fControls[ i ] != nil && !fControls[ i ]->HasFlag( pfGUIControlMod::kIntangible ) && fControls[ i ]->PointInBounds( mousePoint ) && fControls[ i ]->IsVisible() && fControls[ i ]->IsEnabled() ) { if( fControls[ i ]->GetScreenMinZ() < smallestZ ) { if( fControls[ i ]->FilterMousePosition( mousePoint ) ) { fMousedCtrl = fControls[ i ]; smallestZ = fControls[ i ]->GetScreenMinZ(); } } } } } if( fMousedCtrl != nil ) { #ifdef HS_DEBUGGING // Debugging bounds rects if( showBounds ) { const hsBounds3 &bnds = fMousedCtrl->GetBounds(); plDebugText::Instance().DrawString( (uint16_t)(bnds.GetMins().fX), (uint16_t)(bnds.GetMins().fY), fMousedCtrl->GetKeyName().c_str(), (uint32_t)0xffffff00 ); } #endif if( event == pfGameGUIMgr::kMouseDown ) { if( fMousedCtrl->HasFlag( pfGUIControlMod::kWantsInterest ) ) fControlOfInterest = fMousedCtrl; fMousedCtrl->HandleMouseDown( mousePoint, modifiers ); // Clicking on a control (mouse down) also sets focus to that control. Unlike // control-of-interest, this does NOT get reset until a new control is clicked on if( fFocusCtrl != fMousedCtrl ) { if( fHandler != nil ) fHandler->OnCtrlFocusChange( fFocusCtrl, fMousedCtrl ); if( fFocusCtrl != nil ) fFocusCtrl->SetFocused( false ); fFocusCtrl = fMousedCtrl; fFocusCtrl->SetFocused( true ); } } else if( event == pfGameGUIMgr::kMouseUp ) { fMousedCtrl->HandleMouseUp( mousePoint, modifiers ); // Controls lose interest on mouse up fControlOfInterest = nil; } else if( event == pfGameGUIMgr::kMouseMove ) fMousedCtrl->HandleMouseHover( mousePoint, modifiers ); else if( event == pfGameGUIMgr::kMouseDrag ) fMousedCtrl->HandleMouseDrag( mousePoint, modifiers ); else if( event == pfGameGUIMgr::kMouseDblClick ) fMousedCtrl->HandleMouseDblClick( mousePoint, modifiers ); return true; } // Clicked on nobody, make sure we lose focus on any controls if( fFocusCtrl != nil && event == pfGameGUIMgr::kMouseDown ) { if( fHandler != nil ) fHandler->OnCtrlFocusChange( fFocusCtrl, nil ); if( fFocusCtrl != nil ) // The handler call could've changed it fFocusCtrl->SetFocused( false ); fFocusCtrl = nil; } return false; } //// HandleKeyEvent ////////////////////////////////////////////////////////// bool pfGUIDialogMod::HandleKeyEvent( pfGameGUIMgr::EventType event, plKeyDef key, uint8_t modifiers ) { // Only process if a control has focus... if( fFocusCtrl != nil ) { // And guess what, it's up to that control to process it! Gee, how easy... return fFocusCtrl->HandleKeyEvent( event, key, modifiers ); } return false; } //// HandleKeyPress ////////////////////////////////////////////////////////// bool pfGUIDialogMod::HandleKeyPress( wchar_t key, uint8_t modifiers ) { // Same deal as HandleKeyPress. Only problem is, we needed the msg to translate // to a char, so it had to be done up at the mgr level (sadly) // Only process if a control has focus... if( fFocusCtrl != nil ) { return fFocusCtrl->HandleKeyPress( key, modifiers ); } return false; } //// SetFocus //////////////////////////////////////////////////////////////// void pfGUIDialogMod::SetFocus( pfGUIControlMod *ctrl ) { if( ctrl != nil && ctrl->fDialog != this ) { if( fHandler != nil ) fHandler->OnCtrlFocusChange( fFocusCtrl, nil ); if( fFocusCtrl != nil ) fFocusCtrl->SetFocused( false ); fFocusCtrl = nil; ctrl->fDialog->SetFocus( ctrl ); } else if( ctrl != fFocusCtrl ) { if( fFocusCtrl != nil ) fFocusCtrl->SetFocused( false ); if( fHandler != nil ) fHandler->OnCtrlFocusChange( fFocusCtrl, ctrl ); fFocusCtrl = ctrl; if( fFocusCtrl != nil ) fFocusCtrl->SetFocused( true ); } } //// Show/Hide /////////////////////////////////////////////////////////////// void pfGUIDialogMod::Show( void ) { pfGameGUIMgr::GetInstance()->ShowDialog( this ); } void pfGUIDialogMod::ShowNoReset( void ) { pfGameGUIMgr::GetInstance()->ShowDialog( this, false ); } void pfGUIDialogMod::Hide( void ) { pfGameGUIMgr::GetInstance()->HideDialog( this ); } //// GetControlFromTag /////////////////////////////////////////////////////// pfGUIControlMod *pfGUIDialogMod::GetControlFromTag( uint32_t tagID ) { int i; int ctrlCount = fControls.GetCount(); for( i = 0; i < ctrlCount; i++ ) { pfGUIControlMod *ctrl = fControls[i]; if( ctrl && ctrl->GetTagID() == tagID ) return fControls[ i ]; } return nil; } //// SetControlOfInterest //////////////////////////////////////////////////// void pfGUIDialogMod::SetControlOfInterest( pfGUIControlMod *c ) { fControlOfInterest = c; } //// SetHandler ////////////////////////////////////////////////////////////// void pfGUIDialogMod::SetHandler( pfGUIDialogProc *hdlr ) { int i; if( fHandler && fHandler->DecRef() ) delete fHandler; fHandler = hdlr; if( fHandler != nil ) { fHandler->IncRef(); fHandler->SetDialog( this ); } // We also set the handler for any controls that are flagged to inherit // from the parent dialog. Note that SetHandlerForAll() can thus be // seen as a function that forces this flag (temporarily) on all controls for( i = 0; i < fControls.GetCount(); i++ ) { // Test for nil controls since we get this also on destruct if( fControls[ i ] != nil && fControls[ i ]->HasFlag( pfGUIControlMod::kInheritProcFromDlg ) ) fControls[ i ]->ISetHandler( hdlr ); } } //// SetHandlerForAll //////////////////////////////////////////////////////// // Does SetHandler() for the dialog and all of its controls. Handy if you // have one of those all-encompasing dialog procs. :) void pfGUIDialogMod::SetHandlerForAll( pfGUIDialogProc *hdlr ) { int i; SetHandler( hdlr ); for( i = 0; i < fControls.GetCount(); i++ ) fControls[ i ]->ISetHandler( hdlr ); } //// SetControlHandler /////////////////////////////////////////////////////// void pfGUIDialogMod::SetControlHandler( uint32_t tagID, pfGUIDialogProc *hdlr ) { int i; for( i = 0; i < fControls.GetCount(); i++ ) { if( fControls[ i ]->GetTagID() == tagID ) { fControls[ i ]->SetHandler( hdlr ); break; } } } //// UpdateAspectRatio /////////////////////////////////////////////////////// void pfGUIDialogMod::UpdateAspectRatio( void ) { if (fRenderMod) { // Set width fov respecting height fov fRenderMod->SetFovX(pfGameGUIMgr::GetInstance()->GetAspectRatio() * fRenderMod->GetFovY()); } UpdateAllBounds(); } //// UpdateAllBounds ///////////////////////////////////////////////////////// void pfGUIDialogMod::UpdateAllBounds( void ) { int i; for( i = 0; i < fControls.GetCount(); i++ ) { if( fControls[ i ] != nil ) fControls[ i ]->UpdateBounds( nil, true ); } } //// RefreshAllControls ////////////////////////////////////////////////////// void pfGUIDialogMod::RefreshAllControls( void ) { int i; for( i = 0; i < fControls.GetCount(); i++ ) fControls[ i ]->IUpdate(); } ////////////////////////////////////////////////////////////////////////////// //// ListElement Drag Functions ////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// //// ClearDragList /////////////////////////////////////////////////////////// void pfGUIDialogMod::ClearDragList( void ) { fDragElements.Reset(); } //// AddToDragList /////////////////////////////////////////////////////////// void pfGUIDialogMod::AddToDragList( pfGUIListElement *e ) { fDragElements.Append( e ); } //// EnterDragMode /////////////////////////////////////////////////////////// void pfGUIDialogMod::EnterDragMode( pfGUIControlMod *source ) { if( fDragElements.GetCount() > 0 ) { fDragMode = true; fDragReceptive = false; fDragTarget = nil; fDragSource = source; } } //// IHandleDrag ///////////////////////////////////////////////////////////// // Oooh, we're in dragging-list-elements-around mode! So completely ignore // the normal way we do things; what we need to do is wait until the mouse // button is up, all the while testing to see if the control we're on top of // is capable of receiving the elements we have. Once the mouse button is let // up, if the control is indeed receptive, we call its drag handler for each // of our elements, and either way, exit drag mode. void pfGUIDialogMod::IHandleDrag( hsPoint3 &mousePoint, pfGameGUIMgr::EventType event, uint8_t modifiers ) { int i; float smallestZ; // First, see if our target control has changed for( i = 0, fMousedCtrl = nil, smallestZ = 1.e30f; i < fControls.GetCount(); i++ ) { if( fControls[ i ]->PointInBounds( mousePoint ) && fControls[ i ]->GetBounds().GetMaxs().fZ < smallestZ ) fMousedCtrl = fControls[ i ]; } if( fMousedCtrl != fDragTarget ) { // Target has changed, update our receptive flag fDragTarget = fMousedCtrl; if( fDragTarget == nil ) fDragReceptive = false; else { pfGUIDropTargetProc *dropProc = fDragTarget->GetDropTargetHdlr(); if( dropProc == nil ) fDragReceptive = false; else { fDragReceptive = true; for( i = 0; i < fDragElements.GetCount(); i++ ) { if( !dropProc->CanEat( fDragElements[ i ], fDragSource ) ) { fDragReceptive = false; break; } } } } } if( event == pfGameGUIMgr::kMouseUp ) { /// Mouse got let up--we're exiting drag mode, but can we process the drop? fDragMode = false; if( fDragReceptive ) { pfGUIDropTargetProc *dropProc = fDragTarget->GetDropTargetHdlr(); for( i = 0; i < fDragElements.GetCount(); i++ ) dropProc->Eat( fDragElements[ i ], fDragSource, fDragTarget ); } } } //// GetDesiredCursor //////////////////////////////////////////////////////// uint32_t pfGUIDialogMod::GetDesiredCursor( void ) const { if( fMousedCtrl != nil ) return fMousedCtrl->IGetDesiredCursor(); return 0; }