Serious-Engine/Sources/WorldEditor/DlgLinkTree.cpp
2016-03-11 18:20:51 -06:00

591 lines
15 KiB
C++

/* Copyright (c) 2002-2012 Croteam Ltd.
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as published by
the Free Software Foundation
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, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
// DlgLinkTree.cpp : implementation file
//
#include "stdafx.h"
#include "WorldEditor.h"
#include "DlgLinkTree.h"
#ifdef _DEBUG
#undef new
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CDlgLinkTree dialog
CDlgLinkTree::CDlgLinkTree(CEntity *pen, CPoint pt, BOOL bWhoTargets, BOOL bPropertyNames,
CWnd* pParent /*=NULL*/)
: CDialog(CDlgLinkTree::IDD, pParent)
{
//{{AFX_DATA_INIT(CDlgLinkTree)
m_bClass = FALSE;
m_bName = FALSE;
m_bProperty = FALSE;
m_bWho = FALSE;
//}}AFX_DATA_INIT
m_pt=pt;
m_pen=pen;
m_bWho=bWhoTargets;
m_bName=TRUE;
m_bProperty=bPropertyNames;
m_bClass=bPropertyNames;
m_HitItem=NULL;
}
void CDlgLinkTree::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CDlgLinkTree)
DDX_Control(pDX, IDC_LINK_TREE, m_ctrTree);
DDX_Check(pDX, IDC_LT_CLASS, m_bClass);
DDX_Check(pDX, IDC_LT_NAME, m_bName);
DDX_Check(pDX, IDC_LT_PROPERTY, m_bProperty);
DDX_Check(pDX, IDC_LT_WHO, m_bWho);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CDlgLinkTree, CDialog)
//{{AFX_MSG_MAP(CDlgLinkTree)
ON_NOTIFY(NM_DBLCLK, IDC_LINK_TREE, OnDblclkLinkTree)
ON_WM_RBUTTONDOWN()
ON_COMMAND(ID_LT_CONTRACT_ALL, OnLtContractAll)
ON_COMMAND(ID_LT_CONTRACT_BRANCH, OnLtContractBranch)
ON_COMMAND(ID_LT_EXPAND_ALL, OnLtExpandAll)
ON_COMMAND(ID_LT_EXPAND_BRANCH, OnLtExpandBranch)
ON_COMMAND(ID_LT_LEAVE_BRANCH, OnLtLeaveBranch)
ON_COMMAND(ID_LT_LAST_LEVEL, OnLtLastLevel)
ON_BN_CLICKED(IDC_LT_CLASS, OnLtClass)
ON_BN_CLICKED(IDC_LT_NAME, OnLtName)
ON_BN_CLICKED(IDC_LT_PROPERTY, OnLtProperty)
ON_BN_CLICKED(IDC_LT_WHO, OnLtWho)
ON_WM_LBUTTONDOWN()
ON_WM_MOUSEMOVE()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDlgLinkTree message handlers
CDynamicContainer<CEntity> _penAdded;
BOOL CDlgLinkTree::OnInitDialog()
{
InitializeTree();
return TRUE;
}
void CDlgLinkTree::InitializeTree(void)
{
CWorldEditorDoc *pDoc = theApp.GetDocument();
CDialog::OnInitDialog();
_penAdded.Clear();
m_ctrTree.DeleteAllItems();
if( m_pen==NULL || m_pen->IsSelected( ENF_SELECTED))
{
FOREACHINDYNAMICCONTAINER(pDoc->m_selEntitySelection, CEntity, iten)
{
CEntity &en=*iten;
AddEntityPtrsRecursiv( &en, 0, "");
}
}
else
{
AddEntityPtrsRecursiv( m_pen, 0, "");
}
// get dlg wnd - tree ctrl wnd before resizing
CRect rectdlg, recttree;
GetClientRect(recttree);
GetWindowRect(rectdlg);
PIX dW=rectdlg.Width()-recttree.Width();
PIX dH=rectdlg.Height()-recttree.Height();
#define PIX_FLAG_LINE PIX(18)
// get screen size
int iScrW = ::GetSystemMetrics(SM_CXSCREEN); // screen size
int iScrH = ::GetSystemMetrics(SM_CYSCREEN) - 32;
// expand all nodes
HTREEITEM pRootItem = m_ctrTree.GetRootItem();
ExpandTree(pRootItem, TRUE);
CRect result=CRect(0,0,0,0);
CalculateOccupiedSpace(pRootItem, result);
PIX pixIndent=m_ctrTree.GetIndent();
PIX pixOffset=pixIndent+1;
// calculate tree wnd size
result.left-=pixOffset;
result.bottom+=pixOffset;
result.right+=pixOffset;
PIX pixTreeW=Clamp(PIX(result.Width()), PIX(4*32), iScrW-dW);
PIX pixTreeH=ClampUp(PIX(result.Height()), iScrH-dH-PIX_FLAG_LINE);
// now move resulting window so LU-corner would be where mouse was clicked
CRect rectPopup=CRect(m_pt.x, m_pt.y, m_pt.x+pixTreeW+dW, m_pt.y+pixTreeH+dH+PIX_FLAG_LINE);
if( rectPopup.right>iScrW)
{
rectPopup.left=ClampDn(iScrW-rectPopup.Width(), 0);
rectPopup.right=iScrW;
}
if( rectPopup.bottom>iScrH)
{
rectPopup.top=ClampDn( iScrH-rectPopup.Height(), 0);
rectPopup.bottom=iScrH;
}
MoveWindow(rectPopup);
CRect newTreePos;
newTreePos.left=0;
newTreePos.top=0;
newTreePos.right=rectPopup.Width();
newTreePos.bottom=rectPopup.Height()-dH-PIX_FLAG_LINE;
m_ctrTree.MoveWindow(newTreePos);
#define MOVE_FLAG(id, no)\
rectFlag.top=newTreePos.bottom;\
rectFlag.bottom=newTreePos.bottom+PIX_FLAG_LINE;\
rectFlag.left=no*32;\
rectFlag.right=(no+1)*32;\
GetDlgItem(id)->MoveWindow(rectFlag);
CRect rectFlag;
MOVE_FLAG(IDC_LT_CLASS, 0);
MOVE_FLAG(IDC_LT_PROPERTY, 1);
MOVE_FLAG(IDC_LT_NAME, 2);
MOVE_FLAG(IDC_LT_WHO, 3);
}
void CDlgLinkTree::AddEntityPtrsRecursiv(CEntity *pen, HTREEITEM hParent, CTString strPropertyName)
{
CWorldEditorDoc *pDoc = theApp.GetDocument();
if( _penAdded.IsMember( pen)) return;
// Insert entity's ptrs into directory tree
HTREEITEM InsertedEntity;
InsertedEntity = m_ctrTree.InsertItem( 0, L"", 0, 0,
TVIS_SELECTED, TVIF_STATE, 0, hParent, 0);
m_ctrTree.SetItemData( InsertedEntity, (ULONG)(pen));
CTString strText="";
if( m_bClass)
{
CTString strPrev="{";
CTString strPost="}";
if( !m_bName && !m_bProperty)
{
strPrev="";
strPost="";
}
strText=strPrev+pen->GetClass()->GetName().FileName()+strPost+" ";
}
if( m_bProperty && strPropertyName!="")
{
CTString strPrev="<";
CTString strPost=">";
if( !m_bName && !m_bClass)
{
strPrev="";
strPost="";
}
strText=strText+strPrev+strPropertyName+strPost+" ";
}
if( m_bName)
{
strText=strText+pen->GetName();
}
m_ctrTree.SetItemText( InsertedEntity, CString(strText));
_penAdded.Add(pen);
if(_penAdded.Count()>16) return;
if( m_bWho)
{
FOREACHINDYNAMICCONTAINER(pDoc->m_woWorld.wo_cenEntities, CEntity, iten)
{
// ---- Add entities that target
// obtain entity class ptr
CDLLEntityClass *pdecDLLClass = iten->GetClass()->ec_pdecDLLClass;
// for all classes in hierarchy of this entity
for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
{
// for all properties
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
{
CEntityProperty *pepProperty = &pdecDLLClass->dec_aepProperties[iProperty];
if( pepProperty->ep_eptType == CEntityProperty::EPT_ENTITYPTR)
{
// obtain property ptr
CEntity *penPtr = ENTITYPROPERTY( &*iten, pepProperty->ep_slOffset, CEntityPointer);
if( penPtr == pen)
{
AddEntityPtrsRecursiv( &*iten, InsertedEntity, pepProperty->ep_strName);
}
}
}
}
}
}
else
{
// ---- Add this entity's non-NULL ptrs recurively
// obtain entity class ptr
CDLLEntityClass *pdecDLLClass = pen->GetClass()->ec_pdecDLLClass;
// for all classes in hierarchy of this entity
for(;pdecDLLClass!=NULL; pdecDLLClass = pdecDLLClass->dec_pdecBase)
{
// for all properties
for(INDEX iProperty=0; iProperty<pdecDLLClass->dec_ctProperties; iProperty++)
{
CEntityProperty *pepProperty = &pdecDLLClass->dec_aepProperties[iProperty];
if( pepProperty->ep_eptType == CEntityProperty::EPT_ENTITYPTR)
{
// obtain property ptr
CEntity *penPtr = ENTITYPROPERTY( pen, pepProperty->ep_slOffset, CEntityPointer);
if( penPtr != NULL)
{
AddEntityPtrsRecursiv( penPtr, InsertedEntity, pepProperty->ep_strName);
}
}
}
}
}
}
void CDlgLinkTree::CalculateOccupiedSpace(HTREEITEM hItem, CRect &rect)
{
CRect rectThis;
m_ctrTree.GetItemRect( hItem, &rectThis, TRUE);
rect|=rectThis;
HTREEITEM pNext=m_ctrTree.GetNextItem( hItem, TVGN_NEXTVISIBLE);
if( pNext!=NULL)
{
CalculateOccupiedSpace(pNext, rect);
}
}
INDEX _iMaxLevel=-1;
void CDlgLinkTree::ExpandTree(HTREEITEM pItem, BOOL bExpand, INDEX iMaxLevel/*=-1*/, BOOL bNoNextSibling/*=FALSE*/)
{
_iMaxLevel=iMaxLevel;
ExpandRecursivly(pItem, bExpand, bNoNextSibling);
}
void CDlgLinkTree::ExpandRecursivly(HTREEITEM pItem, BOOL bExpand, BOOL bNoNextSibling)
{
BOOL bForceContract=FALSE;
if(_iMaxLevel!=-1 && GetItemLevel(pItem)>=_iMaxLevel) bForceContract=TRUE;
// obtain next child item in branch
HTREEITEM pCurrent=pItem;
do
{
if( m_ctrTree.ItemHasChildren( pCurrent))
{
if( bExpand&&!bForceContract)
{
m_ctrTree.Expand( pCurrent, TVE_EXPAND);
}
else
{
m_ctrTree.Expand( pCurrent, TVE_COLLAPSE);
}
// get its child
HTREEITEM pChild=m_ctrTree.GetNextItem( pCurrent, TVGN_CHILD);
ExpandRecursivly(pChild, bExpand, FALSE);
}
// get next in dir
if( bNoNextSibling) break;
pCurrent=m_ctrTree.GetNextItem( pCurrent, TVGN_NEXT);
}
while( pCurrent!=NULL);
}
void CDlgLinkTree::OnDblclkLinkTree(NMHDR* pNMHDR, LRESULT* pResult)
{
HTREEITEM item = m_ctrTree.GetSelectedItem();
if( item!=NULL)
{
CWorldEditorDoc *pDoc = theApp.GetDocument();
pDoc->m_selEntitySelection.Clear();
CEntity *pen=(CEntity *) m_ctrTree.GetItemData(item);
pDoc->m_selEntitySelection.Select( *pen);
pDoc->m_chSelections.MarkChanged();
EndDialog( IDOK);
}
*pResult = 0;
}
BOOL CDlgLinkTree::PreTranslateMessage(MSG* pMsg)
{
if( (pMsg->message==WM_KEYDOWN) && ((int)pMsg->wParam==192))
{
EndDialog( IDOK);
}
/*
if( pMsg->message==WM_MOUSEMOVE)
{
UINT nKeys = pMsg->wParam;
PIX xPos = LOWORD(pMsg->lParam); // horizontal position of cursor
PIX yPos = HIWORD(pMsg->lParam); // vertical position of cursor
CPoint point=CPoint(xPos, yPos);
OnMouseMove(nKeys, point);
return TRUE;
}
*/
if( pMsg->message==WM_LBUTTONDOWN)
{
PIX xPos = LOWORD(pMsg->lParam); // horizontal position of cursor
PIX yPos = HIWORD(pMsg->lParam); // vertical position of cursor
CPoint pt=CPoint(xPos, yPos);
GetWindowRect(m_rectWndOnMouseDown);
m_ptMouseDown=pt;
UINT nFlags=(int)pMsg->wParam;
BOOL bShift = nFlags & MK_SHIFT;
BOOL bCtrl = nFlags & MK_CONTROL;
if( bShift||bCtrl)
{
OnLButtonDown((int)pMsg->wParam, pt);
return TRUE;
}
}
if( pMsg->message==WM_RBUTTONDOWN)
{
PIX xPos = LOWORD(pMsg->lParam); // horizontal position of cursor
PIX yPos = HIWORD(pMsg->lParam); // vertical position of cursor
CPoint pt=CPoint(xPos, yPos);
OnRButtonDown((int)pMsg->wParam, pt);
return TRUE;
}
return CDialog::PreTranslateMessage(pMsg);
}
void CDlgLinkTree::OnLButtonDown(UINT nFlags, CPoint point)
{
BOOL bShift = nFlags & MK_SHIFT;
BOOL bCtrl = nFlags & MK_CONTROL;
TVHITTESTINFO testinfo;
testinfo.pt=point;
HTREEITEM item=m_ctrTree.HitTest( &testinfo);
// allow only string clicks
if( !(testinfo.flags&TVHT_ONITEMLABEL))
{
item=NULL;
}
m_HitItem=item;
if(bCtrl&&bShift)
{
OnLtContractAll();
}
if( m_HitItem!=NULL)
{
if(bCtrl)
{
OnLtContractBranch();
}
else if(bShift)
{
OnLtLeaveBranch();
}
}
CDialog::OnLButtonDown(nFlags, point);
}
void CDlgLinkTree::OnRButtonDown(UINT nFlags, CPoint point)
{
BOOL bShift = nFlags & MK_SHIFT;
BOOL bCtrl = nFlags & MK_CONTROL;
TVHITTESTINFO testinfo;
testinfo.pt=point;
HTREEITEM item=m_ctrTree.HitTest( &testinfo);
// allow only string clicks
if( !(testinfo.flags&TVHT_ONITEMLABEL))
{
item=NULL;
}
m_HitItem=item;
if(bCtrl&&bShift)
{
OnLtExpandAll();
}
if( m_HitItem!=NULL)
{
if(bCtrl&&!bShift)
{
OnLtExpandBranch();
}
else if(bShift&&!bCtrl)
{
OnLtLastLevel();
}
}
if(!bShift&&!bCtrl)
{
CMenu menu;
if( menu.LoadMenu(IDR_LINK_TREE_POPUP))
{
CMenu* pPopup = menu.GetSubMenu(0);
if( item==NULL)
{
pPopup->EnableMenuItem(ID_LT_CONTRACT_BRANCH, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_LT_EXPAND_BRANCH, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_LT_LAST_LEVEL, MF_DISABLED|MF_GRAYED);
pPopup->EnableMenuItem(ID_LT_LEAVE_BRANCH, MF_DISABLED|MF_GRAYED);
}
ClientToScreen(&point);
pPopup->TrackPopupMenu(TPM_LEFTBUTTON | TPM_RIGHTBUTTON | TPM_LEFTALIGN,
point.x, point.y, this);
}
}
CDialog::OnRButtonDown(nFlags, point);
}
void CDlgLinkTree::OnLtExpandAll()
{
// expand all nodes
HTREEITEM pRootItem = m_ctrTree.GetRootItem();
ExpandTree(pRootItem, TRUE);
}
void CDlgLinkTree::OnLtContractAll()
{
// contract all nodes
HTREEITEM pRootItem = m_ctrTree.GetRootItem();
ExpandTree(pRootItem, FALSE);
}
void CDlgLinkTree::OnLtExpandBranch()
{
ExpandTree(m_HitItem, TRUE, 10000, TRUE);
}
void CDlgLinkTree::OnLtContractBranch()
{
ExpandTree(m_HitItem, FALSE, 10000, TRUE);
}
void CDlgLinkTree::OnLtLastLevel()
{
OnLtContractAll();
INDEX iLevel=GetItemLevel(m_HitItem);
HTREEITEM pRootItem = m_ctrTree.GetRootItem();
ExpandTree(pRootItem, TRUE, iLevel);
}
void CDlgLinkTree::OnLtLeaveBranch()
{
OnLtContractAll();
OnLtExpandBranch();
INDEX iLevel=-1;
HTREEITEM item = m_HitItem;
while( item!=NULL)
{
item=m_ctrTree.GetParentItem( item);
if( item!=NULL)
{
m_ctrTree.Expand( item, TVE_EXPAND);
}
}
}
INDEX CDlgLinkTree::GetItemLevel(HTREEITEM item)
{
INDEX iLevel=-1;
while( item!=NULL)
{
item=m_ctrTree.GetParentItem( item);
iLevel++;
}
return iLevel;
}
void CDlgLinkTree::SetNewWindowOrigin(void)
{
CRect rectWnd;
GetWindowRect(rectWnd);
m_pt.x=rectWnd.left;
m_pt.y=rectWnd.top;
}
void CDlgLinkTree::OnLtClass()
{
m_bClass=!m_bClass;
UpdateData(FALSE);
SetNewWindowOrigin();
InitializeTree();
}
void CDlgLinkTree::OnLtName()
{
m_bName=!m_bName;
UpdateData(FALSE);
SetNewWindowOrigin();
InitializeTree();
}
void CDlgLinkTree::OnLtProperty()
{
m_bProperty=!m_bProperty;
UpdateData(FALSE);
SetNewWindowOrigin();
InitializeTree();
}
void CDlgLinkTree::OnLtWho()
{
m_bWho=!m_bWho;
UpdateData(FALSE);
SetNewWindowOrigin();
InitializeTree();
}
void CDlgLinkTree::OnMouseMove(UINT nFlags, CPoint point)
{
/*
BOOL bSpace = (GetKeyState( VK_SPACE)&0x8000) != 0;
BOOL bLMB = nFlags & MK_LBUTTON;
PIX dx=point.x-m_ptMouseDown.x;
PIX dy=point.y-m_ptMouseDown.y;
if( bSpace && bLMB)
{
CRect rectWnd=m_rectWndOnMouseDown;
rectWnd.left+=dx;
rectWnd.right+=dx;
rectWnd.top+=dy;
rectWnd.bottom+=dy;
MoveWindow( rectWnd);
}
m_ptLastMouse = point;
*/
CDialog::OnMouseMove(nFlags, point);
}