2
3
mirror of https://foundry.openuru.org/gitblit/r/CWE-ou-minkata.git synced 2025-07-14 02:27:40 -04:00

Initial Commit of CyanWorlds.com Engine Open Source Client/Plugin

This commit is contained in:
JWPlatt
2011-03-12 12:34:52 -05:00
commit a20a222fc2
3976 changed files with 1301356 additions and 0 deletions

View File

@ -0,0 +1,392 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIButtonMod Definition //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUIButtonMod.h"
#include "pfGUIDraggableMod.h"
#include "pfGameGUIMgr.h"
#include "pfGUIControlHandlers.h"
#include "pfGUIDialogMod.h"
#include "../plInputCore/plInputInterface.h"
#include "../pnMessage/plRefMsg.h"
#include "../pfMessage/pfGameGUIMsg.h"
#include "../plMessage/plAnimCmdMsg.h"
#include "../plAvatar/plAGModifier.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Control Proc For Managing the Draggable /////////////////////////////////
class pfGUIButtonDragProc : public pfGUICtrlProcObject
{
protected:
pfGUICtrlProcObject *fOrigProc;
pfGUIButtonMod *fParent;
pfGUIDraggableMod *fDraggable;
hsBool fReportDrag;
public:
pfGUIButtonDragProc( pfGUIButtonMod *parent, pfGUIDraggableMod *draggable, pfGUICtrlProcObject *origProc, hsBool reportDrag )
{
fParent = parent;
fDraggable = draggable;
fOrigProc = origProc;
fReportDrag = reportDrag;
}
virtual void DoSomething( pfGUIControlMod *ctrl )
{
// The draggable was let up, so now we stop dragging, disable the draggable again, and pass
// on the event to our original proc
if( fOrigProc != nil && fParent->IsTriggering() )
fOrigProc->DoSomething( ctrl );
if (!fParent->IsButtonDown())
fParent->StopDragging( false );
}
virtual void HandleExtendedEvent( pfGUIControlMod *ctrl, UInt32 event )
{
if( event == pfGUIDraggableMod::kDragging )
{
// First test if we're inside our button (if so, we stop dragging)
if( fParent->PointInBounds( fDraggable->GetLastMousePt() ) )
{
// Cancel the drag
fParent->StopDragging( true );
return;
}
if( !fReportDrag )
return;
}
if( fOrigProc != nil )
fOrigProc->HandleExtendedEvent( ctrl, event );
}
virtual void UserCallback( UInt32 userValue )
{
if( fOrigProc != nil )
fOrigProc->UserCallback( userValue );
}
};
void pfGUIButtonMod::StopDragging( hsBool cancel )
{
fDraggable->StopDragging( cancel );
fDraggable->SetVisible( false );
fDraggable->SetHandler( fOrigHandler );
fOrigHandler = nil;
if( !fOrigReportedDrag )
fDraggable->ClearFlag( pfGUIDraggableMod::kReportDragging );
// Steal interest back
fDialog->SetControlOfInterest( this );
}
void pfGUIButtonMod::StartDragging( void )
{
fOrigReportedDrag = fDraggable->HasFlag( pfGUIDraggableMod::kReportDragging );
fDraggable->SetFlag( pfGUIDraggableMod::kReportDragging );
fOrigHandler = fDraggable->GetHandler();
fDraggable->SetVisible( true );
fDraggable->SetHandler( TRACKED_NEW pfGUIButtonDragProc( this, fDraggable, fOrigHandler, fOrigReportedDrag ) );
fDraggable->HandleMouseDown( fOrigMouseDownPt, 0 );
}
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIButtonMod::pfGUIButtonMod()
{
fAnimName = nil;
fMouseOverAnimName = nil;
fDraggable = nil;
fOrigHandler = nil;
fClicking = false;
fTriggering = false;
fNotifyType = kNotifyOnUp;
SetFlag( kWantsInterest );
}
pfGUIButtonMod::~pfGUIButtonMod()
{
delete [] fAnimName;
delete [] fMouseOverAnimName;
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool pfGUIButtonMod::IEval( double secs, hsScalar del, UInt32 dirty )
{
return pfGUIControlMod::IEval( secs, del, dirty );
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGUIButtonMod::MsgReceive( plMessage *msg )
{
plGenRefMsg *refMsg = plGenRefMsg::ConvertNoRef( msg );
if( refMsg != nil && refMsg->fType == kRefDraggable )
{
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
{
fDraggable = pfGUIDraggableMod::ConvertNoRef( refMsg->GetRef() );
fDraggable->SetVisible( false ); // Disable until we're dragging
}
else
fDraggable = nil;
return true;
}
return pfGUIControlMod::MsgReceive( msg );
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUIButtonMod::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Read(s, mgr);
fAnimationKeys.Reset();
UInt32 i, count = s->ReadSwap32();
for( i = 0; i < count; i++ )
fAnimationKeys.Append( mgr->ReadKey( s ) );
fAnimName = s->ReadSafeString();
fMouseOverAnimKeys.Reset();
count = s->ReadSwap32();
for( i = 0; i < count; i++ )
fMouseOverAnimKeys.Append( mgr->ReadKey( s ) );
fMouseOverAnimName = s->ReadSafeString();
fNotifyType = s->ReadSwap32();
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefDraggable ), plRefFlags::kActiveRef );
}
void pfGUIButtonMod::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Write( s, mgr );
UInt32 i, count = fAnimationKeys.GetCount();
s->WriteSwap32( count );
for( i = 0; i < count; i++ )
mgr->WriteKey( s, fAnimationKeys[ i ] );
s->WriteSafeString( fAnimName );
count = fMouseOverAnimKeys.GetCount();
s->WriteSwap32( count );
for( i = 0; i < count; i++ )
mgr->WriteKey( s, fMouseOverAnimKeys[ i ] );
s->WriteSafeString( fMouseOverAnimName );
s->WriteSwap32( fNotifyType );
mgr->WriteKey( s, fDraggable != nil ? fDraggable->GetKey() : nil );
}
//// UpdateBounds ////////////////////////////////////////////////////////////
void pfGUIButtonMod::UpdateBounds( hsMatrix44 *invXformMatrix, hsBool force )
{
pfGUIControlMod::UpdateBounds( invXformMatrix, force );
if( fAnimationKeys.GetCount() > 0 || fMouseOverAnimKeys.GetCount() > 0 )
fBoundsValid = false;
}
//// HandleMouseDown/Up //////////////////////////////////////////////////////
void pfGUIButtonMod::HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers )
{
fClicking = true;
if( fAnimationKeys.GetCount() > 0 )
{
plAnimCmdMsg *msg = TRACKED_NEW plAnimCmdMsg();
msg->SetCmd( plAnimCmdMsg::kContinue );
msg->SetCmd( plAnimCmdMsg::kSetForewards );
msg->SetCmd( plAnimCmdMsg::kGoToBegin );
msg->SetAnimName( fAnimName );
msg->AddReceivers( fAnimationKeys );
plgDispatch::MsgSend( msg );
}
IPlaySound( kMouseDown );
fOrigMouseDownPt = mousePt;
if ( fNotifyType == kNotifyOnDown || fNotifyType == kNotifyOnUpAndDown)
{
fTriggering = true;
DoSomething();
fTriggering = false;
}
}
void pfGUIButtonMod::HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers )
{
// make sure that we got the down click first
if ( !fClicking )
return;
fClicking = false;
if( fAnimationKeys.GetCount() > 0 )
{
plAnimCmdMsg *msg = TRACKED_NEW plAnimCmdMsg();
msg->SetCmd( plAnimCmdMsg::kContinue );
msg->SetCmd( plAnimCmdMsg::kSetBackwards );
msg->SetCmd( plAnimCmdMsg::kGoToEnd );
msg->SetAnimName( fAnimName );
msg->AddReceivers( fAnimationKeys );
plgDispatch::MsgSend( msg );
}
IPlaySound( kMouseUp );
// Don't run the command if the mouse is outside our bounds
if( !fBounds.IsInside( &mousePt ) && fNotifyType != kNotifyOnUpAndDown )
return;
if ( fNotifyType == kNotifyOnUp || fNotifyType == kNotifyOnUpAndDown)
fTriggering = true;
DoSomething();
fTriggering = false;
}
void pfGUIButtonMod::HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers )
{
if( !fClicking )
return;
if( fDraggable == nil )
return;
if( !fDraggable->IsVisible() )
{
// Are we outside ourselves?
if( !PointInBounds( mousePt ) )
{
// Yes, start dragging
StartDragging();
// Hand off our interest to the draggable
fDialog->SetControlOfInterest( fDraggable );
}
}
}
void pfGUIButtonMod::SetNotifyType(Int32 kind)
{
fNotifyType = kind;
}
Int32 pfGUIButtonMod::GetNotifyType()
{
return fNotifyType;
}
hsBool pfGUIButtonMod::IsButtonDown()
{
return fClicking;
}
//// SetInteresting //////////////////////////////////////////////////////////
// Overridden to play mouse over animation when we're interesting
void pfGUIButtonMod::SetInteresting( hsBool i )
{
pfGUIControlMod::SetInteresting( i );
if( fMouseOverAnimKeys.GetCount() )
{
plAnimCmdMsg *msg = TRACKED_NEW plAnimCmdMsg();
msg->SetCmd( plAnimCmdMsg::kContinue );
msg->SetCmd( fInteresting ? plAnimCmdMsg::kSetForewards : plAnimCmdMsg::kSetBackwards );
msg->SetAnimName( fMouseOverAnimName );
msg->AddReceivers( fMouseOverAnimKeys );
plgDispatch::MsgSend( msg );
}
if( i )
IPlaySound( kMouseOver );
else
IPlaySound( kMouseOff );
}
void pfGUIButtonMod::SetAnimationKeys( hsTArray<plKey> &keys, const char *name )
{
fAnimationKeys = keys;
delete [] fAnimName;
if( name != nil )
{
fAnimName = TRACKED_NEW char[ strlen( name ) + 1 ];
strcpy( fAnimName, name );
}
else
fAnimName = nil;
}
void pfGUIButtonMod::SetMouseOverAnimKeys( hsTArray<plKey> &keys, const char *name )
{
fMouseOverAnimKeys = keys;
delete [] fMouseOverAnimName;
if( name != nil )
{
fMouseOverAnimName = TRACKED_NEW char[ strlen( name ) + 1 ];
strcpy( fMouseOverAnimName, name );
}
else
fMouseOverAnimName = nil;
}
//// IGetDesiredCursor ///////////////////////////////////////////////////////
UInt32 pfGUIButtonMod::IGetDesiredCursor( void ) const
{
if( fHandler == nil )
return 0;
if( fClicking )
return plInputInterface::kCursorClicked;
return plInputInterface::kCursorPoised;
}

View File

@ -0,0 +1,121 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIButtonMod Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIButtonMod_h
#define _pfGUIButtonMod_h
#include "pfGUIControlMod.h"
class plMessage;
class plPostEffectMod;
class plAGMasterMod;
class pfGUIDraggableMod;
class pfGUIButtonMod : public pfGUIControlMod
{
protected:
hsTArray<plKey> fAnimationKeys;
char *fAnimName;
hsTArray<plKey> fMouseOverAnimKeys;
char *fMouseOverAnimName;
hsBool fClicking;
hsBool fTriggering;
hsPoint3 fOrigMouseDownPt;
pfGUIDraggableMod *fDraggable;
pfGUICtrlProcObject *fOrigHandler;
hsBool fOrigReportedDrag;
Int32 fNotifyType;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
virtual UInt32 IGetDesiredCursor( void ) const; // As specified in plInputInterface.h
public:
pfGUIButtonMod();
virtual ~pfGUIButtonMod();
CLASSNAME_REGISTER( pfGUIButtonMod );
GETINTERFACE_ANY( pfGUIButtonMod, pfGUIControlMod );
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
virtual void SetInteresting( hsBool i );
virtual void HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers );
virtual void UpdateBounds( hsMatrix44 *invXformMatrix = nil, hsBool force = false );
virtual void SetNotifyType(Int32 kind);
virtual Int32 GetNotifyType();
virtual hsBool IsButtonDown();
virtual hsBool IsTriggering() { return fTriggering; }
enum SoundEvents
{
kMouseDown,
kMouseUp,
kMouseOver,
kMouseOff
};
enum
{
kRefDraggable = kRefDerivedStart
};
enum NotifyType
{
kNotifyOnUp = 0,
kNotifyOnDown,
kNotifyOnUpAndDown
};
void StartDragging( void );
void StopDragging( hsBool cancel );
// Export only
void SetAnimationKeys( hsTArray<plKey> &keys, const char *name );
void SetMouseOverAnimKeys( hsTArray<plKey> &keys, const char *name );
};
#endif // _pfGUIButtonMod_h

View File

@ -0,0 +1,206 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUICheckBoxCtrl Definition //
// //
// Almost like buttons, only they keep their stated (pressed/unpressed) //
// when you click them, instead of reverting on mouse up. //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUICheckBoxCtrl.h"
#include "pfGameGUIMgr.h"
#include "../plInputCore/plInputInterface.h"
#include "../pnMessage/plRefMsg.h"
#include "../pfMessage/pfGameGUIMsg.h"
#include "../plMessage/plAnimCmdMsg.h"
#include "../plAvatar/plAGModifier.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUICheckBoxCtrl::pfGUICheckBoxCtrl()
{
fAnimName = nil;
SetFlag( kWantsInterest );
fChecked = false;
fClicking = false;
fPlaySound = true;
}
pfGUICheckBoxCtrl::~pfGUICheckBoxCtrl()
{
delete [] fAnimName;
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool pfGUICheckBoxCtrl::IEval( double secs, hsScalar del, UInt32 dirty )
{
return pfGUIControlMod::IEval( secs, del, dirty );
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGUICheckBoxCtrl::MsgReceive( plMessage *msg )
{
return pfGUIControlMod::MsgReceive( msg );
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUICheckBoxCtrl::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Read(s, mgr);
fAnimationKeys.Reset();
UInt32 i, count = s->ReadSwap32();
for( i = 0; i < count; i++ )
fAnimationKeys.Append( mgr->ReadKey( s ) );
fAnimName = s->ReadSafeString();
fChecked = s->ReadBool();
}
void pfGUICheckBoxCtrl::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Write( s, mgr );
UInt32 i, count = fAnimationKeys.GetCount();
s->WriteSwap32( count );
for( i = 0; i < count; i++ )
mgr->WriteKey( s, fAnimationKeys[ i ] );
s->WriteSafeString( fAnimName );
s->WriteBool( fChecked );
}
//// UpdateBounds ////////////////////////////////////////////////////////////
void pfGUICheckBoxCtrl::UpdateBounds( hsMatrix44 *invXformMatrix, hsBool force )
{
pfGUIControlMod::UpdateBounds( invXformMatrix, force );
if( fAnimationKeys.GetCount() > 0 )
fBoundsValid = false;
}
//// HandleMouseDown/Up //////////////////////////////////////////////////////
void pfGUICheckBoxCtrl::HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers )
{
fClicking = true;
if(fPlaySound)
IPlaySound( kMouseDown );
}
void pfGUICheckBoxCtrl::HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers )
{
if( fClicking )
{
fClicking = false;
if(fPlaySound)
IPlaySound( kMouseUp );
// Don't run the command if the mouse is outside our bounds
if( fBounds.IsInside( &mousePt ) )
{
SetChecked( !fChecked );
DoSomething();
}
}
}
//// SetChecked //////////////////////////////////////////////////////////////
void pfGUICheckBoxCtrl::SetChecked( hsBool checked, hsBool immediate /*= false*/ )
{
fChecked = checked;
if( fAnimationKeys.GetCount() > 0 )
{
plAnimCmdMsg *msg = TRACKED_NEW plAnimCmdMsg();
if( fChecked )
{
// Moving to true
if( immediate )
{
msg->SetCmd( plAnimCmdMsg::kGoToEnd );
}
else
{
msg->SetCmd( plAnimCmdMsg::kContinue );
msg->SetCmd( plAnimCmdMsg::kSetForewards );
msg->SetCmd( plAnimCmdMsg::kGoToBegin );
}
}
else
{
// Moving to false
if( immediate )
{
msg->SetCmd( plAnimCmdMsg::kGoToBegin );
}
else
{
msg->SetCmd( plAnimCmdMsg::kContinue );
msg->SetCmd( plAnimCmdMsg::kSetBackwards );
msg->SetCmd( plAnimCmdMsg::kGoToEnd );
}
}
msg->SetAnimName( fAnimName );
msg->AddReceivers( fAnimationKeys );
plgDispatch::MsgSend( msg );
}
}
void pfGUICheckBoxCtrl::SetAnimationKeys( hsTArray<plKey> &keys, const char *name )
{
fAnimationKeys = keys;
delete [] fAnimName;
if( name != nil )
{
fAnimName = TRACKED_NEW char[ strlen( name ) + 1 ];
strcpy( fAnimName, name );
}
else
fAnimName = nil;
}
//// IGetDesiredCursor ///////////////////////////////////////////////////////
UInt32 pfGUICheckBoxCtrl::IGetDesiredCursor( void ) const
{
if( fClicking )
return plInputInterface::kCursorClicked;
return plInputInterface::kCursorPoised;
}

View File

@ -0,0 +1,95 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUICheckBoxCtrl Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUICheckBoxCtrl_h
#define _pfGUICheckBoxCtrl_h
#include "pfGUIControlMod.h"
class plMessage;
class plPostEffectMod;
class plAGMasterMod;
class pfGUICheckBoxCtrl : public pfGUIControlMod
{
protected:
hsTArray<plKey> fAnimationKeys;
char *fAnimName;
hsBool fClicking;
hsBool fChecked;
hsBool fPlaySound;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
virtual UInt32 IGetDesiredCursor( void ) const; // As specified in plInputInterface.h
public:
pfGUICheckBoxCtrl();
virtual ~pfGUICheckBoxCtrl();
CLASSNAME_REGISTER( pfGUICheckBoxCtrl );
GETINTERFACE_ANY( pfGUICheckBoxCtrl, pfGUIControlMod );
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
virtual void HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers );
virtual void UpdateBounds( hsMatrix44 *invXformMatrix = nil, hsBool force = false );
void SetChecked( hsBool checked, hsBool immediate = false );
hsBool IsChecked( void ) { return fChecked; }
void DontPlaySounds() { fPlaySound = false; } // should the checkbox play sounds?
const hsTArray<plKey> &GetAnimationKeys( void ) const { return fAnimationKeys; }
const char *GetAnimationName( void ) const { return fAnimName; }
enum SoundEvents
{
kMouseDown,
kMouseUp,
kMouseOver,
kMouseOff
};
// Export only
void SetAnimationKeys( hsTArray<plKey> &keys, const char *name );
};
#endif // _pfGUICheckBoxCtrl_h

View File

@ -0,0 +1,130 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIClickMapCtrl Definition //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUIClickMapCtrl.h"
#include "pfGameGUIMgr.h"
#include "pfGUIDialogMod.h"
#include "../plInputCore/plInputInterface.h"
#include "../pnMessage/plRefMsg.h"
#include "../pfMessage/pfGameGUIMsg.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIClickMapCtrl::pfGUIClickMapCtrl()
{
fTracking = false;
fCustomCursor = -1;
}
pfGUIClickMapCtrl::~pfGUIClickMapCtrl()
{
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool pfGUIClickMapCtrl::IEval( double secs, hsScalar del, UInt32 dirty )
{
return pfGUIControlMod::IEval( secs, del, dirty );
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGUIClickMapCtrl::MsgReceive( plMessage *msg )
{
return pfGUIControlMod::MsgReceive( msg );
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUIClickMapCtrl::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Read(s, mgr);
}
void pfGUIClickMapCtrl::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Write( s, mgr );
}
void pfGUIClickMapCtrl::HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers )
{
IScreenToLocalPt( mousePt );
fLastMousePt = fLastMouseDragPt = mousePt;
fTracking = true;
}
void pfGUIClickMapCtrl::HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers )
{
if( fTracking )
{
IScreenToLocalPt( mousePt );
fLastMousePt = fLastMouseUpPt = fLastMouseDragPt = mousePt;
DoSomething();
fTracking = false;
}
}
void pfGUIClickMapCtrl::HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers )
{
if( fTracking )
{
IScreenToLocalPt( mousePt );
fLastMousePt = fLastMouseDragPt = mousePt;
if( HasFlag( kReportDragging ) )
HandleExtendedEvent( kMouseDragged );
}
}
void pfGUIClickMapCtrl::HandleMouseHover( hsPoint3 &mousePt, UInt8 modifiers )
{
IScreenToLocalPt( mousePt );
fLastMousePt = mousePt;
if( HasFlag( kReportHovering ) )
HandleExtendedEvent( kMouseHovered );
}
//// IGetDesiredCursor ///////////////////////////////////////////////////////
UInt32 pfGUIClickMapCtrl::IGetDesiredCursor( void ) const
{
if( fCustomCursor != -1 )
return (UInt32)fCustomCursor;
return plInputInterface::kCursorPoised;
}

View File

@ -0,0 +1,89 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIClickMapCtrl Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIClickMapCtrl_h
#define _pfGUIClickMapCtrl_h
#include "pfGUIControlMod.h"
class plMessage;
class pfGUIClickMapCtrl : public pfGUIControlMod
{
protected:
hsPoint3 fLastMousePt, fLastMouseUpPt, fLastMouseDragPt;
hsBool fTracking;
Int32 fCustomCursor;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
virtual UInt32 IGetDesiredCursor( void ) const; // As specified in plInputInterface.h
public:
pfGUIClickMapCtrl();
virtual ~pfGUIClickMapCtrl();
CLASSNAME_REGISTER( pfGUIClickMapCtrl );
GETINTERFACE_ANY( pfGUIClickMapCtrl, pfGUIControlMod );
enum OurFlags
{
kReportDragging = kDerivedFlagsStart,
kReportHovering
};
// Extended event types
enum ExtendedEvents
{
kMouseDragged,
kMouseHovered
};
virtual void HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseHover( hsPoint3 &mousePt, UInt8 modifiers );
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
const hsPoint3 &GetLastMousePt( void ) const { return fLastMousePt; }
const hsPoint3 &GetLastMouseUpPt( void ) const { return fLastMouseUpPt; }
const hsPoint3 &GetLastMouseDragPt( void ) const { return fLastMouseDragPt; }
void SetCustomCursor( Int32 cursor = -1 ) { fCustomCursor = cursor; }
};
#endif // _pfGUIClickMapCtrl_h

View File

@ -0,0 +1,186 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIControl Handler Definitions //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUIControlHandlers.h"
#include "pfGUIControlMod.h"
#include "pfGUIDialogMod.h"
#include "../plMessage/plConsoleMsg.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Writeable Stuff /////////////////////////////////////////////////////////
void pfGUICtrlProcWriteableObject::Write( pfGUICtrlProcWriteableObject *obj, hsStream *s )
{
if( obj != nil )
{
s->WriteSwap32( obj->fType );
obj->IWrite( s );
}
else
s->WriteSwap32( kNull );
}
pfGUICtrlProcWriteableObject *pfGUICtrlProcWriteableObject::Read( hsStream *s )
{
pfGUICtrlProcWriteableObject *obj;
UInt32 type = s->ReadSwap32();
switch( type )
{
case kConsoleCmd:
obj = TRACKED_NEW pfGUIConsoleCmdProc;
break;
case kPythonScript:
obj = TRACKED_NEW pfGUIPythonScriptProc;
break;
case kCloseDlg:
obj = TRACKED_NEW pfGUICloseDlgProc;
break;
case kNull:
return nil;
default:
hsAssert( false, "Invalid proc type in Read()" );
return nil;
}
obj->IRead( s );
return obj;
}
//////////////////////////////////////////////////////////////////////////////
//// Predefined Exportables //////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//// pfGUIConsoleCmdProc /////////////////////////////////////////////////////
pfGUIConsoleCmdProc::pfGUIConsoleCmdProc() : pfGUICtrlProcWriteableObject( kConsoleCmd )
{
fCommand = nil;
}
pfGUIConsoleCmdProc::pfGUIConsoleCmdProc( const char *cmd )
: pfGUICtrlProcWriteableObject( kConsoleCmd )
{
fCommand = nil;
SetCommand( cmd );
}
pfGUIConsoleCmdProc::~pfGUIConsoleCmdProc()
{
delete [] fCommand;
}
void pfGUIConsoleCmdProc::IRead( hsStream *s )
{
int i = s->ReadSwap32();
if( i > 0 )
{
fCommand = TRACKED_NEW char[ i + 1 ];
memset( fCommand, 0, i + 1 );
s->Read( i, fCommand );
}
else
fCommand = nil;
}
void pfGUIConsoleCmdProc::IWrite( hsStream *s )
{
if( fCommand != nil )
{
s->WriteSwap32( strlen( fCommand ) );
s->Write( strlen( fCommand ), fCommand );
}
else
s->WriteSwap32( 0 );
}
void pfGUIConsoleCmdProc::DoSomething( pfGUIControlMod *ctrl )
{
if( fCommand != nil )
{
plConsoleMsg *cMsg = TRACKED_NEW plConsoleMsg( plConsoleMsg::kExecuteLine, fCommand );
plgDispatch::MsgSend( cMsg );
}
}
void pfGUIConsoleCmdProc::SetCommand( const char *cmd )
{
delete [] fCommand;
if( cmd == nil )
fCommand = nil;
else
{
fCommand = TRACKED_NEW char[ strlen( cmd ) + 1 ];
memset( fCommand, 0, strlen( cmd ) + 1 );
strcpy( fCommand, cmd );
}
}
//// pfGUIPythonScriptProc ///////////////////////////////////////////////////
pfGUIPythonScriptProc::pfGUIPythonScriptProc() : pfGUICtrlProcWriteableObject( kPythonScript )
{
}
pfGUIPythonScriptProc::~pfGUIPythonScriptProc()
{
}
void pfGUIPythonScriptProc::IRead( hsStream *s )
{
}
void pfGUIPythonScriptProc::IWrite( hsStream *s )
{
}
void pfGUIPythonScriptProc::DoSomething( pfGUIControlMod *ctrl )
{
}
//////////////////////////////////////////////////////////////////////////////
//// Simple Runtime Ones /////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
void pfGUICloseDlgProc::DoSomething( pfGUIControlMod *ctrl )
{
ctrl->GetOwnerDlg()->Hide();
}

View File

@ -0,0 +1,180 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIControlHandlers Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIControlHandlers_h
#define _pfGUIControlHandlers_h
#include "hsStream.h"
//// pfGUICtrlProcObject Definition //////////////////////////////////////////
// Any control which "does something" (buttons, edit boxes on Enter/Return,
// etc) uses this in some form. Basically, each control will have an (optional?)
// pointer to an object derived from this class type. The class has a single
// standard, virtual function that gets called on the "do something" event.
// Derive from this class, override the virtual and set the control's handler
// to your object and you're all set. Kinda like windowProcs wrapped in a
// C++ object.
// Note: there are some predefined objects for simple, common events. See
// below.
// Note the second: DoSomething() takes a parameter--namely, a pointer to
// the control that called it. Thus, you can make one object handle
// several controls by just switch()ing on that parameter and save yourself
// some object creation.
//
// UserCallback() is an additional function for use in communicating between
// procs. Basically, if you want another proc to do something (another dialog),
// and want you to get called once it's done, set the callback on the other
// proc/whatever to you and override UserCallback().
//
// HandleExtendedEvent() is similar to DoSomething(), but is called for extended
// event types, such as value changing (for an edit control while typing) or
// list scrolled. The event parameter is control-type-specific.
//
// Dialogs will use a similar functionality, but with more functions available.
class pfGUIControlMod;
class pfGUICtrlProcObject
{
protected:
UInt32 fRefCnt;
public:
pfGUICtrlProcObject() { fRefCnt = 0; }
virtual ~pfGUICtrlProcObject() { ; }
virtual void DoSomething( pfGUIControlMod *ctrl ) = 0;
virtual void HandleExtendedEvent( pfGUIControlMod *ctrl, UInt32 event ) { ; }
virtual void UserCallback( UInt32 userValue ) { ; }
// ONLY THE GUI SYSTEM SHOULD CALL THESE
void IncRef( void ) { fRefCnt++; }
hsBool DecRef( void ) { fRefCnt--; return ( fRefCnt > 0 ) ? false : true; }
};
//// pfGUICtrlProcWriteableObject ////////////////////////////////////////////
// This one is a read/writeable version of the above. Basically, you can just
// call Read/Write() and it'll do all the mini-functionality of the factory
// stuff so you don't have to worry about the derived type at runtime. Do
// NOT derive from this class for your own handlers; this is just for the
// handfull that will get added on export.
class pfGUICtrlProcWriteableObject : public pfGUICtrlProcObject
{
protected:
UInt32 fType;
virtual void IRead( hsStream *s ) = 0;
virtual void IWrite( hsStream *s ) = 0;
public:
enum Types
{
kNull,
kConsoleCmd,
kPythonScript,
kCloseDlg
};
pfGUICtrlProcWriteableObject() { fType = kNull; }
pfGUICtrlProcWriteableObject( UInt32 type ) : fType( type ) { ; }
virtual ~pfGUICtrlProcWriteableObject() { ; }
virtual void DoSomething( pfGUIControlMod *ctrl ) = 0;
static void Write( pfGUICtrlProcWriteableObject *obj, hsStream *s );
static pfGUICtrlProcWriteableObject *Read( hsStream *s );
};
//// pfGUIConsoleCmdProc /////////////////////////////////////////////////////
// Simply runs the console command specified. Exportable.
class pfGUIConsoleCmdProc : public pfGUICtrlProcWriteableObject
{
protected:
char *fCommand;
virtual void IRead( hsStream *s );
virtual void IWrite( hsStream *s );
public:
pfGUIConsoleCmdProc();
pfGUIConsoleCmdProc( const char *cmd );
virtual ~pfGUIConsoleCmdProc();
virtual void DoSomething( pfGUIControlMod *ctrl );
void SetCommand( const char *cmd );
};
//// pfGUIPythonScriptProc ///////////////////////////////////////////////////
class pfGUIPythonScriptProc : public pfGUICtrlProcWriteableObject
{
protected:
virtual void IRead( hsStream *s );
virtual void IWrite( hsStream *s );
public:
pfGUIPythonScriptProc();
virtual ~pfGUIPythonScriptProc();
virtual void DoSomething( pfGUIControlMod *ctrl );
};
//// Simple Runtime Ones /////////////////////////////////////////////////////
class pfGUICloseDlgProc : public pfGUICtrlProcWriteableObject
{
protected:
virtual void IRead( hsStream *s ) {}
virtual void IWrite( hsStream *s ) {}
public:
pfGUICloseDlgProc() : pfGUICtrlProcWriteableObject( kCloseDlg ) {}
virtual ~pfGUICloseDlgProc() {}
virtual void DoSomething( pfGUIControlMod *ctrl );
};
#endif // _pfGUIControlHandlers_h

View File

@ -0,0 +1,996 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIControlMod Definition //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUIControlMod.h"
#include "pfGameGUIMgr.h"
#include "pfGUIDialogMod.h"
#include "pfGUIControlHandlers.h"
#include "pfGUIDialogHandlers.h"
#include "pfGUIListElement.h" // Includes dropTargetProc
#include "../pnMessage/plRefMsg.h"
#include "../pnMessage/plEnableMsg.h"
#include "../pfMessage/pfGameGUIMsg.h"
#include "../pnSceneObject/plDrawInterface.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "../pnSceneObject/plAudioInterface.h"
#include "../plGImage/plDynamicTextMap.h"
#include "../plSurface/plLayer.h"
#include "../plMessage/plRenderMsg.h"
#include "../pnMessage/plSoundMsg.h"
#include "plPipeline.h"
#include "../plDrawable/plAccessGeometry.h"
#include "../plDrawable/plAccessSpan.h"
#include "../plDrawable/plAccessVtxSpan.h"
#include "pfGUIPopUpMenu.h" // For skin, can we move that please? Thank you
#include "plgDispatch.h"
#include "hsResMgr.h"
//// pfGUIColorScheme Functions //////////////////////////////////////////////
void pfGUIColorScheme::IReset( void )
{
fForeColor.Set( 1, 1, 1, 1 );
fBackColor.Set( 0, 0, 0, 1 );
fSelForeColor.Set( 1, 1, 1, 1 );
fSelBackColor.Set( 0, 0, 1, 1 );
fTransparent = false;
fFontFace = hsStrcpy( "Times New Roman" );
fFontSize = 10;
fFontFlags = 0;
}
pfGUIColorScheme::pfGUIColorScheme()
{
IReset();
}
pfGUIColorScheme::~pfGUIColorScheme()
{
delete [] fFontFace;
}
pfGUIColorScheme::pfGUIColorScheme( hsColorRGBA &foreColor, hsColorRGBA &backColor )
{
IReset();
fForeColor = foreColor;
fBackColor = backColor;
}
pfGUIColorScheme::pfGUIColorScheme( const char *face, UInt8 size, UInt8 fontFlags )
{
IReset();
fFontFace = hsStrcpy( face );
fFontSize = size;
fFontFlags = fontFlags;
}
void pfGUIColorScheme::SetFontFace( const char *face )
{
delete [] fFontFace;
fFontFace = hsStrcpy( face );
}
void pfGUIColorScheme::Read( hsStream *s )
{
fForeColor.Read( s );
fBackColor.Read( s );
fSelForeColor.Read( s );
fSelBackColor.Read( s );
s->ReadSwap( &fTransparent );
delete [] fFontFace;
fFontFace = s->ReadSafeString();
s->ReadSwap( &fFontSize );
s->ReadSwap( &fFontFlags );
}
void pfGUIColorScheme::Write( hsStream *s )
{
fForeColor.Write( s );
fBackColor.Write( s );
fSelForeColor.Write( s );
fSelBackColor.Write( s );
s->WriteSwap( fTransparent );
s->WriteSafeString( fFontFace );
s->WriteSwap( fFontSize );
s->WriteSwap( fFontFlags );
}
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIControlMod::pfGUIControlMod()
{
fEnabled = true;
fDialog = nil;
fBoundsValid = false;
fCenterValid = false;
fFocused = false;
fInteresting = false;
fVisible = true;
fHandler = nil;
fTagID = 0;
fDropTargetHdlr = nil;
fDynTextMap = nil;
fProxy = nil;
fColorScheme = nil;
fSkin = nil;
fNotifyOnInteresting = false;
}
pfGUIControlMod::~pfGUIControlMod()
{
ISetHandler( nil );
SetDropTargetHdlr( nil );
SetColorScheme( nil );
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool pfGUIControlMod::IEval( double secs, hsScalar del, UInt32 dirty )
{
// UpdateBounds();
return false;
}
//// GetBounds ///////////////////////////////////////////////////////////////
const hsBounds3 &pfGUIControlMod::GetBounds( void )
{
UpdateBounds();
return fBounds;
}
//// SetTransform ////////////////////////////////////////////////////////////
// Override from plModifier so we can update our bounds
void pfGUIControlMod::SetTransform( const hsMatrix44 &l2w, const hsMatrix44 &w2l )
{
fBoundsValid = false;
}
//// GetVectorAngle //////////////////////////////////////////////////////////
static hsScalar GetVectorAngle( const hsPoint3 &basePt, const hsPoint3 &pointA, const hsPoint3 &pointB )
{
hsVector3 vectorA( &pointA, &basePt ), vectorB( &pointB, &basePt );
hsScalar dot = vectorA * vectorB;
hsVector3 cross = vectorA % vectorB;
hsScalar crossLen = cross.fZ;
return atan2( crossLen, dot );
}
//// CreateConvexHull ////////////////////////////////////////////////////////
// Algorithm is Graham's scan algorithm:
// R.L. Graham, "An efficient algorithm for determining the convex hull of a finite
// planar set", Info. Proc. Lett. 1, 132-133 (1972).
// Note: THIS WILL DESTROY YOUR INPOINTS ARRAY.
static hsBool CreateConvexHull( hsPoint3 *inPoints, int &numPoints )
{
int i, j, pointA, pointB, pointC;
hsScalar *angles;
if( numPoints < 3 )
return false;
// Step 1: Find a point interior to our hull. Easiest is average of all our input points...
// (plus: set the Zs of all the points to the Z of the first point, since we want to be
// working in 2D)
hsPoint3 avgPoint = inPoints[ 0 ];
for( i = 1; i < numPoints; i++ )
{
avgPoint += inPoints[ i ];
inPoints[ i ].fZ = inPoints[ 0 ].fZ;
}
avgPoint.fX /= numPoints;
avgPoint.fY /= numPoints;
avgPoint.fZ /= numPoints;
// Step 2: Sort all the in points by the angle to the X axis (vector <1,0>).
// Step A: Calculate all the angles
angles = TRACKED_NEW hsScalar[ numPoints ];
hsPoint3 xAxisPoint( avgPoint.fX + 1, avgPoint.fY, avgPoint.fZ );
for( i = 0; i < numPoints; i++ )
angles[ i ] = GetVectorAngle( avgPoint, inPoints[ i ], xAxisPoint );
// Step B: Bubble sort by the angles
for( i = 0; i < numPoints - 1; i++ )
{
for( j = i + 1; j < numPoints; j++ )
{
if( angles[ j ] < angles[ i ] )
{
hsScalar tempAngle = angles[ j ];
angles[ j ] = angles[ i ];
angles[ i ] = tempAngle;
hsPoint3 tempPt = inPoints[ j ];
inPoints[ j ] = inPoints[ i ];
inPoints[ i ] = tempPt;
}
}
}
// Step 3: Eliminate non-convex points to form the hull
for( pointA = 0, pointB = 1, pointC = 2; pointA < numPoints && numPoints > 3; )
{
// Two cases of wrap-around...
if( pointC >= numPoints )
pointC -= numPoints;
else if( pointC < 0 )
pointC += numPoints;
if( pointB >= numPoints )
pointB -= numPoints;
else if( pointB < 0 )
pointB += numPoints;
// For points A, B, and C, find the interior angle between them
hsScalar angle = GetVectorAngle( inPoints[ pointB ], inPoints[ pointA ], inPoints[ pointC ] );
// If the angle is < 180, then it's a good angle and we can advance all our points by 1...
// Note: we have a tolerance so that we don't get points that form edges that are pretty darned close...
const hsScalar tolerance = hsScalarPI / 90.f;
if( angle > tolerance && angle < hsScalarPI - tolerance )
{
pointA++;
pointB++;
pointC++;
}
else
{
// Angle is > 180 degrees, this is bad. This means our middle point doesn't belong,
// so we need to remove it
for( i = pointB; i < numPoints - 1; i++ )
inPoints[ i ] = inPoints[ i + 1 ];
numPoints--;
if( pointC > pointB )
pointC--;
// There's one case where point B and C could've wrapped around and so deleting that point
// actually moves point A down by 1...
if( pointA > pointB )
pointA--;
// Back up the points by 1 if possible (so we can keep checking to make sure we're still convex).
// If not, just increment C up
if( pointA > 0 )
{
pointA--;
pointB--;
}
else
pointC++;
}
}
delete [] angles;
return true;
}
//// GetObjectPoints /////////////////////////////////////////////////////////
// Retrieves ALL of the points of a sceneObject's meshes. And I mean ALL of
// 'em...
static void GetObjectPoints( plSceneObject *so, hsTArray<hsPoint3> &outPoints )
{
const plDrawInterface* di = so->GetDrawInterface();
if( !di )
return;
// The following uses mf's spiffy plAccessGeometry/Spans stuff, which, in
// one word, kicksAss.
hsTArray<plAccessSpan> spans;
plAccessGeometry::Instance()->OpenRO( di, spans );
int i;
outPoints.Reset();
for( i = 0; i < spans.GetCount(); i++ )
{
plAccessVtxSpan& vtxSrc = spans[ i ].AccessVtx();
plAccPositionIterator iterSrc( &vtxSrc );
for( iterSrc.Begin(); iterSrc.More(); iterSrc.Advance() )
outPoints.Append( *iterSrc.Position() );
}
if (plAccessGeometry::Instance())
plAccessGeometry::Instance()->Close( spans );
}
//// PointsOnSameSide ////////////////////////////////////////////////////////
// Given two ends of a line segment and two points, tells you whether the
// two points are on the same side of the line. Used in PointInTriangle().
static hsBool PointsOnSameSide( const hsPoint3 &line1, const hsPoint3 &line2, const hsPoint3 &pointA, const hsPoint3 &pointB )
{
hsVector3 baseVec( &line2, &line1 );
hsVector3 cp1 = hsVector3( &pointA, &line1 ) % baseVec;
hsVector3 cp2 = hsVector3( &pointB, &line1 ) % baseVec;
return ( cp1.fZ * cp2.fZ > 0 ) ? true : false;
}
//// PointInTriangle /////////////////////////////////////////////////////////
// Given three points that define a triangle and a fourth point, tells you
// whether the fourth point is inside the triangle.
static hsBool PointInTriangle( hsPoint3 tri1, hsPoint3 tri2, hsPoint3 tri3, const hsPoint3 &testPoint )
{
tri1.fZ = tri2.fZ = tri3.fZ = testPoint.fZ;
if( PointsOnSameSide( tri1, tri2, testPoint, tri3 ) &&
PointsOnSameSide( tri2, tri3, testPoint, tri1 ) &&
PointsOnSameSide( tri3, tri1, testPoint, tri2 ) )
return true;
return false;
}
//// PointInBounds ///////////////////////////////////////////////////////////
// Tells you whether said point is in the control's bounds.
hsBool pfGUIControlMod::PointInBounds( const hsPoint3 &point )
{
UpdateBounds();
if( fBounds.GetType() != kBoundsEmpty && fBounds.GetType() != kBoundsUninitialized && fBounds.IsInside( &point ) )
{
if( fBoundsPoints.GetCount() > 0 )
{
// We have a more-accurate bounds set, so use it
int i;
for( i = 1; i < fBoundsPoints.GetCount() - 1; i++ )
{
// Test the triangle (0,i,i+1)
if( PointInTriangle( fBoundsPoints[ 0 ], fBoundsPoints[ i ], fBoundsPoints[ i + 1 ], point ) )
return true;
}
return false;
}
else
return true;
}
return false;
}
//// CalcInitialBounds ///////////////////////////////////////////////////////
// Called by the dialog once as soon as the dialog adds the control, so that
// initial bounds for the control can be calced. This is used for initing
// any dynmaic text maps, since we want to use the initial bounds to do so
// instead of any currently animated state of the bounds.
void pfGUIControlMod::CalcInitialBounds( void )
{
UpdateBounds( nil, true );
fInitialBounds = fBounds;
}
//// UpdateBounds ////////////////////////////////////////////////////////////
void pfGUIControlMod::UpdateBounds( hsMatrix44 *invXformMatrix, hsBool force )
{
hsMatrix44 xformMatrix, projMatrix;
hsPoint3 corners[ 8 ];
int i;
if( ( !fBoundsValid || force ) && fDialog && GetTarget() )
{
plDrawInterface *DI = IGetTargetDrawInterface( 0 );
if( DI == nil )
return;
if( HasFlag( kBetterHitTesting ) )
{
hsTArray<hsPoint3> scrnPoints;
// Create a list of points to make a 2D convex hull from
GetObjectPoints( GetTarget(), scrnPoints );
hsMatrix44 l2w = GetTarget()->GetLocalToWorld();
for( i = 0; i < scrnPoints.GetCount(); i++ )
{
scrnPoints[ i ] = l2w * scrnPoints[ i ];
scrnPoints[ i ] = fDialog->WorldToScreenPoint( scrnPoints[ i ] );
}
// Now create a convex hull from them, assuming the Zs are all the same
int numPoints = scrnPoints.GetCount();
if( !CreateConvexHull( scrnPoints.AcquireArray(), numPoints ) )
return;
// Copy & store. Also recalc our bounding box just for fun
fBounds.MakeEmpty();
fBoundsPoints.SetCount( numPoints );
for( i = 0; i < numPoints; i++ )
{
fBoundsPoints[ i ] = scrnPoints[ i ];
fBounds.Union( &fBoundsPoints[ i ] );
}
}
else
{
fBounds.MakeEmpty();
hsBounds3Ext worldBounds = DI->GetLocalBounds();
hsMatrix44 l2w = GetTarget()->GetLocalToWorld();
worldBounds.Transform( &l2w );
worldBounds.GetCorners( corners );
for( i = 0; i < 8; i++ )
{
hsPoint3 scrnPt = fDialog->WorldToScreenPoint( corners[ i ] );
fBounds.Union( &scrnPt );
}
}
// Calc center Z
// if( !fCenterValid )
{
#if 0
corners[ 1 ] = GetTarget()->GetLocalToWorld().GetTranslate();
float w = corners[ 1 ].fX * fXformMatrix.fMap[3][0]
+ corners[ 1 ].fY * fXformMatrix.fMap[3][1]
+ corners[ 1 ].fZ * fXformMatrix.fMap[3][2]
+ 1.f * fXformMatrix.fMap[3][3];
corners[ 1 ] = fXformMatrix * corners[ 1 ];
corners[ 1 ].fX = ( ( corners[ 1 ].fX / corners[ 1 ].fZ ) + 1.f ) / 2.f;
corners[ 1 ].fY = ( ( corners[ 1 ].fY / corners[ 1 ].fZ ) + 1.f ) / 2.f;
fScreenCenter = corners[ 1 ];
// fScreenCenter.fZ = w;
corners[ 1 ] = GetTarget()->GetLocalToWorld().GetTranslate();
fDialog->WorldToScreenPoint( corners[ 1 ].fX, corners[ 1 ].fY, corners[ 1 ].fZ, fScreenCenter );
fCenterValid = true;
#else
corners[ 1 ] = GetTarget()->GetLocalToWorld().GetTranslate();
fScreenCenter = fDialog->WorldToScreenPoint( corners[ 1 ] );
corners[ 1 ] = fScreenCenter;
fCenterValid = true;
#endif
}
fScreenMinZ = fBounds.GetMins().fZ;
// Manually change the bounds so we know the z ranges from at least -1 to 1, suitable for us testing against for clicks
corners[ 0 ] = fBounds.GetCenter();
corners[ 0 ].fZ = -1.f;
fBounds.Union( &corners[ 0 ] );
corners[ 0 ].fZ = 1.f;
fBounds.Union( &corners[ 0 ] );
fBoundsValid = true;
}
}
//// SetObjectCenter /////////////////////////////////////////////////////////
// Given the x/y coordinates in 0..1 space, recalcs the sceneObject position
// and moves the object to match, retaining the stored fCenterZ coordinate
void pfGUIControlMod::SetObjectCenter( hsScalar x, hsScalar y )
{
hsMatrix44 xformMatrix, l2p, p2l;
hsPoint3 center, corners[ 8 ];
if( x > 1.f )
x = 1.f;
else if( x < 0.f )
x = 0.f;
if( y > 1.f )
y = 1.f;
else if( y < 0.f )
y = 0.f;
if( fDialog && GetTarget() )
{
plCoordinateInterface *CI = IGetTargetCoordinateInterface( 0 );
if( CI == nil )
return;
// if( !fInvXformValid )
// UpdateBounds();
l2p = GetTarget()->GetLocalToWorld();
hsPoint3 oldPt = l2p.GetTranslate();
hsPoint3 oldScrnPt = fDialog->WorldToScreenPoint( oldPt );
hsPoint3 oldPtRedux;
fDialog->ScreenToWorldPoint( oldScrnPt.fX, oldScrnPt.fY, oldScrnPt.fZ, oldPtRedux );
fDialog->ScreenToWorldPoint( x, y, fScreenCenter.fZ, center );
l2p.SetTranslate( &center );
l2p.GetInverse( &p2l );
GetTarget()->SetTransform( l2p, p2l );
fScreenCenter.fX = x;
fScreenCenter.fY = y;
}
}
void pfGUIControlMod::SetTarget( plSceneObject *object )
{
plSingleModifier::SetTarget( object );
UpdateBounds();
}
//// MsgReceive //////////////////////////////////////////////////////////////
#include "plProfile.h"
plProfile_CreateTimer("Gui", "RenderSetup", GUITime);
hsBool pfGUIControlMod::MsgReceive( plMessage *msg )
{
plRenderMsg* rend = plRenderMsg::ConvertNoRef( msg );
if( rend )
{
plProfile_BeginLap(GUITime, this->GetKey()->GetUoid().GetObjectName());
// Only need it once
if( ISetUpDynTextMap( rend->Pipeline() ) )
plgDispatch::Dispatch()->UnRegisterForExactType( plRenderMsg::Index(), GetKey() );
plProfile_EndLap(GUITime, this->GetKey()->GetUoid().GetObjectName());
return true;
}
plGenRefMsg *refMsg = plGenRefMsg::ConvertNoRef( msg );
if( refMsg != nil )
{
if( refMsg->fType == kRefDynTextMap )
{
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
{
fDynTextMap = plDynamicTextMap::ConvertNoRef( refMsg->GetRef() );
// Register for a render msg so we can leech the material when we finally
// have a pipeline to work with
plgDispatch::Dispatch()->RegisterForExactType( plRenderMsg::Index(), GetKey() );
}
else
fDynTextMap = nil;
return true;
}
else if( refMsg->fType == kRefDynTextLayer )
{
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
fDynTextLayer = plLayerInterface::ConvertNoRef( refMsg->GetRef() );
else
fDynTextLayer = nil;
return true;
}
else if( refMsg->fType == kRefProxy )
{
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
fProxy = plSceneObject::ConvertNoRef( refMsg->GetRef() );
else
fProxy = nil;
return true;
}
else if( refMsg->fType == kRefSkin )
{
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
fSkin = pfGUISkin::ConvertNoRef( refMsg->GetRef() );
else
fSkin = nil;
return true;
}
}
return plSingleModifier::MsgReceive( msg );
}
//// ISetUpDynTextMap ////////////////////////////////////////////////////////
// Given a pointer to a dynamic text map, regurgitates it so it matches our
// screen res and fun stuff like that. Also sets the layer transform to give
// us a 1:1 textel-pixel ratio, which we like.
hsBool pfGUIControlMod::ISetUpDynTextMap( plPipeline *pipe )
{
if( fDynTextMap == nil )
{
hsAssert( false, "Trying to set up a nil dynamicTextMap in a GUI control" );
return true;
}
if( fDynTextLayer == nil || fInitialBounds.GetType() == kBoundsUninitialized )//|| fDialog == nil )
return false;
UInt32 scrnWidth, scrnHeight;
if( !HasFlag( kScaleTextWithResolution ) )
{
// Scale so that there is a 1:1 pixel:textel ratio
scrnWidth = pipe->Width();
scrnHeight = pipe->Height();
}
else
{
// Scale with the resolution so that we take up the same % of screen space no matter what resolution
// Assume a base "resolution" of 1024xX, where X is such that the ratio "1024/X = scrnWidth/scrnHt" holds
const int kBaseScaleRes = 1024;
const int kBaseScaleHeightRes = 768;
scrnWidth = kBaseScaleRes;
scrnHeight = kBaseScaleHeightRes;
// we are going to just force things to be in 4 by 3 ratio...
// ...cause it seems to work better.
/////// scrnHeight = ( pipe->Height() * kBaseScaleRes ) / pipe->Width();
}
const hsBounds3 &bounds = fInitialBounds;//GetBounds();
UInt16 width = (UInt16)(( bounds.GetMaxs().fX - bounds.GetMins().fX ) * scrnWidth);
UInt16 height = (UInt16)(( bounds.GetMaxs().fY - bounds.GetMins().fY ) * scrnHeight);
// Allow derived controls to allocate some extra scratch space if desired
// (Do it this way so we can pass in our current calculated dimensions for them to play with)
UInt16 extraW = width, extraH = height;
IGrowDTMDimsToDesiredSize( extraW, extraH );
extraW -= width;
extraH -= height;
fDynTextMap->Reset();
fDynTextMap->Create( width, height, HasFlag( kXparentBgnd ), extraW, extraH );
fDynTextMap->SetFont( GetColorScheme()->fFontFace, GetColorScheme()->fFontSize, GetColorScheme()->fFontFlags,
HasFlag( kXparentBgnd ) ? false : true );
fDynTextMap->SetTextColor( GetColorScheme()->fForeColor,
( HasFlag( kXparentBgnd ) && GetColorScheme()->fBackColor.a == 0.f ) ? true : false );
// Now we gotta set the texture transform on the layer so our texture comes
// out with 1:1 mapping from textel to pixel
plLayer *layer = (plLayer *)fDynTextLayer;
layer->SetTransform( fDynTextMap->GetLayerTransform() );
// Let the derived classes do their things
IPostSetUpDynTextMap();
// Do our first update
IUpdate();
return true;
}
//// Get/SetColorScheme //////////////////////////////////////////////////////
pfGUIColorScheme *pfGUIControlMod::GetColorScheme( void ) const
{
if( fColorScheme == nil )
return fDialog->GetColorScheme();
return fColorScheme;
}
void pfGUIControlMod::SetColorScheme( pfGUIColorScheme *newScheme )
{
if( fColorScheme != nil )
{
hsRefCnt_SafeUnRef( fColorScheme );
fColorScheme = nil;
}
fColorScheme = newScheme;
if( fColorScheme != nil )
hsRefCnt_SafeRef( fColorScheme );
}
//// SetDynTextMap ///////////////////////////////////////////////////////////
// EXPORT ONLY
void pfGUIControlMod::SetDynTextMap( plLayerInterface *layer, plDynamicTextMap *dynText )
{
hsgResMgr::ResMgr()->AddViaNotify( layer->GetKey(), TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, pfGUIControlMod::kRefDynTextLayer ), plRefFlags::kActiveRef );
hsgResMgr::ResMgr()->AddViaNotify( dynText->GetKey(), TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, pfGUIControlMod::kRefDynTextMap ), plRefFlags::kActiveRef );
}
//// SetEnabled //////////////////////////////////////////////////////////////
void pfGUIControlMod::SetEnabled( hsBool e )
{
if( e == fEnabled )
return;
fEnabled = e;
IUpdate();
}
//// SetFocused //////////////////////////////////////////////////////////////
void pfGUIControlMod::SetFocused( hsBool e )
{
if( e == fFocused )
return;
fFocused = e;
IUpdate();
}
//// SetInteresting //////////////////////////////////////////////////////////
void pfGUIControlMod::SetInteresting( hsBool i )
{
if( i == fInteresting )
return;
fInteresting = i;
IUpdate();
if ( fNotifyOnInteresting && fDialog && fDialog->GetHandler() )
fDialog->GetHandler()->OnInterestingEvent(this);
}
//// SetVisible //////////////////////////////////////////////////////////////
void pfGUIControlMod::SetVisible( hsBool vis )
{
if( vis == fVisible )
return;
fVisible = vis;
if (fTarget)
{
plEnableMsg *msg = TRACKED_NEW plEnableMsg();
msg->SetCmd( fVisible ? plEnableMsg::kEnable : plEnableMsg::kDisable );
msg->SetCmd( plEnableMsg::kDrawable );
msg->AddReceiver( fTarget->GetKey() );
plgDispatch::MsgSend( msg );
}
if( !fVisible && fFocused )
fDialog->SetFocus( nil );
}
void pfGUIControlMod::Refresh( void )
{
IUpdate();
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUIControlMod::Read( hsStream *s, hsResMgr *mgr )
{
plSingleModifier::Read(s, mgr);
s->ReadSwap( &fTagID );
fVisible = s->ReadBool();
// Read the handler in
ISetHandler( pfGUICtrlProcWriteableObject::Read( s ) );
// Read in the dynTextMap if there is one
if( s->ReadBool() )
{
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefDynTextLayer ), plRefFlags::kActiveRef );
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefDynTextMap ), plRefFlags::kActiveRef );
}
else
{
fDynTextLayer = nil;
fDynTextMap = nil;
}
if( s->ReadBool() )
{
SetColorScheme( nil );
fColorScheme = TRACKED_NEW pfGUIColorScheme();
fColorScheme->Read( s );
}
// Read in our sound indices
UInt8 i, count = s->ReadByte();
if( count == 0 )
fSoundIndices.Reset();
else
{
fSoundIndices.SetCountAndZero( count );
for( i = 0; i < count; i++ )
fSoundIndices[ i ] = (int)s->ReadSwap32();
}
if( HasFlag( kHasProxy ) )
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefProxy ), plRefFlags::kActiveRef );
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefSkin ), plRefFlags::kActiveRef );
}
void pfGUIControlMod::Write( hsStream *s, hsResMgr *mgr )
{
if( HasFlag( kHasProxy ) && !fProxy )
ClearFlag( kHasProxy );
plSingleModifier::Write( s, mgr );
s->WriteSwap( fTagID );
s->WriteBool( fVisible );
// Write the handler out (if it's not a writeable, damn you)
pfGUICtrlProcWriteableObject::Write( (pfGUICtrlProcWriteableObject *)fHandler, s );
// Write out the dynTextMap
if( fDynTextMap != nil )
{
s->WriteBool( true );
mgr->WriteKey( s, fDynTextLayer->GetKey() );
mgr->WriteKey( s, fDynTextMap->GetKey() );
}
else
s->WriteBool( false );
if( fColorScheme != nil )
{
s->WriteBool( true );
fColorScheme->Write( s );
}
else
s->WriteBool( false );
// Write out our sound indices
s->WriteByte( fSoundIndices.GetCount() );
UInt8 i;
for( i = 0; i < fSoundIndices.GetCount(); i++ )
s->WriteSwap32( fSoundIndices[ i ] );
if( HasFlag( kHasProxy ) )
mgr->WriteKey( s, fProxy->GetKey() );
mgr->WriteKey( s, fSkin );
}
//// HandleKeyPress/Event ////////////////////////////////////////////////////
hsBool pfGUIControlMod::HandleKeyPress( char key, UInt8 modifiers )
{
return false;
}
hsBool pfGUIControlMod::HandleKeyEvent( pfGameGUIMgr::EventType event, plKeyDef key, UInt8 modifiers )
{
return false;
}
//// IScreenToLocalPt ////////////////////////////////////////////////////////
void pfGUIControlMod::IScreenToLocalPt( hsPoint3 &pt )
{
const hsBounds3 &bnds = GetBounds();
pt.fX -= bnds.GetMins().fX;
pt.fY -= bnds.GetMins().fY;
pt.fX /= bnds.GetMaxs().fX - bnds.GetMins().fX;
pt.fY /= bnds.GetMaxs().fY - bnds.GetMins().fY;
}
//// ISetHandler /////////////////////////////////////////////////////////////
void pfGUIControlMod::ISetHandler( pfGUICtrlProcObject *h, hsBool clearInheritFlag )
{
if( fHandler && fHandler->DecRef() )
delete fHandler;
fHandler = h;
if( fHandler )
fHandler->IncRef();
if( clearInheritFlag )
ClearFlag( kInheritProcFromDlg );
}
//// DoSomething /////////////////////////////////////////////////////////////
void pfGUIControlMod::DoSomething( void )
{
if( fEnabled && fHandler != nil )
fHandler->DoSomething( this );
}
//// HandleExtendedEvent /////////////////////////////////////////////////////
void pfGUIControlMod::HandleExtendedEvent( UInt32 event )
{
if( fEnabled && fHandler != nil )
fHandler->HandleExtendedEvent( this, event );
}
//// SetDropTargetHdlr ///////////////////////////////////////////////////////
void pfGUIControlMod::SetDropTargetHdlr( pfGUIDropTargetProc *h )
{
if( fDropTargetHdlr && fDropTargetHdlr->DecRef() )
delete fDropTargetHdlr;
fDropTargetHdlr = h;
if( fDropTargetHdlr )
fDropTargetHdlr->IncRef();
}
//// SetSoundIndex ///////////////////////////////////////////////////////////
// Associates the given GUI event with an index of a sound on the target SO's
// audioInterface. The guiCtrlEvent is specific to each type of control.
void pfGUIControlMod::SetSoundIndex( UInt8 guiCtrlEvent, int soundIndex )
{
if( fSoundIndices.GetCount() < guiCtrlEvent + 1 )
fSoundIndices.ExpandAndZero( guiCtrlEvent + 1 );
fSoundIndices[ guiCtrlEvent ] = soundIndex + 1; // We +1, since 0 means no sound
}
//// IPlaySound //////////////////////////////////////////////////////////////
// Sends a sound play message with the soundIndex associated with the given
// event.
void pfGUIControlMod::IPlaySound( UInt8 guiCtrlEvent, hsBool loop /* = false */ )
{
if( guiCtrlEvent >= fSoundIndices.GetCount() || fSoundIndices[ guiCtrlEvent ] == 0 )
return;
if( GetTarget() == nil || GetTarget()->GetAudioInterface() == nil )
return;
plSoundMsg *msg = TRACKED_NEW plSoundMsg;
msg->fIndex = fSoundIndices[ guiCtrlEvent ] - 1;
msg->SetCmd( plSoundMsg::kGoToTime );
msg->fTime = 0.f;
msg->SetCmd( plSoundMsg::kPlay );
if (loop)
{
msg->fLoop = true;
msg->SetCmd( plSoundMsg::kSetLooping );
}
msg->Send( GetTarget()->GetAudioInterface()->GetKey() );
}
void pfGUIControlMod::IStopSound(UInt8 guiCtrlEvent)
{
if (guiCtrlEvent >= fSoundIndices.GetCount() || fSoundIndices[guiCtrlEvent] == 0)
return;
if (GetTarget() == nil || GetTarget()->GetAudioInterface() == nil )
return;
plSoundMsg *msg = TRACKED_NEW plSoundMsg;
msg->fIndex = fSoundIndices[guiCtrlEvent] - 1;
msg->SetCmd(plSoundMsg::kStop);
msg->Send(GetTarget()->GetAudioInterface()->GetKey());
}

View File

@ -0,0 +1,250 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIControlMod Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIControlMod_h
#define _pfGUIControlMod_h
#include "../pnModifier/plSingleModifier.h"
#include "hsBounds.h"
#include "../plMessage/plInputEventMsg.h"
#include "pfGameGUIMgr.h"
#include "hsColorRGBA.h"
#include "hsRefCnt.h"
class plMessage;
class plPostEffectMod;
class pfGUIDialogMod;
class pfGUICtrlProcObject;
class pfGUIDropTargetProc;
class plDynamicTextMap;
class plLayerInterface;
//// pfGUIColorScheme ////////////////////////////////////////////////////////
// Tiny helper wrapper for a set of colors used to draw various controls
class pfGUIColorScheme : public hsRefCnt
{
public:
hsColorRGBA fForeColor, fBackColor;
hsColorRGBA fSelForeColor, fSelBackColor;
hsBool fTransparent;
char *fFontFace;
UInt8 fFontSize;
UInt8 fFontFlags;
enum FontFlags
{
kFontBold = 0x01,
kFontItalic = 0x02,
kFontShadowed = 0x04
};
pfGUIColorScheme();
~pfGUIColorScheme();
pfGUIColorScheme( hsColorRGBA &foreColor, hsColorRGBA &backColor );
pfGUIColorScheme( const char *face, UInt8 size, UInt8 fontFlags );
void SetFontFace( const char *face );
void Read( hsStream *s );
void Write( hsStream *s );
hsBool IsBold( void ) { return ( fFontFlags & kFontBold ) ? true : false; }
hsBool IsItalic( void ) { return ( fFontFlags & kFontItalic ) ? true : false; }
hsBool IsShadowed( void ) { return ( fFontFlags & kFontShadowed ) ? true : false; }
protected:
void IReset( void );
};
//// Class Def ///////////////////////////////////////////////////////////////
class pfGUISkin;
class pfGUIControlMod : public plSingleModifier
{
friend class pfGUIDialogMod;
protected:
UInt32 fTagID;
hsBool fEnabled, fFocused, fVisible, fInteresting;
hsBool fNotifyOnInteresting;
pfGUIDialogMod *fDialog;
hsBounds3 fBounds, fInitialBounds; // Z component is 0-1
hsScalar fScreenMinZ; // Closest Z coordinate in screen space
hsPoint3 fScreenCenter;
hsBool fBoundsValid, fCenterValid;
hsMatrix44 fXformMatrix; // Only used for doing drag work, etc.
pfGUICtrlProcObject *fHandler;
pfGUIDropTargetProc *fDropTargetHdlr;
plDynamicTextMap *fDynTextMap; // Some controls use this; for others, it'll be nil
plLayerInterface *fDynTextLayer; // Juse so we can reset the transform. Sheesh!
pfGUIColorScheme *fColorScheme;
plSceneObject *fProxy;
hsTArray<hsPoint3> fBoundsPoints; // For more accurate bounds tests
hsTArray<int> fSoundIndices; // Indices of sounds to trigger on the target SO's audible interface
pfGUISkin *fSkin;
hsBool ISetUpDynTextMap( plPipeline *pipe );
virtual void IPostSetUpDynTextMap( void ) {}
virtual void IGrowDTMDimsToDesiredSize( UInt16 &width, UInt16 &height ) { }
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
void ISetDialog( pfGUIDialogMod *mod ) { fDialog = mod; }
void IScreenToLocalPt( hsPoint3 &pt );
virtual void IUpdate( void ) {;}
void ISetHandler( pfGUICtrlProcObject *h, hsBool clearInheritFlag = false );
void IPlaySound( UInt8 guiCtrlEvent, hsBool loop = false );
void IStopSound( UInt8 guiCtrlEvent );
virtual UInt32 IGetDesiredCursor( void ) const { return 0; } // As specified in plInputInterface.h
public:
pfGUIControlMod();
virtual ~pfGUIControlMod();
CLASSNAME_REGISTER( pfGUIControlMod );
GETINTERFACE_ANY( pfGUIControlMod, plSingleModifier );
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
UInt32 GetTagID( void ) { return fTagID; }
virtual void SetEnabled( hsBool e );
virtual hsBool IsEnabled( void ) { return fEnabled; }
virtual void SetFocused( hsBool e );
virtual hsBool IsFocused( void ) { return fFocused; }
virtual void SetVisible( hsBool vis );
virtual hsBool IsVisible( void ) { return fVisible; }
virtual void SetInteresting( hsBool i );
hsBool IsInteresting( void ) { return fInteresting; }
virtual void SetNotifyOnInteresting( hsBool state ) { fNotifyOnInteresting = state; }
pfGUIDialogMod *GetOwnerDlg( void ) { return fDialog; }
virtual void Refresh( void );
virtual void UpdateBounds( hsMatrix44 *invXformMatrix = nil, hsBool force = false );
void SetObjectCenter( hsScalar x, hsScalar y );
virtual hsPoint3 GetObjectCenter() { return fScreenCenter; }
hsScalar GetScreenMinZ( void ) { return fScreenMinZ; }
void CalcInitialBounds( void );
const hsBounds3 &GetBounds( void );
hsBool PointInBounds( const hsPoint3 &point );
virtual void SetTarget( plSceneObject *object );
// Return false if you actually DON'T want the mouse clicked at this point (should only be used for non-rectangular region rejection)
virtual hsBool FilterMousePosition( hsPoint3 &mousePt ) { return true; }
virtual void HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers ) {;}
virtual void HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers ) {;}
virtual void HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers ) {;}
virtual void HandleMouseHover( hsPoint3 &mousePt, UInt8 modifiers ) {;}
virtual void HandleMouseDblClick( hsPoint3 &mousePt, UInt8 modifiers ) {;}
virtual hsBool HandleKeyPress( char key, UInt8 modifiers );
virtual hsBool HandleKeyEvent( pfGameGUIMgr::EventType event, plKeyDef key, UInt8 modifiers );
void SetHandler( pfGUICtrlProcObject *h ) { ISetHandler( h, true ); }
void DoSomething( void ); // Will call the handler
void HandleExtendedEvent( UInt32 event ); // Will call the handler
pfGUICtrlProcObject *GetHandler( void ) const { return fHandler; }
void SetDropTargetHdlr( pfGUIDropTargetProc *drop );
pfGUIDropTargetProc *GetDropTargetHdlr( void ) { return fDropTargetHdlr; }
enum
{
kRefDynTextMap,
kRefDynTextLayer,
kRefProxy,
kRefSkin,
kRefDerivedStart = 32
};
enum Flags // plSingleModifier already has SetFlag()/HasFlag()
{
kWantsInterest,
kInheritProcFromDlg,
kIntangible, // I.E. it doesn't exists on the screen/can't be clicked on.
// Used for group objects like the up/down pair
kXparentBgnd,
kScaleTextWithResolution, // I.E. take up the same space on screen no matter the resolution
kTakesSpecialKeys, // I.E. disable bindings for keys like backspace because we want them
kHasProxy,
kBetterHitTesting,
kDerivedFlagsStart = 32
};
virtual void SetColorScheme( pfGUIColorScheme *newScheme );
pfGUIColorScheme *GetColorScheme( void ) const;
// should be override by specific GUIcontrol
virtual void PurgeDynaTextMapImage() {;}
// Override from plModifier so we can update our bounds
virtual void SetTransform(const hsMatrix44& l2w, const hsMatrix44& w2l);
// Forces an immediate play of the given GUI control event sound
void PlaySound( UInt8 guiCtrlEvent, hsBool loop = false ) { IPlaySound( guiCtrlEvent, loop ); }
void StopSound( UInt8 guiCtrlEvent ) { IStopSound( guiCtrlEvent ); }
// Export only
void SetTagID( UInt32 id ) { fTagID = id; }
void SetDynTextMap( plLayerInterface *layer, plDynamicTextMap *dynText );
void SetSoundIndex( UInt8 guiCtrlEvent, int soundIndex );
};
#endif // _pfGUIControlMod_h

View File

@ -0,0 +1,508 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUICtrlGenerator Definitions //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUICtrlGenerator.h"
#include "pfGameGUIMgr.h"
#include "pfGUIControlMod.h"
#include "pfGUIDialogMod.h"
#include "pfGUIButtonMod.h"
#include "pfGUIDragBarCtrl.h"
#include "pfGUIControlHandlers.h"
#include "pfGUIMenuItem.h"
#include "../plSurface/hsGMaterial.h"
#include "../plSurface/plLayer.h"
#include "../plGImage/plMipmap.h"
#include "../pnKeyedObject/plFixedKey.h"
#include "../plDrawable/plDrawableSpans.h"
#include "../plDrawable/plDrawableGenerator.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnSceneObject/plDrawInterface.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "../pnMessage/plIntRefMsg.h"
#include "../pnMessage/plObjRefMsg.h"
#include "../pnMessage/plNodeRefMsg.h"
#include "../plPipeline/plTextGenerator.h"
#include "../plScene/plPostEffectMod.h"
#include "../plScene/plSceneNode.h"
#include "../pnMessage/plClientMsg.h"
#include "../plMessage/plLayRefMsg.h"
#include "../pnMessage/plAttachMsg.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUICtrlGenerator::pfGUICtrlGenerator()
{
strcpy( fFontFace, "Arial" );
fFontSize = 18;
}
pfGUICtrlGenerator::~pfGUICtrlGenerator()
{
Shutdown();
}
void pfGUICtrlGenerator::Shutdown( void )
{
int i;
// Destroy our scene nodes and dialogs
for( i = 0; i < fDynDlgNodes.GetCount(); i++ )
{
pfGameGUIMgr::GetInstance()->UnloadDialog( fDynDialogs[ i ] );
fDynDlgNodes[ i ]->GetKey()->UnRefObject();
}
fDynDlgNodes.Reset();
fDynDialogs.Reset();
for( i = 0; i < fTextGens.GetCount(); i++ )
delete fTextGens[ i ];
fTextGens.Reset();
}
//// Instance ////////////////////////////////////////////////////////////////
pfGUICtrlGenerator &pfGUICtrlGenerator::Instance( void )
{
static pfGUICtrlGenerator myInstance;
return myInstance;
}
//// IGetNextKeyName /////////////////////////////////////////////////////////
void pfGUICtrlGenerator::IGetNextKeyName( char *name, const char *prefix )
{
static UInt32 keyCount = 0;
sprintf( name, "%s%d", prefix, keyCount++ );
}
//// IAddKey /////////////////////////////////////////////////////////////////
plKey pfGUICtrlGenerator::IAddKey( hsKeyedObject *ko, const char *prefix )
{
char keyName[ 128 ];
IGetNextKeyName( keyName, prefix );
return hsgResMgr::ResMgr()->NewKey( keyName, ko, plLocation::kGlobalFixedLoc );
}
//// SetFont /////////////////////////////////////////////////////////////////
void pfGUICtrlGenerator::SetFont( const char *face, UInt16 size )
{
strcpy( fFontFace, face );
fFontSize = size;
}
//// ICreateSolidMaterial ////////////////////////////////////////////////////
// Creates a material with no texture, just color.
hsGMaterial *pfGUICtrlGenerator::ICreateSolidMaterial( hsColorRGBA &color )
{
hsColorRGBA black;
// Create a material with a simple blank layer, fully ambient
hsGMaterial *material = TRACKED_NEW hsGMaterial;
IAddKey( material, "GUIMaterial" );
plLayer *lay = material->MakeBaseLayer();
black.Set( 0.f,0.f,0.f,1.f );
lay->SetRuntimeColor( black );
lay->SetPreshadeColor( black );
lay->SetAmbientColor( color );
return material;
}
//// ICreateTextMaterial /////////////////////////////////////////////////////
// Creates a material with a texture that has a string centered on it.
hsGMaterial *pfGUICtrlGenerator::ICreateTextMaterial( const char *text, hsColorRGBA &bgColor,
hsColorRGBA &textColor, float objWidth, float objHeight )
{
UInt16 pixWidth, pixHeight, strWidth, strHeight;
hsColorRGBA black, white;
// Guess at some pixel width and heights we want. We're guessing b/c we want it to look reasonably
// good on the screen, but we don't know exactly how big is big, so we guess
pixWidth = (UInt16)(objWidth * 64.f);
pixHeight = (UInt16)(objHeight * 64.f);
// Create blank mipmap
plMipmap *bitmap = TRACKED_NEW plMipmap( 1, 1, plMipmap::kRGB32Config, 1 );
IAddKey( bitmap, "GUIMipmap" );
// Create textGen to write string with
plTextGenerator *textGen = TRACKED_NEW plTextGenerator( bitmap, pixWidth, pixHeight );
textGen->SetFont( fFontFace, (UInt16)fFontSize );
textGen->ClearToColor( bgColor );
textGen->SetTextColor( textColor );
strWidth = textGen->CalcStringWidth( text, &strHeight );
textGen->DrawString( ( pixWidth - strWidth ) >> 1, ( pixHeight - strHeight ) >> 1, text );
textGen->FlushToHost();
fTextGens.Append( textGen );
// Create a material with a simple blank layer, fully ambient
hsGMaterial *material = TRACKED_NEW hsGMaterial;
IAddKey( material, "GUIMaterial" );
plLayer *lay = material->MakeBaseLayer();
white.Set( 1.f,1.f,1.f,1.f );
black.Set( 0.f,0.f,0.f,1.f );
lay->SetRuntimeColor( black );
lay->SetPreshadeColor( black );
lay->SetAmbientColor( white );
hsgResMgr::ResMgr()->AddViaNotify( bitmap->GetKey(), TRACKED_NEW plLayRefMsg( lay->GetKey(), plRefMsg::kOnCreate, 0, plLayRefMsg::kTexture ), plRefFlags::kActiveRef );
// lay->SetTexture( bitmap );
lay->SetTransform( textGen->GetLayerTransform() );
return material;
}
//// GenerateDialog //////////////////////////////////////////////////////////
void pfGUICtrlGenerator::GenerateDialog( const char *name )
{
IGenerateDialog( name, 20.f, false );
}
//// IGenSceneObject /////////////////////////////////////////////////////////
plSceneObject *pfGUICtrlGenerator::IGenSceneObject( pfGUIDialogMod *dlg, plDrawable *myDraw, plSceneObject *parent,
hsMatrix44 *l2w, hsMatrix44 *w2l )
{
plKey snKey = ( dlg != nil ) ? ( dlg->GetTarget() != nil ? dlg->GetTarget()->GetSceneNode() : nil ) : nil;
if( snKey == nil )
snKey = fDynDlgNodes.Peek()->GetKey();
hsgResMgr::ResMgr()->SendRef( myDraw->GetKey(), TRACKED_NEW plNodeRefMsg( snKey, plRefMsg::kOnCreate, 0, plNodeRefMsg::kDrawable ), plRefFlags::kActiveRef );
plDrawInterface *newDI = TRACKED_NEW plDrawInterface;
IAddKey( newDI, "GUIDrawIFace" );
plSceneObject *newObj = TRACKED_NEW plSceneObject;
IAddKey( newObj, "GUISceneObject" );
plCoordinateInterface *newCI = TRACKED_NEW plCoordinateInterface;
IAddKey( newCI, "GUICoordIFace" );
hsgResMgr::ResMgr()->SendRef( newCI->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kInterface ), plRefFlags::kActiveRef );
hsgResMgr::ResMgr()->SendRef( newDI->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kInterface ), plRefFlags::kActiveRef );
hsgResMgr::ResMgr()->SendRef( myDraw->GetKey(), TRACKED_NEW plIntRefMsg( newDI->GetKey(), plRefMsg::kOnCreate, 0, plIntRefMsg::kDrawable ), plRefFlags::kActiveRef );
if( parent == nil )
{
parent = ( fDynDragBars.GetCount() > 0 ) ? fDynDragBars.Peek() : nil;
if( parent == nil )
parent = dlg->GetTarget();
}
if( parent != nil )
// hsgResMgr::ResMgr()->SendRef( newCI->GetKey(), TRACKED_NEW plIntRefMsg( parent->GetKey(), plRefMsg::kOnCreate, 0, plIntRefMsg::kChild ), plRefFlags::kActiveRef );
hsgResMgr::ResMgr()->SendRef( newCI->GetKey(), TRACKED_NEW plAttachMsg( parent->GetKey(), nil, plRefMsg::kOnRequest ), plRefFlags::kActiveRef );
newObj->SetSceneNode( snKey );
if( l2w != nil )
{
newObj->SetTransform( *l2w, *w2l );
// newCI->SetLocalToParent( *l2w, *w2l );
// myDraw->SetTransform( -1, *l2w, *w2l );
}
return newObj;
}
//// GenerateRectButton //////////////////////////////////////////////////////
pfGUIButtonMod *pfGUICtrlGenerator::GenerateRectButton( const char *title, float x, float y, float width, float height,
const char *consoleCmd, hsColorRGBA &color, hsColorRGBA &textColor )
{
hsGMaterial *material;
hsMatrix44 l2w, w2l;
hsVector3 vec;
pfGUIDialogMod *dlgToAddTo = IGetDialog();
// Get us a material
material = ICreateTextMaterial( title, color, textColor, width * 20.f, height * 20.f );
pfGUIButtonMod *but = CreateRectButton( dlgToAddTo, title, x, y, width, height, material );
if( but != nil )
but->SetHandler( TRACKED_NEW pfGUIConsoleCmdProc( consoleCmd ) );
return but;
}
//// CreateRectButton ////////////////////////////////////////////////////////
pfGUIButtonMod *pfGUICtrlGenerator::CreateRectButton( pfGUIDialogMod *parent, const char *title, float x, float y, float width, float height,
hsGMaterial *material, hsBool asMenuItem )
{
wchar_t *wTitle = hsStringToWString(title);
pfGUIButtonMod *retVal = CreateRectButton(parent,wTitle,x,y,width,height,material,asMenuItem);
delete [] wTitle;
return retVal;
}
pfGUIButtonMod *pfGUICtrlGenerator::CreateRectButton( pfGUIDialogMod *parent, const wchar_t *title, float x, float y, float width, float height,
hsGMaterial *material, hsBool asMenuItem )
{
plDrawableSpans *myDraw;
hsMatrix44 l2w, w2l;
hsVector3 vec;
// Translate x and y from (0:1) to (-10:10)
x = ( x - 0.5f ) * 20.f;
y = ( y - 0.5f ) * 20.f;
// Translate width and height from (0:1) to (-10:10)
width *= 20.f;
height *= 20.f;
// Create drawable that is rectangular
l2w.Reset();
hsPoint3 corner( x, -y, -100 );
hsVector3 xVec( width, 0, 0 ), yVec( 0, height, 0 ), zVec( 0, 0, 0.1f );
myDraw = plDrawableGenerator::GeneratePlanarDrawable( corner, xVec, yVec, material, l2w );
plSceneObject *newObj = IGenSceneObject( parent, myDraw );
pfGUIButtonMod *newBtn = asMenuItem ? TRACKED_NEW pfGUIMenuItem : TRACKED_NEW pfGUIButtonMod;
IAddKey( newBtn, "GUIButton" );
hsgResMgr::ResMgr()->SendRef( newBtn->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kModifier ), plRefFlags::kActiveRef );
parent->AddControl( newBtn );
hsgResMgr::ResMgr()->AddViaNotify( newBtn->GetKey(), TRACKED_NEW plGenRefMsg( parent->GetKey(), plRefMsg::kOnCreate, parent->GetNumControls() - 1, pfGUIDialogMod::kControlRef ), plRefFlags::kActiveRef );
return newBtn;
}
//// GenerateSphereButton ////////////////////////////////////////////////////
pfGUIButtonMod *pfGUICtrlGenerator::GenerateSphereButton( float x, float y, float radius,
const char *consoleCmd, hsColorRGBA &color )
{
hsGMaterial *material;
plDrawableSpans *myDraw;
hsMatrix44 l2w, w2l;
hsVector3 vec;
hsPoint3 pt( x, -y, -100.f );
pfGUIDialogMod *dlgToAddTo = IGetDialog();
// Translate x and y from (0:1) to (-10:10)
x = ( x - 0.5f ) * 20.f;
y = ( y - 0.5f ) * 20.f;
// Translate width and height from (0:1) to (-10:10)
radius *= 20.f;
// Get us a material
material = ICreateSolidMaterial( color );
// Create drawable that is rectangular
l2w.Reset();
// We bump up the quality since we're actually far closer to these things then the normal
// world camera would put us
myDraw = plDrawableGenerator::GenerateSphericalDrawable( pt, radius, material, l2w,
false, nil, nil, nil, 100.f );
vec.Set( x, -y, 0 );
l2w.MakeTranslateMat( &vec );
l2w.GetInverse( &w2l );
plSceneObject *newObj = IGenSceneObject( dlgToAddTo, myDraw );//, nil, &l2w, &w2l );
pfGUIButtonMod *newBtn = TRACKED_NEW pfGUIButtonMod;
IAddKey( newBtn, "GUIButton" );
newBtn->SetHandler( TRACKED_NEW pfGUIConsoleCmdProc( consoleCmd ) );
hsgResMgr::ResMgr()->AddViaNotify( newBtn->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kModifier ), plRefFlags::kActiveRef );
dlgToAddTo->AddControl( newBtn );
return newBtn;
}
//// GenerateDragBar //////////////////////////////////////////////////////
pfGUIDragBarCtrl *pfGUICtrlGenerator::GenerateDragBar( float x, float y, float width, float height, hsColorRGBA &color )
{
hsGMaterial *material;
plDrawableSpans *myDraw;
hsMatrix44 l2w, w2l;
hsVector3 vec;
pfGUIDialogMod *dlgToAddTo = IGetDialog();
// Translate x and y from (0:1) to (-10:10)
x = ( x - 0.5f ) * 20.f;
y = ( y - 0.5f ) * 20.f;
// Translate width and height from (0:1) to (-10:10)
width *= 20.f;
height *= 20.f;
// Get us a material
material = ICreateSolidMaterial( color );
// Create drawable that is rectangular
l2w.Reset();
hsPoint3 corner( x, -y, -100 );//x - width / 2.f, -y - height / 2.f, -100 );
hsVector3 xVec( width, 0, 0 ), yVec( 0, height, 0 ), zVec( 0, 0, 0.1f );
myDraw = plDrawableGenerator::GenerateBoxDrawable( corner, xVec, yVec, zVec,/*width, height, 0.01f, */material, l2w );
// Drag bars are special--everything else gets attached to them and they get attached to the dialog
vec.Set( x, -y, -100 );
l2w.MakeTranslateMat( &vec );
l2w.GetInverse( &w2l );
plSceneObject *newObj = IGenSceneObject( dlgToAddTo, myDraw, dlgToAddTo->GetTarget(), &l2w, &w2l );
fDynDragBars[ fDynDragBars.GetCount() - 1 ] = newObj;
pfGUIDragBarCtrl *newBtn = TRACKED_NEW pfGUIDragBarCtrl;
IAddKey( newBtn, "GUIDragBar" );
hsgResMgr::ResMgr()->AddViaNotify( newBtn->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kModifier ), plRefFlags::kActiveRef );
dlgToAddTo->AddControl( newBtn );
/* vec.Set( -x, y, 100 );
l2w.MakeTranslateMat( &vec );
l2w.GetInverse( &w2l );
plCoordinateInterface *ci = (plCoordinateInterface *)dlgToAddTo->GetTarget()->GetCoordinateInterface();
ci->SetLocalToParent( l2w, w2l );
*/
return newBtn;
}
//// IGetDialog //////////////////////////////////////////////////////////////
pfGUIDialogMod *pfGUICtrlGenerator::IGetDialog( void )
{
if( fDynDialogs.GetCount() == 0 )
IGenerateDialog( "GUIBaseDynamicDlg", 20.f );
hsAssert( fDynDialogs.GetCount() > 0, "Unable to get a dynamic dialog to add buttons to" );
return fDynDialogs.Peek();
}
//// IGenerateDialog /////////////////////////////////////////////////////////
pfGUIDialogMod *pfGUICtrlGenerator::IGenerateDialog( const char *name, float scrnWidth, hsBool show )
{
float fovX, fovY;
plSceneNode *node;
pfGUIDialogMod *dialog;
// Create the rendermod
plPostEffectMod *renderMod = TRACKED_NEW plPostEffectMod;
IAddKey( renderMod, "GUIRenderMod" );
renderMod->SetHither( 0.5f );
renderMod->SetYon( 200.f );
// fovX should be such that scrnWidth is the projected width at z=100
fovX = atan( scrnWidth / ( 2.f * 100.f ) ) * 2.f;
fovY = fovX;// * 3.f / 4.f;
renderMod->SetFovX( fovX * 180.f / hsScalarPI );
renderMod->SetFovY( fovY * 180.f / hsScalarPI );
// Create the sceneNode to go with it
node = TRACKED_NEW plSceneNode;
IAddKey( node, "GUISceneNode" );
node->GetKey()->RefObject();
fDynDlgNodes.Append( node );
fDynDragBars.Append( nil );
hsgResMgr::ResMgr()->AddViaNotify( node->GetKey(), TRACKED_NEW plGenRefMsg( renderMod->GetKey(), plRefMsg::kOnCreate, 0, plPostEffectMod::kNodeRef ), plRefFlags::kPassiveRef );
// Create the dialog
dialog = TRACKED_NEW pfGUIDialogMod;
IAddKey( dialog, "GUIDialog" );
dialog->SetRenderMod( renderMod );
dialog->SetName( name );
// Create the dummy scene object to hold the dialog
plSceneObject *newObj = TRACKED_NEW plSceneObject;
IAddKey( newObj, "GUISceneObject" );
// *#&$(*@&#$ need a coordIface...
plCoordinateInterface *newCI = TRACKED_NEW plCoordinateInterface;
IAddKey( newCI, "GUICoordIFace" );
hsMatrix44 l2w, w2l;
l2w.Reset();
// l2w.NotIdentity();
l2w.GetInverse( &w2l );
// Using SendRef here because AddViaNotify will queue the messages up, which doesn't do us any good
// if we need these refs right away
hsgResMgr::ResMgr()->SendRef( dialog->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kModifier ), plRefFlags::kActiveRef );
hsgResMgr::ResMgr()->AddViaNotify( newCI->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kInterface ), plRefFlags::kActiveRef );
hsgResMgr::ResMgr()->AddViaNotify( renderMod->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kModifier ), plRefFlags::kActiveRef );
// Add the dialog to the GUI mgr
plGenRefMsg *refMsg = TRACKED_NEW plGenRefMsg( pfGameGUIMgr::GetInstance()->GetKey(),
plRefMsg::kOnCreate, 0, pfGameGUIMgr::kDlgModRef );
hsgResMgr::ResMgr()->AddViaNotify( dialog->GetKey(), refMsg, plRefFlags::kActiveRef );
newObj->SetSceneNode( node->GetKey() );
newObj->SetTransform( l2w, w2l );
// newCI->SetLocalToParent( l2w, w2l );
if( show )
pfGameGUIMgr::GetInstance()->ShowDialog( dialog );
fDynDialogs.Append( dialog );
return dialog;
}

View File

@ -0,0 +1,113 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUICtrlGenerator Header //
// Generates really primitive GUI controls (and dialogs) at runtime. //
// Useful for, well, generating really primitive GUI controls and dialogs //
// at runtime...
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUICtrlGenerator_h
#define _pfGUICtrlGenerator_h
#include "hsStream.h"
#include "hsTemplates.h"
//// pfGUICtrlGenerator Definition ///////////////////////////////////////////
class pfGUIDialogMod;
class pfGUIButtonMod;
class pfGUIDragBarCtrl;
class hsGMaterial;
struct hsColorRGBA;
class plSceneNode;
class hsKeyedObject;
class plKey;
class plTextGenerator;
class plSceneObject;
class plDrawable;
struct hsMatrix44;
class pfGUICtrlGenerator
{
protected:
char fFontFace[ 256 ];
UInt32 fFontSize;
hsTArray<plTextGenerator *> fTextGens;
hsTArray<plSceneNode *> fDynDlgNodes;
hsTArray<pfGUIDialogMod *> fDynDialogs;
hsTArray<plSceneObject *> fDynDragBars;
plKey IAddKey( hsKeyedObject *ko, const char *prefix );
void IGetNextKeyName( char *name, const char *prefix );
hsGMaterial *ICreateSolidMaterial( hsColorRGBA &color );
hsGMaterial *ICreateTextMaterial( const char *text, hsColorRGBA &bgColor,
hsColorRGBA &textColor, float objWidth, float objHeight );
pfGUIDialogMod *IGetDialog( void );
pfGUIDialogMod *IGenerateDialog( const char *name, float scrnWidth, hsBool show = true );
plSceneObject *IGenSceneObject( pfGUIDialogMod *dlg, plDrawable *myDraw, plSceneObject *parent = nil, hsMatrix44 *l2w = nil, hsMatrix44 *w2l = nil );
public:
pfGUICtrlGenerator();
~pfGUICtrlGenerator();
void Shutdown( void );
void SetFont( const char *face, UInt16 size );
pfGUIButtonMod *GenerateRectButton( const char *title, float x, float y, float width, float height,
const char *consoleCmd, hsColorRGBA &color, hsColorRGBA &textColor );
pfGUIButtonMod *GenerateSphereButton( float x, float y, float radius,
const char *consoleCmd, hsColorRGBA &color );
pfGUIDragBarCtrl *GenerateDragBar( float x, float y, float width, float height, hsColorRGBA &color );
void GenerateDialog( const char *name );
pfGUIButtonMod *CreateRectButton( pfGUIDialogMod *parent, const char *title, float x, float y,
float width, float height, hsGMaterial *material, hsBool asMenuItem = false );
pfGUIButtonMod *CreateRectButton( pfGUIDialogMod *parent, const wchar_t *title, float x, float y,
float width, float height, hsGMaterial *material, hsBool asMenuItem = false );
static pfGUICtrlGenerator &Instance( void );
};
#endif // _pfGUICtrlGenerator_h

View File

@ -0,0 +1,97 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIDialogHandlers Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIDialogHandlers_h
#define _pfGUIDialogHandlers_h
#include "hsStream.h"
#include "pfGUIControlHandlers.h"
//// pfGUIDialogProc Definition //////////////////////////////////////////////
// This works very much like the control proc objects. The idea is, if you
// want to do some custom work on a dialog (and who doesn't?), you create an
// object derived from this type, override the functions, and do as you
// please. The class type also derives from the control proc type, meaning
// that you can implement DoSomething() as well and use the same object for
// both your dialog and your control procs. (DoSomething() is overloaded here
// so that it's no longer pure virtual, so you can use it for only handling
// dialogs if you prefer).
class pfGUIDialogMod;
class pfGUIDialogProc : public pfGUICtrlProcObject
{
protected:
pfGUIDialogMod *fDialog;
public:
pfGUIDialogProc() { }
virtual ~pfGUIDialogProc() { ; }
// Called by the mgr--don't call yourself!
void SetDialog( pfGUIDialogMod *dlg ) { fDialog = dlg; }
// Enums for OnControlEvent
enum ControlEvt
{
kExitMode
};
//////// FUNCTIONS TO OVERLOAD ////////
// Overloaded here so you don't have to unless you want to. Overload
// it if you want to use this for a control handler as well.
virtual void DoSomething( pfGUIControlMod *ctrl ) {;}
// Called on dialog init (i.e. first showing, before OnShow() is called), only ever called once
virtual void OnInit( void ) { ; }
// Called before the dialog is shown, always after OnInit()
virtual void OnShow( void ) { ; }
// Called before the dialog is hidden
virtual void OnHide( void ) { ; }
// Called on the dialog's destructor, before it's unregistered with the game GUI manager
virtual void OnDestroy( void ) { ; }
// Called when the dialog's focused control changes
virtual void OnCtrlFocusChange( pfGUIControlMod *oldCtrl, pfGUIControlMod *newCtrl ) { ; }
// Called when the key bound to a GUI event is pressed. Only called on the top modal dialog
virtual void OnControlEvent( ControlEvt event ) { ; }
// Called when the GUI changes interesting state
virtual void OnInterestingEvent( pfGUIControlMod *ctrl ) { ; }
};
#endif // _pfGUIDialogHandlers_h

View File

@ -0,0 +1,832 @@
/*==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;
}

View File

@ -0,0 +1,198 @@
/*==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 Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIDialogMod_h
#define _pfGUIDialogMod_h
#include "../pnModifier/plSingleModifier.h"
#include "pfGameGUIMgr.h"
#include "hsMatrix44.h"
class plMessage;
class plPostEffectMod;
class pfGUIControlMod;
class pfGUIDialogProc;
class pfGUIListElement;
class pfGUIColorScheme;
class pfGUIDialogMod : public plSingleModifier
{
private:
pfGUIDialogMod *fNext, **fPrevPtr;
protected:
UInt32 fTagID; // 0 if none
UInt32 fVersion; // Nice for syncing to C++ code
plPostEffectMod *fRenderMod;
hsBool fEnabled;
char fName[ 128 ];
hsTArray<pfGUIControlMod *> fControls;
pfGUIControlMod *fControlOfInterest;
pfGUIControlMod *fFocusCtrl;
pfGUIControlMod *fMousedCtrl; // Which one is the mouse over?
pfGUIColorScheme *fColorScheme;
pfGUIDialogProc *fHandler;
plKey fProcReceiver; // Non-nil means we handle everything by creating notify messages and sending them to this key
hsTArray<pfGUIListElement *> fDragElements;
hsBool fDragMode, fDragReceptive;
pfGUIControlMod *fDragTarget;
pfGUIControlMod *fDragSource;
plKey fSceneNodeKey;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
void IHandleDrag( hsPoint3 &mousePt, pfGameGUIMgr::EventType event, UInt8 modifiers );
public:
enum
{
kRenderModRef = 0,
kControlRef,
kRefDerviedStart
};
enum Flags
{
kModal,
kDerivedFlagsStart
};
pfGUIDialogMod();
virtual ~pfGUIDialogMod();
CLASSNAME_REGISTER( pfGUIDialogMod );
GETINTERFACE_ANY( pfGUIDialogMod, plSingleModifier );
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
void SetSceneNodeKey( plKey &key ) { fSceneNodeKey = key; }
plKey GetSceneNodeKey( void );
virtual void SetEnabled( hsBool e );
hsBool IsEnabled( void ) { return fEnabled; }
const char *GetName( void ) { return fName; }
void ScreenToWorldPoint( hsScalar x, hsScalar y, hsScalar z, hsPoint3 &outPt );
hsPoint3 WorldToScreenPoint( const hsPoint3 &inPt );
virtual hsBool HandleMouseEvent( pfGameGUIMgr::EventType event, hsScalar mouseX, hsScalar mouseY, UInt8 modifiers );
hsBool HandleKeyEvent( pfGameGUIMgr::EventType event, plKeyDef key, UInt8 modifiers );
hsBool HandleKeyPress( char key, UInt8 modifiers );
void UpdateInterestingThings( hsScalar mouseX, hsScalar mouseY, UInt8 modifiers, hsBool modalPreset );
void SetControlOfInterest( pfGUIControlMod *c );
pfGUIControlMod *GetControlOfInterest( void ) const { return fControlOfInterest; }
UInt32 GetDesiredCursor( void ) const;
void UpdateAspectRatio( void );
void UpdateAllBounds( void );
void RefreshAllControls( void );
void AddControl( pfGUIControlMod *ctrl );
UInt32 GetNumControls( void ) { return fControls.GetCount(); }
pfGUIControlMod *GetControl( UInt32 idx ) { return fControls[ idx ]; }
pfGUIColorScheme *GetColorScheme( void ) const { return fColorScheme; }
void LinkToList( pfGUIDialogMod **prevPtr )
{
fNext = *prevPtr;
if( *prevPtr )
(*prevPtr)->fPrevPtr = &fNext;
fPrevPtr = prevPtr;
*prevPtr = this;
}
void Unlink( void )
{
if( fNext )
fNext->fPrevPtr = fPrevPtr;
*fPrevPtr = fNext;
fPrevPtr = nil;
fNext = nil;
}
void SetFocus( pfGUIControlMod *ctrl );
void Show( void );
void ShowNoReset( void );
void Hide( void );
hsBool IsVisible( void ) { return IsEnabled(); }
pfGUIControlMod *GetFocus( void ) { return fFocusCtrl; }
pfGUIDialogMod *GetNext( void ) { return fNext; }
UInt32 GetTagID( void ) { return fTagID; }
pfGUIControlMod *GetControlFromTag( UInt32 tagID );
void SetHandler( pfGUIDialogProc *hdlr );
pfGUIDialogProc *GetHandler( void ) const { return fHandler; }
plPostEffectMod *GetRenderMod( void ) const { return fRenderMod; }
// This sets the handler for the dialog and ALL of its controls
void SetHandlerForAll( pfGUIDialogProc *hdlr );
// Just a little macro-type thing here
void SetControlHandler( UInt32 tagID, pfGUIDialogProc *hdlr );
/// Methods for doing drag & drop of listElements
void ClearDragList( void );
void AddToDragList( pfGUIListElement *e );
void EnterDragMode( pfGUIControlMod *source );
UInt32 GetVersion( void ) const { return fVersion; }
// Export only
void SetRenderMod( plPostEffectMod *mod ) { fRenderMod = mod; }
void SetName( const char *name ) { hsStrncpy( fName, name, sizeof( fName ) - 1 ); }
void AddControlOnExport( pfGUIControlMod *ctrl );
void SetTagID( UInt32 id ) { fTagID = id; }
void SetProcReceiver( plKey key ) { fProcReceiver = key; }
void SetVersion( UInt32 version ) { fVersion = version; }
};
#endif // _pfGUIDialogMod_h

View File

@ -0,0 +1,131 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIDialogNotifyProc //
// //
// Helper dialog proc that takes all control events and turns them into //
// notify messages that get sent out. //
//////////////////////////////////////////////////////////////////////////////
#include "pfGUIDialogNotifyProc.h"
#include "hsTypes.h"
#include "pfGameGUIMgr.h"
#include "pfGUIDialogMod.h"
#include "pfGUIControlMod.h"
#include "pfGUIDialogHandlers.h"
#include "pfGUIListElement.h"
#include "pfGUIButtonMod.h" // Next three are for notify stuff
#include "pfGUIListBoxMod.h"
#include "pfGUIEditBoxMod.h"
#include "../pfMessage/pfGUINotifyMsg.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
pfGUIDialogNotifyProc::pfGUIDialogNotifyProc( plKey &r )
{
fReceiver = r;
}
void pfGUIDialogNotifyProc::ISendNotify( plKey ctrlKey, UInt32 event )
{
pfGUINotifyMsg *notify = TRACKED_NEW pfGUINotifyMsg( fDialog->GetKey(), fReceiver, nil );
notify->SetEvent( ctrlKey, event );
plgDispatch::MsgSend( notify );
}
void pfGUIDialogNotifyProc::DoSomething( pfGUIControlMod *ctrl )
{
if( pfGUIButtonMod::ConvertNoRef( ctrl ) != nil ||
pfGUIListBoxMod::ConvertNoRef( ctrl ) != nil ||
pfGUIEditBoxMod::ConvertNoRef( ctrl ) != nil )
{
// only fire the button if it is triggering
// ... all other types just fire
pfGUIButtonMod* btn = pfGUIButtonMod::ConvertNoRef( ctrl );
if ( !btn || btn->IsTriggering() )
ISendNotify( ctrl->GetKey(), pfGUINotifyMsg::kAction );
}
else
ISendNotify( ctrl->GetKey(), pfGUINotifyMsg::kValueChanged );
}
void pfGUIDialogNotifyProc::OnInit( void )
{
if ( fDialog )
ISendNotify( fDialog->GetKey(), pfGUINotifyMsg::kDialogLoaded );
else
ISendNotify( nil, pfGUINotifyMsg::kDialogLoaded );
}
void pfGUIDialogNotifyProc::OnShow( void )
{
if ( fDialog )
ISendNotify( fDialog->GetKey(), pfGUINotifyMsg::kShowHide );
else
ISendNotify( nil, pfGUINotifyMsg::kShowHide );
}
void pfGUIDialogNotifyProc::OnHide( void )
{
if ( fDialog )
ISendNotify( fDialog->GetKey(), pfGUINotifyMsg::kShowHide );
else
ISendNotify( nil, pfGUINotifyMsg::kShowHide );
}
void pfGUIDialogNotifyProc::OnDestroy( void )
{
}
void pfGUIDialogNotifyProc::OnControlEvent( ControlEvt event )
{
if( event == kExitMode )
ISendNotify( ( fDialog != nil ) ? fDialog->GetKey() : nil, pfGUINotifyMsg::kExitMode );
}
// Called when the dialog's focused control changes
void pfGUIDialogNotifyProc::OnCtrlFocusChange( pfGUIControlMod *oldCtrl, pfGUIControlMod *newCtrl )
{
if ( newCtrl )
ISendNotify( newCtrl->GetKey(), pfGUINotifyMsg::kFocusChange);
else
ISendNotify( nil, pfGUINotifyMsg::kFocusChange);
}
void pfGUIDialogNotifyProc::OnInterestingEvent( pfGUIControlMod *ctrl )
{
ISendNotify( ( ctrl != nil ) ? ctrl->GetKey() : nil, pfGUINotifyMsg::kInterestingEvent );
}

View File

@ -0,0 +1,66 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIDialogNotifyProc Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIDialogNotifyProc_h
#define _pfGUIDialogNotifyProc_h
#include "pfGUIDialogHandlers.h"
#include "../pnKeyedObject/plKey.h"
class plGUIControlMod;
//// pfGUIDialogNotifyProc Definition ////////////////////////////////////////
// Helper dialog proc that takes all control events and turns them into
// notify messages that get sent out.
class pfGUIDialogNotifyProc : public pfGUIDialogProc
{
protected:
plKey fReceiver;
void ISendNotify( plKey ctrlKey, UInt32 event );
public:
pfGUIDialogNotifyProc( plKey &r );
virtual void DoSomething( pfGUIControlMod *ctrl );
virtual void OnInit( void );
virtual void OnShow( void );
virtual void OnHide( void );
virtual void OnDestroy( void );
virtual void OnCtrlFocusChange( pfGUIControlMod *oldCtrl, pfGUIControlMod *newCtrl );
virtual void OnControlEvent( ControlEvt event );
virtual void OnInterestingEvent( pfGUIControlMod *ctrl );
};
#endif // _pfGUIDialogNotifyProc_h

View File

@ -0,0 +1,149 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIDragBarCtrl Definition //
// //
// DragBars are draggable controls that take their dialogs along with //
// them. Because they're essentially part of the dialog directly (the part //
// that can be dragged), they're processed after the normal hit testing. //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUIDragBarCtrl.h"
#include "pfGameGUIMgr.h"
#include "pfGUIDialogMod.h"
#include "../plInputCore/plInputInterface.h"
#include "../pnMessage/plRefMsg.h"
#include "../pfMessage/pfGameGUIMsg.h"
#include "../plMessage/plAnimCmdMsg.h"
#include "../plAvatar/plAGModifier.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIDragBarCtrl::pfGUIDragBarCtrl()
{
SetFlag( kWantsInterest );
fDragging = false;
fAnchored = false;
}
pfGUIDragBarCtrl::~pfGUIDragBarCtrl()
{
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool pfGUIDragBarCtrl::IEval( double secs, hsScalar del, UInt32 dirty )
{
return pfGUIControlMod::IEval( secs, del, dirty );
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGUIDragBarCtrl::MsgReceive( plMessage *msg )
{
return pfGUIControlMod::MsgReceive( msg );
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUIDragBarCtrl::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Read(s, mgr);
}
void pfGUIDragBarCtrl::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Write( s, mgr );
}
//// UpdateBounds ////////////////////////////////////////////////////////////
void pfGUIDragBarCtrl::UpdateBounds( hsMatrix44 *invXformMatrix, hsBool force )
{
pfGUIControlMod::UpdateBounds( invXformMatrix, force );
fBoundsValid = false;
}
//// HandleMouseDown/Up //////////////////////////////////////////////////////
void pfGUIDragBarCtrl::HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers )
{
// if we are anchored <to the floor> then don't let it be moved
if ( fAnchored )
return;
fDragging = true;
fDragOffset = fScreenCenter - mousePt;
SetObjectCenter( mousePt.fX + fDragOffset.fX, mousePt.fY + fDragOffset.fY );
// We know that the entire dialog is going to move, so we better make
// sure to update the bounds on all the controls
fDialog->UpdateAllBounds();
}
void pfGUIDragBarCtrl::HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers )
{
// if we are anchored <to the floor> then don't let it be moved
if ( fAnchored )
return;
fDragging = false;
SetObjectCenter( mousePt.fX + fDragOffset.fX, mousePt.fY + fDragOffset.fY );
fDialog->UpdateAllBounds();
}
void pfGUIDragBarCtrl::HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers )
{
// if we are anchored <to the floor> then don't let it be moved
if ( fAnchored )
return;
SetObjectCenter( mousePt.fX + fDragOffset.fX, mousePt.fY + fDragOffset.fY );
fDialog->UpdateAllBounds();
}
//// IGetDesiredCursor ///////////////////////////////////////////////////////
UInt32 pfGUIDragBarCtrl::IGetDesiredCursor( void ) const
{
// if we are anchored, then no cursors that say we can move
if ( fAnchored )
return 0;
if( fDragging )
return plInputInterface::kCursor4WayDragging;
return plInputInterface::kCursor4WayDraggable;
}

View File

@ -0,0 +1,77 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIDragBarCtrl Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIDragBarCtrl_h
#define _pfGUIDragBarCtrl_h
#include "pfGUIControlMod.h"
class plMessage;
class pfGUIDragBarCtrl : public pfGUIControlMod
{
protected:
hsPoint3 fDragOffset;
hsBool fDragging;
hsBool fAnchored;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
virtual UInt32 IGetDesiredCursor( void ) const; // As specified in plInputInterface.h
public:
pfGUIDragBarCtrl();
virtual ~pfGUIDragBarCtrl();
CLASSNAME_REGISTER( pfGUIDragBarCtrl );
GETINTERFACE_ANY( pfGUIDragBarCtrl, pfGUIControlMod );
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
virtual void HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers );
virtual void SetAnchored( hsBool anchored ) { fAnchored = anchored; }
virtual hsBool IsAnchored(void) { return fAnchored; }
virtual void UpdateBounds( hsMatrix44 *invXformMatrix = nil, hsBool force = false );
// Export only
};
#endif // _pfGUIDragBarCtrl_h

View File

@ -0,0 +1,165 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIDraggableMod Definition //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUIDraggableMod.h"
#include "pfGameGUIMgr.h"
#include "../pnMessage/plRefMsg.h"
#include "../pfMessage/pfGameGUIMsg.h"
#include "../plMessage/plAnimCmdMsg.h"
#include "../plAvatar/plAGModifier.h"
#include "../plInputCore/plInputInterface.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIDraggableMod::pfGUIDraggableMod()
{
SetFlag( kWantsInterest );
fDragging = false;
}
pfGUIDraggableMod::~pfGUIDraggableMod()
{
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool pfGUIDraggableMod::IEval( double secs, hsScalar del, UInt32 dirty )
{
return pfGUIControlMod::IEval( secs, del, dirty );
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGUIDraggableMod::MsgReceive( plMessage *msg )
{
return pfGUIControlMod::MsgReceive( msg );
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUIDraggableMod::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Read(s, mgr);
}
void pfGUIDraggableMod::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Write( s, mgr );
}
//// UpdateBounds ////////////////////////////////////////////////////////////
void pfGUIDraggableMod::UpdateBounds( hsMatrix44 *invXformMatrix, hsBool force )
{
pfGUIControlMod::UpdateBounds( invXformMatrix, force );
fBoundsValid = false;
}
//// HandleMouseDown/Up //////////////////////////////////////////////////////
void pfGUIDraggableMod::HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers )
{
if( !fDragging )
{
fLastMousePt = mousePt;
fOrigCenter = fScreenCenter;
fDragging = true;
fDragOffset = fScreenCenter - mousePt;
SetObjectCenter( mousePt.fX + fDragOffset.fX, mousePt.fY + fDragOffset.fY );
HandleExtendedEvent( kStartingDrag );
}
}
void pfGUIDraggableMod::HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers )
{
if( fDragging )
{
fLastMousePt = mousePt;
fDragging = false;
SetObjectCenter( mousePt.fX + fDragOffset.fX, mousePt.fY + fDragOffset.fY );
DoSomething();
if( HasFlag( kAlwaysSnapBackToStart ) )
SetObjectCenter( fOrigCenter.fX, fOrigCenter.fY );
}
}
void pfGUIDraggableMod::HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers )
{
if( fDragging )
{
fLastMousePt = mousePt;
SetObjectCenter( mousePt.fX + fDragOffset.fX, mousePt.fY + fDragOffset.fY );
if( HasFlag( kReportDragging ) )
HandleExtendedEvent( kDragging );
}
}
//// IGetDesiredCursor ///////////////////////////////////////////////////////
UInt32 pfGUIDraggableMod::IGetDesiredCursor( void ) const
{
// if we are anchored, then no cursors that say we can move
if( fDragging )
{
if( HasFlag( kHideCursorWhileDragging ) )
return plInputInterface::kCursorHidden;
return plInputInterface::kCursor4WayDragging;
}
return plInputInterface::kCursor4WayDraggable;
}
void pfGUIDraggableMod::StopDragging( hsBool cancel )
{
if( fDragging )
{
fDragging = false;
if( cancel )
HandleExtendedEvent( kCancelled );
if( HasFlag( kAlwaysSnapBackToStart ) )
SetObjectCenter( fOrigCenter.fX, fOrigCenter.fY );
}
}

View File

@ -0,0 +1,90 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIDraggableMod Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIDraggableMod_h
#define _pfGUIDraggableMod_h
#include "pfGUIControlMod.h"
class plMessage;
class pfGUIDraggableMod : public pfGUIControlMod
{
protected:
hsPoint3 fDragOffset, fLastMousePt;
hsPoint3 fOrigCenter;
hsBool fDragging;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
virtual UInt32 IGetDesiredCursor( void ) const; // As specified in plInputInterface.h
public:
pfGUIDraggableMod();
virtual ~pfGUIDraggableMod();
CLASSNAME_REGISTER( pfGUIDraggableMod );
GETINTERFACE_ANY( pfGUIDraggableMod, pfGUIControlMod );
enum OurFlags
{
kReportDragging = kDerivedFlagsStart,
kHideCursorWhileDragging,
kAlwaysSnapBackToStart
};
// Extended event types (endDrag is the default event)
enum ExtendedEvents
{
kDragging,
kCancelled,
kStartingDrag
};
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
virtual void HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers );
virtual void UpdateBounds( hsMatrix44 *invXformMatrix = nil, hsBool force = false );
void StopDragging( hsBool cancel );
const hsPoint3 &GetLastMousePt( void ) const { return fLastMousePt; }
};
#endif // _pfGUIDraggableMod_h

View File

@ -0,0 +1,169 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIDynDisplayCtrl Definition //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUIDynDisplayCtrl.h"
#include "pfGameGUIMgr.h"
#include "../pnMessage/plRefMsg.h"
#include "../plGImage/plDynamicTextMap.h"
#include "../plSurface/plLayerInterface.h"
#include "../plSurface/hsGMaterial.h"
#include "../plPipeline/plTextGenerator.h"
#include "plPipeline.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIDynDisplayCtrl::pfGUIDynDisplayCtrl()
{
SetFlag( kIntangible );
}
pfGUIDynDisplayCtrl::~pfGUIDynDisplayCtrl()
{
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool pfGUIDynDisplayCtrl::IEval( double secs, hsScalar del, UInt32 dirty )
{
return pfGUIControlMod::IEval( secs, del, dirty );
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGUIDynDisplayCtrl::MsgReceive( plMessage *msg )
{
plGenRefMsg *refMsg = plGenRefMsg::ConvertNoRef( msg );
if( refMsg != nil )
{
if( refMsg->fType == kRefTextMap )
{
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
fTextMaps[ refMsg->fWhich ] = plDynamicTextMap::ConvertNoRef( refMsg->GetRef() );
else
fTextMaps[ refMsg->fWhich ] = nil;
return true;
}
else if( refMsg->fType == kRefLayer )
{
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
fLayers[ refMsg->fWhich ] = plLayerInterface::ConvertNoRef( refMsg->GetRef() );
else
fLayers[ refMsg->fWhich ] = nil;
return true;
}
else if( refMsg->fType == kRefMaterial )
{
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
fMaterials[ refMsg->fWhich ] = hsGMaterial::ConvertNoRef( refMsg->GetRef() );
else
fMaterials[ refMsg->fWhich ] = nil;
}
}
return pfGUIControlMod::MsgReceive( msg );
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUIDynDisplayCtrl::Read( hsStream *s, hsResMgr *mgr )
{
UInt32 count, i;
pfGUIControlMod::Read(s, mgr);
count = s->ReadSwap32();
fTextMaps.SetCountAndZero( count );
for( i = 0; i < count; i++ )
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, i, kRefTextMap ), plRefFlags::kActiveRef );
count = s->ReadSwap32();
fLayers.SetCountAndZero( count );
for( i = 0; i < count; i++ )
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, i, kRefLayer ), plRefFlags::kActiveRef );
count = s->ReadSwap32();
fMaterials.SetCountAndZero( count );
for( i = 0; i < count; i++ )
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, i, kRefMaterial ), plRefFlags::kActiveRef );
}
void pfGUIDynDisplayCtrl::Write( hsStream *s, hsResMgr *mgr )
{
UInt32 i;
pfGUIControlMod::Write( s, mgr );
s->WriteSwap32( fTextMaps.GetCount() );
for( i = 0; i < fTextMaps.GetCount(); i++ )
mgr->WriteKey( s, fTextMaps[ i ]->GetKey() );
s->WriteSwap32( fLayers.GetCount() );
for( i = 0; i < fLayers.GetCount(); i++ )
mgr->WriteKey( s, fLayers[ i ]->GetKey() );
s->WriteSwap32( fMaterials.GetCount() );
for( i = 0; i < fMaterials.GetCount(); i++ )
mgr->WriteKey( s, fMaterials[ i ]->GetKey() );
}
//// AddMap //////////////////////////////////////////////////////////////////
// Export only
void pfGUIDynDisplayCtrl::AddMap( plDynamicTextMap *map )
{
fTextMaps.Append( map );
hsgResMgr::ResMgr()->AddViaNotify( map->GetKey(), TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, fTextMaps.GetCount() - 1, kRefTextMap ), plRefFlags::kActiveRef );
}
//// AddLayer ////////////////////////////////////////////////////////////////
// Export only
void pfGUIDynDisplayCtrl::AddLayer( plLayerInterface *layer )
{
fLayers.Append( layer );
hsgResMgr::ResMgr()->AddViaNotify( layer->GetKey(), TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, fLayers.GetCount() - 1, kRefLayer ), plRefFlags::kActiveRef );
}
//// AddMaterial /////////////////////////////////////////////////////////////
// Export only
void pfGUIDynDisplayCtrl::AddMaterial( hsGMaterial *material )
{
fMaterials.Append( material );
hsgResMgr::ResMgr()->AddViaNotify( material->GetKey(), TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, fMaterials.GetCount() - 1, kRefMaterial ), plRefFlags::kActiveRef );
}

View File

@ -0,0 +1,97 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIDynDisplayCtrl Header //
// //
// Fun little helper control that just stores a pointer to a single //
// plDynamicTextMap, chosen in MAX. Note that we could also just search //
// for the right key name, but that requires a StupidSearch(tm), while //
// this way just requires an extra dummy control that automatically reads //
// in the right ref (and searching for controls by TagID is a lot faster //
// than searching for keys). //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIDynDisplayCtrl_h
#define _pfGUIDynDisplayCtrl_h
#include "pfGUIControlMod.h"
#include "hsTemplates.h"
class plMessage;
class plDynamicTextMap;
class plLayerInterface;
class hsGMaterial;
class pfGUIDynDisplayCtrl : public pfGUIControlMod
{
protected:
enum
{
kRefTextMap = kRefDerivedStart,
kRefLayer,
kRefMaterial
};
hsTArray<plDynamicTextMap *> fTextMaps;
hsTArray<plLayerInterface *> fLayers;
hsTArray<hsGMaterial *> fMaterials;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
public:
pfGUIDynDisplayCtrl();
virtual ~pfGUIDynDisplayCtrl();
CLASSNAME_REGISTER( pfGUIDynDisplayCtrl );
GETINTERFACE_ANY( pfGUIDynDisplayCtrl, pfGUIControlMod );
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
UInt32 GetNumMaps( void ) const { return fTextMaps.GetCount(); }
plDynamicTextMap *GetMap( UInt32 i ) const { return fTextMaps[ i ]; }
UInt32 GetNumLayers( void ) const { return fLayers.GetCount(); }
plLayerInterface *GetLayer( UInt32 i ) const { return fLayers[ i ]; }
UInt32 GetNumMaterials( void ) const { return fMaterials.GetCount(); }
hsGMaterial *GetMaterial( UInt32 i ) const { return fMaterials[ i ]; }
// Export only
void AddMap( plDynamicTextMap *map );
void AddLayer( plLayerInterface *layer );
void AddMaterial( hsGMaterial *material );
};
#endif // _pfGUIDynDisplayCtrl_h

View File

@ -0,0 +1,650 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIEditBoxMod Definition //
// //
//////////////////////////////////////////////////////////////////////////////
#ifdef PLASMA_EXTERNAL_RELEASE
//#define LIMIT_VOICE_CHAT 1
#endif
#include "hsTypes.h"
#include "pfGUIEditBoxMod.h"
#include "pfGameGUIMgr.h"
#include "../pnMessage/plRefMsg.h"
#include "../pfMessage/pfGameGUIMsg.h"
#include "../plMessage/plAnimCmdMsg.h"
#include "../plAvatar/plAGModifier.h"
#include "../plGImage/plDynamicTextMap.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
#include "../pnInputCore/plKeyMap.h"
#include <locale>
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIEditBoxMod::pfGUIEditBoxMod()
{
SetFlag( kWantsInterest );
SetFlag( kTakesSpecialKeys );
fIgnoreNextKey = false;
fEscapedFlag = false;
fFirstHalfExitKeyPushed = false;
fSpecialCaptureKeyEventMode = false;
fBuffer = 0;
fLastDeadKey = 0;
SetBufferSize( 128 );
SetupDeadKeyConverter();
}
pfGUIEditBoxMod::~pfGUIEditBoxMod()
{
delete [] fBuffer;
}
void pfGUIEditBoxMod::SetupDeadKeyConverter()
{
int i,j;
for (i=0; i<255; i++)
for (j=0; j<255; j++)
fDeadKeyConverter[i][j] = 0L;
// we are adding 100 to the indexes because some of these chars have a negative index for some reason
fDeadKeyConverter['^'+100]['a'] = L'<EFBFBD>';
fDeadKeyConverter['^'+100]['e'] = L'<EFBFBD>';
fDeadKeyConverter['^'+100]['i'] = L'<EFBFBD>';
fDeadKeyConverter['^'+100]['o'] = L'<EFBFBD>';
fDeadKeyConverter['^'+100]['u'] = L'<EFBFBD>';
fDeadKeyConverter['^'+100]['A'] = L'<EFBFBD>';
fDeadKeyConverter['^'+100]['E'] = L'<EFBFBD>';
fDeadKeyConverter['^'+100]['I'] = L'<EFBFBD>';
fDeadKeyConverter['^'+100]['O'] = L'<EFBFBD>';
fDeadKeyConverter['^'+100]['U'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['a'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['e'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['i'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['o'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['u'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['A'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['E'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['I'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['O'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['U'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['a'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['e'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['i'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['o'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['u'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['y'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['A'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['E'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['I'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['O'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['U'] = L'<EFBFBD>';
fDeadKeyConverter['<EFBFBD>'+100]['Y'] = L'<EFBFBD>';
fDeadKeyConverter['`'+100]['a'] = L'<EFBFBD>';
fDeadKeyConverter['`'+100]['e'] = L'<EFBFBD>';
fDeadKeyConverter['`'+100]['i'] = L'<EFBFBD>';
fDeadKeyConverter['`'+100]['o'] = L'<EFBFBD>';
fDeadKeyConverter['`'+100]['u'] = L'<EFBFBD>';
fDeadKeyConverter['`'+100]['A'] = L'<EFBFBD>';
fDeadKeyConverter['`'+100]['E'] = L'<EFBFBD>';
fDeadKeyConverter['`'+100]['I'] = L'<EFBFBD>';
fDeadKeyConverter['`'+100]['O'] = L'<EFBFBD>';
fDeadKeyConverter['`'+100]['U'] = L'<EFBFBD>';
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool pfGUIEditBoxMod::IEval( double secs, hsScalar del, UInt32 dirty )
{
return pfGUIControlMod::IEval( secs, del, dirty );
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGUIEditBoxMod::MsgReceive( plMessage *msg )
{
return pfGUIControlMod::MsgReceive( msg );
}
//// IPostSetUpDynTextMap ////////////////////////////////////////////////////
void pfGUIEditBoxMod::IPostSetUpDynTextMap( void )
{
pfGUIColorScheme *scheme = GetColorScheme();
fDynTextMap->SetFont( scheme->fFontFace, scheme->fFontSize, scheme->fFontFlags,
HasFlag( kXparentBgnd ) ? false : true );
}
//// IUpdate /////////////////////////////////////////////////////////////////
void pfGUIEditBoxMod::IUpdate( void )
{
hsColorRGBA c;
if( fDynTextMap == nil || !fDynTextMap->IsValid() )
return;
c.Set( 0.f, 0.f, 0.f, 1.f );
if ( fFocused && fSpecialCaptureKeyEventMode )
fDynTextMap->ClearToColor( GetColorScheme()->fSelBackColor );
else
fDynTextMap->ClearToColor( GetColorScheme()->fBackColor );
if( fBuffer != nil )
{
// First, calc the cursor position, so we can adjust the scrollPos as necessary
Int16 cursorPos, oldCursorPos;
if( fFocused && !fSpecialCaptureKeyEventMode )
{
// Really cheap hack here to figure out where to draw the cursor
wchar_t backup = fBuffer[ fCursorPos ];
fBuffer[ fCursorPos ] = 0;
cursorPos = fDynTextMap->CalcStringWidth( fBuffer );
fBuffer[ fCursorPos ] = backup;
oldCursorPos = cursorPos;
cursorPos -= (Int16)fScrollPos;
if( 4 + cursorPos > fDynTextMap->GetVisibleWidth() - 18 )
{
fScrollPos += ( 4 + cursorPos ) - ( fDynTextMap->GetVisibleWidth() - 18 );
}
else if( 4 + cursorPos < 4 )
{
fScrollPos -= 4 - ( 4 + cursorPos );
if( fScrollPos < 0 )
fScrollPos = 0;
}
cursorPos = (Int16)(oldCursorPos - fScrollPos);
}
if ( fFocused && fSpecialCaptureKeyEventMode )
// if special and has focus then use select
fDynTextMap->SetTextColor( GetColorScheme()->fSelForeColor, GetColorScheme()->fTransparent &&
GetColorScheme()->fSelBackColor.a == 0.f );
else
fDynTextMap->SetTextColor( GetColorScheme()->fForeColor, GetColorScheme()->fTransparent &&
GetColorScheme()->fBackColor.a == 0.f );
fDynTextMap->DrawClippedString( (Int16)(4 - fScrollPos), 4, fBuffer,
4, 4, fDynTextMap->GetVisibleWidth() - 8, fDynTextMap->GetVisibleHeight() - 8 );
if( fFocused && !fSpecialCaptureKeyEventMode )
{
fDynTextMap->FrameRect( 4 + cursorPos, 4, 2, fDynTextMap->GetVisibleHeight() - 8, GetColorScheme()->fSelForeColor );
}
}
fDynTextMap->FlushToHost();
}
void pfGUIEditBoxMod::PurgeDynaTextMapImage()
{
if ( fDynTextMap != nil )
fDynTextMap->PurgeImage();
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUIEditBoxMod::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Read(s, mgr);
}
void pfGUIEditBoxMod::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Write( s, mgr );
}
//// HandleMouseDown /////////////////////////////////////////////////////////
// What we do: normal click deselects all and selects the item clicked on
// (if any). Shift-click and ctrl-click avoids the deselect and toggles
// the item clicked on.
void pfGUIEditBoxMod::HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers )
{
wchar_t backup;
UInt16 width;
if( fBuffer != nil && fDynTextMap != nil )
{
if( !fBounds.IsInside( &mousePt ) )
return;
IScreenToLocalPt( mousePt );
mousePt.fX *= fDynTextMap->GetVisibleWidth();
mousePt.fX += fScrollPos - 4;
for( fCursorPos = 0; fCursorPos < wcslen( fBuffer ); fCursorPos++ )
{
backup = fBuffer[ fCursorPos + 1 ];
fBuffer[ fCursorPos + 1 ] = 0;
width = fDynTextMap->CalcStringWidth( fBuffer );
fBuffer[ fCursorPos + 1 ] = backup;
if( width > mousePt.fX )
break;
}
IUpdate();
}
}
//// HandleMouseUp ///////////////////////////////////////////////////////////
void pfGUIEditBoxMod::HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers )
{
}
//// HandleMouseDrag /////////////////////////////////////////////////////////
void pfGUIEditBoxMod::HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers )
{
}
hsBool pfGUIEditBoxMod::HandleKeyPress( char inKey, UInt8 modifiers )
{
wchar_t key = (wchar_t)inKey;
if( fBuffer == nil )
return false;
if( fIgnoreNextKey )
{
// So we don't process keys that already got handled by HandleKeyEvent()
fIgnoreNextKey = false;
return true;
}
if (plKeyboardDevice::KeyIsDeadKey())
{
if (fLastDeadKey != 0)
{
wchar_t temp = key; // we have two dead keys in a row, print out the old one and store the new one
key = fLastDeadKey;
fLastDeadKey = temp;
}
else
{
fLastDeadKey = key; // store the dead key and don't print it until we get the next char
return true;
}
}
int i = wcslen( fBuffer );
if (fLastDeadKey != 0) // we have a dead key that needs to be added in
{
wchar_t translatedKey = fDeadKeyConverter[(char)fLastDeadKey+100][(char)key];
if (translatedKey == 0) // no translation possible?
{
// so we need to print the dead key, followed by the typed key
// unless key is a space, then we just type the dead key
if (key == L' ')
{
if (i<fBufferSize - 1)
{
memmove(fBuffer+fCursorPos+1, fBuffer+fCursorPos, (i - fCursorPos + 1) * sizeof(wchar_t));
fBuffer[fCursorPos] = fLastDeadKey;
fCursorPos++;
HandleExtendedEvent(kValueChanging);
}
fLastDeadKey = 0L;
IUpdate();
return true;
}
// print two chars now
if (i<fBufferSize - 2 && key != 0L)
{
memmove(fBuffer+fCursorPos+2, fBuffer+fCursorPos, (i - fCursorPos + 2) * sizeof(wchar_t));
fBuffer[fCursorPos] = fLastDeadKey;
fCursorPos++;
fBuffer[fCursorPos] = key;
fCursorPos++;
HandleExtendedEvent( kValueChanging );
}
fLastDeadKey = 0L;
IUpdate();
return true;
}
// ok, so we have a translated key now, so assign it to our key and print it normally
key = translatedKey;
fLastDeadKey = 0;
}
// Insert character at the current cursor position, then inc the cursor by one
if( i < fBufferSize - 1 && key != 0 )
{
memmove( fBuffer + fCursorPos + 1, fBuffer + fCursorPos, (i - fCursorPos + 1) * sizeof(wchar_t) );
fBuffer[ fCursorPos ] = key;
fCursorPos++;
HandleExtendedEvent( kValueChanging );
}
IUpdate();
return true;
}
hsBool pfGUIEditBoxMod::HandleKeyEvent( pfGameGUIMgr::EventType event, plKeyDef key, UInt8 modifiers )
{
if ( fSpecialCaptureKeyEventMode)
{
// handle doing special caputre mode
if ( event == pfGameGUIMgr::kKeyDown )
{
#ifdef LIMIT_VOICE_CHAT
// don't allow them to map the TAB key to anything! 'cause we'll use it later
if ( key == KEY_TAB)
{
fIgnoreNextKey = true;
fFirstHalfExitKeyPushed = false;
return true;
}
#endif
// capture the key
fSavedKey = key;
fSavedModifiers = modifiers;
// turn key event into string
char keyStr[30];
if (plKeyMap::ConvertVKeyToChar( key ))
strcpy(keyStr, plKeyMap::ConvertVKeyToChar( key ));
else
memset(keyStr, 0, sizeof(keyStr));
static char shortKey[ 2 ];
if( strlen(keyStr) == 0 )
{
if( isalnum( key ) )
{
shortKey[ 0 ] = (char)key;
shortKey[ 1 ] = 0;
strcpy(keyStr, shortKey);
}
else
strcpy(keyStr, plKeyMap::GetStringUnmapped());
}
else
{
// check to see the buffer has ForewardSlash and change it to ForwardSlash
if ( strcmp(keyStr,"ForewardSlash") == 0)
{
strcpy(keyStr,"ForwardSlash");
}
}
static char newKey[ 16 ];
newKey[0] = 0;
if( modifiers & kShift )
strcat( newKey, plKeyMap::GetStringShift() );
if( modifiers & kCtrl )
strcat( newKey, plKeyMap::GetStringCtrl() );
strcat( newKey, keyStr );
// set something in the buffer to be displayed
wchar_t* temp = hsStringToWString(newKey);
wcsncpy( fBuffer, temp , fBufferSize - 1 );
delete [] temp;
fCursorPos = 0;
SetCursorToEnd();
IUpdate();
// done capturing... tell the handler
DoSomething();
}
fIgnoreNextKey = true;
fFirstHalfExitKeyPushed = false;
return true;
}
else
{
// HACK for now--pass through caps lock so the runlock stuff will work even while a GUI is up
if( key == KEY_CAPSLOCK )
return false;
if( event == pfGameGUIMgr::kKeyDown || event == pfGameGUIMgr::kKeyRepeat )
{
fFirstHalfExitKeyPushed = false;
// Use arrow keys to do our dirty work
if( key == KEY_UP || key == KEY_HOME )
{
SetCursorToHome();
}
else if( key == KEY_DOWN || key == KEY_END )
{
SetCursorToEnd();
}
else if( key == KEY_LEFT )
{
if( fCursorPos > 0 )
fCursorPos--;
}
else if( key == KEY_RIGHT && fBuffer != nil )
{
if( fCursorPos < wcslen( fBuffer ) )
fCursorPos++;
}
else if( key == KEY_BACKSPACE && fBuffer != nil )
{
if( fCursorPos > 0 )
{
fCursorPos--;
memmove( fBuffer + fCursorPos, fBuffer + fCursorPos + 1, (wcslen( fBuffer + fCursorPos + 1 ) + 1) * sizeof(wchar_t) );
}
}
else if( key == KEY_DELETE && fBuffer != nil )
{
if( fCursorPos < wcslen( fBuffer ) )
memmove( fBuffer + fCursorPos, fBuffer + fCursorPos + 1, (wcslen( fBuffer + fCursorPos + 1 ) + 1) * sizeof(wchar_t) );
}
else if( key == KEY_ENTER )
{
// do nothing here... wait for the keyup event
fFirstHalfExitKeyPushed = true;
}
else if( key == KEY_ESCAPE )
{
// // do nothing here... wait for the keyup event
// fFirstHalfExitKeyPushed = true;
fEscapedFlag = true;
DoSomething(); // Query WasEscaped() to see if it was escape vs enter
return true;
}
else
{
fIgnoreNextKey = false;
return true;
}
fIgnoreNextKey = true;
IUpdate();
return true;
}
// wait until the Key up for enter and escape to make sure we capture the whole key
// ...before we give on focus control
else if( event == pfGameGUIMgr::kKeyUp )
{
if( key == KEY_ENTER )
{
if (fFirstHalfExitKeyPushed)
{
// Do jack, just here to filter out it being added to the buffer
// Well, ok, actually do *something*. *cough*.
DoSomething();
fFirstHalfExitKeyPushed = false;
return true;
}
}
else if( key == KEY_ESCAPE )
{
if (fFirstHalfExitKeyPushed)
{
// fEscapedFlag = true;
// DoSomething(); // Query WasEscaped() to see if it was escape vs enter
fFirstHalfExitKeyPushed = false;
return true;
}
}
fFirstHalfExitKeyPushed = false;
return true;
}
else
{
// We don't process them, but we don't want anybody else processing them either
return true;
}
}
}
std::string pfGUIEditBoxMod::GetBuffer( void )
{
char* temp = hsWStringToString(fBuffer);
std::string retVal = temp;
delete [] temp;
return retVal;
}
void pfGUIEditBoxMod::ClearBuffer( void )
{
if( fBuffer != nil )
{
memset( fBuffer, 0, (fBufferSize + 1) * sizeof(wchar_t) );
fCursorPos = 0;
fScrollPos = 0;
IUpdate();
}
}
void pfGUIEditBoxMod::SetText( const char *str )
{
wchar_t* temp = hsStringToWString(str);
SetText(temp);
delete [] temp;
}
void pfGUIEditBoxMod::SetText( const wchar_t *str )
{
if( fBuffer != nil )
{
wcsncpy( fBuffer, str, fBufferSize - 1 );
fCursorPos = 0;
fScrollPos = 0;
IUpdate();
}
}
void pfGUIEditBoxMod::SetBufferSize( UInt32 size )
{
delete [] fBuffer;
fBufferSize = size;
if( size > 0 )
{
fBuffer = TRACKED_NEW wchar_t[ size + 1 ];
memset( fBuffer, 0, (size + 1) * sizeof(wchar_t) );
}
else
fBuffer = nil;
fCursorPos = 0;
fScrollPos = 0;
}
void pfGUIEditBoxMod::SetCursorToHome( void )
{
fCursorPos = 0;
}
void pfGUIEditBoxMod::SetCursorToEnd( void )
{
if( fBuffer != nil )
fCursorPos = wcslen( fBuffer );
}
void pfGUIEditBoxMod::SetLastKeyCapture(UInt32 key, UInt8 modifiers)
{
// capture the key
fSavedKey = (plKeyDef)key;
fSavedModifiers = modifiers;
// turn key event into string
char keyStr[30];
if (plKeyMap::ConvertVKeyToChar( key ))
strcpy(keyStr, plKeyMap::ConvertVKeyToChar( key ));
else
memset(keyStr, 0, sizeof(keyStr));
static char shortKey[ 2 ];
if( strlen(keyStr) == 0 )
{
if( isalnum( key ) )
{
shortKey[ 0 ] = (char)key;
shortKey[ 1 ] = 0;
strcpy(keyStr, shortKey);
}
else
strcpy(keyStr, plKeyMap::GetStringUnmapped());
}
else
{
// check to see the buffer has ForewardSlash and change it to ForwardSlash
if ( strcmp(keyStr,"ForewardSlash") == 0)
{
strcpy(keyStr,"ForwardSlash");
}
}
static char newKey[ 16 ];
newKey[0] = 0;
if( modifiers & kShift )
strcat( newKey, plKeyMap::GetStringShift() );
if( modifiers & kCtrl )
strcat( newKey, plKeyMap::GetStringCtrl() );
strcat( newKey, keyStr );
// set something in the buffer to be displayed
wchar_t* temp = hsStringToWString(newKey);
wcsncpy( fBuffer, temp , fBufferSize - 1 );
delete [] temp;
fCursorPos = 0;
SetCursorToEnd();
IUpdate();
}

View File

@ -0,0 +1,125 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIEditBoxMod Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIEditBoxMod_h
#define _pfGUIEditBoxMod_h
#include "hsStlUtils.h"
#include "pfGUIControlMod.h"
#include "../pnInputCore/plKeyDef.h"
#include "../plInputCore/plInputDevice.h"
class plMessage;
class hsGMaterial;
class plTextGenerator;
class pfGUIEditBoxMod : public pfGUIControlMod
{
protected:
wchar_t *fBuffer;
UInt32 fBufferSize, fCursorPos;
Int32 fScrollPos;
hsBool fIgnoreNextKey, fEscapedFlag;
hsBool fFirstHalfExitKeyPushed;
hsBool fSpecialCaptureKeyEventMode;
plKeyDef fSavedKey;
UInt8 fSavedModifiers;
wchar_t fLastDeadKey; // if the previous key was a dead key, its value goes here
wchar_t fDeadKeyConverter[256][256]; // first index is the dead key, second index is the char to combine it with
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
virtual void IPostSetUpDynTextMap( void );
virtual void IUpdate( void );
void SetupDeadKeyConverter();
public:
enum
{
kShift = 0x01,
kCtrl = 0x02
};
pfGUIEditBoxMod();
virtual ~pfGUIEditBoxMod();
CLASSNAME_REGISTER( pfGUIEditBoxMod );
GETINTERFACE_ANY( pfGUIEditBoxMod, pfGUIControlMod );
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
virtual void HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers );
virtual hsBool HandleKeyPress( char key, UInt8 modifiers );
virtual hsBool HandleKeyEvent( pfGameGUIMgr::EventType event, plKeyDef key, UInt8 modifiers );
virtual void PurgeDynaTextMapImage();
void SetBufferSize( UInt32 size );
std::string GetBuffer( void );
std::wstring GetBufferW( void ) { return fBuffer; }
void ClearBuffer( void );
void SetText( const char *str );
void SetText( const wchar_t *str );
void SetCursorToHome( void );
void SetCursorToEnd( void );
hsBool WasEscaped( void ) { hsBool e = fEscapedFlag; fEscapedFlag = false; return e; }
void SetSpecialCaptureKeyMode(hsBool state) { fSpecialCaptureKeyEventMode = state; }
UInt32 GetLastKeyCaptured() { return (UInt32)fSavedKey; }
UInt8 GetLastModifiersCaptured() { return fSavedModifiers; }
void SetLastKeyCapture(UInt32 key, UInt8 modifiers);
void SetChatMode(hsBool state) { plKeyboardDevice::IgnoreCapsLock(state); }
// Extended event types
enum ExtendedEvents
{
kValueChanging
};
};
#endif // _pfGUIEditBoxMod_h

View File

@ -0,0 +1,368 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIKnobCtrl Definition //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUIKnobCtrl.h"
#include "pfGameGUIMgr.h"
#include "pfGUIDialogMod.h"
#include "../plInputCore/plInputInterface.h"
#include "../pnMessage/plRefMsg.h"
#include "../pfMessage/pfGameGUIMsg.h"
#include "../plMessage/plAnimCmdMsg.h"
// #include "../plAvatar/plAGModifier.h"
#include "../plAvatar/plAGMasterMod.h"
#include "../plAvatar/plAGAnimInstance.h"
#include "../plSurface/plLayerAnimation.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIKnobCtrl::pfGUIKnobCtrl() :
fAnimName(nil),
fDragStart(0.f, 0.f, 0.f),
fDragging(false),
fAnimStartPos(0.f, 0.f, 0.f),
fAnimEndPos(0.f, 0.f, 0.f),
fDragRangeMin(0.f),
fDragRangeMax(0.f),
fAnimBegin(0.f),
fAnimEnd(0.f),
fAnimTimesCalced(false)
{
SetFlag( kWantsInterest );
}
pfGUIKnobCtrl::~pfGUIKnobCtrl()
{
delete [] fAnimName;
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool pfGUIKnobCtrl::IEval( double secs, hsScalar del, UInt32 dirty )
{
return pfGUIValueCtrl::IEval( secs, del, dirty );
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGUIKnobCtrl::MsgReceive( plMessage *msg )
{
return pfGUIValueCtrl::MsgReceive( msg );
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUIKnobCtrl::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIValueCtrl::Read(s, mgr);
fAnimationKeys.Reset();
UInt32 i, count = s->ReadSwap32();
for( i = 0; i < count; i++ )
fAnimationKeys.Append( mgr->ReadKey( s ) );
fAnimName = s->ReadSafeString();
fAnimTimesCalced = false;
fAnimStartPos.Read( s );
fAnimEndPos.Read( s );
}
void pfGUIKnobCtrl::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIValueCtrl::Write( s, mgr );
UInt32 i, count = fAnimationKeys.GetCount();
s->WriteSwap32( count );
for( i = 0; i < count; i++ )
mgr->WriteKey( s, fAnimationKeys[ i ] );
s->WriteSafeString( fAnimName );
fAnimStartPos.Write( s );
fAnimEndPos.Write( s );
}
//// UpdateBounds ////////////////////////////////////////////////////////////
void pfGUIKnobCtrl::UpdateBounds( hsMatrix44 *invXformMatrix, hsBool force )
{
pfGUIValueCtrl::UpdateBounds( invXformMatrix, force );
if( fAnimationKeys.GetCount() > 0 )
fBoundsValid = false;
}
//// HandleMouseDown/Up //////////////////////////////////////////////////////
void pfGUIKnobCtrl::HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers )
{
fDragStart = mousePt;
fDragValue = fValue;
fDragging = true;
if( HasFlag( kMapToAnimationRange ) )
{
hsPoint3 scrnStart, scrnEnd;
// At mouse-down, we take our local-space start and end points and
// translate them by our parent object's local-to-world to get the
// right points in world-space. We do this now because our parent
// might be animated, which could complicate matters a tad.
scrnStart = fAnimStartPos;
scrnEnd = fAnimEndPos;
plSceneObject *target = GetTarget();
if( target != nil )
{
const plCoordinateInterface *ci = target->GetCoordinateInterface();
if( ci != nil )
{
const plCoordinateInterface *parentCI = ci->GetParent();
if( parentCI != nil )
{
const hsMatrix44 &parentLocalToWorld = parentCI->GetLocalToWorld();
scrnStart = parentLocalToWorld * scrnStart;
scrnEnd = parentLocalToWorld * scrnEnd;
}
}
}
scrnStart = fDialog->WorldToScreenPoint( scrnStart );
scrnEnd = fDialog->WorldToScreenPoint( scrnEnd );
if( HasFlag( kLeftRightOrientation ) )
{
fDragRangeMin = scrnStart.fX;
fDragRangeMax = scrnEnd.fX;
}
else
{
fDragRangeMin = scrnStart.fY;
fDragRangeMax = scrnEnd.fY;
}
}
else if( HasFlag( kMapToScreenRange ) )
{
fDragRangeMin = 0.f;
fDragRangeMax = 1.f;
}
else
fDragRangeMin = -1;
}
void pfGUIKnobCtrl::HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers )
{
fDragging = false;
HandleMouseDrag( mousePt, modifiers );
}
void pfGUIKnobCtrl::HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers )
{
hsScalar oldValue = fValue, newValue = fDragValue;
if( fDragRangeMin != -1 )
{
if( HasFlag( kLeftRightOrientation ) )
{
if( mousePt.fX < fDragRangeMin )
newValue = fMin;
else if( mousePt.fX > fDragRangeMax )
newValue = fMax;
else
newValue = ( ( mousePt.fX - fDragRangeMin ) / ( fDragRangeMax - fDragRangeMin ) ) *
( fMax - fMin ) + fMin;
}
else
{
if( mousePt.fY > fDragRangeMin )
newValue = fMin;
else if( mousePt.fY < fDragRangeMax )
newValue = fMax;
else
newValue = ( ( fDragRangeMin - mousePt.fY) / ( fDragRangeMin - fDragRangeMax ) ) *
( fMax - fMin ) + fMin;
}
if( HasFlag( kReverseValues ) )
SetCurrValue( fMax - ( newValue - fMin ) );
else
SetCurrValue( newValue );
}
else
{
hsScalar diff;
if( HasFlag( kLeftRightOrientation ) )
diff = ( mousePt.fX - fDragStart.fX ) * 20.f;
else
diff = ( fDragStart.fY - mousePt.fY ) * 20.f;
if( HasFlag( kReverseValues ) )
SetCurrValue( fDragValue - diff );
else
SetCurrValue( fDragValue + diff );
}
// !fDragging = We're mousing-up, so if we're still dragging, we need to not have the only-
// on-mouse-up flag set. Just FYI
if( !fDragging || !HasFlag( kTriggerOnlyOnMouseUp ) )
DoSomething();
}
//// SetAnimationKeys ////////////////////////////////////////////////////////
void pfGUIKnobCtrl::SetAnimationKeys( hsTArray<plKey> &keys, const char *name )
{
fAnimationKeys = keys;
delete [] fAnimName;
if( name != nil )
{
fAnimName = TRACKED_NEW char[ strlen( name ) + 1 ];
strcpy( fAnimName, name );
}
else
fAnimName = nil;
}
//// ICalcAnimTimes //////////////////////////////////////////////////////////
// Loops through and computes the max begin and end for our animations. If
// none of them are loaded and we're not already calced, returns false.
hsBool pfGUIKnobCtrl::ICalcAnimTimes( void )
{
if( fAnimTimesCalced )
return true;
hsScalar tBegin = 1e30, tEnd = -1e30;
bool foundOne = false;
for( int i = 0; i < fAnimationKeys.GetCount(); i++ )
{
// Handle AGMasterMods
plAGMasterMod *mod = plAGMasterMod::ConvertNoRef( fAnimationKeys[ i ]->ObjectIsLoaded() );
if( mod != nil )
{
for( int j = 0; j < mod->GetNumAnimations(); j++ )
{
hsScalar begin = mod->GetAnimInstance( j )->GetTimeConvert()->GetBegin();
hsScalar end = mod->GetAnimInstance( j )->GetTimeConvert()->GetEnd();
if( begin < tBegin )
tBegin = begin;
if( end > tEnd )
tEnd = end;
}
foundOne = true;
}
// Handle layer animations
plLayerAnimation *layer = plLayerAnimation::ConvertNoRef( fAnimationKeys[ i ]->ObjectIsLoaded() );
if( layer != nil )
{
hsScalar begin = layer->GetTimeConvert().GetBegin();
hsScalar end = layer->GetTimeConvert().GetEnd();
if( begin < tBegin )
tBegin = begin;
if( end > tEnd )
tEnd = end;
foundOne = true;
}
}
if( foundOne )
{
fAnimBegin = tBegin;
fAnimEnd = tEnd;
fAnimTimesCalced = true;
}
return fAnimTimesCalced;
}
//// SetCurrValue ////////////////////////////////////////////////////////////
void pfGUIKnobCtrl::SetCurrValue( hsScalar v )
{
int old = (int)fValue;
pfGUIValueCtrl::SetCurrValue( v );
// if( old == (int)fValue )
// return;
if( fAnimationKeys.GetCount() > 0 )
{
ICalcAnimTimes();
hsScalar tLength = fAnimEnd - fAnimBegin;
hsScalar newTime = fMin;
if (fMin != fMax) // Protect against div by zero
{
if( HasFlag( kReverseValues ) )
newTime = ( ( fMax - fValue ) / ( fMax - fMin ) ) * tLength + fAnimBegin;
else
newTime = ( ( fValue - fMin ) / ( fMax - fMin ) ) * tLength + fAnimBegin;
}
plAnimCmdMsg *msg = TRACKED_NEW plAnimCmdMsg();
msg->SetCmd( plAnimCmdMsg::kGoToTime );
msg->SetAnimName( fAnimName );
msg->fTime = newTime;
msg->AddReceivers( fAnimationKeys );
plgDispatch::MsgSend( msg );
}
}
//// IGetDesiredCursor ///////////////////////////////////////////////////////
UInt32 pfGUIKnobCtrl::IGetDesiredCursor( void ) const
{
if( HasFlag( kLeftRightOrientation ) )
{
if( fDragging )
return plInputInterface::kCursorLeftRightDragging;
return plInputInterface::kCursorLeftRightDraggable;
}
else
{
if( fDragging )
return plInputInterface::kCursorUpDownDragging;
return plInputInterface::kCursorUpDownDraggable;
}
}

View File

@ -0,0 +1,100 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIKnobCtrl Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIKnobCtrl_h
#define _pfGUIKnobCtrl_h
#include "pfGUIValueCtrl.h"
class plMessage;
class plAGMasterMod;
class pfGUIKnobCtrl : public pfGUIValueCtrl
{
protected:
hsTArray<plKey> fAnimationKeys;
char *fAnimName;
hsPoint3 fDragStart;
hsScalar fDragValue;
hsBool fDragging;
hsPoint3 fAnimStartPos, fAnimEndPos; // Calculated at export time for kMapToScreenRange
hsScalar fDragRangeMin, fDragRangeMax;
// Computed once, once an anim is loaded that we can compute this with
hsScalar fAnimBegin, fAnimEnd;
hsBool fAnimTimesCalced;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
virtual UInt32 IGetDesiredCursor( void ) const; // As specified in plInputInterface.h
hsBool ICalcAnimTimes( void );
public:
pfGUIKnobCtrl();
virtual ~pfGUIKnobCtrl();
CLASSNAME_REGISTER( pfGUIKnobCtrl );
GETINTERFACE_ANY( pfGUIKnobCtrl, pfGUIValueCtrl );
enum OurFlags
{
kReverseValues = kDerivedFlagsStart,
kLeftRightOrientation,
kMapToScreenRange,
kTriggerOnlyOnMouseUp,
kMapToAnimationRange
};
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
virtual void HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers );
virtual void UpdateBounds( hsMatrix44 *invXformMatrix = nil, hsBool force = false );
virtual void SetCurrValue( hsScalar v );
// Export only
void SetAnimationKeys( hsTArray<plKey> &keys, const char *name );
void SetScreenRange( const hsPoint3 &startPos, const hsPoint3 &endPos ) { fAnimStartPos = startPos; fAnimEndPos = endPos; }
};
#endif // _pfGUIKnobCtrl_h

View File

@ -0,0 +1,183 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIListBoxMod Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIListBoxMod_h
#define _pfGUIListBoxMod_h
#include "pfGUIControlMod.h"
class plMessage;
class hsGMaterial;
class plTextGenerator;
class pfGUIListElement;
class pfScrollProc;
class pfGUIValueCtrl;
class pfGUIListBoxMod : public pfGUIControlMod
{
friend class pfScrollProc;
protected:
struct plSmallRect
{
Int16 fLeft, fTop, fRight, fBottom;
void Set( Int16 l, Int16 t, Int16 r, Int16 b );
hsBool Contains( Int16 x, Int16 y );
plSmallRect& operator=(const int zero) { fLeft = fTop = fRight = fBottom = 0; return *this; }
};
pfGUIValueCtrl *fScrollControl;
pfScrollProc *fScrollProc;
hsTArray<pfGUIListElement *> fElements;
Int32 fCurrClick, fScrollPos, fCurrHover;
UInt8 fModsAtDragTime;
Int32 fMinSel, fMaxSel;
hsBool fCheckScroll, fClicking;
Int32 fSingleSelElement;
hsBool fScrollRangeUpdateDeferred;
hsBool fLocked, fReadyToRoll;
hsTArray<plSmallRect> fElementBounds;
hsTArray<Int16> fWrapStartIdxs;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
void ICalcScrollRange( void );
void ICalcWrapStarts( void );
virtual void IUpdate( void );
virtual void IPostSetUpDynTextMap( void );
virtual UInt32 IGetDesiredCursor( void ) const;
Int32 IGetItemFromPoint( hsPoint3 &mousePt );
void IFindSelectionRange( Int32 *min, Int32 *max );
void ISelectRange( Int8 min, Int8 max, hsBool select );
public:
pfGUIListBoxMod();
virtual ~pfGUIListBoxMod();
CLASSNAME_REGISTER( pfGUIListBoxMod );
GETINTERFACE_ANY( pfGUIListBoxMod, pfGUIControlMod );
enum OurFlags
{
kSingleSelect = kDerivedFlagsStart,
kDragAndDropCapable,
kDisableSelection,
kDisableKeyActions,
kAllowMultipleElementsPerRow,
kScrollLeftToRight,
kAllowMousePassThrough,
kGrowLeavesAndProcessOxygen,
kHandsOffMultiSelect, // Do multiselect w/o needing ctrl or shift
kForbidNoSelection
};
// Extended event types
enum ExtendedEvents
{
kScrollPosChanged,
kItemAdded,
kItemRemoved,
kListCleared
};
enum
{
kRefScrollCtrl = kRefDerivedStart
};
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
virtual void HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseHover( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseDblClick( hsPoint3 &mousePt, UInt8 modifiers );
virtual hsBool HandleKeyPress( char key, UInt8 modifiers );
virtual hsBool HandleKeyEvent( pfGameGUIMgr::EventType event, plKeyDef key, UInt8 modifiers );
virtual hsBool FilterMousePosition( hsPoint3 &mousePt );
virtual void PurgeDynaTextMapImage();
// Returns selected element. Only valid for kSingleSelect list boxes
Int32 GetSelection( void ) { return fSingleSelElement; }
void SetSelection( Int32 item );
void RemoveSelection( Int32 item );
void AddSelection( Int32 item );
virtual void ScrollToBegin( void );
virtual void ScrollToEnd( void );
virtual void SetScrollPos( Int32 pos );
virtual Int32 GetScrollPos( void );
virtual Int32 GetScrollRange( void );
void Refresh( void ) { IUpdate(); }
virtual void SetColorScheme( pfGUIColorScheme *newScheme );
// Element manipulation
UInt16 AddElement( pfGUIListElement *el );
void RemoveElement( UInt16 index );
Int16 FindElement( pfGUIListElement *toCompareTo );
void ClearAllElements( void );
void LockList( void );
void UnlockList( void );
UInt16 GetNumElements( void );
pfGUIListElement *GetElement( UInt16 idx );
UInt16 AddString( const char *string );
UInt16 AddString( const wchar_t *string );
Int16 FindString( const char *toCompareTo );
Int16 FindString( const wchar_t *toCompareTo );
// Export only
void SetScrollCtrl( pfGUIValueCtrl *ctrl ) { fScrollControl = ctrl; }
void SetSingleSelect( hsBool yes ) { if( yes ) SetFlag( kSingleSelect ); else ClearFlag( kSingleSelect ); }
};
#endif // _pfGUIListBoxMod_h

View File

@ -0,0 +1,456 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIListElement Class Definitions //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUIListElement.h"
#include "pfGameGUIMgr.h"
#include "pfGUIPopUpMenu.h" // For skins
#include "../plGImage/plDynamicTextMap.h"
#include "../plGImage/hsCodecManager.h"
#include "../plPipeline/plDebugText.h" // To quickly and hackily get the screen size in pixels
#include "hsResMgr.h"
//////////////////////////////////////////////////////////////////////////////
//// Base Stuff //////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
void pfGUIListElement::Read( hsStream *s, hsResMgr *mgr )
{
fSelected = s->ReadBool();
}
void pfGUIListElement::Write( hsStream *s, hsResMgr *mgr )
{
s->WriteBool( fSelected );
}
//////////////////////////////////////////////////////////////////////////////
//// pfGUIListText ///////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIListText::pfGUIListText() : pfGUIListElement( kText )
{
fText = nil;
fJustify = kLeftJustify;
}
pfGUIListText::pfGUIListText( const char *text ) : pfGUIListElement( kText )
{
fText = hsStringToWString(text);
fJustify = kLeftJustify;
}
pfGUIListText::pfGUIListText( const wchar_t *text ) : pfGUIListElement( kText )
{
fText = TRACKED_NEW wchar_t[ wcslen( text ) + 1 ];
wcscpy( fText, text );
fJustify = kLeftJustify;
}
pfGUIListText::~pfGUIListText()
{
delete [] fText;
}
//// Virtuals ////////////////////////////////////////////////////////////////
void pfGUIListText::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIListElement::Read( s, mgr );
char *text = s->ReadSafeString();
fText = hsStringToWString(text);
delete [] text;
}
void pfGUIListText::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIListElement::Write( s, mgr );
char *text = hsWStringToString(fText);
s->WriteSafeString(text);
delete [] text;
}
hsBool pfGUIListText::Draw( plDynamicTextMap *textGen, UInt16 x, UInt16 y, UInt16 maxWidth, UInt16 maxHeight )
{
textGen->SetJustify( (plDynamicTextMap::Justify)fJustify );
if( fSelected )
{
textGen->FillRect( x, y, maxWidth, maxHeight, fColors->fSelBackColor );
textGen->SetTextColor( fColors->fSelForeColor, fColors->fTransparent && fColors->fSelBackColor.a == 0.f );
}
else
{
// Normal back color will be cleared for us
textGen->SetTextColor( fColors->fForeColor, fColors->fTransparent && fColors->fBackColor.a == 0.f );
}
textGen->DrawClippedString( x + 4, y, GetText(), maxWidth - 8, maxHeight );
return true;
}
void pfGUIListText::GetSize( plDynamicTextMap *textGen, UInt16 *width, UInt16 *height )
{
*width = textGen->CalcStringWidth( GetText(), height );
if( height != nil )
{
if( *height == 0 )
*height = 10; // Never allow zero height elements
else
*height += 0; // Add one pixel on each side for padding (or not, 3.21.02 mcn)
}
}
int pfGUIListText::CompareTo( pfGUIListElement *rightSide )
{
pfGUIListText *text = (pfGUIListText *)rightSide;
if( text->fType != kText )
return -2;
return wcscmp( GetText(), text->GetText() );
}
void pfGUIListText::SetText( const char *text )
{
wchar_t *wText = hsStringToWString(text);
SetText(wText);
delete [] wText;
}
void pfGUIListText::SetText( const wchar_t *text )
{
delete [] fText;
if( text != nil )
{
fText = TRACKED_NEW wchar_t[ wcslen( text ) + 1 ];
wcscpy( fText, text );
}
else
fText = nil;
}
void pfGUIListText::SetJustify( JustifyTypes justify )
{
switch( justify )
{
case kRightJustify:
fJustify = plDynamicTextMap::kRightJustify;
break;
case kCenter:
fJustify = plDynamicTextMap::kCenter;
break;
case kLeftJustify:
default:
fJustify = plDynamicTextMap::kLeftJustify;
break;
}
}
//////////////////////////////////////////////////////////////////////////////
//// pfGUIListPicture ////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIListPicture::pfGUIListPicture() : pfGUIListElement( kPicture )
{
fBorderSize = 2;
fMipmapKey = nil;
}
pfGUIListPicture::pfGUIListPicture( plKey mipKey, hsBool respectAlpha ) : pfGUIListElement( kPicture )
{
fBorderSize = 2;
fMipmapKey = mipKey;
fRespectAlpha = respectAlpha;
plMipmap *mip = plMipmap::ConvertNoRef( fMipmapKey->ObjectIsLoaded() );
if( mip != nil && mip->IsCompressed() )
{
// Gotta make and grab an uncompressed one
plMipmap *uncompBuffer = hsCodecManager::Instance().CreateUncompressedMipmap( mip, hsCodecManager::k32BitDepth );
char str[ 512 ];
sprintf( str, "%s_uncomp", mip->GetKeyName() );
fMipmapKey = hsgResMgr::ResMgr()->NewKey( str, uncompBuffer, fMipmapKey->GetUoid().GetLocation() );
fMipmapKey->RefObject();
}
}
pfGUIListPicture::~pfGUIListPicture()
{
fMipmapKey->UnRefObject();
fMipmapKey = nil;
}
//// Virtuals ////////////////////////////////////////////////////////////////
void pfGUIListPicture::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIListElement::Read( s, mgr );
}
void pfGUIListPicture::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIListElement::Write( s, mgr );
}
hsBool pfGUIListPicture::Draw( plDynamicTextMap *textGen, UInt16 x, UInt16 y, UInt16 maxWidth, UInt16 maxHeight )
{
if( fSelected )
textGen->FillRect( x, y, maxWidth, maxHeight, fColors->fSelBackColor );
plMipmap *mip = plMipmap::ConvertNoRef( fMipmapKey->ObjectIsLoaded() );
if( mip != nil )
{
if( mip->GetWidth() + fBorderSize + fBorderSize > maxWidth || mip->GetHeight() + fBorderSize + fBorderSize > maxHeight )
return false;
textGen->DrawImage( x + fBorderSize, y + fBorderSize, mip, fRespectAlpha ? plDynamicTextMap::kImgBlend : plDynamicTextMap::kImgNoAlpha );
}
return true;
}
void pfGUIListPicture::GetSize( plDynamicTextMap *textGen, UInt16 *width, UInt16 *height )
{
plMipmap *mip = plMipmap::ConvertNoRef( fMipmapKey->ObjectIsLoaded() );
if( mip == nil )
{
*width = 16;
if( height != nil )
*height = 16;
}
*width = (UInt16)(mip->GetWidth() + fBorderSize + fBorderSize);
if( height != nil )
*height = (UInt16)(mip->GetHeight() + fBorderSize + fBorderSize);
}
int pfGUIListPicture::CompareTo( pfGUIListElement *rightSide )
{
pfGUIListPicture *text = (pfGUIListPicture *)rightSide;
if( text->fType != kPicture )
return -2;
return -2;
}
//////////////////////////////////////////////////////////////////////////////
//// pfGUIListTreeRoot ///////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIListTreeRoot::pfGUIListTreeRoot() : pfGUIListElement( kTreeRoot )
{
fText = nil;
fShowChildren = true;
}
pfGUIListTreeRoot::pfGUIListTreeRoot( const char *text ) : pfGUIListElement( kTreeRoot )
{
fText = hsStringToWString(text);
}
pfGUIListTreeRoot::pfGUIListTreeRoot( const wchar_t *text ) : pfGUIListElement( kTreeRoot )
{
fText = TRACKED_NEW wchar_t[ wcslen( text ) + 1 ];
wcscpy( fText, text );
}
pfGUIListTreeRoot::~pfGUIListTreeRoot()
{
delete [] fText;
}
//// Virtuals ////////////////////////////////////////////////////////////////
void pfGUIListTreeRoot::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIListElement::Read( s, mgr );
char *temp = s->ReadSafeString();
fText = hsStringToWString(temp);
delete [] temp;
}
void pfGUIListTreeRoot::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIListElement::Write( s, mgr );
char *temp = hsWStringToString(fText);
s->WriteSafeString( temp );
delete [] temp;
}
hsBool pfGUIListTreeRoot::Draw( plDynamicTextMap *textGen, UInt16 x, UInt16 y, UInt16 maxWidth, UInt16 maxHeight )
{
textGen->SetJustify( plDynamicTextMap::kLeftJustify );
if( fSelected )
{
textGen->FillRect( x, y, maxWidth, maxHeight, fColors->fSelBackColor );
textGen->SetTextColor( fColors->fSelForeColor, fColors->fTransparent && fColors->fSelBackColor.a == 0.f );
}
else
{
// Normal back color will be cleared for us
textGen->SetTextColor( fColors->fForeColor, fColors->fTransparent && fColors->fBackColor.a == 0.f );
}
if( fSkin != nil )
{
const pfGUISkin::pfSRect &r = fSkin->GetElement( fShowChildren ? pfGUISkin::kTreeButtonOpen : pfGUISkin::kTreeButtonClosed );
Int16 e = ( maxHeight - r.fHeight );
if( e < 0 )
e = 0;
e >>= 1;
textGen->DrawClippedImage( x + 2, y + e, fSkin->GetTexture(), r.fX, r.fY, r.fWidth, r.fHeight, plDynamicTextMap::kImgSprite );
x += r.fWidth + 4;
}
textGen->DrawClippedString( x + 4, y, GetTitle(), maxWidth - 8, maxHeight );
return true;
}
hsBool pfGUIListTreeRoot::MouseClicked( UInt16 localX, UInt16 localY )
{
if( fSkin != nil )
{
const pfGUISkin::pfSRect &r = fSkin->GetElement( fShowChildren ? pfGUISkin::kTreeButtonOpen : pfGUISkin::kTreeButtonClosed );
// For now, I can't think of a clean way of getting the current visible height to this function,
// but just testing the X value for tree controls is good enough for now. If we need Y testing for
// other elements, I'll figure out something.
if( localX >= 2 && localX <= 2 + r.fWidth )
{
ShowChildren( !fShowChildren );
return true;
}
}
return false;
}
void pfGUIListTreeRoot::GetSize( plDynamicTextMap *textGen, UInt16 *width, UInt16 *height )
{
*width = textGen->CalcStringWidth( GetTitle(), height );
if( height != nil )
{
if( *height == 0 )
*height = 10; // Never allow zero height elements
else
*height += 0; // Add one pixel on each side for padding (or not, 3.21.02 mcn)
if( fSkin != nil )
{
UInt16 h = fSkin->GetElement( pfGUISkin::kTreeButtonClosed ).fHeight;
if( *height < h )
*height = h;
}
}
if( fSkin != nil )
*width += fSkin->GetElement( pfGUISkin::kTreeButtonClosed ).fWidth;
}
int pfGUIListTreeRoot::CompareTo( pfGUIListElement *rightSide )
{
pfGUIListTreeRoot *text = (pfGUIListTreeRoot *)rightSide;
if( text->fType != kTreeRoot )
return -2;
return wcscmp( GetTitle(), text->GetTitle() );
}
void pfGUIListTreeRoot::SetTitle( const char *text )
{
wchar_t *wText = hsStringToWString(text);
SetTitle(wText);
delete [] wText;
}
void pfGUIListTreeRoot::SetTitle( const wchar_t *text )
{
delete [] fText;
if( text != nil )
{
fText = TRACKED_NEW wchar_t[ wcslen( text ) + 1 ];
wcscpy( fText, text );
}
else
fText = nil;
}
void pfGUIListTreeRoot::AddChild( pfGUIListElement *el )
{
fChildren.Append( el );
el->SetIndentLevel( GetIndentLevel() + 1 );
el->SetCollapsed( !fShowChildren );
}
void pfGUIListTreeRoot::RemoveChild( UInt32 idx )
{
fChildren.Remove( idx );
}
void pfGUIListTreeRoot::ShowChildren( hsBool s )
{
UInt32 i;
fShowChildren = s;
for( i = 0; i < fChildren.GetCount(); i++ )
fChildren[ i ]->SetCollapsed( !s );
}
void pfGUIListTreeRoot::SetCollapsed( hsBool c )
{
UInt32 i;
pfGUIListElement::SetCollapsed( c );
for( i = 0; i < fChildren.GetCount(); i++ )
fChildren[ i ]->SetCollapsed( c ? true : !fShowChildren );
}

View File

@ -0,0 +1,228 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIListElement Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIListElement_h
#define _pfGUIListElement_h
#include "pfGUIControlMod.h"
class plDynamicTextMap;
class pfGUISkin;
class pfGUIListElement
{
protected:
hsBool fSelected;
const UInt8 fType;
hsBool fCollapsed; // For tree view support
UInt8 fIndentLevel; // Ditto
pfGUIColorScheme *fColors;
pfGUISkin *fSkin;
public:
enum Types
{
kText,
kPicture,
kTreeRoot
};
pfGUIListElement( UInt8 type ) : fType( type ), fSelected( false ), fCollapsed( false ), fIndentLevel( 0 ) {}
virtual ~pfGUIListElement() {}
virtual void Read( hsStream *s, hsResMgr *mgr );
virtual void Write( hsStream *s, hsResMgr *mgr );
virtual hsBool Draw( plDynamicTextMap *textGen, UInt16 x, UInt16 y, UInt16 maxWidth, UInt16 maxHeight ) = 0;
virtual void GetSize( plDynamicTextMap *textGen, UInt16 *width, UInt16 *height ) = 0;
virtual int CompareTo( pfGUIListElement *rightSide ) = 0;
virtual void SetSelected( hsBool sel ) { fSelected = sel; }
virtual hsBool IsSelected( void ) { return fSelected; }
virtual hsBool CanBeDragged( void ) { return false; }
// Return true here if you need the list refreshed
virtual hsBool MouseClicked( UInt16 localX, UInt16 localY ) { return false; }
UInt8 GetType( void ) { return fType; }
void SetColorScheme( pfGUIColorScheme *scheme ) { fColors = scheme; }
void SetSkin( pfGUISkin *skin ) { fSkin = skin; }
hsBool IsCollapsed( void ) const { return fCollapsed; }
virtual void SetCollapsed( hsBool c ) { fCollapsed = c; }
UInt8 GetIndentLevel( void ) const { return fIndentLevel; }
void SetIndentLevel( UInt8 i ) { fIndentLevel = i; }
};
class pfGUIListText : public pfGUIListElement
{
public:
// these enums should at least agree with the plDynamicTextMap's version of the Justify types
enum JustifyTypes
{
kLeftJustify = 0,
kCenter,
kRightJustify
};
protected:
wchar_t *fText;
UInt8 fJustify; // This is not our JustifyTypes, but from plDynamicTextMap
public:
pfGUIListText();
pfGUIListText( const char *text );
pfGUIListText( const wchar_t *text );
virtual ~pfGUIListText();
virtual void Read( hsStream *s, hsResMgr *mgr );
virtual void Write( hsStream *s, hsResMgr *mgr );
virtual hsBool Draw( plDynamicTextMap *textGen, UInt16 x, UInt16 y, UInt16 maxWidth, UInt16 maxHeight );
virtual void GetSize( plDynamicTextMap *textGen, UInt16 *width, UInt16 *height );
virtual int CompareTo( pfGUIListElement *rightSide );
virtual hsBool CanBeDragged( void ) { return true; }
virtual void SetJustify( JustifyTypes justify );
// These two are virtual so we can derive and override them
virtual const wchar_t *GetText( void ) { return fText; }
virtual void SetText( const char *text );
virtual void SetText( const wchar_t *text );
};
class pfGUIListPicture : public pfGUIListElement
{
protected:
plKey fMipmapKey;
UInt8 fBorderSize; // Defaults to 2
hsBool fRespectAlpha;
public:
pfGUIListPicture();
pfGUIListPicture( plKey mipKey, hsBool respectAlpha );
virtual ~pfGUIListPicture();
virtual void Read( hsStream *s, hsResMgr *mgr );
virtual void Write( hsStream *s, hsResMgr *mgr );
virtual hsBool Draw( plDynamicTextMap *textGen, UInt16 x, UInt16 y, UInt16 maxWidth, UInt16 maxHeight );
virtual void GetSize( plDynamicTextMap *textGen, UInt16 *width, UInt16 *height );
virtual int CompareTo( pfGUIListElement *rightSide );
virtual hsBool CanBeDragged( void ) { return false; }
void SetBorderSize( UInt32 size ) { fBorderSize = (UInt8)size; }
void SetRespectAlpha( hsBool r ) { fRespectAlpha = r; }
};
class pfGUIListTreeRoot : public pfGUIListElement
{
protected:
wchar_t *fText;
hsBool fShowChildren;
hsTArray<pfGUIListElement *> fChildren;
public:
pfGUIListTreeRoot();
pfGUIListTreeRoot( const char *text );
pfGUIListTreeRoot( const wchar_t *text );
virtual ~pfGUIListTreeRoot();
virtual void Read( hsStream *s, hsResMgr *mgr );
virtual void Write( hsStream *s, hsResMgr *mgr );
virtual hsBool Draw( plDynamicTextMap *textGen, UInt16 x, UInt16 y, UInt16 maxWidth, UInt16 maxHeight );
virtual void GetSize( plDynamicTextMap *textGen, UInt16 *width, UInt16 *height );
virtual int CompareTo( pfGUIListElement *rightSide );
virtual hsBool MouseClicked( UInt16 localX, UInt16 localY );
const wchar_t *GetTitle( void ) { return fText; }
void SetTitle( const char *text );
void SetTitle( const wchar_t *text );
UInt32 GetNumChildren( void ) const { return fChildren.GetCount(); }
pfGUIListElement *GetChild( UInt32 i ) const { return fChildren[ i ]; }
void AddChild( pfGUIListElement *el );
void RemoveChild( UInt32 idx );
virtual void SetCollapsed( hsBool c );
void ShowChildren( hsBool s );
hsBool IsShowingChildren( void ) const { return fShowChildren; }
};
//// pfGUIDropTargetProc /////////////////////////////////////////////////////
// A little proc object you create if you want a control to be a potential
// target for drag & drop operations. It has two functions: one takes a
// listElement and returns whether it can accept that type, and the other
// actually gets called when a listElement is "dropped" onto the associated
// control. Any control can be a dropTarget; just attach the right proc
// to it!
// If you are dragging multiple elements, both CanEat() and Eat() will get
// called for each element that is being dragged.
class pfGUIDropTargetProc
{
protected:
UInt32 fRefCnt;
public:
pfGUIDropTargetProc() { fRefCnt = 0; }
virtual hsBool CanEat( pfGUIListElement *element, pfGUIControlMod *source ) = 0;
virtual void Eat( pfGUIListElement *element, pfGUIControlMod *source, pfGUIControlMod *parent ) = 0;
// ONLY THE GUI SYSTEM SHOULD CALL THESE
void IncRef( void ) { fRefCnt++; }
hsBool DecRef( void ) { fRefCnt--; return ( fRefCnt > 0 ) ? false : true; }
};
#endif // _pfGUIListElement_h

View File

@ -0,0 +1,463 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIMenuItem Definition //
// //
// The type of button that knows how to party. //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUIMenuItem.h"
#include "pfGameGUIMgr.h"
#include "pfGUIControlHandlers.h"
#include "pfGUIDialogMod.h"
#include "pfGUIPopUpMenu.h"
#include "../plInputCore/plInputInterface.h"
#include "../pnMessage/plRefMsg.h"
#include "../plGImage/plDynamicTextMap.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIMenuItem::pfGUIMenuItem()
{
fName = nil;
fSkin = nil;
fReportingHover = false;
fSkinBuffersUpdated = true;
}
pfGUIMenuItem::~pfGUIMenuItem()
{
SetSkin( nil, kTop );
delete [] fName;
}
void pfGUIMenuItem::SetName( const char *name )
{
wchar_t *wName = hsStringToWString(name);
SetName(wName);
delete [] wName;
}
void pfGUIMenuItem::SetName( const wchar_t *name )
{
delete [] fName;
if (name != nil)
{
fName = TRACKED_NEW wchar_t[wcslen(name)+1];
wcscpy(fName,name);
}
else
fName = nil;
IUpdate();
}
//// SetSkin /////////////////////////////////////////////////////////////////
void pfGUIMenuItem::SetSkin( pfGUISkin *skin, HowToSkin s )
{
// Just a function wrapper for SendRef
if( fSkin != nil )
GetKey()->Release( fSkin->GetKey() );
if( skin != nil )
hsgResMgr::ResMgr()->SendRef( skin->GetKey(), TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefSkin ), plRefFlags::kActiveRef );
fHowToSkin = s;
fSkinBuffersUpdated = false;
}
//// IPostSetUpDynTextMap ////////////////////////////////////////////////////
// Draw our initial image on the dynTextMap
void pfGUIMenuItem::IPostSetUpDynTextMap( void )
{
}
//// IGetDesiredExtraDTMRoom /////////////////////////////////////////////////
// Overridden so we can enlarge our DTMap by 3 vertically, to use the extra
// space as basically a double buffer for our skinning
void pfGUIMenuItem::IGrowDTMDimsToDesiredSize( UInt16 &width, UInt16 &height )
{
height *= 3;
}
//// IUpdateSkinBuffers //////////////////////////////////////////////////////
// Redraws the double buffers for the two skin images we keep hidden in the
// DTMap, so we don't have to re-composite them every time we draw the
// control.
void pfGUIMenuItem::IUpdateSkinBuffers( void )
{
if( fSkinBuffersUpdated )
return;
if( fSkin == nil )
return;
if( fDynTextMap == nil )
return;
if( fSkin->GetTexture() == nil )
return;
UInt16 y = fDynTextMap->GetVisibleHeight();
IUpdateSingleSkinBuffer( y, false );
IUpdateSingleSkinBuffer( y << 1, true );
fSkinBuffersUpdated = true;
}
//// IUpdateSingleSkinBuffer /////////////////////////////////////////////////
// Broken down functionality for the above function
void pfGUIMenuItem::IUpdateSingleSkinBuffer( UInt16 y, hsBool sel )
{
hsAssert( fSkin != nil && fDynTextMap != nil, "Invalid pointers in IUpdateSingleSkinBuffer()" );
// Note: add 1 to the visible height so we get enough overlap to take care of mipmapping issues
UInt16 x = 0, totWidth = fDynTextMap->GetVisibleWidth();
UInt16 totHeight = y + fDynTextMap->GetVisibleHeight();
pfGUISkin::pfSRect element;
totWidth -= fSkin->GetElement( pfGUISkin::kRightSpan ).fWidth;
if( fHowToSkin == kTop )
{
// Draw up-left corner
element = fSkin->GetElement( pfGUISkin::kUpLeftCorner );
fDynTextMap->DrawClippedImage( x, y, fSkin->GetTexture(), element.fX, element.fY, element.fWidth, element.fHeight, plDynamicTextMap::kImgSprite );
x += element.fWidth;
element = fSkin->GetElement( pfGUISkin::kTopSpan );
for( ; x < totWidth; )
{
UInt16 wid = element.fWidth;
if( x + wid > totWidth )
wid = totWidth - x;
fDynTextMap->DrawClippedImage( x, y, fSkin->GetTexture(), element.fX, element.fY, wid, element.fHeight, plDynamicTextMap::kImgSprite );
x += wid;
}
element = fSkin->GetElement( pfGUISkin::kUpRightCorner );
fDynTextMap->DrawClippedImage( x, y, fSkin->GetTexture(), element.fX, element.fY, element.fWidth, element.fHeight, plDynamicTextMap::kImgSprite );
y += element.fHeight;
}
else if( fHowToSkin == kBottom )
{
// Clip some space for now
totHeight -= fSkin->GetElement( pfGUISkin::kLowerLeftCorner ).fHeight;
}
// Group drawing by skin elements for caching performance
UInt16 startY = y;
x = 0;
element = fSkin->GetElement( pfGUISkin::kLeftSpan );
for( ; y < totHeight; )
{
UInt16 ht = element.fHeight;
if( y + ht > totHeight )
ht = totHeight - y;
fDynTextMap->DrawClippedImage( x, y, fSkin->GetTexture(), element.fX, element.fY, element.fWidth, ht, plDynamicTextMap::kImgSprite );
y += ht;
}
x += element.fWidth;
if( sel )
element = fSkin->GetElement( pfGUISkin::kSelectedFill );
else
element = fSkin->GetElement( pfGUISkin::kMiddleFill );
for( ; x < totWidth; )
{
UInt16 wid = element.fWidth;
if( x + wid > totWidth )
wid = totWidth - x;
for( y = startY; y < totHeight; )
{
UInt16 ht = element.fHeight;
if( y + ht > totHeight )
ht = totHeight - y;
fDynTextMap->DrawClippedImage( x, y, fSkin->GetTexture(), element.fX, element.fY, wid, ht, plDynamicTextMap::kImgSprite );
y += ht;
}
x += wid;
}
element = fSkin->GetElement( pfGUISkin::kRightSpan );
for( y = startY; y < totHeight; )
{
UInt16 ht = element.fHeight;
if( y + ht > totHeight )
ht = totHeight - y;
fDynTextMap->DrawClippedImage( x, y, fSkin->GetTexture(), element.fX, element.fY, element.fWidth, ht, plDynamicTextMap::kImgSprite );
y += ht;
}
if( fHowToSkin == kBottom )
{
x = 0;
// Draw lower-left corner
element = fSkin->GetElement( pfGUISkin::kLowerLeftCorner );
fDynTextMap->DrawClippedImage( x, y, fSkin->GetTexture(), element.fX, element.fY, element.fWidth, element.fHeight, plDynamicTextMap::kImgSprite );
x += element.fWidth;
element = fSkin->GetElement( pfGUISkin::kBottomSpan );
for( ; x < totWidth; )
{
UInt16 wid = element.fWidth;
if( x + wid > totWidth )
wid = totWidth - x;
fDynTextMap->DrawClippedImage( x, y, fSkin->GetTexture(), element.fX, element.fY, wid, element.fHeight, plDynamicTextMap::kImgSprite );
x += wid;
}
element = fSkin->GetElement( pfGUISkin::kLowerRightCorner );
fDynTextMap->DrawClippedImage( x, y, fSkin->GetTexture(), element.fX, element.fY, element.fWidth, element.fHeight, plDynamicTextMap::kImgSprite );
y += element.fHeight;
}
}
//// IUpdate /////////////////////////////////////////////////////////////////
void pfGUIMenuItem::IUpdate( void )
{
if( fDynTextMap == nil )
return;
if( fSkin != nil )
{
IUpdateSkinBuffers();
if( !fSkinBuffersUpdated )
return;
// Copy now from our skin buffer, plus set our text color
UInt16 y = fDynTextMap->GetVisibleHeight();
if( IsInteresting() )
{
fDynTextMap->DrawClippedImage( 0, 0, fDynTextMap, 0, y << 1, fDynTextMap->GetVisibleWidth(), y, plDynamicTextMap::kImgSprite );
fDynTextMap->SetTextColor( GetColorScheme()->fSelForeColor );
}
else
{
fDynTextMap->DrawClippedImage( 0, 0, fDynTextMap, 0, y, fDynTextMap->GetVisibleWidth(), y, plDynamicTextMap::kImgSprite );
fDynTextMap->SetTextColor( GetColorScheme()->fForeColor );
}
}
else
{
if( IsInteresting() )
{
fDynTextMap->ClearToColor( GetColorScheme()->fSelBackColor );
fDynTextMap->SetTextColor( GetColorScheme()->fSelForeColor );
}
else
{
fDynTextMap->ClearToColor( GetColorScheme()->fBackColor );
fDynTextMap->SetTextColor( GetColorScheme()->fForeColor );
}
}
fDynTextMap->SetJustify( plDynamicTextMap::kLeftJustify );
if( fName != nil )
{
UInt16 ht;
fDynTextMap->CalcStringWidth( fName, &ht );
Int16 x = 0, y = ( fDynTextMap->GetVisibleHeight() - ht ) >> 1;
if( fHowToSkin == kTop && fSkin != nil )
y += fSkin->GetElement( pfGUISkin::kTopSpan ).fHeight >> 1;
else if( fHowToSkin == kBottom && fSkin != nil )
y -= fSkin->GetElement( pfGUISkin::kTopSpan ).fHeight >> 1;
if( fSkin != nil )
x += fSkin->GetBorderMargin();
if( fClicking )
{
x += 2;
y += 2;
}
fDynTextMap->DrawClippedString( x, y, fName, fDynTextMap->GetVisibleWidth(), fDynTextMap->GetVisibleHeight() );
if( HasFlag( kDrawSubMenuArrow ) )
{
if( fSkin != nil )
{
pfGUISkin::pfSRect element;
if( IsInteresting() )
element = fSkin->GetElement( pfGUISkin::kSelectedSubMenuArrow );
else
element = fSkin->GetElement( pfGUISkin::kSubMenuArrow );
y += ( ht >> 1 ) - ( element.fHeight >> 1 );
if( y < 0 || y + element.fHeight >= fDynTextMap->GetHeight() )
y = 0;
fDynTextMap->DrawClippedImage( x + fDynTextMap->GetVisibleWidth() - 2 - element.fWidth
- fSkin->GetElement( pfGUISkin::kRightSpan ).fWidth,
y,
fSkin->GetTexture(), element.fX, element.fY, element.fWidth, element.fHeight, plDynamicTextMap::kImgBlend );
}
else
{
fDynTextMap->SetJustify( plDynamicTextMap::kRightJustify );
fDynTextMap->DrawString( x + fDynTextMap->GetVisibleWidth() - 2, y, ">>" );
}
}
}
fDynTextMap->FlushToHost();
}
void pfGUIMenuItem::PurgeDynaTextMapImage()
{
if ( fDynTextMap != nil )
fDynTextMap->PurgeImage();
}
//// GetTextExtents //////////////////////////////////////////////////////////
// Calculate the size of the drawn text.
void pfGUIMenuItem::GetTextExtents( UInt16 &width, UInt16 &height )
{
if( fName == nil )
width = height = 0;
else
width = fDynTextMap->CalcStringWidth( fName, &height );
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGUIMenuItem::MsgReceive( plMessage *msg )
{
return pfGUIButtonMod::MsgReceive( msg );
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUIMenuItem::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIButtonMod::Read( s, mgr );
}
void pfGUIMenuItem::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIButtonMod::Write( s, mgr );
}
//// HandleMouseDown/Up //////////////////////////////////////////////////////
void pfGUIMenuItem::HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers )
{
pfGUIButtonMod::HandleMouseDown( mousePt, modifiers );
IUpdate();
}
void pfGUIMenuItem::HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers )
{
pfGUIButtonMod::HandleMouseUp( mousePt, modifiers );
IUpdate();
}
void pfGUIMenuItem::HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers )
{
/* if( !fClicking )
return;
if( fDraggable == nil )
return;
if( !fDraggable->IsVisible() )
{
// Are we outside ourselves?
if( !PointInBounds( mousePt ) )
{
// Yes, start dragging
StartDragging();
// Hand off our interest to the draggable
fDialog->SetControlOfInterest( fDraggable );
}
}
*/
pfGUIButtonMod::HandleMouseDrag( mousePt, modifiers );
}
void pfGUIMenuItem::HandleMouseHover( hsPoint3 &mousePt, UInt8 modifiers )
{
pfGUIButtonMod::HandleMouseHover( mousePt, modifiers );
if( HasFlag( kReportHovers ) )
{
if( PointInBounds( mousePt ) )
{
if( !fReportingHover && ( fDialog->GetControlOfInterest() == nil ||
fDialog->GetControlOfInterest() == this ) )
{
fReportingHover = true;
HandleExtendedEvent( kMouseHover );
fDialog->SetControlOfInterest( this );
}
}
else if( fReportingHover )
{
fReportingHover = false;
HandleExtendedEvent( kMouseExit );
fDialog->SetControlOfInterest( nil );
}
}
}
//// SetInteresting //////////////////////////////////////////////////////////
// Overridden to play mouse over animation when we're interesting
void pfGUIMenuItem::SetInteresting( hsBool i )
{
pfGUIButtonMod::SetInteresting( i );
IUpdate();
// Make sure we're not still thinking we're reporting hovers when we're not
if( !i )
fReportingHover = false;
}

View File

@ -0,0 +1,112 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIMenuItem Header //
// //
// The type of button that knows how to party. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIMenuItem_h
#define _pfGUIMenuItem_h
#include "pfGUIButtonMod.h"
class plMessage;
class pfGUISkin;
class pfGUIMenuItem : public pfGUIButtonMod
{
public:
enum HowToSkin
{
kTop,
kMiddle,
kBottom
};
protected:
wchar_t *fName;
hsBool fReportingHover;
HowToSkin fHowToSkin;
hsBool fSkinBuffersUpdated;
virtual void IGrowDTMDimsToDesiredSize( UInt16 &width, UInt16 &height );
virtual void IPostSetUpDynTextMap( void );
virtual void IUpdate( void );
void IUpdateSkinBuffers( void );
void IUpdateSingleSkinBuffer( UInt16 y, hsBool sel );
public:
pfGUIMenuItem();
virtual ~pfGUIMenuItem();
CLASSNAME_REGISTER( pfGUIMenuItem );
GETINTERFACE_ANY( pfGUIMenuItem, pfGUIButtonMod );
enum ItemFlags
{
kDrawSubMenuArrow = kDerivedFlagsStart,
kReportHovers
};
// Extended event types
enum ExtendedEvents
{
kMouseHover,
kMouseExit
};
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
virtual void SetInteresting( hsBool i );
virtual void HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseHover( hsPoint3 &mousePt, UInt8 modifiers );
virtual void PurgeDynaTextMapImage();
void SetName( const char *name );
void SetName( const wchar_t *name );
const wchar_t *GetName( void ) const { return fName; }
void GetTextExtents( UInt16 &width, UInt16 &height );
void SetSkin( pfGUISkin *skin, HowToSkin s );
};
#endif // _pfGUIMenuItem_h

View File

@ -0,0 +1,273 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIMultiLineEditCtrl Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIMultiLineEditCtrl_h
#define _pfGUIMultiLineEditCtrl_h
#include "pfGUIControlMod.h"
#include "hsTemplates.h"
#include "../plInputCore/plInputDevice.h"
class plMessage;
class hsGMaterial;
class plTextGenerator;
class pfMLScrollProc;
class pfGUIValueCtrl;
struct plUndoAction;
class pfGUIMultiLineEditProc
{
public:
pfGUIMultiLineEditProc() {}
virtual ~pfGUIMultiLineEditProc() {}
// we've hit the end of the control list (by moving the cursor)
virtual OnEndOfControlList(Int32 cursorPos) {}
// we've hit the beginning of the control ist (by moving the cursor)
virtual OnBeginningOfControlList(Int32 cursorPos) {}
};
class pfGUIMultiLineEditCtrl : public pfGUIControlMod
{
public:
enum Direction
{
kLineStart = 1,
kLineEnd,
kBufferStart,
kBufferEnd,
kOneBack,
kOneForward,
kOneWordBack,
kOneWordForward,
kOneLineUp,
kOneLineDown,
kPageUp,
kPageDown
};
protected:
mutable hsTArray<wchar_t> fBuffer; // Because AcquireArray() isn't const
hsTArray<Int32> fLineStarts;
UInt16 fLineHeight, fCurrCursorX, fCurrCursorY;
Int32 fCursorPos, fLastCursorLine;
hsBool fIgnoreNextKey, fReadyToRender;
hsBounds3Ext fLastP2PArea;
Int8 fLockCount;
UInt8 fCalcedFontSize; // The font size that we calced our line height at
UInt8 fLastKeyModifiers;
wchar_t fLastKeyPressed;
static wchar_t fColorCodeChar, fStyleCodeChar;
static UInt32 fColorCodeSize, fStyleCodeSize;
wchar_t fLastDeadKey; // if the previous key was a dead key, its value goes here
wchar_t fDeadKeyConverter[256][256]; // first index is the dead key, second index is the char to combine it with
void SetupDeadKeyConverter();
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
virtual void IPostSetUpDynTextMap( void );
virtual void IUpdate( void );
void IUpdate( Int32 startLine, Int32 endLine );
friend class pfMLScrollProc;
pfGUIValueCtrl *fScrollControl;
pfMLScrollProc *fScrollProc;
Int32 fScrollPos;
Int32 fBufferLimit;
pfGUIMultiLineEditCtrl *fNextCtrl; // used for linking multiple controls together to share a buffer
pfGUIMultiLineEditCtrl *fPrevCtrl;
pfGUIMultiLineEditProc *fEventProc; // where we send events to
std::string fFontFace;
hsColorRGBA fFontColor;
UInt8 fFontSize;
UInt8 fFontStyle;
enum flagsSet
{
kFontFaceSet = 1,
kFontColorSet = 2,
kFontSizeSet = 4,
kFontStyleSet = 8
};
UInt8 fFontFlagsSet;
int fTopMargin,fLeftMargin,fBottomMargin,fRightMargin;
void IMoveCursor( Direction dir );
void IMoveCursorTo( Int32 position ); // Updates selection
void ISetCursor( Int32 newPosition ); // Doesn't update selection
Int32 IRecalcLineStarts( Int32 startingLine, hsBool force, hsBool dontUpdate = false );
void IRecalcFromCursor( hsBool forceUpdate = false );
Int32 IFindCursorLine( Int32 cursorPos = -1 ) const;
hsBool IStoreLineStart( UInt32 line, Int32 start );
void IOffsetLineStarts( UInt32 position, Int32 offset, hsBool offsetSelectionEnd = false );
Int32 IPointToPosition( Int16 x, Int16 y, hsBool searchOutsideBounds = false );
Int32 ICalcNumVisibleLines( void ) const;
void IReadColorCode( Int32 &pos, hsColorRGBA &color ) const;
void IReadStyleCode( Int32 &pos, UInt8 &fontStyle ) const;
UInt32 IRenderLine( UInt16 x, UInt16 y, Int32 start, Int32 end, hsBool dontRender = false );
hsBool IFindLastColorCode( Int32 pos, hsColorRGBA &color, hsBool ignoreFirstCharacter = false ) const;
hsBool IFindLastStyleCode( Int32 pos, UInt8 &style, hsBool ignoreFirstCharacter = false ) const;
inline static bool IIsCodeChar( const wchar_t c );
inline static bool IIsRenderable( const wchar_t c );
inline static Int32 IOffsetToNextChar( wchar_t stringChar );
inline Int32 IOffsetToNextCharFromPos( Int32 pos ) const;
void IActuallyInsertColor( Int32 pos, hsColorRGBA &color );
void IActuallyInsertStyle( Int32 pos, UInt8 style );
void IUpdateScrollRange( void );
wchar_t *ICopyRange( Int32 start, Int32 end ) const;
Int32 ICharPosToBufferPos( Int32 charPos ) const;
void IUpdateBuffer();
void IUpdateLineStarts();
void ISetGlobalBuffer();
void ISetLineStarts(hsTArray<Int32> lineStarts);
void IHitEndOfControlList(Int32 cursorPos);
void IHitBeginningOfControlList(Int32 cursorPos);
public:
enum
{
kRefScrollCtrl = kRefDerivedStart
};
pfGUIMultiLineEditCtrl();
virtual ~pfGUIMultiLineEditCtrl();
CLASSNAME_REGISTER( pfGUIMultiLineEditCtrl );
GETINTERFACE_ANY( pfGUIMultiLineEditCtrl, pfGUIControlMod );
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
virtual void HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers );
virtual hsBool HandleKeyPress( char key, UInt8 modifiers );
virtual hsBool HandleKeyEvent( pfGameGUIMgr::EventType event, plKeyDef key, UInt8 modifiers );
virtual void PurgeDynaTextMapImage();
// Extended event types
enum ExtendedEvents
{
kValueChanging,
kScrollPosChanged,
kKeyPressedEvent
};
void SetScrollPosition( Int32 topLine );
void MoveCursor( Direction dir );
void InsertChar( char c );
void InsertChar( wchar_t c);
void InsertString( const char *string );
void InsertString( const wchar_t *string );
void InsertColor( hsColorRGBA &color );
void InsertStyle( UInt8 fontStyle );
void DeleteChar( void );
void ClearBuffer( void );
void SetBuffer( const char *asciiText );
void SetBuffer( const wchar_t *asciiText );
void SetBuffer( const UInt8 *codedText, UInt32 length );
void SetBuffer( const UInt16 *codedText, UInt32 length );
char *GetNonCodedBuffer( void ) const;
wchar_t *GetNonCodedBufferW( void ) const;
UInt8 *GetCodedBuffer( UInt32 &length ) const;
UInt16 *GetCodedBufferW( UInt32 &length ) const;
UInt32 GetBufferSize();
void SetBufferLimit(Int32 limit) { fBufferLimit = limit; }
Int32 GetBufferLimit() { return fBufferLimit; }
void GetThisKeyPressed( char &key, UInt8 &modifiers ) const { key = (char)fLastKeyPressed; modifiers = fLastKeyModifiers; }
void Lock( void );
void Unlock( void );
hsBool IsLocked( void ) const { return ( fLockCount > 0 ) ? true : false; }
void SetScrollEnable( hsBool state );
void ForceUpdate() {/*IRecalcLineStarts(0,true);*/IUpdateLineStarts(); IUpdate();}
void SetNext( pfGUIMultiLineEditCtrl *newNext );
void ClearNext();
void SetPrev( pfGUIMultiLineEditCtrl *newPrev );
void ClearPrev();
void SetEventProc( pfGUIMultiLineEditProc *eventProc );
void ClearEventProc();
Int32 GetFirstVisibleLine();
Int32 GetLastVisibleLine();
Int32 GetNumVisibleLines() {return ICalcNumVisibleLines();}
void SetGlobalStartLine(Int32 line);
void SetCursorToLoc(Int32 loc) {ISetCursor(loc);}
void SetMargins(int top, int left, int bottom, int right);
UInt8 GetFontSize() {return fFontSize;} // because we're too cool to use the color scheme crap
void SetFontFace(std::string fontFace);
void SetFontColor(hsColorRGBA fontColor) {fFontColor = fontColor; fFontFlagsSet |= kFontColorSet;}
void SetFontSize(UInt8 fontSize);
void SetFontStyle(UInt8 fontStyle) {fFontStyle = fontStyle; fFontFlagsSet |= kFontStyleSet;}
hsBool ShowingBeginningOfBuffer();
hsBool ShowingEndOfBuffer();
void DeleteLinesFromTop(int numLines); // cursor and scroll position might be off after this call, not valid on connected controls
};
#endif // _pfGUIMultiLineEditCtrl_h

View File

@ -0,0 +1,940 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIPopUpMenu Header //
// //
// Pop-up menus are really just dialogs that know how to create themselves //
// and create buttons on themselves to simulate a menu (after all, that's //
// all a menu really is anyway). //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGameGUIMgr.h"
#include "pfGUIPopUpMenu.h"
#include "pfGUIMenuItem.h"
#include "pfGUIButtonMod.h"
#include "pfGUIDialogHandlers.h"
#include "pfGUIDialogNotifyProc.h"
#include "pfGUIControlHandlers.h"
#include "pfGUICtrlGenerator.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
#include "../plSurface/hsGMaterial.h"
#include "../plSurface/plLayer.h"
#include "../plGImage/plDynamicTextMap.h"
#include "../plMessage/plLayRefMsg.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnSceneObject/plDrawInterface.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "../pnMessage/plIntRefMsg.h"
#include "../pnMessage/plObjRefMsg.h"
#include "../pnMessage/plNodeRefMsg.h"
#include "../plScene/plPostEffectMod.h"
#include "../plScene/plSceneNode.h"
#include "../pnMessage/plClientMsg.h"
#include "plViewTransform.h"
#include "../plPipeline/plDebugText.h"
class pfPopUpKeyGenerator
{
public:
char fPrefix[ 128 ];
UInt32 fKeyCount;
plLocation fLoc;
pfPopUpKeyGenerator( const char *p, const plLocation &loc )
{
strcpy( fPrefix, p );
fLoc = loc;
}
plKey CreateKey( hsKeyedObject *ko )
{
char name[ 256 ];
sprintf( name, "%s-%d", fPrefix, fKeyCount++ );
return hsgResMgr::ResMgr()->NewKey( name, ko, fLoc );
}
};
//// Router Proc So The Parent Can Handle Click Events ///////////////////////
class pfGUIMenuItemProc : public pfGUICtrlProcObject
{
protected:
pfGUIPopUpMenu *fParent;
UInt32 fIndex;
public:
pfGUIMenuItemProc( pfGUIPopUpMenu *parent, UInt32 idx )
{
fParent = parent;
fIndex = idx;
}
virtual void DoSomething( pfGUIControlMod *ctrl )
{
fParent->IHandleMenuSomething( fIndex, ctrl );
}
virtual void HandleExtendedEvent( pfGUIControlMod *ctrl, UInt32 event )
{
fParent->IHandleMenuSomething( fIndex, ctrl, (Int32)event );
}
};
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIPopUpMenu::pfGUIPopUpMenu()
{
fNeedsRebuilding = false;
fParent = nil;
fKeyGen = nil;
fSubMenuOpen = -1;
SetFlag( kModalOutsideMenus );
fMargin = 4;
fSkin = nil;
fWaitingForSkin = false;
fParentNode = nil;
fOriginX = fOriginY = 0.f;
fOriginAnchor = nil;
fOriginContext = nil;
fAlignment = kAlignDownRight;
}
pfGUIPopUpMenu::~pfGUIPopUpMenu()
{
SetSkin( nil );
// if( fParentNode != nil )
// fParentNode->GetKey()->UnRefObject();
ITearDownMenu();
ClearItems();
delete fKeyGen;
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGUIPopUpMenu::MsgReceive( plMessage *msg )
{
plGenRefMsg *ref = plGenRefMsg::ConvertNoRef( msg );
if( ref != nil )
{
if( ref->fType == kRefSkin )
{
if( ref->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
{
fSkin = pfGUISkin::ConvertNoRef( ref->GetRef() );
fWaitingForSkin = false;
}
else
fSkin = nil;
fNeedsRebuilding = true;
if( IsVisible() )
{
// Rebuild NOW
ITearDownMenu();
IBuildMenu();
}
return true;
}
else if( ref->fType == kRefSubMenu )
{
if( ref->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
fMenuItems[ ref->fWhich ].fSubMenu = pfGUIPopUpMenu::ConvertNoRef( ref->GetRef() );
else
fMenuItems[ ref->fWhich ].fSubMenu = nil;
return true;
}
else if( ref->fType == kRefOriginAnchor )
{
if( ref->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
fOriginAnchor = plSceneObject::ConvertNoRef( ref->GetRef() );
else
fOriginAnchor = nil;
return true;
}
else if( ref->fType == kRefOriginContext )
{
if( ref->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
fOriginContext = pfGUIDialogMod::ConvertNoRef( ref->GetRef() );
else
fOriginContext = nil;
return true;
}
else if( ref->fType == kRefParentNode )
{
if( ref->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
fParentNode = plSceneNode::ConvertNoRef( ref->GetRef() );
else
fParentNode = nil;
return true;
}
}
return pfGUIDialogMod::MsgReceive( msg );
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUIPopUpMenu::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIDialogMod::Read( s, mgr );
// In case we need it...
fKeyGen = TRACKED_NEW pfPopUpKeyGenerator( GetName(), GetKey()->GetUoid().GetLocation() );
fOriginX = fOriginY = -1.f;
fMargin = s->ReadSwap16();
UInt32 i, count = s->ReadSwap32();
fMenuItems.SetCountAndZero( count );
for( i = 0; i < count; i++ )
{
char readTemp[ 256 ];
s->Read( sizeof( readTemp ), readTemp );
wchar_t *wReadTemp = hsStringToWString( readTemp );
fMenuItems[ i ].fName = wReadTemp;
delete [] wReadTemp;
fMenuItems[ i ].fHandler = pfGUICtrlProcWriteableObject::Read( s );
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, i, kRefSubMenu ), plRefFlags::kActiveRef );
}
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefSkin ), plRefFlags::kActiveRef );
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefOriginAnchor ), plRefFlags::kPassiveRef );
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefOriginContext ), plRefFlags::kPassiveRef );
fAlignment = (Alignment)s->ReadByte();
fNeedsRebuilding = true;
}
void pfGUIPopUpMenu::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIDialogMod::Write( s, mgr );
s->WriteSwap16( fMargin );
s->WriteSwap32( fMenuItems.GetCount() );
UInt32 i;
for( i = 0; i < fMenuItems.GetCount(); i++ )
{
char writeTemp[ 256 ];
char *sName = hsWStringToString( fMenuItems[ i ].fName.c_str() );
strncpy( writeTemp, sName, sizeof( writeTemp ) );
delete [] sName;
s->Write( sizeof( writeTemp ), writeTemp );
// Write the handler out (if it's not a writeable, damn you)
pfGUICtrlProcWriteableObject::Write( (pfGUICtrlProcWriteableObject *)fMenuItems[ i ].fHandler, s );
mgr->WriteKey( s, fMenuItems[ i ].fSubMenu );
}
// Note: we force parentNode to nil here because we only use it when we dynamically
// create nodes at runtime and need to unref and destroy them later. Since we're
// reading from disk, we'll already have a sceneNode somewhere, so we don't need
// this.
fParentNode = nil;
mgr->WriteKey( s, fSkin );
mgr->WriteKey( s, fOriginAnchor );
mgr->WriteKey( s, fOriginContext );
s->WriteByte( (UInt8)fAlignment );
}
void pfGUIPopUpMenu::SetOriginAnchor( plSceneObject *anchor, pfGUIDialogMod *context )
{
fOriginAnchor = anchor;
fOriginContext = context;
hsgResMgr::ResMgr()->AddViaNotify( fOriginAnchor->GetKey(), TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefOriginAnchor ), plRefFlags::kPassiveRef );
hsgResMgr::ResMgr()->AddViaNotify( fOriginContext->GetKey(), TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefOriginContext ), plRefFlags::kPassiveRef );
}
//// SetEnabled //////////////////////////////////////////////////////////////
void pfGUIPopUpMenu::SetEnabled( hsBool e )
{
if( e && fNeedsRebuilding )
{
// Make sure our menu is rebuilt before enabling
ITearDownMenu();
IBuildMenu();
}
else if( !e )
{
if( fParent != nil )
pfGUIPopUpMenu::ConvertNoRef( fParent )->fSubMenuOpen = -1;
// Hide our submenus if we have any open
if( fSubMenuOpen != -1 )
{
fMenuItems[ fSubMenuOpen ].fSubMenu->Hide();
fSubMenuOpen = -1;
}
}
pfGUIDialogMod::SetEnabled( e );
}
void pfGUIPopUpMenu::Show( hsScalar x, hsScalar y )
{
fOriginX = x;
fOriginY = y;
pfGUIDialogMod::Show(); // C++ is kinda stupid if it can't find this naturally
ISeekToOrigin();
}
void pfGUIPopUpMenu::ISeekToOrigin( void )
{
#if 0
UInt32 i;
float x = 0.5f/*fOriginX*/, y = fOriginY;
for( i = 0; i < fControls.GetCount(); i++ )
{
if( fControls[ i ] != nil )
{
fControls[ i ]->SetObjectCenter( x, y );
// const hsBounds3 &bnds = fControls[ i ]->GetBounds();
y += fMenuItems[ i ].fYOffsetToNext;//bnds.GetMaxs().fY - bnds.GetMins().fY;
/* hsMatrix44 p2l, l2p = GetTarget()->GetLocalToWorld();
hsPoint3 center, origin;
ScreenToWorldPoint( fOriginX, fOriginY, 100.f, center );
ScreenToWorldPoint( 0.f, 0.f, 100.f, origin );
center = origin - center;
center.fZ = 0.f;
l2p.SetTranslate( &center );
l2p.GetInverse( &p2l );
GetTarget()->SetTransform( l2p, p2l );
*/ }
}
#endif
}
//// IHandleMenuSomething ////////////////////////////////////////////////////
// Handles a normal event from one of the item controls.
void pfGUIPopUpMenu::IHandleMenuSomething( UInt32 idx, pfGUIControlMod *ctrl, Int32 extended )
{
if( extended != -1 )
{
if( fSubMenuOpen != -1 && fSubMenuOpen != idx )
{
// Better close the submenu(s)
fMenuItems[ fSubMenuOpen ].fSubMenu->Hide();
fSubMenuOpen = -1;
}
if( extended == pfGUIMenuItem::kMouseHover && fMenuItems[ idx ].fSubMenu != nil )
{
// Open new submenu
const hsBounds3 &bnds = ctrl->GetBounds();
fMenuItems[ idx ].fSubMenu->Show( bnds.GetMaxs().fX, bnds.GetMins().fY );
fSubMenuOpen = idx;
}
}
else
{
if( fMenuItems[ idx ].fHandler != nil )
fMenuItems[ idx ].fHandler->DoSomething( ctrl );
// If item isn't a sub-menu, close this menu. Else add to list of menus to close
// once the smallest submenu goes away
if( fMenuItems[ idx ].fSubMenu == nil )
{
// Basically, we want to hide ourselves and as many up in the chain of command as
// can be hidden
pfGUIPopUpMenu *menu = this;
while( menu != nil && !menu->HasFlag( kStayOpenAfterClick ) )
{
menu->Hide();
menu = pfGUIPopUpMenu::ConvertNoRef( menu->fParent );
}
}
else
{
// Show relative to the corner of our current item
const hsBounds3 &bnds = ctrl->GetBounds();
fMenuItems[ idx ].fSubMenu->Show( bnds.GetMaxs().fX, bnds.GetMins().fY );
fSubMenuOpen = idx;
}
}
}
//// IBuildMenu //////////////////////////////////////////////////////////////
// Given the list of menu items, builds our set of dynamic buttons
hsBool pfGUIPopUpMenu::IBuildMenu( void )
{
int i;
if( fWaitingForSkin && fSkin == nil )
return false; // Still waiting to get our skin before building
pfGUIColorScheme *scheme = TRACKED_NEW pfGUIColorScheme();
scheme->fForeColor.Set( 0, 0, 0, 1 );
scheme->fBackColor.Set( 1, 1, 1, 1 );
// If we don't have origin points, get them from translating our anchor
if( fOriginX == -1 || fOriginY == -1 && fOriginAnchor != nil )
{
hsPoint3 scrnPt;
const plDrawInterface *di = fOriginAnchor->GetDrawInterface();
if( di != nil )
{
scrnPt = di->GetLocalBounds().GetCenter();
scrnPt = fOriginAnchor->GetLocalToWorld() * scrnPt;
}
else
scrnPt = fOriginAnchor->GetLocalToWorld().GetTranslate();
if( fOriginContext != nil )
scrnPt = fOriginContext->WorldToScreenPoint( scrnPt );
else
scrnPt = WorldToScreenPoint( scrnPt );
if( fOriginX == -1 )
fOriginX = scrnPt.fX;
if( fOriginY == -1 )
fOriginY = scrnPt.fY;
}
float x = fOriginX, y = fOriginY;
float width = 0.f, height = 0.f;
float topMargin = ( fSkin != nil ) ? fSkin->GetBorderMargin() : 0.f;
// First step: loop through and calculate the size of our menu
// The PROBLEM is that we can't do that unless we have a friggin surface on
// which to calculate the text extents! So sadly, we're going to have to create
// a whole new DTMap and use it to calculate some stuff
plDynamicTextMap *scratch = TRACKED_NEW plDynamicTextMap( 8, 8, false );
scratch->SetFont( scheme->fFontFace, scheme->fFontSize, scheme->fFontFlags, true );
for( i = 0; i < fMenuItems.GetCount(); i++ )
{
UInt16 thisW, thisH;
thisW = scratch->CalcStringWidth( fMenuItems[ i ].fName.c_str(), &thisH );
if( fMenuItems[ i ].fSubMenu != nil )
{
if( fSkin != nil )
thisW += 4 + ( fSkin->GetElement( pfGUISkin::kSubMenuArrow ).fWidth << 1 );
else
thisW += scratch->CalcStringWidth( " >>", nil );
}
thisH += 2; // Give us at least one pixel on each side
int margin = fMargin;
if( fSkin != nil )
margin = fSkin->GetBorderMargin() << 1;
if( width < thisW + margin )
width = (float)(thisW + margin);
if( fSkin != nil )
margin = fSkin->GetItemMargin() << 1;
if( height < thisH + margin )
height = (float)(thisH + margin);
}
delete scratch;
width += 4; // give us a little space, just in case
UInt32 scrnWidth, scrnHeight;
// A cheat here, I know, but I'm lazy
plDebugText::Instance().GetScreenSize( &scrnWidth, &scrnHeight );
// Use the same base res calc that dtMaps use
if( !HasFlag( kScaleWithResolution ) )
{
// Just use what we were passed in
}
else
{
// Scale with the resolution so that we take up the same % of screen space no matter what resolution
// Assume a base "resolution" of 1024xX, where X is such that the ratio "1024/X = scrnWidth/scrnHt" holds
const int kBaseScaleRes = 1024;
scrnHeight = ( scrnHeight * kBaseScaleRes ) / scrnWidth;
scrnWidth = kBaseScaleRes;
}
width /= (float)scrnWidth;
height /= (float)scrnHeight;
topMargin /= (float)scrnHeight;
switch( fAlignment )
{
case kAlignUpLeft: x -= width; y -= height * fMenuItems.GetCount(); break;
case kAlignUpRight: y -= height * fMenuItems.GetCount(); break;
case kAlignDownLeft: x -= width; break;
case kAlignDownRight: break;
}
if( y + height * fMenuItems.GetCount() > 1.f )
{
// Make sure we don't go off the bottom
y = 1.f - height * fMenuItems.GetCount();
}
// And the top (takes precedence)
if( y < 0.f )
y = 0.f;
// Control positions are in the lower left corner, so increment Y by 1 control height first
y += height;// + topMargin;
hsTArray<pfGUIPopUpMenu *> buildList;
for( i = 0; i < fMenuItems.GetCount(); i++ )
{
hsGMaterial *mat = ICreateDynMaterial();
float thisMargin = ( i == 0 || i == fMenuItems.GetCount() - 1 ) ? topMargin : 0.f;
float thisOffset = ( i == fMenuItems.GetCount() - 1 ) ? topMargin : 0.f;
pfGUIMenuItem *button = pfGUIMenuItem::ConvertNoRef( pfGUICtrlGenerator::Instance().CreateRectButton( this, fMenuItems[ i ].fName.c_str(), x, y + thisOffset, width, height + thisMargin, mat, true ) );
if( button != nil )
{
button->SetColorScheme( scheme );
button->SetName( fMenuItems[ i ].fName.c_str() );
button->SetHandler( TRACKED_NEW pfGUIMenuItemProc( this, i ) );
// make the tag ID the position in the menu list
button->SetTagID(i);
button->SetDynTextMap( mat->GetLayer( 0 ), plDynamicTextMap::ConvertNoRef( mat->GetLayer( 0 )->GetTexture() ) );
button->SetFlag( pfGUIMenuItem::kReportHovers );
button->SetSkin( fSkin, ( i == 0 ) ? pfGUIMenuItem::kTop : ( i == fMenuItems.GetCount() - 1 ) ? pfGUIMenuItem::kBottom : pfGUIMenuItem::kMiddle );
if( fMenuItems[ i ].fSubMenu != nil )
{
button->SetFlag( pfGUIMenuItem::kDrawSubMenuArrow );
buildList.Append( pfGUIPopUpMenu::ConvertNoRef( fMenuItems[ i ].fSubMenu ) );
}
}
// Tiny bit of overlap to prevent gaps
fMenuItems[ i ].fYOffsetToNext = height + thisOffset;
y += height + thisOffset;// - ( 1.f / kBaseScaleResY );
}
fNeedsRebuilding = false;
#if 0
// Finally, go down our list of submenus and rebuild them, since they'll need to be rebuilt soon anyway,
// and at least this way it's all in one pass
// Also, we need to bump the tag ID used, such as adding parent menuItem TagID * 100.. or something
// Disabled because right now we can't move menus, which is required for this to work
for( i = 0; i < buildList.GetCount(); i++ )
buildList[ i ]->IBuildMenu();
#endif
return true;
}
//// ITearDownMenu ///////////////////////////////////////////////////////////
// Destroys all of our dynamic controls representing the menu
void pfGUIPopUpMenu::ITearDownMenu( void )
{
int i;
for( i = 0; i < fControls.GetCount(); i++ )
{
if( fControls[ i ] != nil )
{
// It's not enough to release the key, we have to have the sceneNode release the key, too.
// Easy enough to do by just setting it's sn to nil
if( fControls[ i ]->GetTarget() != nil )
fControls[ i ]->GetTarget()->SetSceneNode( nil );
// Now release it from us
GetKey()->Release( fControls[ i ]->GetKey() );
}
}
fNeedsRebuilding = true;
}
//// HandleMouseEvent ////////////////////////////////////////////////////////
hsBool pfGUIPopUpMenu::HandleMouseEvent( pfGameGUIMgr::EventType event, hsScalar mouseX, hsScalar mouseY,
UInt8 modifiers )
{
hsBool r = pfGUIDialogMod::HandleMouseEvent( event, mouseX, mouseY, modifiers );
if( r == false && event == pfGameGUIMgr::kMouseUp )
{
// We don't want to be active anymore!
if( !HasFlag( kStayOpenAfterClick ) )
{
Hide();
// Now we pass the click to our parent. Why? Because it's possible that someone above us
// will either a) also want to hide (cancel the entire menu selection) or b) select
// another option
if( fParent != nil )
return fParent->HandleMouseEvent( event, mouseX, mouseY, modifiers );
}
}
return ( fParent != nil ) ? r : ( HasFlag( kModalOutsideMenus ) || ( fSubMenuOpen != -1 ) );
}
//// ClearItems //////////////////////////////////////////////////////////////
// Clears the list of template items
void pfGUIPopUpMenu::ClearItems( void )
{
int i;
for( i = 0; i < fMenuItems.GetCount(); i++ )
{
if( fMenuItems[ i ].fHandler != nil )
{
if( fMenuItems[ i ].fHandler->DecRef() )
delete fMenuItems[ i ].fHandler;
}
}
fMenuItems.Reset();
fNeedsRebuilding = true;
}
//// AddItem /////////////////////////////////////////////////////////////////
// Append a new item to the list of things to build the menu from
void pfGUIPopUpMenu::AddItem( const char *name, pfGUICtrlProcObject *handler, pfGUIPopUpMenu *subMenu )
{
wchar_t *wName = hsStringToWString(name);
AddItem(wName,handler,subMenu);
delete [] wName;
}
void pfGUIPopUpMenu::AddItem( const wchar_t *name, pfGUICtrlProcObject *handler, pfGUIPopUpMenu *subMenu )
{
pfMenuItem newItem;
newItem.fName = name;
newItem.fHandler = handler;
if( newItem.fHandler != nil )
newItem.fHandler->IncRef();
newItem.fSubMenu = subMenu;
if( subMenu != nil )
subMenu->fParent = this;
fMenuItems.Append( newItem );
fNeedsRebuilding = true;
}
//// ICreateDynMaterial //////////////////////////////////////////////////////
// Creates the hsGMaterial tree for a single layer with a plDynamicTextMap.
hsGMaterial *pfGUIPopUpMenu::ICreateDynMaterial( void )
{
hsColorRGBA black, white;
// Create the new dynTextMap
plDynamicTextMap *textMap = TRACKED_NEW plDynamicTextMap();
fKeyGen->CreateKey( textMap );
// Create the material
hsGMaterial *material = TRACKED_NEW hsGMaterial;
fKeyGen->CreateKey( material );
// Create the layer and attach
plLayer *lay = material->MakeBaseLayer();
white.Set( 1.f,1.f,1.f,1.f );
black.Set( 0.f,0.f,0.f,1.f );
lay->SetRuntimeColor( black );
lay->SetPreshadeColor( black );
lay->SetAmbientColor( white );
lay->SetClampFlags( hsGMatState::kClampTexture );
// Do sendRef here, since we're going to need it set pretty darned quick
hsgResMgr::ResMgr()->SendRef( textMap->GetKey(), TRACKED_NEW plLayRefMsg( lay->GetKey(), plRefMsg::kOnCreate, 0, plLayRefMsg::kTexture ), plRefFlags::kActiveRef );
return material;
}
//// Build ///////////////////////////////////////////////////////////////////
// Constructs a shiny new pop-up menu at runtime, complete with trimmings
#include "../plJPEG/plJPEG.h"
pfGUIPopUpMenu *pfGUIPopUpMenu::Build( const char *name, pfGUIDialogMod *parent, hsScalar x, hsScalar y, const plLocation &destLoc )
{
float fovX, fovY;
// Create the menu and give it a key gen
pfGUIPopUpMenu *menu = TRACKED_NEW pfGUIPopUpMenu();
menu->fKeyGen = TRACKED_NEW pfPopUpKeyGenerator( name, destLoc );
menu->fKeyGen->CreateKey( menu );
menu->fOriginX = x;
menu->fOriginY = y;
// By default, share the same skin as the parent
if( parent != nil && ( (pfGUIPopUpMenu *)parent )->fSkin != nil )
{
menu->fWaitingForSkin = true;
hsgResMgr::ResMgr()->SendRef( ( (pfGUIPopUpMenu *)parent )->fSkin->GetKey(), TRACKED_NEW plGenRefMsg( menu->GetKey(), plRefMsg::kOnCreate, -1, pfGUIPopUpMenu::kRefSkin ), plRefFlags::kActiveRef );
}
// HACK for now: create us a temp skin to use
/* static pfGUISkin *skin = nil;
if( skin == nil )
{
plLocation loc;
loc.Set( 0x1425 );
plKey skinKey = hsgResMgr::ResMgr()->FindKey( plUoid( loc, pfGUISkin::Index(), "GUISkin01_GUISkin" ) );
menu->fWaitingForSkin = true;
hsgResMgr::ResMgr()->AddViaNotify( skinKey, TRACKED_NEW plGenRefMsg( menu->GetKey(), plRefMsg::kOnCreate, -1, pfGUIPopUpMenu::kRefSkin ), plRefFlags::kActiveRef );
}
*/
// Create the rendermod
plPostEffectMod *renderMod = TRACKED_NEW plPostEffectMod;
menu->fKeyGen->CreateKey( renderMod );
renderMod->SetHither( 0.5f );
renderMod->SetYon( 200.f );
float scrnWidth = 20.f;
// fovX should be such that scrnWidth is the projected width at z=100
fovX = atan( scrnWidth / ( 2.f * 100.f ) ) * 2.f;
fovY = fovX;// * 3.f / 4.f;
renderMod->SetFovX( fovX * 180.f / hsScalarPI );
renderMod->SetFovY( fovY * 180.f / hsScalarPI );
// Create the sceneNode to go with it
menu->fParentNode= TRACKED_NEW plSceneNode;
menu->fKeyGen->CreateKey( menu->fParentNode );
// menu->fParentNode->GetKey()->RefObject();
hsgResMgr::ResMgr()->SendRef( menu->fParentNode->GetKey(), TRACKED_NEW plGenRefMsg( menu->GetKey(), plRefMsg::kOnCreate, 0, kRefParentNode ), plRefFlags::kActiveRef );
hsgResMgr::ResMgr()->AddViaNotify( menu->fParentNode->GetKey(), TRACKED_NEW plGenRefMsg( renderMod->GetKey(), plRefMsg::kOnCreate, 0, plPostEffectMod::kNodeRef ), plRefFlags::kPassiveRef );
menu->SetRenderMod( renderMod );
menu->SetName( name );
// Create the dummy scene object to hold the menu
plSceneObject *newObj = TRACKED_NEW plSceneObject;
menu->fKeyGen->CreateKey( newObj );
// *#&$(*@&#$ need a coordIface...
plCoordinateInterface *newCI = TRACKED_NEW plCoordinateInterface;
menu->fKeyGen->CreateKey( newCI );
hsMatrix44 l2w, w2l;
l2w.Reset();
l2w.GetInverse( &w2l );
// Using SendRef here because AddViaNotify will queue the messages up, which doesn't do us any good
// if we need these refs right away
hsgResMgr::ResMgr()->SendRef( newCI->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kInterface ), plRefFlags::kActiveRef );
hsgResMgr::ResMgr()->SendRef( renderMod->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kModifier ), plRefFlags::kActiveRef );
newObj->SetSceneNode( menu->fParentNode->GetKey() );
newObj->SetTransform( l2w, w2l );
hsgResMgr::ResMgr()->SendRef( menu->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, 0, plObjRefMsg::kModifier ), plRefFlags::kActiveRef );
// Add the menu to the GUI mgr
plGenRefMsg *refMsg = TRACKED_NEW plGenRefMsg( pfGameGUIMgr::GetInstance()->GetKey(),
plRefMsg::kOnCreate, 0, pfGameGUIMgr::kDlgModRef );
hsgResMgr::ResMgr()->AddViaNotify( menu->GetKey(), refMsg, plRefFlags::kActiveRef );
menu->ISeekToOrigin();
return menu;
}
//// SetSkin /////////////////////////////////////////////////////////////////
void pfGUIPopUpMenu::SetSkin( pfGUISkin *skin )
{
// Just a function wrapper for SendRef
if( fSkin != nil )
GetKey()->Release( fSkin->GetKey() );
if( skin != nil )
{
hsgResMgr::ResMgr()->SendRef( skin->GetKey(), TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefSkin ), plRefFlags::kActiveRef );
fWaitingForSkin = true;
}
else
fWaitingForSkin = false;
}
//////////////////////////////////////////////////////////////////////////////
//// pfGUISkin Implementation ////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
pfGUISkin::pfGUISkin()
{
fTexture = nil;
memset( fElements, 0, sizeof( pfSRect ) * kNumElements );
}
pfGUISkin::pfGUISkin( plMipmap *texture )
{
fTexture = texture;
if( fTexture != nil )
{
hsAssert( fTexture->GetKey() != nil, "Creating a GUI skin via a mipmap with no key!" );
fTexture->GetKey()->RefObject();
}
memset( fElements, 0, sizeof( pfSRect ) * kNumElements );
}
pfGUISkin::~pfGUISkin()
{
SetTexture( nil );
}
void pfGUISkin::SetTexture( plMipmap *tex )
{
if( fTexture != nil && fTexture->GetKey() != nil )
fTexture->GetKey()->UnRefObject();
fTexture = tex;
if( fTexture != nil )
{
hsAssert( fTexture->GetKey() != nil, "Creating a GUI skin via a mipmap with no key!" );
fTexture->GetKey()->RefObject();
}
}
void pfGUISkin::SetElement( UInt32 idx, UInt16 x, UInt16 y, UInt16 w, UInt16 h )
{
fElements[ idx ].fX = x;
fElements[ idx ].fY = y;
fElements[ idx ].fWidth = w;
fElements[ idx ].fHeight = h;
}
void pfGUISkin::Read( hsStream *s, hsResMgr *mgr )
{
hsKeyedObject::Read( s, mgr );
s->ReadSwap( &fItemMargin );
s->ReadSwap( &fBorderMargin );
UInt32 i, count;
s->ReadSwap( &count );
for( i = 0; i < count; i++ )
fElements[ i ].Read( s );
for( ; i < kNumElements; i++ )
fElements[ i ].Empty();
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefMipmap ), plRefFlags::kActiveRef );
}
void pfGUISkin::Write( hsStream *s, hsResMgr *mgr )
{
hsKeyedObject::Write( s, mgr );
s->WriteSwap( fItemMargin );
s->WriteSwap( fBorderMargin );
UInt32 i = kNumElements;
s->WriteSwap( i );
for( i = 0; i < kNumElements; i++ )
fElements[ i ].Write( s );
mgr->WriteKey( s, fTexture );
}
hsBool pfGUISkin::MsgReceive( plMessage *msg )
{
plGenRefMsg *ref = plGenRefMsg::ConvertNoRef( msg );
if( ref != nil )
{
if( ref->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
fTexture = plMipmap::ConvertNoRef( ref->GetRef() );
else
fTexture = nil;
return true;
}
return hsKeyedObject::MsgReceive( msg );
}
void pfGUISkin::pfSRect::Read( hsStream *s )
{
s->ReadSwap( &fX );
s->ReadSwap( &fY );
s->ReadSwap( &fWidth );
s->ReadSwap( &fHeight );
}
void pfGUISkin::pfSRect::Write( hsStream *s )
{
s->WriteSwap( fX );
s->WriteSwap( fY );
s->WriteSwap( fWidth );
s->WriteSwap( fHeight );
}

View File

@ -0,0 +1,225 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIPopUpMenu Header //
// //
// Pop-up menus are really just dialogs that know how to create themselves //
// and create buttons on themselves to simulate a menu (after all, that's //
// all a menu really is anyway). //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIPopUpMenu_h
#define _pfGUIPopUpMenu_h
#include "pfGUIDialogMod.h"
#include "hsBounds.h"
class plMessage;
class pfGUIButtonMod;
class pfPopUpKeyGenerator;
class pfGUICtrlProcObject;
class hsGMaterial;
class plSceneNode;
class pfGUIMenuItemProc;
class pfGUISkin;
class pfGUIPopUpMenu : public pfGUIDialogMod
{
public:
enum Alignment
{
kAlignUpLeft,
kAlignUpRight,
kAlignDownLeft,
kAlignDownRight // Default
};
protected:
friend class pfGUIMenuItemProc;
pfGUIDialogMod *fParent; // Pop-up menus also have a sense of who owns them
plSceneNode *fParentNode;
pfPopUpKeyGenerator *fKeyGen; // Generates keys for our dynamic objects
class pfMenuItem
{
// Simple wrapper class that tells us how to build our menu
public:
std::wstring fName;
pfGUICtrlProcObject *fHandler;
pfGUIPopUpMenu *fSubMenu;
float fYOffsetToNext; // Filled in by IBuildMenu()
pfMenuItem& operator=(const int zero) { fName = L""; fHandler = nil; fSubMenu = nil; fYOffsetToNext = 0; return *this; }
};
// Array of info to rebuild our menu from. Note that this is ONLY used when rebuilding
hsBool fNeedsRebuilding, fWaitingForSkin;
hsScalar fOriginX, fOriginY;
UInt16 fMargin;
hsTArray<pfMenuItem> fMenuItems;
Int32 fSubMenuOpen;
pfGUISkin *fSkin;
plSceneObject *fOriginAnchor;
pfGUIDialogMod *fOriginContext;
Alignment fAlignment;
hsBool IBuildMenu( void );
void ITearDownMenu( void );
hsGMaterial *ICreateDynMaterial( void );
void IHandleMenuSomething( UInt32 idx, pfGUIControlMod *ctrl, Int32 extended = -1 );
void ISeekToOrigin( void );
public:
pfGUIPopUpMenu();
virtual ~pfGUIPopUpMenu();
CLASSNAME_REGISTER( pfGUIPopUpMenu );
GETINTERFACE_ANY( pfGUIPopUpMenu, pfGUIDialogMod );
enum MenuFlags
{
kStayOpenAfterClick = kDerivedFlagsStart,
kModalOutsideMenus,
kOpenSubMenusOnHover,
kScaleWithResolution
};
enum Refs
{
kRefSkin = kRefDerviedStart,
kRefSubMenu,
kRefOriginAnchor,
kRefOriginContext,
kRefParentNode
};
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
virtual void SetEnabled( hsBool e );
virtual hsBool HandleMouseEvent( pfGameGUIMgr::EventType event, hsScalar mouseX, hsScalar mouseY, UInt8 modifiers );
void Show( hsScalar x, hsScalar y );
void SetOriginAnchor( plSceneObject *anchor, pfGUIDialogMod *context );
void SetAlignment( Alignment a ) { fAlignment = a; }
void ClearItems( void );
void AddItem( const char *name, pfGUICtrlProcObject *handler, pfGUIPopUpMenu *subMenu = nil );
void AddItem( const wchar_t *name, pfGUICtrlProcObject *handler, pfGUIPopUpMenu *subMenu = nil );
void SetSkin( pfGUISkin *skin );
static pfGUIPopUpMenu *Build( const char *name, pfGUIDialogMod *parent, hsScalar x, hsScalar y, const plLocation &destLoc = plLocation::kGlobalFixedLoc );
};
// Skin definition. Here for now 'cause only the menus use it, but might move it later
class plMipmap;
class pfGUISkin : public hsKeyedObject
{
public:
enum Elements
{
kUpLeftCorner = 0,
kTopSpan,
kUpRightCorner,
kRightSpan,
kLowerRightCorner,
kBottomSpan,
kLowerLeftCorner,
kLeftSpan,
kMiddleFill,
kSelectedFill,
kSubMenuArrow,
kSelectedSubMenuArrow,
kTreeButtonClosed,
kTreeButtonOpen,
kNumElements
};
class pfSRect
{
public:
UInt16 fX, fY, fWidth, fHeight;
void Empty( void ) { fX = fY = fWidth = fHeight = 0; }
void Read( hsStream *s );
void Write( hsStream *s );
};
protected:
plMipmap *fTexture;
pfSRect fElements[ kNumElements ];
UInt16 fItemMargin, fBorderMargin;
public:
pfGUISkin();
pfGUISkin( plMipmap *texture );
virtual ~pfGUISkin();
CLASSNAME_REGISTER( pfGUISkin );
GETINTERFACE_ANY( pfGUISkin, hsKeyedObject );
enum Refs
{
kRefMipmap
};
virtual void Read( hsStream *s, hsResMgr *mgr );
virtual void Write( hsStream *s, hsResMgr *mgr );
virtual hsBool MsgReceive( plMessage *msg );
plMipmap *GetTexture( void ) const { return fTexture; }
void SetTexture( plMipmap *tex );
const pfSRect &GetElement( UInt32 idx ) const { return fElements[ idx ]; }
hsBool IsElementSet( UInt32 idx ) const { return ( fElements[ idx ].fWidth > 0 && fElements[ idx ].fHeight > 0 ); }
void SetElement( UInt32 idx, UInt16 x, UInt16 y, UInt16 w, UInt16 h );
void SetMargins( UInt16 item, UInt16 border ) { fItemMargin = item; fBorderMargin = border; }
UInt16 GetItemMargin( void ) const { return fItemMargin; }
UInt16 GetBorderMargin( void ) const { return fBorderMargin; }
};
#endif // _pfGUIPopUpMenu_h

View File

@ -0,0 +1,255 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIProgressCtrl Definition //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUIProgressCtrl.h"
#include "pfGameGUIMgr.h"
#include "pfGUIDialogMod.h"
#include "../plInputCore/plInputInterface.h"
#include "../pnMessage/plRefMsg.h"
#include "../pfMessage/pfGameGUIMsg.h"
#include "../plMessage/plAnimCmdMsg.h"
#include "../plMessage/plTimerCallbackMsg.h"
// #include "../plAvatar/plAGModifier.h"
#include "../plAvatar/plAGMasterMod.h"
#include "../plAvatar/plAGAnimInstance.h"
#include "../plSurface/plLayerAnimation.h"
#include "../pnSceneObject/plSceneObject.h"
#include "../pnSceneObject/plCoordinateInterface.h"
#include "../pnTimer/plTimerCallbackManager.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIProgressCtrl::pfGUIProgressCtrl() : fStopSoundTimer(99)
{
fAnimTimesCalced = false;
fAnimName = nil;
fPlaySound = true;
}
pfGUIProgressCtrl::~pfGUIProgressCtrl()
{
delete [] fAnimName;
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool pfGUIProgressCtrl::IEval( double secs, hsScalar del, UInt32 dirty )
{
return pfGUIValueCtrl::IEval( secs, del, dirty );
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGUIProgressCtrl::MsgReceive( plMessage *msg )
{
plTimerCallbackMsg *timerMsg = plTimerCallbackMsg::ConvertNoRef(msg);
if (timerMsg)
{
if (timerMsg->fID == fStopSoundTimer)
{
// we've finished animating, stop the sound that's playing
StopSound(kAnimateSound);
}
}
return pfGUIValueCtrl::MsgReceive( msg );
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUIProgressCtrl::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIValueCtrl::Read(s, mgr);
fAnimationKeys.Reset();
UInt32 i, count = s->ReadSwap32();
for( i = 0; i < count; i++ )
fAnimationKeys.Append( mgr->ReadKey( s ) );
fAnimName = s->ReadSafeString();
fAnimTimesCalced = false;
}
void pfGUIProgressCtrl::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIValueCtrl::Write( s, mgr );
UInt32 i, count = fAnimationKeys.GetCount();
s->WriteSwap32( count );
for( i = 0; i < count; i++ )
mgr->WriteKey( s, fAnimationKeys[ i ] );
s->WriteSafeString( fAnimName );
}
//// UpdateBounds ////////////////////////////////////////////////////////////
void pfGUIProgressCtrl::UpdateBounds( hsMatrix44 *invXformMatrix, hsBool force )
{
pfGUIValueCtrl::UpdateBounds( invXformMatrix, force );
if( fAnimationKeys.GetCount() > 0 )
fBoundsValid = false;
}
//// SetAnimationKeys ////////////////////////////////////////////////////////
void pfGUIProgressCtrl::SetAnimationKeys( hsTArray<plKey> &keys, const char *name )
{
fAnimationKeys = keys;
delete [] fAnimName;
if( name != nil )
{
fAnimName = TRACKED_NEW char[ strlen( name ) + 1 ];
strcpy( fAnimName, name );
}
else
fAnimName = nil;
}
//// ICalcAnimTimes //////////////////////////////////////////////////////////
// Loops through and computes the max begin and end for our animations. If
// none of them are loaded and we're not already calced, returns false.
hsBool pfGUIProgressCtrl::ICalcAnimTimes( void )
{
if( fAnimTimesCalced )
return true;
hsScalar tBegin = 1e30, tEnd = -1e30;
bool foundOne = false;
for( int i = 0; i < fAnimationKeys.GetCount(); i++ )
{
// Handle AGMasterMods
plAGMasterMod *mod = plAGMasterMod::ConvertNoRef( fAnimationKeys[ i ]->ObjectIsLoaded() );
if( mod != nil )
{
for( int j = 0; j < mod->GetNumAnimations(); j++ )
{
hsScalar begin = mod->GetAnimInstance( j )->GetTimeConvert()->GetBegin();
hsScalar end = mod->GetAnimInstance( j )->GetTimeConvert()->GetEnd();
if( begin < tBegin )
tBegin = begin;
if( end > tEnd )
tEnd = end;
}
foundOne = true;
}
// Handle layer animations
plLayerAnimation *layer = plLayerAnimation::ConvertNoRef( fAnimationKeys[ i ]->ObjectIsLoaded() );
if( layer != nil )
{
hsScalar begin = layer->GetTimeConvert().GetBegin();
hsScalar end = layer->GetTimeConvert().GetEnd();
if( begin < tBegin )
tBegin = begin;
if( end > tEnd )
tEnd = end;
foundOne = true;
}
}
if( foundOne )
{
fAnimBegin = tBegin;
fAnimEnd = tEnd;
fAnimTimesCalced = true;
}
return fAnimTimesCalced;
}
//// SetCurrValue ////////////////////////////////////////////////////////////
void pfGUIProgressCtrl::SetCurrValue( hsScalar v )
{
int old = (int)fValue;
pfGUIValueCtrl::SetCurrValue( v );
// if( old == (int)fValue )
// return;
if( fAnimationKeys.GetCount() > 0 )
{
ICalcAnimTimes();
hsScalar tLength = fAnimEnd - fAnimBegin;
hsScalar newTime;
if( HasFlag( kReverseValues ) )
newTime = ( ( fMax - fValue ) / ( fMax - fMin ) ) * tLength + fAnimBegin;
else
newTime = ( ( fValue - fMin ) / ( fMax - fMin ) ) * tLength + fAnimBegin;
plAnimCmdMsg *msg = TRACKED_NEW plAnimCmdMsg();
msg->SetCmd( plAnimCmdMsg::kGoToTime );
msg->SetAnimName( fAnimName );
msg->fTime = newTime;
msg->AddReceivers( fAnimationKeys );
plgDispatch::MsgSend( msg );
}
}
void pfGUIProgressCtrl::AnimateToPercentage( hsScalar percent )
{
// percent should be a value in range 0.0 to 1.0
if (percent >= 0.0f && percent <= 1.0f)
{
pfGUIValueCtrl::SetCurrValue( (fMax - fMin) * percent + fMin );
if( fAnimationKeys.GetCount() > 0 )
{
plAnimCmdMsg *msg = TRACKED_NEW plAnimCmdMsg();
msg->SetCmd( plAnimCmdMsg::kPlayToPercentage );
msg->SetAnimName( fAnimName );
msg->fTime = percent;
msg->AddReceivers( fAnimationKeys );
plgDispatch::MsgSend( msg );
if (fPlaySound)
{
// play the sound, looping
PlaySound(kAnimateSound, true);
// setup a timer to call back when we finish animating
hsScalar elapsedTime = (fAnimEnd - fAnimBegin) * percent;
plTimerCallbackMsg *timerMsg = TRACKED_NEW plTimerCallbackMsg(GetKey(), fStopSoundTimer);
plgTimerCallbackMgr::NewTimer(elapsedTime, timerMsg);
}
}
}
}

View File

@ -0,0 +1,93 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIProgressCtrl Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIProgressCtrl_h
#define _pfGUIProgressCtrl_h
#include "pfGUIValueCtrl.h"
class plMessage;
class plAGMasterMod;
class pfGUIProgressCtrl : public pfGUIValueCtrl
{
protected:
hsTArray<plKey> fAnimationKeys;
char *fAnimName;
// Computed once, once an anim is loaded that we can compute this with
hsScalar fAnimBegin, fAnimEnd;
hsBool fAnimTimesCalced;
hsBool fPlaySound;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
hsBool ICalcAnimTimes( void );
const UInt32 fStopSoundTimer;
public:
pfGUIProgressCtrl();
virtual ~pfGUIProgressCtrl();
CLASSNAME_REGISTER( pfGUIProgressCtrl );
GETINTERFACE_ANY( pfGUIProgressCtrl, pfGUIValueCtrl );
enum OurFlags
{
kReverseValues = kDerivedFlagsStart
};
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
virtual void UpdateBounds( hsMatrix44 *invXformMatrix = nil, hsBool force = false );
virtual void SetCurrValue( hsScalar v );
virtual void AnimateToPercentage( hsScalar percent );
enum SoundEvents
{
kAnimateSound
};
void DontPlaySounds() { fPlaySound = false; }
// Export only
void SetAnimationKeys( hsTArray<plKey> &keys, const char *name );
};
#endif // _pfGUIProgressCtrl_h

View File

@ -0,0 +1,257 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIRadioGroupCtrl Definition //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUIRadioGroupCtrl.h"
#include "pfGameGUIMgr.h"
#include "pfGUICheckBoxCtrl.h"
#include "pfGUIControlHandlers.h"
#include "../pnMessage/plRefMsg.h"
#include "../pfMessage/pfGameGUIMsg.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Wee Little Control Proc for our buttons /////////////////////////////////
class pfGroupProc : public pfGUICtrlProcObject
{
protected:
pfGUIRadioGroupCtrl *fParent;
public:
pfGroupProc( pfGUIRadioGroupCtrl *parent )
{
fParent = parent;
}
virtual void DoSomething( pfGUIControlMod *ctrl )
{
Int32 newIdx;
// So one of our controls got clicked. That means that we change our value
// to the proper index
pfGUICheckBoxCtrl *check = pfGUICheckBoxCtrl::ConvertNoRef( ctrl );
// Are we unselecting? And do we allow this?
if( !check->IsChecked() && !fParent->HasFlag( pfGUIRadioGroupCtrl::kAllowNoSelection ) )
{
// Boo on you. Re-check
check->SetChecked( true );
return;
}
for( newIdx = 0; newIdx < fParent->fControls.GetCount(); newIdx++ )
{
if( fParent->fControls[ newIdx ] == check )
break;
}
if( newIdx == fParent->fControls.GetCount() )
newIdx = -1;
if( newIdx != fParent->fValue )
{
if( fParent->fValue != -1 )
fParent->fControls[ fParent->fValue ]->SetChecked( false );
fParent->fValue = newIdx;
if( newIdx != -1 )
fParent->fControls[ newIdx ]->SetChecked( true );
}
else
{
if( !check->IsChecked() && fParent->HasFlag( pfGUIRadioGroupCtrl::kAllowNoSelection ) )
{
// nobody is checked!
fParent->fValue = -1;
}
}
fParent->DoSomething();
}
};
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIRadioGroupCtrl::pfGUIRadioGroupCtrl()
{
fButtonProc = TRACKED_NEW pfGroupProc( this );
fButtonProc->IncRef();
SetFlag( kIntangible );
}
pfGUIRadioGroupCtrl::~pfGUIRadioGroupCtrl()
{
if( fButtonProc->DecRef() )
delete fButtonProc;
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool pfGUIRadioGroupCtrl::IEval( double secs, hsScalar del, UInt32 dirty )
{
return pfGUIControlMod::IEval( secs, del, dirty );
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGUIRadioGroupCtrl::MsgReceive( plMessage *msg )
{
plGenRefMsg *refMsg = plGenRefMsg::ConvertNoRef( msg );
if( refMsg != nil )
{
if( refMsg->fType == kRefControl )
{
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
{
fControls[ refMsg->fWhich ] = pfGUICheckBoxCtrl::ConvertNoRef( refMsg->GetRef() );
fControls[ refMsg->fWhich ]->SetHandler( fButtonProc );
if( fValue == refMsg->fWhich )
fControls[ refMsg->fWhich ]->SetChecked( true );
}
else
{
fControls[ refMsg->fWhich ] = nil;
}
return true;
}
}
return pfGUIControlMod::MsgReceive( msg );
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUIRadioGroupCtrl::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Read(s, mgr);
UInt32 i, count = s->ReadSwap32();
fControls.SetCountAndZero( count );
for( i = 0; i < count; i++ )
{
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, i, kRefControl ), plRefFlags::kActiveRef );
}
fValue = fDefaultValue = s->ReadSwap16();
if( fValue != -1 && fControls[ fValue ] != nil )
fControls[ fValue ]->SetChecked( true );
}
void pfGUIRadioGroupCtrl::Write( hsStream *s, hsResMgr *mgr )
{
UInt32 i;
pfGUIControlMod::Write( s, mgr );
s->WriteSwap32( fControls.GetCount() );
for( i = 0; i < fControls.GetCount(); i++ )
mgr->WriteKey( s, fControls[ i ]->GetKey() );
s->WriteSwap16( (UInt16)fDefaultValue );
}
//// SetValue ////////////////////////////////////////////////////////////////
void pfGUIRadioGroupCtrl::SetValue( Int32 value )
{
if( value != fValue && ( value != -1 || HasFlag( kAllowNoSelection ) ) )
{
if( fValue != -1 )
fControls[ fValue ]->SetChecked( false );
fValue = value;
if( value != -1 )
fControls[ value ]->SetChecked( true );
DoSomething();
}
}
///// Setting to be trickled down to the underlings
void pfGUIRadioGroupCtrl::SetEnabled( hsBool e )
{
int i;
for( i = 0; i < fControls.GetCount(); i++ )
fControls[ i ]->SetEnabled(e);
}
void pfGUIRadioGroupCtrl::SetInteresting( hsBool e )
{
int i;
for( i = 0; i < fControls.GetCount(); i++ )
fControls[ i ]->SetInteresting(e);
}
void pfGUIRadioGroupCtrl::SetVisible( hsBool vis )
{
int i;
for( i = 0; i < fControls.GetCount(); i++ )
fControls[ i ]->SetVisible(vis);
}
void pfGUIRadioGroupCtrl::SetControlsFlag( int flag )
{
int i;
for( i = 0; i < fControls.GetCount(); i++ )
fControls[ i ]->SetFlag(flag);
}
void pfGUIRadioGroupCtrl::ClearControlsFlag( int flag )
{
int i;
for( i = 0; i < fControls.GetCount(); i++ )
fControls[ i ]->ClearFlag(flag);
}
//// Export Functions ////////////////////////////////////////////////////////
void pfGUIRadioGroupCtrl::ClearControlList( void )
{
fControls.Reset();
fValue = -1;
}
void pfGUIRadioGroupCtrl::AddControl( pfGUICheckBoxCtrl *ctrl )
{
fControls.Append( ctrl );
}

View File

@ -0,0 +1,94 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIRadioGroupCtrl Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIRadioGroupCtrl_h
#define _pfGUIRadioGroupCtrl_h
#include "pfGUIValueCtrl.h"
#include "hsTemplates.h"
class plMessage;
class pfGUICheckBoxCtrl;
class pfGroupProc;
class pfGUIRadioGroupCtrl : public pfGUIControlMod
{
friend class pfGroupProc;
protected:
enum
{
kRefControl = kRefDerivedStart
};
hsTArray<pfGUICheckBoxCtrl *> fControls;
pfGroupProc *fButtonProc;
Int32 fValue, fDefaultValue;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
public:
pfGUIRadioGroupCtrl();
virtual ~pfGUIRadioGroupCtrl();
CLASSNAME_REGISTER( pfGUIRadioGroupCtrl );
GETINTERFACE_ANY( pfGUIRadioGroupCtrl, pfGUIControlMod );
enum OurFlags
{
kAllowNoSelection = kDerivedFlagsStart
};
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
Int32 GetValue( void ) { return fValue; }
void SetValue( Int32 value );
virtual void SetEnabled( hsBool e );
virtual void SetInteresting( hsBool e );
virtual void SetVisible( hsBool vis );
virtual void SetControlsFlag( int flag );
virtual void ClearControlsFlag( int flag );
/// Export ONLY
void ClearControlList( void );
void AddControl( pfGUICheckBoxCtrl *ctrl );
void SetDefaultValue( Int32 value ) { fDefaultValue = value; }
};
#endif // _pfGUIRadioGroupCtrl_h

View File

@ -0,0 +1,82 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUITagDefs.cpp //
// List of Tag IDs for the GameGUIMgr //
// //
//////////////////////////////////////////////////////////////////////////////
#include "pfGameGUIMgr.h"
#include "pfGUITagDefs.h"
//// Tag List ////////////////////////////////////////////////////////////////
// Here's the actual list of tags. It's basically a list of konstants, but
// they get translated into two things:
// 1. An enum, to send as a UInt32 to the GetDialogFromTag() and
// GetControlFromTag() functions.
// 2. A string, which gets put in a dropdown box in the appropriate
// MAX component, which sets the given control's tag ID to the
// right konstant.
// Step 1: add your konstant to the end of the .h file list
// Step 2: Add the string here
pfGUITag gGUITags[] = {
{ kKIMainDialog, "KI Main Dialog" },
{ kKITestEditBox, "KI Test Control" },
{ kKIEntryDlg, "KI Entry Dlg" },
{ kKICloseButton, "KI Close Dlg Button" },
{ kKITestControl2, "KI Test Control 2" },
{ kKIAddButton, "KI Add Button" },
{ kKIEditButton, "KI Edit Button" },
{ kKIRemoveButton, "KI Remove Button" },
{ kKIYesNoDlg, "KI Yes/No Dialog" },
{ kKIYesBtn, "KI Yes Button" },
{ kKINoBtn, "KI No Button" },
{ kKIStaticText, "KI Static Text" },
{ kKITestControl3, "KI Test Control 3" },
{ kKIMiniDialog, "KI Mini Dialog" },
{ kPlayerBook, "PB Dialog" },
{ kPBLinkToBtn, "PB Link To Button" },
{ kPBSaveLinkBtn, "PB Save Link Button" },
{ kPBSaveSlotRadio, "PB Save Slot Radio" },
{ kPBSaveSlotPrev1, "PB Save Slot Preview 1" },
{ kPBSaveSlotPrev2, "PB Save Slot Preview 2" },
{ kPBSaveSlotPrev3, "PB Save Slot Preview 3" },
{ kPBSaveSlotPrev4, "PB Save Slot Preview 4" },
{ kPBSaveSlotPrev5, "PB Save Slot Preview 5" },
{ kPBSaveSlotPrev6, "PB Save Slot Preview 6" },
{ kKICurrPlayerText, "KI Current Player Label" },
{ kKIPlayerList, "KI Mini Friends List" },
{ kKIChatModeBtn, "KI Toggle Chat Mode Btn" },
{ kBlackBarDlg, "Black Bar Dialog" },
{ kBlackBarKIButtons, "Black Bar KI Radio Group" },
{ kKILogoutButton, "KI Logout Button" },
{ 0, "" } // Ending tag, MUST ALWAYS BE HERE
};

View File

@ -0,0 +1,88 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUITagDefs.cpp //
// List of Tag IDs for the GameGUIMgr //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUITagDefs_h
#define _pfGUITagDefs_h
#include "pfGameGUIMgr.h"
//// Tag List ////////////////////////////////////////////////////////////////
// Here's the actual list of tags. It's basically a list of konstants, but
// they get translated into two things:
// 1. An enum, to send as a UInt32 to the GetDialogFromTag() and
// GetControlFromTag() functions.
// 2. A string, which gets put in a dropdown box in the appropriate
// MAX component, which sets the given control's tag ID to the
// right konstant.
// Step 1: Add your konstant to the end of this list
enum
{
kKIMainDialog = 1,
kKITestEditBox,
kKIEntryDlg,
kKICloseButton,
kKITestControl2,
kKIAddButton,
kKIEditButton,
kKIRemoveButton,
kKIYesNoDlg,
kKIYesBtn,
kKINoBtn,
kKIStaticText,
kKITestControl3,
kKIMiniDialog,
kPlayerBook,
kPBLinkToBtn,
kPBSaveLinkBtn,
kPBSaveSlotRadio,
kPBSaveSlotPrev1,
kPBSaveSlotPrev2,
kPBSaveSlotPrev3,
kPBSaveSlotPrev4,
kPBSaveSlotPrev5,
kPBSaveSlotPrev6,
kKICurrPlayerText = 30,
kKIPlayerList = 31,
kKIChatModeBtn = 32,
kBlackBarDlg = 33,
kBlackBarKIButtons = 34,
kKILogoutButton = 35,
};
// Step 2: Add the string to the .cpp file
#endif

View File

@ -0,0 +1,246 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUITextBoxMod Definition //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "hsStlUtils.h"
#include "pfGUITextBoxMod.h"
#include "pfGameGUIMgr.h"
#include "../pnMessage/plRefMsg.h"
#include "../pfMessage/pfGameGUIMsg.h"
#include "../plMessage/plAnimCmdMsg.h"
#include "../plAvatar/plAGModifier.h"
#include "../plGImage/plDynamicTextMap.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
#include "../plResMgr/plLocalization.h"
#include "../pfLocalizationMgr/pfLocalizationMgr.h"
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUITextBoxMod::pfGUITextBoxMod()
{
// SetFlag( kWantsInterest );
SetFlag( kIntangible );
fText = nil;
fUseLocalizationPath = false;
}
pfGUITextBoxMod::~pfGUITextBoxMod()
{
delete [] fText;
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool pfGUITextBoxMod::IEval( double secs, hsScalar del, UInt32 dirty )
{
return pfGUIControlMod::IEval( secs, del, dirty );
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGUITextBoxMod::MsgReceive( plMessage *msg )
{
return pfGUIControlMod::MsgReceive( msg );
}
//// IPostSetUpDynTextMap ////////////////////////////////////////////////////
void pfGUITextBoxMod::IPostSetUpDynTextMap( void )
{
pfGUIColorScheme *scheme = GetColorScheme();
fDynTextMap->SetFont( scheme->fFontFace, scheme->fFontSize, scheme->fFontFlags,
HasFlag( kXparentBgnd ) ? false : true );
fDynTextMap->SetTextColor( scheme->fForeColor,
( HasFlag( kXparentBgnd ) && scheme->fBackColor.a == 0.f ) ? true : false );
}
//// IUpdate /////////////////////////////////////////////////////////////////
void pfGUITextBoxMod::IUpdate( void )
{
if( fDynTextMap == nil || !fDynTextMap->IsValid() )
return;
if( HasFlag( kCenterJustify ) )
fDynTextMap->SetJustify( plDynamicTextMap::kCenter );
else if( HasFlag( kRightJustify ) )
fDynTextMap->SetJustify( plDynamicTextMap::kRightJustify );
else
fDynTextMap->SetJustify( plDynamicTextMap::kLeftJustify );
fDynTextMap->ClearToColor( GetColorScheme()->fBackColor );
std::wstring drawStr;
if (fUseLocalizationPath && !fLocalizationPath.empty() && pfLocalizationMgr::InstanceValid())
drawStr = pfLocalizationMgr::Instance().GetString(fLocalizationPath.c_str());
else
{
if( fText != nil )
{
int lang = plLocalization::GetLanguage();
std::vector<std::wstring> translations = plLocalization::StringToLocal(fText);
if (translations[lang] == L"") // if the translations doesn't exist, draw English
drawStr = translations[0].c_str();
else
drawStr = translations[lang].c_str();
}
}
if (!drawStr.empty())
fDynTextMap->DrawWrappedString( 4, 4, drawStr.c_str(), fDynTextMap->GetVisibleWidth() - 8, fDynTextMap->GetVisibleHeight() - 8 );
fDynTextMap->FlushToHost();
}
void pfGUITextBoxMod::PurgeDynaTextMapImage()
{
if ( fDynTextMap != nil )
fDynTextMap->PurgeImage();
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUITextBoxMod::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Read(s, mgr);
UInt32 len = s->ReadSwap32();
if( len > 0 )
{
char *text = TRACKED_NEW char[ len + 1 ];
s->Read( len, text );
text[ len ] = 0;
fText = hsStringToWString(text);
delete [] text;
}
else
fText = nil;
fUseLocalizationPath = (s->ReadBool() != 0);
if (fUseLocalizationPath)
{
wchar_t* temp = s->ReadSafeWString();
fLocalizationPath = temp;
delete [] temp;
}
}
void pfGUITextBoxMod::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Write( s, mgr );
if( fText == nil )
s->WriteSwap32( 0 );
else
{
char *text = hsWStringToString(fText);
s->WriteSwap32( strlen( text ) );
s->Write( strlen( text ), text );
delete [] text;
}
// Make sure we only write out to use localization path if the box is checked
// and the path isn't empty
bool useLoc = fUseLocalizationPath && !fLocalizationPath.empty();
s->WriteBool(useLoc);
if (useLoc)
s->WriteSafeWString(fLocalizationPath.c_str());
}
//// HandleMouseDown/Up //////////////////////////////////////////////////////
void pfGUITextBoxMod::HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers )
{
}
void pfGUITextBoxMod::HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers )
{
}
void pfGUITextBoxMod::HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers )
{
}
//// SetText /////////////////////////////////////////////////////////////////
void pfGUITextBoxMod::SetText( const char *text )
{
delete [] fText;
if (text)
{
fText = hsStringToWString(text);
}
else
fText = nil;
IUpdate();
}
void pfGUITextBoxMod::SetText( const wchar_t *text )
{
delete [] fText;
if (text)
{
fText = TRACKED_NEW wchar_t[wcslen(text)+1];
wcscpy(fText,text);
}
else
fText = nil;
IUpdate();
}
void pfGUITextBoxMod::SetLocalizationPath(const wchar_t* path)
{
if (path)
fLocalizationPath = path;
}
void pfGUITextBoxMod::SetLocalizationPath(const char* path)
{
if (path)
{
wchar_t* wPath = hsStringToWString(path);
fLocalizationPath = wPath;
delete [] wPath;
}
}
void pfGUITextBoxMod::SetUseLocalizationPath(bool use)
{
fUseLocalizationPath = use;
}

View File

@ -0,0 +1,93 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUITextBoxMod Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUITextBoxMod_h
#define _pfGUITextBoxMod_h
#include "pfGUIControlMod.h"
class plMessage;
class hsGMaterial;
class plTextGenerator;
class pfGUITextBoxMod : public pfGUIControlMod
{
protected:
wchar_t *fText;
std::wstring fLocalizationPath;
bool fUseLocalizationPath;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
virtual void IUpdate( void );
virtual void IPostSetUpDynTextMap( void );
public:
pfGUITextBoxMod();
virtual ~pfGUITextBoxMod();
CLASSNAME_REGISTER( pfGUITextBoxMod );
GETINTERFACE_ANY( pfGUITextBoxMod, pfGUIControlMod );
enum OurFlags
{
kCenterJustify = kDerivedFlagsStart,
kRightJustify
};
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
virtual void HandleMouseDown( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseUp( hsPoint3 &mousePt, UInt8 modifiers );
virtual void HandleMouseDrag( hsPoint3 &mousePt, UInt8 modifiers );
virtual void PurgeDynaTextMapImage();
virtual const wchar_t* GetText() { return fText; }
// Export only
void SetText( const char *text );
void SetText( const wchar_t *text );
void SetLocalizationPath(const wchar_t* path);
void SetLocalizationPath(const char* path);
void SetUseLocalizationPath(bool use);
virtual void UpdateColorScheme() { IPostSetUpDynTextMap(); IUpdate(); }
};
#endif // _pfGUITextBoxMod_h

View File

@ -0,0 +1,225 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIUpDownPairMod Definition //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUIUpDownPairMod.h"
#include "pfGameGUIMgr.h"
#include "pfGUIButtonMod.h"
#include "pfGUIControlHandlers.h"
#include "../pnMessage/plRefMsg.h"
#include "../pfMessage/pfGameGUIMsg.h"
#include "../plMessage/plAnimCmdMsg.h"
#include "../plAvatar/plAGModifier.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Wee Little Control Proc for our buttons /////////////////////////////////
class pfUpDownBtnProc : public pfGUICtrlProcObject
{
protected:
pfGUIButtonMod *fUp, *fDown;
pfGUIUpDownPairMod *fParent;
public:
pfUpDownBtnProc( pfGUIButtonMod *up, pfGUIButtonMod *down, pfGUIUpDownPairMod *parent )
{
fUp = up;
fDown = down;
fParent = parent;
}
void SetUp( pfGUIButtonMod *up ) { fUp = up; }
void SetDown( pfGUIButtonMod *down ) { fDown = down; }
virtual void DoSomething( pfGUIControlMod *ctrl )
{
if( (pfGUIButtonMod *)ctrl == fUp )
{
fParent->fValue += fParent->fStep;
if( fParent->fValue > fParent->fMax )
fParent->fValue = fParent->fMax;
}
else
{
fParent->fValue -= fParent->fStep;
if( fParent->fValue < fParent->fMin )
fParent->fValue = fParent->fMin;
}
fParent->Update();
fParent->DoSomething();
}
};
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIUpDownPairMod::pfGUIUpDownPairMod()
{
fUpControl = nil;
fDownControl = nil;
fValue = fMin = fMax = fStep = 0.f;
fButtonProc = TRACKED_NEW pfUpDownBtnProc( nil, nil, this );
fButtonProc->IncRef();
SetFlag( kIntangible );
}
pfGUIUpDownPairMod::~pfGUIUpDownPairMod()
{
if( fButtonProc->DecRef() )
delete fButtonProc;
}
//// IEval ///////////////////////////////////////////////////////////////////
hsBool pfGUIUpDownPairMod::IEval( double secs, hsScalar del, UInt32 dirty )
{
return pfGUIValueCtrl::IEval( secs, del, dirty );
}
void pfGUIUpDownPairMod::IUpdate( void )
{
if (fEnabled)
{
if (fUpControl)
{
if ( fValue >= fMax)
fUpControl->SetVisible(false);
else
fUpControl->SetVisible(true);
}
if (fDownControl)
{
if ( fValue <= fMin )
fDownControl->SetVisible(false);
else
fDownControl->SetVisible(true);
}
}
else
{
fUpControl->SetVisible(false);
fDownControl->SetVisible(false);
}
}
void pfGUIUpDownPairMod::Update( void )
{
IUpdate();
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGUIUpDownPairMod::MsgReceive( plMessage *msg )
{
plGenRefMsg *refMsg = plGenRefMsg::ConvertNoRef( msg );
if( refMsg != nil )
{
if( refMsg->fType == kRefUpControl )
{
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
{
fUpControl = pfGUIButtonMod::ConvertNoRef( refMsg->GetRef() );
fUpControl->SetHandler( fButtonProc );
fButtonProc->SetUp( fUpControl );
}
else
{
fUpControl = nil;
fButtonProc->SetUp( nil );
}
return true;
}
else if( refMsg->fType == kRefDownControl )
{
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest | plRefMsg::kOnReplace ) )
{
fDownControl = pfGUIButtonMod::ConvertNoRef( refMsg->GetRef() );
fDownControl->SetHandler( fButtonProc );
fButtonProc->SetDown( fDownControl );
}
else
{
fDownControl = nil;
fButtonProc->SetDown( nil );
}
return true;
}
}
return pfGUIValueCtrl::MsgReceive( msg );
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUIUpDownPairMod::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIValueCtrl::Read(s, mgr);
fUpControl = nil;
fDownControl = nil;
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefUpControl ), plRefFlags::kActiveRef );
mgr->ReadKeyNotifyMe( s, TRACKED_NEW plGenRefMsg( GetKey(), plRefMsg::kOnCreate, -1, kRefDownControl ), plRefFlags::kActiveRef );
s->ReadSwap( &fMin );
s->ReadSwap( &fMax );
s->ReadSwap( &fStep );
fValue = fMin;
}
void pfGUIUpDownPairMod::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIValueCtrl::Write( s, mgr );
mgr->WriteKey( s, fUpControl->GetKey() );
mgr->WriteKey( s, fDownControl->GetKey() );
s->WriteSwap( fMin );
s->WriteSwap( fMax );
s->WriteSwap( fStep );
}
void pfGUIUpDownPairMod::SetRange( hsScalar min, hsScalar max )
{
pfGUIValueCtrl::SetRange( min, max );
IUpdate();
}
void pfGUIUpDownPairMod::SetCurrValue( hsScalar v )
{
pfGUIValueCtrl::SetCurrValue( v );
IUpdate();
}

View File

@ -0,0 +1,84 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIUpDownPairMod Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIUpDownPairMod_h
#define _pfGUIUpDownPairMod_h
#include "pfGUIValueCtrl.h"
class plMessage;
class pfGUIButtonMod;
class pfUpDownBtnProc;
class pfGUIUpDownPairMod : public pfGUIValueCtrl
{
friend class pfUpDownBtnProc;
protected:
enum
{
kRefUpControl = kRefDerivedStart,
kRefDownControl
};
pfGUIButtonMod *fUpControl, *fDownControl;
pfUpDownBtnProc *fButtonProc;
virtual hsBool IEval( double secs, hsScalar del, UInt32 dirty ); // called only by owner object's Eval()
virtual void IUpdate( void );
public:
pfGUIUpDownPairMod();
virtual ~pfGUIUpDownPairMod();
CLASSNAME_REGISTER( pfGUIUpDownPairMod );
GETINTERFACE_ANY( pfGUIUpDownPairMod, pfGUIValueCtrl );
virtual hsBool MsgReceive( plMessage* pMsg );
virtual void Update( void );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
virtual void SetRange( hsScalar min, hsScalar max );
virtual void SetCurrValue( hsScalar v );
/// Export ONLY
void SetControls( pfGUIButtonMod *up, pfGUIButtonMod *down ) { fUpControl = up; fDownControl = down; }
};
#endif // _pfGUIUpDownPairMod_h

View File

@ -0,0 +1,95 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIValueCtrl Definition //
// //
//////////////////////////////////////////////////////////////////////////////
#include "hsTypes.h"
#include "pfGUIValueCtrl.h"
#include "pfGameGUIMgr.h"
#include "plgDispatch.h"
#include "hsResMgr.h"
//// Constructor/Destructor //////////////////////////////////////////////////
pfGUIValueCtrl::pfGUIValueCtrl()
{
fValue = fMin = fMax = fStep = 0.f;
}
pfGUIValueCtrl::~pfGUIValueCtrl()
{
}
//// SetCurrValue ////////////////////////////////////////////////////////////
void pfGUIValueCtrl::SetCurrValue( hsScalar v )
{
fValue = v;
if( fValue < fMin )
fValue = fMin;
else if( fValue > fMax )
fValue = fMax;
}
//// SetRange ////////////////////////////////////////////////////////////////
void pfGUIValueCtrl::SetRange( hsScalar min, hsScalar max )
{
fMin = min;
fMax = max;
if( fValue < fMin )
SetCurrValue( fMin );
else if( fValue > fMax )
SetCurrValue( fMax );
}
//// Read/Write //////////////////////////////////////////////////////////////
void pfGUIValueCtrl::Read( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Read(s, mgr);
s->ReadSwap( &fMin );
s->ReadSwap( &fMax );
s->ReadSwap( &fStep );
fValue = fMin;
}
void pfGUIValueCtrl::Write( hsStream *s, hsResMgr *mgr )
{
pfGUIControlMod::Write( s, mgr );
s->WriteSwap( fMin );
s->WriteSwap( fMax );
s->WriteSwap( fStep );
}

View File

@ -0,0 +1,68 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGUIValueCtrl Header //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGUIValueCtrl_h
#define _pfGUIValueCtrl_h
#include "pfGUIControlMod.h"
class pfGUIValueCtrl : public pfGUIControlMod
{
protected:
hsScalar fValue, fMin, fMax, fStep;
public:
pfGUIValueCtrl();
virtual ~pfGUIValueCtrl();
CLASSNAME_REGISTER( pfGUIValueCtrl );
GETINTERFACE_ANY( pfGUIValueCtrl, pfGUIControlMod );
virtual void Read( hsStream* s, hsResMgr* mgr );
virtual void Write( hsStream* s, hsResMgr* mgr );
virtual hsScalar GetCurrValue( void ) { return fValue; }
virtual void SetCurrValue( hsScalar v );
virtual hsScalar GetMin( void ) { return fMin; }
virtual hsScalar GetMax( void ) { return fMax; }
virtual hsScalar GetStep( void ) { return fStep; }
virtual void SetRange( hsScalar min, hsScalar max );
virtual void SetStep( hsScalar step ) { fStep = step; }
};
#endif // _pfGUIValueCtrl_h

View File

@ -0,0 +1,943 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGameGUIMgr //
// //
//// History /////////////////////////////////////////////////////////////////
// //
// 11.13.2001 mcn - Created //
// //
//////////////////////////////////////////////////////////////////////////////
#include <stdlib.h>
#include "hsTimer.h"
#include "hsTypes.h"
#include "pfGameGUIMgr.h"
#include "pfGUIDialogMod.h"
#include "pfGUIDialogHandlers.h"
#include "pfGUIDialogNotifyProc.h"
#include "pfGUIControlMod.h"
#include "pfGUIPopUpMenu.h"
#include "../pfMessage/pfGameGUIMsg.h"
#include "../plMessage/plInputEventMsg.h"
#include "../plMessage/plInputIfaceMgrMsg.h"
#include "../pnMessage/plClientMsg.h"
#include "../pnNetCommon/plSynchedObject.h"
#include "../plInputCore/plInputInterface.h"
#include "../plInputCore/plInputDevice.h"
#include "../plInputCore/plInputInterfaceMgr.h"
#include "../pnInputCore/plKeyMap.h"
#include "../pnKeyedObject/plFixedKey.h"
#include "../pnSceneObject/plSceneObject.h" // So we can get the target sceneNode of a dialog
#include "../plMessage/plConsoleMsg.h"
#include "plgDispatch.h"
#include "../plResMgr/plKeyFinder.h"
#include "pfGUITagDefs.h"
//////////////////////////////////////////////////////////////////////////////
//// pfGameUIInputInterface Definition ///////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
class pfGameUIInputInterface : public plInputInterface
{
protected:
pfGameGUIMgr * const fGUIManager;
UInt8 fModifiers;
UInt8 fButtonState;
hsBool fHaveInterestingCursor;
UInt32 fCurrentCursor;
virtual hsBool IHandleCtrlCmd( plCtrlCmd *cmd );
virtual hsBool IControlCodeEnabled( ControlEventCode code );
public:
pfGameUIInputInterface( pfGameGUIMgr * const mgr );
virtual UInt32 GetPriorityLevel( void ) const { return kGUISystemPriority; }
virtual hsBool InterpretInputEvent( plInputEventMsg *pMsg );
virtual UInt32 GetCurrentCursorID( void ) const;
virtual hsScalar GetCurrentCursorOpacity( void ) const;
virtual hsBool HasInterestingCursorID( void ) const { return fHaveInterestingCursor; }
virtual hsBool SwitchInterpretOrder( void ) const { return true; }
virtual void RestoreDefaultKeyMappings( void )
{
if( fControlMap != nil )
{
fControlMap->UnmapAllBindings();
fControlMap->BindKey( KEY_BACKSPACE, B_CONTROL_EXIT_GUI_MODE, plKeyMap::kFirstAlways );
fControlMap->BindKey( KEY_ESCAPE, B_CONTROL_EXIT_GUI_MODE, plKeyMap::kSecondAlways );
}
}
};
//////////////////////////////////////////////////////////////////////////////
//// pfGameGUIMgr Functions //////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
pfGameGUIMgr *pfGameGUIMgr::fInstance = nil;
//// Constructor & Destructor ////////////////////////////////////////////////
pfGameGUIMgr::pfGameGUIMgr()
{
fActivated = false;
fInputCtlIndex = 0;
fActiveDialogs = nil;
fInputConfig = nil;
fInstance = this;
fDefaultCursor = plInputInterface::kCursorUp;
fCursorOpacity = 1.f;
fAspectRatio = 0;
}
pfGameGUIMgr::~pfGameGUIMgr()
{
int i;
// the GUIMgr is dead!
fInstance = nil;
for( i = 0; i < fDialogs.GetCount(); i++ )
UnloadDialog( fDialogs[ i ] );
for( i = 0; i < fDialogToSetKeyOf.GetCount(); i++ )
delete fDialogToSetKeyOf[i];
if( fActivated )
IActivateGUI( false );
delete fInputConfig;
}
//// Init ////////////////////////////////////////////////////////////////////
hsBool pfGameGUIMgr::Init( void )
{
return true;
}
//// Draw ////////////////////////////////////////////////////////////////////
void pfGameGUIMgr::Draw( plPipeline *p )
{
}
//// MsgReceive //////////////////////////////////////////////////////////////
hsBool pfGameGUIMgr::MsgReceive( plMessage* pMsg )
{
pfGameGUIMsg *guiMsg = pfGameGUIMsg::ConvertNoRef( pMsg );
if( guiMsg != nil )
{
if( guiMsg->GetCommand() == pfGameGUIMsg::kLoadDialog )
LoadDialog( guiMsg->GetString(), nil, guiMsg->GetAge() );
else if( guiMsg->GetCommand() == pfGameGUIMsg::kShowDialog )
IShowDialog( guiMsg->GetString() );
else if( guiMsg->GetCommand() == pfGameGUIMsg::kHideDialog )
IHideDialog( guiMsg->GetString() );
return true;
}
plGenRefMsg *refMsg = plGenRefMsg::ConvertNoRef( pMsg );
if( refMsg != nil )
{
if( refMsg->fType == kDlgModRef )
{
if( refMsg->GetContext() & ( plRefMsg::kOnCreate | plRefMsg::kOnRequest ) )
{
IAddDlgToList( refMsg->GetRef() );
}
else if( refMsg->GetContext() & plRefMsg::kOnReplace )
{
IRemoveDlgFromList( refMsg->GetOldRef() );
IAddDlgToList( refMsg->GetRef() );
}
else if( refMsg->GetContext() & ( plRefMsg::kOnRemove | plRefMsg::kOnDestroy ) )
{
IRemoveDlgFromList( refMsg->GetRef() );
}
}
return true;
}
return hsKeyedObject::MsgReceive( pMsg );
}
//// IAddDlgToList ///////////////////////////////////////////////////////////
void pfGameGUIMgr::IAddDlgToList( hsKeyedObject *obj )
{
int i;
if( fDialogs.Find( (pfGUIDialogMod *)obj ) == fDialogs.kMissingIndex )
{
pfGUIDialogMod *mod = pfGUIDialogMod::ConvertNoRef( obj );
if( mod != nil )
{
mod->UpdateAspectRatio(); // adding a new dialog, make sure the correct aspect ratio is set
fDialogs.Append( mod );
// check to see if it is the dialog we are waiting for to be loaded
for ( i=0 ; i<fDialogToSetKeyOf.Count() ; i++ )
{
if ( hsStrEQ(fDialogToSetKeyOf[i]->GetName(), mod->GetName()) )
{
SetDialogToNotify(mod,fDialogToSetKeyOf[i]->GetKey());
// now remove this entry... we did it
delete fDialogToSetKeyOf[i];
fDialogToSetKeyOf.Remove(i);
// that's all the damage we can do for now...
break;
}
}
}
}
/* // It's now officially "loaded"; take it off the pending list
for( i = 0; i < fDlgsPendingLoad.GetCount(); i++ )
{
if( stricmp( fDlgsPendingLoad[ i ]->GetName(), ( (pfGUIDialogMod *)obj )->GetName() ) == 0 )
{
// Here it is
delete fDlgsPendingLoad[ i ];
fDlgsPendingLoad.Remove( i );
break;
}
}
*/
}
//// IRemoveDlgFromList //////////////////////////////////////////////////////
void pfGameGUIMgr::IRemoveDlgFromList( hsKeyedObject *obj )
{
int idx = fDialogs.Find( (pfGUIDialogMod *)obj );
if( idx != fDialogs.kMissingIndex )
{
pfGUIDialogMod *mod = pfGUIDialogMod::ConvertNoRef( obj );
hsAssert( mod != nil, "Non-dialog sent to gameGUIMgr::IRemoveDlg()" );
if( mod != nil )
{
if( mod->IsEnabled() )
{
mod->SetEnabled( false );
mod->Unlink();
if( fActiveDialogs == nil )
IActivateGUI( false );
}
// Needed?
// GetKey()->Release( mod->GetKey() );
fDialogs.Remove( idx );
}
}
// It's now officially "unloaded"; take it off the pending list
/* int i;
for( i = 0; i < fDlgsPendingUnload.GetCount(); i++ )
{
if( stricmp( fDlgsPendingUnload[ i ]->GetName(), ( (pfGUIDialogMod *)obj )->GetName() ) == 0 )
{
// Here it is
delete fDlgsPendingUnload[ i ];
fDlgsPendingUnload.Remove( i );
break;
}
}
*/
}
//// LoadDialog //////////////////////////////////////////////////////////////
void pfGameGUIMgr::LoadDialog( const char *name, plKey recvrKey, const char *ageName )
{
// see if they want to set the receiver key once the dialog is loaded
if ( recvrKey != nil )
{
// first see if we are loading a dialog that is already being loaded
bool alreadyLoaded = false;
int i;
for ( i=0 ; i<fDialogToSetKeyOf.Count() ; i++ )
{
if ( hsStrEQ(fDialogToSetKeyOf[i]->GetName(), name) )
{
alreadyLoaded = true;
break;
}
}
if (!alreadyLoaded)
{
pfDialogNameSetKey* pDNSK = TRACKED_NEW pfDialogNameSetKey(name,recvrKey);
fDialogToSetKeyOf.Append(pDNSK);
}
}
hsStatusMessageF("\nLoading Dialog %s %s ... %f\n", name, ( ageName != nil ) ? ageName : "GUI", hsTimer::GetSeconds() );
plKey clientKey = hsgResMgr::ResMgr()->FindKey( kClient_KEY );
plClientMsg *msg = TRACKED_NEW plClientMsg( plClientMsg::kLoadRoomHold );
msg->AddReceiver( clientKey );
msg->AddRoomLoc(plKeyFinder::Instance().FindLocation(ageName ? ageName : "GUI", name));
msg->Send();
// Now add this dialog to a list of pending loads (will remove it once it's fully loaded)
// fDlgsPendingLoad.Append( TRACKED_NEW pfDialogNameSetKey( name, nil ) );
}
//// IShowDialog /////////////////////////////////////////////////////////////
void pfGameGUIMgr::IShowDialog( const char *name )
{
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
if( stricmp( fDialogs[ i ]->GetName(), name ) == 0 )
{
ShowDialog( fDialogs[ i ] );
fDialogs[i]->RefreshAllControls();
break;
}
}
}
//// IHideDialog /////////////////////////////////////////////////////////////
void pfGameGUIMgr::IHideDialog( const char *name )
{
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
if( stricmp( fDialogs[ i ]->GetName(), name ) == 0 )
{
HideDialog( fDialogs[ i ] );
break;
}
}
}
//// ShowDialog //////////////////////////////////////////////////////////////
void pfGameGUIMgr::ShowDialog( pfGUIDialogMod *dlg, bool resetClickables /* = true */ )
{
if ( resetClickables )
plInputInterfaceMgr::GetInstance()->ResetClickableState();
if( !dlg->IsEnabled() )
{
dlg->SetEnabled( true );
// Add to active list
if( fActiveDialogs == nil )
IActivateGUI( true );
dlg->LinkToList( &fActiveDialogs );
return;
}
}
//// HideDialog //////////////////////////////////////////////////////////////
void pfGameGUIMgr::HideDialog( pfGUIDialogMod *dlg )
{
if( dlg->IsEnabled() )
{
dlg->SetEnabled( false );
dlg->Unlink();
if( fActiveDialogs == nil )
IActivateGUI( false );
}
}
//// UnloadDialog ////////////////////////////////////////////////////////////
// Destroy the dialog and all the things associated with it. Fun fun.
void pfGameGUIMgr::UnloadDialog( const char *name )
{
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
if( stricmp( fDialogs[ i ]->GetName(), name ) == 0 )
{
UnloadDialog( fDialogs[ i ] );
break;
}
}
}
void pfGameGUIMgr::UnloadDialog( pfGUIDialogMod *dlg )
{
// IRemoveDlgFromList( dlg );
// Add the name to our list of dialogs pending unload
// fDlgsPendingUnload.Append( TRACKED_NEW pfDialogNameSetKey( dlg->GetName(), nil ) );
plKey sceneNodeKey = dlg->GetSceneNodeKey();
if( sceneNodeKey == nil )
{
hsStatusMessageF( "Warning: Unable to grab sceneNodeKey to unload dialog %s; searching for it...", dlg->GetName() );
sceneNodeKey = plKeyFinder::Instance().FindSceneNodeKey( dlg->GetKey()->GetUoid().GetLocation() );
}
// if( dlg->GetTarget() )
if( sceneNodeKey != nil )
{
plKey clientKey = hsgResMgr::ResMgr()->FindKey( kClient_KEY );
plClientMsg *msg = TRACKED_NEW plClientMsg( plClientMsg::kUnloadRoom );
msg->AddReceiver( clientKey );
// msg->SetProgressBarSuppression( true );
msg->AddRoomLoc(sceneNodeKey->GetUoid().GetLocation());
msg->Send();
}
// GetKey()->Release( dlg->GetKey() );
}
//// IsDialogLoaded ////// see if the dialog is in our list of loaded dialogs
hsBool pfGameGUIMgr::IsDialogLoaded( const char *name )
{
// search through all the dialogs we've loaded
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
if( stricmp( fDialogs[ i ]->GetName(), name ) == 0 )
{
// found 'em
return true;
}
}
// nota
return false;
}
pfGUIPopUpMenu *pfGameGUIMgr::FindPopUpMenu( const char *name )
{
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
pfGUIPopUpMenu *menu = pfGUIPopUpMenu::ConvertNoRef( fDialogs[ i ] );
if( menu != nil && stricmp( menu->GetName(), name ) == 0 )
return menu;
}
return nil;
}
std::vector<plPostEffectMod*> pfGameGUIMgr::GetDlgRenderMods( void ) const
{
std::vector<plPostEffectMod*> retVal;
pfGUIDialogMod* curDialog = fActiveDialogs;
while (curDialog)
{
retVal.push_back(curDialog->GetRenderMod());
curDialog = curDialog->GetNext();
}
return retVal;
}
///// SetDialogToNotify - based on name
// This will Set the handler to a Notify Handler that will send a GUINotifyMsg to the receiver
//
void pfGameGUIMgr::SetDialogToNotify(const char *name, plKey recvrKey)
{
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
if( stricmp( fDialogs[ i ]->GetName(), name ) == 0 )
{
SetDialogToNotify( fDialogs[ i ], recvrKey );
break;
}
}
}
///// SetDialogToNotify - pfGUIDialogMod*
// This will Set the handler to a Notify Handler that will send a GUINotifyMsg to the receiver
//
void pfGameGUIMgr::SetDialogToNotify(pfGUIDialogMod *dlg, plKey recvrKey)
{
pfGUIDialogNotifyProc* handler = TRACKED_NEW pfGUIDialogNotifyProc(recvrKey);
dlg->SetHandler(handler);
handler->OnInit();
}
//// IActivateGUI ////////////////////////////////////////////////////////////
// "Activates" the GUI manager. This means enabling the drawing of GUI
// elements on the screen as well as rerouting input to us.
void pfGameGUIMgr::IActivateGUI( hsBool activate )
{
if( fActivated == activate )
return;
if( activate )
{
fInputConfig = TRACKED_NEW pfGameUIInputInterface( this );
plInputIfaceMgrMsg *msg = TRACKED_NEW plInputIfaceMgrMsg( plInputIfaceMgrMsg::kAddInterface );
msg->SetIFace( fInputConfig );
plgDispatch::MsgSend( msg );
}
else
{
plInputIfaceMgrMsg *msg = TRACKED_NEW plInputIfaceMgrMsg( plInputIfaceMgrMsg::kRemoveInterface );
msg->SetIFace( fInputConfig );
plgDispatch::MsgSend( msg );
hsRefCnt_SafeUnRef( fInputConfig );
fInputConfig = nil;
}
fActivated = activate;
}
//// IHandleMouse ////////////////////////////////////////////////////////////
// Distributes mouse events to the dialogs currently active
hsBool pfGameGUIMgr::IHandleMouse( EventType event, hsScalar mouseX, hsScalar mouseY, UInt8 modifiers, UInt32 *desiredCursor )
{
pfGUIDialogMod *dlg;
// Update interesting things first, no matter what, for ALL dialogs
hsBool modalPresent = false;
for( dlg = fActiveDialogs; dlg != nil; dlg = dlg->GetNext() )
{
dlg->UpdateInterestingThings( mouseX, mouseY, modifiers, modalPresent );
if (dlg->HasFlag( pfGUIDialogMod::kModal ))
modalPresent = true;
}
for( dlg = fActiveDialogs; dlg != nil; dlg = dlg->GetNext() )
{
if( dlg->HandleMouseEvent( event, mouseX, mouseY, modifiers ) ||
( dlg->HasFlag( pfGUIDialogMod::kModal ) && event != pfGameGUIMgr::kMouseUp ) )
{
// If this dialog handled it, also get the cursor it wants
*desiredCursor = dlg->GetDesiredCursor();
return true;
}
}
return false;
}
//// IHandleKeyEvt ///////////////////////////////////////////////////////////
// Distributes mouse events to the dialogs currently active
hsBool pfGameGUIMgr::IHandleKeyEvt( EventType event, plKeyDef key, UInt8 modifiers )
{
pfGUIDialogMod *dlg;
for( dlg = fActiveDialogs; dlg != nil; dlg = dlg->GetNext() )
{
if( dlg->HandleKeyEvent( event, key, modifiers ) )
return true;
}
return false;
}
//// IHandleKeyPress /////////////////////////////////////////////////////////
// Like IHandleKeyPress, but takes in a char for distributing actual
// characters typed.
hsBool pfGameGUIMgr::IHandleKeyPress( char key, UInt8 modifiers )
{
pfGUIDialogMod *dlg;
for( dlg = fActiveDialogs; dlg != nil; dlg = dlg->GetNext() )
{
if( dlg->HandleKeyPress( key, modifiers ) )
return true;
}
return false;
}
//// IModalBlocking //////////////////////////////////////////////////////////
// Looks at the chain of active dialogs and determines if there's any modals
// blocking input. Returns true if so.
hsBool pfGameGUIMgr::IModalBlocking( void )
{
return ( IGetTopModal() != nil ) ? true : false;
}
//// IGetTopModal ////////////////////////////////////////////////////////////
// Returns the topmost (visible) modal dialog, nil if none.
pfGUIDialogMod *pfGameGUIMgr::IGetTopModal( void ) const
{
pfGUIDialogMod *dlg;
for( dlg = fActiveDialogs; dlg != nil; dlg = dlg->GetNext() )
{
if( dlg->HasFlag( pfGUIDialogMod::kModal ) )
return dlg;
}
return nil;
}
//////////////////////////////////////////////////////////////////////////////
//// Control Config Class ////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
pfGameUIInputInterface::pfGameUIInputInterface( pfGameGUIMgr * const mgr ) : plInputInterface(), fGUIManager( mgr )
{
fModifiers = pfGameGUIMgr::kNoModifiers;
fButtonState = 0;
fHaveInterestingCursor = false;
SetEnabled( true ); // Always enabled
fCurrentCursor = kCursorUp;
// Add our control codes to our control map. Do NOT add the key bindings yet.
// Note: HERE is where you specify the actions for each command, i.e. net propagate and so forth.
// This part basically declares us master of the bindings for these commands.
// IF YOU ARE LOOKING TO CHANGE THE DEFAULT KEY BINDINGS, DO NOT LOOK HERE. GO TO
// RestoreDefaultKeyMappings()!!!!
fControlMap->AddCode( B_CONTROL_EXIT_GUI_MODE, kControlFlagNormal | kControlFlagNoRepeat );
// IF YOU ARE LOOKING TO CHANGE THE DEFAULT KEY BINDINGS, DO NOT LOOK HERE. GO TO
// RestoreDefaultKeyMappings()!!!!
}
hsBool pfGameUIInputInterface::IControlCodeEnabled( ControlEventCode code )
{
if( code == B_CONTROL_EXIT_GUI_MODE )
{
// Disable the exitGUIMode key binding if we don't have a modal dialog up or if
// the cursor is inside an edit or multiline edit control
if( !fGUIManager->IModalBlocking() )
return false;
pfGUIDialogMod *dlg = fGUIManager->IGetTopModal();
if( dlg != nil )
{
pfGUIControlMod *ctrl = dlg->GetFocus();
if( ctrl != nil && ctrl->HasFlag( pfGUIControlMod::kTakesSpecialKeys ) )
return false;
}
}
return true; // Enable all other codes
}
hsBool pfGameUIInputInterface::IHandleCtrlCmd( plCtrlCmd *cmd )
{
if( cmd->fControlCode == B_CONTROL_EXIT_GUI_MODE )
{
if( cmd->fControlActivated )
{
pfGUIDialogMod *dlg = fGUIManager->IGetTopModal();
if( dlg != nil && dlg->GetHandler() != nil )
dlg->GetHandler()->OnControlEvent( pfGUIDialogProc::kExitMode );
}
return true;
}
return false;
}
hsBool pfGameUIInputInterface::InterpretInputEvent( plInputEventMsg *pMsg )
{
hsBool handled = false;
/// The in-game UI has to do far more complicated control handling, so we just overload this entirely
plKeyEventMsg *pKeyMsg = plKeyEventMsg::ConvertNoRef( pMsg );
if( pKeyMsg )
{
// By default, we don't want the modifier keys treated as "handled", 'cause
// we want the other interfaces to get them as well (unless we have a modal
// as the top dialog).
if( pKeyMsg->GetKeyCode() == KEY_SHIFT )
{
if( pKeyMsg->GetKeyDown() )
fModifiers |= pfGameGUIMgr::kShiftDown;
else
fModifiers &= ~pfGameGUIMgr::kShiftDown;
}
else if( pKeyMsg->GetKeyCode() == KEY_CTRL )
{
if( pKeyMsg->GetKeyDown() )
fModifiers |= pfGameGUIMgr::kCtrlDown;
else
fModifiers &= ~pfGameGUIMgr::kCtrlDown;
}
else if( pKeyMsg->GetKeyCode() == KEY_CAPSLOCK )
{
if( pKeyMsg->GetKeyDown() )
fModifiers |= pfGameGUIMgr::kCapsDown;
else
fModifiers &= ~pfGameGUIMgr::kCapsDown;
}
else
{
// Sometimes I can't explain why Mathew does some of the things he does.
// I going to replace his modifier flags (which I don't know why he thought he had to have his own)
// with the ones that are in the keymsg since they seem to be more accurate!
fModifiers = 0;
if ( pKeyMsg->GetShiftKeyDown() )
fModifiers |= pfGameGUIMgr::kShiftDown;
if ( pKeyMsg->GetCtrlKeyDown() )
fModifiers |= pfGameGUIMgr::kCtrlDown;
if ( pKeyMsg->GetCapsLockKeyDown() )
fModifiers |= pfGameGUIMgr::kCapsDown;
if( pKeyMsg->GetKeyDown() )
{
if( !pKeyMsg->GetRepeat() )
handled = fGUIManager->IHandleKeyEvt( pfGameGUIMgr::kKeyDown, pKeyMsg->GetKeyCode(), fModifiers );
else
handled = fGUIManager->IHandleKeyEvt( pfGameGUIMgr::kKeyRepeat, pKeyMsg->GetKeyCode(), fModifiers );
handled |= fGUIManager->IHandleKeyPress( plKeyboardDevice::KeyEventToChar( pKeyMsg ), fModifiers );
}
else
handled = fGUIManager->IHandleKeyEvt( pfGameGUIMgr::kKeyUp, pKeyMsg->GetKeyCode(), fModifiers );
}
// We need to do early interception of a screenshot request, since they want
// us to be able to take screen shots while in a modal GUI... whee
// Also, this should only be run if the dialog didn't handle the command in
// the first place (taking screenshots while the user is typing would be
// awkward) and we must do it on key down because the key binding routines
// also trigger on key-down and we don't want to be taking screen shots when
// the user re-binds the screenshot command.
// HACK HACK HACK
if ((!handled) && (pKeyMsg->GetKeyDown()))
{
const plKeyBinding* keymap = plInputInterfaceMgr::GetInstance()->FindBindingByConsoleCmd("Game.KITakePicture");
if (keymap)
{
unsigned keyFlags = 0;
if (pKeyMsg->GetCtrlKeyDown())
keyFlags |= plKeyCombo::kCtrl;
if (pKeyMsg->GetShiftKeyDown())
keyFlags |= plKeyCombo::kShift;
plKeyCombo combo(pKeyMsg->GetKeyCode(), keyFlags);
if ((keymap->GetKey1().IsSatisfiedBy(combo)) || (keymap->GetKey2().IsSatisfiedBy(combo)))
{
// tell the KI to take the shot
plConsoleMsg * consoleMsg = NEWZERO(plConsoleMsg);
consoleMsg->SetCmd(plConsoleMsg::kExecuteLine);
consoleMsg->SetString("Game.KITakePicture");
consoleMsg->Send(nil, true);
}
}
}
bool modal = fGUIManager->IModalBlocking();
return handled || modal; // we "handle" it if we are modal, even if it didn't do anything
}
plMouseEventMsg *pMouseMsg = plMouseEventMsg::ConvertNoRef( pMsg );
if( pMouseMsg && fManager->IsClickEnabled() )
{
if( pMouseMsg->GetButton() == kLeftButtonDown )
{
handled = fGUIManager->IHandleMouse( pfGameGUIMgr::kMouseDown, pMouseMsg->GetXPos(), pMouseMsg->GetYPos(), fModifiers, &fCurrentCursor );
if (handled)
fButtonState |= kLeftButtonDown;
}
else if( pMouseMsg->GetButton() == kLeftButtonUp )
{
handled = fGUIManager->IHandleMouse( pfGameGUIMgr::kMouseUp, pMouseMsg->GetXPos(), pMouseMsg->GetYPos(), fModifiers, &fCurrentCursor );
if ((handled) || (fButtonState & kLeftButtonDown)) // even if we didn't handle the mouse up, if we think the button is still down, we should clear our flag
fButtonState &= ~kLeftButtonDown;
}
else if( pMouseMsg->GetButton() == kLeftButtonDblClk )
handled = fGUIManager->IHandleMouse( pfGameGUIMgr::kMouseDblClick, pMouseMsg->GetXPos(), pMouseMsg->GetYPos(), fModifiers, &fCurrentCursor );
else if( fButtonState & kLeftButtonDown )
handled = fGUIManager->IHandleMouse( pfGameGUIMgr::kMouseDrag, pMouseMsg->GetXPos(), pMouseMsg->GetYPos(), fModifiers, &fCurrentCursor );
else
handled = fGUIManager->IHandleMouse( pfGameGUIMgr::kMouseMove, pMouseMsg->GetXPos(), pMouseMsg->GetYPos(), fModifiers, &fCurrentCursor );
fHaveInterestingCursor = handled;
return handled;
}
return false;
}
UInt32 pfGameUIInputInterface::GetCurrentCursorID( void ) const
{
if( fCurrentCursor == 0 )
{
if ( pfGameGUIMgr::GetInstance() )
return pfGameGUIMgr::GetInstance()->GetDefaultCursor();
else
return kCursorUp;
}
return fCurrentCursor;
}
hsScalar pfGameUIInputInterface::GetCurrentCursorOpacity( void ) const
{
if ( pfGameGUIMgr::GetInstance() )
return pfGameGUIMgr::GetInstance()->GetCursorOpacity();
else
return 1.f;
}
//////////////////////////////////////////////////////////////////////////////
//// Tag Stuff ///////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////
extern pfGUITag gGUITags[]; // From pfGUITagDefs.cpp
//// GetDialogFromTag ////////////////////////////////////////////////////////
pfGUIDialogMod *pfGameGUIMgr::GetDialogFromTag( UInt32 tagID )
{
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
if( fDialogs[ i ]->GetTagID() == tagID )
return fDialogs[ i ];
}
return nil;
}
//// GetDialogFromString ////////////////////////////////////////////////////////
pfGUIDialogMod *pfGameGUIMgr::GetDialogFromString( const char *name )
{
int i;
for( i = 0; i < fDialogs.GetCount(); i++ )
{
if( stricmp( fDialogs[ i ]->GetName(), name ) == 0 )
return fDialogs[ i ];
}
return nil;
}
//// GetControlFromTag ///////////////////////////////////////////////////////
pfGUIControlMod *pfGameGUIMgr::GetControlFromTag( pfGUIDialogMod *dlg, UInt32 tagID )
{
return dlg->GetControlFromTag( tagID );
}
//// GetNumTags //////////////////////////////////////////////////////////////
UInt32 pfGameGUIMgr::GetNumTags( void )
{
UInt32 count;
for( count = 0; gGUITags[ count ].fID != 0; count++ );
return count;
}
//// GetTag //////////////////////////////////////////////////////////////////
pfGUITag *pfGameGUIMgr::GetTag( UInt32 tagIndex )
{
UInt32 count;
for( count = 0; gGUITags[ count ].fID != 0; count++ );
hsAssert( tagIndex < count, "Bad index to GetTag()" );
return &gGUITags[ tagIndex ];
}
UInt32 pfGameGUIMgr::GetHighestTag( void )
{
UInt32 i, id = 1;
for( i = 0; gGUITags[ i ].fID != 0; i++ )
{
if( id < gGUITags[ i ].fID )
id = gGUITags[ i ].fID;
}
return id;
}
void pfGameGUIMgr::SetAspectRatio(hsScalar aspectratio)
{
hsScalar oldAspectRatio = fAspectRatio;
// don't allow the aspectratio below 4:3
hsScalar fourThree = 4.0f/3.0f;
fAspectRatio = aspectratio < fourThree ? fourThree : aspectratio;
if (fAspectRatio != oldAspectRatio)
{
// need to tell dialogs to update
int i;
for (i = 0; i < fDialogs.GetCount(); i++)
{
if (fDialogs[i])
fDialogs[i]->UpdateAspectRatio();
}
}
}

View File

@ -0,0 +1,221 @@
/*==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==*/
//////////////////////////////////////////////////////////////////////////////
// //
// pfGameGUIMgr Header //
// A.K.A. "Ooh, we get a GUI!" //
// //
//// Description /////////////////////////////////////////////////////////////
// //
// The in-game GUI manager. Handles reading, creation, and input for //
// dialog boxes at runtime. //
// //
//////////////////////////////////////////////////////////////////////////////
#ifndef _pfGameGUIMgr_h
#define _pfGameGUIMgr_h
#include "hsTypes.h"
#include "hsTemplates.h"
#include "../pnInputCore/plKeyDef.h"
#include "../pnKeyedObject/hsKeyedObject.h"
#include <vector>
class plPipeline;
class plMessage;
class pfGUIDialogMod;
class pfGUIControlMod;
class pfGameUIInputInterface;
class plPostEffectMod;
//// Tag Definitions /////////////////////////////////////////////////////////
// Each dialog/control gets an optional tag ID number. This is the link
// between MAX and C++. You attach a Tag component to a control or dialog
// in MAX and assign it an ID (supplied by a list of konstants that are
// hard-coded). Then, in code, you ask the gameGUIMgr for the dialog (or
// control) with that ID, and pop, you get it back. Then you run with it.
//
// Easy, huh?
class pfGUITag
{
public:
UInt32 fID;
char fName[ 128 ];
};
//
// This class just holds a name and the key to set the receiver to
// after the dialog gets loaded.
class pfDialogNameSetKey
{
private:
char *fName;
plKey fKey;
public:
pfDialogNameSetKey(const char *name, plKey key) { fName = hsStrcpy(name); fKey=key; }
~pfDialogNameSetKey() { delete [] fName; }
const char *GetName() { return fName; }
plKey GetKey() { return fKey; }
};
//// Manager Class Definition ////////////////////////////////////////////////
class pfGUIPopUpMenu;
class pfGameGUIMgr : public hsKeyedObject
{
friend class pfGameUIInputInterface;
public:
enum EventType
{
kMouseDown,
kMouseUp,
kMouseMove,
kMouseDrag,
kKeyDown,
kKeyUp,
kKeyRepeat,
kMouseDblClick
};
enum
{
kNoModifiers = 0,
kShiftDown = 0x01,
kCtrlDown = 0x02,
kCapsDown = 0x04
};
private:
static pfGameGUIMgr *fInstance;
protected:
hsTArray<pfGUIDialogMod *> fDialogs;
pfGUIDialogMod *fActiveDialogs;
// These two lists help us manage when dialogs get told to load or unload versus when they actually *do*
hsTArray<pfDialogNameSetKey *> fDlgsPendingLoad;
hsTArray<pfDialogNameSetKey *> fDlgsPendingUnload;
hsBool fActivated;
UInt32 fActiveDlgCount;
pfGameUIInputInterface *fInputConfig;
UInt32 fInputCtlIndex;
UInt32 fDefaultCursor;
hsScalar fCursorOpacity;
hsScalar fAspectRatio;
// This is an array of the dialogs (by name) that need their
// receiver key set once they are loaded.
// This array shouldn't get more than one entry... but
// it could be more....
// LoadDialog adds an entry and MsgReceive removes it
hsTArray<pfDialogNameSetKey *> fDialogToSetKeyOf;
void ILoadDialog( const char *name );
void IShowDialog( const char *name );
void IHideDialog( const char *name );
void IAddDlgToList( hsKeyedObject *obj );
void IRemoveDlgFromList( hsKeyedObject *obj );
void IActivateGUI( hsBool activate );
hsBool IHandleMouse( EventType event, hsScalar mouseX, hsScalar mouseY, UInt8 modifiers, UInt32 *desiredCursor );
hsBool IHandleKeyEvt( EventType event, plKeyDef key, UInt8 modifiers );
hsBool IHandleKeyPress( char key, UInt8 modifiers );
hsBool IModalBlocking( void );
pfGUIDialogMod *IGetTopModal( void ) const;
public:
enum
{
kDlgModRef = 0
};
pfGameGUIMgr();
~pfGameGUIMgr();
CLASSNAME_REGISTER( pfGameGUIMgr );
GETINTERFACE_ANY( pfGameGUIMgr, hsKeyedObject );
void Draw( plPipeline *p );
hsBool Init( void );
virtual hsBool MsgReceive( plMessage* pMsg );
void LoadDialog( const char *name, plKey recvrKey=nil, const char *ageName = nil ); // AgeName = nil defaults to "GUI"
void ShowDialog( const char *name ) { IShowDialog(name); }
void HideDialog( const char *name ) { IHideDialog(name); }
void UnloadDialog( const char *name );
void UnloadDialog( pfGUIDialogMod *dlg );
void ShowDialog( pfGUIDialogMod *dlg, bool resetClickables=true );
void HideDialog( pfGUIDialogMod *dlg );
hsBool IsDialogLoaded( const char *name );
pfGUIDialogMod *GetDialogFromString( const char *name );
void SetDialogToNotify(const char *name, plKey recvrKey);
void SetDialogToNotify(pfGUIDialogMod *dlg, plKey recvrKey);
void SetDefaultCursor(UInt32 defaultCursor) { fDefaultCursor = defaultCursor; }
UInt32 GetDefaultCursor() { return fDefaultCursor; }
void SetCursorOpacity(hsScalar opacity) { fCursorOpacity = opacity; }
hsScalar GetCursorOpacity() { return fCursorOpacity; }
pfGUIPopUpMenu *FindPopUpMenu( const char *name );
std::vector<plPostEffectMod*> GetDlgRenderMods( void ) const;
hsBool IsModalBlocking( void ) {return IModalBlocking();}
// Tag ID stuff
pfGUIDialogMod *GetDialogFromTag( UInt32 tagID );
pfGUIControlMod *GetControlFromTag( pfGUIDialogMod *dlg, UInt32 tagID );
static UInt32 GetNumTags( void );
static pfGUITag *GetTag( UInt32 tagIndex );
static UInt32 GetHighestTag( void );
void SetAspectRatio(hsScalar aspectratio);
hsScalar GetAspectRatio() { return fAspectRatio; }
static pfGameGUIMgr *GetInstance( void ) { return fInstance; }
};
#endif //_pfGameGUIMgr_h

View File

@ -0,0 +1,77 @@
/*==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==*/
#ifndef _pfGameGUIMgrCreatable_inc
#define _pfGameGUIMgrCreatable_inc
#include "../pnFactory/plCreator.h"
#include "pfGameGUIMgr.h"
REGISTER_CREATABLE( pfGameGUIMgr );
#include "pfGUIDialogMod.h"
#include "pfGUIControlMod.h"
#include "pfGUIButtonMod.h"
#include "pfGUIDraggableMod.h"
#include "pfGUIListBoxMod.h"
#include "pfGUITextBoxMod.h"
#include "pfGUIEditBoxMod.h"
#include "pfGUIUpDownPairMod.h"
#include "pfGUIValueCtrl.h"
#include "pfGUIKnobCtrl.h"
#include "pfGUIDragBarCtrl.h"
#include "pfGUICheckBoxCtrl.h"
#include "pfGUIRadioGroupCtrl.h"
#include "pfGUIDynDisplayCtrl.h"
#include "pfGUIMultiLineEditCtrl.h"
#include "pfGUIProgressCtrl.h"
#include "pfGUIClickMapCtrl.h"
#include "pfGUIPopUpMenu.h"
#include "pfGUIMenuItem.h"
REGISTER_CREATABLE( pfGUIDialogMod );
REGISTER_NONCREATABLE( pfGUIControlMod );
REGISTER_CREATABLE( pfGUIButtonMod );
REGISTER_CREATABLE( pfGUIDraggableMod );
REGISTER_CREATABLE( pfGUIListBoxMod );
REGISTER_CREATABLE( pfGUITextBoxMod );
REGISTER_CREATABLE( pfGUIEditBoxMod );
REGISTER_NONCREATABLE( pfGUIValueCtrl );
REGISTER_CREATABLE( pfGUIUpDownPairMod );
REGISTER_CREATABLE( pfGUIKnobCtrl );
REGISTER_CREATABLE( pfGUIDragBarCtrl );
REGISTER_CREATABLE( pfGUICheckBoxCtrl );
REGISTER_CREATABLE( pfGUIRadioGroupCtrl );
REGISTER_CREATABLE( pfGUIDynDisplayCtrl );
REGISTER_CREATABLE( pfGUIMultiLineEditCtrl );
REGISTER_CREATABLE( pfGUIProgressCtrl );
REGISTER_CREATABLE( pfGUIClickMapCtrl );
REGISTER_CREATABLE( pfGUIPopUpMenu );
REGISTER_CREATABLE( pfGUIMenuItem );
REGISTER_CREATABLE( pfGUISkin );
#endif // _pfGameGUIMgrCreatable_inc