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

📄 coolscroll.c

📁 功能强大的自制滚动条
💻 C
📖 第 1 页 / 共 5 页
字号:
/*
    Cool Scrollbar Library Version 1.2

    Module: coolscroll.c
	Copyright (c) J Brown 2001
	  
	This code is freeware, however, you may not publish
	this code elsewhere or charge any money for it. This code
	is supplied as-is. I make no guarantees about the suitability
	of this code - use at your own risk.
	
	It would be nice if you credited me, in the event
	that you use this code in a product.
	
	VERSION HISTORY:

	 V1.2: TreeView problem fixed by Diego Tartara
		   Small problem in thumbsize calculation also fixed (thanks Diego!)

	 V1.1: Added support for Right-left windows
	       Changed calling convention of APIs to WINAPI (__stdcall)
		   Completely standalone (no need for c-runtime)
		   Now supports ALL windows with appropriate USER32.DLL patching
		    (you provide!!)

	 V1.0: Apr 2001: Initial Version

  IMPORTANT:
	 This whole library is based around code for a horizontal scrollbar.
	 All "vertical" scrollbar drawing / mouse interaction uses the
	 horizontal scrollbar functions, but uses a trick to convert the vertical
	 scrollbar coordinates into horizontal equivelants. When I started this project,
	 I quickly realised that the code for horz/vert bars was IDENTICAL, apart
	 from the fact that horizontal code uses left/right coords, and vertical code
	 uses top/bottom coords. On entry to a "vertical" drawing function, for example,
	 the coordinates are "rotated" before the horizontal function is called, and
	 then rotated back once the function has completed. When something needs to
	 be drawn, the coords are converted back again before drawing.
	 
     This trick greatly reduces the amount of code required, and makes
	 maintanence much simpler. This way, only one function is needed to draw
	 a scrollbar, but this can be used for both horizontal and vertical bars
	 with careful thought.
*/
#define STRICT
#define WIN32_LEAN_AND_MEAN

#include <windows.h>
#include <commctrl.h>
#include <tchar.h>
#include "coolscroll.h"
#include "userdefs.h"
#include "coolsb_internal.h"

//define some values if the new version of common controls
//is not available.
#ifndef NM_CUSTOMDRAW
#define NM_CUSTOMDRAW (NM_FIRST-12)
#define CDRF_DODEFAULT		0x0000
#define CDRF_SKIPDEFAULT	0x0004
#define CDDS_PREPAINT		0x0001
#define CDDS_POSTPAINT		0x0002
#endif

//
//	Special thumb-tracking variables
//
//
static UINT uCurrentScrollbar = COOLSB_NONE;	//SB_HORZ / SB_VERT
static UINT uCurrentScrollPortion = HTSCROLL_NONE;
static UINT uCurrentButton = 0;

static RECT rcThumbBounds;		//area that the scroll thumb can travel in
static int  nThumbSize;			//(pixels)
static int  nThumbPos;			//(pixels)
static int  nThumbMouseOffset;	//(pixels)
static int  nLastPos = -1;		//(scrollbar units)
static int  nThumbPos0;			//(pixels) initial thumb position

//
//	Temporary state used to auto-generate timer messages
//
static UINT uMouseOverId = 0;
static UINT uMouseOverScrollbar = COOLSB_NONE;
static UINT uHitTestPortion = HTSCROLL_NONE;
static UINT uLastHitTestPortion = HTSCROLL_NONE;
static RECT MouseOverRect;

static UINT uScrollTimerMsg = 0;
static UINT uScrollTimerPortion = HTSCROLL_NONE;
static UINT uScrollTimerId = 0;
static HWND hwndCurCoolSB = 0;

//
//	Provide this so there are NO dependencies on CRT
//
static void CoolSB_ZeroMemory(void *ptr, DWORD bytes)
{
	BYTE *bptr = (BYTE *)ptr;

	while(bytes--) *bptr++ = 0;
}

BOOL WINAPI CoolSB_IsThumbTracking(HWND hwnd)	
{ 
	SCROLLWND *sw;

	if((sw = GetScrollWndFromHwnd(hwnd)) == NULL)
		return FALSE;
	else
		return sw->fThumbTracking; 
}

//
//	swap the rectangle's x coords with its y coords
//
static void __stdcall RotateRect(RECT *rect)
{
	int temp;
	temp = rect->left;
	rect->left = rect->top;
	rect->top = temp;

	temp = rect->right;
	rect->right = rect->bottom;
	rect->bottom = temp;
}

//
//	swap the coords if the scrollbar is a SB_VERT
//
static void __stdcall RotateRect0(SCROLLBAR *sb, RECT *rect)
{
	if(sb->nBarType == SB_VERT)
		RotateRect(rect);
}

//
//	Calculate if the SCROLLINFO members produce
//  an enabled or disabled scrollbar
//
static BOOL IsScrollInfoActive(SCROLLINFO *si)
{
	if((si->nPage > (UINT)si->nMax
		|| si->nMax <= si->nMin || si->nMax == 0))
		return FALSE;
	else
		return TRUE;
}

//
//	Return if the specified scrollbar is enabled or not
//
static BOOL IsScrollbarActive(SCROLLBAR *sb)
{
	SCROLLINFO *si = &sb->scrollInfo;
	if(((sb->fScrollFlags & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH) ||
		!(sb->fScrollFlags & CSBS_THUMBALWAYS) && !IsScrollInfoActive(si))
		return FALSE;
	else
		return TRUE;
}

//
//	Draw a standard scrollbar arrow
//
static int DrawScrollArrow(SCROLLBAR *sbar, HDC hdc, RECT *rect, UINT arrow, BOOL fMouseDown, BOOL fMouseOver)
{
	UINT ret;
	UINT flags = arrow;

	//HACKY bit so this routine can be called by vertical and horizontal code
	if(sbar->nBarType == SB_VERT)
	{
		if(flags & DFCS_SCROLLLEFT)		flags = flags & ~DFCS_SCROLLLEFT  | DFCS_SCROLLUP;
		if(flags & DFCS_SCROLLRIGHT)	flags = flags & ~DFCS_SCROLLRIGHT | DFCS_SCROLLDOWN;
	}

	if(fMouseDown) flags |= (DFCS_FLAT | DFCS_PUSHED);

#ifdef FLAT_SCROLLBARS
	if(sbar->fFlatScrollbar != CSBS_NORMAL)
	{
		HDC hdcmem1, hdcmem2;
		HBITMAP hbm1, oldbm1;
		HBITMAP hbm2, oldbm2;
		RECT rc;
		int width, height;

		rc = *rect;
		width  = rc.right-rc.left;
		height = rc.bottom-rc.top;
		SetRect(&rc, 0, 0, width, height);

		//MONOCHROME bitmap to convert the arrow to black/white mask
		hdcmem1 = CreateCompatibleDC(hdc);
		hbm1    = CreateBitmap(width, height, 1, 1, NULL);
		UnrealizeObject(hbm1);
		oldbm1  = SelectObject(hdcmem1, hbm1);
		

		//NORMAL bitmap to draw the arrow into
		hdcmem2 = CreateCompatibleDC(hdc);
		hbm2    = CreateCompatibleBitmap(hdc, width, height);
		UnrealizeObject(hbm2);
		oldbm2  = SelectObject(hdcmem2, hbm2);
		

		flags = flags & ~DFCS_PUSHED | DFCS_FLAT;	//just in case
		DrawFrameControl(hdcmem2, &rc, DFC_SCROLL, flags);


#ifndef HOT_TRACKING
		if(fMouseDown)
		{
			//uncomment these to make the cool scrollbars
			//look like the common controls flat scrollbars
			//fMouseDown = FALSE;
			//fMouseOver = TRUE;
		}
#endif
		//draw a flat monochrome version of a scrollbar arrow (dark)
		if(fMouseDown)
		{
			SetBkColor(hdcmem2, GetSysColor(COLOR_BTNTEXT));
			BitBlt(hdcmem1, 0, 0, width, height, hdcmem2, 0, 0, SRCCOPY);
			SetBkColor(hdc, 0x00ffffff);
			SetTextColor(hdc, GetSysColor(COLOR_3DDKSHADOW));
			BitBlt(hdc, rect->left, rect->top, width, height, hdcmem1, 0, 0, SRCCOPY);
		}
		//draw a flat monochrome version of a scrollbar arrow (grey)
		else if(fMouseOver)
		{
			SetBkColor(hdcmem2, GetSysColor(COLOR_BTNTEXT));
			FillRect(hdcmem1, &rc, GetStockObject(WHITE_BRUSH));
			BitBlt(hdcmem1, 0, 0, width, height, hdcmem2, 0, 0, SRCINVERT);

			SetBkColor(hdc, GetSysColor(COLOR_3DSHADOW));
			SetTextColor(hdc, 0x00ffffff);
			BitBlt(hdc, rect->left, rect->top, width, height, hdcmem1, 0, 0, SRCCOPY);
		}
		//draw the arrow normally
		else
		{
			BitBlt(hdc, rect->left, rect->top, width, height, hdcmem2, 0, 0, SRCCOPY);
		}

		SelectObject(hdcmem1, oldbm1);
		SelectObject(hdcmem2, oldbm2);
		DeleteObject(hbm1);
		DeleteObject(hbm2);
		DeleteDC(hdcmem1);
		DeleteDC(hdcmem2);

		ret = 0;
	}
	else
#endif
	ret = DrawFrameControl(hdc, rect, DFC_SCROLL, flags);

	return ret;
}

//
//	Return the size in pixels for the specified scrollbar metric,
//  for the specified scrollbar
//
static int GetScrollMetric(SCROLLBAR *sbar, int metric)
{
	if(sbar->nBarType == SB_HORZ)
	{
		if(metric == SM_CXHORZSB)
		{
			if(sbar->nArrowLength < 0)
				return -sbar->nArrowLength * GetSystemMetrics(SM_CXHSCROLL);
			else
				return sbar->nArrowLength;
		}
		else
		{
			if(sbar->nArrowWidth < 0)
				return -sbar->nArrowWidth * GetSystemMetrics(SM_CYHSCROLL);
			else
				return sbar->nArrowWidth;
		}
	}
	else if(sbar->nBarType == SB_VERT)
	{
		if(metric == SM_CYVERTSB)
		{
			if(sbar->nArrowLength < 0)
				return -sbar->nArrowLength * GetSystemMetrics(SM_CYVSCROLL);
			else
				return sbar->nArrowLength;
		}
		else
		{
			if(sbar->nArrowWidth < 0)
				return -sbar->nArrowWidth * GetSystemMetrics(SM_CXVSCROLL);
			else
				return sbar->nArrowWidth;
		}
	}

	return 0;
}

//
//	
//
static COLORREF GetSBForeColor(void)
{
	COLORREF c1 = GetSysColor(COLOR_3DHILIGHT);
	COLORREF c2 = GetSysColor(COLOR_WINDOW);

	if(c1 != 0xffffff && c1 == c2)
	{
		return GetSysColor(COLOR_BTNFACE);
	}
	else
	{
		return GetSysColor(COLOR_3DHILIGHT);
	}
}

static COLORREF GetSBBackColor(void)
{
	return GetSysColor(COLOR_SCROLLBAR);
}

//
//	Paint a checkered rectangle, with each alternate
//	pixel being assigned a different colour
//
static void DrawCheckedRect(HDC hdc, RECT *rect, COLORREF fg, COLORREF bg)
{
	static WORD wCheckPat[8] = 
	{ 
		0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555, 0xaaaa, 0x5555 
	};

	HBITMAP hbmp;
	HBRUSH  hbr, hbrold;
	COLORREF fgold, bgold;

	hbmp = CreateBitmap(8, 8, 1, 1, wCheckPat);
	hbr  = CreatePatternBrush(hbmp);

	UnrealizeObject(hbr);
	SetBrushOrgEx(hdc, rect->left, rect->top, 0);

	hbrold = (HBRUSH)SelectObject(hdc, hbr);

	fgold = SetTextColor(hdc, fg);
	bgold = SetBkColor(hdc, bg);
	
	PatBlt(hdc, rect->left, rect->top, 
				rect->right - rect->left, 
				rect->bottom - rect->top, 
				PATCOPY);
	
	SetBkColor(hdc, bgold);
	SetTextColor(hdc, fgold);
	
	SelectObject(hdc, hbrold);
	DeleteObject(hbr);
	DeleteObject(hbmp);
}

//
//	Fill the specifed rectangle using a solid colour
//
static void PaintRect(HDC hdc, RECT *rect, COLORREF color)
{
	COLORREF oldcol = SetBkColor(hdc, color);
	ExtTextOut(hdc, 0, 0, ETO_OPAQUE, rect, _T(""), 0, 0);
	SetBkColor(hdc, oldcol);
}

//
//	Draw a simple blank scrollbar push-button. Can be used
//	to draw a push button, or the scrollbar thumb
//	drawflag - could set to BF_FLAT to make flat scrollbars
//
void DrawBlankButton(HDC hdc, const RECT *rect, UINT drawflag)
{
	RECT rc = *rect;
		
#ifndef FLAT_SCROLLBARS	
	drawflag &= ~BF_FLAT;
#endif
	
	DrawEdge(hdc, &rc, EDGE_RAISED, BF_RECT | drawflag | BF_ADJUST);
	FillRect(hdc, &rc, GetSysColorBrush(COLOR_BTNFACE));
}

//
//	Send a WM_VSCROLL or WM_HSCROLL message
//
static void SendScrollMessage(HWND hwnd, UINT scrMsg, UINT scrId, UINT pos)
{
	SendMessage(hwnd, scrMsg, MAKEWPARAM(scrId, pos), 0);
}

//
//	Calculate the screen coordinates of the area taken by
//  the horizontal scrollbar. Take into account the size
//  of the window borders
//
static BOOL GetHScrollRect(SCROLLWND *sw, HWND hwnd, RECT *rect)
{
	GetWindowRect(hwnd, rect);
	
	if(sw->fLeftScrollbar)
	{
		rect->left  += sw->cxLeftEdge + (sw->sbarVert.fScrollVisible ? 
					GetScrollMetric(&sw->sbarVert, SM_CXVERTSB) : 0);
		rect->right -= sw->cxRightEdge;
	}
	else
	{
		rect->left   += sw->cxLeftEdge;					//left window edge
	
		rect->right  -= sw->cxRightEdge +				//right window edge
					(sw->sbarVert.fScrollVisible ? 
					GetScrollMetric(&sw->sbarVert, SM_CXVERTSB) : 0);
	}
	
	rect->bottom -= sw->cyBottomEdge;				//bottom window edge
	
	rect->top	  = rect->bottom -
					(sw->sbarHorz.fScrollVisible ?
					GetScrollMetric(&sw->sbarHorz, SM_CYHORZSB) : 0);
	
	return TRUE;
}

//
//	Calculate the screen coordinates of the area taken by the
//  vertical scrollbar
//
static BOOL GetVScrollRect(SCROLLWND *sw, HWND hwnd, RECT *rect)
{
	GetWindowRect(hwnd, rect);
	rect->top	 += sw->cyTopEdge;						//top window edge
	
	rect->bottom -= sw->cyBottomEdge + 
					(sw->sbarHorz.fScrollVisible ?		//bottom window edge
					GetScrollMetric(&sw->sbarHorz, SM_CYHORZSB) : 0);

	if(sw->fLeftScrollbar)
	{
		rect->left	+= sw->cxLeftEdge;
		rect->right = rect->left + (sw->sbarVert.fScrollVisible ?
					GetScrollMetric(&sw->sbarVert, SM_CXVERTSB) : 0);
	}
	else
	{
		rect->right  -= sw->cxRightEdge;
		rect->left    = rect->right - (sw->sbarVert.fScrollVisible ?	
					GetScrollMetric(&sw->sbarVert, SM_CXVERTSB) : 0);
	}

	return TRUE;
}

//	Depending on what type of scrollbar nBar refers to, call the
//  appropriate Get?ScrollRect function
//
BOOL GetScrollRect(SCROLLWND *sw, UINT nBar, HWND hwnd, RECT *rect)
{
	if(nBar == SB_HORZ)
		return GetHScrollRect(sw, hwnd, rect);
	else if(nBar == SB_VERT)
		return GetVScrollRect(sw, hwnd, rect);
	else
		return FALSE;
}

//
//	This code is a prime candidate for splitting out into a separate
//  file at some stage
//
#ifdef INCLUDE_BUTTONS

//
//	Calculate the size in pixels of the specified button
//
static int GetSingleButSize(SCROLLBAR *sbar, SCROLLBUT *sbut)
{
	//multiple of the system button size
	//or a specific button size
	if(sbut->nSize < 0)
	{
		if(sbar->nBarType == SB_HORZ)
			return -sbut->nSize * GetSystemMetrics(SM_CXHSCROLL);
		else 
			return -sbut->nSize * GetSystemMetrics(SM_CYVSCROLL);
	}
	else
		return  sbut->nSize;

⌨️ 快捷键说明

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