|
|
|
/*==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 ];
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|