?? scroll.c
字號:
/*
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 + -