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.
832 lines
23 KiB
832 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; |
|
} |
|
|
|
|