2934 lines
88 KiB
C
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;
|
|
}
|