You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
834 lines
18 KiB
C++
834 lines
18 KiB
C++
2 years ago
|
// XTPFlowGraphPage.cpp : implementation of the CXTPFlowGraphPage class.
|
||
|
//
|
||
|
// This file is a part of the XTREME TOOLKIT PRO MFC class library.
|
||
|
// (c)1998-2012 Codejock Software, All Rights Reserved.
|
||
|
//
|
||
|
// THIS SOURCE FILE IS THE PROPERTY OF CODEJOCK SOFTWARE AND IS NOT TO BE
|
||
|
// RE-DISTRIBUTED BY ANY MEANS WHATSOEVER WITHOUT THE EXPRESSED WRITTEN
|
||
|
// CONSENT OF CODEJOCK SOFTWARE.
|
||
|
//
|
||
|
// THIS SOURCE CODE CAN ONLY BE USED UNDER THE TERMS AND CONDITIONS OUTLINED
|
||
|
// IN THE XTREME TOOLKIT PRO LICENSE AGREEMENT. CODEJOCK SOFTWARE GRANTS TO
|
||
|
// YOU (ONE SOFTWARE DEVELOPER) THE LIMITED RIGHT TO USE THIS SOFTWARE ON A
|
||
|
// SINGLE COMPUTER.
|
||
|
//
|
||
|
// CONTACT INFORMATION:
|
||
|
// support@codejock.com
|
||
|
// http://www.codejock.com
|
||
|
//
|
||
|
/////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
#include "stdafx.h"
|
||
|
#include <math.h>
|
||
|
|
||
|
#include "Common/XTPPropExchange.h"
|
||
|
|
||
|
#include "XTPFlowGraphElement.h"
|
||
|
#include "XTPFlowGraphPage.h"
|
||
|
#include "XTPFlowGraphPages.h"
|
||
|
#include "XTPFlowGraphNode.h"
|
||
|
#include "XTPFlowGraphNodes.h"
|
||
|
#include "XTPFlowGraphNodeGroup.h"
|
||
|
#include "XTPFlowGraphNodeGroups.h"
|
||
|
#include "XTPFlowGraphNodeGroups.h"
|
||
|
#include "XTPFlowGraphPaintManager.h"
|
||
|
#include "XTPFlowGraphConnection.h"
|
||
|
#include "XTPFlowGraphConnectionPoints.h"
|
||
|
#include "XTPFlowGraphConnectionPoint.h"
|
||
|
#include "XTPFlowGraphConnections.h"
|
||
|
#include "XTPFlowGraphControl.h"
|
||
|
#include "XTPFlowGraphSelectedElements.h"
|
||
|
#include "XTPFlowGraphUndoManager.h"
|
||
|
#include "XTPFlowGraphMessages.h"
|
||
|
|
||
|
CLIPFORMAT CXTPFlowGraphPage::m_cfNode = (CLIPFORMAT)::RegisterClipboardFormat(_T("FlowGraphNode"));
|
||
|
|
||
|
|
||
|
IMPLEMENT_SERIAL(CXTPFlowGraphPage, CCmdTarget, VERSIONABLE_SCHEMA | _XTP_SCHEMA_CURRENT)
|
||
|
|
||
|
|
||
|
CXTPFlowGraphPage::CXTPFlowGraphPage()
|
||
|
{
|
||
|
m_pControl = NULL;
|
||
|
m_rcPage.SetRectEmpty();
|
||
|
|
||
|
m_ptScrollOffset = CPoint(0, 0);
|
||
|
m_nId = 0;
|
||
|
|
||
|
m_pNodes = new CXTPFlowGraphNodes(this);
|
||
|
|
||
|
m_pGroups = new CXTPFlowGraphNodeGroups(this);
|
||
|
|
||
|
m_pConnections = new CXTPFlowGraphConnections(this);
|
||
|
|
||
|
m_dZoomLevel = 1.0;
|
||
|
|
||
|
m_pSelectedElements = new CXTPFlowGraphSelectedElements(this);
|
||
|
|
||
|
m_pFirstVisibleNode = NULL;
|
||
|
m_pFirstVisibleConnection = NULL;
|
||
|
|
||
|
}
|
||
|
|
||
|
CXTPFlowGraphPage::~CXTPFlowGraphPage()
|
||
|
{
|
||
|
|
||
|
if (m_pSelectedElements)
|
||
|
{
|
||
|
m_pSelectedElements->Clear();
|
||
|
m_pSelectedElements->InternalRelease();
|
||
|
m_pSelectedElements = NULL;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (m_pGroups)
|
||
|
{
|
||
|
m_pGroups->RemoveAll();
|
||
|
m_pGroups->InternalRelease();
|
||
|
m_pGroups = NULL;
|
||
|
}
|
||
|
|
||
|
if (m_pConnections)
|
||
|
{
|
||
|
m_pConnections->RemoveAll();
|
||
|
m_pConnections->InternalRelease();
|
||
|
m_pConnections = NULL;
|
||
|
}
|
||
|
|
||
|
if (m_pNodes)
|
||
|
{
|
||
|
m_pNodes->RemoveAll();
|
||
|
m_pNodes->InternalRelease();
|
||
|
m_pNodes = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CXTPFlowGraphPage::OnRemoved()
|
||
|
{
|
||
|
if (m_pGroups)
|
||
|
{
|
||
|
m_pGroups->RemoveAll();
|
||
|
}
|
||
|
|
||
|
if (m_pConnections)
|
||
|
{
|
||
|
m_pConnections->RemoveAll();
|
||
|
}
|
||
|
|
||
|
if (m_pNodes)
|
||
|
{
|
||
|
m_pNodes->RemoveAll();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CXTPFlowGraphPage::OnGraphChanged()
|
||
|
{
|
||
|
for (int i = 0; i < m_pNodes->GetCount(); i++)
|
||
|
m_pNodes->GetAt(i)->m_bDirty = TRUE;
|
||
|
|
||
|
m_pFirstVisibleNode = NULL;
|
||
|
m_pFirstVisibleConnection = NULL;
|
||
|
|
||
|
if (m_pControl) m_pControl->OnGraphChanged();
|
||
|
}
|
||
|
|
||
|
void CXTPFlowGraphPage::Reposition(CXTPFlowGraphDrawContext* pDC, CRect rcPage)
|
||
|
{
|
||
|
m_rcPage = rcPage;
|
||
|
|
||
|
m_rcWorkRect.SetRect(0, 0, 0, 0);
|
||
|
CXTPFlowGraphPaintManager* pPaintManager = m_pControl->GetPaintManager();
|
||
|
|
||
|
int i;
|
||
|
int nNodesCount = m_pNodes->GetCount();
|
||
|
|
||
|
for (i = 0; i < nNodesCount; i++)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pNode = m_pNodes->GetAt(i);
|
||
|
|
||
|
|
||
|
if (pNode->m_bDirty)
|
||
|
{
|
||
|
pNode->RecalLayout(pDC);
|
||
|
}
|
||
|
|
||
|
CRect rc = pPaintManager->GetNodeBoundingRectangle(pNode);
|
||
|
|
||
|
if (i == 0)
|
||
|
{
|
||
|
m_rcWorkRect = rc;
|
||
|
}
|
||
|
|
||
|
m_rcWorkRect.right = max(m_rcWorkRect.right, rc.right);
|
||
|
m_rcWorkRect.bottom = max(m_rcWorkRect.bottom, rc.bottom);
|
||
|
|
||
|
m_rcWorkRect.left = min(m_rcWorkRect.left, rc.left);
|
||
|
m_rcWorkRect.top = min(m_rcWorkRect.top, rc.top);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < m_pGroups->GetCount(); i++)
|
||
|
{
|
||
|
CXTPFlowGraphNodeGroup* pGroup = m_pGroups->GetAt(i);
|
||
|
CRect rcWorkRect(0, 0, 0, 0);
|
||
|
|
||
|
for (int j = 0; j < pGroup->GetCount(); j++)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pNode = pGroup->GetAt(j);
|
||
|
|
||
|
CRect rc = pPaintManager->GetNodeBoundingRectangle(pNode);
|
||
|
|
||
|
if (j == 0)
|
||
|
{
|
||
|
rcWorkRect = rc;
|
||
|
}
|
||
|
|
||
|
rcWorkRect.right = max(rcWorkRect.right, rc.right);
|
||
|
rcWorkRect.bottom = max(rcWorkRect.bottom, rc.bottom);
|
||
|
|
||
|
rcWorkRect.left = min(rcWorkRect.left, rc.left);
|
||
|
rcWorkRect.top = min(rcWorkRect.top, rc.top);
|
||
|
}
|
||
|
pGroup->m_rcWorkRect = rcWorkRect;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < m_pConnections->GetCount(); i++)
|
||
|
{
|
||
|
CXTPFlowGraphConnection* pConnection = GetConnections()->GetAt(i);
|
||
|
|
||
|
if (pConnection->m_bDirty || (pConnection->GetInputPoint() && pConnection->GetInputPoint()->GetNode()->m_bDirty) ||
|
||
|
(pConnection->GetOutputPoint() && pConnection->GetOutputPoint()->GetNode()->m_bDirty))
|
||
|
{
|
||
|
pConnection->RecalcLayout(pDC);
|
||
|
pConnection->m_bDirty = FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
for (i = 0; i < nNodesCount; i++)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pNode = m_pNodes->GetAt(i);
|
||
|
pNode->m_bDirty = FALSE;
|
||
|
}
|
||
|
|
||
|
m_pFirstVisibleNode = NULL;
|
||
|
CRect rcBounds = ScreenToPage(rcPage);
|
||
|
|
||
|
for (i = 0; i < nNodesCount; i++)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pNode = m_pNodes->GetAt(i);
|
||
|
CRect rcNodeBounds = pPaintManager->GetNodeBoundingRectangle(pNode);
|
||
|
|
||
|
pNode->m_pNextVisibleNode = m_pFirstVisibleNode;
|
||
|
|
||
|
if (rcBounds.right < rcNodeBounds.left || rcBounds.left > rcNodeBounds.right || rcBounds.top > rcNodeBounds.bottom || rcBounds.bottom < rcNodeBounds.top)
|
||
|
continue;
|
||
|
|
||
|
m_pFirstVisibleNode = pNode;
|
||
|
}
|
||
|
|
||
|
m_pFirstVisibleConnection = NULL;
|
||
|
|
||
|
for (i = 0; i < m_pConnections->GetCount(); i++)
|
||
|
{
|
||
|
CXTPFlowGraphConnection* pConnection = GetConnections()->GetAt(i);
|
||
|
pConnection->m_pNextVisibleConnection = m_pFirstVisibleConnection;
|
||
|
|
||
|
CRect rcConnectionBounds = pConnection->GetBoundingRect();
|
||
|
|
||
|
pConnection->m_pNextVisibleConnection = m_pFirstVisibleConnection;
|
||
|
|
||
|
if (rcBounds.right < rcConnectionBounds.left || rcBounds.left > rcConnectionBounds.right ||
|
||
|
rcBounds.top > rcConnectionBounds.bottom || rcBounds.bottom < rcConnectionBounds.top)
|
||
|
continue;
|
||
|
|
||
|
m_pFirstVisibleConnection = pConnection;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CRect CXTPFlowGraphPage::PageToScreen(LPCRECT lpRect) const
|
||
|
{
|
||
|
CRect rc(lpRect);
|
||
|
rc.OffsetRect(GetPageRect().TopLeft());
|
||
|
rc.OffsetRect(-GetScrollOffset());
|
||
|
|
||
|
double dZoomLevel = GetZoomLevel();
|
||
|
|
||
|
return CRect(int(rc.left * dZoomLevel), int(rc.top * dZoomLevel), int(rc.right * dZoomLevel), int(rc.bottom * dZoomLevel));
|
||
|
}
|
||
|
|
||
|
void CXTPFlowGraphPage::ScreenToPage(double& x, double& y) const
|
||
|
{
|
||
|
double dZoomLevel = GetZoomLevel();
|
||
|
|
||
|
x /= dZoomLevel;
|
||
|
x += GetScrollOffset().x;
|
||
|
|
||
|
y /= dZoomLevel;
|
||
|
y += GetScrollOffset().y;
|
||
|
}
|
||
|
|
||
|
CPoint CXTPFlowGraphPage::ScreenToPage(CPoint point) const
|
||
|
{
|
||
|
double dZoomLevel = GetZoomLevel();
|
||
|
|
||
|
point.x = int(point.x / dZoomLevel);
|
||
|
point.x += GetScrollOffset().x;
|
||
|
|
||
|
point.y = int(point.y / dZoomLevel);
|
||
|
point.y += GetScrollOffset().y;
|
||
|
|
||
|
return point;
|
||
|
}
|
||
|
|
||
|
CRect CXTPFlowGraphPage::ScreenToPage(LPCRECT lpRect) const
|
||
|
{
|
||
|
double dZoomLevel = GetZoomLevel();
|
||
|
|
||
|
return CRect(int(lpRect->left / dZoomLevel + GetScrollOffset().x), int(lpRect->top / dZoomLevel + GetScrollOffset().y),
|
||
|
(int)ceil(lpRect->right / dZoomLevel + GetScrollOffset().x), (int)ceil(lpRect->bottom / dZoomLevel + GetScrollOffset().y));
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
void CXTPFlowGraphPage::DoPropExchange(CXTPPropExchange* pPX)
|
||
|
{
|
||
|
PX_Double(pPX, _T("ZoomLevel"), m_dZoomLevel, 1.0);
|
||
|
|
||
|
PX_String(pPX, _T("Caption"), m_strCaption, _T(""));
|
||
|
PX_Int(pPX, _T("Id"), m_nId, 0);
|
||
|
|
||
|
PX_Point(pPX, _T("ScrollOffset"), m_ptScrollOffset, CPoint(0, 0));
|
||
|
|
||
|
m_pNodes->DoPropExchange(pPX);
|
||
|
|
||
|
m_pConnections->DoPropExchange(pPX);
|
||
|
|
||
|
if (pPX->IsLoading())
|
||
|
{
|
||
|
m_pGroups->RemoveAll();
|
||
|
|
||
|
CMap<int, int, CXTPFlowGraphNodeGroup*, CXTPFlowGraphNodeGroup*> mapGroups;
|
||
|
|
||
|
for (int i = 0; i < m_pNodes->GetCount(); i++)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pNode = m_pNodes->GetAt(i);
|
||
|
|
||
|
if (pNode->m_nGroupId != 0)
|
||
|
{
|
||
|
CXTPFlowGraphNodeGroup* pGroup = NULL;
|
||
|
if (!mapGroups.Lookup(pNode->m_nGroupId, pGroup))
|
||
|
{
|
||
|
pGroup = m_pGroups->AddGroup();
|
||
|
mapGroups[pNode->m_nGroupId] = pGroup;
|
||
|
}
|
||
|
|
||
|
pGroup->AddNode(pNode);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void CXTPFlowGraphPage::Copy()
|
||
|
{
|
||
|
try
|
||
|
{
|
||
|
int nCount = 0, i;
|
||
|
for (i = 0; i < GetSelection()->GetCount(); i++)
|
||
|
{
|
||
|
if (DYNAMIC_DOWNCAST(CXTPFlowGraphNode, GetSelection()->GetAt(i)))
|
||
|
{
|
||
|
nCount++;
|
||
|
}
|
||
|
}
|
||
|
if (nCount == 0)
|
||
|
return;
|
||
|
|
||
|
CSharedFile sharedFile;
|
||
|
CArchive ar (&sharedFile, CArchive::store);
|
||
|
|
||
|
ar.WriteCount(nCount);
|
||
|
|
||
|
CXTPPropExchangeArchive px(ar);
|
||
|
|
||
|
for (i = 0; i < GetSelection()->GetCount(); i++)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pNode = DYNAMIC_DOWNCAST(CXTPFlowGraphNode, GetSelection()->GetAt(i));
|
||
|
if (pNode)
|
||
|
{
|
||
|
CRuntimeClass* pClass = pNode->GetRuntimeClass();
|
||
|
ASSERT (pClass != NULL);
|
||
|
|
||
|
ar.WriteClass (pClass);
|
||
|
pNode->DoPropExchange(&px);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ar.Close();
|
||
|
|
||
|
if (!m_pControl->OpenClipboard())
|
||
|
return;
|
||
|
|
||
|
if (!::EmptyClipboard())
|
||
|
{
|
||
|
::CloseClipboard();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
HGLOBAL hGlobal = sharedFile.Detach();
|
||
|
|
||
|
if (hGlobal)
|
||
|
{
|
||
|
SetClipboardData(m_cfNode, hGlobal);
|
||
|
}
|
||
|
|
||
|
::CloseClipboard();
|
||
|
}
|
||
|
catch (COleException* pEx)
|
||
|
{
|
||
|
TRACE(_T("CXTPFlowGraphPage::PrepareDrag. OLE exception: %x\r\n"),
|
||
|
pEx->m_sc);
|
||
|
pEx->Delete ();
|
||
|
}
|
||
|
catch (CArchiveException* pEx)
|
||
|
{
|
||
|
TRACE(_T("CXTPFlowGraphPage::PrepareDrag. Archive exception\r\n"));
|
||
|
pEx->Delete ();
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void CXTPFlowGraphPage::Paste()
|
||
|
{
|
||
|
COleDataObject data;
|
||
|
|
||
|
if (!data.AttachClipboard())
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!data.IsDataAvailable(m_cfNode))
|
||
|
return;
|
||
|
|
||
|
CFile* pFile = data.GetFileData(m_cfNode);
|
||
|
if (!pFile)
|
||
|
return;
|
||
|
|
||
|
GetSelection()->Clear();
|
||
|
m_pControl->GetUndoManager()->StartGroup();
|
||
|
|
||
|
try
|
||
|
{
|
||
|
CArchive ar (pFile, CArchive::load);
|
||
|
CXTPPropExchangeArchive px(ar);
|
||
|
|
||
|
int nCount = (int)ar.ReadCount();
|
||
|
for (int i = 0; i < nCount; i++)
|
||
|
{
|
||
|
CRuntimeClass* pClass = ar.ReadClass ();
|
||
|
|
||
|
if (pClass != NULL)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pNode = (CXTPFlowGraphNode*)pClass->CreateObject();
|
||
|
|
||
|
if (pNode != NULL)
|
||
|
{
|
||
|
pNode->DoPropExchange(&px);
|
||
|
}
|
||
|
|
||
|
CPoint pt = pNode->GetLocation();
|
||
|
pNode->SetLocation(pt + CPoint(10, 10));
|
||
|
|
||
|
m_pNodes->AddNode(pNode);
|
||
|
|
||
|
GetSelection()->AddSelection(pNode);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ar.Close ();
|
||
|
}
|
||
|
catch (COleException* pEx)
|
||
|
{
|
||
|
TRACE(_T("CXTPFlowGraphPage::CreateFromOleData. OLE exception: %x\r\n"),
|
||
|
pEx->m_sc);
|
||
|
pEx->Delete ();
|
||
|
}
|
||
|
catch (CArchiveException* pEx)
|
||
|
{
|
||
|
TRACE(_T("CXTPFlowGraphPage::CreateFromOleData. Archive exception\r\n"));
|
||
|
pEx->Delete ();
|
||
|
}
|
||
|
catch (CNotSupportedException *pEx)
|
||
|
{
|
||
|
TRACE(_T("CXTPFlowGraphPage::CreateFromOleData. \"Not Supported\" exception\r\n"));
|
||
|
pEx->Delete ();
|
||
|
}
|
||
|
|
||
|
m_pControl->GetUndoManager()->EndGroup();
|
||
|
|
||
|
|
||
|
delete pFile;
|
||
|
}
|
||
|
|
||
|
void CXTPFlowGraphPage::Remove()
|
||
|
{
|
||
|
if (!m_pControl)
|
||
|
return;
|
||
|
|
||
|
m_pControl->GetPages()->Remove(this);
|
||
|
|
||
|
}
|
||
|
|
||
|
BOOL CXTPFlowGraphPage::CanPaste()
|
||
|
{
|
||
|
return IsClipboardFormatAvailable(m_cfNode);
|
||
|
}
|
||
|
|
||
|
void CXTPFlowGraphPage::Cut()
|
||
|
{
|
||
|
Copy();
|
||
|
|
||
|
m_pControl->GetUndoManager()->StartGroup();
|
||
|
|
||
|
for (int i = GetSelection()->GetCount() - 1; i >= 0; i--)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pNode = DYNAMIC_DOWNCAST(CXTPFlowGraphNode, GetSelection()->GetAt(i));
|
||
|
if (pNode)
|
||
|
{
|
||
|
pNode->Remove();
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
CXTPFlowGraphConnection* pConnection = DYNAMIC_DOWNCAST(CXTPFlowGraphConnection, GetSelection()->GetAt(i));
|
||
|
|
||
|
if (pConnection)
|
||
|
{
|
||
|
pConnection->Remove();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
m_pControl->GetUndoManager()->EndGroup();
|
||
|
}
|
||
|
|
||
|
void CXTPFlowGraphPage::OnDraw(CXTPFlowGraphDrawContext* pDC)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
CXTPFlowGraphPaintManager* pPaintManager = GetControl()->GetPaintManager();
|
||
|
|
||
|
|
||
|
if (pPaintManager->m_bShowNodeGroupsAlways)
|
||
|
{
|
||
|
for (i = 0; i < GetGroups()->GetCount(); i++)
|
||
|
{
|
||
|
CXTPFlowGraphNodeGroup* pGroup = GetGroups()->GetAt(i);
|
||
|
if (pGroup->GetCount() > 1 && (!pGroup->GetAt(0)->IsSelected()))
|
||
|
{
|
||
|
pPaintManager->DrawNodeGroup(pDC, pGroup);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < GetConnections()->GetCount(); i++)
|
||
|
{
|
||
|
CXTPFlowGraphConnection* pConnection = GetConnections()->GetAt(i);
|
||
|
if (!pConnection->IsSelected())
|
||
|
pPaintManager->DrawConnection(pDC, pConnection);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < GetNodes()->GetCount(); i++)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pNode = GetNodes()->GetAt(i);
|
||
|
if (!pNode->IsSelected())
|
||
|
pNode->Draw(pDC);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < GetConnections()->GetCount(); i++)
|
||
|
{
|
||
|
CXTPFlowGraphConnection* pConnection = GetConnections()->GetAt(i);
|
||
|
if (pConnection->IsSelected())
|
||
|
pPaintManager->DrawConnection(pDC, pConnection);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < GetGroups()->GetCount(); i++)
|
||
|
{
|
||
|
CXTPFlowGraphNodeGroup* pGroup = GetGroups()->GetAt(i);
|
||
|
if (pGroup->GetCount() > 1 && pGroup->GetAt(0)->IsSelected())
|
||
|
{
|
||
|
pPaintManager->DrawNodeGroup(pDC, pGroup);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < GetNodes()->GetCount(); i++)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pNode = GetNodes()->GetAt(i);
|
||
|
if (pNode->IsSelected())
|
||
|
pNode->Draw(pDC);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
void CXTPFlowGraphPage::SetArrangeLevel(int v, CArray<CDWordArray*, CDWordArray*>& graph)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pRootNode = m_pNodes->GetAt(v);
|
||
|
ASSERT(pRootNode->m_nArrangeIndex == v);
|
||
|
pRootNode->m_nArrangeIndex = -1;
|
||
|
|
||
|
int nLevel = pRootNode->m_nArrangeLevel;
|
||
|
|
||
|
for (int i = 0; i < graph[v]->GetSize(); i++)
|
||
|
{
|
||
|
int t = graph[v]->GetAt(i);
|
||
|
CXTPFlowGraphNode* pNode = GetNodes()->GetAt(t);
|
||
|
|
||
|
if ((pNode->m_nArrangeIndex != -1) &&
|
||
|
(pNode->m_nArrangeLevel == -1 || pNode->m_nArrangeLevel < nLevel + 1))
|
||
|
{
|
||
|
pNode->m_nArrangeLevel = nLevel + 1;
|
||
|
SetArrangeLevel(t, graph);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pRootNode->m_nArrangeIndex = v;
|
||
|
}
|
||
|
|
||
|
int CXTPFlowGraphPage::SetArrangeLocation(int v, int x, int y, int nLevelWidth, CArray<CDWordArray*, CDWordArray*>& graph)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pRootNode = m_pNodes->GetAt(v);
|
||
|
pRootNode->m_nArrangeLevel = -1;
|
||
|
|
||
|
pRootNode->SetLocation(CPoint(x, y));
|
||
|
|
||
|
int nBottom = y + pRootNode->GetSize().cy + 10;
|
||
|
|
||
|
for (int i = 0; i < graph[v]->GetSize(); i++)
|
||
|
{
|
||
|
int t = graph[v]->GetAt(i);
|
||
|
CXTPFlowGraphNode* pNode = GetNodes()->GetAt(t);
|
||
|
if (pNode->m_nArrangeLevel == -1)
|
||
|
continue;
|
||
|
|
||
|
int nChildBottom = SetArrangeLocation(t, x + nLevelWidth, y, nLevelWidth, graph);
|
||
|
|
||
|
y = nChildBottom;
|
||
|
}
|
||
|
|
||
|
nBottom = max(nBottom, y);
|
||
|
|
||
|
return nBottom;
|
||
|
}
|
||
|
|
||
|
void CXTPFlowGraphPage::Arrange()
|
||
|
{
|
||
|
m_dZoomLevel = 1;
|
||
|
m_ptScrollOffset = CPoint(0, 0);
|
||
|
|
||
|
CXTPFlowGraphControl* pControl = GetControl();
|
||
|
pControl->GetUndoManager()->StartGroup();
|
||
|
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < GetConnections()->GetCount(); i++)
|
||
|
{
|
||
|
CXTPFlowGraphConnection* pConnection = GetConnections()->GetAt(i);
|
||
|
|
||
|
pConnection->SetControlPoint(CPoint(-1, -1));
|
||
|
}
|
||
|
|
||
|
int nMaxWidth = 0;
|
||
|
int nNodesCount = GetNodes()->GetCount();
|
||
|
|
||
|
for (i = 0; i < nNodesCount; i++)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pNode = GetNodes()->GetAt(i);
|
||
|
|
||
|
nMaxWidth = max(nMaxWidth, pNode->GetSize().cx);
|
||
|
|
||
|
pNode->m_nArrangeIndex = i;
|
||
|
pNode->m_nArrangeLevel = -1;
|
||
|
pNode->m_nArrangeComponent = -1;
|
||
|
}
|
||
|
|
||
|
CArray<CDWordArray*, CDWordArray*> graph;
|
||
|
graph.SetSize(nNodesCount);
|
||
|
|
||
|
CArray<CDWordArray*, CDWordArray*> tgraph;
|
||
|
tgraph.SetSize(nNodesCount);
|
||
|
|
||
|
|
||
|
for (i = 0; i < nNodesCount; i++)
|
||
|
{
|
||
|
graph[i] = new CDWordArray();
|
||
|
tgraph[i] = new CDWordArray();
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < GetConnections()->GetCount(); i++)
|
||
|
{
|
||
|
CXTPFlowGraphConnection* pConnection = GetConnections()->GetAt(i);
|
||
|
|
||
|
if (!pConnection->GetInputNode() || !pConnection->GetOutputNode())
|
||
|
continue;
|
||
|
|
||
|
int nFrom = pConnection->GetOutputNode()->m_nArrangeIndex;
|
||
|
int nTo = pConnection->GetInputNode()->m_nArrangeIndex;
|
||
|
|
||
|
graph[nFrom]->Add(nTo);
|
||
|
tgraph[nTo]->Add(nFrom);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < nNodesCount; i++)
|
||
|
{
|
||
|
if (tgraph[i]->GetSize() == 0)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pNode = GetNodes()->GetAt(i);
|
||
|
|
||
|
pNode->m_nArrangeLevel = 0;
|
||
|
SetArrangeLevel(i, graph);
|
||
|
}
|
||
|
}
|
||
|
for (i = 0; i < nNodesCount; i++)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pNode = GetNodes()->GetAt(i);
|
||
|
if (pNode->m_nArrangeLevel == -1)
|
||
|
{
|
||
|
pNode->m_nArrangeLevel = 0;
|
||
|
SetArrangeLevel(i, graph);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int nCompCount = 0;
|
||
|
|
||
|
for (i = 0; i < nNodesCount; i++)
|
||
|
{
|
||
|
if (m_pNodes->GetAt(i)->m_nArrangeComponent == -1)
|
||
|
{
|
||
|
m_pNodes->GetAt(i)->m_nArrangeComponent = nCompCount;
|
||
|
|
||
|
CDWordArray stack;
|
||
|
stack.Add(i);
|
||
|
|
||
|
while (stack.GetSize())
|
||
|
{
|
||
|
int v = stack[stack.GetSize() - 1], j;
|
||
|
stack.RemoveAt(stack.GetSize() - 1);
|
||
|
|
||
|
for (j = 0; j < graph[v]->GetSize(); j++)
|
||
|
{
|
||
|
int t = graph[v]->GetAt(j);
|
||
|
if (m_pNodes->GetAt(t)->m_nArrangeComponent == -1)
|
||
|
{
|
||
|
m_pNodes->GetAt(t)->m_nArrangeComponent = nCompCount;
|
||
|
stack.Add(t);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (j = 0; j < tgraph[v]->GetSize(); j++)
|
||
|
{
|
||
|
int t = tgraph[v]->GetAt(j);
|
||
|
if (m_pNodes->GetAt(t)->m_nArrangeComponent == -1)
|
||
|
{
|
||
|
m_pNodes->GetAt(t)->m_nArrangeComponent = nCompCount;
|
||
|
stack.Add(t);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
nCompCount++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < nNodesCount; i++)
|
||
|
{
|
||
|
CDWordArray* pConnections = graph[i];
|
||
|
int nSize = (int)pConnections->GetSize();
|
||
|
|
||
|
for (int j = 0; j < nSize; j++)
|
||
|
{
|
||
|
for (int k = j + 1; k < nSize; k++)
|
||
|
{
|
||
|
CXTPFlowGraphNode* pj = m_pNodes->GetAt(pConnections->GetAt(j));
|
||
|
CXTPFlowGraphNode* pk = m_pNodes->GetAt(pConnections->GetAt(k));
|
||
|
|
||
|
if ((pj->m_nArrangeLevel > pk->m_nArrangeLevel) ||
|
||
|
(pj->m_nArrangeLevel == pk->m_nArrangeLevel && pj->m_nArrangeIndex > pk->m_nArrangeIndex))
|
||
|
{
|
||
|
int t = (*pConnections)[j];
|
||
|
(*pConnections)[j] = (*pConnections)[k];
|
||
|
(*pConnections)[k] = t;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
CDWordArray order;
|
||
|
|
||
|
for (i = 0; i < nNodesCount; i++)
|
||
|
{
|
||
|
if (m_pNodes->GetAt(i)->m_nArrangeLevel == 0)
|
||
|
order.Add(i);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < order.GetSize(); i++)
|
||
|
{
|
||
|
for (int j = i + 1; j < order.GetSize(); j++)
|
||
|
{
|
||
|
CDWordArray& pi = *graph[order[i]];
|
||
|
CDWordArray& pj = *graph[order[j]];
|
||
|
|
||
|
BOOL bOrder = TRUE;
|
||
|
|
||
|
if (m_pNodes->GetAt(order[i])->m_nArrangeComponent != m_pNodes->GetAt(order[j])->m_nArrangeComponent)
|
||
|
{
|
||
|
if (m_pNodes->GetAt(order[i])->m_nArrangeComponent > m_pNodes->GetAt(order[j])->m_nArrangeComponent)
|
||
|
{
|
||
|
bOrder = FALSE;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (int k = 0; ; k++)
|
||
|
{
|
||
|
if (pi.GetSize() <= k)
|
||
|
break;
|
||
|
if (pj.GetSize() <= k)
|
||
|
{
|
||
|
bOrder = FALSE;
|
||
|
break;
|
||
|
}
|
||
|
if (pi[k] != pj[k])
|
||
|
{
|
||
|
bOrder = pi[k] < pj[k];
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (!bOrder)
|
||
|
{
|
||
|
int t = order[i];
|
||
|
order[i] = order[j];
|
||
|
order[j] = t;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int x = 10, y = 10;
|
||
|
|
||
|
for (i = 0; i < order.GetSize(); i++)
|
||
|
{
|
||
|
y = SetArrangeLocation(order[i], x, y, 50 + nMaxWidth, graph);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < nNodesCount; i++)
|
||
|
{
|
||
|
delete graph[i];
|
||
|
delete tgraph[i];
|
||
|
}
|
||
|
|
||
|
|
||
|
pControl->GetUndoManager()->EndGroup();
|
||
|
|
||
|
pControl->SendNotifyMessage(XTP_FGN_PAGESCROLLOFFSETCHANGED);
|
||
|
pControl->SendNotifyMessage(XTP_FGN_PAGEZOOMLEVELCHANGED);
|
||
|
|
||
|
}
|
||
|
|