📄 textdiagram.cpp
字号:
// left
DrawLine(diagram, CPoint(rect.left, rect.top), CPoint(rect.left, rect.bottom));
// top
DrawLine(diagram, CPoint(rect.left, rect.top), CPoint(rect.right, rect.top));
// bottom
DrawLine(diagram, CPoint(rect.left, rect.bottom), CPoint(rect.right, rect.bottom));
// corners
SetChar(diagram, rect.left, rect.top, SPACE);
SetChar(diagram, rect.right, rect.top, SPACE);
SetChar(diagram, rect.right, rect.bottom, SPACE);
SetChar(diagram, rect.left, rect.bottom, SPACE);
// text
int nLen = rect.GetTextLen(), nX = rect.left + 1, nY = rect.top + 1;
LPCTSTR szText = rect.GetText();
for (int nChar = 0; nChar < nLen && nY < rect.bottom; nChar++)
{
char c = szText[nChar];
#ifdef _VER_CHINESE
// new line?
if (c == _T('\r'))
{
nX = rect.left + 1;
nY++;
nChar++; // jump '\n'
}
else if (
(((c & 0x80) != 0) && ((nX + 1) >= rect.right)) || //it is a Chinese character,it need two bytes space
(((c & 0x80) == 0) && (nX >= rect.right))
)
{
nX = rect.left + 1;
nY++;
nChar--;
}
else
{
if((c & 0x80) != 0)//it is the first byte of a Chinese character
{
//set the first byte of this Chinese character
SetChar(diagram, nX, nY, c);
nX++;
//set the next byte of this Chinese character
nChar++;
c = szText[nChar];
SetChar(diagram, nX, nY, c);
nX++;
}
else//general ASCII character
{
SetChar(diagram, nX, nY, c);
nX++;
}
}
#else
// new line?
if (c == '\r')
{
nX = rect.left + 1;
nY++;
nChar++; // jump '\n'
}
else if (nX >= rect.right)
{
nX = rect.left + 1;
nY++;
nChar--;
}
else
{
SetChar(diagram, nX, nY, c);
nX++;
}
#endif
}
}
void CTextDiagram::DrawConn(CStringArray& diagram, const CTDConnection& conn) const
{
CPoint ptEnd, ptStart = conn.GetStartPos();
for (int nSegment = 0; nSegment < conn.NumSegments(); nSegment++)
{
ptEnd = conn.GetSegmentPos(nSegment);
DrawLine(diagram, ptStart, ptEnd, &conn);
ptStart = ptEnd;
}
// replace start with '+'
ptStart = conn.GetStartPos();
SetChar(diagram, ptStart.x, ptStart.y, CHAR_START);
// replace end with '*'
ptEnd = conn.GetEndPos();
SetChar(diagram, ptEnd.x, ptEnd.y, CHAR_END);
/* // replace end with arrows
switch (conn.GetEndDirection())
{
case CONN_UP:
SetChar(diagram, ptEnd.x, ptEnd.y, CHAR_ENDUP);
break;
case CONN_DOWN:
SetChar(diagram, ptEnd.x, ptEnd.y, CHAR_ENDDOWN);
break;
case CONN_LEFT:
SetChar(diagram, ptEnd.x, ptEnd.y, CHAR_ENDLEFT);
break;
case CONN_RIGHT:
SetChar(diagram, ptEnd.x, ptEnd.y, CHAR_ENDRIGHT);
break;
}
*/
}
void CTextDiagram::DrawLine(CStringArray& diagram, CPoint ptFrom, CPoint ptTo, const CTDConnection* pConn) const
{
// must be vert or horz
ASSERT (ptFrom.x == ptTo.x || ptFrom.y == ptTo.y);
int nXLen = abs(ptFrom.x - ptTo.x);
int nYLen = abs(ptFrom.y - ptTo.y);
if (nYLen) // vert
{
int nFrom = (ptFrom.y > ptTo.y) ? ptTo.y : ptFrom.y;
int nTo = (ptFrom.y > ptTo.y) ? ptFrom.y : ptTo.y;
if (pConn && nYLen > 0)
{
nFrom++;
// make sure the line is at least one char long
// with the exception of the start and end points
if (nTo - nFrom > 0 || ptFrom == pConn->GetStartPos() || ptTo == pConn->GetEndPos())
nTo--;
}
for (int nY = nFrom; nY <= nTo; nY++)
{
char c = CHAR_VERT;
if (pConn && PtInConn(ptTo.x, nY, TRUE) && !pConn->PtInConn(CPoint(ptTo.x, nY), TRUE))
c = CHAR_CROSSOVER;
SetChar(diagram, ptTo.x, nY, c);
}
}
else if (nXLen) // horz
{
int nFrom = (ptFrom.x > ptTo.x) ? ptTo.x : ptFrom.x;
int nTo = (ptFrom.x > ptTo.x) ? ptFrom.x : ptTo.x;
for (int nX = nFrom; nX <= nTo; nX++)
{
char c = CHAR_HORZ;
if (pConn && PtInConn(nX, ptTo.y, FALSE) && !pConn->PtInConn(CPoint(nX, ptTo.y), FALSE))
c = CHAR_CROSSOVER;
SetChar(diagram, nX, ptTo.y, c);
}
}
}
void CTextDiagram::ExpandTabs(CString& sLine, int nTabSize)
{
CString sExpanded;
for (int nPos = 0; nPos < sLine.GetLength(); nPos++)
{
char c = sLine[nPos];
if (c == '\t')
{
int nTabs = nTabSize - (sExpanded.GetLength() % nTabSize);
while (nTabs--)
sExpanded += ' ';
}
else
sExpanded += c;
}
sLine = sExpanded;
}
char CTextDiagram::GetChar(const CStringArray& diagram, int nX, int nY)
{
if (nY < 0 || nY >= diagram.GetSize())
return 0;
CString& sLine = diagram[nY];
if (nX < 0 || nX >= sLine.GetLength())
return 0;
return sLine[nX];
}
BOOL CTextDiagram::SetChar(CStringArray& diagram, int nX, int nY, char c)
{
if (!c)
return FALSE;
if (nY < 0 || nY >= diagram.GetSize())
{
ASSERT(0);
return FALSE;
}
CString& sLine = diagram[nY];
if (nX < 0 || nX >= sLine.GetLength())
{
ASSERT(0);
return FALSE;
}
sLine.SetAt(nX, c);
return TRUE;
}
int CTextDiagram::LineLength(const CStringArray& diagram, int nY)
{
return (nY < 0 || nY >= diagram.GetSize()) ? 0 : diagram[nY].GetLength();
}
BOOL CTextDiagram::TestChar(const CStringArray& diagram, int nX, int nY, char cTest1, char cTest2, char cTest3)
{
char c = GetChar(diagram, nX, nY);
return ((cTest1 && cTest1 == c) || (cTest2 && cTest2 == c) || (cTest3 && cTest3 == c));
}
void CTextDiagram::ProcessDiagram(const CStringArray& diagram)
{
if (!diagram.GetSize())
return;
CStringArray diagramTemp;
diagramTemp.Copy(diagram);
// 1. title
// find the first non-empty line
int nLine = 0;
BOOL bContinue = TRUE;
while (bContinue && nLine < diagramTemp.GetSize())
{
CString sLine = diagramTemp[nLine];
sLine.TrimLeft();
if (bContinue = sLine.IsEmpty())
nLine++;
}
// title lines must begin with a ':'
if (TestChar(diagramTemp, 0, nLine, ':'))
{
while (TestChar(diagramTemp, 0, nLine, ':'))
{
CString sLine = diagramTemp[nLine].Mid(1);
sLine.TrimLeft();
sLine.TrimRight();
m_sTitle += sLine;
m_sTitle += "\r\n";
nLine++;
}
// remove the title lines
while (nLine--)
diagramTemp.RemoveAt(0);
}
if (!diagramTemp.GetSize())
return;
// 2. check boundary conditions.
// specifically rects either of whose left or top is zero
BOOL bFoundHorz = FALSE, bFoundVert = FALSE;
for (int nX = 0; nX < LineLength(diagramTemp, 0) && !bFoundHorz; nX++)
bFoundHorz = (RECT_TOP == RectStartChar(diagramTemp, nX, 0));
for (int nY = 0; nY < diagramTemp.GetSize() && !bFoundVert; nY++)
bFoundVert = (RECT_TOP == RectStartChar(diagramTemp, 1, nY));
// if we find a rect at y==0 then simply add an empty line at the start
if (bFoundHorz)
diagramTemp.InsertAt(0, "");
// if we find a rect at x==0 then prepeand a space to every line
if (bFoundVert)
{
for (int nY = 0; nY < diagramTemp.GetSize(); nY++)
diagramTemp[nY] = " " + diagramTemp[nY];
}
// 3. process rects
for (nY = 0; nY < diagramTemp.GetSize(); nY++)
{
int nLineLen = LineLength(diagramTemp, nY);
for (int nX = 0; nX < nLineLen; nX++)
{
AddRect(diagramTemp, nX, nY);
}
}
// 4. process connections
if (GetRectCount() > 1)
{
for (nY = 0; nY < diagramTemp.GetSize(); nY++)
{
int nLineLen = LineLength(diagramTemp, nY);
for (int nX = 0; nX < nLineLen; nX++)
{
AddConn(diagramTemp, nX, nY);
}
}
}
}
TDPOS CTextDiagram::RectGetNextChar(const CStringArray& diagram, TDPOS nCurPos, int& nX, int& nY) const
{
if (PtInRect(nX, nY))
return NONE;
switch (nCurPos)
{
case RECT_TOP:
// test change of direction first
if (TestChar(diagram, nX + 1, nY + 1, CHAR_RIGHT, CHAR_START, CHAR_END))
{
nX++;
nY++;
return RECT_RIGHT;
}
else if (TestChar(diagram, nX + 1, nY, CHAR_TOP, CHAR_START, CHAR_END))
{
nX++;
return RECT_TOP;
}
break;
case RECT_RIGHT:
// test change of direction first
if (TestChar(diagram, nX - 1, nY + 1, CHAR_BOTTOM, CHAR_START, CHAR_END))
{
nX--;
nY++;
return RECT_BOTTOM;
}
else if (TestChar(diagram, nX, nY + 1, CHAR_RIGHT, CHAR_START, CHAR_END))
{
nY++;
return RECT_RIGHT;
}
break;
case RECT_BOTTOM:
// test change of direction first
if (TestChar(diagram, nX - 1, nY - 1, CHAR_LEFT, CHAR_START, CHAR_END))
{
nX--;
nY--;
return RECT_LEFT;
}
else if (TestChar(diagram, nX - 1, nY, CHAR_BOTTOM, CHAR_START, CHAR_END))
{
nX--;
return RECT_BOTTOM;
}
break;
case RECT_LEFT:
// test change of direction first
if (TestChar(diagram, nX + 1, nY - 1, CHAR_TOP, CHAR_START, CHAR_END))
{
nX++;
nY--;
return RECT_TOP;
}
else if (TestChar(diagram, nX, nY - 1, CHAR_LEFT, CHAR_START, CHAR_END))
{
nY--;
return RECT_LEFT;
}
break;
}
return NONE;
}
TDPOS CTextDiagram::RectStartChar(const CStringArray& diagram, int nX, int nY) const
{
if (PtInRect(nX, nY))
return NONE;
char c = GetChar(diagram, nX, nY);
// test for top char
if (c == CHAR_TOP || c == CHAR_START || c == CHAR_END)
{
// test for left char
c = GetChar(diagram, nX - 1, nY + 1);
if (c == CHAR_LEFT || c == CHAR_START || c == CHAR_END)
{
// finally test for corner char
c = GetChar(diagram, nX - 1, nY);
if (c == SPACE || c == CHAR_START || c == CHAR_END)
return RECT_TOP;
}
}
return NONE;
}
TDPOS CTextDiagram::ConnStartChar(const CStringArray& diagram, int nX, int nY) const
{
if (!PtInRect(nX, nY))
return NONE;
char c = GetChar(diagram, nX, nY);
if (c == CHAR_START)
{
// check we are on a rect border
int nRect = IntersectRect(nX, nY);
ASSERT (nRect != -1);
CTDRect rect;
if (GetRect(nRect, rect) && rect.GetSide(CPoint(nX, nY)) != NONE)
return CONN_START;
}
// all else
return NONE;
}
TDPOS CTextDiagram::ConnGetNextChar(const CStringArray& diagram, TDPOS nCurPos, int& nX, int& nY) const
{
switch (nCurPos)
{
case CONN_START:
// test normal chars first
if (IntersectRect(nX + 1, nY) == -1 && TestChar(diagram, nX + 1, nY, CHAR_HORZ, CHAR_CROSSOVER))
{
nX++;
return CONN_RIGHT;
}
else if (IntersectRect(nX - 1, nY) == -1 && TestChar(diagram, nX - 1, nY, CHAR_HORZ, CHAR_CROSSOVER))
{
nX--;
return CONN_LEFT;
}
else if (IntersectRect(nX, nY + 1) == -1 && TestChar(diagram, nX, nY + 1, CHAR_VERT, CHAR_CROSSOVER))
{
nY++;
return CONN_DOWN;
}
else if (IntersectRect(nX, nY - 1) == -1 && TestChar(diagram, nX, nY - 1, CHAR_VERT, CHAR_CROSSOVER))
{
nY--;
return CONN_UP;
}
// then, if vertical, test for immediate change of direction
else if (IntersectRect(nX, nY + 1) == -1 && TestChar(diagram, nX, nY + 1, CHAR_HORZ))
{
nY++;
// which way does it go?
if (TestChar(diagram, nX + 1, nY, CHAR_HORZ, CHAR_CROSSOVER))
return CONN_RIGHT;
else
return CONN_LEFT;
}
else if (IntersectRect(nX, nY - 1) == -1 && TestChar(diagram, nX, nY - 1, CHAR_HORZ))
{
nY--;
// which way does it go?
if (TestChar(diagram, nX + 1, nY, CHAR_HORZ, CHAR_CROSSOVER))
return CONN_RIGHT;
else
return CONN_LEFT;
}
break;
case CONN_RIGHT:
// 1. test for continuation
if (TestChar(diagram, nX + 1, nY, CHAR_HORZ, CHAR_CROSSOVER))
{
nX++;
return CONN_RIGHT;
}
// 2. test for termination
else if (TestChar(diagram, nX + 1, nY, CHAR_END/*, CHAR_ENDRIGHT*/))
{
nX++;
return CONN_END;
}
// 3. test for change of direction (down)
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_LEFT:
// 1. test for continuation
if (TestChar(diagram, nX - 1, nY, CHAR_HORZ, CHAR_CROSSOVER))
{
nX--;
return CONN_LEFT;
}
// 2. test for termination
else if (TestChar(diagram, nX - 1, nY, CHAR_END/*, CHAR_ENDLEFT*/))
{
nX--;
return CONN_END;
}
// 3. test for change of direction (down)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -