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

📄 textviewscroll.cpp

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

#define STRICT
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <tchar.h>
#include "TextView.h"
#include "TextViewInternal.h"

bool IsKeyPressed(UINT nVirtKey);

//
//	Set scrollbar positions and range
//
VOID TextView::SetupScrollbars()
{
	SCROLLINFO si = { sizeof(si) };

	si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE | SIF_DISABLENOSCROLL;

	//
	//	Vertical scrollbar
	//
	si.nPos  = m_nVScrollPos;		// scrollbar thumb position
	si.nPage = m_nWindowLines;		// number of lines in a page
	si.nMin  = 0;					
	si.nMax  = m_nLineCount - 1;	// total number of lines in file
	
	SetScrollInfo(m_hWnd, SB_VERT, &si, TRUE);

	//
	//	Horizontal scrollbar
	//
	si.nPos  = m_nHScrollPos;		// scrollbar thumb position
	si.nPage = m_nWindowColumns;	// number of lines in a page
	si.nMin  = 0;
	si.nMax  = m_nLongestLine - 1;	// total number of lines in file

	SetScrollInfo(m_hWnd, SB_HORZ, &si, TRUE);

	// adjust our interpretation of the max scrollbar range to make
	// range-checking easier. The scrollbars don't use these values, they
	// are for our own use.
	m_nVScrollMax = m_nLineCount   - m_nWindowLines;
	m_nHScrollMax = m_nLongestLine - m_nWindowColumns;
}

//
//	Ensure that we never scroll off the end of the file
//
bool TextView::PinToBottomCorner()
{
	bool repos = false;

	if(m_nHScrollPos + m_nWindowColumns > m_nLongestLine)
	{
		m_nHScrollPos = m_nLongestLine - m_nWindowColumns;
		repos = true;
	}

	if(m_nVScrollPos + m_nWindowLines > m_nLineCount)
	{
		m_nVScrollPos = m_nLineCount - m_nWindowLines;
		repos = true;
	}

	return repos;
}

//
//	The window has changed size - update the scrollbars
//
LONG TextView::OnSize(UINT nFlags, int width, int height)
{
	int margin = LeftMarginWidth();

	m_nWindowLines   = min((unsigned)height		/ m_nLineHeight, m_nLineCount);
	m_nWindowColumns = min((width - margin)		/ m_nFontWidth,  m_nLongestLine);

	if(PinToBottomCorner())
	{
		RefreshWindow();
		RepositionCaret();
	}
	
	SetupScrollbars();

	return 0;
}

//
//	ScrollRgn
//
//	Scrolls the viewport in specified direction. If fReturnUpdateRgn is true, 
//	then a HRGN is returned which holds the client-region that must be redrawn 
//	manually. This region must be deleted by the caller using DeleteObject.
//
//  Otherwise ScrollRgn returns NULL and updates the entire window 
//
HRGN TextView::ScrollRgn(int dx, int dy, bool fReturnUpdateRgn)
{
	RECT clip;

	GetClientRect(m_hWnd, &clip);

	//
	// make sure that dx,dy don't scroll us past the edge of the document!
	//

	// scroll up
	if(dy < 0)
	{
		dy = -(int)min((ULONG)-dy, m_nVScrollPos);
		clip.top = -dy * m_nLineHeight;
	}
	// scroll down
	else if(dy > 0)
	{
		dy = min((ULONG)dy, m_nVScrollMax-m_nVScrollPos);
		clip.bottom = (m_nWindowLines -dy) * m_nLineHeight;
	}


	// scroll left
	if(dx < 0)
	{
		dx = -(int)min(-dx, m_nHScrollPos);
		clip.left = -dx * m_nFontWidth * 4;
	}
	// scroll right
	else if(dx > 0)
	{
		dx = min((unsigned)dx, (unsigned)m_nHScrollMax-m_nHScrollPos);
		clip.right = (m_nWindowColumns - dx - 4) * m_nFontWidth ;
	}

	// adjust the scrollbar thumb position
	m_nHScrollPos += dx;
	m_nVScrollPos += dy;

	// ignore clipping rectangle if its a whole-window scroll
	if(fReturnUpdateRgn == false)
		GetClientRect(m_hWnd, &clip);

	// take margin into account
	clip.left += LeftMarginWidth();

	// perform the scroll
	if(dx != 0 || dy != 0)
	{
		// do the scroll!
		ScrollWindowEx(
			m_hWnd, 
			-dx * m_nFontWidth,					// scale up to pixel coords
			-dy * m_nLineHeight,
			NULL,								// scroll entire window
			&clip,								// clip the non-scrolling part
			0, 
			0, 
			SW_INVALIDATE
			);

		SetupScrollbars();

		if(fReturnUpdateRgn)
		{
			RECT client;

			GetClientRect(m_hWnd, &client);

			//clip.left -= LeftMarginWidth();

			HRGN hrgnClient  = CreateRectRgnIndirect(&client);
			HRGN hrgnUpdate  = CreateRectRgnIndirect(&clip);

			// create a region that represents the area outside the
			// clipping rectangle (i.e. the part that is never scrolled)
			CombineRgn(hrgnUpdate, hrgnClient, hrgnUpdate, RGN_XOR);

			DeleteObject(hrgnClient);

			return hrgnUpdate;
		}
	}

	if(dy != 0)
	{
		GetClientRect(m_hWnd, &clip);
		clip.right = LeftMarginWidth();
		//ScrollWindow(m_hWnd, 0, -dy * m_nLineHeight, 0, &clip);
		InvalidateRect(m_hWnd, &clip, 0);
	}

	return NULL;
}

//
//	Scroll viewport in specified direction
//
VOID TextView::Scroll(int dx, int dy)
{
	// do a "normal" scroll - don't worry about invalid regions,
	// just scroll the whole window 
	ScrollRgn(dx, dy, false);
}

//
//	Ensure that the specified file-location is visible within
//  the window-viewport, Scrolling the viewport as necessary
//
VOID TextView::ScrollToPosition(int xpos, ULONG lineno)
{
	bool fRefresh = false;
	RECT rect;
	int  marginWidth = LeftMarginWidth();

	GetClientRect(m_hWnd, &rect);

	xpos -= m_nHScrollPos * m_nFontWidth;
	xpos += marginWidth;
	
	if(xpos < marginWidth)
	{
		m_nHScrollPos -= (marginWidth - xpos) / m_nFontWidth;
		fRefresh = true;
	}

	if(xpos >= rect.right)
	{
		m_nHScrollPos += (xpos - rect.right) / m_nFontWidth + 1;
		fRefresh = true;
	}
	
	if(lineno < m_nVScrollPos)
	{
		m_nVScrollPos = lineno;
		fRefresh = true;
	}
	else if(lineno > m_nVScrollPos + m_nWindowLines - 1)
	{
		m_nVScrollPos = lineno - m_nWindowLines + 1;
		fRefresh = true;
	}


	if(fRefresh)
	{
		SetupScrollbars();
		RefreshWindow();
		RepositionCaret();
	}
}

VOID TextView::ScrollToCaret()
{
	ScrollToPosition(m_nCaretPosX, m_nCurrentLine);
}

LONG GetTrackPos32(HWND hwnd, int nBar)
{
	SCROLLINFO si = { sizeof(si), SIF_TRACKPOS };
	GetScrollInfo(hwnd, nBar, &si);
	return si.nTrackPos;
}

//
//	Vertical scrollbar support
//
LONG TextView::OnVScroll(UINT nSBCode, UINT nPos)
{
	ULONG oldpos = m_nVScrollPos;

	switch(nSBCode)
	{
	case SB_TOP:
		m_nVScrollPos = 0;
		RefreshWindow();
		break;

	case SB_BOTTOM:
		m_nVScrollPos = m_nVScrollMax;
		RefreshWindow();
		break;

	case SB_LINEUP:
		Scroll(0, -1);
		break;

	case SB_LINEDOWN:
		Scroll(0, 1);
		break;

	case SB_PAGEDOWN:
		Scroll(0, m_nWindowLines);
		break;

	case SB_PAGEUP:
		Scroll(0, -m_nWindowLines);
		break;

	case SB_THUMBPOSITION:
	case SB_THUMBTRACK:

		m_nVScrollPos = GetTrackPos32(m_hWnd, SB_VERT);
		RefreshWindow();

		break;
	}

	if(oldpos != m_nVScrollPos)
	{
		SetupScrollbars();
		RepositionCaret();
	}


	return 0;
}

//
//	Horizontal scrollbar support
//
LONG TextView::OnHScroll(UINT nSBCode, UINT nPos)
{
	int oldpos = m_nHScrollPos;

	switch(nSBCode)
	{
	case SB_LEFT:
		m_nHScrollPos = 0;
		RefreshWindow();
		break;

	case SB_RIGHT:
		m_nHScrollPos = m_nHScrollMax;
		RefreshWindow();
		break;

	case SB_LINELEFT:
		Scroll(-1, 0);
		break;

	case SB_LINERIGHT:
		Scroll(1, 0);
		break;

	case SB_PAGELEFT:
		Scroll(-m_nWindowColumns, 0);
		break;

	case SB_PAGERIGHT:
		Scroll(m_nWindowColumns, 0);
		break;

	case SB_THUMBPOSITION:
	case SB_THUMBTRACK:

		m_nHScrollPos = GetTrackPos32(m_hWnd, SB_HORZ);
		RefreshWindow();
		break;
	}

	if(oldpos != m_nHScrollPos)
	{
		SetupScrollbars();
		RepositionCaret();
	}

	return 0;
}

LONG TextView::OnMouseWheel(int nDelta)
{
#ifndef	SPI_GETWHEELSCROLLLINES	
#define SPI_GETWHEELSCROLLLINES   104
#endif

	if(!IsKeyPressed(VK_SHIFT))
	{
		int nScrollLines;

		SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &nScrollLines, 0);

		if(nScrollLines <= 1)
			nScrollLines = 3;

		Scroll(0, (-nDelta/120) * nScrollLines);
		RepositionCaret();
	}
	
	return 0;
}

⌨️ 快捷键说明

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