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.

833 lines
23 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/>.
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 "hsTypes.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 = TRACKED_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 = TRACKED_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( hsScalar x, hsScalar y, hsScalar 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 ///////////////////////////////////////////////////////////////////
hsBool pfGUIDialogMod::IEval( double secs, hsScalar del, UInt32 dirty )
{
return false;
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool 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 = TRACKED_NEW plAnimCmdMsg( GetKey(), fRenderMod->GetKey(), nil );
animMsg->SetCmd( plAnimCmdMsg::kContinue );
plgDispatch::MsgSend( animMsg );
}
}
else if( ref->GetContext() & ( plRefMsg::kOnRemove | plRefMsg::kOnDestroy ) )
{
plAnimCmdMsg *animMsg = TRACKED_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(), TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, fControls.GetCount() - 1, pfGUIDialogMod::kControlRef ), plRefFlags::kActiveRef );
}
//// SetEnabled //////////////////////////////////////////////////////////////
void pfGUIDialogMod::SetEnabled( hsBool 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 = TRACKED_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, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRenderModRef ), plRefFlags::kActiveRef );
s->Read( sizeof( fName ), fName );
UInt32 i, count = s->ReadSwap32();
fControls.SetCountAndZero( count );
for( i = 0; i < count; i++ )
mgr->ReadKeyNotifyMe( s, TRACKED_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 = TRACKED_NEW plGenRefMsg( mgrKey, plRefMsg::kOnCreate, 0, pfGameGUIMgr::kDlgModRef );
hsgResMgr::ResMgr()->AddViaNotify( GetKey(), refMsg, plRefFlags::kPassiveRef );
}
s->ReadSwap( &fTagID );
fProcReceiver = mgr->ReadKey( s );
if( fProcReceiver != nil )
SetHandler( TRACKED_NEW pfGUIDialogNotifyProc( fProcReceiver ) );
s->ReadSwap( &fVersion );
fColorScheme->Read( s );
fSceneNodeKey = mgr->ReadKey( s );
}
void pfGUIDialogMod::Write( hsStream *s, hsResMgr *mgr )
{
UInt32 i;
plSingleModifier::Write( s, mgr );
mgr->WriteKey( s, fRenderMod->GetKey() );
s->Write( sizeof( fName ), fName );
s->WriteSwap32( fControls.GetCount() );
for( i = 0; i < fControls.GetCount(); i++ )
mgr->WriteKey( s, fControls[ i ]->GetKey() );
s->WriteSwap( fTagID );
mgr->WriteKey( s, fProcReceiver );
s->WriteSwap( 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( hsScalar mouseX, hsScalar mouseY, UInt8 modifiers, hsBool 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
hsBool pfGUIDialogMod::HandleMouseEvent( pfGameGUIMgr::EventType event, hsScalar mouseX, hsScalar mouseY,
UInt8 modifiers )
{
hsPoint3 mousePoint;
UInt32 i;
pfGUIControlMod *oldInterestingCtrl = nil;
hsScalar smallestZ;
#ifdef HS_DEBUGGING // Debugging bounds rects
static bool showBounds = false;
if( showBounds )
{
UInt32 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)(sW * bnds.GetMins().fX),
(UInt16)(sH * bnds.GetMins().fY),
(UInt16)(sW * bnds.GetMaxs().fX),
(UInt16)(sH * bnds.GetMaxs().fY), 0x3000ffff, 0x3000ffff );
UInt32 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)(x - 2), (UInt16)(y - 2), (UInt16)(x + 2), (UInt16)(y + 2), color );
char str[ 16 ];
itoa( j, str, 10 );
plDebugText::Instance().DrawString( (UInt16)(x + 8), (UInt16)(y - 8), str, color );
}
}
else
{
const hsBounds3 &bnds = fControls[ i ]->GetBounds();
plDebugText::Instance().Draw3DBorder( (UInt16)(sW * bnds.GetMins().fX),
(UInt16)(sH * bnds.GetMins().fY),
(UInt16)(sW * bnds.GetMaxs().fX),
(UInt16)(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)(bnds.GetMins().fX), (UInt16)(bnds.GetMins().fY), fMousedCtrl->GetKeyName(), (UInt32)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 //////////////////////////////////////////////////////////
hsBool pfGUIDialogMod::HandleKeyEvent( pfGameGUIMgr::EventType event, plKeyDef key, UInt8 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 //////////////////////////////////////////////////////////
hsBool pfGUIDialogMod::HandleKeyPress( char key, UInt8 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 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 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 modifiers )
{
int i;
hsScalar 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 pfGUIDialogMod::GetDesiredCursor( void ) const
{
if( fMousedCtrl != nil )
return fMousedCtrl->IGetDesiredCursor();
return 0;
}