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

📄 textviewmouse.cpp

📁 支持Unicode及Uniscribe的多语言输入的文本编辑器源码。
💻 CPP
📖 第 1 页 / 共 2 页
字号:
	// get the mouse's client-coordinates
	GetCursorPos(&pt);
	ScreenToClient(m_hWnd, &pt);

	//
	// scrolling up / down??
	//
	if(pt.y < rect.top)					
		dy = ScrollDir(m_nScrollCounter, pt.y - rect.top);

	else if(pt.y >= rect.bottom)	
		dy = ScrollDir(m_nScrollCounter, pt.y - rect.bottom);

	//
	// scrolling left / right?
	//
	if(pt.x < rect.left)					
		dx = ScrollDir(m_nScrollCounter, pt.x - rect.left);

	else if(pt.x > rect.right)		
		dx = ScrollDir(m_nScrollCounter, pt.x - rect.right);

	//
	// Scroll the window but don't update any invalid
	// areas - we will do this manually after we have 
	// repositioned the caret
	//
	HRGN hrgnUpdate = ScrollRgn(dx, dy, true);

	//
	// do the redraw now that the selection offsets are all 
	// pointing to the right places and the scroll positions are valid.
	//
	if(hrgnUpdate != NULL)
	{
		// We perform a "fake" WM_MOUSEMOVE for two reasons:
		//
		// 1. To get the cursor/caret/selection offsets set to the correct place
		//    *before* we redraw (so everything is synchronized correctly)
		//
		// 2. To invalidate any areas due to mouse-movement which won't
		//    get done until the next WM_MOUSEMOVE - and then it would
		//    be too late because we need to redraw *now*
		//
		OnMouseMove(0, pt.x, pt.y);

		// invalidate the area returned by ScrollRegion
		InvalidateRgn(m_hWnd, hrgnUpdate, FALSE);
		DeleteObject(hrgnUpdate);

		// the next time we process WM_PAINT everything 
		// should get drawn correctly!!
		UpdateWindow(m_hWnd);
	}
	
	// keep track of how many WM_TIMERs we process because
	// we might want to skip the next one
	m_nScrollCounter++;

	return 0;
}

//
//	Convert mouse(client) coordinates to a file-relative offset
//
//	Currently only uses the main font so will not support other
//	fonts introduced by syntax highlighting
//
BOOL TextView::MouseCoordToFilePos(	int		 mx,			// [in]  mouse x-coord
									int		 my,			// [in]  mouse x-coord
									ULONG	*pnLineNo,		// [out] line number
									ULONG	*pnFileOffset,  // [out] zero-based file-offset (in chars)
									int		*psnappedX		// [out] adjusted x coord of caret
									)
{
	ULONG nLineNo;
	ULONG off_chars;
	RECT  rect;
	int	  cp;

	// get scrollable area
	GetClientRect(m_hWnd, &rect);
	rect.bottom -= rect.bottom % m_nLineHeight;

	// take left margin into account
	mx -= LeftMarginWidth();
		
	// clip mouse to edge of window
	if(mx < 0)				mx = 0;
	if(my < 0)				my = 0;
	if(my >= rect.bottom)	my = rect.bottom - 1;
	if(mx >= rect.right)	mx = rect.right  - 1;

	// It's easy to find the line-number: just divide 'y' by the line-height
	nLineNo = (my / m_nLineHeight) + m_nVScrollPos;
	
	// make sure we don't go outside of the document
	if(nLineNo >= m_nLineCount)
	{
		nLineNo   = m_nLineCount ? m_nLineCount - 1 : 0;
		off_chars = m_pTextDoc->size();
	}

	mx += m_nHScrollPos * m_nFontWidth;

	// get the USPDATA object for the selected line!!
	USPDATA *uspData = GetUspData(0, nLineNo);

	// convert mouse-x coordinate to a character-offset relative to start of line
	UspSnapXToOffset(uspData, mx, &mx, &cp, 0);
	
	// return coords!
	TextIterator itor = m_pTextDoc->iterate_line(nLineNo, &off_chars);
	*pnLineNo		= nLineNo;
	*pnFileOffset	= cp + off_chars;
	*psnappedX		= mx;// - m_nHScrollPos * m_nFontWidth;
	//*psnappedX		+= LeftMarginWidth();

	return 0;
}

LONG TextView::InvalidateLine(ULONG nLineNo, bool forceAnalysis)
{
	if(nLineNo >= m_nVScrollPos && nLineNo <= m_nVScrollPos + m_nWindowLines)
	{
		RECT rect;
		
		GetClientRect(m_hWnd, &rect);
		
		rect.top    = (nLineNo - m_nVScrollPos) * m_nLineHeight;
		rect.bottom = rect.top + m_nLineHeight;
	
		InvalidateRect(m_hWnd, &rect, FALSE);
	}

	if(forceAnalysis)
	{
		for(int i = 0; i < USP_CACHE_SIZE; i++)
		{
			if(nLineNo == m_uspCache[i].lineno)
			{
				m_uspCache[i].usage = 0;
				break;
			}
		}
	}

	return 0;
}
//
//	Redraw any line which spans the specified range of text
//
LONG TextView::InvalidateRange(ULONG nStart, ULONG nFinish)
{
	ULONG start  = min(nStart, nFinish);
	ULONG finish = max(nStart, nFinish);
	
	int   ypos;
	RECT  rect;
	RECT  client;
	TextIterator itor;

	// information about current line:
	ULONG lineno;
	ULONG off_chars;
	ULONG len_chars;

	// nothing to do?
	if(start == finish)
		return 0;

	//
	//	Find the start-of-line information from specified file-offset
	//
	lineno = m_pTextDoc->lineno_from_offset(start);

	// clip to top of window
	if(lineno < m_nVScrollPos)
	{
		lineno = m_nVScrollPos;
		itor   = m_pTextDoc->iterate_line(lineno, &off_chars, &len_chars);
		start  = off_chars;
	}
	else
	{
		itor   = m_pTextDoc->iterate_line(lineno, &off_chars, &len_chars);
	}

	if(!itor || start >= finish)
		return 0;

	ypos = (lineno - m_nVScrollPos) * m_nLineHeight;
	GetClientRect(m_hWnd, &client);

	// invalidate *whole* lines. don't care about flickering anymore because
	// all output is double-buffered now, and this method is much simpler
	while(itor && off_chars < finish)
	{
		SetRect(&rect, 0, ypos, client.right, ypos + m_nLineHeight);
		rect.left -= m_nHScrollPos * m_nFontWidth;
		rect.left += LeftMarginWidth();
			
		InvalidateRect(m_hWnd, &rect, FALSE);

		// jump down to next line
		itor  = m_pTextDoc->iterate_line(++lineno, &off_chars, &len_chars);
		ypos += m_nLineHeight;
	}

	return 0;
}
/*
//
//	Wrapper around SetCaretPos, hides the caret when it goes
//  off-screen (this protects against x/y wrap around due to integer overflow)
//
VOID TextView::MoveCaret(int x, int y)
{
	if(x < LeftMarginWidth() && m_fHideCaret == false)
	{
		m_fHideCaret = true;
		HideCaret(m_hWnd);
	}
	else if(x >= LeftMarginWidth() && m_fHideCaret == true)
	{
		m_fHideCaret = false;
		ShowCaret(m_hWnd);
	}

	if(m_fHideCaret == false)
		SetCaretPos(x, y);
}*/

//
//	x		- x-coord relative to start of line
//	lineno	- line-number
//
VOID TextView::UpdateCaretXY(int xpos, ULONG lineno)
{
	bool visible = false;

	// convert x-coord to window-relative
	xpos -= m_nHScrollPos * m_nFontWidth;
	xpos += LeftMarginWidth();

	// only show caret if it is visible within viewport
	if(lineno >= m_nVScrollPos && lineno <= m_nVScrollPos + m_nWindowLines)
	{
		if(xpos >= LeftMarginWidth())
			visible = true;
	}

	// hide caret if it was previously visible
	if(visible == false && m_fHideCaret == false)
	{
		m_fHideCaret = true;
		HideCaret(m_hWnd);
	}
	// show caret if it was previously hidden
	else if(visible == true && m_fHideCaret == true)
	{
		m_fHideCaret = false;
		ShowCaret(m_hWnd);
	}

	// set caret position if within window viewport
	if(m_fHideCaret == false)
	{
		SetCaretPos(xpos, (lineno - m_nVScrollPos) * m_nLineHeight);
	}
}

//
//	Reposition the caret based on cursor-offset
//	return the resulting x-coord and line#
//
VOID TextView::UpdateCaretOffset(ULONG offset, BOOL fTrailing, int *outx, ULONG *outlineno)
{
	ULONG		lineno = 0;
	int			xpos = 0;
	ULONG		off_chars;
	USPDATA	  * uspData;

	// get line information from cursor-offset
	if(m_pTextDoc->lineinfo_from_offset(offset, &lineno, &off_chars, 0, 0, 0))
	{
		// locate the USPDATA for this line
		if((uspData = GetUspData(NULL, lineno)) != 0)
		{	
			// convert character-offset to x-coordinate
			off_chars = m_nCursorOffset - off_chars;
			
			if(fTrailing && off_chars > 0)
				UspOffsetToX(uspData, off_chars-1, TRUE, &xpos);
			else
				UspOffsetToX(uspData, off_chars, FALSE, &xpos);

			// update caret position
			UpdateCaretXY(xpos, lineno);
		}
	}
	
	if(outx)	  *outx = xpos;
	if(outlineno) *outlineno = lineno;
}

VOID TextView::RepositionCaret()
{
	UpdateCaretXY(m_nCaretPosX, m_nCurrentLine);
}

//
//	Set the caret position based on m_nCursorOffset,
//	typically used whilst scrolling 
//	(i.e. not due to mouse clicks/keyboard input)
//
/*
ULONG TextView::RepositionCaret(POINT *pt)
{
	int   xpos   = 0;
	int   ypos   = 0;

	ULONG lineno;
	ULONG off_chars;

	USPDATA *uspData;

	// get line information from cursor-offset
	TextIterator itor = m_pTextDoc->iterate_line_offset(m_nCursorOffset, &lineno, &off_chars);

	if(!itor)
		return 0;

	if((uspData = GetUspData(NULL, lineno)) != 0)
	{
		off_chars = m_nCursorOffset - off_chars;
		UspOffsetToX(uspData, off_chars, FALSE, &xpos);
	}

	// y-coordinate from line-number
	ypos = (lineno - m_nVScrollPos) * m_nLineHeight;

	if(pt)
	{
		pt->x = xpos;
		pt->y = ypos;
	}

	// take horizontal scrollbar into account
	xpos -= m_nHScrollPos * m_nFontWidth;

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

	MoveCaret(xpos, ypos);

	return 0;
}
*/
void TextView::UpdateLine(ULONG nLineNo)
{
	// redraw the old and new lines if they are different
	if(m_nCurrentLine != nLineNo)
	{
		if(CheckStyle(TXS_HIGHLIGHTCURLINE))
			InvalidateLine(m_nCurrentLine, true);

		m_nCurrentLine = nLineNo;

		if(CheckStyle(TXS_HIGHLIGHTCURLINE))
			InvalidateLine(m_nCurrentLine, true);
	}
}

//
//	return direction to scroll (+ve, -ve or 0) based on 
//  distance of mouse from window edge
//
//	note: counter now redundant, we scroll multiple lines at
//  a time (with a slower timer than before) to achieve
//	variable-speed scrolling
//
int ScrollDir(int counter, int distance)
{
	if(distance > 48)		return 5;
	if(distance > 16)		return 2;
	if(distance > 3)		return 1;
	if(distance > 0)		return counter % 5 == 0 ? 1 : 0;
	
	if(distance < -48)		return -5;
	if(distance < -16)		return -2;
	if(distance < -3)		return -1;
	if(distance < 0)		return counter % 5 == 0 ? -1 : 0;

	return 0;
}



⌨️ 快捷键说明

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