Files
FC1/Editor/TrackViewNodes.cpp
romkazvo 34d6c5d489 123
2023-08-07 19:29:24 +08:00

792 lines
19 KiB
C++

// TrackViewNodes.cpp : implementation file
//
#include "stdafx.h"
#include "TrackViewNodes.h"
#include "TrackViewKeyList.h"
#include "TrackViewUndo.h"
#include "StringDlg.h"
#include "IMovieSystem.h"
#include "Objects\ObjectManager.h"
// CTrackViewNodes
IMPLEMENT_DYNAMIC(CTrackViewNodes, CTreeCtrl)
CTrackViewNodes::CTrackViewNodes()
{
m_keysCtrl = 0;
}
CTrackViewNodes::~CTrackViewNodes()
{
}
BEGIN_MESSAGE_MAP(CTrackViewNodes, CTreeCtrlEx)
ON_NOTIFY_REFLECT(TVN_ITEMEXPANDED, OnTvnItemexpanded)
ON_WM_CREATE()
ON_NOTIFY_REFLECT(NM_RCLICK, OnNMRclick)
ON_WM_VSCROLL()
ON_NOTIFY_REFLECT(TVN_SELCHANGED, OnTvnSelchanged)
ON_NOTIFY_REFLECT(NM_DBLCLK, OnNMDblclk)
ON_WM_KEYDOWN()
END_MESSAGE_MAP()
void CTrackViewNodes::RefreshNodes()
{
SetSequence(m_sequence);
}
CTrackViewNodes::SItemInfo* CTrackViewNodes::GetSelectedNode()
{
HTREEITEM hItem=GetSelectedItem();
if (!hItem)
return NULL;
return (SItemInfo*)GetItemData(hItem);
}
void CTrackViewNodes::AddNode( IAnimNode *node )
{
AddNodeItem( node,TVI_ROOT );
}
//////////////////////////////////////////////////////////////////////////
void CTrackViewNodes::AddNodeItem( IAnimNode *node,HTREEITEM root )
{
bool bNeedExpand = false;
HTREEITEM MyRoot=root;
CBaseObject *pBaseObject=GetIEditor()->GetObjectManager()->FindAnimNodeOwner(node);
if (pBaseObject)
{
// connect to parent if it is in treeview already
CBaseObject *pParent=pBaseObject->GetParent();
if (pParent)
{
HTREEITEM hParent=GetChildNode(root, pParent->GetAnimNode());
if (hParent!=NULL)
MyRoot=hParent;
}
}
int nNodeImage = 1;
EAnimNodeType nodeType = node->GetType();
switch (nodeType)
{
case ANODE_ENTITY: nNodeImage = 1; break;
case ANODE_CAMERA: nNodeImage = 1; break;
case ANODE_SCRIPTVAR: nNodeImage = 14; break;
case ANODE_CVAR: nNodeImage = 15; break;
case ANODE_MATERIAL: nNodeImage = 16; break;
}
HTREEITEM hItem = InsertItem( node->GetName(),nNodeImage,nNodeImage,MyRoot);
//SetItemState(MyRoot, TVIS_BOLD, TVIS_BOLD);
SetItemState(hItem, TVIS_BOLD, TVIS_BOLD);
SItemInfo *pItemInfo = &(*m_itemInfos.insert(m_itemInfos.begin(),SItemInfo()));
pItemInfo->node = node;
pItemInfo->baseObj = pBaseObject;
pItemInfo->track = 0;
pItemInfo->paramId = 0;
SetItemData( hItem,(DWORD_PTR)pItemInfo );
if (MyRoot != root)
{
// Expand root object.
Expand( MyRoot,TVE_EXPAND );
}
if (node->GetFlags()&ANODE_FLAG_EXPANDED)
{
bNeedExpand = true;
}
IAnimBlock *anim = node->GetAnimBlock();
if (anim)
{
int type;
IAnimTrack *track;
IAnimNode::SParamInfo paramInfo;
for (int i = 0; i < anim->GetTrackCount(); i++)
{
if (!anim->GetTrackInfo( i,type,&track ))
continue;
if (!track)
continue;
if (track->GetFlags() & ATRACK_HIDDEN)
continue;
if (!node->GetParamInfoFromId(type,paramInfo))
continue;
int nImage = 13; // Default
if (type == APARAM_FOV)
nImage = 2;
if (type == APARAM_POS)
nImage = 3;
if (type == APARAM_ROT)
nImage = 4;
if (type == APARAM_SCL)
nImage = 5;
if (type == APARAM_EVENT)
nImage = 6;
if (type == APARAM_VISIBLE)
nImage = 7;
if (type == APARAM_CAMERA)
nImage = 8;
if ((type >= APARAM_SOUND1) && (type <= APARAM_SOUND3))
nImage = 9;
if ((type >= APARAM_CHARACTER1) && (type <= APARAM_CHARACTER3))
nImage = 10;
if (type == APARAM_SEQUENCE)
nImage = 11;
if ((type >= APARAM_EXPRESSION1) && (type <= APARAM_EXPRESSION3))
nImage = 12;
if (type == APARAM_FLOAT_1)
nImage = 13;
HTREEITEM hTrackItem = InsertItem( paramInfo.name,nImage,nImage,hItem );
SItemInfo *pItemInfo = &(*m_itemInfos.insert(m_itemInfos.begin(),SItemInfo()));
pItemInfo->node = node;
pItemInfo->paramId = type;
pItemInfo->track = track;
SetItemData( hTrackItem,(DWORD_PTR)pItemInfo );
}
}
if (pBaseObject)
{
// connect children if they are in treeview already
for (int i=0;i<pBaseObject->GetChildCount();i++)
{
CBaseObject *pChild=pBaseObject->GetChild(i);
HTREEITEM hChild=GetChildNode(root, pChild->GetAnimNode());
if (hChild!=NULL)
{
HTREEITEM hNewItem=CopyBranch(hChild, hItem);
//SetItemState(hItem, TVIS_BOLD, TVIS_BOLD);
SetItemState(hNewItem, TVIS_BOLD, TVIS_BOLD);
DeleteItem(hChild);
// If node have child nodes. expand it.
bNeedExpand = true;
}
}
}
if (bNeedExpand)
{
// If node have child nodes. expand it.
Expand( hItem,TVE_EXPAND );
}
}
//////////////////////////////////////////////////////////////////////////
void CTrackViewNodes::SetKeyListCtrl( CTrackViewKeys *keysCtrl )
{
m_keysCtrl = keysCtrl;
//SyncKeyCtrl();
}
//////////////////////////////////////////////////////////////////////////
void CTrackViewNodes::SyncKeyCtrl()
{
if (!m_keysCtrl)
return;
m_keysCtrl->ResetContent();
if (!m_sequence)
return;
HTREEITEM hItem = GetFirstVisibleItem();
while (hItem)
{
SItemInfo *pItemInfo = (SItemInfo*)GetItemData(hItem);
if (pItemInfo && pItemInfo->track)
{
m_keysCtrl->AddItem( CTrackViewKeyList::Item(pItemInfo->node,pItemInfo->paramId,pItemInfo->track) );
}
else
{
m_keysCtrl->AddItem( CTrackViewKeyList::Item() );
}
hItem = GetNextVisibleItem(hItem);
}
}
// CTrackViewNodes message handlers
void CTrackViewNodes::OnTvnItemexpanded(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
SItemInfo *pItemInfo = (SItemInfo*)GetItemData(pNMTreeView->itemNew.hItem);
if (pItemInfo && pItemInfo->node)
{
IAnimNode *node = pItemInfo->node;
if ((pNMTreeView->itemNew.state & TVIS_EXPANDED) || (pNMTreeView->itemNew.state & TVIS_EXPANDPARTIAL))
{
// Mark node expanded
node->SetFlags( node->GetFlags()|ANODE_FLAG_EXPANDED );
}
else
{
// Mark node collapsed.
node->SetFlags( node->GetFlags()&(~ANODE_FLAG_EXPANDED) );
}
}
SyncKeyCtrl();
*pResult = 0;
}
//////////////////////////////////////////////////////////////////////////
int CTrackViewNodes::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CTreeCtrl::OnCreate(lpCreateStruct) == -1)
return -1;
// Create the list
CMFCUtils::LoadTrueColorImageList( m_cImageList,IDB_TRACKVIEW_NODES,16,RGB(255,0,255) );
SetImageList( &m_cImageList,TVSIL_NORMAL );
return 0;
}
//////////////////////////////////////////////////////////////////////////
void CTrackViewNodes::CreateAnimNode( int type,const char *sName )
{
IAnimNode *pAnimNode = GetIEditor()->GetSystem()->GetIMovieSystem()->CreateNode( type );
if (pAnimNode && m_sequence->AddNode(pAnimNode))
{
pAnimNode->SetName( sName );
pAnimNode->CreateDefaultTracks();
}
RefreshNodes();
}
//////////////////////////////////////////////////////////////////////////
void CTrackViewNodes::SetSequence( IAnimSequence *seq )
{
DeleteAllItems();
m_sequence = seq;
if (!m_sequence)
return;
// Create root item.
HTREEITEM hRootItem = InsertItem( seq->GetName(),0,0,TVI_ROOT );
SetItemData(hRootItem,(DWORD_PTR)0);
SetItemState(hRootItem, TVIS_BOLD, TVIS_BOLD);
for (int i = 0; i < seq->GetNodeCount(); i++)
{
IAnimNode *node = seq->GetNode(i);
AddNodeItem( node,hRootItem );
}
Expand( hRootItem,TVE_EXPAND );
SyncKeyCtrl();
}
void CTrackViewNodes::OnNMRclick(NMHDR *pNMHDR, LRESULT *pResult)
{
CPoint point;
SItemInfo *pItemInfo = 0;
if (!m_sequence)
return;
// Find node under mouse.
GetCursorPos( &point );
ScreenToClient( &point );
// Select the item that is at the point myPoint.
UINT uFlags;
HTREEITEM hItem = HitTest(point,&uFlags);
if ((hItem != NULL) && (TVHT_ONITEM & uFlags))
{
pItemInfo = (SItemInfo*)GetItemData(hItem);
}
// Create pop up menu.
CMenu menu;
CMenu menuAddTrack;
menu.CreatePopupMenu();
if (!pItemInfo || !pItemInfo->node)
{
menu.AppendMenu( MF_STRING,500,_T("Add Selected Entity Node") );
menu.AppendMenu( MF_STRING,501,_T("Add Scene Node") );
menu.AppendMenu( MF_STRING,502,_T("Add Console Variable Node") );
menu.AppendMenu( MF_STRING,503,_T("Add Script Variable Node") );
menu.AppendMenu( MF_STRING,504,_T("Add Material Node") );
}
else
{
if (pItemInfo && pItemInfo->node && pItemInfo->track == 0)
{
menu.AppendMenu( MF_STRING,10,"Remove Node" );
}
if (pItemInfo && pItemInfo->node != 0)
{
if (pItemInfo->node->GetFlags() & ANODE_FLAG_CAN_CHANGE_NAME)
{
menu.AppendMenu( MF_STRING,11,"Rename Node" );
}
}
menu.AppendMenu( MF_SEPARATOR,0,"" );
}
// add tracks menu
menuAddTrack.CreatePopupMenu();
bool bTracksToAdd=false;
if (pItemInfo && pItemInfo->node != 0)
{
IAnimNode::SParamInfo paramInfo;
// List`s which tracks can be added to animation node.
for (int i = 0; i < pItemInfo->node->GetParamCount(); i++)
{
if (!pItemInfo->node->GetParamInfo( i,paramInfo ))
continue;
int flags = 0;
IAnimTrack *track = pItemInfo->node->GetTrack( paramInfo.paramId );
if (track)
{
continue;
//flags |= MF_CHECKED;
}
menuAddTrack.AppendMenu( MF_STRING|flags,1000+paramInfo.paramId,paramInfo.name );
bTracksToAdd=true;
}
}
if (bTracksToAdd)
menu.AppendMenu(MF_POPUP,(UINT_PTR)menuAddTrack.m_hMenu,"Add Track");
// delete track menu
if (pItemInfo && pItemInfo->node && pItemInfo->track)
{
menu.AppendMenu(MF_STRING, 299, "Remove Track");
}
if (bTracksToAdd || (pItemInfo && pItemInfo->track))
menu.AppendMenu( MF_SEPARATOR,0,"" );
if (pItemInfo && pItemInfo->node != 0)
{
CString str;
str.Format( "%s Tracks",pItemInfo->node->GetName() );
menu.AppendMenu( MF_STRING|MF_DISABLED,0,str );
// Show tracks in anim node.
IAnimBlock *anim = pItemInfo->node->GetAnimBlock();
if (anim)
{
IAnimNode::SParamInfo paramInfo;
int type;
IAnimTrack *track;
for (int i = 0; i < anim->GetTrackCount(); i++)
{
if (!anim->GetTrackInfo( i,type,&track ))
continue;
if (!pItemInfo->node->GetParamInfo( type,paramInfo ))
continue;
// change hidden flag for this track.
int checked = MF_CHECKED;
if (track->GetFlags() & ATRACK_HIDDEN)
{
checked = MF_UNCHECKED;
}
menu.AppendMenu( MF_STRING|checked,100+i,CString( " " ) + paramInfo.name );
}
}
}
GetCursorPos( &point );
int cmd = menu.TrackPopupMenu( TPM_RETURNCMD|TPM_LEFTALIGN|TPM_LEFTBUTTON,point.x,point.y,this->GetParent()->GetParent() );
//////////////////////////////////////////////////////////////////////////
// Check Remove Node.
if (cmd == 10)
{
// Remove node under mouse.
if (pItemInfo)
{
CUndo undo("Remove Anim Node");
CUndo::Record( new CUndoAnimSequenceObject(m_sequence) );
m_sequence->RemoveNode(pItemInfo->node);
RefreshNodes();
}
}
//////////////////////////////////////////////////////////////////////////
// Add scene node.
if (cmd == 500)
{
AddSelectedNodes();
}
//////////////////////////////////////////////////////////////////////////
// Add scene node.
if (cmd == 501)
{
m_sequence->AddSceneNode();
RefreshNodes();
}
//////////////////////////////////////////////////////////////////////////
// Add cvar node.
if (cmd == 502)
{
CStringDlg dlg( _T("Console Variable Name") );
if (dlg.DoModal() == IDOK && !dlg.GetString().IsEmpty())
{
CreateAnimNode( ANODE_CVAR,dlg.GetString() );
}
}
//////////////////////////////////////////////////////////////////////////
// Add script var node.
if (cmd == 503)
{
CStringDlg dlg( _T("Script Variable Name") );
if (dlg.DoModal() == IDOK && !dlg.GetString().IsEmpty())
{
CreateAnimNode( ANODE_SCRIPTVAR,dlg.GetString() );
}
}
//////////////////////////////////////////////////////////////////////////
// Add Material node.
if (cmd == 504)
{
CStringDlg dlg( _T("Material Name") );
if (dlg.DoModal() == IDOK && !dlg.GetString().IsEmpty())
{
CreateAnimNode( ANODE_MATERIAL,dlg.GetString() );
}
}
//////////////////////////////////////////////////////////////////////////
// Check Rename Node.
if (cmd == 11 && pItemInfo && pItemInfo->node)
{
// Rename node under cursor.
CStringDlg dlg( _T("Rename Node") );
dlg.SetString(pItemInfo->node->GetName());
if (dlg.DoModal() == IDOK)
{
pItemInfo->node->SetName( dlg.GetString() );
RefreshNodes();
}
}
if (cmd >= 1000 && cmd < 2000)
{
if (pItemInfo)
{
IAnimNode *node = pItemInfo->node;
IAnimBlock *anim = node->GetAnimBlock();
if (anim)
{
CUndo undo("Create Anim Track");
CUndo::Record( new CUndoAnimSequenceObject(m_sequence) );
int paramId = cmd-1000;
node->CreateTrack( paramId );
ExpandNode(node);
}
}
}
if (cmd == 299)
{
if (pItemInfo)
{
IAnimNode *node = pItemInfo->node;
IAnimBlock *anim = node->GetAnimBlock();
if (anim)
{
if (AfxMessageBox("Are you sure you want to delete this track ? Undo will not be available !", MB_ICONQUESTION | MB_YESNO)==IDYES)
{
CUndo undo("Remove Anim Track");
CUndo::Record( new CUndoAnimSequenceObject(m_sequence) );
node->RemoveTrack(pItemInfo->track);
ExpandNode(node);
}
}
}
}
if (cmd >= 100 && cmd < 200)
{
if (pItemInfo)
{
IAnimNode *node = pItemInfo->node;
IAnimBlock *anim = node->GetAnimBlock();
if (anim)
{
CUndo undo("Modify Sequence");
CUndo::Record( new CUndoAnimSequenceObject(m_sequence) );
int type;
IAnimTrack *track;
for (int i = 0; i < anim->GetTrackCount(); i++)
{
if (!anim->GetTrackInfo( i,type,&track ))
continue;
if (cmd-100 == i)
{
// change hidden flag for this track.
if (track->GetFlags() & ATRACK_HIDDEN)
track->SetFlags( track->GetFlags() & ~ATRACK_HIDDEN );
else
track->SetFlags( track->GetFlags() | ATRACK_HIDDEN );
}
RefreshNodes();
ExpandNode( node );
break;
}
}
}
}
// processed
*pResult = 1;
}
void CTrackViewNodes::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
CTreeCtrl::OnVScroll(nSBCode, nPos, pScrollBar);
SyncKeyCtrl();
}
void CTrackViewNodes::OnTvnSelchanged(NMHDR *pNMHDR, LRESULT *pResult)
{
LPNMTREEVIEW pNMTreeView = reinterpret_cast<LPNMTREEVIEW>(pNMHDR);
if (m_keysCtrl)
{
SItemInfo *pItemInfo = (SItemInfo*)GetItemData(pNMTreeView->itemNew.hItem);
if (pItemInfo && pItemInfo->track)
{
for (int i = 0; i < m_keysCtrl->GetCount(); i++)
{
if (m_keysCtrl->GetTrack(i) == pItemInfo->track)
{
m_keysCtrl->SetCurSel(i);
break;
}
}
}
else
{
m_keysCtrl->SetCurSel(-1);
}
}
*pResult = 0;
}
//////////////////////////////////////////////////////////////////////////
HTREEITEM CTrackViewNodes::GetChildNode( HTREEITEM hItem,IAnimNode *node )
{
// Look at all of the root-level items
while (hItem != NULL)
{
SItemInfo *pItemInfo = (SItemInfo*)GetItemData(hItem);
if (pItemInfo)
{
if (pItemInfo->node == node && pItemInfo->track == 0)
{
return hItem;
}
}
HTREEITEM hChild = GetNextItem( hItem, TVGN_CHILD);
HTREEITEM hRes=GetChildNode(hChild,node);
if (hRes!=NULL)
return hRes;
hItem = GetNextItem( hItem, TVGN_NEXT);
}
return NULL;
}
//////////////////////////////////////////////////////////////////////////
bool CTrackViewNodes::ExpandChildNode( HTREEITEM hItem,IAnimNode *node )
{
// Look at all of the root-level items
while (hItem != NULL)
{
SItemInfo *pItemInfo = (SItemInfo*)GetItemData(hItem);
if (pItemInfo)
{
if (pItemInfo->node == node && pItemInfo->track == 0)
{
HTREEITEM hParent = GetParentItem(hItem);
if (hParent != NULL)
Expand(hParent, TVE_EXPAND);
Expand( hItem,TVE_EXPAND );
EnsureVisible(hItem);
return true;
}
}
HTREEITEM hChild = GetNextItem( hItem, TVGN_CHILD);
if (ExpandChildNode(hChild,node))
return true;
hItem = GetNextItem( hItem, TVGN_NEXT);
}
return false;
}
//////////////////////////////////////////////////////////////////////////
void CTrackViewNodes::ExpandNode( IAnimNode *node )
{
// Look at all of the root-level items
HTREEITEM hCurrent = GetRootItem();
ExpandChildNode( GetNextItem(GetRootItem(),TVGN_CHILD),node );
}
//////////////////////////////////////////////////////////////////////////
void CTrackViewNodes::AddSelectedNodes()
{
CUndo undo("Add Anim Node(s)");
CUndo::Record( new CUndoAnimSequenceObject(m_sequence) );
// Add selected nodes.
CSelectionGroup *sel = GetIEditor()->GetSelection();
for (int i = 0; i < sel->GetCount(); i++)
{
CBaseObject *obj = sel->GetObject(i);
if (obj && obj->GetAnimNode())
{
IAnimNode *pAnimNode = obj->GetAnimNode();
if (!m_sequence->AddNode(pAnimNode))
continue;
IAnimBlock *pAnimBlock=pAnimNode->GetAnimBlock();
if (pAnimBlock) // lets add basic tracks
{
pAnimNode->CreateDefaultTracks();
}
// Force default parameters.
pAnimNode->SetPos(0,obj->GetPos());
Quat rotate;
rotate.SetRotationXYZ( DEG2RAD(obj->GetAngles()));
pAnimNode->SetRotate(0,rotate);
pAnimNode->SetScale(0,obj->GetScale());
}
}
RefreshNodes();
for (int i = 0; i < sel->GetCount(); i++)
{
CBaseObject *obj = sel->GetObject(i);
if (obj && obj->GetAnimNode())
ExpandNode( obj->GetAnimNode() );
}
}
//////////////////////////////////////////////////////////////////////////
void CTrackViewNodes::AddSceneNodes()
{
CUndo undo("Add Scene Node");
CUndo::Record( new CUndoAnimSequenceObject(m_sequence) );
IAnimNode *pSceneNode=m_sequence->AddSceneNode();
if (!pSceneNode)
AfxMessageBox("Scene-track already exists.", MB_ICONEXCLAMATION | MB_OK);
else
{
pSceneNode->CreateDefaultTracks();
RefreshNodes();
ExpandNode(pSceneNode);
}
}
//////////////////////////////////////////////////////////////////////////
// Select object in Editor with Double click.
//////////////////////////////////////////////////////////////////////////
void CTrackViewNodes::OnNMDblclk(NMHDR *pNMHDR, LRESULT *pResult)
{
*pResult = 0;
CPoint point;
SItemInfo *pItemInfo = 0;
if (!m_sequence)
return;
// Find node under mouse.
GetCursorPos( &point );
ScreenToClient( &point );
// Select the item that is at the point myPoint.
UINT uFlags;
HTREEITEM hItem = HitTest(point,&uFlags);
if ((hItem != NULL) && (TVHT_ONITEM & uFlags))
{
pItemInfo = (SItemInfo*)GetItemData(hItem);
}
if (pItemInfo && pItemInfo->node)
{
// Double Clicked on node or track.
// Make this object selected in Editor.
CBaseObject *obj = GetIEditor()->GetObjectManager()->FindAnimNodeOwner(pItemInfo->node);
if (obj)
{
GetIEditor()->ClearSelection();
GetIEditor()->SelectObject(obj);
// Disable expanding on dblclick.
*pResult = TRUE;
}
}
}
void CTrackViewNodes::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (nChar == VK_DELETE)
{
if (!m_sequence)
return;
SItemInfo *pItemInfo = GetSelectedNode();
if (pItemInfo)
{
if (pItemInfo->node && pItemInfo->track)
{
// Delete track.
if (AfxMessageBox("Delete Selected Track?", MB_ICONQUESTION|MB_YESNO)==IDYES)
{
IAnimNode *node = pItemInfo->node;
CUndo undo("Remove Anim Track");
CUndo::Record( new CUndoAnimSequenceObject(m_sequence) );
node->RemoveTrack( pItemInfo->track );
ExpandNode( node );
}
}
else if (pItemInfo->node && pItemInfo->track == 0)
{
// Delete node.
if (AfxMessageBox("Delete Selected Animation Node?", MB_ICONQUESTION|MB_YESNO)==IDYES)
{
CUndo undo("Remove Anim Node");
CUndo::Record( new CUndoAnimSequenceObject(m_sequence) );
m_sequence->RemoveNode(pItemInfo->node);
RefreshNodes();
}
}
}
}
else
CTreeCtrlEx::OnKeyDown(nChar, nRepCnt, nFlags);
}