1280 lines
28 KiB
C++
1280 lines
28 KiB
C++
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
|
|
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
|
|
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
|
|
// PARTICULAR PURPOSE.
|
|
//
|
|
// Copyright (c) Microsoft Corporation. All rights reserved
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include "tedvis.h"
|
|
#include "tededit.h"
|
|
#include "commctrl.h"
|
|
|
|
#include <assert.h>
|
|
#include <math.h>
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
BOOL CVisualRect::IsIn(CVisualRect& rect)
|
|
{
|
|
return !( x() > rect.right()
|
|
|| right() < rect.x()
|
|
|| y() > rect.bottom()
|
|
|| bottom() < rect.y() );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
CVisualCoordinateTransform::CVisualCoordinateTransform()
|
|
: m_xScale(1)
|
|
, m_yScale(1)
|
|
, m_xOffset(0)
|
|
, m_yOffset(0)
|
|
{
|
|
}
|
|
|
|
POINT CVisualCoordinateTransform::VisualToScreen(CVisualPoint & vis)
|
|
{
|
|
POINT pt;
|
|
|
|
pt.x = LONG((vis.x() + m_xOffset) * m_xScale);
|
|
pt.y = LONG((vis.y() + m_yOffset) * m_yScale);
|
|
|
|
return pt;
|
|
}
|
|
|
|
RECT CVisualCoordinateTransform::VisualToScreen(CVisualRect & vis)
|
|
{
|
|
RECT rc;
|
|
|
|
rc.left = LONG((vis.x() + m_xOffset) * m_xScale);
|
|
rc.top = LONG((vis.y() + m_yOffset) * m_yScale);
|
|
rc.right = LONG((vis.right() + m_xOffset) * m_xScale);
|
|
rc.bottom = LONG((vis.bottom() + m_yOffset) * m_yScale);
|
|
|
|
return rc;
|
|
}
|
|
|
|
CVisualPoint CVisualCoordinateTransform::ScreenToVisual(POINT & pt)
|
|
{
|
|
CVisualPoint vis(pt.x / m_xScale - m_xOffset, pt.y / m_yScale - m_yOffset);
|
|
|
|
return vis;
|
|
}
|
|
|
|
void CVisualCoordinateTransform::SetPointOffset(double xOffset, double yOffset)
|
|
{
|
|
m_xOffset = xOffset;
|
|
m_yOffset = yOffset;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
CVisualDrawContext::CVisualDrawContext(CVisualCoordinateTransform * pTransform)
|
|
: m_pTransform(pTransform)
|
|
{
|
|
}
|
|
|
|
CVisualDrawContext::~CVisualDrawContext()
|
|
{
|
|
}
|
|
|
|
BOOL CVisualDrawContext::BeginPaint(HWND hWnd)
|
|
{
|
|
m_hWnd = hWnd;
|
|
m_hdc = ::BeginPaint(hWnd, &m_ps);
|
|
|
|
RECT rect;
|
|
::GetClientRect(m_hWnd, &rect);
|
|
|
|
m_hBgBuffer = ::CreateCompatibleDC(m_hdc);
|
|
if(NULL == m_hBgBuffer)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
HBITMAP hBitmap = ::CreateCompatibleBitmap(m_hdc, rect.right - rect.left, rect.bottom - rect.top);
|
|
if(NULL == hBitmap)
|
|
{
|
|
DeleteObject(m_hBgBuffer);
|
|
return FALSE;
|
|
}
|
|
|
|
m_hOldBitmap = (HBITMAP) SelectObject(m_hBgBuffer, hBitmap);
|
|
if(NULL == m_hOldBitmap)
|
|
{
|
|
DeleteObject(hBitmap);
|
|
DeleteObject(m_hBgBuffer);
|
|
return FALSE;
|
|
}
|
|
|
|
HBRUSH hWhiteBrush = ::CreateSolidBrush(RGB(255,255,255));
|
|
if(NULL == hWhiteBrush)
|
|
{
|
|
SelectObject(m_hBgBuffer, m_hOldBitmap);
|
|
DeleteObject(hBitmap);
|
|
DeleteObject(m_hBgBuffer);
|
|
return FALSE;
|
|
}
|
|
|
|
::FillRect(m_hBgBuffer, &rect, hWhiteBrush);
|
|
DeleteObject(hWhiteBrush);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CVisualDrawContext::EndPaint()
|
|
{
|
|
RECT rect;
|
|
::GetClientRect(m_hWnd, &rect);
|
|
|
|
::BitBlt(m_hdc, rect.left, rect.top, rect.right - rect.left, rect.bottom - rect.top, m_hBgBuffer, 0, 0, SRCCOPY);
|
|
::EndPaint(m_hWnd, &m_ps);
|
|
|
|
HBITMAP hBitmap = (HBITMAP) SelectObject(m_hBgBuffer, m_hOldBitmap);
|
|
DeleteObject(hBitmap);
|
|
DeleteDC(m_hBgBuffer);
|
|
|
|
}
|
|
|
|
void CVisualDrawContext::PushState()
|
|
{
|
|
m_StateStack.AddHead(m_State);
|
|
|
|
// cleanup brush. hdc should have selected brush.
|
|
// when we pop state and m_hOldBrush is not NULL - select old brush
|
|
m_State.m_hNewBrush = NULL;
|
|
m_State.m_hOldBrush = NULL;
|
|
m_State.m_hNewPen = NULL;
|
|
m_State.m_hOldPen = NULL;
|
|
}
|
|
|
|
void CVisualDrawContext::PopState()
|
|
{
|
|
if(m_State.m_hOldBrush)
|
|
{
|
|
SelectObject(m_hBgBuffer, m_State.m_hOldBrush);
|
|
}
|
|
|
|
if(m_State.m_hNewBrush)
|
|
{
|
|
DeleteObject(m_State.m_hNewBrush);
|
|
}
|
|
|
|
if(m_State.m_hOldPen)
|
|
{
|
|
SelectObject(m_hBgBuffer, m_State.m_hOldPen);
|
|
}
|
|
|
|
if(m_State.m_hNewPen)
|
|
{
|
|
DeleteObject(m_State.m_hNewPen);
|
|
}
|
|
|
|
m_State = m_StateStack.RemoveHead();
|
|
}
|
|
|
|
BOOL CVisualDrawContext::SelectSmallFont()
|
|
{
|
|
CAtlString strFontSize = LoadAtlString(IDS_FONT_SIZE_12);
|
|
CAtlString strFontFace = LoadAtlString(IDS_FONT_FACE_ARIAL);
|
|
|
|
LOGFONT lfLabelFont;
|
|
lfLabelFont.lfHeight = _wtol(strFontSize);
|
|
lfLabelFont.lfWidth = 0;
|
|
lfLabelFont.lfEscapement = 0;
|
|
lfLabelFont.lfOrientation = 0;
|
|
lfLabelFont.lfWeight = FW_DONTCARE;
|
|
lfLabelFont.lfItalic = FALSE;
|
|
lfLabelFont.lfUnderline = FALSE;
|
|
lfLabelFont.lfStrikeOut = FALSE;
|
|
lfLabelFont.lfCharSet = DEFAULT_CHARSET;
|
|
lfLabelFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
|
|
lfLabelFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
|
|
lfLabelFont.lfQuality = DEFAULT_QUALITY;
|
|
lfLabelFont.lfPitchAndFamily = FF_DONTCARE | DEFAULT_PITCH;
|
|
wcscpy_s(lfLabelFont.lfFaceName, 32, strFontFace);
|
|
|
|
HFONT hSmallFont = CreateFontIndirect(&lfLabelFont);
|
|
if(NULL == hSmallFont)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
m_State.m_hOldFont = SelectObject(m_hBgBuffer, hSmallFont);
|
|
if(NULL == m_State.m_hOldFont)
|
|
{
|
|
DeleteObject(hSmallFont);
|
|
return FALSE;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void CVisualDrawContext::DeselectSmallFont()
|
|
{
|
|
HGDIOBJ hFont = SelectObject(m_hBgBuffer, m_State.m_hOldFont);
|
|
DeleteObject(hFont);
|
|
}
|
|
|
|
BOOL CVisualDrawContext::SelectPen(COLORREF color, int width)
|
|
{
|
|
HPEN hOldPen;
|
|
|
|
HPEN hNewPen = CreatePen(PS_SOLID, width, color);
|
|
if(NULL == hNewPen)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hOldPen = (HPEN)SelectObject(m_hBgBuffer, hNewPen);
|
|
if(NULL == hOldPen)
|
|
{
|
|
DeleteObject(hNewPen);
|
|
return FALSE;
|
|
}
|
|
|
|
// if we already have old - keep previous
|
|
if(!m_State.m_hOldPen)
|
|
{
|
|
m_State.m_hOldPen = hOldPen;
|
|
}
|
|
|
|
if(m_State.m_hNewPen)
|
|
{
|
|
DeleteObject(m_State.m_hNewPen);
|
|
}
|
|
|
|
m_State.m_hNewPen = hNewPen;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CVisualDrawContext::SelectSolidBrush(COLORREF color)
|
|
{
|
|
HBRUSH hOldBrush;
|
|
|
|
HBRUSH hNewBrush = CreateSolidBrush(color);
|
|
if(NULL == hNewBrush)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
hOldBrush = (HBRUSH)SelectObject(m_hBgBuffer, hNewBrush);
|
|
if(NULL == hOldBrush)
|
|
{
|
|
DeleteObject(hNewBrush);
|
|
return FALSE;
|
|
}
|
|
|
|
// if we already have old - keep previous
|
|
if(!m_State.m_hOldBrush)
|
|
{
|
|
m_State.m_hOldBrush = hOldBrush;
|
|
}
|
|
|
|
if(m_State.m_hNewBrush)
|
|
{
|
|
DeleteObject(m_State.m_hNewBrush);
|
|
}
|
|
|
|
m_State.m_hNewBrush = hNewBrush;
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CVisualDrawContext::MapPoint(CVisualPoint & vis, POINT & disp)
|
|
{
|
|
CVisualPoint v(vis);
|
|
|
|
v.Add(m_State.m_xCoord, m_State.m_yCoord);
|
|
disp = m_pTransform->VisualToScreen(v);
|
|
}
|
|
|
|
void CVisualDrawContext::MapRect(CVisualRect & vis, RECT & disp)
|
|
{
|
|
CVisualRect v(vis);
|
|
|
|
v.Add(m_State.m_xCoord, m_State.m_yCoord);
|
|
disp = m_pTransform->VisualToScreen(v);
|
|
|
|
}
|
|
|
|
void CVisualDrawContext::ShiftCoordinates(double xOffset, double yOffset)
|
|
{
|
|
m_State.m_xCoord += xOffset;
|
|
m_State.m_yCoord += yOffset;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
void CVisualObject::Select(bool bIsSelected)
|
|
{
|
|
m_bIsSelected = bIsSelected;
|
|
}
|
|
|
|
bool CVisualObject::ContainsVisual(CVisualObject* pVisual)
|
|
{
|
|
if(this == pVisual)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
// draw connector
|
|
void CVisualConnector::Draw(CVisualDrawContext & Ctx)
|
|
{
|
|
// set color
|
|
if(IsSelected())
|
|
{
|
|
Ctx.SelectPen(m_clrSelected, 2);
|
|
}
|
|
else
|
|
{
|
|
Ctx.SelectPen(m_clrLine, 1);
|
|
}
|
|
|
|
POINT left, right;
|
|
Ctx.MapPoint(m_Left, left);
|
|
Ctx.MapPoint(m_Right, right);
|
|
|
|
MoveToEx(Ctx.DC(), left.x, left.y, NULL);
|
|
LineTo(Ctx.DC(), right.x, right.y);
|
|
}
|
|
|
|
CVisualObject::CONNECTION_TYPE CVisualConnector::GetConnectionType() const
|
|
{
|
|
return CVisualObject::NONE;
|
|
}
|
|
|
|
void CVisualConnector::NotifyRemoved(CVisualObject* removed)
|
|
{
|
|
|
|
}
|
|
|
|
bool CVisualConnector::IsDependent(CVisualObject* pOtherObj) const
|
|
{
|
|
return false;
|
|
}
|
|
|
|
BOOL CVisualConnector::HitTest(CVisualPoint & pt, CVisualObject ** ppObj)
|
|
{
|
|
double alpha = m_Right.x() - m_Left.x();
|
|
double beta = m_Right.y() - m_Left.y();
|
|
|
|
double t1 = (pt.x() - m_Left.x()) / alpha;
|
|
double t2 = (pt.y() - m_Left.y()) / beta;
|
|
|
|
if(fabs(t1 - t2) < .1 && t1 >= 0 && t1 <= 1)
|
|
{
|
|
*ppObj = this;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
const int CVisualPin::LABEL_OFFSET_X = 30;
|
|
const int CVisualPin::LABEL_OFFSET_Y = 2;
|
|
|
|
CVisualPin::CVisualPin(CVisualComponent * pOwner, CVisualRect & Rect, CVisualObject::CONNECTION_TYPE connType, const CAtlStringW& strLabel, int nPinId)
|
|
: CVisualObject(Rect)
|
|
, m_ConnType(connType)
|
|
, m_pOwner(pOwner)
|
|
, m_pConnector(NULL)
|
|
, m_strLabel(strLabel)
|
|
, m_nPinId(nPinId)
|
|
, m_fHighlight(false)
|
|
{
|
|
m_Type = PIN;
|
|
}
|
|
|
|
CVisualPoint CVisualPin::GetConnectorPoint()
|
|
{
|
|
CVisualPoint pt(m_pOwner->Rect().x(), m_pOwner->Rect().y());
|
|
|
|
if(m_ConnType == INPUT)
|
|
{
|
|
pt.Add(Rect().x(), Rect().y() + Rect().h() / 2);
|
|
}
|
|
else
|
|
{
|
|
pt.Add(Rect().right(), Rect().y() + Rect().h() / 2);
|
|
}
|
|
|
|
return pt;
|
|
}
|
|
|
|
void CVisualPin::Draw(CVisualDrawContext & Ctx)
|
|
{
|
|
RECT rect;
|
|
|
|
if(m_fHighlight)
|
|
{
|
|
Ctx.SelectPen(RGB(0, 0, 200), 2);
|
|
}
|
|
else
|
|
{
|
|
Ctx.SelectPen(RGB(0, 0, 0), 1);
|
|
}
|
|
Ctx.SelectSolidBrush(RGB(0, 0, 0));
|
|
|
|
// draw rect
|
|
Ctx.MapRect(m_Rect, rect);
|
|
Rectangle(Ctx.DC(), rect.left, rect.top, rect.right, rect.bottom);
|
|
|
|
rect.left -= LABEL_OFFSET_X;
|
|
rect.top -= LABEL_OFFSET_Y;
|
|
rect.bottom += LABEL_OFFSET_Y;
|
|
|
|
DrawText(Ctx.DC(), m_strLabel, -1, &rect, 0);
|
|
}
|
|
|
|
CVisualObject::CONNECTION_TYPE CVisualPin::GetConnectionType() const
|
|
{
|
|
return m_ConnType;
|
|
}
|
|
|
|
int CVisualPin::GetPinId() const
|
|
{
|
|
return m_nPinId;
|
|
}
|
|
|
|
void CVisualPin::NotifyRemoved(CVisualObject* removed)
|
|
{
|
|
if(removed == m_pConnector)
|
|
{
|
|
m_pConnector = NULL;
|
|
}
|
|
}
|
|
|
|
void CVisualPin::Select(bool selected)
|
|
{
|
|
CVisualObject::Select(selected);
|
|
|
|
if(m_pConnector)
|
|
{
|
|
m_pConnector->Select(selected);
|
|
}
|
|
}
|
|
|
|
bool CVisualPin::IsDependent(CVisualObject* pOtherObj) const
|
|
{
|
|
if(pOtherObj == m_pConnector)
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
CVisualComponent::CVisualComponent(CVisualRect& Rect)
|
|
: CVisualObject(Rect)
|
|
{
|
|
}
|
|
|
|
CVisualComponent::~CVisualComponent()
|
|
{
|
|
}
|
|
|
|
CVisualObject::CONNECTION_TYPE CVisualComponent::GetConnectionType() const
|
|
{
|
|
return CVisualObject::NONE;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
CCommandHandler* CVisualNode::ms_pPinHandler = NULL;
|
|
|
|
CVisualNode::CVisualNode(const CAtlStringW& strLabel, bool fAutoInserted)
|
|
: CVisualComponent(CVisualRect(0, 0, COMP_DEF_WIDTH, COMP_DEF_HEIGHT))
|
|
, m_strLabel(strLabel)
|
|
, m_fTopoError(false)
|
|
{
|
|
if(fAutoInserted)
|
|
{
|
|
m_clrFill = RGB(153, 153, 243);
|
|
}
|
|
else
|
|
{
|
|
m_clrFill = RGB(153, 243, 153);
|
|
}
|
|
|
|
m_clrLine = RGB(0, 0, 0);
|
|
m_clrSelectedBorder = RGB(0, 0, 200);
|
|
m_clrErrorText = RGB(200, 0, 0);
|
|
|
|
m_Type = CVisualObject::NODE;
|
|
}
|
|
|
|
CVisualNode::~CVisualNode()
|
|
{
|
|
for(size_t i = 0; i < m_InputPins.GetCount(); i++)
|
|
{
|
|
delete m_InputPins.GetAt(i);
|
|
}
|
|
|
|
for(size_t i = 0; i < m_OutputPins.GetCount(); i++)
|
|
{
|
|
delete m_OutputPins.GetAt(i);
|
|
}
|
|
}
|
|
|
|
void CVisualNode::Draw(CVisualDrawContext & Ctx)
|
|
{
|
|
RECT rect;
|
|
size_t n;
|
|
|
|
Ctx.SelectSmallFont();
|
|
|
|
if(IsSelected())
|
|
{
|
|
Ctx.SelectPen(m_clrSelectedBorder, 2);
|
|
}
|
|
else
|
|
{
|
|
Ctx.SelectPen(m_clrLine, 1);
|
|
}
|
|
|
|
// select colors
|
|
Ctx.SelectSolidBrush(m_clrFill);
|
|
|
|
// draw rect
|
|
Ctx.MapRect(m_Rect, rect);
|
|
Rectangle(Ctx.DC(), rect.left, rect.top, rect.right, rect.bottom);
|
|
|
|
if(!m_strLabel.IsEmpty())
|
|
{
|
|
COLORREF oldColor = SetTextColor(Ctx.DC(), m_clrLine);
|
|
Ctx.SelectSolidBrush(RGB(0, 0, 0));
|
|
SetBkColor(Ctx.DC(), m_clrFill);
|
|
|
|
rect.left += 5;
|
|
rect.right -= 5;
|
|
rect.top +=5;
|
|
|
|
DrawText(Ctx.DC(), m_strLabel, m_strLabel.GetLength(), &rect, DT_WORDBREAK);
|
|
|
|
SetTextColor(Ctx.DC(), oldColor);
|
|
}
|
|
|
|
if(m_fTopoError)
|
|
{
|
|
COLORREF oldColor = SetTextColor(Ctx.DC(), m_clrErrorText);
|
|
rect.top += 10;
|
|
|
|
CAtlStringW errString = LoadAtlString(IDS_E_TOPO_RESOLUTION);
|
|
DrawText(Ctx.DC(), errString, errString.GetLength(), &rect, DT_WORDBREAK);
|
|
|
|
SetTextColor(Ctx.DC(), oldColor);
|
|
}
|
|
|
|
Ctx.PushState();
|
|
|
|
Ctx.ShiftCoordinates(m_Rect.x(), m_Rect.y());
|
|
|
|
// draw pins
|
|
for(n = 0; n < m_InputPins.GetCount(); n++)
|
|
{
|
|
m_InputPins.GetAt(n)->Draw(Ctx);
|
|
}
|
|
|
|
for(n = 0; n < m_OutputPins.GetCount(); n++)
|
|
{
|
|
m_OutputPins.GetAt(n)->Draw(Ctx);
|
|
}
|
|
|
|
Ctx.PopState();
|
|
|
|
Ctx.DeselectSmallFont();
|
|
}
|
|
|
|
bool CVisualNode::IsDependent(CVisualObject* pOtherObj) const
|
|
{
|
|
for(size_t i = 0; i < m_InputPins.GetCount(); i++)
|
|
{
|
|
if(m_InputPins.GetAt(i)->IsDependent(pOtherObj)) return true;
|
|
}
|
|
|
|
for(size_t i = 0; i < m_OutputPins.GetCount(); i++)
|
|
{
|
|
if(m_OutputPins.GetAt(i)->IsDependent(pOtherObj)) return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void CVisualNode::NotifyRemoved(CVisualObject* removed)
|
|
{
|
|
for(size_t i = 0; i < m_InputPins.GetCount(); i++)
|
|
{
|
|
m_InputPins.GetAt(i)->NotifyRemoved(removed);
|
|
}
|
|
|
|
for(size_t i = 0; i < m_OutputPins.GetCount(); i++)
|
|
{
|
|
m_OutputPins.GetAt(i)->NotifyRemoved(removed);
|
|
}
|
|
}
|
|
|
|
BOOL CVisualNode::HitTest(CVisualPoint & pt, CVisualObject ** ppObj)
|
|
{
|
|
size_t n;
|
|
CVisualPoint ptLocal(pt);
|
|
|
|
ptLocal.Sub(m_Rect.x(), m_Rect.y());
|
|
|
|
// first check if we hit any pin
|
|
for(n = 0; n < m_InputPins.GetCount(); n++)
|
|
{
|
|
if(m_InputPins.GetAt(n)->Rect().IsIn(ptLocal))
|
|
{
|
|
*ppObj = m_InputPins.GetAt(n);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
for(n = 0; n < m_OutputPins.GetCount(); n++)
|
|
{
|
|
if(m_OutputPins.GetAt(n)->Rect().IsIn(ptLocal))
|
|
{
|
|
*ppObj = m_OutputPins.GetAt(n);
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
if(m_Rect.IsIn(pt))
|
|
{
|
|
(*ppObj) = this;
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void CVisualNode::Move(double x, double y)
|
|
{
|
|
size_t n;
|
|
CVisualPin * pPin;
|
|
|
|
CVisualObject::Move(x, y);
|
|
|
|
for(n = 0; n < m_InputPins.GetCount(); n++)
|
|
{
|
|
pPin = m_InputPins.GetAt(n);
|
|
|
|
if(pPin->GetConnector())
|
|
{
|
|
pPin->GetConnector()->Right() = pPin->GetConnectorPoint();
|
|
}
|
|
}
|
|
|
|
for(n = 0; n < m_OutputPins.GetCount(); n++)
|
|
{
|
|
pPin = m_OutputPins.GetAt(n);
|
|
|
|
if(pPin->GetConnector())
|
|
{
|
|
pPin->GetConnector()->Left() = pPin->GetConnectorPoint();
|
|
}
|
|
}
|
|
}
|
|
|
|
int CVisualNode::GetPinIDWithConnector(CVisualConnector* pConnector)
|
|
{
|
|
for(size_t i = 0; i < m_OutputPins.GetCount(); i++)
|
|
{
|
|
CVisualPin* pPin = m_OutputPins.GetAt(i);
|
|
if(pPin->GetConnector() == pConnector)
|
|
{
|
|
return pPin->GetPinId();
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void CVisualNode::SetPinHandler(CCommandHandler* pHandler)
|
|
{
|
|
ms_pPinHandler = pHandler;
|
|
}
|
|
|
|
CVisualPin* CVisualNode::AddPin(bool fInput, LONG_PTR pData, const CAtlStringW& strLabel, int nPinId)
|
|
{
|
|
HRESULT hr;
|
|
CVisualPin* pPin = new CVisualPin(this,
|
|
CVisualRect(0, 0, PIN_WIDTH, PIN_HEIGHT),
|
|
(fInput) ? CVisualObject::INPUT : CVisualObject::OUTPUT, strLabel, nPinId);
|
|
CHECK_ALLOC( pPin );
|
|
|
|
pPin->SetData(pData);
|
|
|
|
if(fInput)
|
|
{
|
|
m_InputPins.Add(pPin);
|
|
}
|
|
else
|
|
{
|
|
m_OutputPins.Add(pPin);
|
|
}
|
|
|
|
pPin->SetHandler(ms_pPinHandler);
|
|
|
|
RecalcPins();
|
|
|
|
Cleanup:
|
|
return pPin;
|
|
}
|
|
|
|
CVisualPin* CVisualNode::GetInputPinByIndex(size_t nIndex)
|
|
{
|
|
return m_InputPins.GetAt(nIndex);
|
|
}
|
|
|
|
CVisualPin* CVisualNode::GetOutputPinByIndex(size_t nIndex)
|
|
{
|
|
return m_OutputPins.GetAt(nIndex);
|
|
}
|
|
|
|
|
|
CVisualPin* CVisualNode::GetInputPin(int nPinID)
|
|
{
|
|
for(size_t i = 0; i < m_InputPins.GetCount(); i++)
|
|
{
|
|
if(m_InputPins.GetAt(i)->GetPinId() == nPinID) return m_InputPins.GetAt(i);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CVisualPin* CVisualNode::GetOutputPin(int nPinID)
|
|
{
|
|
for(size_t i = 0; i < m_OutputPins.GetCount(); i++)
|
|
{
|
|
if(m_OutputPins.GetAt(i)->GetPinId() == nPinID) return m_OutputPins.GetAt(i);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void CVisualNode::FlagTopoLoadError(size_t nIndex, bool fError)
|
|
{
|
|
assert(nIndex == 0);
|
|
|
|
m_fTopoError = fError;
|
|
}
|
|
|
|
void CVisualNode::RecalcPins()
|
|
{
|
|
size_t nInputs = 0;
|
|
size_t nOutputs = 0;
|
|
|
|
// calculate number of inputs and outputs
|
|
nInputs = m_InputPins.GetCount();
|
|
nOutputs = m_OutputPins.GetCount();
|
|
|
|
// position pins
|
|
PositionPins(nInputs, CVisualPin::INPUT);
|
|
PositionPins(nOutputs, CVisualPin::OUTPUT);
|
|
}
|
|
|
|
void CVisualNode::PositionPins(size_t nPins, CVisualObject::CONNECTION_TYPE Dir)
|
|
{
|
|
size_t n;
|
|
|
|
if(nPins == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// TODO: resize if necessary
|
|
|
|
double yCur;
|
|
double x;
|
|
|
|
yCur = (m_Rect.h() - (nPins * PIN_HEIGHT) - ((nPins - 1) * PIN_INTERVAL)) / 2;
|
|
x = (Dir == CVisualObject::INPUT) ? -PIN_WIDTH : m_Rect.w();
|
|
|
|
// calculate number of inputs and outputs
|
|
for(n = 0; n < m_InputPins.GetCount(); n++)
|
|
{
|
|
if(m_InputPins.GetAt(n)->GetConnectionType() == Dir)
|
|
{
|
|
m_InputPins.GetAt(n)->Rect() = CVisualRect(x, yCur, PIN_WIDTH, PIN_HEIGHT);
|
|
yCur += PIN_HEIGHT + PIN_INTERVAL;
|
|
}
|
|
}
|
|
|
|
for(n = 0; n < m_OutputPins.GetCount(); n++)
|
|
{
|
|
if(m_OutputPins.GetAt(n)->GetConnectionType() == Dir)
|
|
{
|
|
m_OutputPins.GetAt(n)->Rect() = CVisualRect(x, yCur, PIN_WIDTH, PIN_HEIGHT);
|
|
yCur += PIN_HEIGHT + PIN_INTERVAL;
|
|
}
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
CVisualContainer::CVisualContainer(const CAtlStringW& label)
|
|
: CVisualComponent(CVisualRect(0, 0, COMP_DEF_WIDTH, BOTTOM_MARGIN))
|
|
, m_strLabel(label)
|
|
, m_clrFill(RGB(192, 192, 192))
|
|
{
|
|
m_Type = CVisualObject::CONTAINER;
|
|
}
|
|
|
|
CVisualContainer::~CVisualContainer()
|
|
{
|
|
for(size_t i = 0; i < m_arrComponents.GetCount(); i++)
|
|
{
|
|
delete m_arrComponents.GetAt(i);
|
|
}
|
|
}
|
|
|
|
void CVisualContainer::Draw(CVisualDrawContext& Ctx)
|
|
{
|
|
RECT rect;
|
|
|
|
Ctx.SelectSmallFont();
|
|
|
|
// select colors
|
|
Ctx.SelectSolidBrush(m_clrFill);
|
|
|
|
// draw rect
|
|
Ctx.MapRect(m_Rect, rect);
|
|
Rectangle(Ctx.DC(), rect.left, rect.top, rect.right, rect.bottom);
|
|
|
|
if(!m_strLabel.IsEmpty())
|
|
{
|
|
Ctx.SelectSolidBrush(RGB(0, 0, 0));
|
|
SetBkColor(Ctx.DC(), m_clrFill);
|
|
|
|
rect.left += 5;
|
|
rect.right -= 5;
|
|
rect.top +=5;
|
|
|
|
DrawText(Ctx.DC(), m_strLabel, m_strLabel.GetLength(), &rect, DT_WORDBREAK);
|
|
}
|
|
|
|
Ctx.DeselectSmallFont();
|
|
|
|
for(size_t i = 0; i < m_arrComponents.GetCount(); i++)
|
|
{
|
|
Ctx.PushState();
|
|
m_arrComponents.GetAt(i)->Draw(Ctx);
|
|
Ctx.PopState();
|
|
}
|
|
}
|
|
|
|
BOOL CVisualContainer::HitTest(CVisualPoint& pt, CVisualObject** ppObj)
|
|
{
|
|
for(size_t i = 0; i < m_arrComponents.GetCount(); i++)
|
|
{
|
|
if(m_arrComponents.GetAt(i)->HitTest(pt, ppObj))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void CVisualContainer::Move(double x, double y)
|
|
{
|
|
CVisualObject::Move(x, y);
|
|
|
|
RecalcPositions();
|
|
}
|
|
|
|
void CVisualContainer::AddPosition(double x, double y)
|
|
{
|
|
CVisualObject::AddPosition(x, y);
|
|
|
|
RecalcPositions();
|
|
}
|
|
|
|
void CVisualContainer::NotifyRemoved(CVisualObject* removed)
|
|
{
|
|
for(size_t i = 0; i < m_arrComponents.GetCount(); i++)
|
|
{
|
|
m_arrComponents.GetAt(i)->NotifyRemoved(removed);
|
|
}
|
|
}
|
|
|
|
bool CVisualContainer::IsDependent(CVisualObject* pOtherObj) const
|
|
{
|
|
for(size_t i = 0; i < m_arrComponents.GetCount(); i++)
|
|
{
|
|
if(m_arrComponents.GetAt(i) == pOtherObj) return true;
|
|
if(m_arrComponents.GetAt(i)->IsDependent(pOtherObj)) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void CVisualContainer::AddComponent(CVisualComponent* pComponent)
|
|
{
|
|
pComponent->SetContainer(this);
|
|
|
|
m_arrComponents.Add(pComponent);
|
|
|
|
m_Rect.Expand(0, pComponent->Rect().h() + TOP_MARGIN);
|
|
|
|
RecalcPositions();
|
|
}
|
|
|
|
DWORD CVisualContainer::GetComponentCount()
|
|
{
|
|
return (DWORD) m_arrComponents.GetCount();
|
|
}
|
|
|
|
CVisualComponent* CVisualContainer::GetComponent(DWORD dwIndex)
|
|
{
|
|
return m_arrComponents.GetAt(dwIndex);
|
|
}
|
|
|
|
void CVisualContainer::SetParent(CVisualContainer* pParent)
|
|
{
|
|
m_pParent = pParent;
|
|
}
|
|
|
|
void CVisualContainer::SetHandler(CCommandHandler* pHandler)
|
|
{
|
|
CVisualObject::SetHandler(pHandler);
|
|
|
|
for(size_t i = 0; i < m_arrComponents.GetCount(); i++)
|
|
{
|
|
m_arrComponents.GetAt(i)->SetHandler(pHandler);
|
|
}
|
|
}
|
|
|
|
void CVisualContainer::RecalcPositions()
|
|
{
|
|
double dblHeightSoFar = 0;
|
|
for(size_t i = 0; i < m_arrComponents.GetCount(); i++)
|
|
{
|
|
m_arrComponents.GetAt(i)->Move(m_Rect.x(), m_Rect.y() + (TOP_MARGIN * (i + 1)) + (dblHeightSoFar * i));
|
|
dblHeightSoFar = m_arrComponents.GetAt(i)->Rect().h();
|
|
}
|
|
}
|
|
|
|
CVisualPin* CVisualContainer::GetInputPinByIndex(size_t nIndex)
|
|
{
|
|
size_t cPinsSoFar = 0;
|
|
|
|
for(size_t i = 0; i < m_arrComponents.GetCount(); i++)
|
|
{
|
|
size_t cPins = m_arrComponents.GetAt(i)->GetInputPinCount();
|
|
|
|
if(nIndex < cPinsSoFar + cPins)
|
|
{
|
|
return m_arrComponents.GetAt(i)->GetInputPinByIndex(nIndex - cPinsSoFar);
|
|
}
|
|
|
|
cPinsSoFar += cPins;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CVisualPin* CVisualContainer::GetOutputPinByIndex(size_t nIndex)
|
|
{
|
|
size_t cPinsSoFar = 0;
|
|
|
|
for(size_t i = 0; i < m_arrComponents.GetCount(); i++)
|
|
{
|
|
size_t cPins = m_arrComponents.GetAt(i)->GetOutputPinCount();
|
|
|
|
if(nIndex < cPinsSoFar + cPins)
|
|
{
|
|
return m_arrComponents.GetAt(i)->GetOutputPinByIndex(nIndex - cPinsSoFar);
|
|
}
|
|
|
|
cPinsSoFar += cPins;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
size_t CVisualContainer::GetInputPinCount()
|
|
{
|
|
size_t cTotal = 0;
|
|
|
|
for(size_t i = 0; i < m_arrComponents.GetCount(); i++)
|
|
{
|
|
cTotal += m_arrComponents.GetAt(i)->GetInputPinCount();
|
|
}
|
|
|
|
return cTotal;
|
|
}
|
|
|
|
size_t CVisualContainer::GetOutputPinCount()
|
|
{
|
|
size_t cTotal = 0;
|
|
|
|
for(size_t i = 0; i < m_arrComponents.GetCount(); i++)
|
|
{
|
|
cTotal += m_arrComponents.GetAt(i)->GetOutputPinCount();
|
|
}
|
|
|
|
return cTotal;
|
|
}
|
|
|
|
CVisualPin* CVisualContainer::GetInputPin(int nPinID)
|
|
{
|
|
for(size_t i = 0; i < m_arrComponents.GetCount(); i++)
|
|
{
|
|
CVisualPin* pPin = m_arrComponents.GetAt(i)->GetInputPin(nPinID);
|
|
if(pPin)
|
|
{
|
|
return pPin;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CVisualPin* CVisualContainer::GetOutputPin(int nPinID)
|
|
{
|
|
for(size_t i = 0; i < m_arrComponents.GetCount(); i++)
|
|
{
|
|
CVisualPin* pPin = m_arrComponents.GetAt(i)->GetOutputPin(nPinID);
|
|
if(pPin)
|
|
{
|
|
return pPin;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void CVisualContainer::FlagTopoLoadError(size_t nIndex, bool fError)
|
|
{
|
|
assert(nIndex < m_arrComponents.GetCount());
|
|
|
|
m_arrComponents.GetAt(nIndex)->FlagTopoLoadError(0, fError);
|
|
}
|
|
|
|
bool CVisualContainer::ContainsVisual(CVisualObject* pVisual)
|
|
{
|
|
if(CVisualComponent::ContainsVisual(pVisual))
|
|
{
|
|
return true;
|
|
}
|
|
|
|
for(size_t i = 0; i < m_arrComponents.GetCount(); i++)
|
|
{
|
|
if(m_arrComponents.GetAt(i)->ContainsVisual(pVisual))
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
|
|
CVisualTree::CVisualTree()
|
|
: m_pEventHandler(NULL)
|
|
{
|
|
}
|
|
CVisualTree::~CVisualTree()
|
|
{
|
|
for(size_t i = 0; i < m_Objects.GetCount(); i++) {
|
|
delete m_Objects.GetAt(i);
|
|
}
|
|
}
|
|
|
|
HRESULT CVisualTree::AddVisual(CVisualObject * pVisual, bool fEnsureOpenSpace)
|
|
{
|
|
assert(pVisual != NULL);
|
|
|
|
m_Objects.Add(pVisual);
|
|
|
|
if(fEnsureOpenSpace)
|
|
{
|
|
while(IsOccupied(pVisual))
|
|
{
|
|
pVisual->AddPosition(120, 0);
|
|
|
|
if(pVisual->Rect().x() > 600)
|
|
{
|
|
pVisual->Move(20, pVisual->Rect().y() + 120);
|
|
}
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
void CVisualTree::RemoveVisual(CVisualObject * pVisual)
|
|
{
|
|
size_t n;
|
|
CVisualObject * pIter;
|
|
|
|
for(n = 0; n < m_Objects.GetCount(); n++)
|
|
{
|
|
pIter = m_Objects.GetAt(n);
|
|
|
|
if(pVisual->IsDependent(pIter))
|
|
{
|
|
RemoveVisual(pIter);
|
|
n--;
|
|
}
|
|
else if(pIter == pVisual)
|
|
{
|
|
m_Objects.RemoveAt(n);
|
|
n--;
|
|
}
|
|
else
|
|
{
|
|
pIter->NotifyRemoved(pVisual);
|
|
}
|
|
}
|
|
|
|
if(m_pEventHandler)
|
|
{
|
|
m_pEventHandler->NotifyObjectDeleted(pVisual);
|
|
}
|
|
|
|
delete pVisual;
|
|
}
|
|
|
|
void CVisualTree::Draw(CVisualDrawContext & Ctx)
|
|
{
|
|
size_t n;
|
|
CVisualObject * pObject;
|
|
|
|
if(m_Objects.IsEmpty()) return;
|
|
|
|
for(n = m_Objects.GetCount() - 1; n > 0; n--)
|
|
{
|
|
Ctx.PushState();
|
|
pObject = m_Objects.GetAt(n);
|
|
pObject->Draw(Ctx);
|
|
Ctx.PopState();
|
|
}
|
|
|
|
Ctx.PushState();
|
|
m_Objects.GetAt(0)->Draw(Ctx);
|
|
Ctx.PopState();
|
|
}
|
|
|
|
BOOL CVisualTree::HitTest(CVisualPoint & pt, CVisualObject ** ppObj)
|
|
{
|
|
size_t n;
|
|
CVisualObject * pObject;
|
|
|
|
for(n = 0; n < m_Objects.GetCount(); n++)
|
|
{
|
|
pObject = m_Objects.GetAt(n);
|
|
if(pObject->HitTest(pt, ppObj))
|
|
{
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
void CVisualTree::RouteAllConnectors()
|
|
{
|
|
size_t n;
|
|
CVisualObject * pObject;
|
|
|
|
for(n = 0; n < m_Objects.GetCount(); n++)
|
|
{
|
|
pObject = m_Objects.GetAt(n);
|
|
if(pObject->Type() == CVisualObject::NODE)
|
|
{
|
|
CVisualNode* pNode = (CVisualNode*) pObject;
|
|
for(size_t i = 0; i < pNode->GetOutputPinCount(); i++)
|
|
{
|
|
CVisualPin* pPin = pNode->GetOutputPinByIndex((DWORD) i);
|
|
if(pPin->GetConnector())
|
|
{
|
|
pPin->GetConnector()->Left() = pPin->GetConnectorPoint();
|
|
}
|
|
}
|
|
|
|
for(size_t i = 0; i < pNode->GetInputPinCount(); i++)
|
|
{
|
|
CVisualPin* pPin = pNode->GetInputPinByIndex((DWORD) i);
|
|
if(pPin->GetConnector())
|
|
{
|
|
pPin->GetConnector()->Right() = pPin->GetConnectorPoint();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
BOOL CVisualTree::MakeConnector(CVisualPin* pSourcePin, CVisualPin* pSinkPin)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
|
|
CVisualConnector* pVisualConnector = new CVisualConnector;
|
|
CHECK_ALLOC( pVisualConnector );
|
|
|
|
AddVisual(pVisualConnector);
|
|
|
|
pVisualConnector->Left() = pSourcePin->GetConnectorPoint();
|
|
pVisualConnector->Right() = pSinkPin->GetConnectorPoint();
|
|
pSourcePin->SetConnector(pVisualConnector);
|
|
pSinkPin->SetConnector(pVisualConnector);
|
|
|
|
Cleanup:
|
|
if(FAILED(hr))
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CVisualTree::GetMaxExtent(UINT32& maxXExtent, UINT32& maxYExtent)
|
|
{
|
|
for(size_t n = 0; n < m_Objects.GetCount(); n++)
|
|
{
|
|
CVisualObject* pObj = m_Objects.GetAt(n);
|
|
|
|
UINT32 objXExtent = UINT32(pObj->Rect().x() + pObj->Rect().w() + 10);
|
|
UINT32 objYExtent = UINT32(pObj->Rect().y() + pObj->Rect().h() + 10);
|
|
|
|
if(objXExtent > maxXExtent) maxXExtent = objXExtent;
|
|
if(objYExtent > maxYExtent) maxYExtent = objYExtent;
|
|
}
|
|
}
|
|
|
|
bool CVisualTree::IsOccupied(CVisualObject* pObj)
|
|
{
|
|
for(size_t n = 0; n < m_Objects.GetCount(); n++)
|
|
{
|
|
CVisualObject* pObj2 = m_Objects.GetAt(n);
|
|
|
|
if( pObj != pObj2 && pObj->Rect().IsIn(pObj2->Rect()) ) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|