📄 textdiagram.cpp
字号:
else if (TestChar(diagram, nX, nY + 1, CHAR_VERT, CHAR_CROSSOVER))
{
nY++;
return CONN_DOWN;
}
// 4. test for change of direction (up)
else if (TestChar(diagram, nX, nY - 1, CHAR_VERT, CHAR_CROSSOVER))
{
nY--;
return CONN_UP;
}
// 5. test for termination (down)
else if (TestChar(diagram, nX, nY + 1, CHAR_END/*, CHAR_ENDDOWN*/))
{
nY++;
return CONN_END;
}
// 6. test for termination (up)
else if (TestChar(diagram, nX, nY - 1, CHAR_END/*, CHAR_ENDUP*/))
{
nY--;
return CONN_END;
}
break;
case CONN_UP:
if (TestChar(diagram, nX, nY - 1, CHAR_HORZ))
{
nY--;
// which way does it go?
if (TestChar(diagram, nX + 1, nY, CHAR_HORZ, CHAR_CROSSOVER, CHAR_END))
return CONN_RIGHT;
else
return CONN_LEFT;
}
else if (TestChar(diagram, nX, nY - 1, CHAR_CROSSOVER))
{
nY--;
return CONN_UP;
}
else if (TestChar(diagram, nX, nY - 1, CHAR_END/*, CHAR_ENDUP*/))
{
nY--;
return CONN_END;
}
else if (TestChar(diagram, nX, nY - 1, CHAR_VERT))
{
nY--;
return CONN_UP;
}
break;
case CONN_DOWN:
if (TestChar(diagram, nX, nY + 1, CHAR_HORZ))
{
nY++;
// which way does it go?
if (TestChar(diagram, nX + 1, nY, CHAR_HORZ, CHAR_CROSSOVER, CHAR_END))
return CONN_RIGHT;
else
return CONN_LEFT;
}
else if (TestChar(diagram, nX, nY + 1, CHAR_CROSSOVER))
{
nY++;
return CONN_DOWN;
}
else if (TestChar(diagram, nX, nY + 1, CHAR_END/*, CHAR_ENDDOWN*/))
{
nY++;
return CONN_END;
}
else if (TestChar(diagram, nX, nY + 1, CHAR_VERT))
{
nY++;
return CONN_DOWN;
}
break;
}
return NONE;
}
void CTextDiagram::AddConn(const CStringArray& diagram, int nX, int nY)
{
TDPOS nPos = ConnStartChar(diagram, nX, nY);
if (nPos == CONN_START)
{
CPoint ptStart(nX, nY);
int nFromRect = IntersectRect(nX, nY);
BOOL bDone = FALSE;
TDPOS nPosOrg = nPos;
int nIteration = 0; // for catching infinite loops
while (nPos != NONE && !bDone && nIteration < MAXITERATIONS)
{
nIteration++;
nPos = ConnGetNextChar(diagram, nPos, nX, nY);
// are we done yet?
bDone = (nPos == CONN_END);
}
if (bDone)
{
int nToRect = IntersectRect(nX, nY);
if (nToRect != -1 && nToRect != nFromRect)
{
CTDRect rect;
GetRect(nFromRect, rect);
int nSideFrom = rect.GetSide(ptStart);
ASSERT (nSideFrom != NONE);
AddConnection(nFromRect, nToRect, nSideFrom);
}
}
}
}
BOOL CTextDiagram::PtInRect(int nX, int nY) const
{
return (IntersectRect(nX, nY) != -1);
}
int CTextDiagram::IntersectRect(int nX, int nY) const
{
if (!m_aRects.GetSize())
return -1;
// else
for (int nRect = 0; nRect < m_aRects.GetSize(); nRect++)
{
CRect rect = m_aRects[nRect];
rect.right++; // inclusive
rect.bottom++; // inclusive
if (rect.PtInRect(CPoint(nX, nY)))
return nRect;
}
return -1;
}
BOOL CTextDiagram::PtInConn(int nX, int nY, BOOL bHorz) const
{
return (IntersectConn(CPoint(nX, nY), bHorz) != -1);
}
int CTextDiagram::IntersectConn(CPoint point, BOOL bHorz) const
{
int nConn = m_aConns.GetSize();
while (nConn--)
{
if (m_aConns[nConn].PtInConn(point, bHorz))
return nConn;
}
return -1; // not found
}
BOOL CTextDiagram::IntersectRect(const CRect& rect, int nIgnoreRect) const
{
if (!m_aRects.GetSize())
return FALSE;
// else
CRect rTest(rect);
rTest.right++; // inclusive
rTest.bottom++; // inclusive
for (int nRect = 0; nRect < m_aRects.GetSize(); nRect++)
{
CRect r = m_aRects[nRect];
r.right++; // inclusive
r.bottom++; // inclusive
if (CRect().IntersectRect(r, rTest) && nRect != nIgnoreRect)
return TRUE;
}
return FALSE;
}
void CTextDiagram::AddRect(const CStringArray& diagram, int nX, int nY)
{
TDPOS nPos = RectStartChar(diagram, nX, nY);
if (nPos != NONE)
{
CPoint ptOrg(nX, nY);
CRect rect(nX, nY, nX, nY);
BOOL bDone = FALSE;
TDPOS nPosOrg = nPos;
int nIteration = 0; // for catching infinite loops
while (nPos != NONE && !bDone && nIteration < MAXITERATIONS)
{
nIteration++;
nPos = RectGetNextChar(diagram, nPos, nX, nY);
if (nPos != NONE)
{
rect.left = min(rect.left, nX);
rect.top = min(rect.top, nY);
rect.right = max(rect.right, nX);
rect.bottom = max(rect.bottom, nY);
// are we done yet?
bDone = (nPos == nPosOrg && nX == ptOrg.x && nY == ptOrg.y);
}
}
// get rect text
if (bDone)
{
CString sText;
for (nY = rect.top + 1; nY < rect.bottom; nY++)
{
for (nX = rect.left + 1; nX < rect.right; nX++)
{
sText += GetChar(diagram, nX, nY);
}
// if the last char is a space then insert a carriage return
if (sText.Right(1) == " ")
{
sText.TrimRight();
sText += "\r\n";
}
}
sText.TrimRight();
AddRect(rect, sText);
}
}
}
int CTextDiagram::GetRectCount() const
{
return m_aRects.GetSize();
}
int CTextDiagram::GetConnectionCount() const
{
return m_aConns.GetSize();
}
BOOL CTextDiagram::GetRect(int nRect, CTDRect& rect) const
{
if (nRect < 0 || nRect >= GetRectCount())
return FALSE;
// else
rect = m_aRects[nRect];
return TRUE;
}
BOOL CTextDiagram::GetRect(int nRect, CRect& rect) const
{
CTDRect tdRect;
if (GetRect(nRect, tdRect))
{
rect = tdRect;
return TRUE;
}
return FALSE;
}
BOOL CTextDiagram::DeleteRect(int nRect)
{
if (nRect < 0 || nRect >= GetRectCount())
return FALSE;
// modify all connections referencing rects after this one
// to take account of the removal
// and remove all connections which reference this rect
int nConn = m_aConns.GetSize();
while (nConn--)
{
CTDConnection& conn = m_aConns[nConn];
int nRectFrom = conn.RectFrom();
int nRectTo = conn.RectTo();
if (nRectFrom == nRect || nRectTo == nRect)
m_aConns.RemoveAt(nConn);
else
{
if (nRectFrom > nRect)
conn.SetRectFrom(nRectFrom - 1);
if (nRectTo > nRect)
conn.SetRectTo(nRectTo - 1);
}
}
m_aRects.RemoveAt(nRect);
RebuildConnections();
return TRUE;
}
BOOL CTextDiagram::DeleteConnection(int nConn)
{
if (nConn < 0 || nConn >= GetConnectionCount())
return FALSE;
m_aConns.RemoveAt(nConn);
return TRUE;
}
BOOL CTextDiagram::GetConnection(int nConn, CTDConnection& conn) const
{
if (nConn < 0 || nConn >= GetConnectionCount())
return FALSE;
// else
conn = m_aConns[nConn];
return TRUE;
}
BOOL CTextDiagram::SetRect(int nRect, const CTDRect& rect)
{
if (nRect < 0 || nRect >= GetRectCount())
return FALSE;
// validate the rect
if (rect.left <= 0 || rect.top <= 0 || rect.Width() < 2 || rect.Height() < 2)
return FALSE;
// make sure it doesn't overlap any other rect
// don't let it come too close either
CRect r(rect);
r.InflateRect(1, 1);
if (IntersectRect(r, nRect))
return FALSE;
// save current state in case this fails
CTextDiagram diagramBackup(*this);
m_aRects[nRect] = rect;
// rebuild all connections to ensure no overlaps
if (RebuildConnections())
{
// update the diagram size
RecalcSize();
return TRUE;
}
// else restore the backup
SetDiagram(diagramBackup);
return FALSE;
}
BOOL CTextDiagram::SetText(int nRect, LPCTSTR szText)
{
if (nRect < 0 || nRect >= GetRectCount())
return FALSE;
m_aRects[nRect].SetText(szText);
return TRUE;
}
BOOL CTextDiagram::GetText(int nRect, CString& sText)
{
if (nRect < 0 || nRect >= GetRectCount())
return FALSE;
sText = m_aRects[nRect].GetText();
return TRUE;
}
BOOL CTextDiagram::RebuildConnections()
{
// save a copy of existing connections
CArray<CTDConnection, CTDConnection&> aConns;
aConns.Copy(m_aConns);
// delete all connections and re-add
m_aConns.RemoveAll();
for (int nConn = 0; nConn < aConns.GetSize(); nConn++)
{
// defensive programming
CTDConnection conn = aConns[nConn];
if (AddConnection(conn.RectFrom(), conn.RectTo(), conn.SideFrom()) == -1)
return FALSE;
}
return TRUE;
}
int CTextDiagram::AddRect(LPCRECT pRect, LPCTSTR szText)
{
if (!pRect)
return NewRect();
// validate the rect
CRect rect(pRect);
if (rect.left <= 0 || rect.top <= 0 || rect.Width() < 2 || rect.Height() < 2)
return -1;
// make sure it doesn't overlap any other rect
// don't let it come too close either
CRect r(rect);
r.InflateRect(1, 1);
if (IntersectRect(r))
return -1;
// don't let it overlap or touch any connections
if (IntersectConn(rect))
return -1;
// save current state in case this fails
CTextDiagram diagramBackup(*this);
int nRect = m_aRects.Add(CTDRect(rect, szText));
// rebuild all connections to ensure no overlaps
if (nRect >= 0 && RebuildConnections())
{
// update the diagram size
RecalcSize();
return nRect;
}
// else restore backup
SetDiagram(diagramBackup);
return -1;
}
int CTextDiagram::FindConnection(int nRectFrom, int nRectTo) const
{
int nConn = m_aConns.GetSize();
while (nConn--)
{
if (m_aConns[nConn].RectFrom() == nRectFrom && m_aConns[nConn].RectTo() == nRectTo)
return nConn;
}
return -1; // not found
}
int CTextDiagram::AddConnection(int nRectFrom, int nRectTo, int nSideFrom)
{
if (FindConnection(nRectFrom, nRectTo) != -1)
return -1;
CTDConnection conn(nRectFrom, nRectTo, nSideFrom);
if (BuildPath(conn, -1))
{
int nConn = m_aConns.Add(conn);
// update the diagram size
RecalcSize();
return nConn;
}
return -1;
}
BOOL CTextDiagram::SetConnection(int nConn, const CTDConnection& conn)
{
CTDConnection connExist;
// retrieve existing connection
if (!GetConnection(nConn, connExist))
return FALSE;
// ensure requested connection is not already taken
int nCurConn = FindConnection(conn.RectFrom(), conn.RectTo());
if (nCurConn != -1 && nCurConn != nConn)
return FALSE;
// save current state in case this fails
CTextDiagram diagramBackup(*this);
// update existing connection
m_aConns.SetAt(nConn, CTDConnection(conn));
if (RebuildConnections())
{
// update the diagram size
RecalcSize();
return TRUE;
}
// restore backup
SetDiagram(diagramBackup);
return FALSE;
}
void CTextDiagram::GetRelationship(const CRect& rFrom, const CRect& rTo, int& nHorz, int& nVert)
{
GetRelationship(rFrom.CenterPoint(), rTo.CenterPoint(), nHorz, nVert);
}
void CTextDiagram::GetRelationship(CPoint ptFrom, const CRect& rTo, int& nHorz, int& nVert)
{
// horz
if (ptFrom.x >= rTo.left && ptFrom.x <= rTo.right)
nHorz = 0; // 'to' is aligned with 'from'
else if (ptFrom.x < rTo.left)
nHorz = 1; // 'to' is to the right of 'from'
else
nHorz = -1; // 'to' is to the left of 'from'
// vert
if (ptFrom.y >= rTo.top && ptFrom.y <= rTo.bottom)
nVert = 0; // 'to' is aligned with 'from'
else if (ptFrom.y < rTo.top)
nVert = 1; // 'to' is below 'from'
else
nVert = -1; // 'to' is above 'from'
}
void CTextDiagram::GetRelationship(CPoint ptFrom, CPoint ptTo, int& nHorz, int& nVert)
{
// horz
if (ptFrom.x == ptTo.x)
nHorz = 0; // 'to' is aligned with 'from'
else if (ptFrom.x < ptTo.x)
nHorz = 1; // 'to' is to the right of 'from'
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -