You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
5075 lines
169 KiB
5075 lines
169 KiB
/*==LICENSE==* |
|
|
|
CyanWorlds.com Engine - MMOG client, server and tools |
|
Copyright (C) 2011 Cyan Worlds, Inc. |
|
|
|
This program is free software: you can redistribute it and/or modify |
|
it under the terms of the GNU General Public License as published by |
|
the Free Software Foundation, either version 3 of the License, or |
|
(at your option) any later version. |
|
|
|
This program is distributed in the hope that it will be useful, |
|
but WITHOUT ANY WARRANTY; without even the implied warranty of |
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|
GNU General Public License for more details. |
|
|
|
You should have received a copy of the GNU General Public License |
|
along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
|
|
Additional permissions under GNU GPL version 3 section 7 |
|
|
|
If you modify this Program, or any covered work, by linking or |
|
combining it with any of RAD Game Tools Bink SDK, Autodesk 3ds Max SDK, |
|
NVIDIA PhysX SDK, Microsoft DirectX SDK, OpenSSL library, Independent |
|
JPEG Group JPEG library, Microsoft Windows Media SDK, or Apple QuickTime SDK |
|
(or a modified version of those libraries), |
|
containing parts covered by the terms of the Bink SDK EULA, 3ds Max EULA, |
|
PhysX SDK EULA, DirectX SDK EULA, OpenSSL and SSLeay licenses, IJG |
|
JPEG Library README, Windows Media SDK EULA, or QuickTime SDK EULA, the |
|
licensors of this Program grant you additional |
|
permission to convey the resulting work. Corresponding Source for a |
|
non-source form of such a combination shall include the source code for |
|
the parts of OpenSSL and IJG JPEG Library used as well as that of the covered |
|
work. |
|
|
|
You can contact Cyan Worlds, Inc. by email legal@cyan.com |
|
or by snail mail at: |
|
Cyan Worlds, Inc. |
|
14617 N Newport Hwy |
|
Mead, WA 99021 |
|
|
|
*==LICENSE==*/ |
|
#include "HeadSpin.h" |
|
#include "max.h" |
|
#include "resource.h" |
|
#include "hsTemplates.h" |
|
#include "plComponent.h" |
|
#include "plComponentReg.h" |
|
#include "plMiscComponents.h" |
|
#include "plAnimComponent.h" |
|
#include "plNotetrackAnim.h" |
|
|
|
#include "plGUIComponents.h" |
|
|
|
#include "plAudioComponents.h" |
|
|
|
#include "../MaxMain/plPlasmaRefMsgs.h" |
|
|
|
#include "../pnSceneObject/plSceneObject.h" |
|
#include "../pnSceneObject/plCoordinateInterface.h" |
|
#include "../pnSceneObject/plDrawInterface.h" |
|
#include "../plDrawable/plDrawableSpans.h" |
|
#include "../plDrawable/plGeometrySpan.h" |
|
#include "../plSurface/plLayerInterface.h" |
|
#include "../plSurface/plLayer.h" |
|
#include "../plSurface/hsGMaterial.h" |
|
#include "../plGImage/plMipmap.h" |
|
#include "../plGImage/plDynamicTextMap.h" |
|
|
|
#include "../plMessage/plLayRefMsg.h" |
|
#include "../plMessage/plMatRefMsg.h" |
|
|
|
#include "../MaxMain/plPluginResManager.h" |
|
|
|
|
|
#include "plgDispatch.h" |
|
#include "../pnMessage/plObjRefMsg.h" |
|
#include "../pnMessage/plIntRefMsg.h" |
|
#include "../pnMessage/plNodeRefMsg.h" |
|
|
|
|
|
#include "../plScene/plSceneNode.h" |
|
#include "../MaxConvert/hsConverterUtils.h" |
|
#include "../MaxConvert/hsControlConverter.h" |
|
#include "../MaxConvert/hsMaterialConverter.h" |
|
#include "../MaxConvert/plLayerConverter.h" |
|
#include "../plInterp/plController.h" |
|
#include "../plInterp/plAnimEaseTypes.h" |
|
#include "../MaxMain/plMaxNode.h" |
|
#include "../pnKeyedObject/plKey.h" |
|
|
|
// GUIDialog component. |
|
#include "../plScene/plPostEffectMod.h" |
|
#include "../pfGameGUIMgr/pfGameGUIMgr.h" |
|
#include "../pfGameGUIMgr/pfGUIDialogMod.h" |
|
#include "../pfGameGUIMgr/pfGUIControlMod.h" |
|
#include "../pfGameGUIMgr/pfGUIControlHandlers.h" |
|
#include "../pfGameGUIMgr/pfGUIButtonMod.h" |
|
#include "../pfGameGUIMgr/pfGUIDraggableMod.h" |
|
#include "../pfGameGUIMgr/pfGUIListBoxMod.h" |
|
#include "../pfGameGUIMgr/pfGUITextBoxMod.h" |
|
#include "../pfGameGUIMgr/pfGUIEditBoxMod.h" |
|
#include "../pfGameGUIMgr/pfGUIUpDownPairMod.h" |
|
#include "../pfGameGUIMgr/pfGUIKnobCtrl.h" |
|
#include "../pfGameGUIMgr/pfGUITagDefs.h" |
|
#include "../pfGameGUIMgr/pfGUIDragBarCtrl.h" |
|
#include "../pfGameGUIMgr/pfGUICheckBoxCtrl.h" |
|
#include "../pfGameGUIMgr/pfGUIRadioGroupCtrl.h" |
|
#include "../pfGameGUIMgr/pfGUIDynDisplayCtrl.h" |
|
#include "../pfGameGUIMgr/pfGUIMultiLineEditCtrl.h" |
|
#include "../pfGameGUIMgr/pfGUIProgressCtrl.h" |
|
#include "../pfGameGUIMgr/pfGUIClickMapCtrl.h" |
|
#include "../pfGameGUIMgr/pfGUIPopUpMenu.h" |
|
|
|
// Location Related |
|
#include "../plAgeDescription/plAgeDescription.h" |
|
#include "../MaxMain/plMaxCFGFile.h" |
|
#include "../MaxMain/plAgeDescInterface.h" |
|
#include "../plFile/hsFiles.h" |
|
|
|
#include "../MaxConvert/plConvert.h" |
|
#include "../MaxPlasmaMtls/Layers/plDynamicTextLayer.h" |
|
#include "../MaxPlasmaMtls/Layers/plLayerTexBitmapPB.h" |
|
|
|
#include "../MaxMain/plMaxAccelerators.h" |
|
|
|
#include "plPickMaterialMap.h" |
|
|
|
#include "../plInterp/plController.h" |
|
#include "../plAvatar/plMatrixChannel.h" |
|
|
|
#include "../MaxPlasmaMtls/Layers/plLayerTex.h" |
|
|
|
#include "pfGUISkinComp.h" |
|
|
|
#include "../plResMgr/plLocalization.h" |
|
|
|
#include "plPickLocalizationDlg.h" |
|
|
|
#include <vector> |
|
#include <string> |
|
|
|
|
|
void DummyCodeIncludeFuncGUI() {} |
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// Helper Classes ///////////////////////////////////////////////////////////////////////////// |
|
|
|
//// Hit Callback for GUI Controls ////////////////////////////////////////////////////////////// |
|
|
|
class plGUICtrlHitCallback : public HitByNameDlgCallback |
|
{ |
|
protected: |
|
INode* fOwner; |
|
IParamBlock2* fPB; |
|
ParamID fNodeListID; |
|
BOOL fRestrict; |
|
hsTArray<Class_ID> fRestrictedIDs; |
|
TCHAR fTitle[ 128 ]; |
|
BOOL fSingle; |
|
|
|
public: |
|
plGUICtrlHitCallback( INode* owner, IParamBlock2 *pb, ParamID nodeListID, TCHAR *title = nil, |
|
BOOL restricted = FALSE, Class_ID rID = GUI_BUTTON_CLASSID, BOOL single = TRUE ) |
|
: fOwner( owner ), fPB( pb ), fNodeListID( nodeListID ), fRestrict( restricted ), fSingle( single ) |
|
|
|
{ |
|
fRestrictedIDs.Append( rID ); |
|
strcpy( fTitle, title ); |
|
} |
|
|
|
plGUICtrlHitCallback( INode* owner, IParamBlock2 *pb, ParamID nodeListID, TCHAR *title, |
|
hsTArray<Class_ID> &rID ) |
|
: fOwner( owner ), fPB( pb ), fNodeListID( nodeListID ), fRestrict( true ), fSingle(TRUE) |
|
|
|
{ |
|
for( int i = 0; i < rID.GetCount(); i++ ) |
|
fRestrictedIDs.Append( rID[ i ] ); |
|
|
|
strcpy( fTitle, title ); |
|
} |
|
|
|
virtual TCHAR *dialogTitle() { return fTitle; } |
|
virtual TCHAR *buttonText() { return "OK"; } |
|
|
|
virtual int filter(INode *node) |
|
{ |
|
if( node == fOwner ) |
|
return FALSE; |
|
|
|
plComponentBase *comp = ((plMaxNodeBase*)node)->ConvertToComponent(); |
|
|
|
// If this is an activator type component |
|
if( comp ) |
|
{ |
|
if( ( fRestrict && fRestrictedIDs.Find( comp->ClassID() ) != fRestrictedIDs.kMissingIndex ) |
|
|| ( !fRestrict && plGUIControlBase::GetGUIComp( comp ) != nil ) ) |
|
{ |
|
|
|
// And this wouldn't create a cyclical reference (Max doesn't like those) |
|
if (comp->TestForLoop(FOREVER, fPB) == REF_FAIL) |
|
return FALSE; |
|
|
|
return TRUE; |
|
} |
|
} |
|
else if( fRestrict && fRestrictedIDs.Find( node->ClassID() ) != fRestrictedIDs.kMissingIndex ) |
|
{ |
|
return TRUE; |
|
} |
|
|
|
return FALSE; |
|
} |
|
|
|
virtual void proc(INodeTab &nodeTab) |
|
{ |
|
if ( nodeTab.Count() > 0 ) |
|
{ |
|
if( fSingle ) |
|
fPB->SetValue( fNodeListID, TimeValue(0), nodeTab[0] ); |
|
else |
|
fPB->Append( fNodeListID, nodeTab.Count(), &nodeTab[0] ); |
|
} |
|
} |
|
|
|
virtual BOOL showHiddenAndFrozen() { return TRUE; } |
|
virtual BOOL singleSelect() { return TRUE; } |
|
}; |
|
|
|
//// Single GUI Control Dialog Proc ///////////////////////////////////////////////////////////// |
|
|
|
class plGUISingleCtrlDlgProc : public ParamMap2UserDlgProc |
|
{ |
|
protected: |
|
ParamID fNodeID; |
|
int fDlgItem; |
|
TCHAR fTitle[ 128 ]; |
|
hsTArray<Class_ID> fClassesToSelect; |
|
|
|
ParamMap2UserDlgProc *fProcChain; |
|
|
|
public: |
|
|
|
int GetHandledDlgItem( void ) const { return fDlgItem; } |
|
|
|
static const Class_ID kEndClassList; |
|
|
|
plGUISingleCtrlDlgProc( ParamID nodeID, int dlgItem, TCHAR *title, Class_ID *restrict, ParamMap2UserDlgProc *parentProc = nil ) |
|
{ |
|
fNodeID = nodeID; |
|
fDlgItem = dlgItem; |
|
for( int i = 0; restrict[ i ] != kEndClassList; i++ ) |
|
fClassesToSelect.Append( restrict[ i ] ); |
|
// fClassToSelect = restrict; |
|
strcpy( fTitle, title ); |
|
fProcChain = parentProc; |
|
} |
|
|
|
BOOL DlgProc( TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
switch ( msg ) |
|
{ |
|
case WM_INITDIALOG: |
|
{ |
|
IParamBlock2 *pb = map->GetParamBlock(); |
|
|
|
INode *node = pb->GetINode( fNodeID ); |
|
TSTR newName( node ? node->GetName() : "Pick" ); |
|
::SetWindowText( ::GetDlgItem( hWnd, fDlgItem ), newName ); |
|
} |
|
break; |
|
|
|
case WM_COMMAND: |
|
if( ( HIWORD( wParam ) == BN_CLICKED ) ) |
|
{ |
|
if( LOWORD( wParam ) == fDlgItem ) |
|
{ |
|
IParamBlock2 *pb = map->GetParamBlock(); |
|
plGUICtrlHitCallback hitCB( (INode *)pb->GetOwner(), pb, fNodeID, fTitle, fClassesToSelect ); |
|
GetCOREInterface()->DoHitByNameDialog( &hitCB ); |
|
|
|
INode* node = pb->GetINode( fNodeID ); |
|
TSTR newName( node ? node->GetName() : "Pick" ); |
|
::SetWindowText( ::GetDlgItem(hWnd, fDlgItem ), newName ); |
|
map->Invalidate( fNodeID ); |
|
::InvalidateRect( hWnd, NULL, TRUE ); |
|
return true; |
|
} |
|
} |
|
break; |
|
} |
|
|
|
if( fProcChain ) |
|
fProcChain->DlgProc( t, map, hWnd, msg, wParam, lParam ); |
|
|
|
return false; |
|
} |
|
|
|
void DeleteThis() {} |
|
}; |
|
|
|
const Class_ID plGUISingleCtrlDlgProc::kEndClassList = Class_ID(); |
|
|
|
Class_ID sSkinClassesToSelect[] = { GUI_SKIN_CLASSID, plGUISingleCtrlDlgProc::kEndClassList }; |
|
|
|
|
|
//// Multiple GUI Control Dialog Proc /////////////////////////////////////////////////////////// |
|
|
|
class plGUIMultipleCtrlDlgProc : public ParamMap2UserDlgProc |
|
{ |
|
protected: |
|
hsTArray<plGUISingleCtrlDlgProc *> fSingleProcs; |
|
hsTArray<ParamMap2UserDlgProc *> fProcs; |
|
|
|
public: |
|
|
|
plGUIMultipleCtrlDlgProc( plGUISingleCtrlDlgProc **singleProcs, ParamMap2UserDlgProc **procs=nil ) |
|
{ |
|
for( int i = 0; singleProcs[ i ] != nil; i++ ) |
|
fSingleProcs.Append( singleProcs[ i ] ); |
|
if ( procs ) |
|
{ |
|
for( int i = 0; procs[ i ] != nil; i++ ) |
|
fProcs.Append( procs[ i ] ); |
|
} |
|
} |
|
|
|
BOOL DlgProc( TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
int i; |
|
|
|
|
|
switch ( msg ) |
|
{ |
|
case WM_INITDIALOG: |
|
for( i = 0; i < fSingleProcs.GetCount(); i++ ) |
|
fSingleProcs[ i ]->DlgProc( t, map, hWnd, msg, wParam, lParam ); |
|
|
|
for( i = 0; i < fProcs.GetCount(); i++ ) |
|
fProcs[ i ]->DlgProc( t, map, hWnd, msg, wParam, lParam ); |
|
|
|
return true; |
|
|
|
case WM_COMMAND: |
|
for( i = 0; i < fSingleProcs.GetCount(); i++ ) |
|
{ |
|
if( fSingleProcs[ i ]->GetHandledDlgItem() == LOWORD( wParam ) ) |
|
{ |
|
fSingleProcs[ i ]->DlgProc( t, map, hWnd, msg, wParam, lParam ); |
|
break; |
|
} |
|
} |
|
// and now do the procs that want more control |
|
for( i = 0; i < fProcs.GetCount(); i++ ) |
|
fProcs[ i ]->DlgProc( t, map, hWnd, msg, wParam, lParam ); |
|
|
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void DeleteThis() {} |
|
}; |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUITag Component ///////////////////////////////////////////////////////////////////// |
|
// |
|
// GUI element that can be dragged anywhere in the 2D viewing plane. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
class plGUITagProc : public ParamMap2UserDlgProc |
|
{ |
|
protected: |
|
|
|
void ILoadTags( HWND hWnd, IParamBlock2 *pb ); |
|
|
|
public: |
|
|
|
void DeleteThis() {} |
|
|
|
BOOL DlgProc( TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); |
|
}; |
|
|
|
static plGUITagProc gGUITagProc; |
|
|
|
// Class that accesses the paramblock below. |
|
class plGUITagComponent : public plComponent |
|
{ |
|
public: |
|
plGUITagComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefCurrIDSel = 64 // So we can share it among other components |
|
}; |
|
|
|
static UInt32 GetTagIDOnNode( plMaxNode *node ); |
|
}; |
|
|
|
//Max desc stuff necessary below. |
|
#define kGUITagClassID Class_ID(0x77276e84, 0x24f360c5) |
|
CLASS_DESC(plGUITagComponent, gGUITagDesc, "GUI ID Tag", "GUITag", COMP_TYPE_GUI, kGUITagClassID ) |
|
|
|
ParamBlockDesc2 gGUITagBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUITag"), 0, &gGUITagDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp, |
|
|
|
IDD_COMP_GUITAG, IDS_COMP_GUITAG, 0, 0, &gGUITagProc, |
|
|
|
plGUITagComponent::kRefCurrIDSel, _T("currSel"), TYPE_INT, 0, 0, |
|
end, |
|
|
|
end |
|
); |
|
|
|
void plGUITagProc::ILoadTags( HWND hWnd, IParamBlock2 *pb ) |
|
{ |
|
int idx, idx2 = 0; |
|
char str[] = "(none)"; |
|
|
|
|
|
SendMessage( hWnd, CB_RESETCONTENT, 0, 0 ); |
|
idx2 = idx = SendMessage( hWnd, CB_ADDSTRING, 0, (LPARAM)str ); |
|
SendMessage( hWnd, CB_SETITEMDATA, (WPARAM)idx, (LPARAM)0 ); |
|
|
|
for( UInt32 i = 0; i < pfGameGUIMgr::GetNumTags(); i++ ) |
|
{ |
|
pfGUITag *tag = pfGameGUIMgr::GetTag( i ); |
|
idx = SendMessage( hWnd, CB_ADDSTRING, 0, (LPARAM)tag->fName ); |
|
SendMessage( hWnd, CB_SETITEMDATA, (WPARAM)idx, (LPARAM)tag->fID ); |
|
|
|
if( tag->fID == pb->GetInt( plGUITagComponent::kRefCurrIDSel ) ) |
|
idx2 = idx; |
|
} |
|
|
|
if( idx2 == 0 && pb->GetInt( plGUITagComponent::kRefCurrIDSel ) != 0 ) |
|
{ |
|
char str[ 32 ]; |
|
sprintf( str, "%d", pb->GetInt( plGUITagComponent::kRefCurrIDSel ) ); |
|
SendMessage( hWnd, WM_SETTEXT, 0, (LPARAM)str ); |
|
} |
|
else |
|
SendMessage( hWnd, CB_SETCURSEL, idx2, 0 ); |
|
} |
|
|
|
// Callback enum proc for below |
|
BOOL CALLBACK GetEditCtrlEnumProc( HWND hWnd, LPARAM lParam ) |
|
{ |
|
char className[ 128 ]; |
|
|
|
|
|
// ICK |
|
GetClassName( hWnd, className, sizeof( className ) - 1 ); |
|
if( stricmp( className, "EDIT" ) == 0 ) |
|
{ |
|
HWND *ptr = (HWND *)lParam; |
|
*ptr = hWnd; |
|
return FALSE; |
|
} |
|
return TRUE; |
|
} |
|
|
|
// Small proc that, given the handle of a combo box, returns the handle of the edit window for it |
|
static HWND GetEditCtrlFromComboBox( HWND combo ) |
|
{ |
|
HWND toReturn; |
|
|
|
EnumChildWindows( combo, GetEditCtrlEnumProc, (LPARAM)&toReturn ); |
|
return toReturn; |
|
} |
|
|
|
// Small proc to only allow numbers in an edit box |
|
static WNDPROC sOriginalProc = nil; |
|
LRESULT CALLBACK SubclassedEditProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
switch( msg ) |
|
{ |
|
case WM_CHAR: |
|
if( !isdigit( (TCHAR)wParam ) ) |
|
return 0; |
|
break; |
|
|
|
case WM_GETDLGCODE: |
|
return DLGC_WANTALLKEYS; |
|
|
|
case WM_KEYDOWN: |
|
if( wParam == VK_RETURN ) |
|
{ |
|
// Do the same thing as when we lose focus--check our int value and make |
|
// sure it's big enough (don't worry about setting the paramBlock value, |
|
// that'll happen when the control loses focus) |
|
|
|
char str[ 32 ]; |
|
GetWindowText( hWnd, str, sizeof( str ) - 1 ); |
|
int id = atoi( str ); |
|
|
|
if( id < pfGameGUIMgr::GetHighestTag() + 1 ) |
|
{ |
|
id = pfGameGUIMgr::GetHighestTag() + 1; |
|
sprintf( str, "%d", id ); |
|
SetWindowText( hWnd, str ); |
|
} |
|
SendMessage( hWnd, EM_SETSEL, 0, (LPARAM)-1 ); |
|
return 0; |
|
} |
|
break; |
|
} |
|
|
|
return CallWindowProc( sOriginalProc, hWnd, msg, wParam, lParam ); |
|
} |
|
|
|
BOOL plGUITagProc::DlgProc( TimeValue t, IParamMap2 *pmap, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
HWND edit; |
|
BOOL dummy1; |
|
|
|
|
|
switch( msg ) |
|
{ |
|
case WM_INITDIALOG: |
|
ILoadTags( GetDlgItem( hWnd, IDC_GUI_TAGCOMBO ), pmap->GetParamBlock() ); |
|
|
|
// Set the edit control of the combo box to only accept number characters |
|
edit = GetEditCtrlFromComboBox( GetDlgItem( hWnd, IDC_GUI_TAGCOMBO ) ); |
|
SetWindowLong( edit, GWL_STYLE, GetWindowLong( edit, GWL_STYLE ) | ES_WANTRETURN ); |
|
sOriginalProc = (WNDPROC)SetWindowLong( edit, GWL_WNDPROC, (DWORD)SubclassedEditProc ); |
|
|
|
return true; |
|
|
|
case WM_DESTROY: |
|
SetWindowLong( GetDlgItem( hWnd, IDC_GUI_TAGCOMBO ), GWL_WNDPROC, (DWORD)sOriginalProc ); |
|
break; |
|
|
|
case WM_COMMAND: |
|
if( LOWORD( wParam ) == IDC_GUI_TAGCOMBO ) |
|
{ |
|
if( HIWORD( wParam ) == CBN_SELCHANGE ) |
|
{ |
|
int idx = SendDlgItemMessage( hWnd, IDC_GUI_TAGCOMBO, CB_GETCURSEL, 0, 0 ); |
|
if( idx == CB_ERR ) |
|
{ |
|
// Must be a custom one |
|
int id = GetDlgItemInt( hWnd, IDC_GUI_TAGCOMBO, &dummy1, false ); |
|
pmap->GetParamBlock()->SetValue( plGUITagComponent::kRefCurrIDSel, 0, id ); |
|
} |
|
else |
|
{ |
|
pmap->GetParamBlock()->SetValue( plGUITagComponent::kRefCurrIDSel, 0, |
|
SendDlgItemMessage( hWnd, IDC_GUI_TAGCOMBO, CB_GETITEMDATA, idx, 0 ) ); |
|
} |
|
} |
|
else if( HIWORD( wParam ) == CBN_KILLFOCUS ) |
|
{ |
|
plMaxAccelerators::Enable(); |
|
|
|
// Make sure the number inside is valid |
|
if( SendDlgItemMessage( hWnd, IDC_GUI_TAGCOMBO, CB_GETCURSEL, 0, 0 ) == CB_ERR ) |
|
{ |
|
int id = GetDlgItemInt( hWnd, IDC_GUI_TAGCOMBO, &dummy1, false ); |
|
if( id < pfGameGUIMgr::GetHighestTag() + 1 ) |
|
{ |
|
id = pfGameGUIMgr::GetHighestTag() + 1; |
|
SetDlgItemInt( hWnd, IDC_GUI_TAGCOMBO, id, false ); |
|
} |
|
|
|
pmap->GetParamBlock()->SetValue( plGUITagComponent::kRefCurrIDSel, 0, id ); |
|
} |
|
} |
|
else if( HIWORD( wParam ) == CBN_SETFOCUS ) |
|
{ |
|
plMaxAccelerators::Disable(); |
|
} |
|
} |
|
break; |
|
} |
|
return false; |
|
} |
|
|
|
plGUITagComponent::plGUITagComponent() |
|
{ |
|
fClassDesc = &gGUITagDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUITagComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return true; |
|
} |
|
|
|
hsBool plGUITagComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
|
|
return true; |
|
} |
|
|
|
hsBool plGUITagComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return true; |
|
} |
|
|
|
UInt32 plGUITagComponent::GetTagIDOnNode( plMaxNode *node ) |
|
{ |
|
UInt32 i; |
|
|
|
|
|
for( i = 0; i < node->NumAttachedComponents( false ); i++ ) |
|
{ |
|
plComponentBase *comp = node->GetAttachedComponent( i, false ); |
|
if( comp->ClassID() == kGUITagClassID ) |
|
{ |
|
plGUITagComponent *tag = (plGUITagComponent *)comp; |
|
return tag->GetParamBlockByID( plComponent::kBlkComp )->GetInt( kRefCurrIDSel ); |
|
} |
|
} |
|
|
|
return 0; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIColorScheme Component ///////////////////////////////////////////////////////////// |
|
// |
|
// Defines the color scheme for a single control or an entire dialog |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
class plGUIColorSchemeProc : public ParamMap2UserDlgProc |
|
{ |
|
protected: |
|
|
|
void ILoadFonts( HWND hWnd, IParamBlock2 *pb ); |
|
|
|
static int CALLBACK IMyFontEnumProc( const ENUMLOGFONTEX *logFontData, const NEWTEXTMETRICEX *physFontData, |
|
unsigned long fontType, LPARAM lParam ); |
|
|
|
public: |
|
|
|
void DeleteThis() {} |
|
|
|
virtual void Update( TimeValue t, Interval &valid, IParamMap2 *map ); |
|
|
|
BOOL DlgProc( TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); |
|
|
|
}; |
|
|
|
static plGUIColorSchemeProc gGUIColorSchemeProc; |
|
|
|
// Class that accesses the paramblock below. |
|
class plGUIColorSchemeComp : public plComponent |
|
{ |
|
public: |
|
plGUIColorSchemeComp(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefForeColor = 128, // So we can share it among other components |
|
kRefBackColor, |
|
kRefSelForeColor, |
|
kRefSelBackColor, |
|
kRefUseAlphas, |
|
kRefFontFace, |
|
kRefFontSize, |
|
kRefFontBold, |
|
kRefFontItalic, |
|
|
|
kRefForeAlpha, |
|
kRefBackAlpha, |
|
kRefSelForeAlpha, |
|
kRefSelBackAlpha, |
|
|
|
kRefFontShadowed |
|
}; |
|
|
|
static void ConvertScheme( IParamBlock2 *pb, pfGUIColorScheme *destScheme, plErrorMsg *pErrMsg ); |
|
}; |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIColorSchemeComp, gGUIColorSchemeDesc, "GUI Color Scheme", "GUIColorScheme", COMP_TYPE_GUI, GUI_COLORSCHEME_CLASSID ) |
|
|
|
static ParamBlockDesc2 gGUIColorSchemeBk |
|
( |
|
/// Main def |
|
plComponent::kBlkComp, _T("GUIColorScheme"), 0, &gGUIColorSchemeDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, plComponent::kRefComp, |
|
|
|
1, |
|
plGUIDialogComponent::kSchemeRollout, IDD_COMP_GUISCHEME, IDS_COMP_GUISCHEME, 0, 0, &gGUIColorSchemeProc, |
|
|
|
plGUIColorSchemeComp::kRefForeColor, _T("foreColor"), TYPE_RGBA, 0, 0, |
|
p_ui, plGUIDialogComponent::kSchemeRollout, TYPE_COLORSWATCH, IDC_GUI_FGCOLOR, |
|
p_default, Color( 1.f, 1.f, 1.f ), |
|
end, |
|
|
|
plGUIColorSchemeComp::kRefBackColor, _T("backColor"), TYPE_RGBA, 0, 0, |
|
p_ui, plGUIDialogComponent::kSchemeRollout, TYPE_COLORSWATCH, IDC_GUI_BGCOLOR, |
|
p_default, Color( 0.f, 0.f, 0.f ), |
|
end, |
|
|
|
plGUIColorSchemeComp::kRefSelForeColor, _T("selForeColor"), TYPE_RGBA, 0, 0, |
|
p_ui, plGUIDialogComponent::kSchemeRollout, TYPE_COLORSWATCH, IDC_GUI_SFGCOLOR, |
|
p_default, Color( 1.f, 1.f, 1.f ), |
|
end, |
|
|
|
plGUIColorSchemeComp::kRefSelBackColor, _T("selBackColor"), TYPE_RGBA, 0, 0, |
|
p_ui, plGUIDialogComponent::kSchemeRollout, TYPE_COLORSWATCH, IDC_GUI_SBGCOLOR, |
|
p_default, Color( 0.f, 0.f, 1.f ), |
|
end, |
|
|
|
|
|
plGUIColorSchemeComp::kRefForeAlpha, _T("foreAlpha"), TYPE_FLOAT, 0, 0, |
|
p_ui, plGUIDialogComponent::kSchemeRollout, TYPE_SLIDER, EDITTYPE_FLOAT, IDC_GUI_FGAEDIT, IDC_GUI_FGALPHA, 4, |
|
p_range, 0.f, 1.f, |
|
p_default, 1.f, |
|
end, |
|
|
|
plGUIColorSchemeComp::kRefBackAlpha, _T("backAlpha"), TYPE_FLOAT, 0, 0, |
|
p_ui, plGUIDialogComponent::kSchemeRollout, TYPE_SLIDER, EDITTYPE_FLOAT, IDC_GUI_BGAEDIT, IDC_GUI_BGALPHA, 4, |
|
p_range, 0.f, 1.f, |
|
p_default, 1.f, |
|
end, |
|
|
|
plGUIColorSchemeComp::kRefSelForeAlpha, _T("selForeAlpha"), TYPE_FLOAT, 0, 0, |
|
p_ui, plGUIDialogComponent::kSchemeRollout, TYPE_SLIDER, EDITTYPE_FLOAT, IDC_GUI_SFGAEDIT, IDC_GUI_SFGALPHA, 4, |
|
p_range, 0.f, 1.f, |
|
p_default, 1.f, |
|
end, |
|
|
|
plGUIColorSchemeComp::kRefSelBackAlpha, _T("selBackAlpha"), TYPE_FLOAT, 0, 0, |
|
p_ui, plGUIDialogComponent::kSchemeRollout, TYPE_SLIDER, EDITTYPE_FLOAT, IDC_GUI_SBGAEDIT, IDC_GUI_SBGALPHA, 4, |
|
p_range, 0.f, 1.f, |
|
p_default, 1.f, |
|
end, |
|
|
|
|
|
plGUIColorSchemeComp::kRefUseAlphas, _T("useAlphas"), TYPE_BOOL, 0, 0, |
|
p_default, FALSE, |
|
p_ui, plGUIDialogComponent::kSchemeRollout, TYPE_SINGLECHEKBOX, IDC_GUI_USEALPHAS, |
|
p_enable_ctrls, 4, plGUIColorSchemeComp::kRefForeAlpha, plGUIColorSchemeComp::kRefBackAlpha, |
|
plGUIColorSchemeComp::kRefSelForeAlpha, plGUIColorSchemeComp::kRefSelBackAlpha, |
|
end, |
|
|
|
|
|
plGUIColorSchemeComp::kRefFontFace, _T("fontFace"), TYPE_STRING, 0, 0, |
|
p_default, _T( "Times New Roman" ), |
|
end, |
|
|
|
plGUIColorSchemeComp::kRefFontSize, _T("fontSize"), TYPE_INT, 0, 0, |
|
p_ui, plGUIDialogComponent::kSchemeRollout, TYPE_SPINNER, EDITTYPE_POS_INT, IDC_GUI_FONTSIZE, IDC_GUI_FONTSIZE_SPIN, SPIN_AUTOSCALE, |
|
p_default, 10, |
|
end, |
|
|
|
plGUIColorSchemeComp::kRefFontBold, _T("fontBold"), TYPE_BOOL, 0, 0, |
|
p_default, FALSE, |
|
p_ui, plGUIDialogComponent::kSchemeRollout, TYPE_SINGLECHEKBOX, IDC_GUI_FONTBOLD, |
|
end, |
|
|
|
plGUIColorSchemeComp::kRefFontItalic, _T("fontItalic"), TYPE_BOOL, 0, 0, |
|
p_default, FALSE, |
|
p_ui, plGUIDialogComponent::kSchemeRollout, TYPE_SINGLECHEKBOX, IDC_GUI_FONTITALIC, |
|
end, |
|
|
|
plGUIColorSchemeComp::kRefFontShadowed, _T("fontShadowed"), TYPE_BOOL, 0, 0, |
|
p_default, FALSE, |
|
p_ui, plGUIDialogComponent::kSchemeRollout, TYPE_SINGLECHEKBOX, IDC_GUI_FONTSHADOWED, |
|
end, |
|
|
|
end |
|
); |
|
|
|
int CALLBACK plGUIColorSchemeProc::IMyFontEnumProc( const ENUMLOGFONTEX *logFontData, const NEWTEXTMETRICEX *physFontData, |
|
unsigned long fontType, LPARAM lParam ) |
|
{ |
|
HWND combo = (HWND)lParam; |
|
|
|
|
|
if( SendMessage( combo, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)logFontData->elfLogFont.lfFaceName ) == CB_ERR ) |
|
SendMessage( combo, CB_ADDSTRING, 0, (LPARAM)logFontData->elfLogFont.lfFaceName ); |
|
|
|
return -1; |
|
} |
|
|
|
void plGUIColorSchemeProc::ILoadFonts( HWND hWnd, IParamBlock2 *pb ) |
|
{ |
|
LOGFONT logFont; |
|
|
|
|
|
logFont.lfCharSet = DEFAULT_CHARSET; |
|
strcpy( logFont.lfFaceName, "" ); |
|
logFont.lfPitchAndFamily = 0; |
|
|
|
SendMessage( hWnd, CB_RESETCONTENT, 0, 0 ); |
|
|
|
HDC hDC = GetDC( nil ); |
|
EnumFontFamiliesEx( hDC, &logFont, (FONTENUMPROC)IMyFontEnumProc, (LPARAM)hWnd, 0 ); |
|
ReleaseDC( nil, hDC ); |
|
|
|
SendMessage( hWnd, CB_SELECTSTRING, (WPARAM)-1, (LPARAM)pb->GetStr( plGUIColorSchemeComp::kRefFontFace ) ); |
|
} |
|
|
|
#define MAXTOCOLORREF( max ) RGB( max.r * 255.f, max.g * 255.f, max.b * 255.f ) |
|
|
|
void plGUIColorSchemeProc::Update( TimeValue t, Interval &valid, IParamMap2 *pmap ) |
|
{ |
|
} |
|
|
|
BOOL plGUIColorSchemeProc::DlgProc( TimeValue t, IParamMap2 *pmap, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
char str[ 256 ]; |
|
HWND placeCtrl; |
|
PAINTSTRUCT paintInfo; |
|
RECT previewRect, r; |
|
HBRUSH bgPattBrush = nil; |
|
Color fgColor, bgColor, selFgColor, selBgColor; |
|
Color hatchColor = Color( 0.4f, 0.4f, 0.4f ), blendedColor, whiteColor = Color( 0.7f, 0.7f, 0.7f ); |
|
Color blackColor = Color( 0, 0, 0 ), blendedColor2; |
|
float fgAlpha, bgAlpha, selFgAlpha, selBgAlpha; |
|
char previewString[] = "Preview"; |
|
HFONT font; |
|
|
|
|
|
switch( msg ) |
|
{ |
|
case WM_INITDIALOG: |
|
ILoadFonts( GetDlgItem( hWnd, IDC_GUI_FONTFACE ), pmap->GetParamBlock() ); |
|
return true; |
|
|
|
case WM_DESTROY: |
|
break; |
|
|
|
case WM_COMMAND: |
|
if( LOWORD( wParam ) == IDC_GUI_FONTFACE ) |
|
{ |
|
if( HIWORD( wParam ) == CBN_SELCHANGE ) |
|
{ |
|
int idx = SendDlgItemMessage( hWnd, IDC_GUI_FONTFACE, CB_GETCURSEL, 0, 0 ); |
|
|
|
SendDlgItemMessage( hWnd, IDC_GUI_FONTFACE, CB_GETLBTEXT, idx, (LPARAM)str ); |
|
|
|
pmap->GetParamBlock()->SetValue( plGUIColorSchemeComp::kRefFontFace, 0, str ); |
|
} |
|
} |
|
break; |
|
|
|
case CC_COLOR_CHANGE: |
|
case CC_COLOR_DROP: |
|
placeCtrl = ::GetDlgItem( hWnd, IDC_GUI_SCHEMEPREV ); |
|
::GetClientRect( placeCtrl, &previewRect ); |
|
::MapWindowPoints( placeCtrl, hWnd, (POINT *)&previewRect, 2 ); |
|
::InvalidateRect( hWnd, &previewRect, FALSE ); |
|
break; |
|
|
|
case WM_PAINT: |
|
|
|
fgColor = pmap->GetParamBlock()->GetColor( plGUIColorSchemeComp::kRefForeColor ); |
|
bgColor = pmap->GetParamBlock()->GetColor( plGUIColorSchemeComp::kRefBackColor ); |
|
selFgColor = pmap->GetParamBlock()->GetColor( plGUIColorSchemeComp::kRefSelForeColor ); |
|
selBgColor = pmap->GetParamBlock()->GetColor( plGUIColorSchemeComp::kRefSelBackColor ); |
|
|
|
fgAlpha = pmap->GetParamBlock()->GetFloat( plGUIColorSchemeComp::kRefForeAlpha ); |
|
bgAlpha = pmap->GetParamBlock()->GetFloat( plGUIColorSchemeComp::kRefBackAlpha ); |
|
selFgAlpha = pmap->GetParamBlock()->GetFloat( plGUIColorSchemeComp::kRefSelForeAlpha ); |
|
selBgAlpha = pmap->GetParamBlock()->GetFloat( plGUIColorSchemeComp::kRefSelBackAlpha ); |
|
if( pmap->GetParamBlock()->GetInt( plGUIColorSchemeComp::kRefUseAlphas ) == 0 ) |
|
fgAlpha = bgAlpha = selFgAlpha = selBgAlpha = 1.f; |
|
|
|
placeCtrl = ::GetDlgItem( hWnd, IDC_GUI_SCHEMEPREV ); |
|
::GetClientRect( placeCtrl, &previewRect ); |
|
::MapWindowPoints( placeCtrl, hWnd, (POINT *)&previewRect, 2 ); |
|
|
|
::BeginPaint( hWnd, &paintInfo ); |
|
::SetBkMode( paintInfo.hdc, TRANSPARENT ); |
|
|
|
int weight = pmap->GetParamBlock()->GetInt( plGUIColorSchemeComp::kRefFontBold ) ? FW_BOLD : FW_NORMAL; |
|
bool italic = pmap->GetParamBlock()->GetInt( plGUIColorSchemeComp::kRefFontItalic ) ? true : false; |
|
int nHeight = -MulDiv( pmap->GetParamBlock()->GetInt( plGUIColorSchemeComp::kRefFontSize ), GetDeviceCaps( paintInfo.hdc, LOGPIXELSY ), 72 ); |
|
const char *face = pmap->GetParamBlock()->GetStr( plGUIColorSchemeComp::kRefFontFace ); |
|
|
|
font = ::CreateFont( nHeight, 0, 0, 0, weight, italic, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, |
|
CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, VARIABLE_PITCH, face ); |
|
SelectObject( paintInfo.hdc, font ); |
|
|
|
// Left side |
|
r = previewRect; |
|
r.right = ( r.right + r.left ) >> 1; |
|
|
|
blendedColor = bgColor * bgAlpha + ( whiteColor * ( 1.f - bgAlpha ) ); |
|
|
|
// doesn't like the Color to DWORD operator, so duplicating it here |
|
#define ColorToDWORD(color) RGB(FLto255(color.r),FLto255(color.g),FLto255(color.b)) |
|
::SetBkColor( paintInfo.hdc, ColorToDWORD(blendedColor) ); |
|
|
|
blendedColor = bgColor * bgAlpha + ( hatchColor * ( 1.f - bgAlpha ) ); |
|
bgPattBrush = CreateHatchBrush( HS_DIAGCROSS, MAXTOCOLORREF( blendedColor ) ); |
|
|
|
::FillRect( paintInfo.hdc, &r, bgPattBrush ); |
|
if( pmap->GetParamBlock()->GetInt( plGUIColorSchemeComp::kRefFontShadowed ) ) |
|
{ |
|
blendedColor2 = blackColor * fgAlpha + ( blendedColor * ( 1.f - fgAlpha ) ); |
|
::SetTextColor( paintInfo.hdc, MAXTOCOLORREF( blendedColor2 ) ); |
|
::OffsetRect( &r, 1, 1 ); |
|
::DrawText( paintInfo.hdc, previewString, strlen( previewString ), &r, DT_CENTER | DT_VCENTER ); |
|
::OffsetRect( &r, -1, -1 ); |
|
} |
|
|
|
blendedColor = fgColor * fgAlpha + ( blendedColor * ( 1.f - fgAlpha ) ); |
|
::SetTextColor( paintInfo.hdc, MAXTOCOLORREF( blendedColor ) ); |
|
::DrawText( paintInfo.hdc, previewString, strlen( previewString ), &r, DT_CENTER | DT_VCENTER ); |
|
|
|
::DeleteObject( bgPattBrush ); |
|
|
|
// Right side |
|
r.left = r.right; |
|
r.right = previewRect.right; |
|
|
|
blendedColor = selBgColor * selBgAlpha + ( whiteColor * ( 1.f - selBgAlpha ) ); |
|
::SetBkColor( paintInfo.hdc, ColorToDWORD(blendedColor) ); |
|
blendedColor = selBgColor * selBgAlpha + ( hatchColor * ( 1.f - selBgAlpha ) ); |
|
bgPattBrush = CreateHatchBrush( HS_DIAGCROSS, MAXTOCOLORREF( blendedColor ) ); |
|
|
|
::FillRect( paintInfo.hdc, &r, bgPattBrush ); |
|
if( pmap->GetParamBlock()->GetInt( plGUIColorSchemeComp::kRefFontShadowed ) ) |
|
{ |
|
blendedColor2 = blackColor * selFgAlpha + ( blendedColor * ( 1.f - selFgAlpha ) ); |
|
::SetTextColor( paintInfo.hdc, MAXTOCOLORREF( blendedColor2 ) ); |
|
::OffsetRect( &r, 1, 1 ); |
|
::DrawText( paintInfo.hdc, previewString, strlen( previewString ), &r, DT_CENTER | DT_VCENTER ); |
|
::OffsetRect( &r, -1, -1 ); |
|
} |
|
blendedColor = selFgColor * selFgAlpha + ( blendedColor * ( 1.f - selFgAlpha ) ); |
|
::SetTextColor( paintInfo.hdc, MAXTOCOLORREF( blendedColor ) ); |
|
::DrawText( paintInfo.hdc, previewString, strlen( previewString ), &r, DT_CENTER | DT_VCENTER ); |
|
|
|
::DeleteObject( bgPattBrush ); |
|
|
|
::DeleteObject( font ); |
|
|
|
::EndPaint( hWnd, &paintInfo ); |
|
|
|
return true; |
|
} |
|
return false; |
|
} |
|
|
|
plGUIColorSchemeComp::plGUIColorSchemeComp() |
|
{ |
|
fClassDesc = &gGUIColorSchemeDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIColorSchemeComp::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return true; |
|
} |
|
|
|
hsBool plGUIColorSchemeComp::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
|
|
return true; |
|
} |
|
|
|
hsBool plGUIColorSchemeComp::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
pfGUIControlMod *ctrl = plGUIControlBase::GrabControlFromObject( node ); |
|
if( ctrl != nil ) |
|
{ |
|
pfGUIColorScheme *cs = TRACKED_NEW pfGUIColorScheme; |
|
ConvertScheme( fCompPB, cs, pErrMsg ); |
|
ctrl->SetColorScheme( cs ); |
|
} |
|
else |
|
{ |
|
pErrMsg->Set( true, "GUI Color Scheme Error", "You have applied a GUI color scheme to an object (%s) without a GUI control. This scheme will be ignored.", node->GetName()).Show(); |
|
pErrMsg->Set( false ); |
|
return false; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void SMaxRGBAToPlasmaRGBA( Color maxRGB, hsColorRGBA &plasmaRGBA ) |
|
{ |
|
plasmaRGBA.Set( maxRGB.r, maxRGB.g, maxRGB.b, 1.f ); |
|
} |
|
|
|
void plGUIColorSchemeComp::ConvertScheme( IParamBlock2 *pb, pfGUIColorScheme *destScheme, plErrorMsg *pErrMsg ) |
|
{ |
|
SMaxRGBAToPlasmaRGBA( pb->GetColor( kRefForeColor ), destScheme->fForeColor ); |
|
SMaxRGBAToPlasmaRGBA( pb->GetColor( kRefBackColor ), destScheme->fBackColor ); |
|
SMaxRGBAToPlasmaRGBA( pb->GetColor( kRefSelForeColor ), destScheme->fSelForeColor ); |
|
SMaxRGBAToPlasmaRGBA( pb->GetColor( kRefSelBackColor ), destScheme->fSelBackColor ); |
|
|
|
destScheme->fForeColor.a = pb->GetFloat( kRefForeAlpha ); |
|
destScheme->fBackColor.a = pb->GetFloat( kRefBackAlpha ); |
|
destScheme->fSelForeColor.a = pb->GetFloat( kRefSelForeAlpha ); |
|
destScheme->fSelBackColor.a = pb->GetFloat( kRefSelBackAlpha ); |
|
|
|
destScheme->fTransparent = pb->GetInt( kRefUseAlphas ) ? true : false; |
|
|
|
destScheme->SetFontFace( pb->GetStr( kRefFontFace ) ); |
|
destScheme->fFontSize = pb->GetInt( kRefFontSize ); |
|
destScheme->fFontFlags = 0; |
|
if( pb->GetInt( kRefFontBold ) ) |
|
destScheme->fFontFlags |= pfGUIColorScheme::kFontBold; |
|
if( pb->GetInt( kRefFontItalic ) ) |
|
destScheme->fFontFlags |= pfGUIColorScheme::kFontItalic; |
|
if( pb->GetInt( kRefFontShadowed ) ) |
|
destScheme->fFontFlags |= pfGUIColorScheme::kFontShadowed; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIProxy Rollout ///////////////////////////////////////////////////////////////////////// |
|
// |
|
// Defines a proxy object to be used when calculating mouse-down locations and dynamic text |
|
// sizing. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
enum plProxyRefs |
|
{ |
|
kRefProxyNode = 196, |
|
kRefHideProxy, |
|
kRefBetterHitTests |
|
}; |
|
|
|
//// DialogProc ///////////////////////////////////////////////////////////////////////////////// |
|
|
|
class plGUIProxyDlgProc : public ParamMap2UserDlgProc |
|
{ |
|
public: |
|
|
|
plGUIProxyDlgProc() |
|
{ |
|
} |
|
|
|
void DeleteThis() {} |
|
|
|
BOOL DlgProc(TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) |
|
{ |
|
IParamBlock2 *pblock = map->GetParamBlock(); |
|
|
|
switch( msg ) |
|
{ |
|
case WM_COMMAND: |
|
// if( LOWORD( wParam ) == IDC_GUI_CLEAR ) |
|
// { |
|
// pblock->Reset( (ParamID)kRefProxyNode ); |
|
// return true; |
|
// } |
|
break; |
|
} |
|
return false; |
|
} |
|
|
|
}; |
|
|
|
static plGUIProxyDlgProc sGUIProxyDlgProc; |
|
|
|
//// ParamBlock ///////////////////////////////////////////////////////////////////////////////// |
|
// Note: we can't make this a real ParamBlock and do P_INCLUDE_PARAMS because, in Discreet's |
|
// amazing method of doing things, we can't INCLUDE more than one ParamBlock in any other PB. |
|
// So either we chain them together here (and thus make them dependent on one another, which |
|
// is lame) or we just make the whole damned thing a #define, which is all P_INCLUDE_PARAMS |
|
// really does anyway. |
|
|
|
#define sGUIProxyParamHeader plGUIControlBase::kRollProxy, IDD_COMP_GUIPROXY, IDS_COMP_GUIPROXY, 0, APPENDROLL_CLOSED, &sGUIProxyDlgProc |
|
//static ParamBlockDesc2 sSndEAXPropsParamTemplate |
|
//( |
|
/// Main def |
|
// plComponent::kBlkComp + 1, _T("sndEAXProps"), 0, nil, P_AUTO_UI + P_MULTIMAP + P_AUTO_CONSTRUCT, plComponent::kRefComp, |
|
|
|
// 1, |
|
// kSndEAXParams, IDD_COMP_EAXBUFFER, IDS_COMP_EAXBUFFER, 0, 0, nil, |
|
|
|
#define sGUIProxyParamTemplate \ |
|
\ |
|
kRefBetterHitTests, _T("guiBetterHitTests"), TYPE_BOOL, 0, 0, \ |
|
p_ui, plGUIControlBase::kRollProxy, TYPE_SINGLECHEKBOX, IDC_GUI_BETTERHIT, \ |
|
p_default, false, \ |
|
end |
|
|
|
// , end |
|
//); |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIDialog Component ////////////////////////////////////////////////////////////////////// |
|
// |
|
// Defines a dialog box (i.e. a collection of controls) to be defined with the GUI manager at |
|
// runtime. Acts a lot like a CamView component, but it additionally handles a few other things. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
class plGUIDialogProc : public ParamMap2UserDlgProc |
|
{ |
|
protected: |
|
|
|
void ILoadPages( HWND hWnd, IParamBlock2 *pb ); |
|
|
|
public: |
|
|
|
void DeleteThis() {} |
|
|
|
BOOL DlgProc( TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); |
|
}; |
|
static plGUIDialogProc gGUIDialogProc; |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIDialogComponent, gGUIDialogDesc, "GUI Dialog", "GUIDialog", COMP_TYPE_GUI, GUI_DIALOG_COMP_CLASS_ID ) |
|
|
|
ParamBlockDesc2 gGUIDialogBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUIDialog"), 0, &gGUIDialogDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP + P_INCLUDE_PARAMS, plComponent::kRefComp, |
|
|
|
3, |
|
plGUIDialogComponent::kMainRollout, IDD_COMP_GUIDIALOG, IDS_COMP_GUIDIALOG, 0, 0, &gGUIDialogProc, |
|
plGUIDialogComponent::kTagIDRollout, IDD_COMP_GUITAG, IDS_COMP_GUITAG, 0, 0, &gGUITagProc, |
|
plGUIDialogComponent::kSchemeRollout, IDD_COMP_GUISCHEME, IDS_COMP_GUISCHEME, 0, 0, &gGUIColorSchemeProc, |
|
|
|
&gGUIColorSchemeBk, |
|
|
|
plGUIDialogComponent::kRefDialogName, _T("DialogName"), TYPE_STRING, 0, 0, |
|
// p_ui, plGUIDialogComponent::kMainRollout, TYPE_EDITBOX, IDC_GUIDLG_NAME, |
|
end, |
|
|
|
plGUIDialogComponent::kRefAgeName, _T("ageName"), TYPE_STRING, 0, 0, |
|
p_default, _T( "GUI" ), |
|
end, |
|
|
|
plGUIDialogComponent::kRefIsModal, _T("isModal"), TYPE_BOOL, 0, 0, |
|
p_default, FALSE, |
|
p_ui, plGUIDialogComponent::kMainRollout, TYPE_SINGLECHEKBOX, IDC_COMP_GUI_MODAL, |
|
end, |
|
|
|
plGUIDialogComponent::kRefVersion, _T("version"), TYPE_INT, 0, 0, |
|
p_ui, plGUIDialogComponent::kMainRollout, TYPE_SPINNER, EDITTYPE_POS_INT, IDC_GUI_VERSION, IDC_GUI_VERSION_SPIN, SPIN_AUTOSCALE, |
|
p_default, 0, |
|
end, |
|
|
|
plGUITagComponent::kRefCurrIDSel, _T("currSel"), TYPE_INT, 0, 0, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plGUIDialogComponent::plGUIDialogComponent( hsBool dontInit ) |
|
{ |
|
if( !dontInit ) |
|
{ |
|
fClassDesc = &gGUIDialogDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
fDialogMod = nil; |
|
fProcReceiver = nil; |
|
} |
|
|
|
pfGUIDialogMod *plGUIDialogComponent::IMakeDialog( void ) |
|
{ |
|
return TRACKED_NEW pfGUIDialogMod(); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIDialogComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
TimeValue timeVal( 0 ); |
|
Object* obj = node->EvalWorldState( timeVal ).obj; |
|
|
|
fDialogMod = nil; |
|
|
|
if( obj->CanConvertToType( Class_ID( LOOKAT_CAM_CLASS_ID, 0 ) ) || |
|
obj->CanConvertToType( Class_ID( SIMPLE_CAM_CLASS_ID, 0 ) ) ) |
|
{ |
|
// We're applied to a camera. Do our camera stuff |
|
node->SetForceLocal( true ); |
|
} |
|
else |
|
{ |
|
// We're applied to a normal object. |
|
node->SetNoSpanReSort(true); |
|
node->SetNoSpanSort(true); |
|
} |
|
|
|
/// Either way, we mangle our own location component. None of this user-defined-location stuff. |
|
|
|
char *dialogName = fCompPB->GetStr( kRefDialogName ); |
|
if( dialogName == nil || *dialogName == 0 ) |
|
{ |
|
pErrMsg->Set(true, "GUI Dialog Component Error", "No dialog name specified on GUI Dialog component (object: %s)", node->GetName()).Show(); |
|
return false; |
|
} |
|
|
|
char *ageName = fCompPB->GetStr(kRefAgeName); |
|
Int32 seqNum = plPageInfoUtils::GetSeqNumFromAgeDesc( ageName, dialogName ); |
|
Int32 newNum = plPluginResManager::ResMgr()->VerifySeqNumber( seqNum, ageName, dialogName ); |
|
if( newNum != seqNum ) |
|
{ |
|
if( !fSeqNumValidated ) |
|
{ |
|
plLocation pageLoc = plPluginResManager::ResMgr()->FindLocation( ageName, dialogName ); |
|
Int32 pageSeqNum = pageLoc.GetSequenceNumber(); |
|
char errMsg[ 512 ]; |
|
sprintf( errMsg, "The sequence number stored by the resource manager (0x%X) for page %s, District, %s does not match\n" |
|
"the sequence number stored in the .age file (0x%X). Forcing it to use the one in the .age file", |
|
pageSeqNum, ageName, dialogName, seqNum ); |
|
pErrMsg->Set( true, "PageInfo Convert Error", errMsg ).Show(); |
|
pErrMsg->Set( false ); |
|
fSeqNumValidated = true; |
|
} |
|
// force the component to use the sequence number in the .age file |
|
//seqNum = newNum; |
|
} |
|
|
|
plKey roomKey = plPluginResManager::ResMgr()->NameToLoc( fCompPB->GetStr( kRefAgeName ), fCompPB->GetStr( kRefDialogName ), seqNum ); |
|
if( !roomKey ) |
|
{ |
|
pErrMsg->Set( true, "GUI Dialog Component Error", "GUI Dialog Component %s has a Missing Location. Nuke the files in the dat directory and re-export.",((INode*)node)->GetName()).Show(); |
|
return false; |
|
} |
|
|
|
node->SetRoomKey( roomKey ); |
|
|
|
// Also, we make sure this node will never be fogged (affects material convert) |
|
node->SetIsGUI( true ); |
|
|
|
return true; |
|
} |
|
|
|
hsBool plGUIDialogComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
TimeValue timeVal(0); |
|
|
|
Object* obj = node->EvalWorldState(timeVal).obj; |
|
|
|
GenCamera* cam = nil; |
|
if( obj->CanConvertToType(Class_ID(LOOKAT_CAM_CLASS_ID, 0)) ) |
|
cam = (GenCamera *) obj->ConvertToType(timeVal, Class_ID(LOOKAT_CAM_CLASS_ID, 0)); |
|
else |
|
if( obj->CanConvertToType(Class_ID(SIMPLE_CAM_CLASS_ID, 0)) ) |
|
cam = (GenCamera *) obj->ConvertToType(timeVal, Class_ID(SIMPLE_CAM_CLASS_ID, 0)); |
|
|
|
if( !cam ) |
|
{ |
|
// Not applied to a camera, so applied to a normal object. Since this is valid (we also act |
|
// as a location component), just return |
|
return true; |
|
} |
|
|
|
plPostEffectMod* mod = TRACKED_NEW plPostEffectMod; |
|
|
|
float hither = cam->GetEnvRange(timeVal, ENV_NEAR_RANGE); |
|
if( hither < 0.5f ) |
|
hither = 0.5f; |
|
float yon = cam->GetEnvRange(timeVal, ENV_FAR_RANGE); |
|
mod->SetHither(hither); |
|
mod->SetYon(yon); |
|
|
|
// radians |
|
float fov = cam->GetFOV(timeVal); |
|
// convert |
|
int FOVType = cam->GetFOVType(); |
|
hsScalar fovX, fovY; |
|
switch(FOVType) |
|
{ |
|
case 0: // FOV_W |
|
{ |
|
fovX = fov; |
|
fovY = fovX *3.f / 4.f; |
|
} |
|
break; |
|
case 1: // FOV_H |
|
{ |
|
fovY = fov; |
|
fovX = fovY * 4.f / 3.f; |
|
} |
|
break; |
|
} |
|
fovX *= 180.f / hsScalarPI; |
|
fovY *= 180.f / hsScalarPI; |
|
mod->SetFovX(fovX); |
|
mod->SetFovY(fovY); |
|
|
|
// Should already be created from SetupProperties... |
|
// Note: can't just grab the node's room key, 'cause we might not be on the right node! |
|
plKey sceneNodeKey = plPluginResManager::ResMgr()->NameToLoc( fCompPB->GetStr( kRefAgeName ), |
|
fCompPB->GetStr( kRefDialogName ), (UInt32)-1 ); |
|
mod->SetNodeKey( sceneNodeKey ); |
|
|
|
// node->AddModifier(mod); |
|
// Note: we do NOT add this to the sceneObject, we don't want it actually associated with |
|
// a sceneObject. Instead, we just grab the LocalToWorld() off the sceneObject, since that's |
|
// all we want |
|
hsMatrix44 l2w = node->GetLocalToWorld44(); |
|
hsMatrix44 w2l = node->GetWorldToLocal44(); |
|
mod->SetWorldToCamera( w2l, l2w ); |
|
|
|
// Add it to the sceneNode as a generic interface, so it gets loaded with the sceneNode |
|
plLocation nodeLoc = sceneNodeKey->GetUoid().GetLocation(); |
|
|
|
plKey modKey = hsgResMgr::ResMgr()->NewKey( fCompPB->GetStr( kRefDialogName ), mod, nodeLoc ); |
|
hsgResMgr::ResMgr()->AddViaNotify( modKey, TRACKED_NEW plNodeRefMsg( sceneNodeKey, plRefMsg::kOnCreate, -1, plNodeRefMsg::kGeneric ), plRefFlags::kActiveRef ); |
|
|
|
// Also add our dialog mod to the scene node in the same way |
|
hsgResMgr::ResMgr()->AddViaNotify( fDialogMod->GetKey(), TRACKED_NEW plNodeRefMsg( sceneNodeKey, plRefMsg::kOnCreate, -1, plNodeRefMsg::kGeneric ), plRefFlags::kActiveRef ); |
|
|
|
/// Already created our mod, just gotta fill it out |
|
fDialogMod->SetRenderMod( mod ); |
|
fDialogMod->SetName( fCompPB->GetStr( kRefDialogName ) ); |
|
if( fCompPB->GetInt( kRefIsModal ) ) |
|
fDialogMod->SetFlag( pfGUIDialogMod::kModal ); |
|
fDialogMod->SetProcReceiver(fProcReceiver); |
|
fDialogMod->SetVersion( fCompPB->GetInt( kRefVersion ) ); |
|
|
|
plGUIColorSchemeComp::ConvertScheme( fCompPB, fDialogMod->GetColorScheme(), pErrMsg ); |
|
|
|
return true; |
|
} |
|
|
|
hsBool plGUIDialogComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
TimeValue timeVal(0); |
|
Object* obj = node->EvalWorldState(timeVal).obj; |
|
|
|
if( obj->CanConvertToType(Class_ID(LOOKAT_CAM_CLASS_ID, 0)) |
|
|| obj->CanConvertToType(Class_ID(SIMPLE_CAM_CLASS_ID, 0)) ) |
|
{ |
|
// Don't do this. -mf |
|
// IMakeEveryoneOpaque(node); |
|
|
|
// Make a blank dialog modifier, which will be filled in on convert. Do |
|
// this as a separate step so the dialog controls can query and get the dialog |
|
// mod to store a ref to |
|
|
|
fDialogMod = IMakeDialog(); |
|
|
|
// Note: can't just grab the node's room key, 'cause we might not be on the right node! |
|
plKey sceneNodeKey = plPluginResManager::ResMgr()->NameToLoc( fCompPB->GetStr( kRefAgeName ), |
|
fCompPB->GetStr( kRefDialogName ), (UInt32)-1 ); |
|
|
|
plLocation nodeLoc = sceneNodeKey->GetUoid().GetLocation(); |
|
plKey dlgKey = hsgResMgr::ResMgr()->NewKey( fCompPB->GetStr( kRefDialogName ), fDialogMod, nodeLoc ); |
|
|
|
fDialogMod->SetSceneNodeKey( sceneNodeKey ); |
|
|
|
// See if there's a tag to be had |
|
UInt32 id = fCompPB->GetInt( plGUITagComponent::kRefCurrIDSel ); |
|
if( id > 0 ) |
|
fDialogMod->SetTagID( id ); |
|
|
|
fProcReceiver = nil; |
|
} |
|
else |
|
{ |
|
} |
|
|
|
return true; |
|
} |
|
|
|
void plGUIDialogComponent::IMakeEveryoneOpaque(plMaxNode* node) |
|
{ |
|
plMaxNode* root = (plMaxNode *)node->GetInterface()->GetRootNode(); |
|
|
|
int i; |
|
for( i = 0; i < root->NumberOfChildren(); i++ ) |
|
IMakeEveryoneOpaqueRecur((plMaxNode*)(root->GetChildNode(i))); |
|
|
|
} |
|
|
|
void plGUIDialogComponent::IMakeEveryoneOpaqueRecur(plMaxNode* node) |
|
{ |
|
if( node->CanConvert() ) |
|
{ |
|
node->SetNoSpanReSort(true); |
|
node->SetNoSpanSort(true); |
|
|
|
int i; |
|
for( i = 0; i < node->NumberOfChildren(); i++ ) |
|
{ |
|
IMakeEveryoneOpaqueRecur((plMaxNode *)(node->GetChildNode(i))); |
|
} |
|
} |
|
} |
|
|
|
plKey plGUIDialogComponent::GetModifierKey( void ) |
|
{ |
|
if( fDialogMod != nil ) |
|
return fDialogMod->GetKey(); |
|
|
|
return nil; |
|
} |
|
|
|
bool plGUIDialogComponent::SetNotifyReceiver( plKey key ) |
|
{ |
|
if( fProcReceiver != nil ) |
|
return false; |
|
|
|
fProcReceiver = key; |
|
return true; |
|
} |
|
|
|
pfGUIDialogMod *plGUIDialogComponent::GetNodeDialog( plMaxNode *childNode ) |
|
{ |
|
UInt32 i, numComp = childNode->NumAttachedComponents( false ); |
|
for( i = 0; i < numComp; i++ ) |
|
{ |
|
plComponentBase *comp = childNode->GetAttachedComponent( i ); |
|
if( comp->ClassID() == GUI_DIALOG_COMP_CLASS_ID ) |
|
return ( (plGUIDialogComponent *)comp )->GetModifier(); |
|
} |
|
|
|
return nil; |
|
} |
|
|
|
void plGUIDialogProc::ILoadPages( HWND hWnd, IParamBlock2 *pb ) |
|
{ |
|
plAgeDescription *aged = plPageInfoUtils::GetAgeDesc( pb->GetStr( plGUIDialogComponent::kRefAgeName ) ); |
|
|
|
if( aged == nil ) |
|
return; |
|
|
|
plAgePage *page; |
|
char *selPageName = pb->GetStr( plGUIDialogComponent::kRefDialogName ); |
|
aged->SeekFirstPage(); |
|
ComboBox_ResetContent( hWnd ); |
|
|
|
while( ( page = aged->GetNextPage() ) != nil ) |
|
{ |
|
int idx = ComboBox_AddString( hWnd, page->GetName() ); |
|
if( selPageName && stricmp( page->GetName(), selPageName ) == 0 ) |
|
ComboBox_SetCurSel( hWnd, idx ); |
|
} |
|
|
|
delete aged; |
|
} |
|
|
|
BOOL plGUIDialogProc::DlgProc( TimeValue t, IParamMap2 *pmap, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
switch( msg ) |
|
{ |
|
case WM_INITDIALOG: |
|
// Load the age combo box |
|
{ |
|
int i, idx, selIdx = 0; |
|
HWND ageCombo = GetDlgItem( hWnd, IDC_GUIDLG_AGE ); |
|
hsTArray<char *> ageList; |
|
|
|
plAgeDescInterface::BuildAgeFileList( ageList ); |
|
ComboBox_ResetContent( ageCombo ); |
|
for( i = 0; i < ageList.GetCount(); i++ ) |
|
{ |
|
char ageName[ _MAX_FNAME ]; |
|
_splitpath( ageList[ i ], nil, nil, ageName, nil ); |
|
|
|
idx = ComboBox_AddString( ageCombo, ageName ); |
|
if( stricmp( ageName, pmap->GetParamBlock()->GetStr( plGUIDialogComponent::kRefAgeName ) ) == 0 ) |
|
{ |
|
selIdx = idx; |
|
} |
|
} |
|
ComboBox_SetCurSel( ageCombo, selIdx ); |
|
} |
|
|
|
ILoadPages( GetDlgItem( hWnd, IDC_GUIDLG_NAME ), pmap->GetParamBlock() ); |
|
return true; |
|
|
|
case WM_DESTROY: |
|
break; |
|
|
|
case WM_COMMAND: |
|
if( HIWORD( wParam ) == CBN_SELCHANGE ) |
|
{ |
|
if( LOWORD( wParam ) == IDC_GUIDLG_NAME ) |
|
{ |
|
int idx = SendDlgItemMessage( hWnd, IDC_GUIDLG_NAME, CB_GETCURSEL, 0, 0 ); |
|
if( idx != CB_ERR ) |
|
{ |
|
char name[ 256 ]; |
|
ComboBox_GetLBText( GetDlgItem( hWnd, IDC_GUIDLG_NAME ), idx, name ); |
|
pmap->GetParamBlock()->SetValue( plGUIDialogComponent::kRefDialogName, 0, name ); |
|
} |
|
} |
|
else if( LOWORD( wParam ) == IDC_GUIDLG_AGE ) |
|
{ |
|
int idx = SendDlgItemMessage( hWnd, IDC_GUIDLG_AGE, CB_GETCURSEL, 0, 0 ); |
|
if( idx != CB_ERR ) |
|
{ |
|
char name[ 256 ]; |
|
ComboBox_GetLBText( GetDlgItem( hWnd, IDC_GUIDLG_AGE ), idx, name ); |
|
pmap->GetParamBlock()->SetValue( plGUIDialogComponent::kRefAgeName, 0, name ); |
|
} |
|
|
|
ILoadPages( GetDlgItem( hWnd, IDC_GUIDLG_NAME ), pmap->GetParamBlock() ); |
|
} |
|
} |
|
break; |
|
} |
|
return false; |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIControl Component Base Class ////////////////////////////////////////////////////////// |
|
// |
|
// Defines a base class for all GUI control components. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
void plGUIControlBase::CollectNonDrawables( INodeTab &nonDrawables ) |
|
{ |
|
/* if( ICanHaveProxy() ) |
|
{ |
|
bool hideProxy = fCompPB->GetInt( (ParamID)kRefHideProxy ) ? true : false; |
|
if( hideProxy ) |
|
{ |
|
INode *node = fCompPB->GetINode( (ParamID)kRefProxyNode ); |
|
if( node != nil ) |
|
nonDrawables.Append( 1, &node ); |
|
} |
|
} |
|
*/ |
|
} |
|
|
|
pfGUIDialogMod *plGUIControlBase::IGetDialogMod( plMaxNode *node ) |
|
{ |
|
UInt32 i; |
|
|
|
|
|
for( i = 0; i < node->NumAttachedComponents( false ); i++ ) |
|
{ |
|
plComponentBase *comp = node->GetAttachedComponent( i, false ); |
|
if( comp->ClassID() == GUI_DIALOG_COMP_CLASS_ID ) |
|
{ |
|
// Found it! |
|
pfGUIDialogMod *dlgMod = ((plGUIDialogComponent *)comp)->GetModifier(); |
|
return dlgMod; |
|
} |
|
} |
|
|
|
return nil; |
|
} |
|
|
|
hsBool plGUIControlBase::SetupProperties( plMaxNode *pNode, plErrorMsg *pErrMsg ) |
|
{ |
|
if( INeedsDynamicText() ) |
|
{ |
|
// If we're going to be using a dynamic text layer, we need to make sure the material |
|
// is unique for every node we're applied to |
|
pNode->SetForceMaterialCopy( true ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
hsBool plGUIControlBase::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
// Create a new control |
|
fControl = IGetNewControl(); |
|
|
|
// Add it as a modifier to this node |
|
node->AddModifier( fControl, IGetUniqueName(node) ); |
|
|
|
// Look for any tag IDs |
|
UInt32 id = plGUITagComponent::GetTagIDOnNode( node ); |
|
if( id > 0 ) |
|
fControl->SetTagID( id ); |
|
|
|
// Now add it to our list of converted nodes |
|
UInt32 i = fTargetNodes.Find( node ); |
|
if( i == fTargetNodes.kMissingIndex ) |
|
{ |
|
fTargetNodes.Append( node ); |
|
fTargetControls.Append( fControl ); |
|
} |
|
else |
|
{ |
|
fTargetControls[ i ] = fControl; |
|
} |
|
|
|
return true; |
|
} |
|
|
|
hsBool plGUIControlBase::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
// Error check--make sure we're in the same room as our parent (can get confusing with the wrong |
|
// parent-child relationships) |
|
if( !node->GetParentNode()->IsRootNode() ) |
|
{ |
|
plMaxNode *parent = (plMaxNode *)node->GetParentNode(); |
|
if( parent->GetRoomKey() != node->GetRoomKey() ) |
|
{ |
|
pErrMsg->Set( true, "GUI Control Component Error", "The object %s is assigned to a different GUI dialog than its parent. Make sure both this object and its parent belong to the same GUI dialog (this control will be ignored).", node->GetName() ).Show(); |
|
pErrMsg->Set( false ); |
|
return false; |
|
} |
|
} |
|
|
|
pfGUIDialogMod *dialog = IGetDialogMod( node ); |
|
if( dialog == nil ) |
|
{ |
|
pErrMsg->Set( true, "GUI Control Component Error", "The object %s has a GUI control applied but not a GUI Dialog Component. Apply a GUI Dialog Component to this object.", node->GetName() ).Show(); |
|
pErrMsg->Set( false ); |
|
return false; |
|
} |
|
|
|
// Grab fControl from the modifier list on the node, since fControl isn't valid |
|
// between PreConvert() and Convert() (it might get called multiple times, once per node applied) |
|
UInt32 i = fTargetNodes.Find( node ); |
|
if( i == fTargetNodes.kMissingIndex ) |
|
{ |
|
pErrMsg->Set( true, "GUI Control Component Error", "The object %s somehow skipped the GUI control Pre-convert stage. Inform a programmer immediately and seek shelter.", node->GetName() ).Show(); |
|
pErrMsg->Set( false ); |
|
return false; |
|
} |
|
|
|
fControl = fTargetControls[ i ]; |
|
|
|
dialog->AddControlOnExport( fControl ); |
|
|
|
if( IHasProcRollout() ) |
|
{ |
|
// Also common for all controls: process the Procedure rollout--i.e. what kind of control proc do we get? |
|
switch( fCompPB->GetInt( kRefChoice ) ) |
|
{ |
|
case 0: |
|
// Console command |
|
fControl->SetHandler( TRACKED_NEW pfGUIConsoleCmdProc( fCompPB->GetStr( kRefConsoleCmd ) ) ); |
|
break; |
|
|
|
case 1: |
|
// Inherit from parent dialog - this is a runtime flag, so we don't bother actually setting |
|
// a handler here, except to ensure it's nil |
|
fControl->SetHandler( nil ); |
|
fControl->SetFlag( pfGUIControlMod::kInheritProcFromDlg ); |
|
break; |
|
|
|
case 2: |
|
fControl->SetHandler( TRACKED_NEW pfGUICloseDlgProc() ); |
|
break; |
|
|
|
case 3: |
|
// Do nothing. Just set a nil proc, but do NOT inherit from the dialog |
|
fControl->SetHandler( nil ); |
|
fControl->ClearFlag( pfGUIControlMod::kInheritProcFromDlg ); |
|
break; |
|
} |
|
} |
|
|
|
if( INeedsDynamicText() ) |
|
{ |
|
// We're a control that dynamically creates text, so look for the first dynamic layer |
|
// (and hopefully the ONLY one) and store it on the control |
|
Mtl *maxMaterial = hsMaterialConverter::Instance().GetBaseMtl( node ); |
|
hsTArray<plExportMaterialData> *mtlArray = hsMaterialConverter::Instance().CreateMaterialArray( maxMaterial, node, 0 ); |
|
|
|
UInt32 i, j; |
|
plDynamicTextMap *dynText = nil; |
|
plLayerInterface *layerIFace = nil; |
|
|
|
for( i = 0; i < mtlArray->GetCount() && dynText == nil; i++ ) |
|
{ |
|
hsGMaterial *plasmaMat = (*mtlArray)[ 0 ].fMaterial; |
|
|
|
for( j = 0; j < plasmaMat->GetNumLayers(); j++ ) |
|
{ |
|
layerIFace = plasmaMat->GetLayer( j ); |
|
dynText = plDynamicTextMap::ConvertNoRef( layerIFace->GetTexture() ); |
|
if( dynText != nil ) |
|
break; |
|
} |
|
} |
|
|
|
if( dynText == nil ) |
|
{ |
|
pErrMsg->Set( true, "GUI Component Error", "The object %s needs a Plasma Dynamic Text Layer in its material. " |
|
"This control will not function properly until you apply one.", node->GetName() ).Show(); |
|
pErrMsg->Set( false ); |
|
} |
|
else |
|
fControl->SetDynTextMap( layerIFace, dynText ); |
|
|
|
delete mtlArray; |
|
} |
|
|
|
if( ICanHaveProxy() ) |
|
{ |
|
// No proxy objects just yet, just options for better hit testing |
|
if( fCompPB->GetInt( kRefBetterHitTests ) ) |
|
fControl->SetFlag( pfGUIControlMod::kBetterHitTesting ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
pfGUIControlMod *plGUIControlBase::GrabControlFromObject( INode *node ) |
|
{ |
|
UInt32 i; |
|
plMaxNodeBase *maxNode = (plMaxNodeBase *)node; |
|
|
|
|
|
for( i = 0; i < maxNode->NumAttachedComponents( false ); i++ ) |
|
{ |
|
plComponentBase *comp = maxNode->GetAttachedComponent( i, false ); |
|
pfGUIControlMod *ctrl = ConvertCompToControl( comp, maxNode ); |
|
if( ctrl != nil ) |
|
return ctrl; |
|
} |
|
|
|
return nil; |
|
} |
|
|
|
// Given an INode, gives you a pointer to the GUI component if it actually is one, nil otherwise |
|
plGUIControlBase *plGUIControlBase::GetGUIComp( INode *node ) |
|
{ |
|
if( node == nil ) |
|
return nil; |
|
|
|
return GetGUIComp( ( ( plMaxNodeBase *)node )->ConvertToComponent() ); |
|
} |
|
|
|
plGUIControlBase *plGUIControlBase::GetGUIComp( plComponentBase *comp ) |
|
{ |
|
if( comp == nil ) |
|
return nil; |
|
|
|
if( comp->ClassID() == GUI_UPDOWNPAIR_CLASSID || |
|
comp->ClassID() == GUI_BUTTON_CLASSID || |
|
comp->ClassID() == GUI_DRAGGABLE_CLASSID || |
|
comp->ClassID() == GUI_LISTBOX_CLASSID || |
|
comp->ClassID() == GUI_TEXTBOX_CLASSID || |
|
comp->ClassID() == GUI_EDITBOX_CLASSID || |
|
comp->ClassID() == GUI_KNOBCTRL_CLASSID || |
|
comp->ClassID() == GUI_DRAGBAR_CLASSID || |
|
comp->ClassID() == GUI_CHECKBOX_CLASSID || |
|
comp->ClassID() == GUI_RADIOGROUP_CLASSID || |
|
comp->ClassID() == GUI_DYNDISPLAY_CLASSID || |
|
comp->ClassID() == GUI_MULTILINE_CLASSID || |
|
comp->ClassID() == GUI_PROGRESS_CLASSID || |
|
comp->ClassID() == GUI_CLICKMAP_CLASSID ) |
|
{ |
|
return (plGUIControlBase *)comp; |
|
} |
|
|
|
return nil; |
|
} |
|
|
|
pfGUIControlMod *plGUIControlBase::GrabControlMod( INode *node, INode *sceneObjectNode ) |
|
{ |
|
if( node == nil ) |
|
return nil; |
|
|
|
plComponentBase *comp = ( ( plMaxNodeBase *)node )->ConvertToComponent(); |
|
return ConvertCompToControl( comp, sceneObjectNode ); |
|
} |
|
|
|
pfGUIControlMod *plGUIControlBase::ConvertCompToControl( plComponentBase *comp, INode *sceneObjectNode ) |
|
{ |
|
plGUIControlBase *base = GetGUIComp( comp ); |
|
if( base != nil ) |
|
{ |
|
if( sceneObjectNode == nil ) |
|
{ |
|
// Not good, but if you select a component like this, it better only be applied to one object, |
|
// hence will only have one fTargetControl |
|
if( base->fTargetControls.GetCount() > 0 ) |
|
return base->fTargetControls[ 0 ]; |
|
} |
|
else |
|
{ |
|
UInt32 i = base->fTargetNodes.Find( (plMaxNode *)sceneObjectNode ); |
|
if( i == base->fTargetNodes.kMissingIndex ) |
|
return nil; |
|
|
|
return base->fTargetControls[ i ]; |
|
} |
|
} |
|
|
|
return nil; |
|
} |
|
|
|
const char *plGUIControlBase::ISetSoundIndex( ParamID checkBoxID, ParamID sndCompID, UInt8 guiCtrlEvent, plMaxNode *maxNode ) |
|
{ |
|
if( fCompPB->GetInt( checkBoxID ) ) |
|
{ |
|
plMaxNode *sndNode = (plMaxNode *)fCompPB->GetReferenceTarget( sndCompID ); |
|
if( sndNode != nil ) |
|
{ |
|
plComponentBase *comp = sndNode->ConvertToComponent(); |
|
if( comp != nil ) |
|
{ |
|
int idx = plAudioComp::GetSoundModIdx( comp, maxNode ); |
|
if( idx != -1 ) |
|
{ |
|
fControl->SetSoundIndex( guiCtrlEvent, idx ); |
|
return nil; |
|
} |
|
else |
|
return "The selected sound component could not be found on GUI control %s. Make sure you have a sound component on the same object selected."; |
|
} |
|
else |
|
return "The selected sound node on GUI control %s could not be converted to a component. Make sure you have a sound component selected."; |
|
} |
|
else |
|
return "The GUI control %s has a sound event enabled but no sound component selected. Make sure you have a sound component on the same object selected."; |
|
} |
|
|
|
return nil; |
|
} |
|
|
|
|
|
//// ParamBlock for Control Proc Rollout //////////////////////////////////////////////////////// |
|
|
|
static ParamBlockDesc2 sGUIControlProcParamTemplate |
|
( |
|
/// Main def |
|
plGUIControlBase::kBlkProc, _T("GUIControlProc"), 0, nil, P_AUTO_UI + P_MULTIMAP + P_AUTO_CONSTRUCT, plComponent::kRefComp, |
|
|
|
1, |
|
plGUIControlBase::kRollProc, IDD_COMP_GUIPROCROLLOUT, IDS_COMP_GUIPROCROLLOUT, 0, 0, nil, |
|
|
|
plGUIControlBase::kRefChoice, _T("which"), TYPE_INT, 0, 0, |
|
p_ui, plGUIControlBase::kRollProc, TYPE_RADIO, 4, IDC_GUI_CONRADIO, IDC_GUI_INHERITRADIO, IDC_GUI_CLOSERADIO, IDC_GUI_NILRADIO, |
|
p_default, 1, |
|
end, |
|
|
|
plGUIControlBase::kRefConsoleCmd, _T("ConsoleCmd"), TYPE_STRING, 0, 0, |
|
p_ui, plGUIControlBase::kRollProc, TYPE_EDITBOX, IDC_GUI_CONCMD, |
|
end, |
|
|
|
end |
|
); |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIButton Component ////////////////////////////////////////////////////////////////////// |
|
// |
|
// Defines a dialog button to be defined with the GUI manager at runtime. Belongs to exactly |
|
// one dialog, defined by parent-child relationship, also at runtime. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
class plGUIButtonProc : public ParamMap2UserDlgProc |
|
{ |
|
public: |
|
|
|
void DeleteThis() {} |
|
|
|
BOOL DlgProc( TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); |
|
}; |
|
|
|
|
|
static plGUIButtonProc gGUIButtonProc; |
|
|
|
|
|
// Class that accesses the paramblock below. |
|
class plGUIButtonComponent : public plGUIControlBase |
|
{ |
|
protected: |
|
|
|
virtual pfGUIControlMod *IGetNewControl( void ) { return TRACKED_NEW pfGUIButtonMod; } |
|
virtual bool ICanHaveProxy( void ) { return true; } |
|
|
|
public: |
|
plGUIButtonComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefConCmdRadio, |
|
kRefPythonRadio, |
|
kRefConsoleCmd, |
|
kRefAnimate, |
|
kRefAnimation, |
|
kRefMouseOverAnimate, |
|
kRefMouseOverAnimation, |
|
kRefMouseDownSound, |
|
kRefMouseDownSoundComp, |
|
kRefMouseUpSound, |
|
kRefMouseUpSoundComp, |
|
kRefMouseOverSound, |
|
kRefMouseOverSoundComp, |
|
kRefMouseOffSound, |
|
kRefMouseOffSoundComp, |
|
kRefAnimationNode, |
|
kRefAnimationNodeType, |
|
kRefMouseOverAnimationNode, |
|
kRefMouseOverAnimationNodeType, |
|
kRefDraggableChild, |
|
kRefUseDraggableChild, |
|
kRefNotifyType |
|
}; |
|
}; |
|
|
|
BOOL plGUIButtonProc::DlgProc( TimeValue t, IParamMap2 *pmap, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
|
|
switch( msg ) |
|
{ |
|
case WM_INITDIALOG: |
|
SendMessage( GetDlgItem( hWnd, IDC_COMBO_BUTTON_NOTIFYTYPE ), CB_RESETCONTENT, 0, 0 ); |
|
SendMessage( GetDlgItem( hWnd, IDC_COMBO_BUTTON_NOTIFYTYPE ), CB_ADDSTRING, 0, (LPARAM)"Button Up" ); |
|
SendMessage( GetDlgItem( hWnd, IDC_COMBO_BUTTON_NOTIFYTYPE ), CB_ADDSTRING, 0, (LPARAM)"Button Down" ); |
|
SendMessage( GetDlgItem( hWnd, IDC_COMBO_BUTTON_NOTIFYTYPE ), CB_ADDSTRING, 0, (LPARAM)"Button Down and Up" ); |
|
SendMessage( GetDlgItem( hWnd, IDC_COMBO_BUTTON_NOTIFYTYPE ), CB_SETCURSEL, pmap->GetParamBlock()->GetInt( plGUIButtonComponent::kRefNotifyType ), 0 ); |
|
return true; |
|
|
|
case WM_DESTROY: |
|
break; |
|
|
|
case WM_COMMAND: |
|
if( LOWORD( wParam ) == IDC_COMBO_BUTTON_NOTIFYTYPE ) |
|
{ |
|
if( HIWORD( wParam ) == CBN_SELCHANGE ) |
|
{ |
|
int idx = SendDlgItemMessage( hWnd, IDC_COMBO_BUTTON_NOTIFYTYPE, CB_GETCURSEL, 0, 0 ); |
|
pmap->GetParamBlock()->SetValue( plGUIButtonComponent::kRefNotifyType, 0, idx ); |
|
} |
|
} |
|
break; |
|
} |
|
return false; |
|
} |
|
|
|
class plGUIButtonAccessor : public PBAccessor |
|
{ |
|
public: |
|
void Set( PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t ) |
|
{ |
|
if( id == plGUIButtonComponent::kRefAnimation || |
|
id == plGUIButtonComponent::kRefMouseOverAnimation || |
|
id == plGUIButtonComponent::kRefMouseDownSoundComp || |
|
id == plGUIButtonComponent::kRefMouseUpSoundComp || |
|
id == plGUIButtonComponent::kRefMouseOverSoundComp || |
|
id == plGUIButtonComponent::kRefMouseOffSoundComp || |
|
id == plGUIButtonComponent::kRefAnimationNode || |
|
id == plGUIButtonComponent::kRefMouseOverAnimationNode ) |
|
{ |
|
plGUIButtonComponent *comp = (plGUIButtonComponent *)owner; |
|
comp->NotifyDependents( FOREVER, PART_ALL, REFMSG_USER_COMP_REF_CHANGED ); |
|
} |
|
} |
|
}; |
|
|
|
Class_ID sBtnClassesToSelect[] = { ANIM_COMP_CID, ANIM_GROUP_COMP_CID, plGUISingleCtrlDlgProc::kEndClassList }; |
|
Class_ID sBtnSndClassesToSelect[] = { GUI_SOUND_COMPONENT_ID, plGUISingleCtrlDlgProc::kEndClassList }; |
|
|
|
Class_ID sBtnDragClassesToSelect[] = { GUI_DRAGGABLE_CLASSID, plGUISingleCtrlDlgProc::kEndClassList }; |
|
|
|
static plGUIButtonAccessor sGUIButtonAccessor; |
|
|
|
static plGUISingleCtrlDlgProc sGUIButtonSndAProc( plGUIButtonComponent::kRefMouseDownSoundComp, IDC_GUI_MDOWNSNDCOMP, |
|
"Select the sound to play when the mouse clicks this button", sBtnSndClassesToSelect ); |
|
static plGUISingleCtrlDlgProc sGUIButtonSndBProc( plGUIButtonComponent::kRefMouseUpSoundComp, IDC_GUI_MUPSNDCOMP, |
|
"Select the sound to play when the mouse lets up on this button", sBtnSndClassesToSelect ); |
|
static plGUISingleCtrlDlgProc sGUIButtonSndCProc( plGUIButtonComponent::kRefMouseOverSoundComp, IDC_GUI_MOVERSNDCOMP, |
|
"Select the sound to play when the mouse moves over this button", sBtnSndClassesToSelect ); |
|
static plGUISingleCtrlDlgProc sGUIButtonSndDProc( plGUIButtonComponent::kRefMouseOffSoundComp, IDC_GUI_MOFFSNDCOMP, |
|
"Select the sound to play when the mouse moves off of this button", sBtnSndClassesToSelect ); |
|
|
|
static plGUISingleCtrlDlgProc sGUIButtonDragChildProc( plGUIButtonComponent::kRefDraggableChild, IDC_GUI_DRAGCHILD, |
|
"Select the draggable to use when the mouse is dragged off of this button", sBtnDragClassesToSelect ); |
|
|
|
static plGUISingleCtrlDlgProc *sGUIButtonSubProcs[] = { &sGUIButtonSndAProc, &sGUIButtonSndBProc, |
|
&sGUIButtonSndCProc, &sGUIButtonSndDProc, |
|
&sGUIButtonDragChildProc, nil }; |
|
static ParamMap2UserDlgProc *sGUIButtonSubSubProcs[] = { &gGUIButtonProc, nil }; |
|
|
|
static plGUIMultipleCtrlDlgProc sGUIButtonSels( sGUIButtonSubProcs, sGUIButtonSubSubProcs ); |
|
|
|
static plPlasmaAnimSelectDlgProc sGUIButtonAnimA( plGUIButtonComponent::kRefAnimation, IDC_GUI_COMPSELBTN, |
|
plGUIButtonComponent::kRefAnimationNode, plGUIButtonComponent::kRefAnimationNodeType, IDC_GUI_ANIMNODESEL, |
|
"Select the animation to play when this button is clicked", &sGUIButtonSels ); |
|
static plPlasmaAnimSelectDlgProc sGUIButtonProc( plGUIButtonComponent::kRefMouseOverAnimation, IDC_GUI_COMPSELBTN2, |
|
plGUIButtonComponent::kRefMouseOverAnimationNode, plGUIButtonComponent::kRefMouseOverAnimationNodeType, IDC_GUI_ANIMNODESEL2, |
|
"Select the animation to play when the mouse moves over this button", &sGUIButtonAnimA ); |
|
|
|
|
|
#define GUI_SOUND_REF( comp, evt, allCapsEvt ) \ |
|
comp##::kRefMouse##evt##Sound, _T( "mouse##evt##Sound" ), TYPE_BOOL, 0, 0, \ |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_M##allCapsEvt##SND, \ |
|
p_default, FALSE, \ |
|
p_enable_ctrls, 1, comp##::kRefMouse##evt##SoundComp, \ |
|
end, \ |
|
comp##::kRefMouse##evt##SoundComp, _T("mouse##evt##SoundComp"), TYPE_INODE, 0, 0, \ |
|
p_accessor, &sGUIButtonAccessor, \ |
|
end |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIButtonComponent, gGUIButtonDesc, "GUI Button", "GUIButton", COMP_TYPE_GUI, GUI_BUTTON_CLASSID ) |
|
|
|
ParamBlockDesc2 gGUIButtonBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUIButton"), 0, &gGUIButtonDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_INCLUDE_PARAMS + P_MULTIMAP, plComponent::kRefComp, |
|
|
|
3, |
|
plGUIControlBase::kRollMain, IDD_COMP_GUIBUTTON, IDS_COMP_GUIBUTTON, 0, 0, &sGUIButtonProc, |
|
plGUIControlBase::kRollProc, IDD_COMP_GUIPROCROLLOUT, IDS_COMP_GUIPROCROLLOUT, 0, 0, nil, |
|
sGUIProxyParamHeader, |
|
|
|
&sGUIControlProcParamTemplate, |
|
|
|
plGUIButtonComponent::kRefAnimate, _T( "animate" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_ANIMATE, |
|
p_default, FALSE, |
|
p_enable_ctrls, 1, plGUIButtonComponent::kRefAnimation, |
|
end, |
|
|
|
plGUIButtonComponent::kRefAnimation, _T("animation"), TYPE_INODE, 0, 0, |
|
p_prompt, IDS_COMP_GUI_SELECTANIM, |
|
p_accessor, &sGUIButtonAccessor, |
|
end, |
|
|
|
plGUIButtonComponent::kRefMouseOverAnimate, _T( "mouseOverAnimate" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_MOUSEOVERANIM, |
|
p_default, FALSE, |
|
p_enable_ctrls, 1, plGUIButtonComponent::kRefMouseOverAnimation, |
|
end, |
|
|
|
plGUIButtonComponent::kRefMouseOverAnimation, _T("mouseOverAnimation"), TYPE_INODE, 0, 0, |
|
p_prompt, IDS_COMP_GUI_SELECTMOUSEOVERANIM, |
|
p_accessor, &sGUIButtonAccessor, |
|
end, |
|
|
|
GUI_SOUND_REF( plGUIButtonComponent, Down, DOWN ), |
|
GUI_SOUND_REF( plGUIButtonComponent, Up, UP ), |
|
GUI_SOUND_REF( plGUIButtonComponent, Over, OVER ), |
|
GUI_SOUND_REF( plGUIButtonComponent, Off, OFF ), |
|
|
|
sGUIProxyParamTemplate, |
|
|
|
plGUIButtonComponent::kRefAnimationNode, _T("animationNode"), TYPE_INODE, 0, 0, |
|
p_accessor, &sGUIButtonAccessor, |
|
end, |
|
|
|
plGUIButtonComponent::kRefAnimationNodeType, _T("animationNodeType"), TYPE_INT, 0, 0, |
|
p_default, plAnimObjInterface::kUseOwnerNode, |
|
end, |
|
|
|
plGUIButtonComponent::kRefMouseOverAnimationNode, _T("moAnimationNode"), TYPE_INODE, 0, 0, |
|
p_accessor, &sGUIButtonAccessor, |
|
end, |
|
|
|
plGUIButtonComponent::kRefMouseOverAnimationNodeType, _T("moAnimationNodeType"), TYPE_INT, 0, 0, |
|
p_default, plAnimObjInterface::kUseOwnerNode, |
|
end, |
|
|
|
plGUIButtonComponent::kRefUseDraggableChild, _T( "useDragChild" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_USEDRAGCHILD, |
|
p_default, FALSE, |
|
p_enable_ctrls, 1, plGUIButtonComponent::kRefDraggableChild, |
|
end, |
|
|
|
plGUIButtonComponent::kRefDraggableChild, _T( "dragChild" ), TYPE_INODE, 0, 0, |
|
p_accessor, &sGUIButtonAccessor, |
|
end, |
|
|
|
plGUIButtonComponent::kRefNotifyType, _T("notifyType"), TYPE_INT, 0, 0, |
|
p_default, pfGUIButtonMod::kNotifyOnUp, |
|
end, |
|
end |
|
); |
|
|
|
plGUIButtonComponent::plGUIButtonComponent() |
|
{ |
|
fClassDesc = &gGUIButtonDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIButtonComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( fCompPB->GetInt( kRefAnimate ) ) |
|
{ |
|
plAnimObjInterface *iface = plAnimComponentBase::GetAnimInterface( fCompPB->GetINode( kRefAnimation ) ); |
|
if( iface != nil && iface->MightRequireSeparateMaterial() ) |
|
{ |
|
INode *restrict = ( fCompPB->GetInt( kRefAnimationNodeType ) == plAnimObjInterface::kUseParamBlockNode ) |
|
? fCompPB->GetINode( kRefAnimationNode ) |
|
: (INode *)node; |
|
|
|
if( restrict != nil ) |
|
{ |
|
node->SetForceMaterialCopy( true ); |
|
} |
|
} |
|
} |
|
|
|
if( fCompPB->GetInt( kRefMouseOverAnimate ) ) |
|
{ |
|
plAnimObjInterface *iface = plAnimComponentBase::GetAnimInterface( fCompPB->GetINode( kRefMouseOverAnimation ) ); |
|
if( iface != nil && iface->MightRequireSeparateMaterial() ) |
|
{ |
|
INode *restrict = ( fCompPB->GetInt( kRefMouseOverAnimationNodeType ) == plAnimObjInterface::kUseParamBlockNode ) |
|
? fCompPB->GetINode( kRefMouseOverAnimationNode ) |
|
: (INode *)node; |
|
|
|
if( restrict != nil ) |
|
{ |
|
node->SetForceMaterialCopy( true ); |
|
} |
|
} |
|
} |
|
|
|
return plGUIControlBase::SetupProperties( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIButtonComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIButtonComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( !plGUIControlBase::Convert( node, pErrMsg ) ) |
|
return false; |
|
|
|
pfGUIButtonMod *button = (pfGUIButtonMod *)fControl; |
|
|
|
// set the notify type |
|
button->SetNotifyType(fCompPB->GetInt( kRefNotifyType )); |
|
|
|
if( fCompPB->GetInt( kRefAnimate ) ) |
|
{ |
|
plAnimObjInterface *iface = plAnimComponentBase::GetAnimInterface( fCompPB->GetINode( kRefAnimation ) ); |
|
if( iface != nil ) |
|
{ |
|
INode *restrict = ( fCompPB->GetInt( kRefAnimationNodeType ) == plAnimObjInterface::kUseParamBlockNode ) |
|
? fCompPB->GetINode( kRefAnimationNode ) |
|
: (INode *)node; |
|
|
|
|
|
hsTArray<plKey> keys; |
|
if( iface->GetKeyList( restrict, keys ) && keys.GetCount() > 0 ) |
|
button->SetAnimationKeys( keys, iface->GetIfaceSegmentName( false ) ); |
|
} |
|
} |
|
|
|
if( fCompPB->GetInt( kRefMouseOverAnimate ) ) |
|
{ |
|
plAnimObjInterface *iface = plAnimComponentBase::GetAnimInterface( fCompPB->GetINode( kRefMouseOverAnimation ) ); |
|
if( iface != nil ) |
|
{ |
|
INode *restrict = ( fCompPB->GetInt( kRefMouseOverAnimationNodeType ) == plAnimObjInterface::kUseParamBlockNode ) |
|
? fCompPB->GetINode( kRefMouseOverAnimationNode ) |
|
: (INode *)node; |
|
|
|
|
|
hsTArray<plKey> keys; |
|
if( iface->GetKeyList( restrict, keys ) && keys.GetCount() > 0 ) |
|
button->SetMouseOverAnimKeys( keys, iface->GetIfaceSegmentName( false ) ); |
|
} |
|
} |
|
|
|
// Do sound stuff |
|
const char *errMsg1 = ISetSoundIndex( kRefMouseDownSound, kRefMouseDownSoundComp, pfGUIButtonMod::kMouseDown, node ); |
|
const char *errMsg2 = ISetSoundIndex( kRefMouseUpSound, kRefMouseUpSoundComp, pfGUIButtonMod::kMouseUp, node ); |
|
const char *errMsg3 = ISetSoundIndex( kRefMouseOverSound, kRefMouseOverSoundComp, pfGUIButtonMod::kMouseOver, node ); |
|
const char *errMsg4 = ISetSoundIndex( kRefMouseOffSound, kRefMouseOffSoundComp, pfGUIButtonMod::kMouseOff, node ); |
|
|
|
const char *errMsg = ( errMsg1 != nil ) ? errMsg1 : ( errMsg2 != nil ) ? errMsg2 : ( errMsg3 != nil ) ? errMsg3 : errMsg4; |
|
if( errMsg != nil ) |
|
{ |
|
pErrMsg->Set( true, "GUI Sound Event Error", errMsg, node->GetName() ).Show(); |
|
pErrMsg->Set( false ); |
|
} |
|
|
|
if( fCompPB->GetInt( kRefUseDraggableChild ) ) |
|
{ |
|
pfGUIDraggableMod *dragChild = pfGUIDraggableMod::ConvertNoRef( GrabControlMod( fCompPB->GetINode( kRefDraggableChild ) ) ); |
|
if( dragChild != nil ) |
|
{ |
|
hsgResMgr::ResMgr()->AddViaNotify( dragChild->GetKey(), |
|
new plGenRefMsg( button->GetKey(), plRefMsg::kOnCreate, -1, pfGUIButtonMod::kRefDraggable ), plRefFlags::kActiveRef ); |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUICheckBox Component ////////////////////////////////////////////////////////////////////// |
|
// |
|
// Defines a dialog button to be defined with the GUI manager at runtime. Belongs to exactly |
|
// one dialog, defined by parent-child relationship, also at runtime. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Class that accesses the paramblock below. |
|
class plGUICheckBoxComponent : public plGUIControlBase |
|
{ |
|
protected: |
|
|
|
virtual pfGUIControlMod *IGetNewControl( void ) { return TRACKED_NEW pfGUICheckBoxCtrl; } |
|
virtual bool ICanHaveProxy( void ) { return true; } |
|
|
|
public: |
|
plGUICheckBoxComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefConCmdRadio, |
|
kRefPythonRadio, |
|
kRefConsoleCmd, |
|
kRefAnimate, |
|
kRefAnimation, |
|
kRefAnimationNode, |
|
kRefAnimationNodeType, |
|
kRefMouseDownSound, |
|
kRefMouseDownSoundComp, |
|
kRefMouseUpSound, |
|
kRefMouseUpSoundComp, |
|
kRefMouseOverSound, |
|
kRefMouseOverSoundComp, |
|
kRefMouseOffSound, |
|
kRefMouseOffSoundComp, |
|
}; |
|
}; |
|
|
|
class plGUICheckBoxAccessor : public PBAccessor |
|
{ |
|
public: |
|
void Set( PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t ) |
|
{ |
|
if( id == plGUICheckBoxComponent::kRefAnimation || |
|
id == plGUICheckBoxComponent::kRefMouseDownSoundComp || |
|
id == plGUICheckBoxComponent::kRefMouseUpSoundComp || |
|
id == plGUICheckBoxComponent::kRefMouseOverSoundComp || |
|
id == plGUICheckBoxComponent::kRefMouseOffSoundComp ) |
|
{ |
|
plGUICheckBoxComponent *comp = (plGUICheckBoxComponent *)owner; |
|
comp->NotifyDependents( FOREVER, PART_ALL, REFMSG_USER_COMP_REF_CHANGED ); |
|
} |
|
} |
|
}; |
|
static plGUICheckBoxAccessor sGUICheckBoxAccessor; |
|
|
|
static plGUISingleCtrlDlgProc sGUICheckSndAProc( plGUICheckBoxComponent::kRefMouseDownSoundComp, IDC_GUI_MDOWNSNDCOMP, |
|
"Select the sound to play when the mouse clicks this button", sBtnSndClassesToSelect ); |
|
static plGUISingleCtrlDlgProc sGUICheckSndBProc( plGUICheckBoxComponent::kRefMouseUpSoundComp, IDC_GUI_MUPSNDCOMP, |
|
"Select the sound to play when the mouse lets up on this button", sBtnSndClassesToSelect ); |
|
static plGUISingleCtrlDlgProc sGUICheckSndCProc( plGUICheckBoxComponent::kRefMouseOverSoundComp, IDC_GUI_MOVERSNDCOMP, |
|
"Select the sound to play when the mouse moves over this button", sBtnSndClassesToSelect ); |
|
static plGUISingleCtrlDlgProc sGUICheckSndDProc( plGUICheckBoxComponent::kRefMouseOffSoundComp, IDC_GUI_MOFFSNDCOMP, |
|
"Select the sound to play when the mouse moves off of this button", sBtnSndClassesToSelect ); |
|
|
|
static plGUISingleCtrlDlgProc *sGUICheckSubProcs[] = { &sGUICheckSndAProc, &sGUICheckSndBProc, |
|
&sGUICheckSndCProc, &sGUICheckSndDProc, nil }; |
|
|
|
static plGUIMultipleCtrlDlgProc sGUICheckSels( sGUICheckSubProcs ); |
|
|
|
static plPlasmaAnimSelectDlgProc sGUICheckBoxProc( plGUICheckBoxComponent::kRefAnimation, IDC_GUI_COMPSELBTN, |
|
plGUICheckBoxComponent::kRefAnimationNode, plGUICheckBoxComponent::kRefAnimationNodeType, IDC_GUI_ANIMNODESEL, |
|
"Select the animation to play when this check box is clicked", &sGUICheckSels ); |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUICheckBoxComponent, gGUICheckBoxDesc, "GUI CheckBox", "GUICheckBox", COMP_TYPE_GUI, GUI_CHECKBOX_CLASSID ) |
|
|
|
ParamBlockDesc2 gGUICheckBoxBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUICheckBox"), 0, &gGUICheckBoxDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP + P_INCLUDE_PARAMS, plComponent::kRefComp, |
|
|
|
3, |
|
plGUIControlBase::kRollMain, IDD_COMP_GUIBUTTON, IDS_COMP_GUICHECKBOX, 0, 0, &sGUICheckBoxProc, |
|
plGUIControlBase::kRollProc, IDD_COMP_GUIPROCROLLOUT, IDS_COMP_GUIPROCROLLOUT, 0, 0, nil, |
|
|
|
sGUIProxyParamHeader, |
|
|
|
&sGUIControlProcParamTemplate, |
|
|
|
plGUICheckBoxComponent::kRefAnimate, _T( "animate" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_ANIMATE, |
|
p_default, FALSE, |
|
p_enable_ctrls, 1, plGUIButtonComponent::kRefAnimation, |
|
end, |
|
|
|
plGUICheckBoxComponent::kRefAnimation, _T("animation"), TYPE_INODE, 0, 0, |
|
p_prompt, IDS_COMP_GUI_SELECTANIM, |
|
p_accessor, &sGUICheckBoxAccessor, |
|
end, |
|
|
|
sGUIProxyParamTemplate, |
|
|
|
plGUICheckBoxComponent::kRefAnimationNode, _T("animationNode"), TYPE_INODE, 0, 0, |
|
p_accessor, &sGUIButtonAccessor, |
|
end, |
|
|
|
plGUICheckBoxComponent::kRefAnimationNodeType, _T("animationNodeType"), TYPE_INT, 0, 0, |
|
p_default, plAnimObjInterface::kUseOwnerNode, |
|
end, |
|
|
|
GUI_SOUND_REF( plGUICheckBoxComponent, Down, DOWN ), |
|
GUI_SOUND_REF( plGUICheckBoxComponent, Up, UP ), |
|
GUI_SOUND_REF( plGUICheckBoxComponent, Over, OVER ), |
|
GUI_SOUND_REF( plGUICheckBoxComponent, Off, OFF ), |
|
|
|
end |
|
); |
|
|
|
plGUICheckBoxComponent::plGUICheckBoxComponent() |
|
{ |
|
fClassDesc = &gGUICheckBoxDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUICheckBoxComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( fCompPB->GetInt( kRefAnimate ) ) |
|
{ |
|
plAnimObjInterface *iface = plAnimComponentBase::GetAnimInterface( fCompPB->GetINode( kRefAnimation ) ); |
|
if( iface != nil && iface->MightRequireSeparateMaterial() ) |
|
{ |
|
INode *restrict = ( fCompPB->GetInt( kRefAnimationNodeType ) == plAnimObjInterface::kUseParamBlockNode ) |
|
? fCompPB->GetINode( kRefAnimationNode ) |
|
: (INode *)node; |
|
|
|
if( restrict != nil ) |
|
{ |
|
node->SetForceMaterialCopy( true ); |
|
} |
|
} |
|
} |
|
|
|
return plGUIControlBase::SetupProperties( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUICheckBoxComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUICheckBoxComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( !plGUIControlBase::Convert( node, pErrMsg ) ) |
|
return false; |
|
|
|
pfGUICheckBoxCtrl *button = (pfGUICheckBoxCtrl *)fControl; |
|
|
|
if( fCompPB->GetInt( kRefAnimate ) ) |
|
{ |
|
plAnimObjInterface *iface = plAnimComponentBase::GetAnimInterface( fCompPB->GetINode( kRefAnimation ) ); |
|
if( iface != nil ) |
|
{ |
|
INode *restrict = ( fCompPB->GetInt( kRefAnimationNodeType ) == plAnimObjInterface::kUseParamBlockNode ) |
|
? fCompPB->GetINode( kRefAnimationNode ) |
|
: (INode *)node; |
|
|
|
|
|
hsTArray<plKey> keys; |
|
if( iface->GetKeyList( restrict, keys ) && keys.GetCount() > 0 ) |
|
button->SetAnimationKeys( keys, iface->GetIfaceSegmentName( false ) ); |
|
} |
|
} |
|
|
|
// Do sound stuff |
|
const char *errMsg1 = ISetSoundIndex( kRefMouseDownSound, kRefMouseDownSoundComp, pfGUICheckBoxCtrl::kMouseDown, node ); |
|
const char *errMsg2 = ISetSoundIndex( kRefMouseUpSound, kRefMouseUpSoundComp, pfGUICheckBoxCtrl::kMouseUp, node ); |
|
const char *errMsg3 = ISetSoundIndex( kRefMouseOverSound, kRefMouseOverSoundComp, pfGUICheckBoxCtrl::kMouseOver, node ); |
|
const char *errMsg4 = ISetSoundIndex( kRefMouseOffSound, kRefMouseOffSoundComp, pfGUICheckBoxCtrl::kMouseOff, node ); |
|
|
|
const char *errMsg = ( errMsg1 != nil ) ? errMsg1 : ( errMsg2 != nil ) ? errMsg2 : ( errMsg3 != nil ) ? errMsg3 : errMsg4; |
|
if( errMsg != nil ) |
|
{ |
|
pErrMsg->Set( true, "GUI Sound Event Error", errMsg, node->GetName() ).Show(); |
|
pErrMsg->Set( false ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIDraggable Component /////////////////////////////////////////////////////////////////// |
|
// |
|
// GUI element that can be dragged anywhere in the 2D viewing plane. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Class that accesses the paramblock below. |
|
class plGUIDraggableComponent : public plGUIControlBase |
|
{ |
|
protected: |
|
|
|
virtual pfGUIControlMod *IGetNewControl( void ) { return TRACKED_NEW pfGUIDraggableMod; } |
|
virtual bool ICanHaveProxy( void ) { return true; } |
|
|
|
public: |
|
plGUIDraggableComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefReportDragging, |
|
kRefHideCursor, |
|
kRefAlwaysSnap |
|
}; |
|
}; |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIDraggableComponent, gGUIDraggableDesc, "GUI Draggable", "GUIDraggable", COMP_TYPE_GUI, GUI_DRAGGABLE_CLASSID ) |
|
|
|
ParamBlockDesc2 gGUIDraggableBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUIDraggable"), 0, &gGUIDraggableDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP + P_INCLUDE_PARAMS, plComponent::kRefComp, |
|
|
|
3, |
|
plGUIControlBase::kRollMain, IDD_COMP_GUIDRAGGABLE, IDS_COMP_GUIDRAGGABLE, 0, 0, NULL, |
|
plGUIControlBase::kRollProc, IDD_COMP_GUIPROCROLLOUT, IDS_COMP_GUIPROCROLLOUT, 0, 0, nil, |
|
|
|
sGUIProxyParamHeader, |
|
|
|
&sGUIControlProcParamTemplate, |
|
|
|
sGUIProxyParamTemplate, |
|
|
|
plGUIDraggableComponent::kRefReportDragging, _T("reportWhileDragging"), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_REPORTDRAG, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIDraggableComponent::kRefHideCursor, _T("hideCursorWhileDragging"), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_HIDECURSOR, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIDraggableComponent::kRefAlwaysSnap, _T("alwaysSnapBackToStart"), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_SNAPSTART, |
|
p_default, FALSE, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plGUIDraggableComponent::plGUIDraggableComponent() |
|
{ |
|
fClassDesc = &gGUIDraggableDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIDraggableComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
node->SetForceLocal( true ); |
|
return plGUIControlBase::SetupProperties( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIDraggableComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIDraggableComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( !plGUIControlBase::Convert( node, pErrMsg ) ) |
|
return false; |
|
|
|
pfGUIDraggableMod *ctrl = (pfGUIDraggableMod *)fControl; |
|
|
|
if( fCompPB->GetInt( kRefReportDragging ) ) |
|
ctrl->SetFlag( pfGUIDraggableMod::kReportDragging ); |
|
|
|
if( fCompPB->GetInt( kRefHideCursor ) ) |
|
ctrl->SetFlag( pfGUIDraggableMod::kHideCursorWhileDragging ); |
|
|
|
if( fCompPB->GetInt( kRefAlwaysSnap ) ) |
|
ctrl->SetFlag( pfGUIDraggableMod::kAlwaysSnapBackToStart ); |
|
|
|
return true; |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIKnobCtrl Component /////////////////////////////////////////////////////////////////// |
|
// |
|
// GUI element that can be dragged anywhere in the 2D viewing plane. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Class that accesses the paramblock below. |
|
class plGUIKnobCtrlComponent : public plGUIControlBase |
|
{ |
|
protected: |
|
|
|
virtual pfGUIControlMod *IGetNewControl( void ) { return TRACKED_NEW pfGUIKnobCtrl; } |
|
virtual bool ICanHaveProxy( void ) { return true; } |
|
|
|
hsBool IGrabAnimationRange( plMaxNode *node, plErrorMsg *pErrMsg, hsMatrix44 &startL2W, hsMatrix44 &endL2W ); |
|
|
|
public: |
|
plGUIKnobCtrlComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefMinValue, |
|
kRefMaxValue, |
|
kRefStep, |
|
kReverseValues, |
|
kRefOrientation, |
|
kRefMouseMapping, |
|
kRefTriggerOnMouseUp, |
|
kRefAnimation, |
|
kRefAnimationNode, |
|
kRefAnimationNodeType |
|
}; |
|
}; |
|
|
|
static plPlasmaAnimSelectDlgProc sGUIKnobCtrlProc( plGUIKnobCtrlComponent::kRefAnimation, IDC_GUI_COMPSELBTN, |
|
plGUIKnobCtrlComponent::kRefAnimationNode, plGUIKnobCtrlComponent::kRefAnimationNodeType, IDC_GUI_ANIMNODESEL, |
|
"Select the animation to use when displaying this knob control", nil ); |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIKnobCtrlComponent, gGUIKnobCtrlDesc, "GUI Knob Control", "GUIKnobCtrl", COMP_TYPE_GUI, GUI_KNOBCTRL_CLASSID ) |
|
|
|
ParamBlockDesc2 gGUIKnobCtrlBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUIKnobCtrl"), 0, &gGUIKnobCtrlDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP + P_INCLUDE_PARAMS, plComponent::kRefComp, |
|
|
|
3, |
|
plGUIControlBase::kRollMain, IDD_COMP_GUIKNOB, IDS_COMP_GUIKNOB, 0, 0, &sGUIKnobCtrlProc, |
|
plGUIControlBase::kRollProc, IDD_COMP_GUIPROCROLLOUT, IDS_COMP_GUIPROCROLLOUT, 0, 0, nil, |
|
|
|
sGUIProxyParamHeader, |
|
|
|
&sGUIControlProcParamTemplate, |
|
|
|
plGUIKnobCtrlComponent::kRefMinValue, _T("minValue"), TYPE_FLOAT, 0, 0, |
|
p_default, 0.0f, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_GUI_LOWER, IDC_GUI_LOWER_SPIN, SPIN_AUTOSCALE, |
|
end, |
|
|
|
plGUIKnobCtrlComponent::kRefMaxValue, _T("maxValue"), TYPE_FLOAT, 0, 0, |
|
p_default, 10.0f, |
|
p_range, -10000.f, 10000.f, // WHY do we even need to specify this? |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_GUI_UPPER, IDC_GUI_UPPER_SPIN, SPIN_AUTOSCALE, |
|
end, |
|
|
|
plGUIKnobCtrlComponent::kRefStep, _T("step"), TYPE_FLOAT, 0, 0, |
|
p_default, 1.0f, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_GUI_STEP, IDC_GUI_STEP_SPIN, SPIN_AUTOSCALE, |
|
end, |
|
|
|
plGUIKnobCtrlComponent::kReverseValues, _T("reverseValues"), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_REVERSE, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIKnobCtrlComponent::kRefOrientation, _T("orientation"), TYPE_INT, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_RADIO, 2, IDC_ORIENTATION_RADIO, IDC_ORIENTATION_RADIO2, |
|
p_default, 0, |
|
end, |
|
|
|
plGUIKnobCtrlComponent::kRefMouseMapping, _T("mouseMapping"), TYPE_INT, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_RADIO, 3, IDC_GUI_MOUSEMAPREL, IDC_GUI_MOUSEMAPANIM, IDC_GUI_MOUSEMAPSCRN, |
|
p_default, 0, |
|
end, |
|
|
|
plGUIKnobCtrlComponent::kRefTriggerOnMouseUp, _T("triggerOnMouseUp"), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_TRIGGERONUP, |
|
p_default, FALSE, |
|
end, |
|
|
|
sGUIProxyParamTemplate, |
|
|
|
plGUIKnobCtrlComponent::kRefAnimation, _T("animation"), TYPE_INODE, 0, 0, |
|
p_prompt, IDS_COMP_GUI_SELECTANIM, |
|
end, |
|
|
|
plGUIKnobCtrlComponent::kRefAnimationNode, _T("animationNode"), TYPE_INODE, 0, 0, |
|
end, |
|
|
|
plGUIKnobCtrlComponent::kRefAnimationNodeType, _T("animationNodeType"), TYPE_INT, 0, 0, |
|
p_default, plAnimObjInterface::kUseOwnerNode, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plGUIKnobCtrlComponent::plGUIKnobCtrlComponent() |
|
{ |
|
fClassDesc = &gGUIKnobCtrlDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
hsBool plGUIKnobCtrlComponent::IGrabAnimationRange( plMaxNode *node, plErrorMsg *pErrMsg, hsMatrix44 &startL2W, hsMatrix44 &endL2W ) |
|
{ |
|
hsBool result = false; |
|
|
|
|
|
// Get the affine parts and the TM Controller |
|
plSceneObject *obj = node->GetSceneObject(); |
|
hsAffineParts * parts = TRACKED_NEW hsAffineParts; |
|
plController* tmc = hsControlConverter::Instance().ConvertTMAnim(obj, node, parts); |
|
|
|
if (tmc) |
|
{ |
|
plMatrixControllerChannel *channel = TRACKED_NEW plMatrixControllerChannel(tmc, parts); |
|
|
|
hsScalar length = tmc->GetLength(); |
|
|
|
startL2W = channel->Value( 0.f ); |
|
endL2W = channel->Value( length ); |
|
|
|
delete channel; |
|
result = true; |
|
} |
|
|
|
delete parts; // We copy this over, so no need to keep it around |
|
return result; |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIKnobCtrlComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
node->SetForceLocal( true ); |
|
|
|
plAnimObjInterface *iface = plAnimComponentBase::GetAnimInterface( fCompPB->GetINode( kRefAnimation ) ); |
|
if( iface != nil && iface->MightRequireSeparateMaterial() ) |
|
{ |
|
INode *restrict = ( fCompPB->GetInt( kRefAnimationNodeType ) == plAnimObjInterface::kUseParamBlockNode ) |
|
? fCompPB->GetINode( kRefAnimationNode ) |
|
: (INode *)node; |
|
|
|
if( restrict != nil ) |
|
{ |
|
node->SetForceMaterialCopy( true ); |
|
} |
|
} |
|
|
|
return plGUIControlBase::SetupProperties( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIKnobCtrlComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
// For hackery below (see warning below) |
|
#include "../plAvatar/plAGMasterMod.h" |
|
|
|
hsBool plGUIKnobCtrlComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( !plGUIControlBase::Convert( node, pErrMsg ) ) |
|
return false; |
|
|
|
pfGUIKnobCtrl *ctrl = (pfGUIKnobCtrl *)fControl; |
|
|
|
ctrl->SetRange( fCompPB->GetFloat( kRefMinValue ), fCompPB->GetFloat( kRefMaxValue ) ); |
|
ctrl->SetStep( fCompPB->GetFloat( kRefStep ) ); |
|
|
|
if( fCompPB->GetInt( kReverseValues ) ) |
|
ctrl->SetFlag( pfGUIKnobCtrl::kReverseValues ); |
|
|
|
// Get the animation to use |
|
plAnimObjInterface *iface = plAnimComponentBase::GetAnimInterface( fCompPB->GetINode( kRefAnimation ) ); |
|
if( iface != nil ) |
|
{ |
|
INode *restrict = ( fCompPB->GetInt( kRefAnimationNodeType ) == plAnimObjInterface::kUseParamBlockNode ) |
|
? fCompPB->GetINode( kRefAnimationNode ) |
|
: (INode *)node; |
|
|
|
|
|
hsTArray<plKey> keys; |
|
if( iface->GetKeyList( restrict, keys ) && keys.GetCount() > 0 ) |
|
ctrl->SetAnimationKeys( keys, iface->GetIfaceSegmentName( false ) ); |
|
} |
|
else |
|
{ |
|
// HACKERY WARNING: Old knobs assumed the animation was just the same one applied to our node, |
|
// so to avoid breaking old formats, if we can't grab an animObjInterface, we just grab the key |
|
// of the master mod of our node, like we would've before |
|
plAGMasterMod *master = node->GetAGMasterMod(); |
|
hsTArray<plKey> keys; |
|
keys.Append( master->GetKey() ); |
|
ctrl->SetAnimationKeys( keys, ENTIRE_ANIMATION_NAME ); |
|
} |
|
|
|
if( fCompPB->GetInt( kRefOrientation ) == 1 ) |
|
ctrl->SetFlag( pfGUIKnobCtrl::kLeftRightOrientation ); |
|
|
|
hsMatrix44 startL2W, endL2W; |
|
switch( fCompPB->GetInt( kRefMouseMapping ) ) |
|
{ |
|
case 0: // Default, normal (old) relative behavior |
|
break; |
|
case 1: // Map to the range of animation positions |
|
if( !IGrabAnimationRange( node, pErrMsg, startL2W, endL2W ) ) |
|
{ |
|
pErrMsg->Set( true, "Unable to grab animation range for the GUI Knob Control %s. The Map-To-Screen-Range feature will be disabled.", node->GetName() ).Show(); |
|
pErrMsg->Set( false ); |
|
} |
|
else |
|
{ |
|
hsPoint3 startPos = startL2W.GetTranslate(); |
|
hsPoint3 endPos = endL2W.GetTranslate(); |
|
|
|
ctrl->SetScreenRange( startPos, endPos ); |
|
ctrl->SetFlag( pfGUIKnobCtrl::kMapToAnimationRange ); |
|
} |
|
break; |
|
case 2: // Map to a range on the screen |
|
ctrl->SetFlag( pfGUIKnobCtrl::kMapToScreenRange ); |
|
break; |
|
} |
|
|
|
if( fCompPB->GetInt( kRefTriggerOnMouseUp ) ) |
|
ctrl->SetFlag( pfGUIKnobCtrl::kTriggerOnlyOnMouseUp ); |
|
|
|
return true; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIListBox Component ///////////////////////////////////////////////////////////////////// |
|
// |
|
// GUI element that can be dragged anywhere in the 2D viewing plane. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Class that accesses the paramblock below. |
|
class plGUIListBoxComponent : public plGUIControlBase |
|
{ |
|
protected: |
|
|
|
virtual pfGUIControlMod *IGetNewControl( void ) { return TRACKED_NEW pfGUIListBoxMod; } |
|
virtual bool INeedsDynamicText( void ) { return true; } |
|
|
|
public: |
|
plGUIListBoxComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefUseScroll, |
|
kRefScrollCtrl, |
|
kRefSingleSelect, |
|
kRefXparentBgnd, |
|
kRefDragDropSource, |
|
kRefDisableKeys, |
|
kRefAllow2DElementGrid, |
|
kRefScrollLeftToRight, |
|
kRefScaleWithRes, |
|
kRefPassClicksThrough, |
|
kRefEnableTreeBehavior, |
|
kRefSkin, |
|
kRefHandsOffMultiSelect |
|
}; |
|
}; |
|
|
|
// When one of our parameters that is a ref changes, send out the component ref |
|
// changed message. Normally, messages from component refs are ignored since |
|
// they pass along all the messages of the ref, which generates a lot of false |
|
// converts. |
|
class plGUIListBoxAccessor : public PBAccessor |
|
{ |
|
public: |
|
void Set( PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t ) |
|
{ |
|
if( id == plGUIListBoxComponent::kRefScrollCtrl ) |
|
{ |
|
plGUIListBoxComponent *comp = (plGUIListBoxComponent *)owner; |
|
comp->NotifyDependents( FOREVER, PART_ALL, REFMSG_USER_COMP_REF_CHANGED ); |
|
} |
|
} |
|
}; |
|
|
|
Class_ID sScrollingClassesToSelect[] = { GUI_UPDOWNPAIR_CLASSID, GUI_KNOBCTRL_CLASSID, plGUISingleCtrlDlgProc::kEndClassList }; |
|
|
|
static plGUIListBoxAccessor sGUIListBoxAccessor; |
|
static plGUISingleCtrlDlgProc sGUIListBoxProc( plGUIListBoxComponent::kRefScrollCtrl, IDC_GUI_COMPSELBTN, |
|
"Select the control to use for scrolling this list box", sScrollingClassesToSelect ); |
|
|
|
static plGUISingleCtrlDlgProc sGUILBSkinSelectProc( plGUIListBoxComponent::kRefSkin, IDC_GUI_SKIN, |
|
"Select the skin to use for this list box", sSkinClassesToSelect, |
|
&sGUIListBoxProc ); |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIListBoxComponent, gGUIListBoxDesc, "GUI List Box", "GUIListBox", COMP_TYPE_GUI, GUI_LISTBOX_CLASSID ) |
|
|
|
ParamBlockDesc2 gGUIListBoxBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUIListBox"), 0, &gGUIListBoxDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP + P_INCLUDE_PARAMS, plComponent::kRefComp, |
|
|
|
2, |
|
plGUIControlBase::kRollMain, IDD_COMP_GUILISTBOX, IDS_COMP_GUILISTBOX, 0, 0, &sGUILBSkinSelectProc, |
|
plGUIControlBase::kRollProc, IDD_COMP_GUIPROCROLLOUT, IDS_COMP_GUIPROCROLLOUT, 0, 0, nil, |
|
|
|
&sGUIControlProcParamTemplate, |
|
|
|
plGUIListBoxComponent::kRefUseScroll, _T( "enableScrolling" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_SCROLLCTRL, |
|
p_default, FALSE, |
|
p_enable_ctrls, 1, plGUIListBoxComponent::kRefScrollCtrl, |
|
end, |
|
|
|
plGUIListBoxComponent::kRefScrollCtrl, _T("scrollControl"), TYPE_INODE, 0, 0, |
|
p_prompt, IDS_COMP_GUI_SELECTSCROLL, |
|
p_accessor, &sGUIListBoxAccessor, |
|
end, |
|
|
|
plGUIListBoxComponent::kRefSingleSelect, _T( "singleSelect" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_SINGLESEL, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIListBoxComponent::kRefXparentBgnd, _T( "xparentBgnd" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_XPARENT, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIListBoxComponent::kRefDragDropSource, _T( "dragDropCapable" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_DRAGDROPSRC, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIListBoxComponent::kRefDisableKeys, _T( "disableKeys" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_DISABLEKEYS, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIListBoxComponent::kRefAllow2DElementGrid, _T( "allow2DElementGrid" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_ALLOWMULTIROW, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIListBoxComponent::kRefScrollLeftToRight, _T( "scrollLeftToRight" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_SCROLLL2R, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIListBoxComponent::kRefScaleWithRes, _T( "scaleWithRes" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_SCALERES, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIListBoxComponent::kRefPassClicksThrough, _T( "passClicksThru" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_PASSTHRU, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIListBoxComponent::kRefEnableTreeBehavior, _T( "makeLikeATree" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_ENABLETREE, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIListBoxComponent::kRefSkin, _T("skin"), TYPE_INODE, 0, 0, |
|
end, |
|
|
|
plGUIListBoxComponent::kRefHandsOffMultiSelect, _T( "handsOffMultiSelect" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_HANDSOFF, |
|
p_default, FALSE, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plGUIListBoxComponent::plGUIListBoxComponent() |
|
{ |
|
fClassDesc = &gGUIListBoxDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIListBoxComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::SetupProperties( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIListBoxComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIListBoxComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( !plGUIControlBase::Convert( node, pErrMsg ) ) |
|
return false; |
|
|
|
pfGUIListBoxMod *ctrl = (pfGUIListBoxMod *)fControl; |
|
|
|
if( fCompPB->GetInt( kRefUseScroll ) ) |
|
{ |
|
// Get the scrolling control to use |
|
pfGUIValueCtrl *scroll = pfGUIValueCtrl::ConvertNoRef( GrabControlMod( fCompPB->GetINode( kRefScrollCtrl ) ) ); |
|
if( scroll != nil ) |
|
{ |
|
hsgResMgr::ResMgr()->AddViaNotify( scroll->GetKey(), TRACKED_NEW plGenRefMsg( ctrl->GetKey(), |
|
plRefMsg::kOnCreate, -1, pfGUIListBoxMod::kRefScrollCtrl ), plRefFlags::kActiveRef ); |
|
} |
|
} |
|
|
|
if( fCompPB->GetInt( kRefSingleSelect ) ) |
|
ctrl->SetSingleSelect( true ); |
|
|
|
if( fCompPB->GetInt( kRefXparentBgnd ) ) |
|
ctrl->SetFlag( pfGUIListBoxMod::kXparentBgnd ); |
|
|
|
if( fCompPB->GetInt( kRefDragDropSource ) ) |
|
ctrl->SetFlag( pfGUIListBoxMod::kDragAndDropCapable ); |
|
|
|
if( fCompPB->GetInt( kRefDisableKeys ) ) |
|
ctrl->SetFlag( pfGUIListBoxMod::kDisableKeyActions ); |
|
|
|
if( fCompPB->GetInt( kRefAllow2DElementGrid ) ) |
|
ctrl->SetFlag( pfGUIListBoxMod::kAllowMultipleElementsPerRow ); |
|
|
|
if( fCompPB->GetInt( kRefScrollLeftToRight ) ) |
|
ctrl->SetFlag( pfGUIListBoxMod::kScrollLeftToRight ); |
|
|
|
if( fCompPB->GetInt( kRefScaleWithRes ) ) |
|
ctrl->SetFlag( pfGUIControlMod::kScaleTextWithResolution ); |
|
|
|
if( fCompPB->GetInt( kRefPassClicksThrough ) ) |
|
ctrl->SetFlag( pfGUIListBoxMod::kAllowMousePassThrough ); |
|
|
|
if( fCompPB->GetInt( kRefEnableTreeBehavior ) ) |
|
ctrl->SetFlag( pfGUIListBoxMod::kGrowLeavesAndProcessOxygen ); |
|
|
|
if( fCompPB->GetInt( kRefHandsOffMultiSelect ) ) |
|
ctrl->SetFlag( pfGUIListBoxMod::kHandsOffMultiSelect ); |
|
|
|
INode *sNode = fCompPB->GetINode( kRefSkin ); |
|
if( sNode != nil ) |
|
{ |
|
plComponentBase *comp = ( (plMaxNode *)sNode )->ConvertToComponent(); |
|
if( comp != nil ) |
|
{ |
|
Class_ID nodeID = comp->ClassID(); |
|
hsAssert( nodeID == GUI_SKIN_CLASSID, "Bad node param in GUIMenu::Convert()" ); |
|
|
|
plGUISkinComp *skin = (plGUISkinComp *)comp; |
|
hsgResMgr::ResMgr()->AddViaNotify( skin->GetConvertedSkin()->GetKey(), TRACKED_NEW plGenRefMsg( ctrl->GetKey(), plRefMsg::kOnCreate, -1, pfGUIControlMod::kRefSkin ), plRefFlags::kActiveRef ); |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUITextBox Component ///////////////////////////////////////////////////////////////////// |
|
// |
|
// GUI element that displays a block of wrapped text. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Class that accesses the paramblock below. |
|
class plGUITextBoxComponent : public plGUIControlBase |
|
{ |
|
protected: |
|
|
|
virtual pfGUIControlMod *IGetNewControl( void ) { return TRACKED_NEW pfGUITextBoxMod; } |
|
virtual bool INeedsDynamicText( void ) { return true; } |
|
|
|
public: |
|
plGUITextBoxComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefInitText, |
|
kRefFontSize, |
|
kRefXparentBgnd, |
|
kRefJustify, |
|
kRefScaleWithRes, |
|
kRefUseLocalization, |
|
kRefLocalizationPath |
|
}; |
|
}; |
|
|
|
class plGUITextBoxProc : public ParamMap2UserDlgProc |
|
{ |
|
private: |
|
std::vector<std::string> fTranslations; |
|
int fCurLanguage; |
|
void ISetTranslation(int lang, std::string text) |
|
{ |
|
while (lang >= fTranslations.size()) |
|
fTranslations.push_back(""); |
|
fTranslations[lang] = text; |
|
} |
|
protected: |
|
|
|
public: |
|
|
|
void DeleteThis() {} |
|
|
|
BOOL DlgProc( TimeValue t, IParamMap2 *pmap, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
int i; |
|
switch( msg ) |
|
{ |
|
case WM_INITDIALOG: |
|
// make sure there is a string to get |
|
if ( pmap->GetParamBlock()->GetStr( plGUITextBoxComponent::kRefInitText ) ) |
|
{ |
|
fTranslations = plLocalization::StringToLocal(pmap->GetParamBlock()->GetStr( plGUITextBoxComponent::kRefInitText ) ); |
|
SetDlgItemText( hWnd, IDC_GUI_INITTEXT, fTranslations[0].c_str() ); |
|
} |
|
else |
|
// if there is no text, then there is nothing to translate |
|
SetDlgItemText( hWnd, IDC_GUI_INITTEXT, pmap->GetParamBlock()->GetStr( plGUITextBoxComponent::kRefInitText ) ); |
|
SendMessage( GetDlgItem( hWnd, IDC_GUI_LANGUAGE ), CB_RESETCONTENT, 0, 0 ); |
|
for (i=0; i<plLocalization::kNumLanguages; i++) |
|
SendMessage( GetDlgItem( hWnd, IDC_GUI_LANGUAGE ), CB_ADDSTRING, 0, (LPARAM)plLocalization::GetLanguageName((plLocalization::Language)i) ); |
|
SendMessage( GetDlgItem( hWnd, IDC_GUI_LANGUAGE ), CB_SETCURSEL, 0, 0 ); |
|
fCurLanguage = 0; |
|
|
|
SetDlgItemText( hWnd, IDC_GUI_LOCALIZATION_PATH, pmap->GetParamBlock()->GetStr( plGUITextBoxComponent::kRefLocalizationPath ) ); |
|
|
|
if ( pmap->GetParamBlock()->GetInt( plGUITextBoxComponent::kRefUseLocalization ) != 0 ) |
|
{ |
|
// disable standard text, enable loc path |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_INITTEXT ), false ); |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_LANGUAGE ), false ); |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_LOCALIZATION_PATH ), true ); |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_SELECT_LOC_PATH ), true ); |
|
CheckDlgButton( hWnd, IDC_GUI_USE_LOCALIZATION, BST_CHECKED ); |
|
} |
|
else |
|
{ |
|
// enable standard text, disable loc path |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_INITTEXT ), true ); |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_LANGUAGE ), true ); |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_LOCALIZATION_PATH ), false ); |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_SELECT_LOC_PATH ), false ); |
|
CheckDlgButton( hWnd, IDC_GUI_USE_LOCALIZATION, BST_UNCHECKED ); |
|
} |
|
return true; |
|
|
|
case WM_DESTROY: |
|
break; |
|
|
|
case WM_COMMAND: |
|
if( LOWORD( wParam ) == IDC_GUI_INITTEXT ) |
|
{ |
|
if( HIWORD( wParam ) == EN_CHANGE ) |
|
{ |
|
int strLen = SendDlgItemMessage( hWnd, IDC_GUI_INITTEXT, WM_GETTEXTLENGTH, 0, 0 ); |
|
if( strLen > 0 ) |
|
{ |
|
char *str = TRACKED_NEW char[ strLen + 1 ]; |
|
GetDlgItemText( hWnd, IDC_GUI_INITTEXT, str, strLen + 1 ); |
|
str[ strLen ] = 0; |
|
ISetTranslation(fCurLanguage,str); |
|
delete [] str; |
|
|
|
std::string translation = plLocalization::LocalToString(fTranslations); |
|
str = TRACKED_NEW char[ translation.length() + 1 ]; |
|
strcpy(str,translation.c_str()); |
|
str[translation.length()] = 0; |
|
|
|
pmap->GetParamBlock()->SetValue( plGUITextBoxComponent::kRefInitText, 0, str ); |
|
delete [] str; |
|
} |
|
} |
|
else if( HIWORD( wParam ) == EN_KILLFOCUS ) |
|
{ |
|
plMaxAccelerators::Enable(); |
|
} |
|
else if( HIWORD( wParam ) == EN_SETFOCUS ) |
|
{ |
|
plMaxAccelerators::Disable(); |
|
} |
|
} |
|
else if( LOWORD( wParam ) == IDC_GUI_LOCALIZATION_PATH ) |
|
{ |
|
if( HIWORD( wParam ) == EN_CHANGE ) |
|
{ |
|
int strLen = SendDlgItemMessage( hWnd, IDC_GUI_LOCALIZATION_PATH, WM_GETTEXTLENGTH, 0, 0 ); |
|
if( strLen > 0 ) |
|
{ |
|
char *str = TRACKED_NEW char[ strLen + 1 ]; |
|
GetDlgItemText( hWnd, IDC_GUI_LOCALIZATION_PATH, str, strLen + 1 ); |
|
str[ strLen ] = 0; |
|
pmap->GetParamBlock()->SetValue( plGUITextBoxComponent::kRefLocalizationPath, 0, str ); |
|
delete [] str; |
|
} |
|
} |
|
else if( HIWORD( wParam ) == EN_KILLFOCUS ) |
|
{ |
|
plMaxAccelerators::Enable(); |
|
} |
|
else if( HIWORD( wParam ) == EN_SETFOCUS ) |
|
{ |
|
plMaxAccelerators::Disable(); |
|
} |
|
} |
|
else if( LOWORD( wParam ) == IDC_GUI_LANGUAGE ) |
|
{ |
|
if( HIWORD( wParam ) == CBN_SELCHANGE ) |
|
{ |
|
int idx = SendDlgItemMessage( hWnd, IDC_GUI_LANGUAGE, CB_GETCURSEL, 0, 0 ); |
|
if (idx >= fTranslations.size()) |
|
SetDlgItemText( hWnd, IDC_GUI_INITTEXT, "" ); |
|
else |
|
SetDlgItemText( hWnd, IDC_GUI_INITTEXT, fTranslations[idx].c_str() ); |
|
fCurLanguage = idx; |
|
} |
|
} |
|
else if( LOWORD( wParam ) == IDC_GUI_SELECT_LOC_PATH ) |
|
{ |
|
char value[512]; |
|
GetDlgItemText( hWnd, IDC_GUI_LOCALIZATION_PATH, value, 512 ); |
|
plPickLocalizationDlg dlg( value ); |
|
if( dlg.DoPick() ) |
|
{ |
|
pmap->GetParamBlock()->SetValue( plGUITextBoxComponent::kRefLocalizationPath, 0, (char*)dlg.GetValue() ); |
|
SetDlgItemText( hWnd, IDC_GUI_LOCALIZATION_PATH, (char*)dlg.GetValue() ); |
|
} |
|
} |
|
else if( LOWORD( wParam ) == IDC_GUI_USE_LOCALIZATION ) |
|
{ |
|
// enable/disable the appropriate values |
|
bool useLoc = ( IsDlgButtonChecked( hWnd, IDC_GUI_USE_LOCALIZATION ) == BST_CHECKED ); |
|
pmap->GetParamBlock()->SetValue( plGUITextBoxComponent::kRefUseLocalization, 0, useLoc ? 1 : 0 ); |
|
|
|
if ( useLoc ) |
|
{ |
|
// disable standard text, enable loc path |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_INITTEXT ), false ); |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_LANGUAGE ), false ); |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_LOCALIZATION_PATH ), true ); |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_SELECT_LOC_PATH ), true ); |
|
} |
|
else |
|
{ |
|
// enable standard text, disable loc path |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_INITTEXT ), true ); |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_LANGUAGE ), true ); |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_LOCALIZATION_PATH ), false ); |
|
EnableWindow( GetDlgItem( hWnd, IDC_GUI_SELECT_LOC_PATH ), false ); |
|
} |
|
} |
|
break; |
|
} |
|
return false; |
|
} |
|
}; |
|
static plGUITextBoxProc gGUITextBoxProc; |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUITextBoxComponent, gGUITextBoxDesc, "GUI Text Box", "GUITextBox", COMP_TYPE_GUI, GUI_TEXTBOX_CLASSID ) |
|
|
|
ParamBlockDesc2 gGUITextBoxBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUITextBox"), 0, &gGUITextBoxDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP + P_INCLUDE_PARAMS, plComponent::kRefComp, |
|
|
|
2, |
|
plGUIControlBase::kRollMain, IDD_COMP_GUITEXTBOX, IDS_COMP_GUITEXTBOX, 0, 0, &gGUITextBoxProc, |
|
plGUIControlBase::kRollProc, IDD_COMP_GUIPROCROLLOUT, IDS_COMP_GUIPROCROLLOUT, 0, 0, nil, |
|
|
|
&sGUIControlProcParamTemplate, |
|
|
|
plGUITextBoxComponent::kRefInitText, _T("InitText"), TYPE_STRING, 0, 0, |
|
// p_ui, plGUIControlBase::kRollMain, TYPE_EDITBOX, IDC_GUI_INITTEXT, |
|
end, |
|
|
|
plGUITextBoxComponent::kRefXparentBgnd, _T( "xparentBgnd" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_XPARENT, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUITextBoxComponent::kRefJustify, _T("justify"), TYPE_INT, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_RADIO, 3, IDC_JUSTIFYRADIO, IDC_JUSTRADIO2, IDC_JUSTRADIO3, |
|
p_default, 0, |
|
end, |
|
|
|
plGUITextBoxComponent::kRefScaleWithRes, _T( "scaleWithRes" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_SCALERES, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUITextBoxComponent::kRefUseLocalization, _T( "useLocalization" ), TYPE_BOOL, 0, 0, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUITextBoxComponent::kRefLocalizationPath,_T( "localizationPath" ),TYPE_STRING, 0, 0, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plGUITextBoxComponent::plGUITextBoxComponent() |
|
{ |
|
fClassDesc = &gGUITextBoxDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUITextBoxComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::SetupProperties( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUITextBoxComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUITextBoxComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( !plGUIControlBase::Convert( node, pErrMsg ) ) |
|
return false; |
|
|
|
pfGUITextBoxMod *ctrl = (pfGUITextBoxMod *)fControl; |
|
|
|
ctrl->SetText( fCompPB->GetStr( kRefInitText ) ); |
|
|
|
if( fCompPB->GetInt( kRefXparentBgnd ) ) |
|
ctrl->SetFlag( pfGUITextBoxMod::kXparentBgnd ); |
|
|
|
int just = fCompPB->GetInt( kRefJustify ); |
|
if( just == 1 ) |
|
ctrl->SetFlag( pfGUITextBoxMod::kCenterJustify ); |
|
else if( just == 2 ) |
|
ctrl->SetFlag( pfGUITextBoxMod::kRightJustify ); |
|
|
|
if( fCompPB->GetInt( kRefScaleWithRes ) ) |
|
ctrl->SetFlag( pfGUIControlMod::kScaleTextWithResolution ); |
|
|
|
ctrl->SetUseLocalizationPath( fCompPB->GetInt( kRefUseLocalization ) != 0 ); |
|
ctrl->SetLocalizationPath( fCompPB->GetStr( kRefLocalizationPath ) ); |
|
|
|
return true; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIEditBox Component ///////////////////////////////////////////////////////////////////// |
|
// |
|
// GUI element that can be dragged anywhere in the 2D viewing plane. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Class that accesses the paramblock below. |
|
class plGUIEditBoxComponent : public plGUIControlBase |
|
{ |
|
protected: |
|
|
|
virtual pfGUIControlMod *IGetNewControl( void ) { return TRACKED_NEW pfGUIEditBoxMod; } |
|
virtual bool INeedsDynamicText( void ) { return true; } |
|
|
|
public: |
|
plGUIEditBoxComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefXparentBgnd, |
|
kRefScaleWithRes |
|
}; |
|
}; |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIEditBoxComponent, gGUIEditBoxDesc, "GUI Edit Box", "GUIEditBox", COMP_TYPE_GUI, GUI_EDITBOX_CLASSID ) |
|
|
|
ParamBlockDesc2 gGUIEditBoxBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUIEditBox"), 0, &gGUIEditBoxDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP + P_INCLUDE_PARAMS, plComponent::kRefComp, |
|
|
|
2, |
|
plGUIControlBase::kRollMain, IDD_COMP_GUIEDITBOX, IDS_COMP_GUIEDITBOX, 0, 0, NULL, |
|
plGUIControlBase::kRollProc, IDD_COMP_GUIPROCROLLOUT, IDS_COMP_GUIPROCROLLOUT, 0, 0, nil, |
|
|
|
&sGUIControlProcParamTemplate, |
|
|
|
plGUIEditBoxComponent::kRefXparentBgnd, _T( "xparentBgnd" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_XPARENT, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIEditBoxComponent::kRefScaleWithRes, _T( "scaleWithRes" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_SCALERES, |
|
p_default, FALSE, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plGUIEditBoxComponent::plGUIEditBoxComponent() |
|
{ |
|
fClassDesc = &gGUIEditBoxDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIEditBoxComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::SetupProperties( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIEditBoxComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIEditBoxComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( !plGUIControlBase::Convert( node, pErrMsg ) ) |
|
return false; |
|
|
|
pfGUIEditBoxMod *ctrl = (pfGUIEditBoxMod *)fControl; |
|
|
|
if( fCompPB->GetInt( kRefXparentBgnd ) ) |
|
ctrl->SetFlag( pfGUIEditBoxMod::kXparentBgnd ); |
|
|
|
if( fCompPB->GetInt( kRefScaleWithRes ) ) |
|
ctrl->SetFlag( pfGUIControlMod::kScaleTextWithResolution ); |
|
|
|
return true; |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIUpDownPair Component ////////////////////////////////////////////////////////////////// |
|
// |
|
// GUI grouping element that uses two buttons to alter a value up and down |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Class that accesses the paramblock below. |
|
class plGUIUpDownPairComponent : public plGUIControlBase |
|
{ |
|
protected: |
|
|
|
virtual pfGUIControlMod *IGetNewControl( void ) { return TRACKED_NEW pfGUIUpDownPairMod; } |
|
|
|
public: |
|
plGUIUpDownPairComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefMinValue, |
|
kRefMaxValue, |
|
kRefStep, |
|
kRefUpControl, |
|
kRefDownControl |
|
}; |
|
}; |
|
|
|
//// Dialog proc //////////////////////////////////////////////////////////////////////////////// |
|
|
|
class plGUIUDPairDlgProc : public ParamMap2UserDlgProc |
|
{ |
|
protected: |
|
ParamID fUpNodeID, fDownNodeID; |
|
int fUpDlgItem, fDownDlgItem; |
|
TCHAR fTitle[ 128 ]; |
|
|
|
public: |
|
plGUIUDPairDlgProc( ParamID upNodeID, int upDlgItem, ParamID downNodeID, int downDlgItem, TCHAR *title ) |
|
{ |
|
fUpNodeID = upNodeID; |
|
fDownNodeID = downNodeID; |
|
fUpDlgItem = upDlgItem; |
|
fDownDlgItem = downDlgItem; |
|
strcpy( fTitle, title ); |
|
} |
|
|
|
BOOL DlgProc( TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
switch ( msg ) |
|
{ |
|
case WM_INITDIALOG: |
|
{ |
|
IParamBlock2 *pb = map->GetParamBlock(); |
|
|
|
INode *node = pb->GetINode( fUpNodeID ); |
|
TSTR newName( node ? node->GetName() : "Pick" ); |
|
::SetWindowText( ::GetDlgItem( hWnd, fUpDlgItem ), newName ); |
|
|
|
node = pb->GetINode( fDownNodeID ); |
|
TSTR newName2( node ? node->GetName() : "Pick" ); |
|
::SetWindowText( ::GetDlgItem( hWnd, fDownDlgItem ), newName2 ); |
|
} |
|
return true; |
|
|
|
case WM_COMMAND: |
|
if( ( HIWORD( wParam ) == BN_CLICKED ) ) |
|
{ |
|
if( LOWORD( wParam ) == fUpDlgItem ) |
|
{ |
|
IParamBlock2 *pb = map->GetParamBlock(); |
|
plGUICtrlHitCallback hitCB( (INode *)pb->GetOwner(), pb, fUpNodeID, fTitle, true, GUI_BUTTON_CLASSID ); |
|
GetCOREInterface()->DoHitByNameDialog( &hitCB ); |
|
|
|
INode* node = pb->GetINode( fUpNodeID ); |
|
TSTR newName( node ? node->GetName() : "Pick" ); |
|
::SetWindowText( ::GetDlgItem(hWnd, fUpDlgItem ), newName ); |
|
map->Invalidate( fUpNodeID ); |
|
::InvalidateRect( hWnd, NULL, TRUE ); |
|
} |
|
else if( LOWORD( wParam ) == fDownDlgItem ) |
|
{ |
|
IParamBlock2 *pb = map->GetParamBlock(); |
|
plGUICtrlHitCallback hitCB( (INode *)pb->GetOwner(), pb, fDownNodeID, fTitle, true, GUI_BUTTON_CLASSID ); |
|
GetCOREInterface()->DoHitByNameDialog( &hitCB ); |
|
|
|
INode* node = pb->GetINode( fDownNodeID ); |
|
TSTR newName( node ? node->GetName() : "Pick" ); |
|
::SetWindowText( ::GetDlgItem(hWnd, fDownDlgItem ), newName ); |
|
map->Invalidate( fDownDlgItem ); |
|
::InvalidateRect( hWnd, NULL, TRUE ); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void DeleteThis() {} |
|
}; |
|
|
|
// When one of our parameters that is a ref changes, send out the component ref |
|
// changed message. Normally, messages from component refs are ignored since |
|
// they pass along all the messages of the ref, which generates a lot of false |
|
// converts. |
|
class plGUIUDAccessor : public PBAccessor |
|
{ |
|
public: |
|
void Set( PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t ) |
|
{ |
|
if( id == plGUIUpDownPairComponent::kRefUpControl |
|
|| id == plGUIUpDownPairComponent::kRefDownControl ) |
|
{ |
|
plGUIUpDownPairComponent *comp = (plGUIUpDownPairComponent *)owner; |
|
comp->NotifyDependents( FOREVER, PART_ALL, REFMSG_USER_COMP_REF_CHANGED ); |
|
} |
|
} |
|
}; |
|
|
|
static plGUIUDAccessor sGUIUDAccessor; |
|
static plGUIUDPairDlgProc sGUIUDPairDlgProc( plGUIUpDownPairComponent::kRefUpControl, IDC_GUI_COMPSELBTN, |
|
plGUIUpDownPairComponent::kRefDownControl, IDC_GUI_COMPSELBTN2, |
|
"Select the control to use in this pair" ); |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIUpDownPairComponent, gGUIUDPairDesc, "GUI Up/Down Pair", "GUIUDPair", COMP_TYPE_GUI, GUI_UPDOWNPAIR_CLASSID ) |
|
|
|
ParamBlockDesc2 gGUIUDPairBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUIUDPair"), 0, &gGUIUDPairDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP + P_INCLUDE_PARAMS, plComponent::kRefComp, |
|
|
|
2, |
|
plGUIControlBase::kRollMain, IDD_COMP_GUIUDSCROLL, IDS_COMP_GUIUDSCROLL, 0, 0, &sGUIUDPairDlgProc, |
|
plGUIControlBase::kRollProc, IDD_COMP_GUIPROCROLLOUT, IDS_COMP_GUIPROCROLLOUT, 0, 0, nil, |
|
|
|
&sGUIControlProcParamTemplate, |
|
|
|
plGUIUpDownPairComponent::kRefUpControl, _T("upControl"), TYPE_INODE, 0, 0, |
|
p_prompt, IDS_COMP_GUI_SELECTUDCTRL, |
|
p_accessor, &sGUIUDAccessor, |
|
end, |
|
|
|
plGUIUpDownPairComponent::kRefDownControl, _T("downControl"), TYPE_INODE, 0, 0, |
|
p_prompt, IDS_COMP_GUI_SELECTUDCTRL, |
|
p_accessor, &sGUIUDAccessor, |
|
end, |
|
|
|
plGUIUpDownPairComponent::kRefMinValue, _T("minValue"), TYPE_FLOAT, 0, 0, |
|
p_default, 0.0f, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_GUI_LOWER, IDC_GUI_LOWER_SPIN, SPIN_AUTOSCALE, |
|
end, |
|
|
|
plGUIUpDownPairComponent::kRefMaxValue, _T("maxValue"), TYPE_FLOAT, 0, 0, |
|
p_default, 10.0f, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_GUI_UPPER, IDC_GUI_UPPER_SPIN, SPIN_AUTOSCALE, |
|
end, |
|
|
|
plGUIUpDownPairComponent::kRefStep, _T("step"), TYPE_FLOAT, 0, 0, |
|
p_default, 1.0f, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_GUI_STEP, IDC_GUI_STEP_SPIN, SPIN_AUTOSCALE, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plGUIUpDownPairComponent::plGUIUpDownPairComponent() |
|
{ |
|
fClassDesc = &gGUIUDPairDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIUpDownPairComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::SetupProperties( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIUpDownPairComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIUpDownPairComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( !plGUIControlBase::Convert( node, pErrMsg ) ) |
|
return false; |
|
|
|
pfGUIUpDownPairMod *ctrl = (pfGUIUpDownPairMod *)fControl; |
|
|
|
// Get the child controls |
|
pfGUIButtonMod *up = pfGUIButtonMod::ConvertNoRef( GrabControlMod( fCompPB->GetINode( kRefUpControl ) ) ); |
|
pfGUIButtonMod *down = pfGUIButtonMod::ConvertNoRef( GrabControlMod( fCompPB->GetINode( kRefDownControl ) ) ); |
|
|
|
ctrl->SetControls( up, down ); |
|
|
|
ctrl->SetRange( fCompPB->GetFloat( kRefMinValue ), fCompPB->GetFloat( kRefMaxValue ) ); |
|
ctrl->SetStep( fCompPB->GetFloat( kRefStep ) ); |
|
|
|
return true; |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIDragBar Component /////////////////////////////////////////////////////////////////// |
|
// |
|
// GUI element that can be dragged anywhere in the 2D viewing plane. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Class that accesses the paramblock below. |
|
class plGUIDragBarComponent : public plGUIControlBase |
|
{ |
|
protected: |
|
|
|
virtual pfGUIControlMod *IGetNewControl( void ) { return TRACKED_NEW pfGUIDragBarCtrl; } |
|
virtual bool ICanHaveProxy( void ) { return true; } |
|
|
|
public: |
|
plGUIDragBarComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
}; |
|
}; |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIDragBarComponent, gGUIDragBarDesc, "GUI Dialog Drag Bar", "GUIDragBar", COMP_TYPE_GUI, GUI_DRAGBAR_CLASSID ) |
|
|
|
ParamBlockDesc2 gGUIDragBarBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUIDragBar"), 0, &gGUIDragBarDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP + P_INCLUDE_PARAMS, plComponent::kRefComp, |
|
|
|
3, |
|
plGUIControlBase::kRollMain, IDD_COMP_GUIDRAGBAR, IDS_COMP_GUIDRAGBAR, 0, 0, NULL, |
|
plGUIControlBase::kRollProc, IDD_COMP_GUIPROCROLLOUT, IDS_COMP_GUIPROCROLLOUT, 0, 0, nil, |
|
|
|
sGUIProxyParamHeader, |
|
|
|
&sGUIControlProcParamTemplate, |
|
|
|
sGUIProxyParamTemplate, |
|
|
|
end |
|
); |
|
|
|
plGUIDragBarComponent::plGUIDragBarComponent() |
|
{ |
|
fClassDesc = &gGUIDragBarDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIDragBarComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
node->SetForceLocal( true ); |
|
return plGUIControlBase::SetupProperties( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIDragBarComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIDragBarComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( !plGUIControlBase::Convert( node, pErrMsg ) ) |
|
return false; |
|
|
|
pfGUIDragBarCtrl *ctrl = (pfGUIDragBarCtrl *)fControl; |
|
|
|
return true; |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIRadioGroup Component ////////////////////////////////////////////////////////////////// |
|
// |
|
// GUI grouping element that ensures that only one of a group of check boxes is checked at any |
|
// one time, and takes on the value of whichever one is currently checked, or -1 if none. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Class that accesses the paramblock below. |
|
class plGUIRadioGroupAccessor; |
|
class plGUIRadioGroupComponent : public plGUIControlBase |
|
{ |
|
friend class plGUIRadioGroupAccessor; |
|
|
|
protected: |
|
|
|
virtual pfGUIControlMod *IGetNewControl( void ) { return TRACKED_NEW pfGUIRadioGroupCtrl; } |
|
|
|
public: |
|
plGUIRadioGroupComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefCheckBoxes, |
|
kRefDefaultSel, |
|
kRefAllowNoSel |
|
}; |
|
}; |
|
|
|
//// Dialog proc //////////////////////////////////////////////////////////////////////////////// |
|
|
|
class plGUIRadioGroupProc : public ParamMap2UserDlgProc |
|
{ |
|
protected: |
|
|
|
public: |
|
plGUIRadioGroupProc() |
|
{ |
|
} |
|
|
|
void SetSpinnerRange( IParamMap2 *pMap ) |
|
{ |
|
if( pMap == nil ) |
|
return; |
|
|
|
HWND hWnd = pMap->GetHWnd(); |
|
if( hWnd == nil ) |
|
return; |
|
|
|
ISpinnerControl *spin = GetISpinner( GetDlgItem( hWnd, IDC_GUI_DEFSEL_SPIN ) ); |
|
|
|
int minValue = pMap->GetParamBlock()->GetInt( plGUIRadioGroupComponent::kRefAllowNoSel ) ? -1 : 0; |
|
int maxValue = pMap->GetParamBlock()->Count( plGUIRadioGroupComponent::kRefCheckBoxes ); |
|
|
|
spin->SetLimits( minValue, maxValue ); |
|
|
|
ReleaseISpinner( spin ); |
|
} |
|
|
|
BOOL DlgProc( TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
switch ( msg ) |
|
{ |
|
case WM_INITDIALOG: |
|
{ |
|
SetSpinnerRange( map ); |
|
} |
|
return true; |
|
|
|
case WM_COMMAND: |
|
if( ( HIWORD( wParam ) == BN_CLICKED ) ) |
|
{ |
|
if( LOWORD( wParam ) == IDC_GUI_ADDCHECK ) |
|
{ |
|
IParamBlock2 *pb = map->GetParamBlock(); |
|
|
|
plGUICtrlHitCallback hitCB( (INode *)pb->GetOwner(), pb, plGUIRadioGroupComponent::kRefCheckBoxes, |
|
"Select a check box to add to this radio group", true, GUI_CHECKBOX_CLASSID, false ); |
|
|
|
GetCOREInterface()->DoHitByNameDialog( &hitCB ); |
|
|
|
map->Invalidate( plGUIRadioGroupComponent::kRefCheckBoxes ); |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void DeleteThis() {} |
|
}; |
|
static plGUIRadioGroupProc sGUIRadioGroupProc; |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIRadioGroupComponent, gGUIRadioGroupDesc, "GUI Radio Group", "GUIRadioGroup", COMP_TYPE_GUI, GUI_RADIOGROUP_CLASSID ) |
|
|
|
// When one of our parameters that is a ref changes, send out the component ref |
|
// changed message. Normally, messages from component refs are ignored since |
|
// they pass along all the messages of the ref, which generates a lot of false |
|
// converts. |
|
class plGUIRadioGroupAccessor : public PBAccessor |
|
{ |
|
public: |
|
void Set( PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t ) |
|
{ |
|
plGUIRadioGroupComponent *comp = (plGUIRadioGroupComponent *)owner; |
|
IParamBlock2 *pBlock = comp->fCompPB; |
|
|
|
if( id == plGUIRadioGroupComponent::kRefCheckBoxes ) |
|
{ |
|
comp->NotifyDependents( FOREVER, PART_ALL, REFMSG_USER_COMP_REF_CHANGED ); |
|
sGUIRadioGroupProc.SetSpinnerRange( pBlock->GetMap( plGUIControlBase::kRollMain ) ); |
|
} |
|
else if( id == plGUIRadioGroupComponent::kRefAllowNoSel ) |
|
sGUIRadioGroupProc.SetSpinnerRange( pBlock->GetMap( plGUIControlBase::kRollMain ) ); |
|
} |
|
|
|
void TabChanged( tab_changes changeCode, Tab<PB2Value> *tab, ReferenceMaker *owner, ParamID id, int tabIndex, int count ) |
|
{ |
|
plGUIRadioGroupComponent *comp = (plGUIRadioGroupComponent *)owner; |
|
IParamBlock2 *pBlock = comp->fCompPB; |
|
|
|
if( id == plGUIRadioGroupComponent::kRefCheckBoxes ) |
|
{ |
|
comp->NotifyDependents( FOREVER, PART_ALL, REFMSG_USER_COMP_REF_CHANGED ); |
|
sGUIRadioGroupProc.SetSpinnerRange( pBlock->GetMap( plGUIControlBase::kRollMain ) ); |
|
} |
|
} |
|
|
|
}; |
|
|
|
static plGUIRadioGroupAccessor sGUIRadioGroupAccessor; |
|
|
|
ParamBlockDesc2 gGUIRadioGroupBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUIRadioGroup"), 0, &gGUIRadioGroupDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP + P_INCLUDE_PARAMS, plComponent::kRefComp, |
|
|
|
2, |
|
plGUIControlBase::kRollMain, IDD_COMP_GUIRADIOGROUP, IDS_COMP_GUIRADIOGROUP, 0, 0, &sGUIRadioGroupProc, |
|
plGUIControlBase::kRollProc, IDD_COMP_GUIPROCROLLOUT, IDS_COMP_GUIPROCROLLOUT, 0, 0, nil, |
|
|
|
&sGUIControlProcParamTemplate, |
|
|
|
plGUIRadioGroupComponent::kRefCheckBoxes, _T("checkBoxes"), TYPE_INODE_TAB, 0, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_NODELISTBOX, IDC_GUI_CHECKLIST, 0, 0, IDC_GUI_DELCHECK, |
|
p_accessor, &sGUIRadioGroupAccessor, |
|
end, |
|
|
|
plGUIRadioGroupComponent::kRefDefaultSel, _T("defaultSelection"), TYPE_INT, 0, 0, |
|
p_default, 0, |
|
p_range, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SPINNER, EDITTYPE_INT, IDC_GUI_DEFSEL, IDC_GUI_DEFSEL_SPIN, SPIN_AUTOSCALE, |
|
end, |
|
|
|
plGUIRadioGroupComponent::kRefAllowNoSel, _T( "allowNoSel" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_ALLOWNONE, |
|
p_default, FALSE, |
|
p_accessor, &sGUIRadioGroupAccessor, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plGUIRadioGroupComponent::plGUIRadioGroupComponent() |
|
{ |
|
fClassDesc = &gGUIRadioGroupDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIRadioGroupComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::SetupProperties( node, pErrMsg ); |
|
} |
|
|
|
|
|
hsBool plGUIRadioGroupComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIRadioGroupComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( !plGUIControlBase::Convert( node, pErrMsg ) ) |
|
return false; |
|
|
|
pfGUIRadioGroupCtrl *ctrl = (pfGUIRadioGroupCtrl *)fControl; |
|
|
|
int i; |
|
ctrl->ClearControlList(); |
|
for( i = 0; i < fCompPB->Count( kRefCheckBoxes ); i++ ) |
|
{ |
|
pfGUICheckBoxCtrl *cb = pfGUICheckBoxCtrl::ConvertNoRef( GrabControlMod( fCompPB->GetINode( kRefCheckBoxes, 0, i ) ) ); |
|
if( cb != nil ) |
|
ctrl->AddControl( cb ); |
|
} |
|
|
|
if( fCompPB->GetInt( kRefAllowNoSel ) ) |
|
ctrl->SetFlag( pfGUIRadioGroupCtrl::kAllowNoSelection ); |
|
|
|
ctrl->SetDefaultValue( fCompPB->GetInt( kRefDefaultSel ) ); |
|
|
|
return true; |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIDynDisplay Component ////////////////////////////////////////////////////////////////// |
|
// |
|
// GUI element that can be dragged anywhere in the 2D viewing plane. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Class that accesses the paramblock below. |
|
class plGUIDynDisplayComponent : public plGUIControlBase |
|
{ |
|
protected: |
|
|
|
virtual pfGUIControlMod *IGetNewControl( void ) { return TRACKED_NEW pfGUIDynDisplayCtrl; } |
|
virtual bool IHasProcRollout( void ) { return false; } |
|
|
|
public: |
|
plGUIDynDisplayComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefDynLayer |
|
}; |
|
}; |
|
|
|
//// Dialog proc //////////////////////////////////////////////////////////////////////////////// |
|
|
|
class plGUIDynDisplayProc : public ParamMap2UserDlgProc |
|
{ |
|
protected: |
|
|
|
public: |
|
plGUIDynDisplayProc() |
|
{ |
|
} |
|
|
|
BOOL DlgProc( TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
switch ( msg ) |
|
{ |
|
case WM_INITDIALOG: |
|
{ |
|
IParamBlock2 *pb = map->GetParamBlock(); |
|
|
|
Texmap *tmap = pb->GetTexmap( plGUIDynDisplayComponent::kRefDynLayer ); |
|
if( tmap != nil ) |
|
SetDlgItemText( hWnd, IDC_GUI_PICKMAT, (const char *)tmap->GetName() ); |
|
else |
|
SetDlgItemText( hWnd, IDC_GUI_PICKMAT, "Pick" ); |
|
} |
|
return true; |
|
|
|
case WM_COMMAND: |
|
if( ( HIWORD( wParam ) == BN_CLICKED ) ) |
|
{ |
|
if( LOWORD( wParam ) == IDC_GUI_PICKMAT ) |
|
{ |
|
IParamBlock2 *pb = map->GetParamBlock(); |
|
|
|
if( plPickMaterialMap::PickTexmap( pb, plGUIDynDisplayComponent::kRefDynLayer ) ) |
|
{ |
|
Texmap *tmap = pb->GetTexmap( plGUIDynDisplayComponent::kRefDynLayer ); |
|
if( tmap != nil ) |
|
SetDlgItemText( hWnd, IDC_GUI_PICKMAT, (const char *)tmap->GetName() ); |
|
else |
|
SetDlgItemText( hWnd, IDC_GUI_PICKMAT, "Pick" ); |
|
|
|
map->Invalidate( plGUIDynDisplayComponent::kRefDynLayer ); |
|
} |
|
} |
|
} |
|
return true; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void DeleteThis() {} |
|
}; |
|
static plGUIDynDisplayProc sGUIDynDisplayProc; |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIDynDisplayComponent, gGUIDynDisplayDesc, "GUI Dynamic Display", "GUIDynDisplay", COMP_TYPE_GUI, GUI_DYNDISPLAY_CLASSID ) |
|
|
|
ParamBlockDesc2 gGUIDynDisplayBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUIDynDisplay"), 0, &gGUIDynDisplayDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP, plComponent::kRefComp, |
|
|
|
1, |
|
plGUIControlBase::kRollMain, IDD_COMP_GUIDYNDISPLAY, IDS_COMP_GUIDYNDISPLAY, 0, 0, &sGUIDynDisplayProc, |
|
|
|
plGUIDynDisplayComponent::kRefDynLayer, _T("dynLayer"), TYPE_TEXMAP, 0, 0, |
|
// p_ui, plGUIControlBase::kRollMain, TYPE_TEXMAPBUTTON, IDC_GUI_COMPSELBTN, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plGUIDynDisplayComponent::plGUIDynDisplayComponent() |
|
{ |
|
fClassDesc = &gGUIDynDisplayDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIDynDisplayComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::SetupProperties( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIDynDisplayComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIDynDisplayComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( !plGUIControlBase::Convert( node, pErrMsg ) ) |
|
return false; |
|
|
|
pfGUIDynDisplayCtrl *ctrl = (pfGUIDynDisplayCtrl *)fControl; |
|
|
|
Texmap *tmap = fCompPB->GetTexmap( plGUIDynDisplayComponent::kRefDynLayer ); |
|
plPlasmaMAXLayer *pLayer = plPlasmaMAXLayer::GetPlasmaMAXLayer( tmap ); |
|
if( pLayer == nil /*|| pLayer->ClassID() != DYN_TEXT_LAYER_CLASS_ID */ ) |
|
{ |
|
|
|
pErrMsg->Set(true, "GUI Control Component Error", "The texmap selected for the Dynamic Display Control on object \"%s\" is not a Plasma Dynamic Text Layer. Please fix.", node->GetName() ).Show(); |
|
return false; |
|
} |
|
|
|
const hsTArray<hsMaterialConverter::DoneMaterialData> &materials = hsMaterialConverter::Instance().DoneMaterials(); |
|
|
|
UInt32 i,count = pLayer->GetNumConversionTargets(); |
|
for( i = 0; i < count; i++ ) |
|
{ |
|
plLayerInterface *layIface = pLayer->GetConversionTarget( i ); |
|
|
|
ctrl->AddLayer( layIface ); |
|
|
|
plDynamicTextMap *map = plDynamicTextMap::ConvertNoRef( layIface->GetTexture() ); |
|
if( map != nil ) |
|
ctrl->AddMap( map ); |
|
|
|
UInt32 mat; |
|
bool found = false; |
|
for (mat=0; mat<materials.GetCount(); mat++) |
|
{ |
|
hsGMaterial *curMaterial = materials[mat].fHsMaterial; |
|
UInt32 lay; |
|
for (lay=0; lay<curMaterial->GetNumLayers(); lay++) |
|
{ |
|
if (layIface->BottomOfStack() == curMaterial->GetLayer(lay)) |
|
{ |
|
ctrl->AddMaterial(curMaterial); |
|
found = true; |
|
break; |
|
} |
|
} |
|
if (found) |
|
break; |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIMultiLineEdit Component /////////////////////////////////////////////////////////////// |
|
// |
|
// GUI element that can be dragged anywhere in the 2D viewing plane. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Class that accesses the paramblock below. |
|
class plGUIMultiLineEditComp : public plGUIControlBase |
|
{ |
|
protected: |
|
|
|
virtual pfGUIControlMod *IGetNewControl( void ) { return TRACKED_NEW pfGUIMultiLineEditCtrl; } |
|
virtual bool INeedsDynamicText( void ) { return true; } |
|
|
|
public: |
|
plGUIMultiLineEditComp(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefXparentBgnd, |
|
kRefScaleWithRes, |
|
kRefUseScroll, |
|
kRefScrollCtrl, |
|
}; |
|
}; |
|
|
|
static plGUISingleCtrlDlgProc sGUIMultiLineProc( plGUIMultiLineEditComp::kRefScrollCtrl, IDC_GUI_COMPSELBTN, |
|
"Select the control to use for scrolling this multi-line edit box", sScrollingClassesToSelect ); |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIMultiLineEditComp, gGUIMultiLineEditDesc, "GUI Multi-Line Edit Box", "GUIMultiLineEdit", COMP_TYPE_GUI, GUI_MULTILINE_CLASSID ) |
|
|
|
ParamBlockDesc2 gGUIMultiLineEditBoxBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUIMultiLineEdit"), 0, &gGUIMultiLineEditDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP + P_INCLUDE_PARAMS, plComponent::kRefComp, |
|
|
|
2, |
|
plGUIControlBase::kRollMain, IDD_COMP_GUIMULTILINE, IDS_COMP_GUIMULTILINE, 0, 0, &sGUIMultiLineProc, |
|
plGUIControlBase::kRollProc, IDD_COMP_GUIPROCROLLOUT, IDS_COMP_GUIPROCROLLOUT, 0, 0, nil, |
|
|
|
&sGUIControlProcParamTemplate, |
|
|
|
plGUIMultiLineEditComp::kRefXparentBgnd, _T( "xparentBgnd" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_XPARENT, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIMultiLineEditComp::kRefScaleWithRes, _T( "scaleWithRes" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_SCALERES, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIMultiLineEditComp::kRefUseScroll, _T( "enableScrolling" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_SCROLLCTRL, |
|
p_default, FALSE, |
|
p_enable_ctrls, 1, plGUIMultiLineEditComp::kRefScrollCtrl, |
|
end, |
|
|
|
plGUIMultiLineEditComp::kRefScrollCtrl, _T("scrollControl"), TYPE_INODE, 0, 0, |
|
p_prompt, IDS_COMP_GUI_SELECTSCROLL, |
|
p_accessor, &sGUIListBoxAccessor, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plGUIMultiLineEditComp::plGUIMultiLineEditComp() |
|
{ |
|
fClassDesc = &gGUIMultiLineEditDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIMultiLineEditComp::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::SetupProperties( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIMultiLineEditComp::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIMultiLineEditComp::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( !plGUIControlBase::Convert( node, pErrMsg ) ) |
|
return false; |
|
|
|
pfGUIMultiLineEditCtrl *ctrl = (pfGUIMultiLineEditCtrl *)fControl; |
|
|
|
if( fCompPB->GetInt( kRefXparentBgnd ) ) |
|
ctrl->SetFlag( pfGUIControlMod::kXparentBgnd ); |
|
|
|
if( fCompPB->GetInt( kRefScaleWithRes ) ) |
|
ctrl->SetFlag( pfGUIControlMod::kScaleTextWithResolution ); |
|
|
|
if( fCompPB->GetInt( kRefUseScroll ) ) |
|
{ |
|
// Get the scrolling control to use |
|
pfGUIValueCtrl *scroll = pfGUIValueCtrl::ConvertNoRef( GrabControlMod( fCompPB->GetINode( kRefScrollCtrl ) ) ); |
|
if( scroll != nil ) |
|
{ |
|
hsgResMgr::ResMgr()->AddViaNotify( scroll->GetKey(), TRACKED_NEW plGenRefMsg( ctrl->GetKey(), |
|
plRefMsg::kOnCreate, -1, pfGUIMultiLineEditCtrl::kRefScrollCtrl ), plRefFlags::kActiveRef ); |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIProgressCtrl Component /////////////////////////////////////////////////////////////////// |
|
// |
|
// GUI element that can be dragged anywhere in the 2D viewing plane. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Class that accesses the paramblock below. |
|
class plGUIProgressCtrlComponent : public plGUIControlBase |
|
{ |
|
protected: |
|
|
|
virtual pfGUIControlMod *IGetNewControl( void ) { return TRACKED_NEW pfGUIProgressCtrl; } |
|
virtual bool ICanHaveProxy( void ) { return false; } |
|
|
|
public: |
|
plGUIProgressCtrlComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefMinValue, |
|
kRefMaxValue, |
|
kRefStep, |
|
kReverseValues, |
|
kRefOrientation, |
|
kRefMouseMapping, |
|
kRefTriggerOnMouseUp, |
|
kRefAnimation, |
|
kRefAnimationNode, |
|
kRefAnimationNodeType, |
|
kRefAnimateSound, |
|
kRefAnimateSoundComp |
|
}; |
|
}; |
|
|
|
class plGUIProgressCtrlAccessor : public PBAccessor |
|
{ |
|
public: |
|
void Set( PB2Value& v, ReferenceMaker* owner, ParamID id, int tabIndex, TimeValue t ) |
|
{ |
|
if( id == plGUIProgressCtrlComponent::kRefAnimateSoundComp ) |
|
{ |
|
plGUIProgressCtrlComponent *comp = (plGUIProgressCtrlComponent *)owner; |
|
comp->NotifyDependents( FOREVER, PART_ALL, REFMSG_USER_COMP_REF_CHANGED ); |
|
} |
|
} |
|
}; |
|
|
|
static plGUIProgressCtrlAccessor sGUIProgressCtrlAccessor; |
|
|
|
class plGUISoundDlgProc : public ParamMap2UserDlgProc |
|
{ |
|
protected: |
|
ParamID fSoundID; |
|
int fSoundItem; |
|
TCHAR fTitle[ 128 ]; |
|
|
|
public: |
|
plGUISoundDlgProc( ParamID soundID, int soundItem, TCHAR *title ) |
|
{ |
|
fSoundID = soundID; |
|
fSoundItem = soundItem; |
|
strcpy( fTitle, title ); |
|
} |
|
|
|
BOOL DlgProc( TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
switch ( msg ) |
|
{ |
|
case WM_INITDIALOG: |
|
{ |
|
IParamBlock2 *pb = map->GetParamBlock(); |
|
|
|
INode *node = pb->GetINode( fSoundID ); |
|
TSTR newName( node ? node->GetName() : "Pick" ); |
|
::SetWindowText( ::GetDlgItem( hWnd, fSoundItem ), newName ); |
|
} |
|
return true; |
|
|
|
case WM_COMMAND: |
|
if( ( HIWORD( wParam ) == BN_CLICKED ) ) |
|
{ |
|
if( LOWORD( wParam ) == fSoundItem ) |
|
{ |
|
IParamBlock2 *pb = map->GetParamBlock(); |
|
plGUICtrlHitCallback hitCB( (INode *)pb->GetOwner(), pb, fSoundID, fTitle, true, GUI_SOUND_COMPONENT_ID ); |
|
GetCOREInterface()->DoHitByNameDialog( &hitCB ); |
|
|
|
INode* node = pb->GetINode( fSoundID ); |
|
TSTR newName( node ? node->GetName() : "Pick" ); |
|
::SetWindowText( ::GetDlgItem(hWnd, fSoundItem ), newName ); |
|
map->Invalidate( fSoundID ); |
|
::InvalidateRect( hWnd, NULL, TRUE ); |
|
return true; |
|
} |
|
} |
|
break; |
|
} |
|
|
|
return false; |
|
} |
|
|
|
void DeleteThis() {} |
|
}; |
|
|
|
static plGUISoundDlgProc sGUIProgressCtrlSndProc( plGUIProgressCtrlComponent::kRefAnimateSoundComp, IDC_GUI_ANIMSNDCOMP, |
|
"Select the sound to play when this control animates" ); |
|
|
|
static plPlasmaAnimSelectDlgProc sGUIProgressCtrlProc( plGUIProgressCtrlComponent::kRefAnimation, IDC_GUI_COMPSELBTN, |
|
plGUIProgressCtrlComponent::kRefAnimationNode, plGUIProgressCtrlComponent::kRefAnimationNodeType, IDC_GUI_ANIMNODESEL, |
|
"Select the animation to use when displaying this knob control", &sGUIProgressCtrlSndProc ); |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIProgressCtrlComponent, gGUIProgressCtrlDesc, "GUI Progress Control", "GUIProgressCtrl", COMP_TYPE_GUI, GUI_PROGRESS_CLASSID ) |
|
|
|
ParamBlockDesc2 gGUIProgressCtrlBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUIProgressCtrl"), 0, &gGUIProgressCtrlDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP + P_INCLUDE_PARAMS, plComponent::kRefComp, |
|
|
|
2, |
|
plGUIControlBase::kRollMain, IDD_COMP_GUIPROGRESS, IDS_COMP_GUIPROGRESS, 0, 0, &sGUIProgressCtrlProc, |
|
plGUIControlBase::kRollProc, IDD_COMP_GUIPROCROLLOUT, IDS_COMP_GUIPROCROLLOUT, 0, 0, nil, |
|
|
|
&sGUIControlProcParamTemplate, |
|
|
|
plGUIProgressCtrlComponent::kRefMinValue, _T("minValue"), TYPE_FLOAT, 0, 0, |
|
p_default, 0.0f, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_GUI_LOWER, IDC_GUI_LOWER_SPIN, SPIN_AUTOSCALE, |
|
end, |
|
|
|
plGUIProgressCtrlComponent::kRefMaxValue, _T("maxValue"), TYPE_FLOAT, 0, 0, |
|
p_default, 10.0f, |
|
p_range, -10000.f, 10000.f, // WHY do we even need to specify this? |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_GUI_UPPER, IDC_GUI_UPPER_SPIN, SPIN_AUTOSCALE, |
|
end, |
|
|
|
plGUIProgressCtrlComponent::kRefStep, _T("step"), TYPE_FLOAT, 0, 0, |
|
p_default, 1.0f, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SPINNER, EDITTYPE_POS_FLOAT, IDC_GUI_STEP, IDC_GUI_STEP_SPIN, SPIN_AUTOSCALE, |
|
end, |
|
|
|
plGUIProgressCtrlComponent::kReverseValues, _T("reverseValues"), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_REVERSE, |
|
p_default, FALSE, |
|
end, |
|
|
|
plGUIProgressCtrlComponent::kRefAnimation, _T("animation"), TYPE_INODE, 0, 0, |
|
p_prompt, IDS_COMP_GUI_SELECTANIM, |
|
end, |
|
|
|
plGUIProgressCtrlComponent::kRefAnimationNode, _T("animationNode"), TYPE_INODE, 0, 0, |
|
end, |
|
|
|
plGUIProgressCtrlComponent::kRefAnimationNodeType, _T("animationNodeType"), TYPE_INT, 0, 0, |
|
p_default, plAnimObjInterface::kUseOwnerNode, |
|
end, |
|
|
|
plGUIProgressCtrlComponent::kRefAnimateSound, _T( "animateSound" ), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_ANIMSND, |
|
p_default, FALSE, |
|
p_enable_ctrls, 1, plGUIProgressCtrlComponent::kRefAnimateSoundComp, |
|
end, |
|
|
|
plGUIProgressCtrlComponent::kRefAnimateSoundComp, _T("animateSoundComp"), TYPE_INODE, 0, 0, |
|
p_accessor, &sGUIProgressCtrlAccessor, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plGUIProgressCtrlComponent::plGUIProgressCtrlComponent() |
|
{ |
|
fClassDesc = &gGUIProgressCtrlDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIProgressCtrlComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
node->SetForceLocal( true ); |
|
|
|
plAnimObjInterface *iface = plAnimComponentBase::GetAnimInterface( fCompPB->GetINode( kRefAnimation ) ); |
|
if( iface != nil && iface->MightRequireSeparateMaterial() ) |
|
{ |
|
INode *restrict = ( fCompPB->GetInt( kRefAnimationNodeType ) == plAnimObjInterface::kUseParamBlockNode ) |
|
? fCompPB->GetINode( kRefAnimationNode ) |
|
: (INode *)node; |
|
|
|
if( restrict != nil ) |
|
{ |
|
node->SetForceMaterialCopy( true ); |
|
} |
|
} |
|
|
|
return plGUIControlBase::SetupProperties( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIProgressCtrlComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
// For hackery below (see warning below) |
|
#include "../plAvatar/plAGMasterMod.h" |
|
|
|
hsBool plGUIProgressCtrlComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( !plGUIControlBase::Convert( node, pErrMsg ) ) |
|
return false; |
|
|
|
pfGUIProgressCtrl *ctrl = (pfGUIProgressCtrl *)fControl; |
|
|
|
ctrl->SetRange( fCompPB->GetFloat( kRefMinValue ), fCompPB->GetFloat( kRefMaxValue ) ); |
|
ctrl->SetStep( fCompPB->GetFloat( kRefStep ) ); |
|
|
|
if( fCompPB->GetInt( kReverseValues ) ) |
|
ctrl->SetFlag( pfGUIProgressCtrl::kReverseValues ); |
|
|
|
// Get the animation to use |
|
plAnimObjInterface *iface = plAnimComponentBase::GetAnimInterface( fCompPB->GetINode( kRefAnimation ) ); |
|
if( iface != nil ) |
|
{ |
|
INode *restrict = ( fCompPB->GetInt( kRefAnimationNodeType ) == plAnimObjInterface::kUseParamBlockNode ) |
|
? fCompPB->GetINode( kRefAnimationNode ) |
|
: (INode *)node; |
|
|
|
|
|
hsTArray<plKey> keys; |
|
if( iface->GetKeyList( restrict, keys ) && keys.GetCount() > 0 ) |
|
ctrl->SetAnimationKeys( keys, iface->GetIfaceSegmentName( false ) ); |
|
} |
|
else |
|
{ |
|
// HACKERY WARNING: Old knobs assumed the animation was just the same one applied to our node, |
|
// so to avoid breaking old formats, if we can't grab an animObjInterface, we just grab the key |
|
// of the master mod of our node, like we would've before |
|
plAGMasterMod *master = node->GetAGMasterMod(); |
|
hsTArray<plKey> keys; |
|
keys.Append( master->GetKey() ); |
|
ctrl->SetAnimationKeys( keys, ENTIRE_ANIMATION_NAME ); |
|
} |
|
|
|
const char *errMsg = ISetSoundIndex( kRefAnimateSound, kRefAnimateSoundComp, pfGUIProgressCtrl::kAnimateSound, node ); |
|
if( errMsg != nil ) |
|
{ |
|
pErrMsg->Set( true, "GUI Sound Event Error", errMsg, node->GetName() ).Show(); |
|
pErrMsg->Set( false ); |
|
} |
|
|
|
return true; |
|
} |
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIClickMap Component /////////////////////////////////////////////////////////////////// |
|
// |
|
// GUI element that just keeps track of where on its surface (from 0-1) that it was clicked. |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
// Class that accesses the paramblock below. |
|
class plGUIClickMapComponent : public plGUIControlBase |
|
{ |
|
protected: |
|
|
|
virtual pfGUIControlMod *IGetNewControl( void ) { return TRACKED_NEW pfGUIClickMapCtrl; } |
|
virtual bool ICanHaveProxy( void ) { return false; } |
|
|
|
public: |
|
plGUIClickMapComponent(); |
|
void DeleteThis() { delete this; } |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool SetupProperties(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
|
|
hsBool PreConvert(plMaxNode *pNode, plErrorMsg *pErrMsg); |
|
hsBool Convert(plMaxNode *node, plErrorMsg *pErrMsg); |
|
|
|
enum |
|
{ |
|
kRefReportDragging |
|
}; |
|
}; |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIClickMapComponent, gGUIClickMapDesc, "GUI Clickable Map", "GUIClickMap", COMP_TYPE_GUI, GUI_CLICKMAP_CLASSID ) |
|
|
|
ParamBlockDesc2 gGUIClickMapBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUIClickMap"), 0, &gGUIClickMapDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP + P_INCLUDE_PARAMS, plComponent::kRefComp, |
|
|
|
2, |
|
plGUIControlBase::kRollMain, IDD_COMP_GUICLICKMAP, IDS_COMP_GUICLICKMAP, 0, 0, NULL, |
|
plGUIControlBase::kRollProc, IDD_COMP_GUIPROCROLLOUT, IDS_COMP_GUIPROCROLLOUT, 0, 0, nil, |
|
|
|
&sGUIControlProcParamTemplate, |
|
|
|
plGUIClickMapComponent::kRefReportDragging, _T("reportWhileDragging"), TYPE_BOOL, 0, 0, |
|
p_ui, plGUIControlBase::kRollMain, TYPE_SINGLECHEKBOX, IDC_GUI_REPORTDRAG, |
|
p_default, FALSE, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plGUIClickMapComponent::plGUIClickMapComponent() |
|
{ |
|
fClassDesc = &gGUIClickMapDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIClickMapComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
node->SetForceLocal( true ); |
|
return plGUIControlBase::SetupProperties( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIClickMapComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
return plGUIControlBase::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIClickMapComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
if( !plGUIControlBase::Convert( node, pErrMsg ) ) |
|
return false; |
|
|
|
pfGUIClickMapCtrl *ctrl = (pfGUIClickMapCtrl *)fControl; |
|
|
|
if( fCompPB->GetInt( kRefReportDragging ) ) |
|
ctrl->SetFlag( pfGUIClickMapCtrl::kReportDragging ); |
|
|
|
return true; |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUISkin Component //////////////////////////////////////////////////////////////////// |
|
// |
|
// Defines a skin to use when rendering certain GUI controls (just menus for now) |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
class pfGUISkinProc : public ParamMap2UserDlgProc |
|
{ |
|
protected: |
|
|
|
public: |
|
|
|
void DeleteThis() {} |
|
|
|
// virtual void Update( TimeValue t, Interval &valid, IParamMap2 *map ); |
|
|
|
BOOL DlgProc( TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); |
|
}; |
|
|
|
static pfGUISkinProc gGUISkinProc; |
|
|
|
// Component defined in pfGUISkinProc.h |
|
|
|
#define kDeclSkinRectValues( ref ) (plGUISkinComp::##ref + 0), _T("f##ref##.left"), TYPE_INT, 0, 0, p_default, 0, end, \ |
|
(plGUISkinComp::##ref + 1), _T("f##ref##.top"), TYPE_INT, 0, 0, p_default, 0, end, \ |
|
(plGUISkinComp::##ref + 2), _T("f##ref##.width"), TYPE_INT, 0, 0, p_default, 8, end, \ |
|
(plGUISkinComp::##ref + 3), _T("f##ref##.height"), TYPE_INT, 0, 0, p_default, 8, end |
|
|
|
#define kSetSkinRectValues( pb, ref, l, t, w, h ) { pb->SetValue( ref + 0, 0, (int) l ); \ |
|
pb->SetValue( ref + 1, 0, (int) t ); \ |
|
pb->SetValue( ref + 2, 0, (int) r ); \ |
|
pb->SetValue( ref + 3, 0, (int) b ); } |
|
|
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUISkinComp, gGUISkinDesc, "GUI Skin", "GUISkin", COMP_TYPE_GUI, GUI_SKIN_CLASSID ) |
|
|
|
static ParamBlockDesc2 gGUISkinBk |
|
( |
|
/// Main def |
|
plComponent::kBlkComp, _T("GUISkin"), 0, &gGUISkinDesc, P_AUTO_CONSTRUCT + P_AUTO_UI, plComponent::kRefComp, |
|
|
|
IDD_COMP_GUISKIN, IDS_COMP_GUISKIN, 0, 0, &gGUISkinProc, |
|
|
|
plGUISkinComp::kRefBitmap, _T("bitmap"), TYPE_TEXMAP, 0, 0, |
|
end, |
|
|
|
kDeclSkinRectValues( kRefUpLeftCorner ), |
|
kDeclSkinRectValues( kRefTopSpan ), |
|
kDeclSkinRectValues( kRefUpRightCorner ), |
|
kDeclSkinRectValues( kRefRightSpan ), |
|
kDeclSkinRectValues( kRefLowerRightCorner ), |
|
kDeclSkinRectValues( kRefBottomSpan ), |
|
kDeclSkinRectValues( kRefLowerLeftCorner ), |
|
kDeclSkinRectValues( kRefLeftSpan ), |
|
kDeclSkinRectValues( kRefMiddleFill ), |
|
kDeclSkinRectValues( kRefSelectedFill ), |
|
kDeclSkinRectValues( kRefSubMenuArrow ), |
|
kDeclSkinRectValues( kRefSelectedSubMenuArrow ), |
|
kDeclSkinRectValues( kRefTreeButtonClosed ), |
|
kDeclSkinRectValues( kRefTreeButtonOpen ), |
|
|
|
plGUISkinComp::kRefItemMargin, _T("itemMargin"), TYPE_INT, 0, 0, |
|
p_ui, TYPE_SPINNER, EDITTYPE_POS_INT, IDC_GUI_IMARGIN, IDC_GUI_IMARGIN_SPIN, SPIN_AUTOSCALE, |
|
p_default, 1, |
|
end, |
|
|
|
plGUISkinComp::kRefBorderMargin, _T("borderMargin"), TYPE_INT, 0, 0, |
|
p_ui, TYPE_SPINNER, EDITTYPE_POS_INT, IDC_GUI_BMARGIN, IDC_GUI_BMARGIN_SPIN, SPIN_AUTOSCALE, |
|
p_default, 4, |
|
end, |
|
|
|
end |
|
); |
|
|
|
// Editor proc |
|
extern HINSTANCE hInstance; |
|
|
|
BOOL pfGUISkinProc::DlgProc( TimeValue t, IParamMap2 *pmap, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) |
|
{ |
|
IParamBlock2 *pb = pmap->GetParamBlock(); |
|
plGUISkinComp *comp = (plGUISkinComp *)pb->GetOwner(); |
|
PBBitmap *bitmap; |
|
plLayerTex *layer = comp->GetSkinBitmap(); |
|
ICustButton *bmSelectBtn; |
|
|
|
switch( msg ) |
|
{ |
|
case WM_INITDIALOG: |
|
// Set projection map bitmap name |
|
bmSelectBtn = GetICustButton( GetDlgItem( hWnd, IDC_GUI_SKINBMAP ) ); |
|
if( bmSelectBtn != nil ) |
|
{ |
|
bitmap = ( layer == nil ) ? nil : layer->GetPBBitmap(); |
|
if( bitmap != nil ) |
|
bmSelectBtn->SetText( (TCHAR *)bitmap->bi.Filename() ); |
|
else |
|
bmSelectBtn->SetText( _T( "<none>" ) ); |
|
ReleaseICustButton( bmSelectBtn ); |
|
} |
|
|
|
return true; |
|
|
|
case WM_DESTROY: |
|
break; |
|
|
|
case WM_COMMAND: |
|
if( LOWORD( wParam ) == IDC_GUI_EDITELEM ) |
|
{ |
|
bitmap = ( layer == nil ) ? nil : layer->GetPBBitmap(); |
|
if( bitmap != nil ) |
|
{ |
|
pfGUISkinEditProc proc( comp ); |
|
DialogBox( hInstance, MAKEINTRESOURCE( IDD_COMP_SKINEDIT ), GetCOREInterface()->GetMAXHWnd(), proc.DlgProc ); |
|
} |
|
} |
|
|
|
else if( LOWORD( wParam ) == IDC_GUI_SKINBMAP ) |
|
{ |
|
BOOL selectedNewBitmap = layer->HandleBitmapSelection(); |
|
if( selectedNewBitmap ) |
|
{ |
|
bmSelectBtn = GetICustButton( GetDlgItem( hWnd, IDC_GUI_SKINBMAP ) ); |
|
bitmap = layer->GetPBBitmap(); |
|
bmSelectBtn->SetText( bitmap != nil ? (TCHAR *)bitmap->bi.Filename() : ""); |
|
ReleaseICustButton( bmSelectBtn ); |
|
} |
|
return false; |
|
} |
|
break; |
|
|
|
} |
|
return false; |
|
} |
|
|
|
plKey plGUISkinComp::GetConvertedSkinKey( void ) const |
|
{ |
|
if( fConvertedSkin != nil ) |
|
return fConvertedSkin->GetKey(); |
|
|
|
return nil; |
|
} |
|
|
|
UInt32 plGUISkinComp::GetNumMtls( void ) const |
|
{ |
|
return 1; |
|
} |
|
|
|
Texmap *plGUISkinComp::GetMtl( UInt32 idx ) |
|
{ |
|
return (Texmap *)GetSkinBitmap(); |
|
} |
|
|
|
//// GetSkinBitmap /////////////////////////////////////////////////////////// |
|
|
|
plLayerTex *plGUISkinComp::GetSkinBitmap( void ) |
|
{ |
|
// If we don't have one, create one |
|
plLayerTex *layer = (plLayerTex *)fCompPB->GetTexmap( kRefBitmap, 0 ); |
|
if( layer == nil || layer->ClassID() != LAYER_TEX_CLASS_ID ) |
|
{ |
|
layer = TRACKED_NEW plLayerTex; |
|
|
|
fCompPB->SetValue( kRefBitmap, 0, (Texmap *)layer ); |
|
} |
|
if( layer ) |
|
{ |
|
IParamBlock2* bitmapPB = layer->GetParamBlockByID( plLayerTex::kBlkBitmap ); |
|
if( bitmapPB->GetInt(kBmpScaling) != kScalingNone ) |
|
bitmapPB->SetValue(kBmpScaling, TimeValue(0), kScalingNone); |
|
} |
|
|
|
|
|
return layer; |
|
} |
|
|
|
plGUISkinComp::plGUISkinComp() |
|
{ |
|
fClassDesc = &gGUISkinDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUISkinComp::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
fConvertedSkin = nil; |
|
return true; |
|
} |
|
|
|
hsBool plGUISkinComp::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
// Create and assign key here, so other components can grab the key later |
|
if( fConvertedSkin != nil ) |
|
return true; // Only convert once, since we don't care what node we're on |
|
|
|
Texmap *texture = fCompPB->GetTexmap( kRefBitmap ); |
|
if( texture == nil || texture->ClassID() != LAYER_TEX_CLASS_ID || ( (plLayerTex *)texture )->GetPBBitmap() == nil ) |
|
{ |
|
pErrMsg->Set( true, "GUI Skin Convert Error", |
|
"The GUI skin component %s doesn't have a mipmap associated with it. This skin will not " |
|
"be exported.", GetINode()->GetName() ).CheckAndAsk(); |
|
pErrMsg->Set( false ); |
|
return true; |
|
} |
|
|
|
fConvertedSkin = TRACKED_NEW pfGUISkin(); |
|
hsgResMgr::ResMgr()->NewKey( IGetUniqueName(node), fConvertedSkin, node->GetLocation() ); |
|
|
|
return true; |
|
} |
|
|
|
hsBool plGUISkinComp::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
// Actually do the work of converting all the skin data |
|
if( fConvertedSkin == nil ) |
|
return true; // Eh? |
|
|
|
|
|
fConvertedSkin->SetMargins( fCompPB->GetInt( kRefItemMargin ), fCompPB->GetInt( kRefBorderMargin ) ); |
|
|
|
UInt32 i; |
|
for( i = 0; i < pfGUISkin::kNumElements; i++ ) |
|
{ |
|
ParamID id = ( i * 4 ) + kRefUpLeftCorner; |
|
|
|
fConvertedSkin->SetElement( i, fCompPB->GetInt( id + 0 ), fCompPB->GetInt( id + 1 ), |
|
fCompPB->GetInt( id + 2 ), fCompPB->GetInt( id + 3 ) ); |
|
} |
|
|
|
plLayerTex *layer= (plLayerTex *)fCompPB->GetTexmap( kRefBitmap ); |
|
if( layer != nil ) |
|
{ |
|
PBBitmap *texture = layer->GetPBBitmap(); |
|
if( texture != nil ) |
|
{ |
|
plBitmap *bMap = plLayerConverter::Instance().CreateSimpleTexture( texture->bi.Name(), fConvertedSkin->GetKey()->GetUoid().GetLocation(), 0, plMipmap::kForceNonCompressed | plMipmap::kAlphaChannelFlag | plMipmap::kNoMaxSize ); |
|
if( bMap != nil && plMipmap::ConvertNoRef( bMap ) != nil ) |
|
{ |
|
hsgResMgr::ResMgr()->AddViaNotify( bMap->GetKey(), TRACKED_NEW plGenRefMsg( fConvertedSkin->GetKey(), |
|
plRefMsg::kOnCreate, -1, pfGUISkin::kRefMipmap ), plRefFlags::kActiveRef ); |
|
} |
|
} |
|
} |
|
|
|
return true; |
|
} |
|
|
|
hsBool plGUISkinComp::DeInit(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
fConvertedSkin = nil; |
|
return true; |
|
} |
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
//// plGUIPopUpMenu Component /////////////////////////////////////////////////////////////////// |
|
// |
|
// Defines a pop-up menu, with an auto-anchor to the sceneObject it's attached to |
|
// |
|
///////////////////////////////////////////////////////////////////////////////////////////////// |
|
|
|
|
|
/*class plGUIMenuProc : public ParamMap2UserDlgProc |
|
{ |
|
protected: |
|
|
|
void ILoadPages( HWND hWnd, IParamBlock2 *pb ); |
|
|
|
public: |
|
|
|
void DeleteThis() {} |
|
|
|
BOOL DlgProc( TimeValue t, IParamMap2 *map, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); |
|
}; |
|
static plGUIMenuProc gGUIMenuProc; |
|
*/ |
|
|
|
static plGUISingleCtrlDlgProc sGUISkinSelectProc( plGUIMenuComponent::kRefSkin, IDC_GUI_SKIN, |
|
"Select the skin to use for this pop-up menu", sSkinClassesToSelect, |
|
&gGUIDialogProc ); |
|
|
|
//Max desc stuff necessary below. |
|
CLASS_DESC(plGUIMenuComponent, gGUIMenuDesc, "GUI Menu", "GUIMenu", COMP_TYPE_GUI, GUI_MENUANCHOR_CLASSID ) |
|
|
|
ParamBlockDesc2 gGUIMenuBk |
|
( // KLUDGE: not the defined block ID, but kept for backwards compat. |
|
plComponent::kBlkComp, _T("GUIMenu"), 0, &gGUIMenuDesc, P_AUTO_CONSTRUCT + P_AUTO_UI + P_MULTIMAP + P_INCLUDE_PARAMS, plComponent::kRefComp, |
|
|
|
3, |
|
plGUIMenuComponent::kMainRollout, IDD_COMP_GUIMENUANCHOR, IDS_COMP_GUIMENUANCHOR, 0, 0, &sGUISkinSelectProc, |
|
plGUIMenuComponent::kTagIDRollout, IDD_COMP_GUITAG, IDS_COMP_GUITAG, 0, 0, &gGUITagProc, |
|
plGUIMenuComponent::kSchemeRollout, IDD_COMP_GUISCHEME, IDS_COMP_GUISCHEME, 0, 0, &gGUIColorSchemeProc, |
|
|
|
&gGUIColorSchemeBk, |
|
|
|
plGUIMenuComponent::kRefDialogName, _T("MenuName"), TYPE_STRING, 0, 0, |
|
// p_ui, plGUIMenuComponent::kMainRollout, TYPE_EDITBOX, IDC_GUIDLG_NAME, |
|
end, |
|
|
|
plGUIMenuComponent::kRefAgeName, _T("ageName"), TYPE_STRING, 0, 0, |
|
p_default, _T( "GUI" ), |
|
end, |
|
|
|
plGUIMenuComponent::kRefVersion, _T("version"), TYPE_INT, 0, 0, |
|
p_ui, plGUIMenuComponent::kMainRollout, TYPE_SPINNER, EDITTYPE_POS_INT, IDC_GUI_VERSION, IDC_GUI_VERSION_SPIN, SPIN_AUTOSCALE, |
|
p_default, 0, |
|
end, |
|
|
|
plGUITagComponent::kRefCurrIDSel, _T("currSel"), TYPE_INT, 0, 0, |
|
end, |
|
|
|
plGUIMenuComponent::kRefSkin, _T("skin"), TYPE_INODE, 0, 0, |
|
end, |
|
|
|
plGUIMenuComponent::kRefNeverClose, _T("neverClose"), TYPE_BOOL, 0, 0, |
|
p_default, FALSE, |
|
p_ui, plGUIMenuComponent::kMainRollout, TYPE_SINGLECHEKBOX, IDC_GUI_NEVERCLOSE, |
|
end, |
|
|
|
plGUIMenuComponent::kRefModalOutside, _T("modalOutside"), TYPE_BOOL, 0, 0, |
|
p_default, FALSE, |
|
p_ui, plGUIMenuComponent::kMainRollout, TYPE_SINGLECHEKBOX, IDC_GUI_MODALOUTSIDE, |
|
end, |
|
|
|
plGUIMenuComponent::kRefOpenOnHover, _T("openSubsOnHover"), TYPE_BOOL, 0, 0, |
|
p_default, FALSE, |
|
p_ui, plGUIMenuComponent::kMainRollout, TYPE_SINGLECHEKBOX, IDC_GUI_HOVER, |
|
end, |
|
|
|
plGUIMenuComponent::kRefAlignment, _T("alignment"), TYPE_INT, 0, 0, |
|
p_default, 3, |
|
p_ui, plGUIMenuComponent::kMainRollout, TYPE_RADIO, 4, IDC_ALIGNRADIO1, IDC_ALIGNRADIO2, IDC_ALIGNRADIO3, IDC_ALIGNRADIO4, |
|
end, |
|
|
|
plGUIMenuComponent::kRefScaleWithScreenRes, _T("maintainSizeAcrossRes"), TYPE_BOOL, 0, 0, |
|
p_default, FALSE, |
|
p_ui, plGUIMenuComponent::kMainRollout, TYPE_SINGLECHEKBOX, IDC_GUI_SCALERES, |
|
end, |
|
|
|
end |
|
); |
|
|
|
plGUIMenuComponent::plGUIMenuComponent() : plGUIDialogComponent( true ) |
|
{ |
|
fClassDesc = &gGUIMenuDesc; |
|
fClassDesc->MakeAutoParamBlocks(this); |
|
} |
|
|
|
pfGUIDialogMod *plGUIMenuComponent::IMakeDialog( void ) |
|
{ |
|
return TRACKED_NEW pfGUIPopUpMenu(); |
|
} |
|
|
|
plKey plGUIMenuComponent::GetConvertedMenuKey( void ) const |
|
{ |
|
if( fConvertedMenu == nil ) |
|
return nil; |
|
|
|
return fConvertedMenu->GetKey(); |
|
} |
|
|
|
// SetupProperties - Internal setup and write-only set properties on the MaxNode. No reading |
|
// of properties on the MaxNode, as it's still indeterminant. |
|
hsBool plGUIMenuComponent::SetupProperties(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
// return plGUIDialogComponent::SetupProperties( node, pErrMsg ); |
|
fConvertedMenu = nil; |
|
return true; |
|
} |
|
|
|
hsBool plGUIMenuComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
pfGUIPopUpMenu *menu = fConvertedMenu; |
|
|
|
// hsBool b = plGUIDialogComponent::Convert( node, pErrMsg ); |
|
// if( b ) |
|
{ |
|
// pfGUIPopUpMenu *menu = pfGUIPopUpMenu::ConvertNoRef( fDialogMod ); |
|
// hsAssert( menu != nil, "Somehow got a bad poitner in GUIMenu::Convert()" ); |
|
|
|
INode *sNode = fCompPB->GetINode( kRefSkin ); |
|
if( sNode != nil ) |
|
{ |
|
plComponentBase *comp = ( (plMaxNode *)sNode )->ConvertToComponent(); |
|
if( comp != nil ) |
|
{ |
|
Class_ID nodeID = comp->ClassID(); |
|
hsAssert( nodeID == GUI_SKIN_CLASSID, "Bad node param in GUIMenu::Convert()" ); |
|
|
|
plGUISkinComp *skin = (plGUISkinComp *)comp; |
|
menu->SetSkin( skin->GetConvertedSkin() ); |
|
} |
|
} |
|
|
|
if( fCompPB->GetInt( kRefNeverClose ) ) |
|
menu->SetFlag( pfGUIPopUpMenu::kStayOpenAfterClick ); |
|
|
|
if( fCompPB->GetInt( kRefModalOutside ) ) |
|
menu->SetFlag( pfGUIPopUpMenu::kModalOutsideMenus ); |
|
|
|
if( fCompPB->GetInt( kRefOpenOnHover ) ) |
|
menu->SetFlag( pfGUIPopUpMenu::kOpenSubMenusOnHover ); |
|
|
|
if( fCompPB->GetInt( kRefScaleWithScreenRes ) ) |
|
menu->SetFlag( pfGUIPopUpMenu::kScaleWithResolution ); |
|
|
|
switch( fCompPB->GetInt( kRefAlignment ) ) |
|
{ |
|
case 0: menu->SetAlignment( pfGUIPopUpMenu::kAlignUpLeft ); break; |
|
case 1: menu->SetAlignment( pfGUIPopUpMenu::kAlignUpRight ); break; |
|
case 2: menu->SetAlignment( pfGUIPopUpMenu::kAlignDownLeft ); break; |
|
case 3: menu->SetAlignment( pfGUIPopUpMenu::kAlignDownRight ); break; |
|
} |
|
} |
|
|
|
// Note: we use the owning dialog of our anchor object as the context, i.e. who translates |
|
// our point at runtime into screen coordinates |
|
menu->SetOriginAnchor( node->GetSceneObject(), plGUIDialogComponent::GetNodeDialog( node ) ); |
|
|
|
const plLocation &loc = menu->GetKey()->GetUoid().GetLocation(); |
|
|
|
// Create the rendermod |
|
plPostEffectMod *renderMod = TRACKED_NEW plPostEffectMod; |
|
hsgResMgr::ResMgr()->NewKey( IGetUniqueName(node), renderMod, loc ); |
|
|
|
renderMod->SetHither( 0.5f ); |
|
renderMod->SetYon( 200.f ); |
|
renderMod->SetNodeKey( fConvertedNode ); |
|
|
|
float scrnWidth = 20.f; |
|
|
|
// fovX should be such that scrnWidth is the projected width at z=100 |
|
float fovX = atan( scrnWidth / ( 2.f * 100.f ) ) * 2.f; |
|
float fovY = fovX;// * 3.f / 4.f; |
|
|
|
renderMod->SetFovX( fovX * 180.f / hsScalarPI ); |
|
renderMod->SetFovY( fovY * 180.f / hsScalarPI ); |
|
|
|
|
|
hsgResMgr::ResMgr()->AddViaNotify( renderMod->GetKey(), TRACKED_NEW plNodeRefMsg( fConvertedNode, plRefMsg::kOnCreate, -1, plNodeRefMsg::kGeneric ), plRefFlags::kActiveRef ); |
|
hsgResMgr::ResMgr()->AddViaNotify( fConvertedNode, TRACKED_NEW plGenRefMsg( renderMod->GetKey(), plRefMsg::kOnCreate, 0, plPostEffectMod::kNodeRef ), plRefFlags::kPassiveRef ); |
|
|
|
menu->SetRenderMod( renderMod ); |
|
menu->SetName( fCompPB->GetStr( kRefDialogName ) ); |
|
|
|
// Create the dummy scene object to hold the menu |
|
plSceneObject *newObj = TRACKED_NEW plSceneObject; |
|
hsgResMgr::ResMgr()->NewKey( IGetUniqueName(node), newObj, loc ); |
|
|
|
// *#&$(*@&#$ need a coordIface... |
|
plCoordinateInterface *newCI = TRACKED_NEW plCoordinateInterface; |
|
hsgResMgr::ResMgr()->NewKey( IGetUniqueName(node), newCI, loc ); |
|
|
|
|
|
hsgResMgr::ResMgr()->AddViaNotify( menu->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, -1, plObjRefMsg::kModifier ), plRefFlags::kActiveRef ); |
|
|
|
hsgResMgr::ResMgr()->AddViaNotify( newCI->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, -1, plObjRefMsg::kInterface ), plRefFlags::kActiveRef ); |
|
hsgResMgr::ResMgr()->AddViaNotify( renderMod->GetKey(), TRACKED_NEW plObjRefMsg( newObj->GetKey(), plRefMsg::kOnCreate, -1, plObjRefMsg::kModifier ), plRefFlags::kActiveRef ); |
|
|
|
newObj->SetSceneNode( fConvertedNode ); |
|
menu->SetSceneNodeKey( fConvertedNode ); |
|
|
|
{ |
|
hsMatrix44 l2w, w2l; |
|
l2w.Reset(); |
|
l2w.GetInverse( &w2l ); |
|
newObj->SetTransform( l2w, w2l ); |
|
} |
|
|
|
// Should be done now... |
|
return true; |
|
} |
|
|
|
hsBool plGUIMenuComponent::PreConvert(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
// Create and assign key here, so other components can grab the key later |
|
if( fConvertedMenu != nil ) |
|
return true; // Only convert once, since we don't care what node we're on |
|
|
|
/// Create an entirely new sceneNode for us |
|
Int32 seqNum = plPageInfoUtils::GetSeqNumFromAgeDesc( fCompPB->GetStr( kRefAgeName ), fCompPB->GetStr( kRefDialogName ) ); |
|
Int32 newNum = plPluginResManager::ResMgr()->VerifySeqNumber( seqNum, fCompPB->GetStr( kRefAgeName ), fCompPB->GetStr( kRefDialogName ) ); |
|
if( newNum != seqNum ) |
|
{ |
|
if( !fSeqNumValidated ) |
|
{ |
|
char errMsg[ 512 ]; |
|
sprintf( errMsg, "GUI Menu Component %s has an invalid location sequence number (0x%X). Temporarily using a valid one (0x%X).", |
|
node->GetName(), seqNum, newNum ); |
|
pErrMsg->Set( true, "PageInfo Convert Error", errMsg ).Show(); |
|
pErrMsg->Set( false ); |
|
fSeqNumValidated = true; |
|
} |
|
seqNum = newNum; |
|
} |
|
|
|
fConvertedNode = plPluginResManager::ResMgr()->NameToLoc( fCompPB->GetStr( kRefAgeName ), fCompPB->GetStr( kRefDialogName ), seqNum ); |
|
if( !fConvertedNode ) |
|
{ |
|
pErrMsg->Set( true, "GUI Menu Component Error", "GUI MenuComponent %s has a Missing Location. Nuke the files in the dat directory and re-export.",((INode*)node)->GetName()).Show(); |
|
return false; |
|
} |
|
|
|
fConvertedMenu = TRACKED_NEW pfGUIPopUpMenu(); |
|
hsgResMgr::ResMgr()->NewKey( IGetUniqueName(node), fConvertedMenu, fConvertedNode->GetUoid().GetLocation() ); |
|
|
|
return true; |
|
|
|
// return plGUIDialogComponent::PreConvert( node, pErrMsg ); |
|
} |
|
|
|
hsBool plGUIMenuComponent::DeInit(plMaxNode *node, plErrorMsg *pErrMsg) |
|
{ |
|
fConvertedMenu = nil; |
|
fConvertedNode = nil; |
|
return true; |
|
} |
|
|
|
|
|
|