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.
2110 lines
45 KiB
C++
2110 lines
45 KiB
C++
// XTPFlowGraphControl.cpp : implementation of the CXTPFlowGraphControl 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/XTPDrawHelpers.h"
|
|
#include "Common/XTPPropExchange.h"
|
|
#include "Common/XTPTooltipContext.h"
|
|
#include "Common/XTPMarkupRender.h"
|
|
|
|
#include "XTPFlowGraphElement.h"
|
|
#include "XTPFlowGraphTools.h"
|
|
#include "XTPFlowGraphControl.h"
|
|
#include "XTPFlowGraphMessages.h"
|
|
#include "XTPFlowGraphPage.h"
|
|
#include "XTPFlowGraphPages.h"
|
|
#include "XTPFlowGraphNode.h"
|
|
#include "XTPFlowGraphNodeGroup.h"
|
|
#include "XTPFlowGraphNodes.h"
|
|
#include "XTPFlowGraphPaintManager.h"
|
|
#include "XTPFlowGraphDrawContext.h"
|
|
#include "XTPFlowGraphDrawContextGdiPlus.h"
|
|
#include "XTPFlowGraphConnection.h"
|
|
#include "XTPFlowGraphConnections.h"
|
|
#include "XTPFlowGraphConnectionPoint.h"
|
|
#include "XTPFlowGraphConnectionPoints.h"
|
|
#include "XTPFlowGraphSelectedElements.h"
|
|
#include "XTPFlowGraphUndoManager.h"
|
|
#include "XTPFlowGraphEditItem.h"
|
|
#include "XTPFlowGraphImage.h"
|
|
#include "XTPFlowGraphPageHistory.h"
|
|
|
|
const TCHAR XTPFLOWGRAPH_CLASSNAME[] = _T("XTPFlowGraph");
|
|
|
|
CXTPFlowGraphControl::CXTPFlowGraphControl()
|
|
{
|
|
CXTPFlowGraphDrawContextGdiPlus::Register(TRUE);
|
|
|
|
m_pPaintManager = new CXTPFlowGraphPaintManager();
|
|
m_pPaintManager->RefreshMetrics();
|
|
|
|
m_pActivePage = NULL;
|
|
m_pPages = new CXTPFlowGraphPages(this);
|
|
|
|
m_dMinZoom = 0.1;
|
|
m_dMaxZoom = 5.0;
|
|
|
|
m_bAdjustScrollBars = FALSE;
|
|
|
|
m_pUndoManager = new CXTPFlowGraphUndoManager();
|
|
|
|
m_rcSelectedArea.SetRectEmpty();
|
|
|
|
m_pToolTipContext = new CXTPToolTipContext;
|
|
|
|
m_nAnimationDelay = 20;
|
|
|
|
m_pImages = new CXTPFlowGraphImages();
|
|
|
|
m_pHistory = new CXTPFlowGraphPageHistory(this);
|
|
|
|
m_bAllowMoveNodes = TRUE;
|
|
m_nAllowResizeNodes = xtpFlowGraphResizeHorizontal;
|
|
m_bAllowModifyConnections = TRUE;
|
|
|
|
m_bInAction = FALSE;
|
|
|
|
m_nSmoothingMode = xtpFlowGraphSmoothingModeHighQuality;
|
|
|
|
m_pMarkupContext = NULL;
|
|
|
|
RegisterWindowClass();
|
|
}
|
|
|
|
CXTPFlowGraphControl::~CXTPFlowGraphControl()
|
|
{
|
|
m_pUndoManager->EnableUndoManager(FALSE);
|
|
|
|
if (m_pPaintManager)
|
|
{
|
|
m_pPaintManager->Cleanup();
|
|
m_pPaintManager->InternalRelease();
|
|
m_pPaintManager = NULL;
|
|
}
|
|
|
|
if (m_pImages)
|
|
{
|
|
m_pImages->RemoveAll();
|
|
m_pImages->InternalRelease();
|
|
m_pImages = NULL;
|
|
}
|
|
|
|
if (m_pActivePage)
|
|
{
|
|
m_pActivePage->InternalRelease();
|
|
m_pActivePage = NULL;
|
|
}
|
|
|
|
if (m_pPages)
|
|
{
|
|
m_pPages->RemoveAll();
|
|
m_pPages->InternalRelease();
|
|
m_pPages = NULL;
|
|
}
|
|
|
|
if (m_pHistory)
|
|
{
|
|
m_pHistory->InternalRelease();
|
|
m_pHistory = NULL;
|
|
}
|
|
|
|
if (m_pUndoManager)
|
|
{
|
|
m_pUndoManager->Clear();
|
|
m_pUndoManager->InternalRelease();
|
|
m_pUndoManager = NULL;
|
|
}
|
|
|
|
CMDTARGET_RELEASE(m_pToolTipContext);
|
|
|
|
XTPMarkupReleaseContext(m_pMarkupContext);
|
|
|
|
CXTPFlowGraphDrawContextGdiPlus::Register(FALSE);
|
|
|
|
}
|
|
|
|
|
|
BOOL CXTPFlowGraphControl::RegisterWindowClass(HINSTANCE hInstance /*= NULL*/)
|
|
{
|
|
return XTPDrawHelpers()->RegisterWndClass(hInstance, XTPFLOWGRAPH_CLASSNAME, CS_DBLCLKS);
|
|
}
|
|
|
|
BOOL CXTPFlowGraphControl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
|
|
{
|
|
return CWnd::Create(XTPFLOWGRAPH_CLASSNAME, NULL, dwStyle, rect, pParentWnd, nID);
|
|
}
|
|
|
|
void CXTPFlowGraphControl::SetPaintManager(CXTPFlowGraphPaintManager* pPaintManager)
|
|
{
|
|
if (m_pPaintManager)
|
|
{
|
|
m_pPaintManager->Cleanup();
|
|
m_pPaintManager->InternalRelease();
|
|
m_pPaintManager = NULL;
|
|
}
|
|
|
|
m_pPaintManager = pPaintManager;
|
|
m_pPaintManager->RefreshMetrics();
|
|
|
|
if (m_pActivePage)
|
|
m_pActivePage->OnGraphChanged();
|
|
}
|
|
|
|
BEGIN_MESSAGE_MAP(CXTPFlowGraphControl, CWnd)
|
|
ON_WM_PAINT()
|
|
ON_WM_SIZE()
|
|
ON_WM_HSCROLL()
|
|
ON_WM_VSCROLL()
|
|
ON_WM_LBUTTONDOWN()
|
|
ON_WM_LBUTTONUP()
|
|
ON_WM_RBUTTONUP()
|
|
ON_WM_RBUTTONDOWN()
|
|
ON_WM_LBUTTONDBLCLK()
|
|
ON_WM_MBUTTONDOWN()
|
|
ON_WM_MOUSEWHEEL()
|
|
ON_WM_MOUSEMOVE()
|
|
END_MESSAGE_MAP()
|
|
|
|
CXTPFlowGraphDrawContext* CXTPFlowGraphControl::CreateDrawContext(CDC& dc)
|
|
{
|
|
CXTPFlowGraphDrawContext* pDC;
|
|
if ((m_nSmoothingMode == xtpFlowGraphSmoothingModeGDI) || (m_nSmoothingMode == xtpFlowGraphSmoothingModeAuto && GetZoomLevel() < GetPaintManager()->m_dMinZoomLevelGDIQuality))
|
|
{
|
|
pDC = new CXTPFlowGraphDrawContext(dc);
|
|
}
|
|
else
|
|
{
|
|
pDC = new CXTPFlowGraphDrawContextGdiPlus(dc);
|
|
|
|
if ((m_nSmoothingMode == xtpFlowGraphSmoothingModeAuto && m_bInAction) || (m_nSmoothingMode == xtpFlowGraphSmoothingModeHighSpeed))
|
|
{
|
|
pDC->SetSmoothingMode(0);
|
|
}
|
|
}
|
|
|
|
return pDC;
|
|
}
|
|
|
|
void CXTPFlowGraphControl::OnPaint()
|
|
{
|
|
CPaintDC dcPaint(this); // device context for painting
|
|
CXTPClientRect rc(this);
|
|
|
|
if (m_bReposition)
|
|
{
|
|
Reposition();
|
|
}
|
|
|
|
if (m_bmpCache.GetSafeHandle() == 0)
|
|
{
|
|
CDC memDC;
|
|
memDC.CreateCompatibleDC(&dcPaint);
|
|
|
|
m_bmpCache.DeleteObject();
|
|
m_bmpCache.CreateCompatibleBitmap(&dcPaint, rc.Width(), rc.Height());
|
|
|
|
CBitmap* pOldBitmap = memDC.SelectObject(&m_bmpCache);
|
|
|
|
CXTPFlowGraphDrawContext* pDC = CreateDrawContext(memDC);
|
|
pDC->SetClipRect(rc);
|
|
|
|
OnDraw(pDC);
|
|
|
|
|
|
dcPaint.BitBlt(0, 0, rc.right, rc.bottom, &memDC, 0, 0, SRCCOPY);
|
|
|
|
memDC.SelectObject(pOldBitmap);
|
|
|
|
delete pDC;
|
|
}
|
|
else
|
|
{
|
|
CDC memDC;
|
|
memDC.CreateCompatibleDC(&dcPaint);
|
|
|
|
CBitmap* pOldBitmap = memDC.SelectObject(&m_bmpCache);
|
|
|
|
dcPaint.BitBlt(0, 0, rc.right, rc.bottom, &memDC, 0, 0, SRCCOPY);
|
|
|
|
memDC.SelectObject(pOldBitmap);
|
|
|
|
}
|
|
}
|
|
|
|
void CXTPFlowGraphControl::OnSize(UINT nType, int cx, int cy)
|
|
{
|
|
CWnd::OnSize(nType, cx, cy);
|
|
|
|
OnGraphChanged();
|
|
Reposition();
|
|
AdjustScrollBars();
|
|
}
|
|
|
|
|
|
//#define PERFOMANCE_TRACE 1
|
|
|
|
void CXTPFlowGraphControl::OnDraw(CXTPFlowGraphDrawContext* pDC)
|
|
{
|
|
#ifdef PERFOMANCE_TRACE
|
|
_int64 nPerfomanceEnd;
|
|
_int64 nPerfomanceStart;
|
|
|
|
QueryPerformanceCounter((LARGE_INTEGER*)&nPerfomanceStart);
|
|
#endif
|
|
|
|
m_pPaintManager->DrawControlBackground(pDC, this);
|
|
|
|
if (!m_pActivePage)
|
|
return;
|
|
|
|
pDC->SetWorldTransform(m_pActivePage->m_ptScrollOffset, m_pActivePage->m_dZoomLevel);
|
|
|
|
m_pActivePage->OnDraw(pDC);
|
|
|
|
pDC->SetWorldTransform(CPoint(0, 0), 1);
|
|
|
|
if (!m_rcSelectedArea.IsRectEmpty())
|
|
{
|
|
pDC->DrawSelectionRect(m_rcSelectedArea);
|
|
}
|
|
|
|
#ifdef PERFOMANCE_TRACE
|
|
QueryPerformanceCounter((LARGE_INTEGER*)&nPerfomanceEnd);
|
|
TRACE(_T("CXTPFlowGraphControl::OnDraw = %i \n"), int(nPerfomanceEnd - nPerfomanceStart));
|
|
#endif
|
|
}
|
|
|
|
|
|
double CXTPFlowGraphControl::GetZoomLevel() const
|
|
{
|
|
if (!m_pActivePage)
|
|
return 1.0;
|
|
|
|
return m_pActivePage->m_dZoomLevel;
|
|
}
|
|
|
|
CPoint CXTPFlowGraphControl::GetScrollOffset() const
|
|
{
|
|
if (!m_pActivePage)
|
|
return CPoint(0, 0);
|
|
|
|
return m_pActivePage->GetScrollOffset();
|
|
|
|
}
|
|
|
|
void CXTPFlowGraphControl::SetZoomLevel(double dZoomLevel)
|
|
{
|
|
if (m_pActivePage)
|
|
{
|
|
m_pActivePage->m_dZoomLevel = dZoomLevel;
|
|
OnGraphChanged();
|
|
Reposition();
|
|
AdjustScrollBars();
|
|
}
|
|
}
|
|
|
|
void CXTPFlowGraphControl::RedrawControl()
|
|
{
|
|
m_bmpCache.DeleteObject();
|
|
|
|
if (::IsWindow(m_hWnd))
|
|
{
|
|
Invalidate(FALSE);
|
|
}
|
|
}
|
|
|
|
void CXTPFlowGraphControl::CancelLabelEdit()
|
|
{
|
|
CXTPFlowGraphEditItem* pWnd = DYNAMIC_DOWNCAST(CXTPFlowGraphEditItem, CWnd::FromHandlePermanent(::GetFocus()));
|
|
if (pWnd)
|
|
{
|
|
::SetFocus(m_hWnd);
|
|
}
|
|
}
|
|
|
|
void CXTPFlowGraphControl::Reposition()
|
|
{
|
|
if (!m_pActivePage)
|
|
return;
|
|
|
|
if (!m_hWnd)
|
|
return;
|
|
|
|
CancelLabelEdit();
|
|
|
|
CClientDC dcClient(this);
|
|
CXTPFlowGraphDrawContext* pDC = CreateDrawContext(dcClient);
|
|
|
|
CRect rc;
|
|
GetClientRect(&rc);
|
|
|
|
m_pActivePage->Reposition(pDC, rc);
|
|
|
|
delete pDC;
|
|
|
|
AdjustScrollBars();
|
|
|
|
m_bReposition = FALSE;
|
|
}
|
|
|
|
void CXTPFlowGraphControl::OnGraphChanged()
|
|
{
|
|
m_bmpCache.DeleteObject();
|
|
|
|
m_bReposition = TRUE;
|
|
|
|
if (::IsWindow(m_hWnd))
|
|
{
|
|
Invalidate(FALSE);
|
|
}
|
|
}
|
|
|
|
void CXTPFlowGraphControl::SetActivePage(CXTPFlowGraphPage* pPage)
|
|
{
|
|
if (m_pActivePage == pPage)
|
|
return;
|
|
|
|
if (m_pActivePage)
|
|
{
|
|
m_pActivePage->InternalRelease();
|
|
m_pActivePage = NULL;
|
|
}
|
|
|
|
m_pActivePage = pPage;
|
|
|
|
if (m_pActivePage)
|
|
{
|
|
m_pActivePage->InternalAddRef();
|
|
}
|
|
|
|
m_pUndoManager->Clear();
|
|
|
|
SendNotifyMessage(XTP_FGN_ACTIVEPAGECHANGED);
|
|
|
|
OnGraphChanged();
|
|
}
|
|
|
|
void CXTPFlowGraphControl::AdjustScrollBars()
|
|
{
|
|
if (GetSafeHwnd() == 0 || !m_pActivePage)
|
|
return;
|
|
|
|
if (m_bAdjustScrollBars)
|
|
return;
|
|
|
|
m_bAdjustScrollBars = TRUE;
|
|
|
|
|
|
// Vertical
|
|
{
|
|
int nPageSize = int(m_pActivePage->m_rcPage.Height() / m_pActivePage->m_dZoomLevel);
|
|
int nWorkTop = m_pActivePage->m_rcWorkRect.top;
|
|
int nWorkBottom = m_pActivePage->m_rcWorkRect.bottom;
|
|
int nPos = m_pActivePage->m_ptScrollOffset.y;
|
|
|
|
if (nWorkTop - nPos >= 0 && nWorkBottom - nPos <= nPageSize)
|
|
{
|
|
::EnableScrollBar(m_hWnd, SB_VERT, ESB_DISABLE_BOTH);
|
|
}
|
|
else
|
|
{
|
|
SCROLLINFO si;
|
|
si.cbSize = sizeof(SCROLLINFO);
|
|
|
|
si.nPage = nPageSize;
|
|
|
|
si.nMin = min(nPos, nWorkTop);
|
|
si.nMax = max(nPos + nPageSize, nWorkBottom);
|
|
|
|
si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
|
|
si.nPos = nPos;
|
|
|
|
::EnableScrollBar(m_hWnd, SB_VERT, ESB_ENABLE_BOTH);
|
|
|
|
SetScrollInfo(SB_VERT, &si);
|
|
EnableScrollBarCtrl(SB_VERT, TRUE);
|
|
}
|
|
|
|
}
|
|
|
|
// Horizontal
|
|
{
|
|
int nPageSize = int(m_pActivePage->m_rcPage.Width() / m_pActivePage->m_dZoomLevel);
|
|
int nWorkTop = m_pActivePage->m_rcWorkRect.left;
|
|
int nWorkBottom = m_pActivePage->m_rcWorkRect.right;
|
|
int nPos = m_pActivePage->m_ptScrollOffset.x;
|
|
|
|
if (nWorkTop - nPos >= 0 && nWorkBottom - nPos <= nPageSize)
|
|
{
|
|
//EnableScrollBarCtrl(SB_HORZ, FALSE);
|
|
//SetScrollPos(SB_HORZ, 0);
|
|
::EnableScrollBar(m_hWnd, SB_HORZ, ESB_DISABLE_BOTH);
|
|
|
|
}
|
|
else
|
|
{
|
|
SCROLLINFO si;
|
|
si.cbSize = sizeof(SCROLLINFO);
|
|
si.nPage = nPageSize;
|
|
|
|
si.nMin = min(nPos, nWorkTop);
|
|
si.nMax = max(nPos + nPageSize, nWorkBottom);
|
|
|
|
si.fMask = SIF_PAGE | SIF_RANGE | SIF_POS;
|
|
si.nPos = nPos;
|
|
|
|
::EnableScrollBar(m_hWnd, SB_HORZ, ESB_ENABLE_BOTH);
|
|
|
|
SetScrollInfo(SB_HORZ, &si);
|
|
EnableScrollBarCtrl(SB_HORZ, TRUE);
|
|
}
|
|
}
|
|
|
|
|
|
m_bAdjustScrollBars = FALSE;
|
|
}
|
|
|
|
void CXTPFlowGraphControl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
|
|
{
|
|
if (pScrollBar != NULL)
|
|
{
|
|
CWnd::OnHScroll(nSBCode, nPos, pScrollBar);
|
|
return;
|
|
}
|
|
|
|
if (!m_pActivePage)
|
|
return;
|
|
|
|
int nCurPos = m_pActivePage->m_ptScrollOffset.x;
|
|
|
|
// decide what to do for each different scroll event
|
|
switch (nSBCode)
|
|
{
|
|
case SB_TOP:
|
|
nCurPos = min(m_pActivePage->m_rcWorkRect.left, min(nCurPos, m_pActivePage->m_rcWorkRect.left));
|
|
break;
|
|
|
|
case SB_BOTTOM:
|
|
nCurPos = GetScrollLimit(SB_HORZ);
|
|
break;
|
|
|
|
case SB_LINEUP:
|
|
nCurPos = nCurPos - m_pActivePage->m_rcPage.Width() / 10;
|
|
break;
|
|
|
|
case SB_LINEDOWN:
|
|
nCurPos = nCurPos + m_pActivePage->m_rcPage.Width() / 10;
|
|
break;
|
|
|
|
case SB_PAGEUP:
|
|
nCurPos = max(nCurPos - m_pActivePage->m_rcPage.Width(), m_pActivePage->m_rcWorkRect.left);
|
|
break;
|
|
|
|
case SB_PAGEDOWN:
|
|
nCurPos = min(nCurPos + m_pActivePage->m_rcPage.Width(), GetScrollLimit(SB_HORZ));
|
|
break;
|
|
|
|
case SB_THUMBTRACK:
|
|
case SB_THUMBPOSITION:
|
|
|
|
{
|
|
SCROLLINFO si;
|
|
ZeroMemory(&si, sizeof(SCROLLINFO));
|
|
si.cbSize = sizeof(SCROLLINFO);
|
|
si.fMask = SIF_TRACKPOS;
|
|
|
|
if (!GetScrollInfo(SB_HORZ, &si))
|
|
return;
|
|
nCurPos = si.nTrackPos;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (nCurPos != m_pActivePage->m_ptScrollOffset.x)
|
|
{
|
|
m_pActivePage->m_ptScrollOffset.x = nCurPos;
|
|
AdjustScrollBars();
|
|
|
|
OnGraphChanged();
|
|
}
|
|
}
|
|
|
|
void CXTPFlowGraphControl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
|
|
{
|
|
if (pScrollBar != NULL)
|
|
{
|
|
CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
|
|
return;
|
|
}
|
|
|
|
if (!m_pActivePage)
|
|
return;
|
|
|
|
int nCurPos = m_pActivePage->m_ptScrollOffset.y;
|
|
|
|
// decide what to do for each different scroll event
|
|
switch (nSBCode)
|
|
{
|
|
case SB_TOP:
|
|
nCurPos = min(m_pActivePage->m_rcWorkRect.top, min(nCurPos, m_pActivePage->m_rcWorkRect.top));
|
|
break;
|
|
|
|
case SB_BOTTOM:
|
|
nCurPos = GetScrollLimit(SB_VERT);
|
|
break;
|
|
|
|
case SB_LINEUP:
|
|
nCurPos = nCurPos - m_pActivePage->m_rcPage.Height() / 10;
|
|
break;
|
|
|
|
case SB_LINEDOWN:
|
|
nCurPos = nCurPos + m_pActivePage->m_rcPage.Height() / 10;
|
|
break;
|
|
|
|
case SB_PAGEUP:
|
|
nCurPos = max(nCurPos - m_pActivePage->m_rcPage.Height(), m_pActivePage->m_rcWorkRect.top);
|
|
break;
|
|
|
|
case SB_PAGEDOWN:
|
|
nCurPos = min(nCurPos + m_pActivePage->m_rcPage.Height(), GetScrollLimit(SB_VERT));
|
|
break;
|
|
|
|
case SB_THUMBTRACK:
|
|
case SB_THUMBPOSITION:
|
|
|
|
{
|
|
SCROLLINFO si;
|
|
ZeroMemory(&si, sizeof(SCROLLINFO));
|
|
si.cbSize = sizeof(SCROLLINFO);
|
|
si.fMask = SIF_TRACKPOS;
|
|
|
|
if (!GetScrollInfo(SB_VERT, &si))
|
|
return;
|
|
nCurPos = si.nTrackPos;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (nCurPos != m_pActivePage->m_ptScrollOffset.y)
|
|
{
|
|
m_pActivePage->m_ptScrollOffset.y = nCurPos;
|
|
AdjustScrollBars();
|
|
|
|
OnGraphChanged();
|
|
}
|
|
}
|
|
|
|
|
|
BOOL CXTPFlowGraphControl::OnMouseWheel(UINT /*nFlags*/, short zDelta, CPoint pt)
|
|
{
|
|
GetCursorPos(&pt);
|
|
ScreenToClient(&pt);
|
|
|
|
if (!m_pActivePage)
|
|
return FALSE;
|
|
|
|
double dZoomLevel = m_pActivePage->m_dZoomLevel;
|
|
|
|
int nZoom = int(m_pActivePage->m_dZoomLevel * 100);
|
|
|
|
if (zDelta < 0)
|
|
{
|
|
int nLineDelta = nZoom <= 100 ? 10 : 50;
|
|
|
|
nZoom = max(((nZoom / nLineDelta) - 1) * nLineDelta, int(100 * m_dMinZoom));
|
|
}
|
|
else
|
|
{
|
|
int nLineDelta = nZoom < 100 ? 10 : 50;
|
|
|
|
nZoom = min(((nZoom / nLineDelta) + 1) * nLineDelta, int(100 * m_dMaxZoom));
|
|
}
|
|
|
|
m_pActivePage->m_dZoomLevel = nZoom / 100.0;
|
|
|
|
if (fabs(m_pActivePage->m_dZoomLevel - dZoomLevel) < 1e-6)
|
|
return FALSE;
|
|
|
|
|
|
double x = pt.x / dZoomLevel + m_pActivePage->GetScrollOffset().x;
|
|
double y = pt.y / dZoomLevel + m_pActivePage->GetScrollOffset().y;
|
|
|
|
x = (x - pt.x / m_pActivePage->m_dZoomLevel);
|
|
y = (y - pt.y / m_pActivePage->m_dZoomLevel);
|
|
|
|
m_pActivePage->m_ptScrollOffset = CPoint(int(x), int(y));
|
|
|
|
|
|
OnGraphChanged();
|
|
Reposition();
|
|
AdjustScrollBars();
|
|
|
|
SendNotifyMessage(XTP_FGN_PAGEZOOMLEVELCHANGED);
|
|
SendNotifyMessage(XTP_FGN_PAGESCROLLOFFSETCHANGED);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CXTPFlowGraphControl::OnMouseMove(UINT nFlags, CPoint point)
|
|
{
|
|
CWnd::OnMouseMove(nFlags, point);
|
|
|
|
|
|
}
|
|
|
|
CXTPFlowGraphNode* CXTPFlowGraphControl::HitTestNode(CPoint point) const
|
|
{
|
|
if (!m_pActivePage)
|
|
return NULL;
|
|
|
|
for (CXTPFlowGraphNode* pNode = m_pActivePage->m_pFirstVisibleNode; pNode != NULL; pNode = pNode->m_pNextVisibleNode)
|
|
{
|
|
if (pNode->GetScreenRect().PtInRect(point))
|
|
{
|
|
return pNode;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
CXTPFlowGraphConnection* CXTPFlowGraphControl::HitTestConnection(CPoint point) const
|
|
{
|
|
if (!m_pActivePage)
|
|
return NULL;
|
|
|
|
for (CXTPFlowGraphConnection* pConnection = m_pActivePage->m_pFirstVisibleConnection;
|
|
pConnection != NULL; pConnection = pConnection->m_pNextVisibleConnection)
|
|
{
|
|
if (pConnection->PtInRect(point))
|
|
{
|
|
return pConnection;
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
CXTPFlowGraphConnectionPoint* CXTPFlowGraphControl::HitTestConnectionArea(CPoint point) const
|
|
{
|
|
if (!m_pActivePage)
|
|
return NULL;
|
|
|
|
CXTPFlowGraphNode* pNode = NULL;
|
|
int i;
|
|
|
|
for (i = m_pActivePage->GetNodes()->GetCount() - 1; i >= 0; i--)
|
|
{
|
|
CXTPFlowGraphNode* p = m_pActivePage->GetNodes()->GetAt(i);
|
|
CRect rc = m_pPaintManager->GetNodeBoundingRectangle(p);
|
|
rc = m_pActivePage->PageToScreen(rc);
|
|
|
|
if (rc.PtInRect(point))
|
|
{
|
|
pNode = p;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!pNode)
|
|
return NULL;
|
|
|
|
for (i = 0; i < pNode->GetConnectionPoints()->GetCount(); i++)
|
|
{
|
|
CXTPFlowGraphConnectionPoint* pPoint = pNode->GetConnectionPoints()->GetAt(i);
|
|
|
|
if (pPoint->HitTestConnectionArea(point))
|
|
return pPoint;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
void CXTPFlowGraphControl::OnLButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
CWnd::OnLButtonDown(nFlags, point);
|
|
|
|
SetFocus();
|
|
|
|
if (!m_pActivePage)
|
|
return;
|
|
|
|
|
|
|
|
CXTPFlowGraphSelectedElements* pSelection = m_pActivePage->GetSelection();
|
|
|
|
if (m_bAllowModifyConnections)
|
|
{
|
|
CXTPFlowGraphConnectionPoint* pPoint = HitTestConnectionArea(point);
|
|
if (pPoint && !pPoint->IsLocked())
|
|
{
|
|
StartDragConnectionPoint(pPoint);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
CXTPFlowGraphNode* pNode = HitTestNode(point);
|
|
|
|
if (pNode)
|
|
{
|
|
if (!pNode->IsSelected())
|
|
{
|
|
if (!(GetKeyState(VK_CONTROL) < 0 || GetKeyState(VK_SHIFT) < 0))
|
|
pSelection->Clear();
|
|
|
|
pNode->Select();
|
|
|
|
if (pSelection->GetCount() > 1)
|
|
{
|
|
|
|
for (int j = 0; j < m_pActivePage->GetConnections()->GetCount(); j++)
|
|
{
|
|
CXTPFlowGraphConnection* pConnection = m_pActivePage->GetConnections()->GetAt(j);
|
|
if (pConnection->GetInputPoint() && pConnection->GetInputPoint()->GetNode()->IsSelected() &&
|
|
pConnection->GetOutputPoint() && pConnection->GetOutputPoint()->GetNode()->IsSelected() &&
|
|
(pConnection->GetInputPoint()->GetNode() == pNode || pConnection->GetOutputPoint()->GetNode() == pNode))
|
|
{
|
|
pSelection->AddSelection(pConnection);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
else if (GetKeyState(VK_CONTROL) < 0)
|
|
{
|
|
pSelection->Remove(pNode);
|
|
}
|
|
|
|
m_pActivePage->GetNodes()->MoveToFront(pNode);
|
|
|
|
if (m_nAllowResizeNodes && !pNode->IsLocked())
|
|
{
|
|
CRect rcNode(pNode->GetLocation(), pNode->GetSize());
|
|
rcNode.DeflateRect(4, 4);
|
|
|
|
rcNode = m_pActivePage->PageToScreen(rcNode);
|
|
|
|
if (!rcNode.PtInRect(point))
|
|
{
|
|
StartResizeNode(pNode);
|
|
return;
|
|
}
|
|
}
|
|
StartDragNodes();
|
|
return;
|
|
}
|
|
|
|
CXTPFlowGraphConnection* pConnection = HitTestConnection(point);
|
|
|
|
if (pConnection)
|
|
{
|
|
if (!pConnection->IsSelected())
|
|
{
|
|
if (GetKeyState(VK_CONTROL) < 0 || GetKeyState(VK_SHIFT) < 0)
|
|
pSelection->AddSelection(pConnection);
|
|
else
|
|
pSelection->SetSelection(pConnection);
|
|
}
|
|
else if (GetKeyState(VK_CONTROL) < 0)
|
|
{
|
|
pSelection->Remove(pConnection);
|
|
}
|
|
|
|
StartDragConnection(pConnection);
|
|
return;
|
|
}
|
|
|
|
pSelection->Clear();
|
|
StartDragSelection();
|
|
}
|
|
|
|
void CXTPFlowGraphControl::OnLButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
CWnd::OnLButtonUp(nFlags, point);
|
|
|
|
SendNotifyMessage(NM_CLICK);
|
|
|
|
|
|
}
|
|
|
|
void CXTPFlowGraphControl::OnLButtonDblClk(UINT nFlags, CPoint point)
|
|
{
|
|
CWnd::OnLButtonDblClk(nFlags, point);
|
|
|
|
CXTPFlowGraphConnection* pConnection = HitTestConnection(point);
|
|
|
|
if (pConnection)
|
|
{
|
|
if (pConnection->GetControlPoint() != CPoint(-1, -1))
|
|
pConnection->SetControlPoint(CPoint(-1, -1));
|
|
}
|
|
|
|
SendNotifyMessage(NM_DBLCLK);
|
|
}
|
|
|
|
void CXTPFlowGraphControl::OnMButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
CWnd::OnMButtonDown(nFlags, point);
|
|
|
|
if (!m_pActivePage)
|
|
return;
|
|
|
|
StartDragScreen();
|
|
}
|
|
|
|
|
|
|
|
void CXTPFlowGraphControl::OnMoveSelection(CPoint pt)
|
|
{
|
|
CRect rc(m_ptStartDrag, pt);
|
|
rc.NormalizeRect();
|
|
|
|
ScreenToClient(&rc);
|
|
|
|
m_pActivePage->GetSelection()->Clear();
|
|
|
|
int i;
|
|
|
|
for (i = m_pActivePage->GetNodes()->GetCount() - 1; i >= 0; i--)
|
|
{
|
|
CXTPFlowGraphNode* pNode = m_pActivePage->GetNodes()->GetAt(i);
|
|
|
|
if (CRect().IntersectRect(pNode->GetScreenRect(), rc))
|
|
{
|
|
pNode->Select();
|
|
}
|
|
}
|
|
|
|
for (i = 0; i < m_pActivePage->GetConnections()->GetCount(); i++)
|
|
{
|
|
CXTPFlowGraphConnection* pConnection = m_pActivePage->GetConnections()->GetAt(i);
|
|
if (pConnection->GetInputPoint() && pConnection->GetInputPoint()->GetNode()->IsSelected() &&
|
|
pConnection->GetOutputPoint() && pConnection->GetOutputPoint()->GetNode()->IsSelected())
|
|
{
|
|
m_pActivePage->GetSelection()->AddSelection(pConnection);
|
|
}
|
|
}
|
|
|
|
m_rcSelectedArea = rc;
|
|
RedrawControl();
|
|
}
|
|
|
|
void CXTPFlowGraphControl::StartDragConnection(CXTPFlowGraphConnection* pConnection)
|
|
{
|
|
if (!m_bAllowModifyConnections)
|
|
return;
|
|
|
|
// set capture to the window which received this message
|
|
SetCapture();
|
|
|
|
CPoint pt(0, 0);
|
|
GetCursorPos(&pt);
|
|
|
|
m_ptStartDrag = pt;
|
|
|
|
m_pUndoManager->StartGroup();
|
|
|
|
|
|
// get messages until capture lost or cancelled/accepted
|
|
while (::GetCapture() == m_hWnd)
|
|
{
|
|
MSG msg;
|
|
|
|
while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
|
|
{
|
|
if (!GetMessage(&msg, NULL, WM_PAINT, WM_PAINT))
|
|
break;
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
if (!::GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
AfxPostQuitMessage((int)msg.wParam);
|
|
break;
|
|
}
|
|
|
|
if (msg.message == WM_LBUTTONUP)
|
|
break;
|
|
else if (msg.message == WM_MOUSEMOVE && pt != msg.pt)
|
|
{
|
|
pt = msg.pt;
|
|
|
|
CPoint point(pt);
|
|
ScreenToClient(&point);
|
|
|
|
double x = point.x, y = point.y;
|
|
m_pActivePage->ScreenToPage(x, y);
|
|
|
|
pConnection->SetControlPoint(CPoint((int)x, (int)y));
|
|
}
|
|
else if (msg.message == WM_KEYDOWN)
|
|
{
|
|
if (msg.wParam == VK_ESCAPE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
|
|
ReleaseCapture();
|
|
|
|
RedrawControl();
|
|
|
|
m_pUndoManager->EndGroup();
|
|
}
|
|
|
|
void CXTPFlowGraphControl::StartDragConnectionPoint(CXTPFlowGraphConnectionPoint* pPoint)
|
|
{
|
|
CPoint pt(0, 0);
|
|
GetCursorPos(&pt);
|
|
|
|
m_ptStartDrag = pt;
|
|
BOOL bOutput = pPoint->GetType() & xtpFlowGraphPointOutput;
|
|
CXTPFlowGraphConnectionPoint* pOutputPoint = bOutput ? pPoint : NULL;
|
|
|
|
m_pUndoManager->StartGroup();
|
|
|
|
if (!pOutputPoint)
|
|
{
|
|
int j = -1;
|
|
for (int i = m_pActivePage->GetConnections()->GetCount() - 1; i >= 0; i--)
|
|
{
|
|
CXTPFlowGraphConnection* pConnection = m_pActivePage->GetConnections()->GetAt(i);
|
|
|
|
if (pConnection->GetInputPoint() == pPoint && !pPoint->IsLocked())
|
|
{
|
|
if (pConnection->IsSelected())
|
|
{
|
|
pOutputPoint = pConnection->GetOutputPoint();
|
|
m_pActivePage->GetConnections()->RemoveAt(i);
|
|
break;
|
|
}
|
|
else if (j == -1)
|
|
{
|
|
j = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (pOutputPoint == NULL && j != -1)
|
|
{
|
|
pOutputPoint = m_pActivePage->GetConnections()->GetAt(j)->GetOutputPoint();
|
|
m_pActivePage->GetConnections()->RemoveAt(j);
|
|
}
|
|
|
|
}
|
|
|
|
UpdateWindow();
|
|
|
|
if (pOutputPoint == NULL)
|
|
{
|
|
m_pUndoManager->EndGroup();
|
|
return;
|
|
}
|
|
|
|
if (pOutputPoint->GetMaxConnections() >= 0 && pOutputPoint->GetConnectionsCount() >= pOutputPoint->GetMaxConnections())
|
|
{
|
|
m_pUndoManager->EndGroup();
|
|
return;
|
|
}
|
|
|
|
m_bInAction = TRUE;
|
|
|
|
|
|
CXTPFlowGraphConnection* pDragConnection = new CXTPFlowGraphConnection();
|
|
pDragConnection->SetOutputPoint(pOutputPoint);
|
|
|
|
m_pActivePage->GetConnections()->AddConnection(pDragConnection);
|
|
|
|
m_pActivePage->GetSelection()->Clear();
|
|
m_pActivePage->GetSelection()->AddSelection(pDragConnection);
|
|
|
|
ScreenToClient(&pt);
|
|
pDragConnection->m_ptInputPoint = m_pActivePage->ScreenToPage(pt);
|
|
|
|
CXTPFlowGraphConnectionPoint* pConnectionPoint = HitTestConnectionArea(pt);
|
|
CXTPFlowGraphConnectionPoint* pInputConnectionPoint = NULL;
|
|
|
|
if (pConnectionPoint && pConnectionPoint->GetType() & xtpFlowGraphPointInput &&
|
|
pConnectionPoint->GetNode() != pDragConnection->GetOutputPoint()->GetNode())
|
|
{
|
|
pInputConnectionPoint = pConnectionPoint;
|
|
m_pActivePage->GetSelection()->AddSelection(pInputConnectionPoint);
|
|
}
|
|
|
|
m_pActivePage->GetSelection()->AddSelection(pDragConnection->GetOutputPoint());
|
|
|
|
// set capture to the window which received this message
|
|
SetCapture();
|
|
|
|
BOOL bAccept = FALSE;
|
|
|
|
// get messages until capture lost or cancelled/accepted
|
|
while (::GetCapture() == m_hWnd)
|
|
{
|
|
MSG msg;
|
|
|
|
while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
|
|
{
|
|
if (!GetMessage(&msg, NULL, WM_PAINT, WM_PAINT))
|
|
break;
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
if (!::GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
AfxPostQuitMessage((int)msg.wParam);
|
|
break;
|
|
}
|
|
|
|
if (msg.message == WM_LBUTTONUP)
|
|
{
|
|
bAccept = TRUE;
|
|
break;
|
|
}
|
|
else if (msg.message == WM_MOUSEMOVE && pt != msg.pt)
|
|
{
|
|
pt = msg.pt;
|
|
|
|
CPoint point(pt);
|
|
ScreenToClient(&point);
|
|
|
|
pDragConnection->m_ptInputPoint = m_pActivePage->ScreenToPage(point);
|
|
pDragConnection->OnGraphChanged();
|
|
|
|
CXTPFlowGraphConnectionPoint* pConnectionPoint = HitTestConnectionArea(point);
|
|
|
|
if (pConnectionPoint && pConnectionPoint->GetType() & xtpFlowGraphPointInput && !pConnectionPoint->IsLocked() &&
|
|
pConnectionPoint->GetNode() != pDragConnection->GetOutputPoint()->GetNode())
|
|
{
|
|
if ((pConnectionPoint->GetMaxConnections() == -1 || pConnectionPoint->GetConnectionsCount() < pConnectionPoint->GetMaxConnections())
|
|
&& pInputConnectionPoint != pConnectionPoint)
|
|
{
|
|
XTP_NM_FLOWGRAPH_CONNECTIONCHANGING cc;
|
|
cc.pConnection = pDragConnection;
|
|
cc.pInputConnectionPoint = pConnectionPoint;
|
|
|
|
if (SendNotifyMessage(XTP_FGN_CONNECTIONCHANGING, &cc.hdr) != -1)
|
|
{
|
|
m_pActivePage->GetSelection()->Remove(pInputConnectionPoint);
|
|
|
|
pInputConnectionPoint = pConnectionPoint;
|
|
m_pActivePage->GetSelection()->AddSelection(pInputConnectionPoint);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pInputConnectionPoint != NULL)
|
|
{
|
|
m_pActivePage->GetSelection()->Remove(pInputConnectionPoint);
|
|
pInputConnectionPoint = NULL;
|
|
}
|
|
}
|
|
|
|
|
|
RedrawControl();
|
|
}
|
|
else if (msg.message == WM_KEYDOWN)
|
|
{
|
|
if (msg.wParam == VK_ESCAPE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
|
|
ReleaseCapture();
|
|
|
|
m_pActivePage->GetSelection()->Remove(pDragConnection->GetOutputPoint());
|
|
|
|
if (bAccept && pInputConnectionPoint)
|
|
{
|
|
pDragConnection->SetInputPoint(pInputConnectionPoint);
|
|
}
|
|
|
|
if (pInputConnectionPoint != NULL)
|
|
{
|
|
m_pActivePage->GetSelection()->Remove(pInputConnectionPoint);
|
|
pInputConnectionPoint = NULL;
|
|
}
|
|
|
|
if (pDragConnection->GetInputPoint() == NULL)
|
|
{
|
|
m_pActivePage->GetConnections()->Remove(pDragConnection);
|
|
}
|
|
|
|
m_pUndoManager->EndGroup();
|
|
|
|
m_bInAction = FALSE;
|
|
|
|
RedrawControl();
|
|
}
|
|
|
|
|
|
void CXTPFlowGraphControl::StartDragSelection()
|
|
{
|
|
// set capture to the window which received this message
|
|
SetCapture();
|
|
|
|
CPoint pt(0, 0);
|
|
GetCursorPos(&pt);
|
|
|
|
m_ptStartDrag = pt;
|
|
|
|
BOOL bButtonUp = FALSE;
|
|
|
|
|
|
// get messages until capture lost or cancelled/accepted
|
|
while (::GetCapture() == m_hWnd)
|
|
{
|
|
MSG msg;
|
|
|
|
while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
|
|
{
|
|
if (!GetMessage(&msg, NULL, WM_PAINT, WM_PAINT))
|
|
break;
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
if (!::GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
AfxPostQuitMessage((int)msg.wParam);
|
|
break;
|
|
}
|
|
|
|
if (msg.message == WM_LBUTTONUP)
|
|
{
|
|
bButtonUp = TRUE;
|
|
break;
|
|
}
|
|
else if (msg.message == WM_MOUSEMOVE && pt != msg.pt)
|
|
{
|
|
pt = msg.pt;
|
|
OnMoveSelection(pt);
|
|
}
|
|
else if (msg.message == WM_KEYDOWN)
|
|
{
|
|
if (msg.wParam == VK_ESCAPE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
|
|
ReleaseCapture();
|
|
|
|
m_rcSelectedArea.SetRectEmpty();
|
|
RedrawControl();
|
|
|
|
}
|
|
|
|
void CXTPFlowGraphControl::StartResizeNode(CXTPFlowGraphNode* pNode)
|
|
{
|
|
CPoint pt(0, 0);
|
|
GetCursorPos(&pt);
|
|
|
|
m_ptStartDrag = pt;
|
|
|
|
CRect rcBorders(pNode->GetLocation(), pNode->GetSize());
|
|
rcBorders.DeflateRect(4, 4);
|
|
|
|
rcBorders = m_pActivePage->PageToScreen(&rcBorders);
|
|
ClientToScreen(&rcBorders);
|
|
|
|
int ht = 0;
|
|
|
|
if (m_nAllowResizeNodes & xtpFlowGraphResizeVertical)
|
|
{
|
|
if (pt.y < rcBorders.top)
|
|
ht = (HTTOP - HTSIZEFIRST + 1);
|
|
else if (pt.y >= rcBorders.bottom)
|
|
ht = (HTBOTTOM - HTSIZEFIRST + 1);
|
|
}
|
|
|
|
if (m_nAllowResizeNodes & xtpFlowGraphResizeHorizontal)
|
|
{
|
|
if (pt.x < rcBorders.left)
|
|
ht += (HTLEFT - HTSIZEFIRST + 1);
|
|
else if (pt.x >= rcBorders.right)
|
|
ht += (HTRIGHT - HTSIZEFIRST + 1);
|
|
}
|
|
|
|
if (ht == 0)
|
|
return;
|
|
|
|
ht = (ht + HTSIZEFIRST - 1);
|
|
|
|
CRect rcOrigin(pNode->GetLocation(), pNode->GetSize());
|
|
|
|
|
|
m_pUndoManager->StartGroup();
|
|
|
|
// set capture to the window which received this message
|
|
SetCapture();
|
|
|
|
::SetCursor(AfxGetApp()->LoadStandardCursor(ht == HTLEFT || ht == HTRIGHT ? IDC_SIZEWE :
|
|
ht == HTTOP || ht == HTBOTTOM ? IDC_SIZENS : ht == HTTOPLEFT || ht == HTBOTTOMRIGHT ? IDC_SIZENWSE : IDC_SIZENESW));
|
|
|
|
// get messages until capture lost or cancelled/accepted
|
|
while (::GetCapture() == m_hWnd)
|
|
{
|
|
MSG msg;
|
|
|
|
while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
|
|
{
|
|
if (!GetMessage(&msg, NULL, WM_PAINT, WM_PAINT))
|
|
break;
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
if (!::GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
AfxPostQuitMessage((int)msg.wParam);
|
|
break;
|
|
}
|
|
|
|
if (msg.message == WM_LBUTTONUP)
|
|
break;
|
|
else if (msg.message == WM_MOUSEMOVE && pt != msg.pt)
|
|
{
|
|
CPoint ptOffset(int(1 / m_pActivePage->m_dZoomLevel * (msg.pt.x - m_ptStartDrag.x)), int(1 / m_pActivePage->m_dZoomLevel * (msg.pt.y - m_ptStartDrag.y)));
|
|
|
|
CRect rcRect(rcOrigin);
|
|
if (ht == HTTOP || ht == HTTOPLEFT || ht == HTTOPRIGHT)
|
|
rcRect.top += ptOffset.y;
|
|
if (ht == HTLEFT || ht == HTTOPLEFT || ht == HTBOTTOMLEFT)
|
|
rcRect.left += ptOffset.x;
|
|
if (ht == HTRIGHT || ht == HTTOPRIGHT || ht == HTBOTTOMRIGHT)
|
|
rcRect.right += ptOffset.x;
|
|
if (ht == HTBOTTOM || ht == HTBOTTOMRIGHT || ht == HTBOTTOMLEFT)
|
|
rcRect.bottom += ptOffset.y;
|
|
|
|
pNode->SetLocation(rcRect.TopLeft());
|
|
pNode->SetSize(rcRect.Size());
|
|
|
|
UpdateWindow();
|
|
|
|
pt = msg.pt;
|
|
}
|
|
else if (msg.message == WM_KEYDOWN)
|
|
{
|
|
if (msg.wParam == VK_ESCAPE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
|
|
ReleaseCapture();
|
|
|
|
m_pUndoManager->EndGroup();
|
|
}
|
|
|
|
void CXTPFlowGraphControl::StartDragNodes()
|
|
{
|
|
if (!m_bAllowMoveNodes)
|
|
return;
|
|
|
|
m_arrDragNodes.RemoveAll();
|
|
|
|
for (int i = 0; i < m_pActivePage->GetSelection()->GetCount(); i++)
|
|
{
|
|
CXTPFlowGraphNode* pNode = DYNAMIC_DOWNCAST(CXTPFlowGraphNode, m_pActivePage->GetSelection()->GetAt(i));
|
|
if (pNode)
|
|
{
|
|
if (!pNode->IsLocked())
|
|
{
|
|
DRAGNODE dn;
|
|
dn.pElement = pNode;
|
|
dn.bNode = TRUE;
|
|
dn.ptOrigin = pNode->GetLocation();
|
|
m_arrDragNodes.Add(dn);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CXTPFlowGraphConnection* pConnection = DYNAMIC_DOWNCAST(CXTPFlowGraphConnection, m_pActivePage->GetSelection()->GetAt(i));
|
|
if (pConnection && pConnection->GetControlPoint() != CPoint(-1, -1))
|
|
{
|
|
DRAGNODE dn;
|
|
dn.pElement = pConnection;
|
|
dn.bNode = FALSE;
|
|
dn.ptOrigin = pConnection->GetControlPoint();
|
|
m_arrDragNodes.Add(dn);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (m_arrDragNodes.GetSize() == 0)
|
|
return;
|
|
|
|
m_pUndoManager->StartGroup();
|
|
|
|
m_bInAction = TRUE;
|
|
|
|
// set capture to the window which received this message
|
|
SetCapture();
|
|
|
|
CPoint pt(0, 0);
|
|
GetCursorPos(&pt);
|
|
|
|
m_ptStartDrag = pt;
|
|
|
|
::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL));
|
|
|
|
// get messages until capture lost or cancelled/accepted
|
|
while (::GetCapture() == m_hWnd)
|
|
{
|
|
MSG msg;
|
|
|
|
while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
|
|
{
|
|
if (!GetMessage(&msg, NULL, WM_PAINT, WM_PAINT))
|
|
break;
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
if (!::GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
AfxPostQuitMessage((int)msg.wParam);
|
|
break;
|
|
}
|
|
|
|
if (msg.message == WM_LBUTTONUP)
|
|
break;
|
|
else if (msg.message == WM_MOUSEMOVE && pt != msg.pt)
|
|
{
|
|
CPoint ptOffset(int(1 / m_pActivePage->m_dZoomLevel * (msg.pt.x - m_ptStartDrag.x)), int(1 / m_pActivePage->m_dZoomLevel * (msg.pt.y - m_ptStartDrag.y)));
|
|
|
|
for (int i = 0; i < m_arrDragNodes.GetSize(); i++)
|
|
{
|
|
DRAGNODE& dn = m_arrDragNodes[i];
|
|
|
|
if (dn.bNode)
|
|
{
|
|
((CXTPFlowGraphNode*)dn.pElement)->SetLocation(CPoint(dn.ptOrigin.x + ptOffset.x, dn.ptOrigin.y + ptOffset.y));
|
|
|
|
}
|
|
else
|
|
{
|
|
((CXTPFlowGraphConnection*)dn.pElement)->SetControlPoint(CPoint(dn.ptOrigin.x + ptOffset.x, dn.ptOrigin.y + ptOffset.y));
|
|
}
|
|
|
|
}
|
|
UpdateWindow();
|
|
|
|
pt = msg.pt;
|
|
}
|
|
else if (msg.message == WM_KEYDOWN)
|
|
{
|
|
if (msg.wParam == VK_ESCAPE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
|
|
ReleaseCapture();
|
|
|
|
m_pUndoManager->EndGroup();
|
|
|
|
m_bInAction = FALSE;
|
|
RedrawControl();
|
|
}
|
|
|
|
|
|
void CXTPFlowGraphControl::StartDragScreen()
|
|
{
|
|
m_bInAction = TRUE;
|
|
|
|
// set capture to the window which received this message
|
|
SetCapture();
|
|
|
|
CPoint pt(0, 0);
|
|
GetCursorPos(&pt);
|
|
|
|
m_ptStartDrag = pt;
|
|
|
|
CPoint ptOrigin(m_pActivePage->GetScrollOffset());
|
|
|
|
|
|
::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEALL));
|
|
|
|
|
|
// get messages until capture lost or cancelled/accepted
|
|
while (::GetCapture() == m_hWnd)
|
|
{
|
|
MSG msg;
|
|
|
|
while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
|
|
{
|
|
if (!GetMessage(&msg, NULL, WM_PAINT, WM_PAINT))
|
|
break;
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
if (!::GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
AfxPostQuitMessage((int)msg.wParam);
|
|
break;
|
|
}
|
|
|
|
if (msg.message == WM_LBUTTONUP || msg.message == WM_MBUTTONUP)
|
|
break;
|
|
else if (msg.message == WM_MOUSEMOVE && pt != msg.pt)
|
|
{
|
|
CPoint ptOffset(int(1.0 / m_pActivePage->m_dZoomLevel * (msg.pt.x - m_ptStartDrag.x)), int(1.0 / m_pActivePage->m_dZoomLevel * (msg.pt.y - m_ptStartDrag.y)));
|
|
|
|
m_pActivePage->m_ptScrollOffset = CPoint(ptOrigin.x - ptOffset.x, ptOrigin.y - ptOffset.y);
|
|
SendNotifyMessage(XTP_FGN_PAGESCROLLOFFSETCHANGED);
|
|
|
|
OnGraphChanged();
|
|
UpdateWindow();
|
|
|
|
pt = msg.pt;
|
|
}
|
|
else if (msg.message == WM_KEYDOWN)
|
|
{
|
|
if (msg.wParam == VK_ESCAPE)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
DispatchMessage(&msg);
|
|
|
|
}
|
|
|
|
ReleaseCapture();
|
|
|
|
m_bInAction = FALSE;
|
|
RedrawControl();
|
|
}
|
|
|
|
|
|
void CXTPFlowGraphControl::DoPropExchange(CXTPPropExchange* pPX)
|
|
{
|
|
CXTPPropExchangeSection secPages(pPX->GetSection(_T("Pages")));
|
|
m_pPages->DoPropExchange(&secPages);
|
|
|
|
if (pPX->IsLoading())
|
|
{
|
|
m_pUndoManager->Clear();
|
|
m_pHistory->Clear();
|
|
}
|
|
}
|
|
|
|
void CXTPFlowGraphControl::ZoomToSelection()
|
|
{
|
|
if (!m_pActivePage)
|
|
return;
|
|
|
|
CRect rcWorkRect(0, 0, 0, 0);
|
|
|
|
for (int i = 0; i < m_pActivePage->GetSelection()->GetCount(); i++)
|
|
{
|
|
CRect rc;
|
|
|
|
if (CXTPFlowGraphNode* pNode = DYNAMIC_DOWNCAST(CXTPFlowGraphNode, m_pActivePage->GetSelection()->GetAt(i)))
|
|
{
|
|
rc = GetPaintManager()->GetNodeBoundingRectangle(pNode);
|
|
}
|
|
else if (CXTPFlowGraphConnection* pConnection = DYNAMIC_DOWNCAST(CXTPFlowGraphConnection, m_pActivePage->GetSelection()->GetAt(i)))
|
|
{
|
|
rc = pConnection->GetBoundingRect();
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if (rcWorkRect.IsRectEmpty())
|
|
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);
|
|
}
|
|
if (rcWorkRect.IsRectEmpty())
|
|
return;
|
|
|
|
ZoomToRect(rcWorkRect);
|
|
}
|
|
|
|
void CXTPFlowGraphControl::ZoomFitToWindow()
|
|
{
|
|
if (!m_pActivePage)
|
|
return;
|
|
|
|
ZoomToRect(m_pActivePage->m_rcWorkRect);
|
|
}
|
|
|
|
void CXTPFlowGraphControl::AnimatePageTransition(CXTPFlowGraphNode* pNodeFrom, CXTPFlowGraphNode* pNodeTo)
|
|
{
|
|
CXTPFlowGraphPage* pPageFrom = pNodeFrom->GetPage();
|
|
ASSERT (pPageFrom == m_pActivePage);
|
|
|
|
CXTPFlowGraphPage* pPageTo = pNodeTo->GetPage();
|
|
|
|
CPoint ptScrollOffsetToDest;
|
|
double dZoomLevelToDest;
|
|
|
|
|
|
if (pPageTo->m_rcWorkRect.IsRectEmpty())
|
|
{
|
|
CClientDC dcClient(this);
|
|
CXTPFlowGraphDrawContext* pDC = CreateDrawContext(dcClient);
|
|
|
|
CRect rc;
|
|
GetClientRect(&rc);
|
|
|
|
pPageTo->Reposition(pDC, rc);
|
|
GetZoomParam(pPageTo->m_rcWorkRect, ptScrollOffsetToDest, dZoomLevelToDest);
|
|
|
|
delete pDC;
|
|
}
|
|
else
|
|
{
|
|
ptScrollOffsetToDest = pPageTo->m_ptScrollOffset;
|
|
dZoomLevelToDest = pPageTo->m_dZoomLevel;
|
|
}
|
|
|
|
CRect rcNodeTo(pNodeTo->GetLocation(), pNodeTo->GetSize());
|
|
|
|
CRect rcNodeFrom(pNodeFrom->GetLocation(), pNodeFrom->GetSize());
|
|
|
|
CPoint ptScrollOffsetFromSrc = pPageFrom->m_ptScrollOffset;
|
|
double dZoomLevelFromSrc = pPageFrom->m_dZoomLevel;
|
|
|
|
CPoint ptScrollOffsetFromDest;
|
|
double dZoomLevelFromDest;
|
|
GetZoomParam(rcNodeFrom, ptScrollOffsetFromDest, dZoomLevelFromDest);
|
|
|
|
CPoint ptScrollOffsetToSrc;
|
|
double dZoomLevelToSrc;
|
|
GetZoomParam(rcNodeTo, ptScrollOffsetToSrc, dZoomLevelToSrc);
|
|
|
|
|
|
SetActivePage(pPageTo);
|
|
|
|
double xFrom = ptScrollOffsetToSrc.x * dZoomLevelToSrc;
|
|
double yFrom = ptScrollOffsetToSrc.y * dZoomLevelToSrc;
|
|
|
|
double xTo = ptScrollOffsetToDest.x * dZoomLevelToDest;
|
|
double yTo = ptScrollOffsetToDest.y * dZoomLevelToDest;
|
|
|
|
const int stepCount = 15;
|
|
int step = 0;
|
|
|
|
UINT_PTR nIDTimer = SetTimer(1001, 5, NULL);
|
|
|
|
CClientDC dcPaint(this);
|
|
CXTPClientRect rc(this);
|
|
|
|
CDC mem;
|
|
mem.CreateCompatibleDC(&dcPaint);
|
|
|
|
const int cx = rc.Width();
|
|
const int cy = rc.Height();
|
|
|
|
BITMAPINFOHEADER BMI;
|
|
// Fill in the header info.
|
|
ZeroMemory (&BMI, sizeof(BMI));
|
|
BMI.biSize = sizeof(BITMAPINFOHEADER);
|
|
BMI.biWidth = rc.Width();
|
|
BMI.biHeight = rc.Height();
|
|
BMI.biPlanes = 1;
|
|
BMI.biBitCount = 32;
|
|
BMI.biCompression = BI_RGB; // No compression
|
|
|
|
BYTE * pSrcBits = NULL;
|
|
|
|
CBitmap bmpFrom;
|
|
bmpFrom.Attach(CreateDIBSection (NULL, (BITMAPINFO *)&BMI, DIB_RGB_COLORS, (void **)&pSrcBits, 0, 0l));
|
|
|
|
|
|
CBitmap bmpTo;
|
|
BYTE * pDestBits = NULL;
|
|
bmpTo.Attach(CreateDIBSection (NULL, (BITMAPINFO *)&BMI, DIB_RGB_COLORS, (void **)&pDestBits, 0, 0l));
|
|
|
|
DWORD dwTimePer = 10;
|
|
|
|
m_bInAction = TRUE;
|
|
|
|
for (;;)
|
|
{
|
|
DWORD dwTime = GetTickCount ();
|
|
|
|
if (step == stepCount - 1)
|
|
{
|
|
m_pActivePage->m_dZoomLevel = dZoomLevelToDest;
|
|
m_pActivePage->m_ptScrollOffset = ptScrollOffsetToDest;
|
|
}
|
|
else
|
|
{
|
|
m_pActivePage->m_dZoomLevel = dZoomLevelToSrc + (dZoomLevelToDest - dZoomLevelToSrc) * (step + 1) / stepCount;
|
|
|
|
m_pActivePage->m_ptScrollOffset =
|
|
CPoint(int((xFrom + (xTo - xFrom) * (step + 1) / stepCount) / m_pActivePage->m_dZoomLevel),
|
|
int((yFrom + (yTo - yFrom) * (step + 1) / stepCount) / m_pActivePage->m_dZoomLevel));
|
|
}
|
|
|
|
|
|
double dZoomLevelFrom = dZoomLevelFromSrc + (dZoomLevelFromDest - dZoomLevelFromSrc) * (step + 1) / stepCount;
|
|
CPoint ptScroolOffsetFrom =
|
|
CPoint(int((ptScrollOffsetFromSrc.x * dZoomLevelFromSrc + (ptScrollOffsetFromDest.x * dZoomLevelFromDest - ptScrollOffsetFromSrc.x * dZoomLevelFromSrc) * (step + 1) / stepCount) / dZoomLevelFrom),
|
|
int((ptScrollOffsetFromSrc.y * dZoomLevelFromSrc + (ptScrollOffsetFromDest.y * dZoomLevelFromDest - ptScrollOffsetFromSrc.y * dZoomLevelFromSrc) * (step + 1) / stepCount) / dZoomLevelFrom));
|
|
|
|
{
|
|
CBitmap* pOldBitmap = mem.SelectObject(&bmpFrom);
|
|
|
|
{
|
|
CXTPFlowGraphDrawContext* pDC = CreateDrawContext(mem);
|
|
pDC->SetClipRect(rc);
|
|
|
|
m_pPaintManager->DrawControlBackground(pDC, this);
|
|
|
|
pDC->SetWorldTransform(ptScroolOffsetFrom, dZoomLevelFrom);
|
|
|
|
pPageFrom->OnDraw(pDC);
|
|
|
|
pDC->SetWorldTransform(CPoint(0, 0), 1);
|
|
|
|
delete pDC;
|
|
}
|
|
|
|
mem.SelectObject(pOldBitmap);
|
|
|
|
pOldBitmap = mem.SelectObject(&bmpTo);
|
|
|
|
{
|
|
CXTPFlowGraphDrawContext* pDC = CreateDrawContext(mem);
|
|
pDC->SetClipRect(rc);
|
|
|
|
m_pPaintManager->DrawControlBackground(pDC, this);
|
|
|
|
pDC->SetWorldTransform(m_pActivePage->m_ptScrollOffset, m_pActivePage->m_dZoomLevel);
|
|
|
|
m_pActivePage->OnDraw(pDC);
|
|
|
|
pDC->SetWorldTransform(CPoint(0, 0), 1);
|
|
|
|
delete pDC;
|
|
}
|
|
|
|
mem.SelectObject(pOldBitmap);
|
|
|
|
|
|
{
|
|
int byAlpha = 255 * (step + 1) / stepCount;
|
|
|
|
byAlpha = 255 - byAlpha;
|
|
const BYTE byDiff = (BYTE)(255 - byAlpha);
|
|
|
|
PBYTE pDest = pDestBits;
|
|
PBYTE pSrc = pSrcBits;
|
|
|
|
int cnt = cx * cy;
|
|
for (int i = 0; i < cnt; i++)
|
|
{
|
|
pDest[0] = (BYTE)((pDest[0] * byDiff + pSrc[0] * byAlpha) >> 8);
|
|
pDest[1] = (BYTE)((pDest[1] * byDiff + pSrc[1] * byAlpha) >> 8);
|
|
pDest[2] = (BYTE)((pDest[2] * byDiff + pSrc[2] * byAlpha) >> 8);
|
|
|
|
pDest += 4;
|
|
pSrc += 4;
|
|
}
|
|
}
|
|
|
|
pOldBitmap = mem.SelectObject(&bmpTo);
|
|
|
|
dcPaint.BitBlt(0, 0, rc.right, rc.bottom, &mem, 0, 0, SRCCOPY);
|
|
|
|
mem.SelectObject(pOldBitmap);
|
|
}
|
|
step++;
|
|
|
|
if (step == stepCount)
|
|
break;
|
|
|
|
dwTime = GetTickCount () - dwTime;
|
|
if (dwTime < dwTimePer)
|
|
{
|
|
Sleep(dwTimePer - dwTime);
|
|
}
|
|
}
|
|
m_bInAction = FALSE;
|
|
|
|
AdjustScrollBars();
|
|
SendNotifyMessage(XTP_FGN_PAGESCROLLOFFSETCHANGED);
|
|
SendNotifyMessage(XTP_FGN_PAGEZOOMLEVELCHANGED);
|
|
|
|
KillTimer(nIDTimer);
|
|
|
|
RedrawControl();
|
|
|
|
}
|
|
|
|
void CXTPFlowGraphControl::AnimateTo(CPoint ptScrollOffset, double dZoomLevel)
|
|
{
|
|
if (!m_pActivePage)
|
|
return;
|
|
|
|
CPoint ptOldScrollOffset = m_pActivePage->m_ptScrollOffset;
|
|
double dOldZoomLevel = m_pActivePage->m_dZoomLevel;
|
|
|
|
if (ptOldScrollOffset == ptScrollOffset && fabs(dOldZoomLevel - dZoomLevel) < 1e-6)
|
|
return;
|
|
|
|
double xFrom = ptOldScrollOffset.x * dOldZoomLevel;
|
|
double yFrom = ptOldScrollOffset.y * dOldZoomLevel;
|
|
|
|
double xTo = ptScrollOffset.x * dZoomLevel;
|
|
double yTo = ptScrollOffset.y * dZoomLevel;
|
|
|
|
const int stepCount = 15;
|
|
int step = 0;
|
|
|
|
int dwStart = (int)GetTickCount();
|
|
|
|
UINT_PTR nIDTimer = SetTimer(1001, m_nAnimationDelay, NULL);
|
|
|
|
m_bInAction = TRUE;
|
|
|
|
for (;;)
|
|
{
|
|
if ((int)GetTickCount() - dwStart > m_nAnimationDelay)
|
|
{
|
|
dwStart = (int)GetTickCount();
|
|
|
|
if (step == stepCount - 1)
|
|
{
|
|
m_pActivePage->m_dZoomLevel = dZoomLevel;
|
|
m_pActivePage->m_ptScrollOffset = ptScrollOffset;
|
|
}
|
|
else
|
|
{
|
|
m_pActivePage->m_dZoomLevel = dOldZoomLevel + (dZoomLevel - dOldZoomLevel) * (step + 1) / stepCount;
|
|
|
|
m_pActivePage->m_ptScrollOffset =
|
|
CPoint(int((xFrom + (xTo - xFrom) * (step + 1) / stepCount) / m_pActivePage->m_dZoomLevel),
|
|
int((yFrom + (yTo - yFrom) * (step + 1) / stepCount) / m_pActivePage->m_dZoomLevel));
|
|
}
|
|
|
|
RedrawControl();
|
|
AdjustScrollBars();
|
|
UpdateWindow();
|
|
step++;
|
|
|
|
if (step == stepCount)
|
|
break;
|
|
}
|
|
|
|
|
|
MSG msg;
|
|
|
|
while (::PeekMessage(&msg, NULL, WM_PAINT, WM_PAINT, PM_NOREMOVE))
|
|
{
|
|
if (!GetMessage(&msg, NULL, WM_PAINT, WM_PAINT))
|
|
break;
|
|
DispatchMessage(&msg);
|
|
}
|
|
|
|
if (!::GetMessage(&msg, NULL, 0, 0))
|
|
{
|
|
AfxPostQuitMessage((int)msg.wParam);
|
|
break;
|
|
}
|
|
|
|
DispatchMessage (&msg);
|
|
}
|
|
|
|
m_bInAction = FALSE;
|
|
|
|
SendNotifyMessage(XTP_FGN_PAGESCROLLOFFSETCHANGED);
|
|
SendNotifyMessage(XTP_FGN_PAGEZOOMLEVELCHANGED);
|
|
|
|
KillTimer(nIDTimer);
|
|
|
|
RedrawControl();
|
|
|
|
}
|
|
|
|
void CXTPFlowGraphControl::GetZoomParam(LPCRECT lpRect, CPoint& ptScrollOffset, double& dZoomLevel)
|
|
{
|
|
CRect rc(lpRect);
|
|
|
|
CRect rcClient;
|
|
GetClientRect(&rcClient);
|
|
|
|
dZoomLevel = 0;
|
|
ptScrollOffset = rc.TopLeft();
|
|
|
|
if (rc.Height() * rcClient.Width() > rcClient.Height() * rc.Width())
|
|
{
|
|
dZoomLevel = (double)rcClient.Height() / rc.Height();
|
|
|
|
int nWidth = int(rcClient.Width() / dZoomLevel);
|
|
|
|
ptScrollOffset.x -= (nWidth - rc.Width()) / 2;
|
|
}
|
|
else
|
|
{
|
|
dZoomLevel = (double)rcClient.Width() / rc.Width();
|
|
|
|
int nHeight = int(rcClient.Height() / dZoomLevel);
|
|
|
|
ptScrollOffset.y -= (nHeight - rc.Height()) / 2;
|
|
|
|
}
|
|
}
|
|
|
|
void CXTPFlowGraphControl::ZoomToRect(LPCRECT lpRect, BOOL bAnimate)
|
|
{
|
|
if (!m_pActivePage || !GetSafeHwnd())
|
|
return;
|
|
|
|
CPoint ptScrollOffset;
|
|
double dZoomLevel;
|
|
|
|
GetZoomParam(lpRect, ptScrollOffset, dZoomLevel);
|
|
|
|
if (bAnimate)
|
|
{
|
|
AnimateTo(ptScrollOffset, dZoomLevel);
|
|
}
|
|
else
|
|
{
|
|
m_pActivePage->m_dZoomLevel = dZoomLevel;
|
|
m_pActivePage->m_ptScrollOffset = ptScrollOffset;
|
|
|
|
SendNotifyMessage(XTP_FGN_PAGESCROLLOFFSETCHANGED);
|
|
SendNotifyMessage(XTP_FGN_PAGEZOOMLEVELCHANGED);
|
|
|
|
OnGraphChanged();
|
|
Reposition();
|
|
AdjustScrollBars();
|
|
}
|
|
}
|
|
|
|
void CXTPFlowGraphControl::SelectAll()
|
|
{
|
|
if (!m_pActivePage)
|
|
return;
|
|
m_pActivePage->GetSelection()->Clear();
|
|
|
|
int i;
|
|
|
|
for (i = 0; i < m_pActivePage->GetNodes()->GetCount(); i++)
|
|
m_pActivePage->GetSelection()->AddSelection(m_pActivePage->GetNodes()->GetAt(i));
|
|
|
|
for (i = 0; i < m_pActivePage->GetConnections()->GetCount(); i++)
|
|
m_pActivePage->GetSelection()->AddSelection(m_pActivePage->GetConnections()->GetAt(i));
|
|
|
|
RedrawControl();
|
|
}
|
|
|
|
void CXTPFlowGraphControl::Arrange()
|
|
{
|
|
if (!m_pActivePage)
|
|
return;
|
|
|
|
m_pActivePage->Arrange();
|
|
}
|
|
|
|
INT_PTR CXTPFlowGraphControl::OnToolHitTest(CPoint point, TOOLINFO* pTI) const
|
|
{
|
|
ASSERT_VALID(this);
|
|
ASSERT(::IsWindow(m_hWnd));
|
|
|
|
// check child windows first by calling CControlBar
|
|
INT_PTR nHit = CWnd::OnToolHitTest(point, pTI);
|
|
if (nHit != -1)
|
|
return nHit;
|
|
|
|
CXTPFlowGraphNode* pNode = HitTestNode(point);
|
|
|
|
if (pNode)
|
|
{
|
|
CXTPFlowGraphConnectionPoint* pConnectionPoint = pNode->HitTestConnectionPoint(point);
|
|
|
|
if (pConnectionPoint && !pConnectionPoint->GetTooltip().IsEmpty())
|
|
{
|
|
nHit = (INT_PTR)pConnectionPoint;
|
|
|
|
CString strTip = pConnectionPoint->GetTooltip();
|
|
if (strTip.GetLength() == 0)
|
|
return -1;
|
|
|
|
CXTPToolTipContext::FillInToolInfo(pTI, m_hWnd, pNode->GetScreenRect(), nHit, strTip);
|
|
|
|
return nHit;
|
|
}
|
|
else
|
|
{
|
|
nHit = (INT_PTR)pNode;
|
|
|
|
CString strTip = pNode->GetTooltip();
|
|
if (strTip.GetLength() == 0)
|
|
return -1;
|
|
|
|
CXTPToolTipContext::FillInToolInfo(pTI, m_hWnd, pNode->GetScreenRect(), nHit, strTip);
|
|
|
|
return nHit;
|
|
}
|
|
}
|
|
CXTPFlowGraphConnection* pConnection = HitTestConnection(point);
|
|
|
|
if (pConnection)
|
|
{
|
|
nHit = (INT_PTR)pConnection;
|
|
|
|
CString strTip = pConnection->GetTooltip();
|
|
if (strTip.GetLength() == 0)
|
|
return -1;
|
|
|
|
CXTPToolTipContext::FillInToolInfo(pTI, m_hWnd,
|
|
CRect(point.x - 3, point.y - 3, point.x + 3, point.y + 3), nHit, strTip);
|
|
|
|
return nHit;
|
|
}
|
|
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
|
|
void CXTPFlowGraphControl::RenameNode(CXTPFlowGraphNode* pNode)
|
|
{
|
|
if (!pNode)
|
|
return;
|
|
|
|
CXTPFlowGraphEditItem* pEditItem = new CXTPFlowGraphEditItem;
|
|
pEditItem->Create(pNode);
|
|
}
|
|
|
|
void CXTPFlowGraphControl::RenameConnectionPoint(CXTPFlowGraphConnectionPoint* pConnectionPoint)
|
|
{
|
|
if (!pConnectionPoint)
|
|
return;
|
|
|
|
CXTPFlowGraphEditItem* pEditItem = new CXTPFlowGraphEditItem;
|
|
pEditItem->Create(pConnectionPoint);
|
|
}
|
|
|
|
void CXTPFlowGraphControl::SetSmoothingMode(XTPFlowGraphSmoothingMode nSmoothingMode)
|
|
{
|
|
m_nSmoothingMode = nSmoothingMode;
|
|
|
|
if (m_pActivePage) m_pActivePage->OnGraphChanged();
|
|
RedrawControl();
|
|
}
|
|
void CXTPFlowGraphControl::OnEndLabelEdit(CXTPFlowGraphElement* pItem, LPCTSTR str)
|
|
{
|
|
XTP_NM_FLOWGRAPH_ENDLABELEDIT ele;
|
|
ele.pItem = pItem;
|
|
ele.strNewString = str;
|
|
|
|
if (SendNotifyMessage(XTP_FGN_ENDLABELEDIT, &ele.hdr) == -1)
|
|
return;
|
|
|
|
|
|
pItem->SetCaption(ele.strNewString);
|
|
}
|
|
|
|
|
|
LRESULT CXTPFlowGraphControl::SendNotifyMessage(UINT nMessage, NMHDR* pNMHDR) const
|
|
{
|
|
if (!IsWindow(m_hWnd))
|
|
return 0;
|
|
|
|
NMHDR nmhdr;
|
|
if (pNMHDR == NULL)
|
|
pNMHDR = &nmhdr;
|
|
|
|
pNMHDR->hwndFrom = GetSafeHwnd();
|
|
pNMHDR->idFrom = GetDlgCtrlID();
|
|
pNMHDR->code = nMessage;
|
|
|
|
CWnd *pOwner = GetOwner();
|
|
if (pOwner && IsWindow(pOwner->m_hWnd))
|
|
return pOwner->SendMessage(WM_NOTIFY, pNMHDR->idFrom, (LPARAM)pNMHDR);
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
void CXTPFlowGraphControl::OnRButtonDown(UINT nFlags, CPoint point)
|
|
{
|
|
CWnd::OnRButtonDown(nFlags, point);
|
|
|
|
SetFocus();
|
|
|
|
|
|
}
|
|
|
|
void CXTPFlowGraphControl::OnRButtonUp(UINT nFlags, CPoint point)
|
|
{
|
|
CWnd::OnRButtonUp(nFlags, point);
|
|
|
|
SendNotifyMessage(NM_RCLICK);
|
|
|
|
}
|
|
|
|
|
|
BOOL CXTPFlowGraphControl::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
|
|
{
|
|
if (m_pToolTipContext)
|
|
{
|
|
m_pToolTipContext->FilterToolTipMessage(this, message, wParam, lParam);
|
|
}
|
|
|
|
return CWnd::OnWndMsg(message, wParam, lParam, pResult);
|
|
}
|
|
|
|
void CXTPFlowGraphControl::EnableMarkup(BOOL bEnable)
|
|
{
|
|
XTPMarkupReleaseContext(m_pMarkupContext);
|
|
|
|
if (bEnable)
|
|
{
|
|
m_pMarkupContext = XTPMarkupCreateContext();
|
|
}
|
|
}
|