⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 textdiagramctrl.cpp

📁 TabBars的开源源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
// TextDiagramCtrl.cpp : implementation file
//

#include "stdafx.h"
#include "TextDiagramCtrl.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define CHARSIZE_X 8
#define CHARSIZE_Y 12
#define ARROWSIZE 6
#define IDC_EDITTEXT 101

enum 
{
	ID_RECT_DELETE = 32771,
	ID_RECT_EDITTEXT,
	ID_RECT_NEW,
	ID_CONN_NEW,
	ID_CONN_DELETE,
	ID_CONN_MODIFY,
	ID_RESET,
};

/////////////////////////////////////////////////////////////////////////////
// CTextDiagramCtrl

CTextDiagramCtrl::CTextDiagramCtrl() : 
	m_nSelRect(-1), m_ptScrollOffset(0, 0), m_bMoving(FALSE), m_nSizing(HTNOWHERE), 
	m_ptDragStart(0, 0), m_ptDragPrev(0, 0), m_editText("-|#*+", TRUE), m_bDblClick(FALSE), m_ptContextMenu(0, 0)

{
}

CTextDiagramCtrl::~CTextDiagramCtrl()
{
}


BEGIN_MESSAGE_MAP(CTextDiagramCtrl, CWnd)
	//{{AFX_MSG_MAP(CTextDiagramCtrl)
	ON_WM_PAINT()
	ON_WM_ERASEBKGND()
	ON_WM_LBUTTONDOWN()
	ON_WM_CREATE()
	ON_WM_HSCROLL()
	ON_WM_VSCROLL()
	ON_WM_SIZE()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	ON_WM_CAPTURECHANGED()
	ON_WM_NCHITTEST()
	ON_WM_SETCURSOR()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_GETDLGCODE()
	ON_WM_KEYDOWN()
	ON_WM_CONTEXTMENU()
	ON_COMMAND(ID_RECT_DELETE, OnRectDelete)
	ON_COMMAND(ID_RECT_EDITTEXT, OnRectEditText)
	ON_COMMAND(ID_RECT_NEW, OnRectNew)
	ON_COMMAND(ID_CONN_NEW, OnConnNew)
	ON_COMMAND(ID_CONN_DELETE, OnConnDelete)
	ON_COMMAND(ID_CONN_MODIFY, OnConnModify)
	ON_COMMAND(ID_RESET, OnReset)
	//}}AFX_MSG_MAP
	ON_EN_KILLFOCUS(IDC_EDITTEXT, OnEndTextEdit)
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CTextDiagramCtrl message handlers

BOOL CTextDiagramCtrl::Create(DWORD dwStyle, const RECT& rect, CWnd* pParent, UINT nID)
{
	return CWnd::Create(NULL, NULL, dwStyle | WS_HSCROLL | WS_VSCROLL, rect, pParent, nID);
}

void CTextDiagramCtrl::SetDiagram(const CTextDiagram& diagram)
{
	CTextDiagram::SetDiagram(diagram);

	m_nSelRect = -1;
	SendNotification(TDN_SELCHANGE);

	UpdateScrollbars();
	Invalidate();
}

void CTextDiagramCtrl::SetDiagram(LPCTSTR szDiagram)
{
	CTextDiagram::SetDiagram(szDiagram);

	m_nSelRect = -1;
	SendNotification(TDN_SELCHANGE);

	UpdateScrollbars();
	Invalidate();
}

void CTextDiagramCtrl::SetDiagram(const CStringArray& diagram)
{
	CTextDiagram::SetDiagram(diagram);

	m_nSelRect = -1;
	SendNotification(TDN_SELCHANGE);

	UpdateScrollbars();
	Invalidate();
}

void CTextDiagramCtrl::ResetDiagram()
{
	CTextDiagram::ResetDiagram();

	m_nSelRect = -1;
	SendNotification(TDN_SELCHANGE);

	UpdateScrollbars();
	Invalidate();
}

int CTextDiagramCtrl::AddRect(LPCRECT pRect, LPCTSTR szText)
{
	int nRect = CTextDiagram::AddRect(pRect, szText);

	if (nRect >= 0)
	{
		UpdateScrollbars();
		Invalidate();

		m_nSelRect = nRect;
		SendNotification(TDN_SELCHANGE);
	}

	return nRect;
}

int CTextDiagramCtrl::AddConnection(int nRectFrom, int nRectTo, int nSideFrom)
{
	int nConn = CTextDiagram::AddConnection(nRectFrom, nRectTo, nSideFrom);

	if (nConn >= 0)
	{
		UpdateScrollbars();
		Invalidate();
	}

	return nConn;
}

BOOL CTextDiagramCtrl::DeleteRect(int nRect)
{
	if (CTextDiagram::DeleteRect(nRect))
	{
		UpdateScrollbars();
		Invalidate();

		if (m_nSelRect == nRect)
		{
			m_nSelRect = -1;
			SendNotification(TDN_SELCHANGE);
		}

		return TRUE;
	}

	return FALSE;
}

BOOL CTextDiagramCtrl::DeleteConnection(int nConn)
{
	if (CTextDiagram::DeleteConnection(nConn))
	{
		UpdateScrollbars();
		Invalidate();

		return TRUE;
	}

	return FALSE;
}

BOOL CTextDiagramCtrl::SetRect(int nRect, const CTDRect& rect)
{
	if (CTextDiagram::SetRect(nRect, rect))
	{
		UpdateScrollbars();

		Invalidate();
		return TRUE;
	}

	return FALSE;
}

BOOL CTextDiagramCtrl::SetText(int nRect, LPCTSTR szText)
{
	if (CTextDiagram::SetText(nRect, szText))
	{
		Invalidate();
		return TRUE;
	}

	return FALSE;
}

BOOL CTextDiagramCtrl::SetConnection(int nConn, const CTDConnection& conn)
{
	if (CTextDiagram::SetConnection(nConn, conn))
	{
		UpdateScrollbars();

		Invalidate();
		return TRUE;
	}

	return FALSE;
}

void CTextDiagramCtrl::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	
	CRect rClient;
	GetClientRect(rClient);
	dc.IntersectClipRect(rClient);

	// draw rects
	dc.SelectStockObject(ANSI_FIXED_FONT);

	int nRect = 0;
	CTDRect rect;

	while (GetRect(nRect, rect))
	{
		DrawRect(&dc, rect, nRect == m_nSelRect);
		nRect++;
	}

	// draw connections
	int nConn = 0;
	CTDConnection conn;

	while (GetConnection(nConn, conn))
	{
		DrawConn(&dc, conn);
		nConn++;
	}
}

void CTextDiagramCtrl::DrawRect(CDC* pDC, const CTDRect& rect, BOOL bSelected)
{
	CRect rDraw(rect);
	LogicalToClient(rDraw);

	if (!rDraw.IsRectEmpty())
	{
		if (bSelected)
			pDC->FillSolidRect(rDraw, GetSysColor(COLOR_HIGHLIGHT));
		
		pDC->Draw3dRect(rDraw, 0, 0);

		// text
		rDraw.DeflateRect(CHARSIZE_X / 2, CHARSIZE_Y / 2);

		pDC->SetTextColor(GetSysColor(bSelected ? COLOR_HIGHLIGHTTEXT : COLOR_WINDOWTEXT));
		pDC->SetBkMode(TRANSPARENT);

		RenderText(pDC, rDraw, rect.GetText());
	}
}

void CTextDiagramCtrl::RenderText(CDC* pDC, const CRect& rect, const CString& sText)
{
	int nLen = sText.GetLength(), nX = rect.left, nY = rect.top;

	for (int nChar = 0; nChar < nLen && (nY + CHARSIZE_Y) < rect.bottom; nChar++)
	{
#ifdef _VER_CHINESE
		char c[3];
		c[0] = sText[nChar];

		// new line?
		if (c[0] == _T('\r'))
		{
			nX = rect.left;
			nY += CHARSIZE_Y;
			nChar++; // to account for the trailing '\n'
		}
		else if ( 
			(((c[0] & 0x80) != 0) && ((nX + 2 * CHARSIZE_X) >= rect.right)) || //it is a Chinese character,it need two bytes space
			(((c[0] & 0x80) == 0) && ((nX + CHARSIZE_X) >= rect.right))
			)
		{
			nX = rect.left;
			nY += CHARSIZE_Y;
			nChar--; // try again
		}
		else
		{
			if((c[0] & 0x80) != 0)//it is the first byte of a Chinese character
			{
				nChar++;
				c[1] = sText[nChar];
				c[2] = 0;
				pDC->ExtTextOut(nX, nY, 0, NULL, CString(c), NULL);
				nX +=  2 * CHARSIZE_X;
			}
			else
			{
				c[1] = 0;
				pDC->ExtTextOut(nX, nY, 0, NULL, CString(c), NULL);
				nX += CHARSIZE_X;
			}
		}
#else
		char c = sText[nChar];

		// new line?
		if (c == '\r')
		{
			nX = rect.left;
			nY += CHARSIZE_Y;
			nChar++; // to account for the trailing '\n'
		}
		else if ((nX + CHARSIZE_X) > rect.right)
		{
			nX = rect.left;
			nY += CHARSIZE_Y;
			nChar--; // try again
		}
		else
		{
			pDC->ExtTextOut(nX, nY, 0, NULL, CString(c), NULL);
			nX += CHARSIZE_X;
		}
#endif
	}
}

void CTextDiagramCtrl::DrawConn(CDC* pDC, const CTDConnection& conn)
{
	CPoint ptSegStart = conn.GetStartPos(), ptSegEnd;
	
	CPoint ptFrom(ptSegStart);
	ptFrom.x = ptFrom.x * CHARSIZE_X + CHARSIZE_X / 2;
	ptFrom.y = ptFrom.y * CHARSIZE_Y + CHARSIZE_Y / 2;
	
	CRect rStart(ptFrom.x - 1, ptFrom.y - 1, ptFrom.x + 2, ptFrom.y + 2);

	rStart.OffsetRect(-m_ptScrollOffset);
	ptFrom.Offset(-m_ptScrollOffset);

	pDC->FillSolidRect(rStart, 0);
	pDC->MoveTo(ptFrom);
	
	for (int nSeg = 0; nSeg < conn.NumSegments(); nSeg++)
	{
		CPoint ptTo, ptSegEnd = conn.GetSegmentPos(nSeg);
		
		ptTo.x = ptSegEnd.x * CHARSIZE_X + CHARSIZE_X / 2;
		ptTo.y = ptSegEnd.y * CHARSIZE_Y + CHARSIZE_Y / 2;
		
		ptTo.Offset(-m_ptScrollOffset);
		pDC->LineTo(ptTo);

		ptFrom = ptTo; // for drawing the arrow
	}
	
	DrawArrow(pDC, ptFrom, conn.GetEndDirection());
}

void CTextDiagramCtrl::DrawArrow(CDC* pDC, CPoint point, int nDirection)
{
	switch (nDirection)
	{
	case CONN_UP:
		pDC->MoveTo(point.x - ARROWSIZE, point.y + ARROWSIZE);
		pDC->LineTo(point);
		pDC->LineTo(point.x + (ARROWSIZE + 1), point.y + (ARROWSIZE + 1));
		break;

	case CONN_DOWN:
		pDC->MoveTo(point.x - ARROWSIZE, point.y - ARROWSIZE);
		pDC->LineTo(point);
		pDC->LineTo(point.x + (ARROWSIZE + 1), point.y - (ARROWSIZE + 1));
		break;

	case CONN_LEFT:
		pDC->MoveTo(point.x + ARROWSIZE, point.y - ARROWSIZE);
		pDC->LineTo(point);
		pDC->LineTo(point.x + (ARROWSIZE + 1), point.y + (ARROWSIZE + 1));
		break;

	case CONN_RIGHT:
		pDC->MoveTo(point.x - ARROWSIZE, point.y - ARROWSIZE);
		pDC->LineTo(point);
		pDC->LineTo(point.x - (ARROWSIZE + 1), point.y + (ARROWSIZE + 1));
		break;
	}
}

BOOL CTextDiagramCtrl::OnEraseBkgnd(CDC* pDC) 
{
	CRect rClient;
	GetClientRect(rClient);

	// clip out the selected item
	int nSaveDC = pDC->SaveDC();

	if (m_nSelRect != -1)
	{
		CTDRect rect;
		GetRect(m_nSelRect, rect);

		CRect rDraw(rect);
		LogicalToClient(rDraw);

		pDC->ExcludeClipRect(rDraw);
	}

	pDC->FillSolidRect(rClient, GetSysColor(COLOR_WINDOW));
	DrawGrid(pDC);

	pDC->RestoreDC(nSaveDC);
	
	return TRUE;
}

void CTextDiagramCtrl::DrawGrid(CDC* pDC)
{
	CRect rClient;
	GetClientRect(rClient);
	rClient |= GetBoundingRect();

	for (int nY = CHARSIZE_Y; nY < rClient.bottom; nY += CHARSIZE_Y)
	{
		if ((nY / CHARSIZE_Y) % 10)
			pDC->FillSolidRect(0, nY - m_ptScrollOffset.y, rClient.right, 1, RGB(192, 192, 192));
		else
			pDC->FillSolidRect(0, nY - m_ptScrollOffset.y, rClient.right, 1, RGB(160, 160, 160));
	}

	for (int nX = CHARSIZE_X; nX < rClient.right; nX += CHARSIZE_X)
	{
		if ((nX / CHARSIZE_X) % 10)
			pDC->FillSolidRect(nX - m_ptScrollOffset.x, 0, 1, rClient.bottom, RGB(192, 192, 192));
		else
			pDC->FillSolidRect(nX - m_ptScrollOffset.x, 0, 1, rClient.bottom, RGB(160, 160, 160));
	}
}

void CTextDiagramCtrl::OnLButtonDown(UINT nFlags, CPoint point) 
{
	CWnd::OnLButtonDown(nFlags, point);

	// always make sure existing edit is finished
	OnEndTextEdit();

	m_bDblClick = FALSE;
	SetFocus();

	// update selection
	point.Offset(m_ptScrollOffset);
	int nSel = IntersectRect(point.x / CHARSIZE_X, point.y / CHARSIZE_Y);

	if (nSel != m_nSelRect)
	{
		m_nSelRect = nSel;
		Invalidate();

		SendNotification(TDN_SELCHANGE);
	}

	if (nSel != -1)
	{
		// test for whether we are moving or sizing
		CTDRect rect;
		GetRect(m_nSelRect, rect);

		// deflate this and then check we're still inside
		CRect rDraw(rect);
		LogicalToClient(rDraw);

		rDraw.DeflateRect(2, 2);
		rDraw.OffsetRect(m_ptScrollOffset);

		if (!rDraw.PtInRect(point))
		{
			if (point.x <= rDraw.left)
				m_nSizing = HTLEFT;
			
			else if (point.x >= rDraw.right)
				m_nSizing = HTRIGHT;

			else if (point.y <= rDraw.top)
				m_nSizing = HTTOP;
			
			else if (point.y >= rDraw.bottom)
				m_nSizing = HTBOTTOM;

			else // ??
				ASSERT (0);
		}
		else
			m_bMoving = TRUE;
		
		m_ptDragStart = m_ptDragPrev = point;

		SetCapture();
	}
}

int CTextDiagramCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CWnd::OnCreate(lpCreateStruct) == -1)
		return -1;

	UpdateScrollbars();

	return 0;
}

void CTextDiagramCtrl::UpdateScrollbars()
{
	CRect rClient, rDiagram(GetBoundingRect());
	GetClientRect(rClient);

	CPoint ptOffset(m_ptScrollOffset);

	ShowScrollBar(SB_VERT, rClient.bottom < rDiagram.bottom);
	ShowScrollBar(SB_HORZ, rClient.right < rDiagram.right);

	if (rClient.bottom >= rDiagram.bottom)
		m_ptScrollOffset.y = 0;
	else
	{
		m_ptScrollOffset.y = min(m_ptScrollOffset.y, (rDiagram.bottom - rClient.bottom));

		// set proportional scrollbar
		SCROLLINFO si;
		
		si.cbSize = sizeof(si); 
		si.fMask = SIF_ALL & ~SIF_TRACKPOS; 
		si.nMin = 0; 
		si.nMax = rDiagram.bottom; 
		si.nPage = rClient.bottom; 
		si.nPos = m_ptScrollOffset.y; 
		si.nTrackPos = 0; 

		SetScrollInfo(SB_VERT, &si);
	}

	if (rClient.right >= rDiagram.right)
		m_ptScrollOffset.x = 0;
	else
	{
		m_ptScrollOffset.x = min(m_ptScrollOffset.x, (rDiagram.right - rClient.right));

		// set proportional scrollbar
		SCROLLINFO si;
		
		si.cbSize = sizeof(si); 
		si.fMask = SIF_ALL & ~SIF_TRACKPOS; 
		si.nMin = 0; 
		si.nMax = rDiagram.right; 
		si.nPage = rClient.right; 
		si.nPos = m_ptScrollOffset.x; 
		si.nTrackPos = 0; 

		SetScrollInfo(SB_HORZ, &si);
	}

	if (m_ptScrollOffset != ptOffset)
		Invalidate();
}

CRect CTextDiagramCtrl::GetBoundingRect()
{
	return CRect(0, 0, (m_size.cx + 1) * CHARSIZE_X, (m_size.cy + 1) * CHARSIZE_Y);
}

void CTextDiagramCtrl::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	CRect rClient, rDiagram(GetBoundingRect());
	GetClientRect(rClient);

	CPoint ptOffset(m_ptScrollOffset);
	
	switch (nSBCode)
	{
	case SB_LEFT:
		m_ptScrollOffset.x = 0;
		break;

	case SB_ENDSCROLL:
		break;

	case SB_LINELEFT:
		m_ptScrollOffset.x = max(m_ptScrollOffset.x - CHARSIZE_X, 0);
		break;

	case SB_LINERIGHT:
		m_ptScrollOffset.x = min(rDiagram.right - rClient.right, m_ptScrollOffset.x + CHARSIZE_X);
		break;

	case SB_PAGELEFT:
		m_ptScrollOffset.x = max(m_ptScrollOffset.x - CHARSIZE_X, 0);
		break;

	case SB_PAGERIGHT:
		m_ptScrollOffset.x = min(rDiagram.right - rClient.right, m_ptScrollOffset.x + CHARSIZE_X);
		break;

	case SB_RIGHT:
		m_ptScrollOffset.x = (rDiagram.right - rClient.right);
		break;

	case SB_THUMBPOSITION:
		m_ptScrollOffset.x = (nPos / CHARSIZE_X) * CHARSIZE_X;
		break;

	case SB_THUMBTRACK:
		m_ptScrollOffset.x = (nPos / CHARSIZE_X) * CHARSIZE_X;
		break;
	}

	if (m_ptScrollOffset != ptOffset)
	{
		Invalidate();
		UpdateScrollbars();
	}
	
	CWnd::OnHScroll(nSBCode, nPos, pScrollBar);
}

void CTextDiagramCtrl::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
{
	CRect rClient, rDiagram(GetBoundingRect());
	GetClientRect(rClient);

	CPoint ptOffset(m_ptScrollOffset);
	
	switch (nSBCode)
	{
	case SB_TOP:
		m_ptScrollOffset.y = 0;
		break;

	case SB_ENDSCROLL:
		break;

	case SB_LINEUP:
		m_ptScrollOffset.y = max(m_ptScrollOffset.y - CHARSIZE_Y, 0);
		break;

	case SB_LINEDOWN:
		m_ptScrollOffset.y = min(rDiagram.bottom - rClient.bottom, m_ptScrollOffset.y + CHARSIZE_Y);
		break;

	case SB_PAGEUP:
		m_ptScrollOffset.y = max(m_ptScrollOffset.y - CHARSIZE_Y, 0);
		break;

	case SB_PAGEDOWN:
		m_ptScrollOffset.y = min(rDiagram.bottom - rClient.bottom, m_ptScrollOffset.y + CHARSIZE_Y);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -