📄 textdiagramctrl.cpp
字号:
break;
case SB_BOTTOM:
m_ptScrollOffset.y = (rDiagram.bottom - rClient.bottom);
break;
case SB_THUMBPOSITION:
m_ptScrollOffset.y = (nPos / CHARSIZE_Y) * CHARSIZE_Y;
break;
case SB_THUMBTRACK:
m_ptScrollOffset.y = (nPos / CHARSIZE_Y) * CHARSIZE_Y;
break;
}
if (m_ptScrollOffset != ptOffset)
{
Invalidate();
UpdateScrollbars();
}
CWnd::OnVScroll(nSBCode, nPos, pScrollBar);
}
void CTextDiagramCtrl::OnSize(UINT nType, int cx, int cy)
{
CWnd::OnSize(nType, cx, cy);
UpdateScrollbars();
}
BOOL CTextDiagramCtrl::RebuildConnections()
{
if (!CTextDiagram::RebuildConnections())
{
// GetParent()->PostMessage(WM_COMMAND, MAKEWPARAM(GetDlgCtrlID(), TDN_INTERNALERROR), (LPARAM)GetSafeHwnd());
return FALSE;
}
return TRUE;
}
void CTextDiagramCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_bMoving || m_nSizing != HTNOWHERE)
{
ASSERT (GetCapture() == this);
// get the original rect
CTDRect rect;
GetRect(m_nSelRect, rect);
CRect rNew(rect);
BOOL bStart = (m_ptDragPrev == m_ptDragStart);
CPoint ptPrev(m_ptDragPrev); // cache
CPoint ptOrg(point); // cache
ClientToLogical(ptPrev);
ClientToLogical(point);
// get new pos
if (m_bMoving)
{
rect.OffsetRect(ptPrev);
rNew.OffsetRect(point);
// prevent the rects preceding the origin
rect.OffsetRect(max(0, 1 - rect.left), max(0, 1 - rect.top));
rNew.OffsetRect(max(0, 1 - rNew.left), max(0, 1 - rNew.top));
}
else
{
switch (m_nSizing)
{
case HTLEFT:
rect.left += ptPrev.x;
rNew.left += point.x;
rect.left = max(1, min(rect.left, rect.right - 2));
rNew.left = max(1, min(rNew.left, rNew.right - 2));
break;
case HTRIGHT:
rect.right += ptPrev.x;
rNew.right += point.x;
rect.right = max(rect.right, rect.left + 2);
rNew.right = max(rNew.right, rNew.left + 2);
break;
case HTTOP:
rect.top += ptPrev.y;
rNew.top += point.y;
rect.top = max(1, min(rect.top, rect.bottom - 2));
rNew.top = max(1, min(rNew.top, rNew.bottom - 2));
break;
case HTBOTTOM:
rect.bottom += ptPrev.y;
rNew.bottom += point.y;
rect.bottom = max(rect.bottom, rect.top + 2);
rNew.bottom = max(rNew.bottom, rNew.top + 2);
break;
}
}
if (rNew != rect)
{
// set the cursor
rNew.InflateRect(1, 1);
if (IntersectRect(rNew, m_nSelRect) || rNew.left < 0 || rNew.top < 0)
SetCursor(AfxGetApp()->LoadStandardCursor(IDC_NO));
else
{
if (m_bMoving)
SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
else
{
switch (m_nSizing)
{
case HTLEFT:
case HTRIGHT:
SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
break;
case HTTOP:
case HTBOTTOM:
SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
break;
}
}
}
// draw rect tracker
rNew.DeflateRect(1, 1);
LogicalToClient(rect);
LogicalToClient(rNew);
CDC* pDC = GetDC();
pDC->DrawDragRect(rNew, CSize(2, 2), bStart ? NULL : &rect, CSize(2, 2));
ReleaseDC(pDC);
m_ptDragPrev = ptOrg;
}
}
CWnd::OnMouseMove(nFlags, point);
}
void CTextDiagramCtrl::SnapToGrid(CRect& rect)
{
rect.left = (rect.left / CHARSIZE_X) * CHARSIZE_X + CHARSIZE_X / 2;
rect.right = (rect.right / CHARSIZE_X) * CHARSIZE_X + CHARSIZE_X / 2;
rect.top = (rect.top / CHARSIZE_Y) * CHARSIZE_Y + CHARSIZE_Y / 2;
rect.bottom = (rect.bottom / CHARSIZE_Y) * CHARSIZE_Y + CHARSIZE_Y / 2;
}
void CTextDiagramCtrl::ClientToLogical(CPoint& point)
{
point.Offset(m_ptScrollOffset);
if (m_bMoving || m_nSizing != HTNOWHERE)
point.Offset(-m_ptDragStart);
// convert to logical coords
point.x = point.x / CHARSIZE_X;
point.y = point.y / CHARSIZE_Y;
}
void CTextDiagramCtrl::LogicalToClient(CRect& rect)
{
rect.left *= CHARSIZE_X;
rect.right *= CHARSIZE_X;
rect.top *= CHARSIZE_Y;
rect.bottom *= CHARSIZE_Y;
rect.OffsetRect(CHARSIZE_X / 2, CHARSIZE_Y / 2);
rect.right++;
rect.bottom++;
rect.OffsetRect(-m_ptScrollOffset);
}
void CTextDiagramCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
CWnd::OnLButtonUp(nFlags, point);
if (m_bMoving || m_nSizing != HTNOWHERE)
{
ClientToLogical(point);
CTDRect rect;
GetRect(m_nSelRect, rect);
CRect rNew(rect);
// get new pos
if (m_bMoving)
{
rNew.OffsetRect(point);
// prevent the rect preceding the origin
rNew.OffsetRect(max(0, 1 - rNew.left), max(0, 1 - rNew.top));
}
else
{
switch (m_nSizing)
{
case HTLEFT:
rNew.left += point.x;
rNew.left = max(1, min(rNew.left, rNew.right - 2));
break;
case HTRIGHT:
rNew.right += point.x;
rNew.right = max(rNew.right, rNew.left + 2);
break;
case HTTOP:
rNew.top += point.y;
rNew.top = max(1, min(rNew.top, rNew.bottom - 2));
break;
case HTBOTTOM:
rNew.bottom += point.y;
rNew.bottom = max(rNew.bottom, rNew.top + 2);
break;
}
}
// test the new pos
if (rNew != rect)
{
rect.CopyRect(rNew);
if (SetRect(m_nSelRect, rect))
SendNotification(TDN_SELRECTMOVE);
}
m_bMoving = FALSE;
m_nSizing = HTNOWHERE;
ReleaseCapture();
Invalidate();
}
else if (m_bDblClick)
{
if (m_nSelRect != -1)
EditSelectedText();
else
SendNotification(TDN_DBLCLK, point);
}
}
void CTextDiagramCtrl::EditSelectedText()
{
ASSERT (m_nSelRect != -1);
if (m_nSelRect != -1)
{
CTDRect rect;
if (GetRect(m_nSelRect, rect))
{
CRect rPos(rect);
LogicalToClient(rPos);
if (!m_editText.GetSafeHwnd())
{
m_editText.Create(WS_VISIBLE | WS_CHILD | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL, rPos, this, IDC_EDITTEXT);
m_editText.SetFont(CFont::FromHandle((HFONT)GetStockObject(ANSI_FIXED_FONT)));
}
else
{
m_editText.ShowWindow(SW_SHOW);
m_editText.MoveWindow(rPos);
}
rPos.OffsetRect(-rPos.TopLeft());
rPos.left += CHARSIZE_X / 2 - 2;
rPos.top += CHARSIZE_Y / 2 - 2;
m_editText.SetRect(rPos);
m_editText.SetWindowText(rect.GetText());
m_editText.SetFocus();
}
}
}
void CTextDiagramCtrl::OnCaptureChanged(CWnd *pWnd)
{
if (m_bMoving && pWnd == this)
{
// just cancel
m_bMoving = FALSE;
Invalidate();
}
CWnd::OnCaptureChanged(pWnd);
}
UINT CTextDiagramCtrl::OnNcHitTest(CPoint point)
{
return CWnd::OnNcHitTest(point);
}
BOOL CTextDiagramCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
if (pWnd == this && nHitTest == HTCLIENT && m_nSelRect != -1)
{
CPoint point;
GetCursorPos(&point);
ScreenToClient(&point);
point.Offset(m_ptScrollOffset);
int nRect = IntersectRect(point.x / CHARSIZE_X, point.y / CHARSIZE_Y);
if (nRect == m_nSelRect)
{
// see if we're on the rect border
CTDRect rect;
GetRect(m_nSelRect, rect);
CRect rDraw(rect);
LogicalToClient(rDraw);
rDraw.OffsetRect(m_ptScrollOffset);
// deflate this and then check we're still inside
rDraw.DeflateRect(2, 2);
if (!rDraw.PtInRect(point))
{
if (point.x < rDraw.left || point.x > rDraw.right)
return (BOOL)SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZEWE));
else
return (BOOL)SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENS));
}
}
}
return CWnd::OnSetCursor(pWnd, nHitTest, message);
}
int CTextDiagramCtrl::HitTestConn(CPoint point)
{
// convert to logical coords
ClientToLogical(point);
int nConn = IntersectConn(point, TRUE);
if (nConn == -1)
nConn = IntersectConn(point, FALSE);
return nConn;
}
int CTextDiagramCtrl::HitTestRect(CPoint point)
{
// convert to logical coords
ClientToLogical(point);
return IntersectRect(point);
}
void CTextDiagramCtrl::OnLButtonDblClk(UINT nFlags, CPoint point)
{
CWnd::OnLButtonDblClk(nFlags, point);
m_bDblClick = TRUE;
}
UINT CTextDiagramCtrl::OnGetDlgCode()
{
if (m_nSelRect != -1)
return DLGC_WANTARROWS;
return CWnd::OnGetDlgCode();
}
void CTextDiagramCtrl::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
if (m_nSelRect != -1)
{
CTDRect rect;
GetRect(m_nSelRect, rect);
switch (nChar)
{
case VK_DELETE:
if (DeleteRect(m_nSelRect))
{
UpdateWindow();
m_nSelRect = -1;
SendNotification(TDN_SELRECTDELETE);
}
break;
case VK_LEFT:
{
rect.OffsetRect(-1, 0);
if (SetRect(m_nSelRect, rect))
{
UpdateWindow();
SendNotification(TDN_SELRECTMOVE);
}
}
break;
case VK_RIGHT:
{
rect.OffsetRect(1, 0);
if (SetRect(m_nSelRect, rect))
{
UpdateWindow();
SendNotification(TDN_SELRECTMOVE);
}
}
break;
case VK_UP:
{
rect.OffsetRect(0, -1);
if (SetRect(m_nSelRect, rect))
{
UpdateWindow();
SendNotification(TDN_SELRECTMOVE);
}
}
break;
case VK_DOWN:
{
rect.OffsetRect(0, 1);
if (SetRect(m_nSelRect, rect))
{
UpdateWindow();
SendNotification(TDN_SELRECTMOVE);
}
}
break;
case VK_F2:
EditSelectedText();
break;
}
}
CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}
void CTextDiagramCtrl::OnEndTextEdit()
{
if (EditingText())
{
if (m_nSelRect != -1 && m_editText.IsWindowVisible())
{
CString sItemText;
if (GetText(m_nSelRect, sItemText))
{
CString sText;
m_editText.GetWindowText(sText);
if (sText != sItemText)
{
SetText(m_nSelRect, sText);
SendNotification(TDN_SELRECTTEXTCHANGE);
}
}
}
m_editText.ShowWindow(SW_HIDE);
}
}
BOOL CTextDiagramCtrl::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN && pMsg->hwnd == m_editText)
{
switch (pMsg->wParam)
{
case VK_ESCAPE:
m_editText.ShowWindow(SW_HIDE);
SetFocus(); // hiding the window first casues the text changes to be ignored
return TRUE;
case VK_RETURN:
if (!(GetAsyncKeyState(VK_CONTROL) & 0x8000))
{
SetFocus(); // this automatically causes an end edit
return TRUE;
}
break;
}
}
return CWnd::PreTranslateMessage(pMsg);
}
void CTextDiagramCtrl::OnContextMenu(CWnd* pWnd, CPoint point)
{
// always make sure existing edit is finished
OnEndTextEdit();
CMenu menu;
if (!menu.CreatePopupMenu())
return;
// what have we hit
ScreenToClient(&point);
m_ptContextMenu = point; // cache for command handlers
int nRect = HitTestRect(point);
if (nRect != -1)
{
// remove selection
if (m_nSelRect != nRect)
{
m_nSelRect = nRect;
Invalidate();
SendNotification(TDN_SELCHANGE);
}
// build menu
menu.AppendMenu(MF_STRING, ID_RECT_EDITTEXT, "Edit Box Text");
menu.AppendMenu(MF_STRING, ID_RECT_DELETE, "Delete Box");
menu.AppendMenu(MF_SEPARATOR);
menu.AppendMenu(MF_STRING, ID_CONN_NEW, "New Connection To...");
menu.AppendMenu(MF_SEPARATOR);
menu.AppendMenu(MF_STRING, IDCANCEL, "Cancel\tEsc");
}
else
{
// remove selection
if (m_nSelRect != -1)
{
m_nSelRect = -1;
Invalidate();
SendNotification(TDN_SELCHANGE);
}
int nConn = HitTestConn(point);
if (nConn != -1)
{
// build menu
menu.AppendMenu(MF_STRING, ID_CONN_MODIFY, "Modify Connection...");
menu.AppendMenu(MF_STRING, ID_CONN_DELETE, "Delete Connection");
menu.AppendMenu(MF_SEPARATOR);
menu.AppendMenu(MF_STRING, IDCANCEL, "Cancel\tEsc");
}
else
{
menu.AppendMenu(MF_STRING, ID_RECT_NEW, "New Box");
menu.AppendMenu(MF_SEPARATOR);
menu.AppendMenu(MF_STRING, ID_RESET, "Reset Diagram");
menu.AppendMenu(MF_SEPARATOR);
menu.AppendMenu(MF_STRING, IDCANCEL, "Cancel\tEsc");
// determine whether 'new box' is enabled or not
CPoint ptTopLeft(point);
ClientToLogical(ptTopLeft);
CRect rNew(ptTopLeft, CSize(5, 3));
rNew.InflateRect(1, 1);
menu.EnableMenuItem(ID_RECT_NEW, IntersectRect(rNew) ? MF_GRAYED : MF_ENABLED);
}
}
ClientToScreen(&point);
menu.TrackPopupMenu(TPM_LEFTALIGN, point.x, point.y, this);
}
void CTextDiagramCtrl::OnRectNew()
{
if (HitTestRect(m_ptContextMenu) == -1 && HitTestConn(m_ptContextMenu) == -1)
{
CPoint ptTopLeft(m_ptContextMenu);
ClientToLogical(ptTopLeft);
if (AddRect(CRect(ptTopLeft, CSize(5, 3))) != -1)
{
EditSelectedText();
}
}
}
void CTextDiagramCtrl::OnRectDelete()
{
ASSERT (m_nSelRect == HitTestRect(m_ptContextMenu));
if (m_nSelRect != -1)
DeleteRect(m_nSelRect);
}
void CTextDiagramCtrl::OnRectEditText()
{
ASSERT (m_nSelRect == HitTestRect(m_ptContextMenu));
if (m_nSelRect != -1)
EditSelectedText();
}
void CTextDiagramCtrl::OnConnNew()
{
ASSERT (m_nSelRect == HitTestRect(m_ptContextMenu));
if (m_nSelRect != -1)
{
// short term fudge sends a notification to the parent to provide this functionality
SendNotification(TDN_IMPLCONNNEW, m_ptContextMenu);
}
}
void CTextDiagramCtrl::OnConnModify()
{
int nConn = HitTestConn(m_ptContextMenu);
if (nConn != -1)
{
// short term fudge sends a notification to the parent to provide this functionality
SendNotification(TDN_DBLCLK, m_ptContextMenu);
}
}
void CTextDiagramCtrl::OnConnDelete()
{
int nConn = HitTestConn(m_ptContextMenu);
if (nConn != -1)
DeleteConnection(nConn);
}
void CTextDiagramCtrl::OnReset()
{
if (MessageBox("Are you sure you want to reset the diagram", "Code Plotter", MB_YESNO) == IDYES)
ResetDiagram();
}
void CTextDiagramCtrl::SendNotification(UINT nCode, CPoint point)
{
TDNHDR tdn = { { *this, GetDlgCtrlID(), nCode }, { point.x, point.y } };
GetParent()->SendMessage(WM_NOTIFY, GetDlgCtrlID(), (LPARAM)&tdn);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -