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

📄 textview.cpp

📁 支持Unicode及Uniscribe的多语言输入的文本编辑器源码。
💻 CPP
字号:
//
//	MODULE:		TextView.cpp
//
//	PURPOSE:	Implementation of the TextView control
//
//	NOTES:		www.catch22.net
//
#define _WIN32_WINNT 0x501
#define STRICT
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <tchar.h>
#include <stdio.h>

// for the EM_xxx message constants
#include <richedit.h>

#include "TextView.h"
#include "TextViewInternal.h"
#include "racursor.h"

#if !defined(UNICODE)
#error "Please build as Unicode only!"
#endif

#if !defined(GetWindowLongPtr)
#error "Latest Platform SDK is required to build Neatpad - try PSDK-Feb-2003
#endif

#pragma comment(lib, "comctl32.lib")

//
//	Constructor for TextView class
//
TextView::TextView(HWND hwnd)
{
	m_hWnd = hwnd;

	m_hTheme = OpenThemeData(hwnd, L"edit");

	// Font-related data
	m_nNumFonts		= 1;
	m_nHeightAbove	= 0;
	m_nHeightBelow	= 0;
	
	// File-related data
	m_nLineCount   = 0;
	m_nLongestLine = 0;	
	

	// Scrollbar related data
	m_nVScrollPos = 0;
	m_nHScrollPos = 0;
	m_nVScrollMax = 0;
	m_nHScrollMax = 0;

	// Display-related data
	m_nTabWidthChars = 4;
	m_uStyleFlags	 = 0;
	m_nCaretWidth	 = 0;
	m_nLongLineLimit = 80;
	m_nLineInfoCount = 0;
	m_nCRLFMode		 = TXL_CRLF;//ALL;

	// allocate the USPDATA cache
	m_uspCache		= new USPCACHE[USP_CACHE_SIZE];
	
	for(int i = 0; i < USP_CACHE_SIZE; i++)
	{
		m_uspCache[i].usage   = 0;
		m_uspCache[i].lineno  = 0;
		m_uspCache[i].uspData = UspAllocate();
	}

	SystemParametersInfo(SPI_GETCARETWIDTH, 0, &m_nCaretWidth, 0);

	if(m_nCaretWidth == 0)
		m_nCaretWidth = 2;

	// Default display colours
	m_rgbColourList[TXC_FOREGROUND]		= SYSCOL(COLOR_WINDOWTEXT);
	m_rgbColourList[TXC_BACKGROUND]		= SYSCOL(COLOR_WINDOW);			// RGB(34,54,106)
	m_rgbColourList[TXC_HIGHLIGHTTEXT]	= SYSCOL(COLOR_HIGHLIGHTTEXT);
	m_rgbColourList[TXC_HIGHLIGHT]		= SYSCOL(COLOR_HIGHLIGHT);
	m_rgbColourList[TXC_HIGHLIGHTTEXT2]	= SYSCOL(COLOR_WINDOWTEXT);//INACTIVECAPTIONTEXT);
	m_rgbColourList[TXC_HIGHLIGHT2]		= SYSCOL(COLOR_3DFACE);//INACTIVECAPTION);
	m_rgbColourList[TXC_SELMARGIN1]		= SYSCOL(COLOR_3DFACE);
	m_rgbColourList[TXC_SELMARGIN2]		= SYSCOL(COLOR_3DHIGHLIGHT);
	m_rgbColourList[TXC_LINENUMBERTEXT]	= SYSCOL(COLOR_3DSHADOW);
	m_rgbColourList[TXC_LINENUMBER]		= SYSCOL(COLOR_3DFACE);
	m_rgbColourList[TXC_LONGLINETEXT]	= SYSCOL(COLOR_3DSHADOW);
	m_rgbColourList[TXC_LONGLINE]		= SYSCOL(COLOR_3DFACE);
	m_rgbColourList[TXC_CURRENTLINETEXT] = SYSCOL(COLOR_WINDOWTEXT);
	m_rgbColourList[TXC_CURRENTLINE]	 = RGB(230,240,255);


	// Runtime data
	m_nSelectionMode	= SEL_NONE;
	m_nEditMode			= MODE_INSERT;
	m_nScrollTimer		= 0;
	m_fHideCaret		= false;
	m_hUserMenu			= 0;
	m_hImageList		= 0;
	
	m_nSelectionStart	= 0;
	m_nSelectionEnd		= 0;
	m_nSelectionType	= SEL_NONE;
	m_nCursorOffset		= 0;
	m_nCurrentLine		= 0;

	m_nLinenoWidth		= 0;
	m_nCaretPosX		= 0;
	m_nAnchorPosX		= 0;

	//SetRect(&m_rcBorder, 2, 2, 2, 2);

	m_pTextDoc = new TextDocument();

	m_hMarginCursor = CreateCursor(GetModuleHandle(0), 21, 5, 32, 32, XORMask, ANDMask);
	
	//
	//	The TextView state must be fully initialized before we
	//	start calling member-functions
	//

	memset(m_uspFontList, 0, sizeof(m_uspFontList));

	// Set the default font
	OnSetFont((HFONT)GetStockObject(ANSI_FIXED_FONT));

	UpdateMetrics();
	UpdateMarginWidth();
}

//
//	Destructor for TextView class
//
TextView::~TextView()
{
	if(m_pTextDoc)
		delete m_pTextDoc;

	DestroyCursor(m_hMarginCursor);

	for(int i = 0; i < USP_CACHE_SIZE; i++)
		UspFree(m_uspCache[i].uspData);

	CloseThemeData(m_hTheme);
}

ULONG TextView::NotifyParent(UINT nNotifyCode, NMHDR *optional)
{
	UINT  nCtrlId = GetWindowLong(m_hWnd, GWL_ID);
	NMHDR nmhdr   = { m_hWnd, nCtrlId, nNotifyCode };
	NMHDR *nmptr  = &nmhdr;  
	
	if(optional)
	{
		nmptr  = optional;
		*nmptr = nmhdr;
	}

	return SendMessage(GetParent(m_hWnd), WM_NOTIFY, (WPARAM)nCtrlId, (LPARAM)nmptr);
}

VOID TextView::UpdateMetrics()
{
	RECT rect;
	GetClientRect(m_hWnd, &rect);

	OnSize(0, rect.right, rect.bottom);
	RefreshWindow();

	RepositionCaret();
}

LONG TextView::OnSetFocus(HWND hwndOld)
{
	CreateCaret(m_hWnd, (HBITMAP)NULL, m_nCaretWidth, m_nLineHeight);
	RepositionCaret();

	ShowCaret(m_hWnd);
	RefreshWindow();
	return 0;
}

LONG TextView::OnKillFocus(HWND hwndNew)
{
	// if we are making a selection when we lost focus then
	// stop the selection logic
	if(m_nSelectionMode != SEL_NONE)
	{
		OnLButtonUp(0, 0, 0);
	}

	HideCaret(m_hWnd);
	DestroyCaret();
	RefreshWindow();
	return 0;
}

ULONG TextView::SetStyle(ULONG uMask, ULONG uStyles)
{
	ULONG oldstyle = m_uStyleFlags;

	m_uStyleFlags  = (m_uStyleFlags & ~uMask) | uStyles;

	ResetLineCache();

	// update display here
	UpdateMetrics();
	RefreshWindow();

	return oldstyle;
}

ULONG TextView::SetVar(ULONG nVar, ULONG nValue)
{
	return 0;//oldval;
}

ULONG TextView::GetVar(ULONG nVar)
{
	return 0;
}

ULONG TextView::GetStyleMask(ULONG uMask)
{
	return m_uStyleFlags & uMask;
}
	
bool TextView::CheckStyle(ULONG uMask)
{
	return (m_uStyleFlags & uMask) ? true : false;
}

int TextView::SetCaretWidth(int nWidth)
{
	int oldwidth = m_nCaretWidth;
	m_nCaretWidth  = nWidth;

	return oldwidth;
}

BOOL TextView::SetImageList(HIMAGELIST hImgList)
{
	m_hImageList = hImgList;
	return TRUE;
}

LONG TextView::SetLongLine(int nLength)
{
	int oldlen = m_nLongLineLimit;
	m_nLongLineLimit = nLength;
	return oldlen;
}

int CompareLineInfo(LINEINFO *elem1, LINEINFO *elem2)
{
	if(elem1->nLineNo < elem2->nLineNo)
		return -1;
	if(elem1->nLineNo > elem2->nLineNo)
		return 1;
	else
		return 0;
}

int TextView::SetLineImage(ULONG nLineNo, ULONG nImageIdx)
{
	LINEINFO *linfo = GetLineInfo(nLineNo);

	// if already a line with an image
	if(linfo)
	{
		linfo->nImageIdx = nImageIdx;
	}
	else
	{
		linfo = &m_LineInfo[m_nLineInfoCount++];
		linfo->nLineNo = nLineNo;
		linfo->nImageIdx = nImageIdx;

		// sort the array
		qsort(
			m_LineInfo, 
			m_nLineInfoCount, 
			sizeof(LINEINFO), 
			(COMPAREPROC)CompareLineInfo
			);

	}
	return 0;
}

LINEINFO* TextView::GetLineInfo(ULONG nLineNo)
{
	LINEINFO key = { nLineNo, 0 };

	// perform the binary search
	return (LINEINFO *)	bsearch(
							&key, 
							m_LineInfo,
							m_nLineInfoCount, 
							sizeof(LINEINFO), 
							(COMPAREPROC)CompareLineInfo
							);
}

ULONG TextView::SelectionSize()
{
	ULONG s1 = min(m_nSelectionStart, m_nSelectionEnd); 
	ULONG s2 = max(m_nSelectionStart, m_nSelectionEnd); 
	return s2 - s1;
}

ULONG TextView::SelectAll()
{
	m_nSelectionStart = 0;
	m_nSelectionEnd   = m_pTextDoc->size();
	m_nCursorOffset   = m_nSelectionEnd;

	Smeg(TRUE);
	RefreshWindow();
	return 0;
}

//
//	Public memberfunction 
//
LONG WINAPI TextView::WndProc(UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch(msg)
	{
	// Draw contents of TextView whenever window needs updating
	case WM_ERASEBKGND:
		return 1;

	// Need to custom-draw the border for XP/Vista themes
	case WM_NCPAINT:
		return OnNcPaint((HRGN)wParam);

	case WM_PAINT:
		return OnPaint();

	// Set a new font 
	case WM_SETFONT:
		return OnSetFont((HFONT)wParam);

	case WM_SIZE:
		return OnSize(wParam, LOWORD(lParam), HIWORD(lParam));

	case WM_VSCROLL:
		return OnVScroll(LOWORD(wParam), HIWORD(wParam));

	case WM_HSCROLL:
		return OnHScroll(LOWORD(wParam), HIWORD(wParam));

	case WM_MOUSEACTIVATE:
		return OnMouseActivate((HWND)wParam, LOWORD(lParam), HIWORD(lParam));

	case WM_CONTEXTMENU:
		return OnContextMenu((HWND)wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));

	case WM_MOUSEWHEEL:
		return OnMouseWheel((short)HIWORD(wParam));

	case WM_SETFOCUS:
		return OnSetFocus((HWND)wParam);

	case WM_KILLFOCUS:
		return OnKillFocus((HWND)wParam);

	// make sure we get arrow-keys, enter, tab, etc when hosted inside a dialog
	case WM_GETDLGCODE:
		return DLGC_WANTALLKEYS;

	case WM_LBUTTONDOWN:
		return OnLButtonDown(wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));

	case WM_LBUTTONUP:
		return OnLButtonUp(wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));

	case WM_LBUTTONDBLCLK:
		return OnLButtonDblClick(wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));

	case WM_MOUSEMOVE:
		return OnMouseMove(wParam, (short)LOWORD(lParam), (short)HIWORD(lParam));

	case WM_KEYDOWN:
		return OnKeyDown(wParam, lParam);

	case WM_UNDO: case TXM_UNDO: case EM_UNDO:
		return Undo();

	case TXM_REDO: case EM_REDO:
		return Redo();

	case TXM_CANUNDO: case EM_CANUNDO:
		return CanUndo();

	case TXM_CANREDO: case EM_CANREDO:
		return CanRedo();

	case WM_CHAR:
		return OnChar(wParam, lParam);

	case WM_SETCURSOR:
		
		if(LOWORD(lParam) == HTCLIENT)
			return TRUE;

		break;

	case WM_COPY:
		return OnCopy();

	case WM_CUT:
		return OnCut();

	case WM_PASTE:
		return OnPaste();

	case WM_CLEAR:
		return OnClear();

	case WM_GETTEXT:
		return 0;

	case WM_TIMER:
		return OnTimer(wParam);

	//
	case TXM_OPENFILE:
		return OpenFile((TCHAR *)lParam);

	case TXM_CLEAR:
		return ClearFile();

	case TXM_SETLINESPACING:
		return SetLineSpacing(wParam, lParam);

	case TXM_ADDFONT:
		return AddFont((HFONT)wParam);

	case TXM_SETCOLOR:
		return SetColour(wParam, lParam);

	case TXM_SETSTYLE:
		return SetStyle(wParam, lParam);

	case TXM_SETCARETWIDTH:
		return SetCaretWidth(wParam);

	case TXM_SETIMAGELIST:
		return SetImageList((HIMAGELIST)wParam);

	case TXM_SETLONGLINE:
		return SetLongLine(lParam);

	case TXM_SETLINEIMAGE:
		return SetLineImage(wParam, lParam);

	case TXM_GETFORMAT:
		return m_pTextDoc->getformat();

	case TXM_GETSELSIZE:
		return SelectionSize();

	case TXM_SETSELALL:
		return SelectAll();

	case TXM_GETCURPOS:
		return m_nCursorOffset;

	case TXM_GETCURLINE:
		return m_nCurrentLine;

	case TXM_GETCURCOL:
		ULONG nOffset;
		GetUspData(0, m_nCurrentLine, &nOffset);
		return m_nCursorOffset - nOffset;

	case TXM_GETEDITMODE:
		return m_nEditMode;

	case TXM_SETEDITMODE:
		lParam		= m_nEditMode;
		m_nEditMode = wParam;
		return lParam;

	case TXM_SETCONTEXTMENU:
		m_hUserMenu = (HMENU)wParam;
		return 0;

	default:
		break;
	}

	return DefWindowProc(m_hWnd, msg, wParam, lParam);
}

//
//	Win32 TextView window procedure stub
//
LRESULT WINAPI TextViewWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	TextView *ptv = (TextView *)GetWindowLongPtr(hwnd, 0);

	switch(msg)
	{
	// First message received by any window - make a new TextView object
	// and store pointer to it in our extra-window-bytes
	case WM_NCCREATE:

		if((ptv = new TextView(hwnd)) == 0)
			return FALSE;

		SetWindowLongPtr(hwnd, 0, (LONG)ptv);
		return TRUE;

	// Last message received by any window - delete the TextView object
	case WM_NCDESTROY:
		delete ptv;
		SetWindowLongPtr(hwnd, 0, 0);
		return 0;

	// Pass everything to the TextView window procedure
	default:
		if(ptv)
			return ptv->WndProc(msg, wParam, lParam);
		else
			return 0;
	}
}

//
//	Register the TextView window class
//
BOOL InitTextView()
{
	WNDCLASSEX	wcx;

	//Window class for the main application parent window
	wcx.cbSize			= sizeof(wcx);
	wcx.style			= CS_DBLCLKS;
	wcx.lpfnWndProc		= TextViewWndProc;
	wcx.cbClsExtra		= 0;
	wcx.cbWndExtra		= sizeof(TextView *);
	wcx.hInstance		= GetModuleHandle(0);
	wcx.hIcon			= 0;
	wcx.hCursor			= LoadCursor (NULL, IDC_IBEAM);
	wcx.hbrBackground	= (HBRUSH)0;		//NO FLICKERING FOR US!!
	wcx.lpszMenuName	= 0;
	wcx.lpszClassName	= TEXTVIEW_CLASS;	
	wcx.hIconSm			= 0;

	return RegisterClassEx(&wcx) ? TRUE : FALSE;
}

//
//	Create a TextView control!
//
HWND CreateTextView(HWND hwndParent)
{
	return CreateWindowEx(WS_EX_CLIENTEDGE, 
//		L"EDIT", L"",
		TEXTVIEW_CLASS, _T(""), 
		WS_VSCROLL |WS_HSCROLL | WS_CHILD | WS_VISIBLE,
		0, 0, 0, 0, 
		hwndParent, 
		0, 
		GetModuleHandle(0), 
		0);
}

⌨️ 快捷键说明

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