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

📄 coolscroll.c

📁 功能强大的自制滚动条
💻 C
📖 第 1 页 / 共 5 页
字号:
}

//
//	Find the size in pixels of all the inserted buttons,
//	either before or after the specified scrollbar
//
static int GetButtonSize(SCROLLBAR *sbar, HWND hwnd, UINT uBeforeAfter)
{
	int i;
	int nPixels = 0;

	SCROLLBUT *sbut = sbar->sbButtons;
	
	for(i = 0; i < sbar->nButtons; i++)
	{
		//only consider those buttons on the same side as nTopBottom says
		if(sbut[i].uPlacement == uBeforeAfter)
		{
			nPixels += GetSingleButSize(sbar, &sbut[i]);
		}
	}

	return nPixels;
}
#endif //INCLUDE_BUTTONS

//
//	Work out the scrollbar width/height for either type of scrollbar (SB_HORZ/SB_VERT)
//	rect - coords of the scrollbar.
//	store results into *thumbsize and *thumbpos
//
static int CalcThumbSize(SCROLLBAR *sbar, const RECT *rect, int *pthumbsize, int *pthumbpos)
{
	SCROLLINFO *si;
	int scrollsize;			//total size of the scrollbar including arrow buttons
	int workingsize;		//working area (where the thumb can slide)
	int siMaxMin;
	int butsize;
	int startcoord;
	int thumbpos = 0, thumbsize = 0;

	int adjust=0;
	static int count=0;

	//work out the width (for a horizontal) or the height (for a vertical)
	//of a standard scrollbar button
	butsize = GetScrollMetric(sbar, SM_SCROLL_LENGTH);

	if(1) //sbar->nBarType == SB_HORZ)
	{
		scrollsize = rect->right - rect->left;
		startcoord = rect->left;
	}
	/*else if(sbar->nBarType == SB_VERT)
	{
		scrollsize = rect->bottom - rect->top;
		startcoord = rect->top;
	}
	else
	{
		return 0;
	}*/

	si = &sbar->scrollInfo;
	siMaxMin = si->nMax - si->nMin + 1;
	workingsize = scrollsize - butsize * 2;

	//
	// Work out the scrollbar thumb SIZE
	//
	if(si->nPage == 0)
	{
		thumbsize = butsize;
	}
	else if(siMaxMin > 0)
	{
		thumbsize = MulDiv(si->nPage, workingsize, siMaxMin);

		if(thumbsize < sbar->nMinThumbSize)
			thumbsize = sbar->nMinThumbSize;
	}

	//
	// Work out the scrollbar thumb position
	//
	if(siMaxMin > 0)
	{
		int pagesize = max(1, si->nPage);
		thumbpos = MulDiv(si->nPos - si->nMin, workingsize-thumbsize, siMaxMin - pagesize);
		
		if(thumbpos < 0)						
			thumbpos = 0;

		if(thumbpos >= workingsize-thumbsize)	
			thumbpos = workingsize-thumbsize;
	}

	thumbpos += startcoord + butsize;

	*pthumbpos  = thumbpos;
	*pthumbsize = thumbsize;

	return 1;
}

//
//	return a hit-test value for whatever part of the scrollbar x,y is located in
//	rect, x, y: SCREEN coordinates
//	the rectangle must not include space for any inserted buttons 
//	(i.e, JUST the scrollbar area)
//
static UINT GetHorzScrollPortion(SCROLLBAR *sbar, HWND hwnd, const RECT *rect, int x, int y)
{
	int thumbwidth, thumbpos;
	int butwidth = GetScrollMetric(sbar, SM_SCROLL_LENGTH);
	int scrollwidth  = rect->right-rect->left;
	int workingwidth = scrollwidth - butwidth*2;

	if(y < rect->top || y >= rect->bottom)
		return HTSCROLL_NONE;

	CalcThumbSize(sbar, rect, &thumbwidth, &thumbpos);

	//if we have had to scale the buttons to fit in the rect,
	//then adjust the button width accordingly
	if(scrollwidth <= butwidth * 2)
	{
		butwidth = scrollwidth / 2;	
	}

	//check for left button click
	if(x >= rect->left && x < rect->left + butwidth)
	{
		return HTSCROLL_LEFT;	
	}
	//check for right button click
	else if(x >= rect->right-butwidth && x < rect->right)
	{
		return HTSCROLL_RIGHT;
	}
	
	//if the thumb is too big to fit (i.e. it isn't visible)
	//then return a NULL scrollbar area
	if(thumbwidth >= workingwidth)
		return HTSCROLL_NONE;
	
	//check for point in the thumbbar
	if(x >= thumbpos && x < thumbpos+thumbwidth)
	{
		return HTSCROLL_THUMB;
	}	
	//check for left margin
	else if(x >= rect->left+butwidth && x < thumbpos)
	{
		return HTSCROLL_PAGELEFT;
	}
	else if(x >= thumbpos+thumbwidth && x < rect->right-butwidth)
	{
		return HTSCROLL_PAGERIGHT;
	}
	
	return HTSCROLL_NONE;
}

//
//	For vertical scrollbars, rotate all coordinates by -90 degrees
//	so that we can use the horizontal version of this function
//
static UINT GetVertScrollPortion(SCROLLBAR *sb, HWND hwnd, RECT *rect, int x, int y)
{
	UINT r;
	
	RotateRect(rect);
	r = GetHorzScrollPortion(sb, hwnd, rect, y, x);
	RotateRect(rect);
	return r;
}

//
//	CUSTOM DRAW support
//	
static LRESULT PostCustomPrePostPaint0(HWND hwnd, HDC hdc, SCROLLBAR *sb, UINT dwStage)
{
#ifdef CUSTOM_DRAW
	NMCSBCUSTOMDRAW	nmcd;

	CoolSB_ZeroMemory(&nmcd, sizeof nmcd);
	nmcd.hdr.hwndFrom = hwnd;
	nmcd.hdr.idFrom   = GetWindowLong(hwnd, GWL_ID);
	nmcd.hdr.code     = NM_COOLSB_CUSTOMDRAW;
	nmcd.nBar		  = sb->nBarType;
	nmcd.dwDrawStage  = dwStage;
	nmcd.hdc		  = hdc;

	hwnd = GetParent(hwnd);
	return SendMessage(hwnd, WM_NOTIFY, 0, (LPARAM)&nmcd);
#else
	return 0;
#endif
}

static LRESULT PostCustomDrawNotify0(HWND hwnd, HDC hdc, UINT nBar, RECT *prect, UINT nItem, BOOL fMouseDown, BOOL fMouseOver, BOOL fInactive)
{
#ifdef CUSTOM_DRAW
	NMCSBCUSTOMDRAW	nmcd;

	//fill in the standard header
	nmcd.hdr.hwndFrom = hwnd;
	nmcd.hdr.idFrom   = GetWindowLong(hwnd, GWL_ID);
	nmcd.hdr.code     = NM_COOLSB_CUSTOMDRAW;

	nmcd.dwDrawStage  = CDDS_ITEMPREPAINT;
	nmcd.nBar		  = nBar;
	nmcd.rect		  = *prect;
	nmcd.uItem		  = nItem;
	nmcd.hdc		  = hdc;

	if(fMouseDown) 
		nmcd.uState		  = CDIS_SELECTED;
	else if(fMouseOver)
		nmcd.uState		  = CDIS_HOT;
	else if(fInactive)
		nmcd.uState		  = CDIS_DISABLED;
	else
		nmcd.uState		  = CDIS_DEFAULT;

	hwnd = GetParent(hwnd);
	return SendMessage(hwnd, WM_NOTIFY, nmcd.hdr.idFrom, (LPARAM)&nmcd);
#else
	return 0;
#endif
}

// Depending on if we are supporting custom draw, either define
// a macro to the function name, or to nothing at all. If custom draw
// is turned off, then we can save ALOT of code space by binning all 
// calls to the custom draw support.
//
#ifdef CUSTOM_DRAW
#define PostCustomDrawNotify	PostCustomDrawNotify0
#define PostCustomPrePostPaint	PostCustomPrePostPaint0
#else
#define PostCustomDrawNotify	1 ? (void)0 : PostCustomDrawNotify0
#define PostCustomPrePostPaint	1 ? (void)0 : PostCustomPrePostPaint0
#endif

static LRESULT PostMouseNotify0(HWND hwnd, UINT msg, UINT nBar, RECT *prect, UINT nCmdId, POINT pt)
{
#ifdef NOTIFY_MOUSE
	NMCOOLBUTMSG	nmcb;

	//fill in the standard header
	nmcb.hdr.hwndFrom	= hwnd;
	nmcb.hdr.idFrom		= GetWindowLong(hwnd, GWL_ID);
	nmcb.hdr.code		= NM_CLICK;

	nmcb.nBar			= nBar;
	nmcb.uCmdId			= nCmdId;
	nmcb.uState			= 0;
	nmcb.rect			= *prect;
	nmcb.pt				= pt;

	hwnd = GetParent(hwnd);
	return SendMessage(hwnd, WM_NOTIFY, nmcb.hdr.idFrom, (LPARAM)&nmcb);
#else
	return 0;
#endif
}

#ifdef NOTIFY_MOUSE
#define PostMouseNotify			PostMouseNotify0
#else
#define PostMouseNotify			1 ? (void)0 : PostMouseNotify0
#endif



//
//	Draw a complete HORIZONTAL scrollbar in the given rectangle
//	Don't draw any inserted buttons in this procedure
//	
//	uDrawFlags - hittest code, to say if to draw the
//  specified portion in an active state or not.
//
//
static LRESULT NCDrawHScrollbar(SCROLLBAR *sb, HWND hwnd, HDC hdc, const RECT *rect, UINT uDrawFlags)
{
	SCROLLINFO *si;
	RECT ctrl, thumb;
	RECT sbm;
	int butwidth	 = GetScrollMetric(sb, SM_SCROLL_LENGTH);
	int scrollwidth  = rect->right-rect->left;
	int workingwidth = scrollwidth - butwidth*2;
	int thumbwidth   = 0, thumbpos = 0;
	int siMaxMin;

	BOOL fCustomDraw = 0;

	BOOL fMouseDownL = 0, fMouseOverL = 0, fBarHot = 0;
	BOOL fMouseDownR = 0, fMouseOverR = 0;

	COLORREF crCheck1   = GetSBForeColor();
	COLORREF crCheck2   = GetSBBackColor();
	COLORREF crInverse1 = InvertCOLORREF(crCheck1);
	COLORREF crInverse2 = InvertCOLORREF(crCheck2);

	UINT uDFCFlat = sb->fFlatScrollbar ? DFCS_FLAT : 0;
	UINT uDEFlat  = sb->fFlatScrollbar ? BF_FLAT   : 0;

	//drawing flags to modify the appearance of the scrollbar buttons
	UINT uLeftButFlags  = DFCS_SCROLLLEFT;
	UINT uRightButFlags = DFCS_SCROLLRIGHT;

	if(scrollwidth <= 0)
		return 0;

	si = &sb->scrollInfo;
	siMaxMin = si->nMax - si->nMin;

	if(hwnd != hwndCurCoolSB)
		uDrawFlags = HTSCROLL_NONE;
	//
	// work out the thumb size and position
	//
	CalcThumbSize(sb, rect, &thumbwidth, &thumbpos);
	
	if(sb->fScrollFlags & ESB_DISABLE_LEFT)		uLeftButFlags  |= DFCS_INACTIVE;
	if(sb->fScrollFlags & ESB_DISABLE_RIGHT)	uRightButFlags |= DFCS_INACTIVE;

	//if we need to grey the arrows because there is no data to scroll
	if(!IsScrollInfoActive(si) && !(sb->fScrollFlags & CSBS_THUMBALWAYS))
	{
		uLeftButFlags  |= DFCS_INACTIVE;
		uRightButFlags |= DFCS_INACTIVE;
	}

	if(hwnd == hwndCurCoolSB)
	{
#ifdef FLAT_SCROLLBARS	
		BOOL ldis = !(uLeftButFlags & DFCS_INACTIVE);
		BOOL rdis = !(uRightButFlags & DFCS_INACTIVE);

		fBarHot = (sb->nBarType == (int)uMouseOverScrollbar && sb->fFlatScrollbar == CSBS_HOTTRACKED);
		
		fMouseOverL = uHitTestPortion == HTSCROLL_LEFT && fBarHot && ldis;		
		fMouseOverR = uHitTestPortion == HTSCROLL_RIGHT && fBarHot && rdis;
#endif
		fMouseDownL = (uDrawFlags == HTSCROLL_LEFT);
		fMouseDownR = (uDrawFlags == HTSCROLL_RIGHT);
	}


#ifdef CUSTOM_DRAW
	fCustomDraw = ((PostCustomPrePostPaint(hwnd, hdc, sb, CDDS_PREPAINT)) == CDRF_SKIPDEFAULT);
#endif

	//
	// Draw the scrollbar now
	//
	if(scrollwidth > butwidth*2)
	{
		//LEFT ARROW
		SetRect(&ctrl, rect->left, rect->top, rect->left + butwidth, rect->bottom);

		RotateRect0(sb, &ctrl);

		if(fCustomDraw)
			PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &ctrl, SB_LINELEFT, fMouseDownL, fMouseOverL, uLeftButFlags & DFCS_INACTIVE);
		else
			DrawScrollArrow(sb, hdc, &ctrl, uLeftButFlags, fMouseDownL, fMouseOverL);

		RotateRect0(sb, &ctrl);

		//MIDDLE PORTION
		//if we can fit the thumbbar in, then draw it
		if(thumbwidth > 0 && thumbwidth <= workingwidth
			&& IsScrollInfoActive(si) && ((sb->fScrollFlags & ESB_DISABLE_BOTH) != ESB_DISABLE_BOTH))
		{	
			//Draw the scrollbar margin above the thumb
			SetRect(&sbm, rect->left + butwidth, rect->top, thumbpos, rect->bottom);
			
			RotateRect0(sb, &sbm);
			
			if(fCustomDraw)
			{
				PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &sbm, SB_PAGELEFT, uDrawFlags == HTSCROLL_PAGELEFT, FALSE, FALSE);
			}
			else
			{
				if(uDrawFlags == HTSCROLL_PAGELEFT)
					DrawCheckedRect(hdc, &sbm, crInverse1, crInverse2);
				else
					DrawCheckedRect(hdc, &sbm, crCheck1, crCheck2);

			}

			RotateRect0(sb, &sbm);			
			
			//Draw the margin below the thumb
			sbm.left = thumbpos+thumbwidth;
			sbm.right = rect->right - butwidth;
			
			RotateRect0(sb, &sbm);
			if(fCustomDraw)
			{
				PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &sbm, SB_PAGERIGHT, uDrawFlags == HTSCROLL_PAGERIGHT, 0, 0);
			}
			else
			{
				if(uDrawFlags == HTSCROLL_PAGERIGHT)
					DrawCheckedRect(hdc, &sbm, crInverse1, crInverse2);
				else
					DrawCheckedRect(hdc, &sbm, crCheck1, crCheck2);
			
			}
			RotateRect0(sb, &sbm);
			
			//Draw the THUMB finally
			SetRect(&thumb, thumbpos, rect->top, thumbpos+thumbwidth, rect->bottom);

			RotateRect0(sb, &thumb);			

			if(fCustomDraw)
			{
				PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &thumb, SB_THUMBTRACK, uDrawFlags==HTSCROLL_THUMB, uHitTestPortion == HTSCROLL_THUMB && fBarHot, FALSE);
			}
			else
			{

#ifdef FLAT_SCROLLBARS	
				if(hwnd == hwndCurCoolSB && sb->fFlatScrollbar && (uDrawFlags == HTSCROLL_THUMB || 
				(uHitTestPortion == HTSCROLL_THUMB && fBarHot)))
				{	
					PaintRect(hdc, &thumb, GetSysColor(COLOR_3DSHADOW));
				}
				else
#endif
				{
					DrawBlankButton(hdc, &thumb, uDEFlat);
				}
			}
			RotateRect0(sb, &thumb);

		}
		//otherwise, just leave that whole area blank
		else
		{
			OffsetRect(&ctrl, butwidth, 0);
			ctrl.right = rect->right - butwidth;

			//if we always show the thumb covering the whole scrollbar,
			//then draw it that way
			if(!IsScrollInfoActive(si)	&& (sb->fScrollFlags & CSBS_THUMBALWAYS) 
				&& ctrl.right - ctrl.left > sb->nMinThumbSize)
			{
				//leave a 1-pixel gap between the thumb + right button
				ctrl.right --;
				RotateRect0(sb, &ctrl);

				if(fCustomDraw)
					PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &ctrl, SB_THUMBTRACK, fMouseDownL, FALSE, FALSE);
				else
				{
#ifdef FLAT_SCROLLBARS	
					if(sb->fFlatScrollbar == CSBS_HOTTRACKED && uDrawFlags == HTSCROLL_THUMB)
						PaintRect(hdc, &ctrl, GetSysColor(COLOR_3DSHADOW));
					else
#endif
						DrawBlankButton(hdc, &ctrl, uDEFlat);

				}
				RotateRect0(sb, &ctrl);

				//draw the single-line gap
				ctrl.left = ctrl.right;
				ctrl.right += 1;
				
				RotateRect0(sb, &ctrl);
				
				if(fCustomDraw)
					PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &ctrl, SB_PAGERIGHT, 0, 0, 0);
				else
					PaintRect(hdc, &ctrl, GetSysColor(COLOR_SCROLLBAR));

				RotateRect0(sb, &ctrl);
			}
			//otherwise, paint a blank if the thumb doesn't fit in
			else
			{
				RotateRect0(sb, &ctrl);
	
				if(fCustomDraw)
					PostCustomDrawNotify(hwnd, hdc, sb->nBarType, &ctrl, SB_PAGERIGHT, 0, 0, 0);
				else
					DrawCheckedRect(hdc, &ctrl, crCheck1, crCheck2);
				
				RotateRect0(sb, &ctrl);
			}
		}

		//RIGHT ARROW

⌨️ 快捷键说明

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