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.

849 lines
27 KiB

/*==LICENSE==*
CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011 Cyan Worlds, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
Additional permissions under GNU GPL version 3 section 7
If you modify this Program, or any covered work, by linking or
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK,
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK
(or a modified version of those libraries),
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA,
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the
licensors of this Program grant you additional
permission to convey the resulting work. Corresponding Source for a
non-source form of such a combination shall include the source code for
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered
work.
You can contact Cyan Worlds, Inc. by email legal@cyan.com
or by snail mail at:
Cyan Worlds, Inc.
14617 N Newport Hwy
Mead, WA 99021
*==LICENSE==*/
//////////////////////////////////////////////////////////////////////////////
// //
// 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 ];
snprintf(str, 16, "%d", j);
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( wchar_t 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;
}