windows-nt/Source/XPSP1/NT/shell/comctl32/v5/flat_sb.c
2020-09-26 16:20:57 +08:00

2934 lines
88 KiB
C

#include "ctlspriv.h"
#include "flat_sb.h"
// Following interfaces are imported from newwsbctl.c and newsb.c. These
// functions are for internal use only.
void FlatSB_Internal_CalcSBStuff(WSBState *, BOOL);
void FlatSB_Internal_DoScroll(WSBState *, int, int, BOOL);
void FlatSB_Internal_EndScroll(WSBState *, BOOL);
void FlatSB_Internal_DrawArrow(WSBState *, HDC, CONST RECT *, int, int);
void FlatSB_Internal_DrawElevator(WSBState *, HDC, LPRECT, BOOL);
void FlatSB_Internal_DrawGroove(WSBState *, HDC, LPRECT, BOOL);
void FlatSB_Internal_DrawSize(WSBState *, HDC, int, int);
void FlatSB_Internal_DrawScrollBar(WSBState *, HDC, BOOL, BOOL);
void FlatSB_Internal_DrawThumb(WSBState *, BOOL);
void FlatSB_Internal_DrawThumb2(WSBState *, HDC, BOOL, UINT);
UINT FlatSB_Internal_GetSBFlags(WSBState *, BOOL);
BOOL FlatSB_Internal_EnableScrollBar(WSBState *, int, UINT);
WSBState * FlatSB_Internal_InitPwSB(HWND);
void FlatSB_Internal_RedrawScrollBar(WSBState *, BOOL);
void FlatSB_Internal_SBTrackInit(WSBState *, HWND, LPARAM, int, BOOL);
void FlatSB_Internal_TrackBox(WSBState *, int message, WPARAM, LPARAM);
void FlatSB_Internal_TrackThumb(WSBState *, int message, WPARAM, LPARAM);
BOOL FlatSB_Internal_IsSizeBox(HWND);
LRESULT FlatSB_Internal_SetScrollBar(WSBState *, int, LPSCROLLINFO, BOOL);
LRESULT CALLBACK FlatSB_SubclassWndProc(HWND, UINT, WPARAM, LPARAM, WPARAM, ULONG_PTR);
void FlatSB_Internal_NotifyWinEvent(WSBState *pWState, UINT event, LONG_PTR idChild)
{
MyNotifyWinEvent(event, pWState->sbHwnd,
pWState->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL,
idChild);
}
#define IsHottrackable(STYLE) ((STYLE == FSB_FLAT_MODE) || (STYLE == FSB_ENCARTA_MODE))
HRESULT WINAPI UninitializeFlatSB(HWND hwnd)
{
SCROLLINFO hsi, vsi;
WSBState * pWState;
int style, vFlags, hFlags;
BOOL hValid = FALSE, vValid = FALSE;
GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
if (pWState == (WSBState *)NULL)
return S_FALSE;
else if (pWState == WSB_UNINIT_HANDLE) {
RemoveWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0);
return S_FALSE;
}
if (pWState->fTracking)
return E_FAIL; // Can't do this!
style = pWState->style;
vsi.cbSize = hsi.cbSize = sizeof(SCROLLINFO);
vsi.fMask = hsi.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
hValid = FlatSB_GetScrollInfo(hwnd, SB_HORZ, &hsi);
hFlags = FlatSB_Internal_GetSBFlags(pWState, SB_HORZ);
vValid = FlatSB_GetScrollInfo(hwnd, SB_VERT, &vsi);
vFlags = FlatSB_Internal_GetSBFlags(pWState, SB_VERT);
DeleteObject(pWState->hbm_Bkg);
DeleteObject(pWState->hbr_Bkg);
LocalFree((HLOCAL)pWState);
RemoveWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0);
if (vValid) {
SetScrollInfo(hwnd, SB_VERT, &vsi, FALSE);
EnableScrollBar(hwnd, SB_VERT, vFlags);
}
if (hValid) {
SetScrollInfo(hwnd, SB_HORZ, &hsi, FALSE);
EnableScrollBar(hwnd, SB_HORZ, hFlags);
}
SetWindowBits(hwnd, GWL_STYLE, WS_HSCROLL | WS_VSCROLL, style & (WS_HSCROLL | WS_VSCROLL));
// Force the WM_NCCALCSIZE/WM_NCPAINT to be sent.
CCInvalidateFrame(hwnd);
return S_OK;
}
//
// For accessibility - We keep the original USER scrollbars around and
// keep USER's view of the scrollbar in sync with the flat view. This
// means keeping the WS_[HV]SCROLL styles on the window, forwarding
// all scrollbar APIs into USER, etc. That way, when OLEACC asks USER
// for the scrollbar state, USER returns values that match the flat_sb
// values.
//
// Even though the styles are enabled, the UI isn't affected since we
// take over all nonclient painting and hit-testing so USER never gets
// a chance to paint or hit-test the scrollbars that we took over.
//
BOOL WINAPI InitializeFlatSB(HWND hwnd)
{
int newStyle, style;
SCROLLINFO hsi, vsi, siTmp;
WSBState * pWState;
BOOL hValid = FALSE, vValid = FALSE;
style = GetWindowLong(hwnd, GWL_STYLE);
siTmp.cbSize = vsi.cbSize = hsi.cbSize = sizeof(SCROLLINFO);
vsi.fMask = hsi.fMask = SIF_ALL | SIF_DISABLENOSCROLL;
if (style & WS_HSCROLL)
hValid = GetScrollInfo(hwnd, SB_HORZ, &hsi);
if (style & WS_VSCROLL)
vValid = GetScrollInfo(hwnd, SB_VERT, &vsi);
newStyle = style & (WS_VSCROLL | WS_HSCROLL);
style &= ~(WS_VSCROLL | WS_HSCROLL);
GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
if (!vValid && !hValid) {
if (NULL == pWState) {
if (!SetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR)WSB_UNINIT_HANDLE))
return FALSE;
} else {
// It seems to me unreasonable to do nothing while the caller wants
// to init again the flat SB we are already using.
}
return TRUE;
}
if ((NULL == pWState) || (WSB_UNINIT_HANDLE == pWState)) {
pWState = FlatSB_Internal_InitPwSB(hwnd);
if ((WSBState *)NULL == pWState)
return FALSE;
if (!SetWindowSubclass(hwnd,FlatSB_SubclassWndProc, 0,(ULONG_PTR)pWState)) {
DeleteObject(pWState->hbm_Bkg);
DeleteObject(pWState->hbr_Bkg);
LocalFree((HLOCAL)pWState);
return FALSE;
}
}
pWState->style = newStyle;
if (hValid)
FlatSB_Internal_SetScrollBar(pWState, SB_HORZ, &hsi, FALSE);
if (vValid)
FlatSB_Internal_SetScrollBar(pWState, SB_VERT, &vsi, FALSE);
// Force the WM_NCCALCSIZE/WM_NCPAINT to be sent.
CCInvalidateFrame(hwnd);
return TRUE;
}
LRESULT FlatSB_NCDestroyProc(WSBState * pWState, HWND hwnd, WPARAM wParam, LPARAM lParam)
{
ASSERT(pWState);
if (pWState != WSB_UNINIT_HANDLE) {
DeleteObject(pWState->hbm_Bkg);
DeleteObject(pWState->hbr_Bkg);
LocalFree((HLOCAL)pWState);
}
RemoveWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0);
return DefSubclassProc(hwnd, WM_NCDESTROY, wParam, lParam);
}
LRESULT FlatSB_NCCalcProc(WSBState * pWState, HWND hwnd, WPARAM wParam, LPARAM lParam)
{
RECT * rc = (RECT *) lParam;
NCCALCSIZE_PARAMS * pnc = (NCCALCSIZE_PARAMS *)lParam;
RECT rcClient, rcWin;
LRESULT lres;
DWORD dwStyle;
// ZDC:
//
// Note:
// It's said that if wParam is true, new rgrc[1|2] are also
// computed. Since I didn't see the implementation in the 'user'
// code, I leave it unimplemented.
if ((BOOL)wParam == TRUE)
CopyRect(&rcWin, &(pnc->rgrc[0]));
else
CopyRect(&rcWin, rc);
dwStyle = SetWindowBits(hwnd, GWL_STYLE, WS_VSCROLL | WS_HSCROLL, 0);
// Save pnc->rgrc[0] to keep USER happy (see below)
CopyRect(&rcClient, &pnc->rgrc[0]);
lres = DefSubclassProc(hwnd, WM_NCCALCSIZE, wParam, lParam);
SetWindowBits(hwnd, GWL_STYLE, WS_VSCROLL | WS_HSCROLL, dwStyle);
// USER does funky internal state munging during the WM_NCCALCSIZE
// and we want USER's internal state to see the scrollbars even though
// we're drawing them. So give USER one last look at the original
// values so he will think the scroll bars are really there. This
// sets internal WFVPRESENT and WFHPRESENT flags that OLEACC secretly
// looks at via the undocumented GetScrollBarInfo().
DefSubclassProc(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rcClient);
if ((BOOL)wParam == TRUE)
CopyRect(&rcClient, &(pnc->rgrc[0]));
else
CopyRect(&rcClient, rc);
pWState->style &= ~(WFVPRESENT | WFHPRESENT);
if (TestSTYLE(pWState->style, WS_VSCROLL)
&& (rcClient.right - rcClient.left >= pWState->x_VSBArrow)) {
pWState->style |= WFVPRESENT;
rcClient.right -= pWState->x_VSBArrow;
}
if (TestSTYLE(pWState->style, WS_HSCROLL)
&& (rcClient.bottom - rcClient.top > pWState->y_HSBArrow)) {
pWState->style |= WFHPRESENT;
rcClient.bottom -= pWState->y_HSBArrow;
}
if ((BOOL)wParam == TRUE)
CopyRect(&(pnc->rgrc[0]), &rcClient);
else
CopyRect(rc, &rcClient);
pWState->rcClient.top = rcClient.top - rcWin.top;
pWState->rcClient.bottom = rcClient.bottom - rcWin.top;
pWState->rcClient.left = rcClient.left - rcWin.left;
pWState->rcClient.right = rcClient.right - rcWin.left;
return lres;
}
LRESULT FlatSB_NCPaintProc(WSBState * pWState, HWND hwnd, WPARAM wParam, LPARAM lParam)
{
HDC hdc;
int oldLoc, newLoc;
LRESULT lres;
DWORD dwStyle;
RECT rcClient;
ASSERT(pWState);
ASSERT(pWState != WSB_UNINIT_HANDLE);
//
// DefWindowProc(WM_NCPAINT) is going to try to draw USER's scrollbars,
// and will draw them in the wrong place if our scrollbar width is
// different from the system default width. (Argh.)
//
// So remove the scrollbar styles, do the paint, then put them back.
//
dwStyle = SetWindowBits(hwnd, GWL_STYLE, WS_VSCROLL | WS_HSCROLL, 0);
GetWindowRect(hwnd, &rcClient);
DefSubclassProc(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rcClient);
lres = DefSubclassProc(hwnd, WM_NCPAINT, wParam, lParam);
SetWindowBits(hwnd, GWL_STYLE, WS_VSCROLL | WS_HSCROLL, dwStyle);
GetWindowRect(hwnd, &rcClient);
DefSubclassProc(hwnd, WM_NCCALCSIZE, FALSE, (LPARAM)&rcClient);
// hdc = GetDCEx(hwnd, (HRGN) wParam, DCX_WINDOW |
// DCX_INTERSECTRGN | DCX_LOCKWINDOWUPDATE);
// ZDC:
//
// Note:
// For some reason(wParam == 1) the statements above did not give
// the result we expected. I am not sure if it's the only case that
// GetDCEx will disappoint us.
hdc = GetWindowDC(hwnd);
newLoc = WSB_MOUSELOC_OUTSIDE;
oldLoc = pWState->locMouse;
if (TestSTYLE(pWState->style, WFHPRESENT)
&& TestSTYLE(pWState->style, WFVPRESENT)) {
int cxFrame, cyFrame;
cxFrame = pWState->rcClient.right;
cyFrame = pWState->rcClient.bottom;
FlatSB_Internal_DrawSize(pWState, hdc, cxFrame, cyFrame);
}
if (TestSTYLE(pWState->style, WFHPRESENT)) {
FlatSB_Internal_DrawScrollBar(pWState, hdc, FALSE, FALSE);
if (pWState->fHActive)
newLoc = pWState->locMouse;
}
if (TestSTYLE(pWState->style, WFVPRESENT)) {
pWState->locMouse = oldLoc;
FlatSB_Internal_DrawScrollBar(pWState, hdc, TRUE, FALSE);
if (pWState->fVActive)
newLoc = pWState->locMouse;
}
pWState->locMouse = newLoc;
ReleaseDC(hwnd, hdc);
return lres;
}
LRESULT FlatSB_NCHitTestProc(WSBState *pWState, HWND hwnd, WPARAM wParam, LPARAM lParam, BOOL fTrack);
VOID CALLBACK TimerMouseLeave(
HWND hwnd, // handle of window for timer messages
UINT uMsg, // WM_TIMER message
UINT_PTR idEvent, // timer identifier
DWORD dwTime // current system time
)
{
WSBState * pWState;
if (idEvent != IDWSB_TRACK)
return;
GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
if ((pWState == (WSBState *)NULL) || (pWState == WSB_UNINIT_HANDLE)) {
KillTimer(hwnd, IDWSB_TRACK);
return;
}
if (pWState->fTracking) {
return;
}
FlatSB_NCHitTestProc(pWState, hwnd, 0, 0, TRUE);
return;
}
LRESULT FlatSB_NCHitTestProc(WSBState *pWState, HWND hwnd, WPARAM wParam, LPARAM lParam, BOOL fTTrack)
{
LRESULT lres, lHTCode=HTBOTTOMRIGHT;
RECT rcTest, rcWindow;
POINT pt;
BOOL fVChanged = FALSE, fHChanged = FALSE;
BOOL fWinActive = ChildOfActiveWindow(hwnd);
int newLoc, oldLoc;
ASSERT(pWState);
ASSERT(pWState != WSB_UNINIT_HANDLE);
GetWindowRect(hwnd, &rcWindow);
if (fTTrack) {
lres = HTNOWHERE;
if (fWinActive)
GetCursorPos(&pt);
else {
pt.x = rcWindow.left - 1; // NOWHERE --- to fool CalcSBtuff2
pt.y = rcWindow.top - 1;
}
} else {
lres = DefSubclassProc(hwnd, WM_NCHITTEST, wParam, lParam);
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
}
//
// If this is a RTL mirrored window, then measure
// the client coordinates from the visual right edge.
// [samera]
//
if (IS_WINDOW_RTL_MIRRORED(hwnd)) {
pt.x = rcWindow.right - pt.x;
lHTCode = HTBOTTOMLEFT;
} else {
pt.x -= rcWindow.left;
}
pt.y -= rcWindow.top;
if (fTTrack && fWinActive && (pt.x == pWState->ptMouse.x) && (pt.y == pWState->ptMouse.y))
return lres /* Meaningless result*/;
// We shouldn't get HTVSCROLL / HTHSCROLL for system scrollbar here.
if (lres != HTNOWHERE) {
goto Redraw;
}
if (TestSTYLE(pWState->style, WFVPRESENT)) {
rcTest.left = pWState->rcClient.right;
rcTest.right = pWState->rcClient.right + pWState->x_VSBArrow;
rcTest.top = pWState->rcClient.top;
rcTest.bottom = pWState->rcClient.bottom;
if (PtInRect(&rcTest, pt)) {
lres = HTVSCROLL;
goto Redraw;
}
}
if (TestSTYLE(pWState->style, WFHPRESENT)) {
rcTest.left = pWState->rcClient.left;
rcTest.right = pWState->rcClient.right;
rcTest.top = pWState->rcClient.bottom;
rcTest.bottom = pWState->rcClient.bottom + pWState->y_HSBArrow;
if (PtInRect(&rcTest, pt)) {
lres = HTHSCROLL;
goto Redraw;
}
}
if (TestSTYLE(pWState->style, WFHPRESENT) && TestSTYLE(pWState->style, WFVPRESENT))
{
rcTest.left = pWState->rcClient.right;
rcTest.right = pWState->rcClient.right + pWState->x_VSBArrow;
rcTest.top = pWState->rcClient.bottom;
rcTest.bottom = pWState->rcClient.bottom + pWState->y_HSBArrow;
if (PtInRect(&rcTest, pt)) {
if (!FlatSB_Internal_IsSizeBox(hwnd))
lres = HTSIZE;
else
lres = lHTCode;
goto Redraw;
}
}
lres = HTNOWHERE;
Redraw:
if(pWState->fTracking)
return lres;
if (!fWinActive) {
fVChanged = pWState->fVActive; pWState->fVActive = FALSE;
fHChanged = pWState->fHActive; pWState->fHActive = FALSE;
} else {
switch (lres) {
case HTVSCROLL:
fVChanged = TRUE; pWState->fVActive = TRUE;
fHChanged = pWState->fHActive; pWState->fHActive = FALSE;
break;
case HTHSCROLL:
fVChanged = pWState->fVActive; pWState->fVActive = FALSE;
fHChanged = TRUE; pWState->fHActive = TRUE;
break;
default:
fVChanged = pWState->fVActive; pWState->fVActive = FALSE;
fHChanged = pWState->fHActive; pWState->fHActive = FALSE;
break;
}
}
pWState->ptMouse.x = pt.x;
pWState->ptMouse.y = pt.y;
newLoc = WSB_MOUSELOC_OUTSIDE;
oldLoc = pWState->locMouse;
if (fVChanged && IsHottrackable(pWState->vStyle)) {
FlatSB_Internal_RedrawScrollBar(pWState, TRUE);
if (pWState->fVActive)
newLoc = pWState->locMouse;
}
if (fHChanged && IsHottrackable(pWState->hStyle)) {
pWState->locMouse = oldLoc;
FlatSB_Internal_RedrawScrollBar(pWState, FALSE);
if (pWState->fHActive)
newLoc = pWState->locMouse;
}
pWState->locMouse = newLoc;
if (pWState->fVActive || pWState->fHActive) {
if (pWState->hTrackSB == 0)
pWState->hTrackSB = SetTimer(hwnd, IDWSB_TRACK,
GetDoubleClickTime()/2,
TimerMouseLeave);
} else {
if (pWState->hTrackSB) {
KillTimer(hwnd, IDWSB_TRACK);
pWState->hTrackSB = 0;
}
}
return lres;
}
LRESULT FlatSB_SysCommandProc(WSBState * pWState, HWND hwnd, WPARAM wParam, LPARAM lParam)
{
LRESULT lres;
unsigned uCmdType;
int hitArea;
ASSERT(pWState);
ASSERT(pWState != WSB_UNINIT_HANDLE);
uCmdType = (unsigned) wParam & 0xFFF0; // type of system command requested
hitArea = (int) wParam & 0x000F;
if (uCmdType != SC_HSCROLL && uCmdType != SC_VSCROLL)
return DefSubclassProc(hwnd, WM_SYSCOMMAND, wParam, lParam);
else
// There are some initialization we may need.
#define SC_INVALID 0
lres = DefSubclassProc(hwnd, WM_SYSCOMMAND, (WPARAM)SC_INVALID, lParam);
#undef SC_INVALID
FlatSB_Internal_SBTrackInit(pWState, hwnd, lParam, hitArea, GetKeyState(VK_SHIFT) < 0);
return 0;
}
LRESULT FlatSB_CancelModeProc(WSBState * pWState, HWND hwnd, WPARAM wParam, LPARAM lParam)
{
LRESULT lres;
ASSERT(pWState);
ASSERT(pWState != WSB_UNINIT_HANDLE);
lres = DefSubclassProc(hwnd, WM_CANCELMODE, wParam, lParam);
// A good citizen of Subclass, we have to wait the DefSubclassProc
// release capture first!
if (pWState->pfnSB)
FlatSB_Internal_EndScroll(pWState, TRUE);
return lres;
}
//
// This updates the system metrics and points pPWState->pwmet at the
// application metrics or system metrics, depending on whether a
// screenreader is running.
//
void FlatSB_InitWSBMetrics(WSBState *pWState)
{
BOOL fScreenRead;
pWState->metSys.cxHSBThumb = GetSystemMetrics(SM_CXHTHUMB);
pWState->metSys.cyVSBThumb = GetSystemMetrics(SM_CYVTHUMB);
pWState->metSys.cxVSBArrow = GetSystemMetrics(SM_CXVSCROLL);
pWState->metSys.cyVSBArrow = GetSystemMetrics(SM_CYVSCROLL);
pWState->metSys.cxHSBArrow = GetSystemMetrics(SM_CXHSCROLL);
pWState->metSys.cyHSBArrow = GetSystemMetrics(SM_CYHSCROLL);
fScreenRead = FALSE;
SystemParametersInfo(SPI_GETSCREENREADER, 0, &fScreenRead, 0);
// If a screen reader is running, then the active metrics are the
// system metrics; otherwise, it's the app metrics.
pWState->pmet = fScreenRead ? &pWState->metSys : &pWState->metApp;
}
LRESULT FlatSB_OnSettingChangeProc(WSBState *pWState, HWND hwnd, WPARAM wParam, LPARAM lParam)
{
ASSERT(pWState);
ASSERT(pWState != WSB_UNINIT_HANDLE);
FlatSB_InitWSBMetrics(pWState);
// These new metrics will most likely have altered our frame, so
// recompute our frame stuff too
CCInvalidateFrame(hwnd);
return DefSubclassProc(hwnd, WM_SETTINGCHANGE, wParam, lParam);
}
LRESULT FlatSB_OnScrollProc(WSBState *pWState, HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (GET_WM_HSCROLL_HWND(wParam, lParam) == NULL && !pWState->fInDoScroll) {
// Somebody on the outside (probably USER) changed our scroll stuff,
// so re-sync with the USER values.
if (GET_WM_HSCROLL_CODE(wParam, lParam) == SB_ENDSCROLL)
FlatSB_NCPaintProc(pWState, hwnd, (WPARAM)1, 0);
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK FlatSB_SubclassWndProc
(
HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam,
WPARAM uIdSubclass,
ULONG_PTR dwRefData
)
{
WSBState * pWState = (WSBState *)dwRefData;
ASSERT (dwRefData);
if (pWState == (WSBState *)NULL)
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
else if (pWState == WSB_UNINIT_HANDLE && uMsg != WM_NCDESTROY)
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
switch (uMsg)
{
case WM_NCDESTROY:
return FlatSB_NCDestroyProc(pWState, hwnd, wParam, lParam);
case WM_NCCALCSIZE:
return FlatSB_NCCalcProc(pWState, hwnd, wParam, lParam);
case WM_NCPAINT:
return FlatSB_NCPaintProc(pWState, hwnd, wParam, lParam);
case WM_NCHITTEST:
return FlatSB_NCHitTestProc(pWState, hwnd, wParam, lParam, FALSE);
case WM_SYSCOMMAND:
return FlatSB_SysCommandProc(pWState, hwnd, wParam, lParam);
case WM_CANCELMODE:
return FlatSB_CancelModeProc(pWState, hwnd, wParam, lParam);
case WM_SETTINGCHANGE:
return FlatSB_OnSettingChangeProc(pWState, hwnd, wParam, lParam);
case WM_VSCROLL:
case WM_HSCROLL:
return FlatSB_OnScrollProc(pWState, hwnd, uMsg, wParam, lParam);
}
return DefSubclassProc(hwnd, uMsg, wParam, lParam);
}
//=------------------------------------------------------------------
// Start of drawing functions.
//=-------------------------------------------------------------------
#define WSB_BUTTON_UPARROW DFCS_SCROLLUP
#define WSB_BUTTON_DOWNARROW DFCS_SCROLLDOWN
#define WSB_BUTTON_LEFTARROW DFCS_SCROLLLEFT
#define WSB_BUTTON_RIGHTARROW DFCS_SCROLLRIGHT
#define WSB_RESTING_MODE 0
#define WSB_HOTTRACKED_MODE 1
#define WSB_MOUSEDOWN_MODE 2
#define WSB_DISABLED_MODE 3
void FlatSB_Internal_DrawBox(HDC hdc, CONST RECT * prct, int mode)
{
HBRUSH hbrOld, hbrEdge, hbrFace;
int w, h, l, t;
if (prct->left > prct->right)
return;
else if (prct->top > prct->bottom)
return;
l = prct->left;
t = prct->top;
w = prct->right - prct->left;
h = prct->bottom - prct->top;
switch (mode) {
case WSB_HOTTRACKED_MODE:
hbrEdge = GetSysColorBrush(COLOR_3DSHADOW);
hbrFace = hbrEdge;
break;
case WSB_MOUSEDOWN_MODE:
hbrEdge = GetSysColorBrush(COLOR_3DSHADOW);
hbrFace = (HBRUSH)GetStockObject(BLACK_BRUSH);
break;
case WSB_DISABLED_MODE:
hbrEdge = GetSysColorBrush(COLOR_3DHILIGHT);
hbrFace = GetSysColorBrush(COLOR_3DFACE);
break;
case WSB_RESTING_MODE:
default:
hbrEdge = GetSysColorBrush(COLOR_3DSHADOW);
hbrFace = GetSysColorBrush(COLOR_3DFACE);
break;
}
hbrOld = SelectObject(hdc, hbrEdge);
PatBlt(hdc, l, t, w, 1, PATCOPY);
PatBlt(hdc, l, t, 1, h, PATCOPY);
PatBlt(hdc, l, t + h - 1, w, 1, PATCOPY);
PatBlt(hdc, l + w - 1, t, 1, h, PATCOPY);
SelectObject(hdc, hbrFace);
PatBlt(hdc, l + 1, t + 1, w - 2, h - 2, PATCOPY);
SelectObject(hdc, hbrOld);
}
void FlatSB_Internal_DrawEncartaBox(HDC hdc, CONST RECT * prct, int mode)
{
HBRUSH hbrOld, hbrLite, hbrDark, hbrFace;
int w, h, l, t;
if (prct->left > prct->right)
return;
else if (prct->top > prct->bottom)
return;
l = prct->left;
t = prct->top;
w = prct->right - prct->left;
h = prct->bottom - prct->top;
switch (mode) {
case WSB_HOTTRACKED_MODE:
hbrLite = GetSysColorBrush(COLOR_3DHILIGHT);
hbrDark = GetSysColorBrush(COLOR_3DSHADOW);
break;
case WSB_MOUSEDOWN_MODE:
hbrDark = GetSysColorBrush(COLOR_3DHILIGHT);
hbrLite = GetSysColorBrush(COLOR_3DSHADOW);
break;
case WSB_DISABLED_MODE:
hbrDark = hbrLite = GetSysColorBrush(COLOR_3DHILIGHT);
break;
case WSB_RESTING_MODE:
default:
hbrDark = hbrLite = GetSysColorBrush(COLOR_3DSHADOW);
break;
}
hbrFace = GetSysColorBrush(COLOR_3DFACE);
hbrOld = SelectObject(hdc, hbrLite);
PatBlt(hdc, l, t, w, 1, PATCOPY);
PatBlt(hdc, l, t, 1, h, PATCOPY);
SelectObject(hdc, hbrDark);
PatBlt(hdc, l, t + h - 1, w, 1, PATCOPY);
PatBlt(hdc, l + w - 1, t, 1, h, PATCOPY);
SelectObject(hdc, hbrFace);
PatBlt(hdc, l + 1, t + 1, w - 2, h - 2, PATCOPY);
SelectObject(hdc, hbrOld);
}
void FlatSB_Internal_DrawArrow(WSBState * pWState, HDC hdc, CONST RECT * rcArrow, int buttonIndex, int extraModeBits)
{
COLORREF rgb;
LPCTSTR strIndex;
HFONT hFont, hOldFont;
int x, y, cx, cy, iOldBk, c;
BOOL fDisabled = extraModeBits & DFCS_INACTIVE;
BOOL fMouseDown = extraModeBits & DFCS_PUSHED;
BOOL fHotTracked;
int mode, style;
if (rcArrow->left >= rcArrow->right)
return;
else if (rcArrow->top >= rcArrow->bottom)
return;
if (buttonIndex == WSB_BUTTON_LEFTARROW || buttonIndex == WSB_BUTTON_RIGHTARROW)
style = pWState->hStyle;
else
style = pWState->vStyle;
switch (buttonIndex) {
case WSB_BUTTON_LEFTARROW:
fHotTracked = (pWState->locMouse == WSB_MOUSELOC_ARROWLF);
strIndex = TEXT("3");
break;
case WSB_BUTTON_RIGHTARROW:
fHotTracked = (pWState->locMouse == WSB_MOUSELOC_ARROWRG);
strIndex = TEXT("4");
break;
case WSB_BUTTON_UPARROW:
fHotTracked = (pWState->locMouse == WSB_MOUSELOC_ARROWUP);
strIndex = TEXT("5");
break;
case WSB_BUTTON_DOWNARROW:
fHotTracked = (pWState->locMouse == WSB_MOUSELOC_ARROWDN);
strIndex = TEXT("6");
break;
default:
return;
}
if (!fDisabled && fHotTracked && pWState->fHitOld)
fMouseDown = TRUE;
if (style == FSB_REGULAR_MODE) {
RECT rc;
CopyRect(&rc, rcArrow);
if (fDisabled)
DrawFrameControl(hdc, &rc, DFC_SCROLL, buttonIndex | DFCS_INACTIVE);
else if (fMouseDown)
DrawFrameControl(hdc, &rc, DFC_SCROLL, buttonIndex | DFCS_FLAT);
else
DrawFrameControl(hdc, &rc, DFC_SCROLL, buttonIndex);
return;
}
if (fDisabled)
mode = WSB_DISABLED_MODE;
else if (fMouseDown)
mode = WSB_MOUSEDOWN_MODE;
else if (fHotTracked)
mode = WSB_HOTTRACKED_MODE;
else
mode = WSB_RESTING_MODE;
if (style == FSB_ENCARTA_MODE) {
FlatSB_Internal_DrawEncartaBox(hdc, rcArrow, mode);
} else {
FlatSB_Internal_DrawBox(hdc, rcArrow, mode);
}
cx = rcArrow->right - rcArrow->left;
cy = rcArrow->bottom - rcArrow->top;
c = min(cx, cy);
if (c < 4) // Couldn't fill in a char after drawing the edges.
return;
x = rcArrow->left + ((cx - c) / 2) + 2;
y = rcArrow->top + ((cy - c) / 2) + 2;
c -= 4;
if (style == FSB_FLAT_MODE) {
switch (mode) {
case WSB_RESTING_MODE:
rgb = RGB(0, 0, 0);
break;
case WSB_HOTTRACKED_MODE:
case WSB_MOUSEDOWN_MODE:
rgb = RGB(255, 255, 255);
break;
case WSB_DISABLED_MODE:
rgb = GetSysColor(COLOR_3DSHADOW);
break;
default:
rgb = RGB(0, 0, 0);
break;
}
} else { // FSB_ENCARTA_MODE
switch (mode) {
case WSB_DISABLED_MODE:
rgb = GetSysColor(COLOR_3DSHADOW);
break;
case WSB_RESTING_MODE:
case WSB_HOTTRACKED_MODE:
case WSB_MOUSEDOWN_MODE:
default:
rgb = RGB(0, 0, 0);
break;
}
}
hFont = CreateFont(c, 0, 0, 0, FW_NORMAL, 0, 0, 0, SYMBOL_CHARSET, 0, 0, 0, 0, WSB_SYS_FONT);
iOldBk = SetBkMode(hdc, TRANSPARENT);
hOldFont = SelectObject(hdc, hFont);
rgb = SetTextColor(hdc, rgb);
TextOut(hdc, x, y, strIndex, 1);
SetBkMode(hdc, iOldBk);
SelectObject(hdc, hOldFont);
DeleteObject(hFont);
return;
}
void FlatSB_Internal_DrawElevator(WSBState * pWState, HDC hdc, LPRECT lprc, BOOL fVert)
{
BOOL fHit;
int mode;
int style;
fHit = (fVert)?(pWState->locMouse == WSB_MOUSELOC_V_THUMB)
:(pWState->locMouse == WSB_MOUSELOC_H_THUMB);
style = (fVert)?pWState->vStyle:pWState->hStyle;
switch (style) {
case FSB_FLAT_MODE:
case FSB_ENCARTA_MODE:
if ((pWState->cmdSB == SB_THUMBPOSITION) && (fVert == pWState->fTrackVert))
mode = WSB_HOTTRACKED_MODE;
else
mode = (fHit)?WSB_HOTTRACKED_MODE:WSB_RESTING_MODE;
if (style == FSB_FLAT_MODE)
FlatSB_Internal_DrawBox(hdc, lprc, mode);
else
FlatSB_Internal_DrawEncartaBox(hdc, lprc, mode);
break;
case FSB_REGULAR_MODE:
default:
{
RECT rc;
CopyRect(&rc, lprc);
DrawFrameControl(hdc, &rc, DFC_BUTTON, DFCS_BUTTONPUSH);
}
break;
}
}
//=-------------------------------------------------------------
// FlatSB_Internal_DrawSize
// Draw the size grip if needed.
//=-------------------------------------------------------------
void FlatSB_Internal_DrawSize(WSBState * pWState, HDC hdc, int x, int y)
{
HBRUSH hbrSave, hbr3DFACE;
RECT rcWindow;
HWND hwnd = pWState->sbHwnd;
int style;
style = GetWindowLong(hwnd, GWL_STYLE);
if (!FlatSB_Internal_IsSizeBox(hwnd))
{
hbr3DFACE = GetSysColorBrush(COLOR_3DFACE);
hbrSave = SelectObject(hdc, hbr3DFACE);
PatBlt(hdc, x, y, pWState->x_VSBArrow, pWState->y_HSBArrow, PATCOPY);
SelectBrush(hdc, hbrSave);
}
else
{
rcWindow.left = x;
rcWindow.right = x + pWState->x_VSBArrow;
rcWindow.top = y;
rcWindow.bottom = y + pWState->y_HSBArrow;
DrawFrameControl(hdc, &rcWindow, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
}
}
//=-------------------------------------------------------------
// FlatSB_Internal_DrawGroove
// Draw lines & middle of the thumb groove
//=-------------------------------------------------------------
void FlatSB_Internal_DrawGroove(WSBState * pWState, HDC hdc, LPRECT prct, BOOL fVert)
{
HBRUSH hbrLight;
COLORREF cBkg, cFg;
HPALETTE oldPal = 0;
if (fVert) {
hbrLight = pWState->hbr_VSBBkg;
cBkg = pWState->col_VSBBkg;
} else {
hbrLight = pWState->hbr_HSBBkg;
cBkg = pWState->col_HSBBkg;
}
if (hbrLight == (HBRUSH)NULL) {
hbrLight = GetSysColorBrush(COLOR_3DLIGHT);
FillRect(hdc, prct, hbrLight);
return;
}
if (pWState->hPalette != (HPALETTE)NULL) {
oldPal = SelectPalette(hdc, pWState->hPalette, TRUE);
RealizePalette(hdc);
}
cFg = SetTextColor(hdc, GetSysColor(COLOR_3DFACE));
cBkg = SetBkColor(hdc, cBkg);
FillRect(hdc, prct, hbrLight);
if (oldPal != (HPALETTE)NULL)
SelectPalette(hdc, oldPal, TRUE);
SetTextColor(hdc, cFg);
SetBkColor(hdc, cBkg);
}
//=-------------------------------------------------------------------
// Following functions are ported from winsbctl.c in user code.
//=-------------------------------------------------------------------
//=-------------------------------------------------------------------------
// SBPosFromPx() -
//=-------------------------------------------------------------------------
int FlatSB_Internal_SBPosFromPx(WSBState * pWState, int px)
{
int * pw;
if (pWState->fTrackVert)
pw = &(pWState->sbVMinPos);
else
pw = &(pWState->sbHMinPos);
if (px < pWState->pxUpArrow)
return pw[SBO_MIN];
if (px >= pWState->pxDownArrow)
return (pw[SBO_MAX] - (pw[SBO_PAGE]?pw[SBO_PAGE] - 1 : 0));
return (pw[SBO_MIN] + DMultDiv(pw[SBO_MAX] - pw[SBO_MIN] - (pw[SBO_PAGE]?pw[SBO_PAGE] - 1 : 0),
px - pWState->pxUpArrow,
pWState->cpxSpace)
);
}
//=-------------------------------------------------------------------------
// InvertScrollHilite()
//=-------------------------------------------------------------------------
void FlatSB_Internal_InvertScrollHilite(WSBState * pWState)
{
HWND hwnd = pWState->sbHwnd;
HDC hdc;
// Don't invert if the thumb is all the way at the top or bottom
// or you will end up inverting the line between the arrow and the thumb.
if (!IsRectEmpty(&(pWState->rcTrack)))
{
hdc = GetWindowDC(hwnd);
InvertRect(hdc, &(pWState->rcTrack));
ReleaseDC(hwnd, hdc);
}
}
//=-------------------------------------------------------------------------
// FlatSB_Internal_MoveThumb()
//=-------------------------------------------------------------------------
void FlatSB_Internal_MoveThumb(WSBState * pWState, int px)
{
HWND hwnd = pWState->sbHwnd;
HDC hdc;
if (px == pWState->pxOld)
return;
pxReCalc:
pWState->posNew = FlatSB_Internal_SBPosFromPx(pWState, px);
/* Tentative position changed -- notify the guy. */
if (pWState->posNew != pWState->posOld) {
FlatSB_Internal_DoScroll(pWState, SB_THUMBTRACK, pWState->posNew, pWState->fTrackVert);
if (!pWState->fTracking)
return;
pWState->posOld = pWState->posNew;
//
// Anything can happen after the SendMessage above in DoScroll!
// Make sure that the SBINFO structure contains data for the
// window being tracked -- if not, recalculate data in SBINFO
// If fVertSB is TRUE, the last CalcSBStuff call is for SB_VERT.
// If fTrackVert != fVertSB, we got garbage in pWState.
//
if (pWState->fTrackVert != pWState->fVertSB)
FlatSB_Internal_CalcSBStuff(pWState, pWState->fTrackVert);
// when we yield, our range can get messed with
// so make sure we handle this
if (px >= pWState->pxDownArrow - pWState->cpxThumb) {
px = pWState->pxDownArrow - pWState->cpxThumb;
goto pxReCalc;
}
}
hdc = GetWindowDC(hwnd);
pWState->pxThumbTop = px;
pWState->pxThumbBottom = pWState->pxThumbTop + pWState->cpxThumb;
// At this point, the disable flags are always going to be 0 --
// we're in the middle of tracking.
// We are Okay in this case, since in DrawElevator we decide the mode by
// cmd == SB_THUMBPOSITION.
FlatSB_Internal_DrawThumb2(pWState, hdc, pWState->fTrackVert, 0);
ReleaseDC(hwnd, hdc);
pWState->pxOld = px;
}
//=-------------------------------------------------------------------------
// DrawInvertScrollArea() -
//=-------------------------------------------------------------------------
void FlatSB_Internal_DrawInvertScrollArea(WSBState * pWState, BOOL fHit, int cmd)
{
HWND hwnd = pWState->sbHwnd;
HDC hdc;
if ((cmd != SB_LINEUP) && (cmd != SB_LINEDOWN))
{
FlatSB_Internal_InvertScrollHilite(pWState);
FlatSB_Internal_NotifyWinEvent(pWState, EVENT_OBJECT_STATECHANGE,
cmd == SB_PAGEUP ? INDEX_SCROLLBAR_UPPAGE
: INDEX_SCROLLBAR_DOWNPAGE);
return;
}
hdc = GetWindowDC(hwnd);
if (cmd == SB_LINEUP) {
if (pWState->fTrackVert) {
FlatSB_Internal_DrawArrow(pWState, hdc, &(pWState->rcTrack), DFCS_SCROLLUP, (fHit) ? DFCS_PUSHED : 0);
} else {
FlatSB_Internal_DrawArrow(pWState, hdc, &(pWState->rcTrack), DFCS_SCROLLLEFT, (fHit) ? DFCS_PUSHED : 0);
}
} else {
if (pWState->fTrackVert) {
FlatSB_Internal_DrawArrow(pWState, hdc, &(pWState->rcTrack), DFCS_SCROLLDOWN, (fHit) ? DFCS_PUSHED : 0);
} else {
FlatSB_Internal_DrawArrow(pWState, hdc, &(pWState->rcTrack), DFCS_SCROLLRIGHT, (fHit) ? DFCS_PUSHED : 0);
}
}
FlatSB_Internal_NotifyWinEvent(pWState, EVENT_OBJECT_STATECHANGE,
cmd == SB_LINEUP ? INDEX_SCROLLBAR_UP : INDEX_SCROLLBAR_DOWN);
ReleaseDC(hwnd, hdc);
}
//=-------------------------------------------------------------------------
// FlatSB_Internal_EndScroll() -
//=-------------------------------------------------------------------------
void FlatSB_Internal_EndScroll(WSBState * pWState, BOOL fCancel)
{
HWND hwnd = pWState->sbHwnd;
BOOL fVert = pWState->fTrackVert;
int oldcmd;
if (pWState->fTracking)
{
oldcmd = pWState->cmdSB;
pWState->cmdSB = 0;
// will not have capture if called by CancelModeProc
if (GetCapture() == hwnd)
ReleaseCapture();
if (pWState->pfnSB == FlatSB_Internal_TrackThumb)
{
if (fCancel) {
pWState->posOld = pWState->posStart;
}
FlatSB_Internal_DoScroll(pWState, SB_THUMBPOSITION, pWState->posOld, fVert);
FlatSB_Internal_DrawThumb(pWState, fVert);
}
else if (pWState->pfnSB == FlatSB_Internal_TrackBox)
{
DWORD lpt;
RECT rcWindow;
POINT pt;
if (pWState->hTimerSB)
KillTimer(hwnd, IDSYS_SCROLL);
lpt = GetMessagePos();
ASSERT(hwnd != GetDesktopWindow());
GetWindowRect(hwnd, &rcWindow);
pt.x = GET_X_LPARAM(lpt) - rcWindow.left;
pt.y = GET_Y_LPARAM(lpt) - rcWindow.top;
if (PtInRect(&(pWState->rcTrack), pt)) {
pWState->fHitOld = FALSE;
FlatSB_Internal_DrawInvertScrollArea(pWState, FALSE, oldcmd);
}
}
// Always send SB_ENDSCROLL message.
pWState->pfnSB = NULL;
// Anything can happen here. Client can call GetScrollInfo for THUMBPOSITION, and we
// should return 0, so we should set pfnSB to NULL first.
FlatSB_Internal_DoScroll(pWState, SB_ENDSCROLL, 0, fVert);
pWState->fTracking = FALSE;
pWState->fHitOld = FALSE;
FlatSB_Internal_NotifyWinEvent(pWState, EVENT_SYSTEM_SCROLLINGEND,
INDEXID_CONTAINER);
// Redraw the components.
FlatSB_NCHitTestProc(pWState, hwnd, 0, 0, TRUE);
}
}
//=-------------------------------------------------------------------------
// FlatSB_Internal_DoScroll() -
//=-------------------------------------------------------------------------
void FlatSB_Internal_DoScroll(WSBState *pWState, int cmd, int pos, BOOL fVert)
{
if (pWState->sbHwnd)
{
pWState->fInDoScroll++;
SendMessage(pWState->sbHwnd, (fVert ? WM_VSCROLL : WM_HSCROLL), (WPARAM)(LOWORD(pos) << 16 | (cmd & 0xffff)), (LPARAM)NULL);
pWState->fInDoScroll--;
}
}
//=-------------------------------------------------------------------------
// TimerScroll()
//=--------------------------------------------------------------------------
VOID CALLBACK TimerScroll(HWND hwnd, UINT message, UINT_PTR id, DWORD time)
{
LONG pos;
POINT pt;
UINT dblClkTime, dtScroll;
WSBState * pWState;
RECT rcWindow;
GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
if ((pWState == (WSBState *)NULL) || (pWState == WSB_UNINIT_HANDLE)) {
KillTimer(hwnd, IDSYS_SCROLL);
return;
}
ASSERT(hwnd != GetDesktopWindow());
pos = GetMessagePos();
pt.x = GET_X_LPARAM(pos), pt.y = GET_Y_LPARAM(pos);
dblClkTime = GetDoubleClickTime();
dtScroll = (dblClkTime * 4) / 5;
GetWindowRect(hwnd, &rcWindow);
pt.x -= rcWindow.left;
pt.y -= rcWindow.top;
pos = LOWORD(pt.y) << 16 | LOWORD(pt.x);
FlatSB_Internal_TrackBox(pWState, WM_NULL, 0, (LPARAM) pos);
if (pWState->fHitOld)
{
pWState->hTimerSB = SetTimer(hwnd, IDSYS_SCROLL, dtScroll / 8, TimerScroll);
FlatSB_Internal_DoScroll(pWState, pWState->cmdSB, 0, pWState->fTrackVert);
}
return;
}
//=-------------------------------------------------------------------------
// FlatSB_Internal_TrackBox() -
//=-------------------------------------------------------------------------
void FlatSB_Internal_TrackBox(WSBState * pWState, int message, WPARAM wParam, LPARAM lParam)
{
HWND hwnd = pWState->sbHwnd;
BOOL fHit, fVert = pWState->fTrackVert;
BOOL fHitOld = pWState->fHitOld;
POINT pt;
int cmsTimer;
UINT dblClkTime, dtScroll;
if (message && (message < WM_MOUSEFIRST || message > WM_MOUSELAST))
return;
dblClkTime = GetDoubleClickTime();
dtScroll = (dblClkTime * 4) / 5;
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
fHit = PtInRect(&(pWState->rcTrack), pt);
if (fHit != fHitOld) {
pWState->fHitOld = fHit;
FlatSB_Internal_DrawInvertScrollArea(pWState, fHit, pWState->cmdSB);
}
cmsTimer = dtScroll / 8;
switch (message)
{
case WM_LBUTTONUP:
FlatSB_Internal_EndScroll(pWState, FALSE);
break;
case WM_LBUTTONDOWN:
pWState->hTimerSB = 0;
cmsTimer = dtScroll;
/*** FALL THRU ***/
case WM_MOUSEMOVE:
if (fHit && (fHit != fHitOld))
{
/* We moved back into the normal rectangle: reset timer */
pWState->hTimerSB = SetTimer(hwnd, IDSYS_SCROLL, cmsTimer, TimerScroll);
FlatSB_Internal_DoScroll(pWState, pWState->cmdSB, 0, fVert);
}
}
}
//=-------------------------------------------------------------------------
// FlatSB_Internal_TrackThumb() -
//=-------------------------------------------------------------------------
void FlatSB_Internal_TrackThumb(WSBState * pWState, int message, WPARAM wParam, LPARAM lParam)
{
HWND hwnd = pWState->sbHwnd;
BOOL fVert = pWState->fTrackVert;
POINT pt;
if (message < WM_MOUSEFIRST || message > WM_MOUSELAST)
return;
// Make sure that the SBINFO structure contains data for the
// window being tracked -- if not, recalculate data in SBINFO
if (pWState->fTrackVert != pWState->fVertSB)
FlatSB_Internal_CalcSBStuff(pWState, pWState->fTrackVert);
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
if (!PtInRect(&(pWState->rcTrack), pt))
pWState->px = pWState->pxStart;
else
{
pWState->px = (fVert ? GET_Y_LPARAM(lParam) : GET_X_LPARAM(lParam)) + pWState->dpxThumb;
if (pWState->px < pWState->pxUpArrow)
pWState->px = pWState->pxUpArrow;
else if (pWState->px >= (pWState->pxDownArrow - pWState->cpxThumb))
pWState->px = pWState->pxDownArrow - pWState->cpxThumb;
}
FlatSB_Internal_MoveThumb(pWState, pWState->px);
if (message == WM_LBUTTONUP)
FlatSB_Internal_EndScroll(pWState, FALSE);
}
//=-------------------------------------------------------------------------
// FlatSB_Internal_SBTrackLoop() -
//=-------------------------------------------------------------------------
void FlatSB_Internal_SBTrackLoop(WSBState * pWState, LPARAM lParam)
{
HWND hwnd = pWState->sbHwnd;
MSG msg;
int cmd, newlParam;
POINT pt;
if (!pWState->fTracking)
return;
FlatSB_Internal_NotifyWinEvent(pWState, EVENT_SYSTEM_SCROLLINGSTART,
INDEXID_CONTAINER);
(*(pWState->pfnSB))(pWState, WM_LBUTTONDOWN, 0, lParam);
while (GetCapture() == hwnd)
{
if (!GetMessage(&msg, NULL, 0, 0))
break;
if (!CallMsgFilter(&msg, MSGF_SCROLLBAR)) {
cmd = msg.message;
if (msg.hwnd == hwnd &&
((cmd >= WM_MOUSEFIRST && cmd <= WM_MOUSELAST) ||
(cmd >= WM_KEYFIRST && cmd <= WM_KEYLAST ) ))
{
// Process Key
#define ALT_PRESSED 0x20000000L
if (cmd >= WM_SYSKEYDOWN
&& cmd <= WM_SYSDEADCHAR
&& msg.lParam & ALT_PRESSED)
cmd -= (WM_SYSKEYDOWN - WM_KEYDOWN);
#undef ALT_PRESSED
if (!pWState->fTracking)
return;
// Change to coordinates according to left-top corner of the window.
pt.x = GET_X_LPARAM(msg.lParam) + pWState->rcClient.left;
pt.y = GET_Y_LPARAM(msg.lParam) + pWState->rcClient.top;
newlParam = LOWORD(pt.y) << 16 | LOWORD(pt.x);
(*(pWState->pfnSB))(pWState, cmd, msg.wParam, (LPARAM)newlParam);
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
}
//=-------------------------------------------------------------------------
// FlatSB_Internal_SBTrackInit() -
//=-------------------------------------------------------------------------
void FlatSB_Internal_SBTrackInit(WSBState * pWState, HWND hwnd, LPARAM lParam, int hitArea, BOOL fDirect)
{
int hitX = GET_X_LPARAM(lParam);
int hitY = GET_Y_LPARAM(lParam);
int px;
int *pwX;
int *pwY;
int wDisable; // Scroll bar disable flags;
RECT rcWindow;
BOOL fVert;
POINT pt;
// hitArea = 0 indicates a scroll bar control
// otherwise, curArea will have the hit test area
if (hitArea == HTHSCROLL)
fVert = FALSE;
else if (hitArea == HTVSCROLL)
fVert = TRUE;
else
return;
ASSERT(hwnd != GetDesktopWindow());
GetWindowRect(hwnd, &rcWindow);
pt.x = GET_X_LPARAM(lParam) - rcWindow.left;
pt.y = GET_Y_LPARAM(lParam) - rcWindow.top;
lParam = LOWORD(pt.y) << 16 | LOWORD(pt.x);
wDisable = FlatSB_Internal_GetSBFlags(pWState, fVert);
if ((wDisable & ESB_DISABLE_BOTH) == ESB_DISABLE_BOTH) {
// Whole Scroll Bar is disabled -- do not respond
pWState->pfnSB = NULL;
pWState->fTracking = FALSE;
return;
}
pWState->hTimerSB = 0;
pWState->fHitOld = FALSE;
pWState->fTracking = FALSE;
// For the case we click on scroll bar of a nonactive window. The mode is set to FLAT
// by HitTestProc. This will work because we set the tracking flag right away.
if (fVert) {
pWState->fVActive = TRUE; pWState->fHActive = FALSE;
} else {
pWState->fHActive = TRUE; pWState->fVActive = FALSE;
}
// This will give us the right locMouse. We will keep it till EndScroll.
FlatSB_Internal_CalcSBStuff(pWState, fVert);
// From now till EndScroll, CalcSBStuff won't compute new locMouse.
pWState->pfnSB = FlatSB_Internal_TrackBox;
pWState->fTracking = TRUE;
// Initialize rcSB to the Rectangle of the Entire Scroll Bar
pwX = (int *)&(pWState->rcSB);
pwY = pwX + 1;
if (!fVert)
pwX = pwY--;
pwX[0] = pWState->pxLeft;
pwY[0] = pWState->pxTop;
pwX[2] = pWState->pxRight;
pwY[2] = pWState->pxBottom;
px = (fVert ? pt.y : pt.x);
pWState->px = px;
if (px < pWState->pxUpArrow)
{ // The click occurred on Left/Up arrow
if(wDisable & LTUPFLAG)
{ // Disabled -- do not respond
pWState->pfnSB = NULL;
pWState->fTracking = FALSE;
return;
}
// LINEUP -- make rcSB the Up Arrow's Rectangle
pWState->cmdSB = SB_LINEUP;
pwY[2] = pWState->pxUpArrow;
}
else if (px >= pWState->pxDownArrow)
{ // The click occurred on Right/Down arrow
if(wDisable & RTDNFLAG)
{ // Disabled -- do not respond
pWState->pfnSB = NULL;
pWState->fTracking = FALSE;
return;
}
// LINEDOWN -- make rcSB the Down Arrow's Rectangle
pWState->cmdSB = SB_LINEDOWN;
pwY[0] = pWState->pxDownArrow;
}
else if (px < pWState->pxThumbTop)
{
// PAGEUP -- make rcSB the rectangle between Up Arrow and Thumb
pWState->cmdSB = SB_PAGEUP;
pwY[0] = pWState->pxUpArrow;
pwY[2] = pWState->pxThumbTop;
}
else if (px < pWState->pxThumbBottom)
{
DoThumbPos:
if (pWState->pxDownArrow - pWState->pxUpArrow <= pWState->cpxThumb) {
// Not enough room -- elevator isn't there
pWState->pfnSB = NULL;
pWState->fTracking = FALSE;
return;
}
// THUMBPOSITION -- we're tracking with the thumb
pWState->cmdSB = SB_THUMBPOSITION;
pWState->fTrackVert = fVert;
CopyRect(&(pWState->rcTrack), &(pWState->rcSB));
if (pWState->sbGutter < 0) {
// Negative gutter means "infinite size"
pWState->rcTrack.top = MINLONG;
pWState->rcTrack.left = MINLONG;
pWState->rcTrack.right = MAXLONG;
pWState->rcTrack.bottom = MAXLONG;
} else
if (fVert)
InflateRect(&(pWState->rcTrack),
(pWState->rcTrack.right - pWState->rcTrack.left) * pWState->sbGutter,
pWState->y_VSBThumb * pWState->sbGutter);
else
InflateRect(&(pWState->rcTrack),
pWState->x_HSBThumb * pWState->sbGutter,
(pWState->rcTrack.bottom - pWState->rcTrack.top) * pWState->sbGutter);
pWState->pfnSB = FlatSB_Internal_TrackThumb;
pWState->pxOld = pWState->pxStart = pWState->pxThumbTop;
pWState->posOld = pWState->posNew = pWState->posStart = fVert?pWState->sbVThumbPos:pWState->sbHThumbPos;
pWState->dpxThumb = pWState->pxThumbTop - pWState->px;
SetCapture(hwnd);
FlatSB_Internal_DoScroll(pWState, SB_THUMBTRACK, pWState->posOld, fVert);
FlatSB_Internal_DrawThumb(pWState, fVert);
}
else if (px < pWState->pxDownArrow)
{
// PAGEDOWN -- make rcSB the rectangle between Thumb and Down Arrow
pWState->cmdSB = SB_PAGEDOWN;
pwY[0] = pWState->pxThumbBottom;
pwY[2] = pWState->pxDownArrow;
}
// NT5-style tracking: Shift+Click = "Go here"
if (g_bRunOnNT5 && fDirect && pWState->cmdSB != SB_LINEUP && pWState->cmdSB != SB_LINEDOWN) {
if (pWState->cmdSB != SB_THUMBPOSITION) {
goto DoThumbPos;
}
pWState->dpxThumb = -(pWState->cpxThumb / 2);
}
if (pWState->cmdSB != SB_THUMBPOSITION) {
pWState->fTrackVert = fVert;
SetCapture(hwnd);
CopyRect(&(pWState->rcTrack), &(pWState->rcSB));
}
FlatSB_Internal_SBTrackLoop(pWState, lParam);
}
//=-------------------------------------------------------------------------
// GetScroll...() -
//=-------------------------------------------------------------------------
int WINAPI FlatSB_GetScrollPos(HWND hwnd, int code)
{
WSBState * pWState;
ASSERT (code != SB_CTL);
GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
if (pWState == (WSBState *)NULL) {
return GetScrollPos(hwnd, code);
} else if (pWState == WSB_UNINIT_HANDLE) {
return 0;
} else if (pWState->sbHwnd != hwnd) {
return 0;
} else {
return ((code == SB_VERT)?pWState->sbVThumbPos:pWState->sbHThumbPos);
}
}
BOOL WINAPI FlatSB_GetScrollPropPtr(HWND hwnd, int propIndex, PINT_PTR pValue)
{
WSBState * pWState;
if (!pValue)
return FALSE;
else
*pValue = 0; // If we can't set it, we reset it.
GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
if (pWState == (WSBState *)NULL) {
return FALSE;
} else if (pWState == WSB_UNINIT_HANDLE) {
pWState = FlatSB_Internal_InitPwSB(hwnd);
if (pWState == (WSBState *)NULL)
return FALSE;
else if (!SetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR)pWState)) {
DeleteObject(pWState->hbm_Bkg);
DeleteObject(pWState->hbr_Bkg);
LocalFree((HLOCAL)pWState);
return FALSE;
} else {
// Fall through.
}
} else if (pWState->sbHwnd != hwnd) {
return FALSE;
}
switch (propIndex) {
case WSB_PROP_CYVSCROLL:
*pValue = pWState->metApp.cyVSBArrow;
break;
case WSB_PROP_CXVSCROLL:
*pValue = pWState->metApp.cxVSBArrow;
break;
case WSB_PROP_CYHSCROLL:
*pValue = pWState->metApp.cyHSBArrow;
break;
case WSB_PROP_CXHSCROLL:
*pValue = pWState->metApp.cxHSBArrow;
break;
case WSB_PROP_CXHTHUMB:
*pValue = pWState->metApp.cxHSBThumb;
break;
case WSB_PROP_CYVTHUMB:
*pValue = pWState->metApp.cyVSBThumb;
break;
case WSB_PROP_WINSTYLE:
// To check if a scrollbar is present, the WF(HV)PRESENT bits may
// be more useful than WS_(HV)SCROLL bits.
*pValue = pWState->style;
break;
case WSB_PROP_HSTYLE:
*pValue = pWState->hStyle;
break;
case WSB_PROP_VSTYLE:
*pValue = pWState->vStyle;
break;
case WSB_PROP_HBKGCOLOR:
*pValue = pWState->col_HSBBkg;
break;
case WSB_PROP_VBKGCOLOR:
*pValue = pWState->col_VSBBkg;
break;
case WSB_PROP_PALETTE:
*pValue = (INT_PTR)pWState->hPalette;
break;
case WSB_PROP_GUTTER:
*pValue = pWState->sbGutter;
break;
default:
return FALSE;
}
return TRUE;
}
#ifdef _WIN64
BOOL WINAPI FlatSB_GetScrollProp(HWND hwnd, int propIndex, LPINT pValue)
{
INT_PTR iValue;
BOOL fRc;
if (!pValue)
return FALSE;
#ifdef DEBUG
if (propIndex == WSB_PROP_PALETTE)
{
TraceMsg(TF_ERROR, "FlatSB_GetScrollProp(WSB_PROP_PALETTE): Use GetScrollPropPtr for Win64 compat");
}
#endif
fRc = FlatSB_GetScrollPropPtr(hwnd, propIndex, &iValue);
*pValue = (int)iValue;
return fRc;
}
#endif
BOOL WINAPI FlatSB_GetScrollRange(HWND hwnd, int code, LPINT lpposMin, LPINT lpposMax)
{
int *pw;
WSBState * pWState;
ASSERT(code != SB_CTL);
if (!lpposMin || !lpposMax)
return FALSE;
GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
if (pWState == (WSBState *)NULL) {
return GetScrollRange(hwnd, code, lpposMin, lpposMax);
// *lpposMin = 0;
// *lpposMax = 0;
} else if (pWState == WSB_UNINIT_HANDLE) {
*lpposMin = 0;
*lpposMax = 0;
} else if (pWState->sbHwnd != hwnd) {
return FALSE;
} else {
pw = (code == SB_VERT) ? &(pWState->sbVMinPos) : &(pWState->sbHMinPos);
*lpposMin = pw[SBO_MIN];
*lpposMax = pw[SBO_MAX];
}
return TRUE;
}
BOOL WINAPI FlatSB_GetScrollInfo(HWND hwnd, int fnBar, LPSCROLLINFO lpsi)
{
int *pw;
WSBState * pWState;
ASSERT(fnBar != SB_CTL);
// ZDC@Oct. 10, Detect GP faults here.
if ((LPSCROLLINFO)NULL == lpsi)
return FALSE;
if (lpsi->cbSize < sizeof (SCROLLINFO))
return FALSE;
// ZDC@Oct. 11, Don't zero out buffer anymore.
GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
if (pWState == (WSBState *)NULL) {
return GetScrollInfo(hwnd, fnBar, lpsi);
} else if (pWState == WSB_UNINIT_HANDLE) {
return FALSE;
} else if (pWState->sbHwnd != hwnd) {
return FALSE;
} else if (fnBar == SB_VERT) {
pw = &(pWState->sbVMinPos);
} else if (fnBar == SB_HORZ) {
pw = &(pWState->sbHMinPos);
} else {
return FALSE;
}
if (lpsi->fMask & SIF_RANGE)
lpsi->nMin = pw[SBO_MIN], lpsi->nMax = pw[SBO_MAX];
if (lpsi->fMask & SIF_POS)
lpsi->nPos = pw[SBO_POS];
if (lpsi->fMask & SIF_PAGE)
lpsi->nPage = pw[SBO_PAGE];
// ZDC@Oct 9, Add support for SIF_TRACKPOS
if (lpsi->fMask & SIF_TRACKPOS) {
// This is the olny place that pfnSB is used instead of fTracking.
if (pWState->pfnSB != NULL) {
if ((fnBar == SB_VERT) && pWState->fTrackVert)
lpsi->nTrackPos = pWState->posNew;
else if ((fnBar == SB_HORZ) && !(pWState->fTrackVert))
lpsi->nTrackPos = pWState->posNew;
else
lpsi->nTrackPos = pw[SBO_POS];
} else
lpsi->nTrackPos = pw[SBO_POS];
}
return TRUE;
}
BOOL WINAPI FlatSB_ShowScrollBar(HWND hwnd, int fnBar, BOOL fShow)
{
BOOL fChanged = FALSE;
int newStyle = 0;
WSBState * pWState;
ASSERT(fnBar != SB_CTL);
GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
if (pWState == (WSBState *)NULL)
return ShowScrollBar(hwnd, fnBar, fShow);
switch (fnBar) {
case SB_VERT:
newStyle = WS_VSCROLL;
break;
case SB_HORZ:
newStyle = WS_HSCROLL;
break;
case SB_BOTH:
newStyle = WS_VSCROLL | WS_HSCROLL;
break;
default:
return FALSE;
}
if (pWState == WSB_UNINIT_HANDLE) {
if (fShow) {
pWState = FlatSB_Internal_InitPwSB(hwnd);
if (pWState == (WSBState *)NULL)
return FALSE;
else if (!SetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR)pWState)) {
DeleteObject(pWState->hbm_Bkg);
DeleteObject(pWState->hbr_Bkg);
LocalFree((HLOCAL)pWState);
return FALSE;
}
} else {
return FALSE;
}
}
if (!fShow) {
if (pWState->style & newStyle) {
fChanged = TRUE;
pWState->style &= ~newStyle;
}
} else {
if ((pWState->style & newStyle) != newStyle) {
fChanged = TRUE;
pWState->style |= newStyle;
}
}
if (fChanged) {
// Keep USER scrollbars in sync for accessibility
ShowScrollBar(hwnd, fnBar, fShow);
CCInvalidateFrame(hwnd);
}
return TRUE;
}
//=------------------------------------------------------------------
// Following functions are ported from winsb.c in user code.
//=------------------------------------------------------------------
//=--------------------------------------------------------------
// InitPwSB
// [in] hwnd
// Note:
// This function is only a memory allocating func. It won't
// do any check. On the other hand, this function should be
// called before any consequent functions are used.
//=--------------------------------------------------------------
WSBState * FlatSB_Internal_InitPwSB(HWND hwnd)
{
int patGray[4];
HBITMAP hbm;
WSBState * pw;
pw = (WSBState *)LocalAlloc(LPTR, sizeof(WSBState));
// The buffer should already be zero-out.
if (pw == (WSBState *)NULL)
return pw;
patGray[0] = 0x005500AA;
patGray[1] = 0x005500AA;
patGray[2] = 0x005500AA;
patGray[3] = 0x005500AA;
pw->sbVMaxPos = pw->sbHMaxPos = 100;
pw->sbHwnd = hwnd;
// We start out with app metrics equal to system metrics
FlatSB_InitWSBMetrics(pw);
pw->metApp = pw->metSys;
//
// NT5's gutter is 8; Win9x's and NT4's gutter is 2.
//
pw->sbGutter = g_bRunOnNT5 ? 8 : 2;
// ZDC
// make sure get hbm_Bkg and hbr_Bkg deleted.
hbm = CreateBitmap(8, 8, 1, 1, (LPSTR)patGray);
if ((HBITMAP)NULL == hbm) {
LocalFree((HLOCAL)pw);
return NULL;
}
pw->hbr_VSBBkg = CreatePatternBrush(hbm);
if ((HBRUSH)NULL == pw->hbr_VSBBkg) {
DeleteObject(hbm);
LocalFree((HLOCAL)pw);
return NULL;
}
pw->hbr_Bkg = pw->hbr_HSBBkg = pw->hbr_VSBBkg;
pw->col_VSBBkg = pw->col_HSBBkg = RGB(255, 255, 255);
pw->hbm_Bkg = hbm;
pw->hStyle = pw->vStyle = FSB_FLAT_MODE; // Default state: Flat.
pw->ptMouse.x = -1;
pw->ptMouse.y = -1;
return(pw);
}
void FlatSB_Internal_RedrawScrollBar(WSBState * pWState, BOOL fVert)
{
HDC hdc;
hdc = GetWindowDC(pWState->sbHwnd);
FlatSB_Internal_DrawScrollBar(pWState, hdc, fVert, TRUE);
ReleaseDC(pWState->sbHwnd, hdc);
}
//=-------------------------------------------------------------
// FlatSB_Internal_GetSBFlags
//=-------------------------------------------------------------
UINT FlatSB_Internal_GetSBFlags(WSBState * pWState, BOOL fVert)
{
int wFlags;
if (pWState == (WSBState *)NULL) {
return(0);
}
wFlags = pWState->sbFlags;
return(fVert ? (wFlags & WSB_VERT) >> 2 : wFlags & WSB_HORZ);
}
//=--------------------------------------------------------------
// return TRUE if there is a change.
//=--------------------------------------------------------------
BOOL WINAPI FlatSB_EnableScrollBar(HWND hwnd, int wSBflags, UINT wArrows)
{
WSBState * pWState;
GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
if (pWState == (WSBState *)NULL) {
return EnableScrollBar(hwnd, wSBflags, wArrows);
} else if (pWState == WSB_UNINIT_HANDLE) {
if (wArrows == ESB_ENABLE_BOTH)
// Leave it to later calls.
return FALSE;
else {
pWState = FlatSB_Internal_InitPwSB(hwnd);
if (pWState == (WSBState *)NULL)
return FALSE;
else if (!SetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR)pWState)) {
DeleteObject(pWState->hbm_Bkg);
DeleteObject(pWState->hbr_Bkg);
LocalFree((HLOCAL)pWState);
return FALSE;
}
}
} else if (hwnd != pWState->sbHwnd) {
return FALSE;
}
return FlatSB_Internal_EnableScrollBar(pWState, wSBflags, wArrows);
}
//=-------------------------------------------------------------
// FlatSB_Internal_EnableScrollBar
//
// Note:
// The func will simply fail in case of uninitialized pointer
// pWState is passed.
// Since we now use WSBState * as handle, we always hope it's
// valid already.
//
// The following func is implemented following the comments in
// winsbctl.c and the comment of the in MSDN library. In
// access\inc16\windows.h you can find:
// #define SB_DISABLE_MASK ESB_DISABLE_BOTH // 0x03
//
// The sbFlags is slightly different with rgwScroll[SB_FLAGS].
//=-------------------------------------------------------------
BOOL FlatSB_Internal_EnableScrollBar(WSBState * pWState, int wSBflags, UINT wArrows)
{
int wOldFlags;
int style;
BOOL bRetValue = FALSE;
BOOL bDrawHBar = FALSE;
BOOL bDrawVBar = FALSE;
HDC hdc;
HWND hwnd;
ASSERT (wSBflags != SB_CTL);
wOldFlags = pWState->sbFlags;
hwnd = pWState->sbHwnd;
style = GetWindowLong(hwnd, GWL_STYLE);
switch (wSBflags) {
case SB_HORZ:
case SB_BOTH:
if (wArrows == ESB_ENABLE_BOTH)
pWState->sbFlags &= ~WSB_HORZ;
else
pWState->sbFlags |= wArrows;
if (wOldFlags != pWState->sbFlags)
{
bRetValue = TRUE;
if (TestSTYLE(pWState->style, WFHPRESENT)
&& !TestSTYLE(style, WS_MINIMIZE)
&& IsWindowVisible(hwnd))
bDrawHBar = TRUE;
}
if (wSBflags == SB_HORZ)
break;
else
wOldFlags = pWState->sbFlags; // Fall through
case SB_VERT:
if (wArrows == ESB_ENABLE_BOTH)
pWState->sbFlags &= ~WSB_VERT;
else
pWState->sbFlags |= (wArrows<<2);
if (wOldFlags != pWState->sbFlags)
{
bRetValue = TRUE;
if (TestSTYLE(pWState->style, WFVPRESENT)
&& !TestSTYLE(style, WS_MINIMIZE)
&& IsWindowVisible(hwnd))
bDrawVBar = TRUE;
}
break;
default:
return FALSE;
}
if (bDrawVBar || bDrawHBar) {
int oldLoc = pWState->locMouse;
int newLoc;
if (!(hdc = GetWindowDC(hwnd)))
return(FALSE);
newLoc = oldLoc;
if (bDrawHBar) {
FlatSB_Internal_DrawScrollBar(pWState, hdc, FALSE, FALSE);
if (pWState->fHActive)
newLoc = pWState->locMouse;
}
if (bDrawVBar) {
pWState->locMouse = oldLoc;
FlatSB_Internal_DrawScrollBar(pWState, hdc, TRUE, FALSE);
if (pWState->fVActive)
newLoc = pWState->locMouse;
}
pWState->locMouse = newLoc;
ReleaseDC(hwnd, hdc);
}
// Keep USER scrollbar in sync for accessibility
if (bRetValue)
EnableScrollBar(hwnd, wSBflags, wArrows);
return bRetValue;
}
//=-------------------------------------------------------------
// FlatSB_Internal_DrawThumb2
//=-------------------------------------------------------------
void FlatSB_Internal_DrawThumb2(WSBState * pWState, HDC hdc, BOOL fVert, UINT wDisable)
{
int *pLength;
int *pWidth;
HWND hwnd;
HBRUSH hbr;
hwnd = pWState->sbHwnd;
hbr = (fVert)?pWState->hbr_VSBBkg:pWState->hbr_HSBBkg;
// Bail out if the scrollbar has an empty rect
if ((pWState->pxTop >= pWState->pxBottom)
|| (pWState->pxLeft >= pWState->pxRight))
return;
pLength = (int *) &(pWState->rcSB);
if (fVert)
pWidth = pLength++;
else
pWidth = pLength + 1;
pWidth[0] = pWState->pxLeft;
pWidth[2] = pWState->pxRight;
// If both scroll arrows are disabled or if there isn't enough room for
// the thumb, just erase the whole slide area and return
if (((wDisable & LTUPFLAG) && (wDisable & RTDNFLAG)) ||
((pWState->pxDownArrow - pWState->pxUpArrow) < pWState->cpxThumb))
{
pLength[0] = pWState->pxUpArrow;
pLength[2] = pWState->pxDownArrow;
FlatSB_Internal_DrawGroove(pWState, hdc, &(pWState->rcSB), fVert);
return;
}
// UI designers want a at least 1 pixel gap between arrow and thumb.
// Have to do this :(
if (pWState->pxUpArrow <= pWState->pxThumbTop)
{
// Fill in space above Thumb
pLength[0] = pWState->pxUpArrow;
pLength[2] = pWState->pxThumbTop;
FlatSB_Internal_DrawGroove(pWState, hdc, &(pWState->rcSB), fVert);
}
if (pWState->pxThumbBottom <= pWState->pxDownArrow)
{
// Fill in space below Thumb
pLength[0] = pWState->pxThumbBottom;
pLength[2] = pWState->pxDownArrow;
FlatSB_Internal_DrawGroove(pWState, hdc, &(pWState->rcSB), fVert);
}
// Draw elevator
pLength[0] = pWState->pxThumbTop;
pLength[2] = pWState->pxThumbBottom;
FlatSB_Internal_DrawElevator(pWState, hdc, &(pWState->rcSB), fVert);
// If we're tracking a page scroll, then we've obliterated the hilite.
// We need to correct the hiliting rectangle, and rehilite it.
if ((pWState->cmdSB == SB_PAGEUP || pWState->cmdSB == SB_PAGEDOWN)
&& pWState->fTrackVert == fVert)
{
pLength = (int *) &pWState->rcTrack;
if (fVert)
pLength++;
if (pWState->cmdSB == SB_PAGEUP)
pLength[2] = pWState->pxThumbTop;
else
pLength[0] = pWState->pxThumbBottom;
if (pLength[0] < pLength[2])
InvertRect(hdc, &(pWState->rcTrack));
}
}
//=-------------------------------------------------------------
// DrawSB2
//=-------------------------------------------------------------
void FlatSB_Internal_DrawSB2(WSBState * pWState, HDC hdc, BOOL fVert, BOOL fRedraw, int oldLoc)
{
int cLength;
int cWidth;
int cpxArrow;
int *pwX;
int *pwY;
int newLoc = pWState->locMouse;
UINT wDisable = FlatSB_Internal_GetSBFlags(pWState, fVert);
HBRUSH hbrSave;
HWND hwnd;
RECT rc, * prcSB;
hwnd = pWState->sbHwnd;
cLength = (pWState->pxBottom - pWState->pxTop) / 2;
cWidth = (pWState->pxRight - pWState->pxLeft);
if ((cLength <= 0) || (cWidth <= 0))
return;
cpxArrow = (fVert) ? pWState->y_VSBArrow : pWState->x_HSBArrow;
if (cLength > cpxArrow)
cLength = cpxArrow;
prcSB = &(pWState->rcSB);
pwX = (int *)prcSB;
pwY = pwX + 1;
if (!fVert)
pwX = pwY--;
pwX[0] = pWState->pxLeft;
pwY[0] = pWState->pxTop;
pwX[2] = pWState->pxRight;
pwY[2] = pWState->pxBottom;
hbrSave = SelectObject(hdc, GetSysColorBrush(COLOR_BTNTEXT));
CopyRect(&rc, prcSB);
if (fVert)
{
rc.bottom = rc.top + cLength;
if (!fRedraw || newLoc == WSB_MOUSELOC_ARROWUP
|| oldLoc == WSB_MOUSELOC_ARROWUP)
FlatSB_Internal_DrawArrow(pWState, hdc, &rc, DFCS_SCROLLUP,
((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
rc.bottom = prcSB->bottom;
rc.top = prcSB->bottom - cLength;
if (!fRedraw || newLoc == WSB_MOUSELOC_ARROWDN
|| oldLoc == WSB_MOUSELOC_ARROWDN)
FlatSB_Internal_DrawArrow(pWState, hdc, &rc, DFCS_SCROLLDOWN,
((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0));
}
else
{
rc.right = rc.left + cLength;
if (!fRedraw || newLoc == WSB_MOUSELOC_ARROWLF
|| oldLoc == WSB_MOUSELOC_ARROWLF)
FlatSB_Internal_DrawArrow(pWState, hdc, &rc, DFCS_SCROLLLEFT,
((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
rc.right = prcSB->right;
rc.left = prcSB->right - cLength;
if (!fRedraw || newLoc == WSB_MOUSELOC_ARROWRG
|| oldLoc == WSB_MOUSELOC_ARROWRG)
FlatSB_Internal_DrawArrow(pWState, hdc, &rc, DFCS_SCROLLRIGHT,
((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0));
}
SelectObject(hdc, hbrSave);
if (!fRedraw)
FlatSB_Internal_DrawThumb2(pWState, hdc, fVert, wDisable);
else if (!fVert || newLoc == WSB_MOUSELOC_H_THUMB
|| oldLoc == WSB_MOUSELOC_H_THUMB)
FlatSB_Internal_DrawThumb2(pWState, hdc, fVert, wDisable);
else if (fVert || newLoc == WSB_MOUSELOC_V_THUMB
|| oldLoc == WSB_MOUSELOC_V_THUMB)
FlatSB_Internal_DrawThumb2(pWState, hdc, fVert, wDisable);
else
return;
}
//=-------------------------------------------------------------
// FlatSB_Internal_CalcSBStuff2
//=-------------------------------------------------------------
void FlatSB_Internal_CalcSBStuff2(WSBState * pWState, LPRECT lprc, BOOL fVert)
{
int cpxThumb; // Height of (V)scroll bar thumb.
int cpxArrow; // Height of (V)scroll bar arrow.
int cpxSpace; // The space in scroll bar;
int pxTop;
int pxBottom;
int pxLeft;
int pxRight;
int pxUpArrow;
int pxDownArrow;
int pxThumbTop;
int pxThumbBottom;
int pxMouse;
int locMouse;
int dwRange, page, relPos;
BOOL fSBActive;
if (fVert) {
pxTop = lprc->top;
pxBottom = lprc->bottom;
pxLeft = lprc->left;
pxRight = lprc->right;
cpxArrow = pWState->y_VSBArrow;
cpxThumb = pWState->y_VSBThumb;
relPos = pWState->sbVThumbPos - pWState->sbVMinPos;
page = pWState->sbVPage;
dwRange = pWState->sbVMaxPos - pWState->sbVMinPos + 1;
pxMouse = pWState->ptMouse.y;
fSBActive = pWState->fVActive;
} else {
// For horiz scroll bars, "left" & "right" are "top" and "bottom",
// and vice versa.
pxTop = lprc->left;
pxBottom = lprc->right;
pxLeft = lprc->top;
pxRight = lprc->bottom;
cpxArrow = pWState->x_HSBArrow;
cpxThumb = pWState->x_HSBThumb;
relPos = pWState->sbHThumbPos - pWState->sbHMinPos;
page = pWState->sbHPage;
dwRange = pWState->sbHMaxPos - pWState->sbHMinPos + 1;
pxMouse = pWState->ptMouse.x;
fSBActive = pWState->fHActive;
}
// For the case of short scroll bars that don't have enough
// room to fit the full-sized up and down arrows, shorten
// their sizes to make 'em fit
cpxArrow = min((pxBottom - pxTop) >> 1, cpxArrow);
pxUpArrow = pxTop + cpxArrow;
pxDownArrow = pxBottom - cpxArrow;
cpxSpace = pxDownArrow - pxUpArrow;
if (page)
{
// JEFFBOG -- This is the one and only place where we should
// see 'range'. Elsewhere it should be 'range - page'.
cpxThumb = max(DMultDiv(cpxSpace, page, dwRange),
min(cpxThumb, MINITHUMBSIZE));
}
cpxSpace -= cpxThumb;
pxThumbTop = DMultDiv(relPos, cpxSpace, dwRange - (page ? page : 1)) + pxUpArrow;
pxThumbBottom = pxThumbTop + cpxThumb;
// Save it to local structure
pWState->pxLeft = pxLeft;
pWState->pxRight = pxRight;
pWState->pxTop = pxTop;
pWState->pxBottom = pxBottom;
pWState->pxUpArrow = pxUpArrow;
pWState->pxDownArrow = pxDownArrow;
pWState->pxThumbTop = pxThumbTop;
pWState->pxThumbBottom = pxThumbBottom;
pWState->cpxArrow = cpxArrow;
pWState->cpxThumb = cpxThumb;
pWState->cpxSpace = cpxSpace;
pWState->fVertSB = fVert;
if (pWState->fTracking) {
return;
} else if (!fSBActive) {
locMouse = WSB_MOUSELOC_OUTSIDE;
} else if (pxMouse < pxTop) {
locMouse = WSB_MOUSELOC_OUTSIDE;
} else if (pxMouse < pxUpArrow) {
locMouse = WSB_MOUSELOC_ARROWUP;
} else if (pxMouse < pxThumbTop) {
locMouse = WSB_MOUSELOC_V_GROOVE;
} else if (pxMouse >= pxBottom) {
locMouse = WSB_MOUSELOC_OUTSIDE;
} else if (pxMouse >= pxDownArrow) {
locMouse = WSB_MOUSELOC_ARROWDN;
} else if (pxMouse >= pxThumbBottom) {
locMouse = WSB_MOUSELOC_V_GROOVE;
} else { // pxThumbTop <= pxMouse < pxThumbBottom
if (pxDownArrow - pxUpArrow <= cpxThumb) { // No space for thumnb.
locMouse = WSB_MOUSELOC_V_GROOVE;
} else {
locMouse = WSB_MOUSELOC_V_THUMB;
}
}
if ((!fVert) && locMouse)
locMouse += 4;
pWState->locMouse = locMouse;
}
//=-------------------------------------------------------------
// FlatSB_Internal_CalcSBStuff
//
// Note:
// We won't call InitPwSB in this func.
//=-------------------------------------------------------------
void FlatSB_Internal_CalcSBStuff(WSBState * pWState, BOOL fVert)
{
HWND hwnd;
RECT rcT;
int style;
if (pWState == (WSBState *)NULL)
return;
hwnd = pWState->sbHwnd;
style = GetWindowLong(hwnd, GWL_STYLE);
if (fVert)
{
// Only add on space if vertical scrollbar is really there.
rcT.right = rcT.left = pWState->rcClient.right;
if (TestSTYLE(pWState->style, WFVPRESENT))
rcT.right += pWState->x_VSBArrow;
rcT.top = pWState->rcClient.top;
rcT.bottom = pWState->rcClient.bottom;
}
else
{
// Only add on space if horizontal scrollbar is really there.
rcT.bottom = rcT.top = pWState->rcClient.bottom;
if (TestSTYLE(pWState->style, WFHPRESENT))
rcT.bottom += pWState->y_HSBArrow;
rcT.left = pWState->rcClient.left;
rcT.right = pWState->rcClient.right;
}
FlatSB_Internal_CalcSBStuff2(pWState, &rcT, fVert);
}
//=-------------------------------------------------------------
// FlatSB_Internal_DrawThumb
//=-------------------------------------------------------------
void FlatSB_Internal_DrawThumb(WSBState * pWState, BOOL fVert)
{
HWND hwnd = pWState->sbHwnd;
HDC hdc;
UINT wDisableFlags;
hdc = (HDC) GetWindowDC(hwnd);
FlatSB_Internal_CalcSBStuff(pWState, fVert);
wDisableFlags = FlatSB_Internal_GetSBFlags(pWState, fVert);
FlatSB_Internal_DrawThumb2(pWState, hdc, fVert, wDisableFlags);
ReleaseDC(hwnd, hdc);
}
BOOL FlatSB_Internal_SBSetParms(int * pw, SCROLLINFO si, BOOL * lpfScroll, LRESULT * lplres, BOOL bOldPos)
{
// pass the struct because we modify the struct but don't want that
// modified version to get back to the calling app
BOOL fChanged = FALSE;
if (bOldPos)
// save previous position
*lplres = pw[SBO_POS];
if (si.fMask & SIF_RANGE)
{
// if the range MAX is below the range MIN -- then treat is as a
// zero range starting at the range MIN.
if (si.nMax < si.nMin)
si.nMax = si.nMin;
if ((pw[SBO_MIN] != si.nMin) || (pw[SBO_MAX] != si.nMax))
{
pw[SBO_MIN] = si.nMin;
pw[SBO_MAX] = si.nMax;
if (!(si.fMask & SIF_PAGE))
{
si.fMask |= SIF_PAGE;
si.nPage = pw[SBO_PAGE];
}
if (!(si.fMask & SIF_POS))
{
si.fMask |= SIF_POS;
si.nPos = pw[SBO_POS];
}
fChanged = TRUE;
}
}
if (si.fMask & SIF_PAGE)
{
unsigned dwMaxPage = abs(pw[SBO_MAX] - pw[SBO_MIN]) + 1;
if (si.nPage > dwMaxPage)
si.nPage = dwMaxPage;
if (pw[SBO_PAGE] != (int) si.nPage)
{
pw[SBO_PAGE] = (int) si.nPage;
if (!(si.fMask & SIF_POS))
{
si.fMask |= SIF_POS;
si.nPos = pw[SBO_POS];
}
fChanged = TRUE;
}
}
if (si.fMask & SIF_POS)
{
// Clip pos to posMin, posMax - (page - 1).
int lMaxPos = pw[SBO_MAX] - ((pw[SBO_PAGE]) ? pw[SBO_PAGE] - 1 : 0);
// * BOGUS -- show this to SIMONK -- the following doesn't generate *
// * proper code so I had to use the longer form *
// * si.nPos = min(max(si.nPos, pw[SBO_MIN]), lMaxPos); *
if (si.nPos < pw[SBO_MIN])
si.nPos = pw[SBO_MIN];
else if (si.nPos > lMaxPos)
si.nPos = lMaxPos;
if (pw[SBO_POS] != si.nPos)
{
pw[SBO_POS] = si.nPos;
fChanged = TRUE;
}
}
if (!(bOldPos))
// Return the new position
*lplres = pw[SBO_POS];
if (si.fMask & SIF_RANGE)
{
if (*lpfScroll = (pw[SBO_MIN] != pw[SBO_MAX]))
goto checkPage;
}
else if (si.fMask & SIF_PAGE)
checkPage:
*lpfScroll = (pw[SBO_PAGE] <= (pw[SBO_MAX] - pw[SBO_MIN]));
return(fChanged);
}
//=-------------------------------------------------------------
// FlatSB_Internal_SetScrollBar
//
// Note:
// This func is called by SetScrollPos/Range/Info. We let
// the callers take care of checking pWState.
// Return 0 if failed.
//=-------------------------------------------------------------
LRESULT FlatSB_Internal_SetScrollBar(WSBState *pWState, int code, LPSCROLLINFO lpsi, BOOL fRedraw)
{
BOOL fVert;
int *pw;
BOOL fOldScroll;
BOOL fScroll;
BOOL bReturnOldPos = TRUE;
LRESULT lres;
int wfScroll;
HWND hwnd = pWState->sbHwnd;
ASSERT (code != SB_CTL);
// window must be visible to redraw
if (fRedraw)
fRedraw = IsWindowVisible(hwnd);
fVert = (code != SB_HORZ);
bReturnOldPos = (lpsi->fMask == SIF_POS);
wfScroll = (fVert) ? WS_VSCROLL : WS_HSCROLL;
fScroll = fOldScroll = (TestSTYLE(pWState->style, wfScroll)) ? TRUE : FALSE;
// Don't do anything if we're NOT setting the range and the scroll doesn't
// exist.
if (!(lpsi->fMask & SIF_RANGE) && !fOldScroll)
{
return(0);
}
pw = &(pWState->sbFlags);
// user.h: SBO_VERT = 5, SBO_HORZ = 1;
// pw += (fVert) ? SBO_VERT : SBO_HORZ;
pw += (fVert)? 5 : 1;
// Keep USER scrollbars in sync for accessibility
SetScrollInfo(hwnd, code, lpsi, FALSE);
if (!FlatSB_Internal_SBSetParms(pw, *lpsi, &fScroll, &lres, bReturnOldPos))
{
// no change -- but if REDRAW is specified and there's a scrollbar,
// redraw the thumb
if (fOldScroll && fRedraw)
goto redrawAfterSet;
return(lres);
}
if (fScroll)
pWState->style |= wfScroll;
else
pWState->style &= ~wfScroll;
// Keep style bits in sync so OLEACC can read them
SetWindowBits(hwnd, GWL_STYLE, WS_VSCROLL | WS_HSCROLL, pWState->style);
if (lpsi->fMask & SIF_DISABLENOSCROLL)
{
if (fOldScroll)
{
pWState->style |= wfScroll;
// Keep style bits in sync so OLEACC can read them
SetWindowBits(hwnd, GWL_STYLE, WS_VSCROLL | WS_HSCROLL, pWState->style);
FlatSB_Internal_EnableScrollBar(pWState, code, (fScroll) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH);
}
}
else if (fOldScroll ^ fScroll)
{
CCInvalidateFrame(hwnd);
return(lres);
}
if (fScroll && fRedraw && (fVert ? TestSTYLE(pWState->style, WFVPRESENT) : TestSTYLE(pWState->style, WFHPRESENT)))
{
redrawAfterSet:
// Don't send this, since USER already sent one for us when we
// called SetScrollBar.
// FlatSB_Internal_NotifyWinEvent(pWState, EVENT_OBJECT_VALUECHANGE, INDEX_SCROLLBAR_SELF);
// Bail out if the caller is trying to change a scrollbar which is
// in the middle of tracking. We'll hose FlatSB_Internal_TrackThumb() otherwise.
// BUGBUG: CalcSBStuff will change locMouse!
if (pWState->pfnSB == FlatSB_Internal_TrackThumb)
{
FlatSB_Internal_CalcSBStuff(pWState, fVert);
return(lres);
}
FlatSB_Internal_DrawThumb(pWState, fVert);
}
return(lres);
}
//=-------------------------------------------------------------
// SetScrollPos()
//=-------------------------------------------------------------
int WINAPI FlatSB_SetScrollPos(HWND hwnd, int code, int pos, BOOL fRedraw)
{
SCROLLINFO si;
WSBState * pWState;
GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
if (pWState == (WSBState *)NULL) {
return SetScrollPos(hwnd, code, pos, fRedraw);
} else if (pWState == WSB_UNINIT_HANDLE) {
return 0;
} else if (hwnd != pWState->sbHwnd) {
return 0;
}
si.cbSize = sizeof(si);
si.fMask = SIF_POS;
si.nPos = pos;
return (int)FlatSB_Internal_SetScrollBar(pWState, code, &si, fRedraw);
}
//=-------------------------------------------------------------
// SetScrollRange()
//=-------------------------------------------------------------
BOOL WINAPI FlatSB_SetScrollRange(HWND hwnd, int code, int nMin, int nMax, BOOL fRedraw)
{
SCROLLINFO si;
WSBState * pWState;
GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
if (pWState == (WSBState *)NULL) {
return SetScrollRange(hwnd, code, nMin, nMax, fRedraw);
} else if (pWState == WSB_UNINIT_HANDLE) {
pWState = FlatSB_Internal_InitPwSB(hwnd);
if (pWState == (WSBState *)NULL)
return FALSE;
else if (!SetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR)pWState)) {
DeleteObject(pWState->hbm_Bkg);
DeleteObject(pWState->hbr_Bkg);
LocalFree((HLOCAL)pWState);
return FALSE;
}
// In this case we always need to (re)draw the scrollbar.
fRedraw = TRUE;
} else if (hwnd != pWState->sbHwnd) {
return FALSE;
}
//
// Still need MAXINT check for PackRat 4. 32-bit apps don't
// go thru this--we wrap 'em to SetScrollInfo() on the 32-bit side,
// so DWORD precision is preserved.
//
if ((UINT)(nMax - nMin) > 0x7FFF)
return FALSE;
si.cbSize = sizeof(si);
si.fMask = SIF_RANGE;
si.nMin = nMin;
si.nMax = nMax;
FlatSB_Internal_SetScrollBar(pWState, code, &si, fRedraw);
return(TRUE);
}
//=-------------------------------------------------------------
// SetScrollInfo()
//
// Note:
// Inconsistent with 'user' code. Under no circumstance will
// we create a new scrollbar(by allocate a new buffer).
//=-------------------------------------------------------------
int WINAPI FlatSB_SetScrollInfo(HWND hwnd, int code, LPSCROLLINFO lpsi, BOOL fRedraw)
{
WSBState * pWState;
// ZDC@Oct. 10, Detect GP faults here.
if ((LPSCROLLINFO)NULL == lpsi)
return FALSE;
if (lpsi->cbSize < sizeof (SCROLLINFO))
return FALSE;
GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
if (pWState == (WSBState *)NULL) {
return SetScrollInfo(hwnd, code, lpsi, fRedraw);
} else if (pWState == WSB_UNINIT_HANDLE) {
if (!(lpsi->fMask & SIF_RANGE))
return 0;
pWState = FlatSB_Internal_InitPwSB(hwnd);
if (pWState == (WSBState *)NULL)
return 0;
else if (!SetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR)pWState)) {
DeleteObject(pWState->hbm_Bkg);
DeleteObject(pWState->hbr_Bkg);
LocalFree((HLOCAL)pWState);
return 0;
}
// In this case we always need to (re)draw the scrollbar.
fRedraw = TRUE;
} else if (hwnd != pWState->sbHwnd) {
return 0;
}
// ZDC@Oct 9, We should always return new pos. How ever, if the fMask
// is SIF_POS, SetScrollBar returns the old pos.
if (lpsi->fMask == SIF_POS)
lpsi->fMask = SIF_POS | SIF_TRACKPOS;
return (int)FlatSB_Internal_SetScrollBar(pWState, code, lpsi, fRedraw);
}
//=-------------------------------------------------------------
// FlatSB_SetScrollProp
// This functions shouldn't be called we we are tracking.
//=-------------------------------------------------------------
BOOL WINAPI FlatSB_SetScrollProp(HWND hwnd, UINT index, INT_PTR newValue, BOOL fRedraw)
{
BOOL fResize = FALSE;
BOOL fVert = FALSE;
WSBState * pWState;
GetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR *)&pWState);
if (pWState == (WSBState *)NULL)
return FALSE;
else if (pWState == WSB_UNINIT_HANDLE) {
pWState = FlatSB_Internal_InitPwSB(hwnd);
if (pWState == (WSBState *)NULL)
return 0;
else if (!SetWindowSubclass(hwnd, FlatSB_SubclassWndProc, 0, (ULONG_PTR)pWState)) {
DeleteObject(pWState->hbm_Bkg);
DeleteObject(pWState->hbr_Bkg);
LocalFree((HLOCAL)pWState);
return 0;
}
// In this case we don't want to (re)draw the scrollbar.
fRedraw = FALSE;
}
if (pWState->fTracking)
return FALSE;
switch (index) {
case WSB_PROP_CXVSCROLL:
if ((int)newValue == pWState->metApp.cxVSBArrow)
return TRUE;
pWState->metApp.cxVSBArrow = (int)newValue;
fResize = TRUE;
break;
case WSB_PROP_CXHSCROLL:
if ((int)newValue == pWState->metApp.cxHSBArrow)
return TRUE;
pWState->metApp.cxHSBArrow = (int)newValue;
fResize = TRUE;
break;
case WSB_PROP_CYVSCROLL:
if ((int)newValue == pWState->metApp.cyVSBArrow)
return TRUE;
pWState->metApp.cyVSBArrow = (int)newValue;
fResize = TRUE;
break;
case WSB_PROP_CYHSCROLL:
if ((int)newValue == pWState->metApp.cyHSBArrow)
return TRUE;
pWState->metApp.cyHSBArrow = (int)newValue;
fResize = TRUE;
break;
case WSB_PROP_CXHTHUMB:
if ((int)newValue == pWState->metApp.cxHSBThumb)
return TRUE;
pWState->metApp.cxHSBThumb = (int)newValue;
fResize = TRUE;
break;
case WSB_PROP_CYVTHUMB:
if ((int)newValue == pWState->metApp.cyVSBThumb)
return TRUE;
pWState->metApp.cyVSBThumb = (int)newValue;
fResize = TRUE;
break;
case WSB_PROP_VBKGCOLOR:
if ((COLORREF)newValue == pWState->col_VSBBkg)
return TRUE;
pWState->col_VSBBkg = (COLORREF)newValue;
fVert = TRUE;
break;
case WSB_PROP_HBKGCOLOR:
if ((COLORREF)newValue == pWState->col_HSBBkg)
return TRUE;
pWState->col_HSBBkg = (COLORREF)newValue;
break;
case WSB_PROP_PALETTE:
if ((HPALETTE)newValue == pWState->hPalette)
return TRUE;
pWState->hPalette = (HPALETTE)newValue;
break;
case WSB_PROP_VSTYLE:
if ((int)newValue == pWState->vStyle)
return TRUE;
pWState->vStyle = (int)newValue;
fVert = TRUE;
break;
case WSB_PROP_HSTYLE:
if ((int)newValue == pWState->hStyle)
return TRUE;
pWState->hStyle = (int)newValue;
break;
case WSB_PROP_GUTTER:
if ((int)newValue == pWState->sbGutter)
return TRUE;
pWState->sbGutter = (int)newValue;
break;
default:
return FALSE;
}
if (fResize) {
// Always redraw after we change the size.
CCInvalidateFrame(hwnd);
} else if (fRedraw) {
HDC hdc;
int oldLoc = pWState->locMouse;
int fSBActive = (fVert)?pWState->fVActive:pWState->fHActive;
hdc = GetWindowDC(hwnd);
FlatSB_Internal_DrawScrollBar(pWState, hdc, fVert, FALSE /* Not redraw*/);
if (!fSBActive)
pWState->locMouse = oldLoc;
ReleaseDC(hwnd, hdc);
}
return TRUE;
}
//=-------------------------------------------------------------
// FlatSB_Internal_DrawScrollBar()
//=-------------------------------------------------------------
void FlatSB_Internal_DrawScrollBar(WSBState * pWState, HDC hdc, BOOL fVert, BOOL fRedraw)
{
int oldLoc = pWState->locMouse;
FlatSB_Internal_CalcSBStuff(pWState, fVert);
if ((!fRedraw) || oldLoc != pWState->locMouse)
FlatSB_Internal_DrawSB2(pWState, hdc, fVert, fRedraw, oldLoc);
}
//=------------------------------------------------------------
// FlatSB_Internal_IsSizeBox
// It's still an incomplete mimic of SizeBoxWnd in user/winwhere.c
//=------------------------------------------------------------
BOOL FlatSB_Internal_IsSizeBox(HWND hwndStart)
{
int style;
HWND hwnd, hwndDesktop;
int cxEdge, cyEdge;
RECT rcChild, rcParent;
ASSERT(hwndStart);
hwnd = hwndStart;
hwndDesktop = GetDesktopWindow();
cxEdge = GetSystemMetrics(SM_CXEDGE);
cyEdge = GetSystemMetrics(SM_CYEDGE);
if (!GetWindowRect(hwnd, &rcChild))
return FALSE;
do {
style = GetWindowStyle(hwnd);
if (TestSTYLE(style, WS_SIZEBOX)) {
if (IsZoomed(hwnd))
return FALSE;
else {
POINT pt;
GetClientRect(hwnd, &rcParent);
pt.x = rcParent.right;
pt.y = rcParent.bottom;
ClientToScreen(hwnd, &pt);
if (rcChild.right + cxEdge < pt.x)
return FALSE;
if (rcChild.bottom + cyEdge < pt.y)
return FALSE;
return TRUE;
}
} else {
hwnd = GetParent(hwnd);
}
}
while ((hwnd) && (hwnd != hwndDesktop));
return FALSE;
}