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

📄 scroll.c

📁 功能强大的自制滚动条
💻 C
📖 第 1 页 / 共 5 页
字号:
		//make sure there is room for the buttons
		vbarheight = rect.bottom - rect.top;

		//check that we can fit any left/right buttons in the available space
		if(sb->nButSizeAfter < (vbarheight - MIN_COOLSB_SIZE))
		{
			//adjust the scrollbar rectangle to fit the buttons into
			sb->fButVisibleAfter = TRUE;
			rect.bottom -= sb->nButSizeAfter;
			updown |= SBBP_BOTTOM;
			
			//check that there is enough space for the right buttons
			if(sb->nButSizeBefore + sb->nButSizeAfter < (vbarheight - MIN_COOLSB_SIZE))
			{
				sb->fButVisibleBefore = TRUE;
				rect.top += sb->nButSizeBefore;
				updown |= SBBP_TOP;
			}
			else
				sb->fButVisibleBefore = FALSE;
		}	
		else
			sb->fButVisibleAfter = FALSE;
		
	
		DrawVertButtons(sb, hdc, &rect, updown);
#endif // INCLUDE_BUTTONS

		if(uCurrentScrollbar == SB_VERT)
			fCustomDraw |= NCDrawVScrollbar(sb, hwnd, hdc, &rect, uScrollTimerPortion);
		else
			fCustomDraw |= NCDrawVScrollbar(sb, hwnd, hdc, &rect, HTSCROLL_NONE);
	}

	//Call the default window procedure for WM_NCPAINT, with the
	//new window region. ** region must be in SCREEN coordinates **
	dwStyle = GetWindowLong(hwnd, GWL_STYLE);

    // If the window has WS_(H-V)SCROLL bits set, we should reset them
    // to avoid windows taking the scrollbars into account.
    // We temporarily set a flag preventing the subsecuent 
    // WM_STYLECHANGING/WM_STYLECHANGED to be forwarded to 
    // the original window procedure
    if ( dwStyle & (WS_VSCROLL|WS_HSCROLL) )
    {
        sw->bPreventStyleChange = TRUE;
        SetWindowLong(hwnd, GWL_STYLE, dwStyle & ~(WS_VSCROLL|WS_HSCROLL));
    }
	
	ret = CallWindowProc(sw->oldproc, hwnd, WM_NCPAINT, (WPARAM)hrgn, lParam);
	
    if ( dwStyle & (WS_VSCROLL|WS_HSCROLL) )
    {
        SetWindowLong(hwnd, GWL_STYLE, dwStyle);
        sw->bPreventStyleChange = FALSE;
    }


	// DRAW THE DEAD AREA
	// only do this if the horizontal and vertical bars are visible
	if(sw->sbarHorz.fScrollVisible && sw->sbarVert.fScrollVisible)
	{
		GetWindowRect(hwnd, &rect);
		OffsetRect(&rect, -winrect.left, -winrect.top);

		rect.bottom -= sw->cyBottomEdge;
		rect.top  = rect.bottom - GetScrollMetric(&sw->sbarHorz, SM_CYHORZSB);

		if(sw->fLeftScrollbar)
		{
			rect.left += sw->cxLeftEdge;
			rect.right = rect.left + GetScrollMetric(&sw->sbarVert, SM_CXVERTSB);
		}
		else
		{
			rect.right -= sw->cxRightEdge;
			rect.left = rect.right  - GetScrollMetric(&sw->sbarVert, SM_CXVERTSB);
		}
		
		if(fCustomDraw)
			PostCustomDrawNotify(hwnd, hdc, SB_BOTH, &rect, 32, 0, 0, 0);
		else
		{
			//calculate the position of THIS window's dead area
			//with the position of the PARENT window's client rectangle.
			//if THIS window has been positioned such that its bottom-right
			//corner sits in the parent's bottom-right corner, then we should
			//show the sizing-grip.
			//Otherwise, assume this window is not in the right place, and
			//just draw a blank rectangle
			RECT parent;
			RECT rect2;
			HWND hwndParent = GetParent(hwnd);

			GetClientRect(hwndParent, &parent);
			MapWindowPoints(hwndParent, 0, (POINT *)&parent, 2);

			CopyRect(&rect2, &rect);
			OffsetRect(&rect2, winrect.left, winrect.top);

			if(!sw->fLeftScrollbar && parent.right == rect2.right+sw->cxRightEdge && parent.bottom == rect2.bottom+sw->cyBottomEdge
			 || sw->fLeftScrollbar && parent.left  == rect2.left -sw->cxLeftEdge  && parent.bottom == rect2.bottom+sw->cyBottomEdge)
				DrawFrameControl(hdc, &rect, DFC_SCROLL, sw->fLeftScrollbar ? DFCS_SCROLLSIZEGRIPRIGHT : DFCS_SCROLLSIZEGRIP );
			else
				PaintRect(hdc, &rect, GetSysColor(COLOR_3DFACE));
		}
	}

	UNREFERENCED_PARAMETER(clip);

	ReleaseDC(hwnd, hdc);
	return ret;
}

//
// Need to detect if we have clicked in the scrollbar region or not
//
static LRESULT NCHitTest(SCROLLWND *sw, HWND hwnd, WPARAM wParam, LPARAM lParam)
{
	RECT hrect;
	RECT vrect;
	POINT pt;

	pt.x = LOWORD(lParam);
	pt.y = HIWORD(lParam);
	
	//work out exactly where the Horizontal and Vertical scrollbars are
	GetHScrollRect(sw, hwnd, &hrect);
	GetVScrollRect(sw, hwnd, &vrect);
	
	//Clicked in the horizontal scrollbar area
	if(sw->sbarHorz.fScrollVisible && PtInRect(&hrect, pt))
	{
		return HTHSCROLL;
	}
	//Clicked in the vertical scrollbar area
	else if(sw->sbarVert.fScrollVisible && PtInRect(&vrect, pt))
	{
		return HTVSCROLL;
	}
	//clicked somewhere else
	else
	{
		return CallWindowProc(sw->oldproc, hwnd, WM_NCHITTEST, wParam, lParam);
	}
}

//
//	Return a HT* value indicating what part of the scrollbar was clicked
//	Rectangle is not adjusted
//
static UINT GetHorzPortion(SCROLLBAR *sb, HWND hwnd, RECT *rect, int x, int y)
{
	RECT rc = *rect;

	if(y < rc.top || y >= rc.bottom) return HTSCROLL_NONE;

#ifdef INCLUDE_BUTTONS

	if(sb->fButVisibleBefore) 
	{
		//clicked on the buttons to the left of the scrollbar
		if(x >= rc.left && x < rc.left + sb->nButSizeBefore)
			return HTSCROLL_INSERTED;

		//adjust the rectangle to exclude the left-side buttons, now that we
		//know we havn't clicked on them
		rc.left  += sb->nButSizeBefore;
	}

	if(sb->fButVisibleAfter)
	{
		//clicked on the buttons to the right of the scrollbar
		if(x >= rc.right - sb->nButSizeAfter && x < rc.right)
			return HTSCROLL_INSERTED;

		//adjust the rectangle to exclude the right-side buttons, now that we
		//know we havn't clicked on them
		rc.right -= sb->nButSizeAfter;
	}

#endif INCLUDE_BUTTONS

	//Now we have the rectangle for the scrollbar itself, so work out
	//what part we clicked on.
	return GetHorzScrollPortion(sb, hwnd, &rc, x, y);
}

//
//	Just call the horizontal version, with adjusted coordinates
//
static UINT GetVertPortion(SCROLLBAR *sb, HWND hwnd, RECT *rect, int x, int y)
{
	UINT ret;
	RotateRect(rect);
	ret = GetHorzPortion(sb, hwnd, rect, y, x);
	RotateRect(rect);
	return ret;
}

//
//	Wrapper function for GetHorzPortion and GetVertPortion
//
static UINT GetPortion(SCROLLBAR *sb, HWND hwnd, RECT *rect, int x, int y)
{
	if(sb->nBarType == SB_HORZ)
		return GetHorzPortion(sb, hwnd, rect, x, y);
	else if(sb->nBarType == SB_VERT)
		return GetVertPortion(sb, hwnd, rect, x, y);
	else
		return HTSCROLL_NONE;
}

//
//	Input: rectangle of the total scrollbar area
//	Output: adjusted to take the inserted buttons into account
//
static void GetRealHorzScrollRect(SCROLLBAR *sb, RECT *rect)
{
	if(sb->fButVisibleBefore) rect->left += sb->nButSizeBefore;
	if(sb->fButVisibleAfter)  rect->right -= sb->nButSizeAfter;
}

//
//	Input: rectangle of the total scrollbar area
//	Output: adjusted to take the inserted buttons into account
//
static void GetRealVertScrollRect(SCROLLBAR *sb, RECT *rect)
{
	if(sb->fButVisibleBefore) rect->top += sb->nButSizeBefore;
	if(sb->fButVisibleAfter)  rect->bottom -= sb->nButSizeAfter;
}

//
//	Decide which type of scrollbar we have before calling
//  the real function to do the job
//
static void GetRealScrollRect(SCROLLBAR *sb, RECT *rect)
{
	if(sb->nBarType == SB_HORZ)
	{
		GetRealHorzScrollRect(sb, rect);
	}
	else if(sb->nBarType == SB_VERT)
	{
		GetRealVertScrollRect(sb, rect);
	}
}

//
//	All button code shoule be collected together
//	
//
#ifdef INCLUDE_BUTTONS

//
//	Return the index of the button covering the specified point
//	rect		- rectangle of the whole scrollbar area
//	pt			- screen coords of the mouse
//	fReturnRect - do/don't modify the rect to return the button's area
//
static UINT GetHorzButtonFromPt(SCROLLBAR *sb, RECT *rect, POINT pt, BOOL fReturnRect)
{
	int leftpos = rect->left, rightpos = rect->right;
	int i;
	int butwidth;
	SCROLLBUT *sbut = sb->sbButtons;

	if(!PtInRect(rect, pt))
		return -1;

	if(sb->fButVisibleAfter)
		rightpos -= sb->nButSizeAfter;

	for(i = 0; i < sb->nButtons; i++)
	{
		if(sb->fButVisibleBefore && sbut[i].uPlacement == SBBP_LEFT)
		{
			butwidth = GetSingleButSize(sb, &sbut[i]);
			
			//if the current button is under the specified point
			if(pt.x >= leftpos && pt.x < leftpos + butwidth)
			{
				//if the caller wants us to return the rectangle of the button
				if(fReturnRect)
				{
					rect->left  = leftpos;
					rect->right = leftpos + butwidth;
				}

				return i;
			}

			leftpos += butwidth;
		}
		else if(sb->fButVisibleAfter && sbut[i].uPlacement == SBBP_RIGHT)
		{
			butwidth = GetSingleButSize(sb, &sbut[i]);

			//if the current button is under the specified point
			if(pt.x >= rightpos && pt.x < rightpos + butwidth)
			{
				//if the caller wants us to return the rectangle of the button
				if(fReturnRect)
				{
					rect->left  = rightpos;
					rect->right = rightpos + butwidth;
				}
				return i;
			}

			rightpos += butwidth;
		}
	}

	return -1;
}


static UINT GetVertButtonFromPt(SCROLLBAR *sb, RECT *rect, POINT pt, BOOL fReturnRect)
{
	UINT ret;
	int temp;
	
	//swap the X/Y coords
	temp = pt.x;
	pt.x = pt.y;
	pt.y = temp;

	//swap the rectangle
	RotateRect(rect);
	
	ret = GetHorzButtonFromPt(sb, rect, pt, fReturnRect);

	RotateRect(rect);
	return ret;
}

//
//
//
static UINT GetButtonFromPt(SCROLLBAR *sb, RECT *rect, POINT pt, BOOL fReturnRect)
{
	if(sb->nBarType == SB_HORZ)
	{
		return GetHorzButtonFromPt(sb, rect, pt, fReturnRect);
	}
	else
	{
		return GetVertButtonFromPt(sb, rect, pt, fReturnRect);
	}
}

//
//	Find the coordinates (in RECT format) of the specified button index
//
static UINT GetHorzButtonRectFromId(SCROLLBAR *sb, RECT *rect, UINT index)
{
	UINT i;
	SCROLLBUT *sbut = sb->sbButtons;
	int leftpos = rect->left, rightpos = rect->right;

	if(sb->fButVisibleAfter)
		rightpos -= sb->nButSizeAfter;

	//find the particular button in question
	for(i = 0; i < index; i++)
	{
		if(sb->fButVisibleBefore && sbut[i].uPlacement == SBBP_LEFT)
		{
			leftpos += GetSingleButSize(sb, &sbut[i]);
		}
		else if(sb->fButVisibleAfter && sbut[i].uPlacement == SBBP_RIGHT)
		{
			rightpos += GetSingleButSize(sb, &sbut[i]);
		}
	}

	//now return the rectangle
	if(sbut[i].uPlacement == SBBP_LEFT)
	{
		rect->left  = leftpos;
		rect->right = leftpos + GetSingleButSize(sb, &sbut[i]);
	}
	else
	{
		rect->left  = rightpos;
		rect->right = rightpos + GetSingleButSize(sb, &sbut[i]);
	}

	return 0;
}

static UINT GetVertButtonRectFromId(SCROLLBAR *sb, RECT *rect, UINT index)
{
	UINT ret;
	RotateRect(rect);
	ret = GetHorzButtonRectFromId(sb, rect, index);
	RotateRect(rect);
	return ret;
}

static UINT GetButtonRectFromId(SCROLLBAR *sb, RECT *rect, UINT index)
{
	if(sb->nBarType == SB_HORZ)
	{
		return GetHorzButtonRectFromId(sb, rect, index);
	}
	else
	{
		return GetVertButtonRectFromId(sb, rect, index);
	}
}
#endif //INCLUDE_BUTTONS	

//
//	Left button click in the non-client area
//
static LRESULT NCLButtonDown(SCROLLWND *sw, HWND hwnd, WPARAM wParam, LPARAM lParam)
{
	RECT rect, winrect;
	HDC hdc;
	SCROLLBAR *sb;
	SCROLLBUT *sbut = 0;
	POINT pt;

	pt.x = LOWORD(lParam);
	pt.y = HIWORD(lParam);

	hwndCurCoolSB = hwnd;

	//
	//	HORIZONTAL SCROLLBAR PROCESSING
	//
	if(wParam == HTHSCROLL)
	{
		uScrollTimerMsg = WM_HSCROLL;
		uCurrentScrollbar = SB_HORZ;
		sb = &sw->sbarHorz;

		//get the total area of the normal Horz scrollbar area
		GetHScrollRect(sw, hwnd, &rect);
		uCurrentScrollPortion = GetHorzPortion(sb, hwnd, &rect, LOWORD(lParam), HIWORD(lParam));
	}
	//
	//	VERTICAL SCROLLBAR PROCESSING
	//
	else if(wParam == HTVSCROLL)
	{
		uScrollTimerMsg = WM_VSCROLL;
		uCurrentScrollbar = SB_VERT;
		sb = &sw->sbarVert;

		//get the total area of the normal Horz scrollbar area
		GetVScrollRect(sw, hwnd, &rect);
		uCurrentScrollPortion = GetVertPortion(sb, hwnd, &rect, LOWORD(lParam), HIWORD(lParam));
	}
	//
	//	NORMAL PROCESSING
	//
	else
	{
		uCurrentScrollPortion = HTSCROLL_NONE;
		return CallWindowProc(sw->oldproc, hwnd, WM_NCLBUTTONDOWN, wParam, lParam);
	}

	//
	// we can now share the same code for vertical
	// and horizontal scrollbars
	//
	switch(uCurrentScrollPortion)
	{
	//inserted buttons to the left/right
#ifdef INCLUDE_BUTTONS
	case HTSCROLL_INSERTED:  

#ifdef HOT_TRACKING
		KillTimer(hwnd, uMouseOverId);
		uMouseOverId = 0;
		uMouseOverScrollbar = COOLSB_NONE;
#endif

		//find the index of the button that has been clicked
		//adjust the rectangle to give the button's rectangle
		uCurrentButton = GetButtonFromPt(sb, &rect, pt, TRUE);

		sbut = &sb->sbButtons[uCurrentButton];
		
		//post a notification message
		PostMouseNotify(hwnd, NM_CLICK, sb->nBarType, &rect, sbut->uCmdId, pt);

		GetWindowRect(hwnd, &winrect);
		OffsetRect(&rect, -winrect.left, -winrect.top);
		hdc = GetWindowDC(hwnd);
			
		DrawScrollButton(sbut, hdc, &rect, SBBS_PUSHED);

		ReleaseDC(hwnd, hdc);
	
		break;
#endif	//INCLUDE_BUTTONS

⌨️ 快捷键说明

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