#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; }