|
|
/**************************** Module Header ********************************\
* Module Name: sbctl.c * * Copyright (c) 1985 - 1999, Microsoft Corporation * * Scroll bar internal routines * * History: * 11/21/90 JimA Created. * 02-04-91 IanJa Revalidaion added \***************************************************************************/
#include "precomp.h"
#pragma hdrstop
void CalcSBStuff( PWND pwnd, PSBCALC pSBCalc, BOOL fVert);
#define IsScrollBarControl(h) (GETFNID(h) == FNID_SCROLLBAR)
/*
* Now it is possible to selectively Enable/Disable just one arrow of a Window * scroll bar; Various bits in the 7th word in the rgwScroll array indicates which * one of these arrows are disabled; The following masks indicate which bit of the * word indicates which arrow; */ #define WSB_HORZ_LF 0x0001 // Represents the Left arrow of the horizontal scroll bar.
#define WSB_HORZ_RT 0x0002 // Represents the Right arrow of the horizontal scroll bar.
#define WSB_VERT_UP 0x0004 // Represents the Up arrow of the vert scroll bar.
#define WSB_VERT_DN 0x0008 // Represents the Down arrow of the vert scroll bar.
#define WSB_VERT (WSB_VERT_UP | WSB_VERT_DN)
#define WSB_HORZ (WSB_HORZ_LF | WSB_HORZ_RT)
void DrawCtlThumb(PSBWND);
/*
* RETURN_IF_PSBTRACK_INVALID: * This macro tests whether the pSBTrack we have is invalid, which can happen * if it gets freed during a callback. * This protects agains the original pSBTrack being freed and no new one * being allocated or a new one being allocated at a different address. * This does not protect against the original pSBTrack being freed and a new * one being allocated at the same address. * If pSBTrack has changed, we assert that there is not already a new one * because we are really not expecting this. */ #define RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd) \
if ((pSBTrack) != PWNDTOPSBTRACK(pwnd)) { \ UserAssert(PWNDTOPSBTRACK(pwnd) == NULL); \ return; \ }
/*
* REEVALUATE_PSBTRACK * This macro just refreshes the local variable pSBTrack, in case it has * been changed during a callback. After performing this operation, pSBTrack * should be tested to make sure it is not now NULL. */ #if DBG
#define REEVALUATE_PSBTRACK(pSBTrack, pwnd, str) \
if ((pSBTrack) != PWNDTOPSBTRACK(pwnd)) { \ RIPMSG3(RIP_VERBOSE, \ "%s: pSBTrack changed from %#p to %#p", \ (str), (pSBTrack), PWNDTOPSBTRACK(pwnd)); \ } \ (pSBTrack) = PWNDTOPSBTRACK(pwnd) #else
#define REEVALUATE_PSBTRACK(pSBTrack, pwnd, str) \
(pSBTrack) = PWNDTOPSBTRACK(pwnd) #endif
/***************************************************************************\
* HitTestScrollBar * * 11/15/96 vadimg ported from Memphis sources \***************************************************************************/
int HitTestScrollBar(PWND pwnd, BOOL fVert, POINT pt) { UINT wDisable; int px; BOOL fCtl = IsScrollBarControl(pwnd); SBCALC SBCalc, *pSBCalc;
if (fCtl) { wDisable = ((PSBWND)pwnd)->wDisableFlags; } else { //
// Reflect the click coordinates on the horizontal
// scroll bar if the window is mirrored
//
if (TestWF(pwnd,WEFLAYOUTRTL) && !fVert) { pt.x = pwnd->rcWindow.right - pt.x; } else { pt.x -= pwnd->rcWindow.left; }
pt.y -= pwnd->rcWindow.top; wDisable = GetWndSBDisableFlags(pwnd, fVert); }
if ((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) { return HTERROR; }
if (fCtl) { pSBCalc = &(((PSBWND)pwnd)->SBCalc); } else { pSBCalc = &SBCalc; CalcSBStuff(pwnd, pSBCalc, fVert); }
px = fVert ? pt.y : pt.x;
if (px < pSBCalc->pxUpArrow) { if (wDisable & LTUPFLAG) { return HTERROR; } return HTSCROLLUP; } else if (px >= pSBCalc->pxDownArrow) { if (wDisable & RTDNFLAG) { return HTERROR; } return HTSCROLLDOWN; } else if (px < pSBCalc->pxThumbTop) { return HTSCROLLUPPAGE; } else if (px < pSBCalc->pxThumbBottom) { return HTSCROLLTHUMB; } else if (px < pSBCalc->pxDownArrow) { return HTSCROLLDOWNPAGE; } return HTERROR; }
BOOL _SBGetParms( PWND pwnd, int code, PSBDATA pw, LPSCROLLINFO lpsi) { PSBTRACK pSBTrack;
pSBTrack = PWNDTOPSBTRACK(pwnd);
if (lpsi->fMask & SIF_RANGE) { lpsi->nMin = pw->posMin; lpsi->nMax = pw->posMax; }
if (lpsi->fMask & SIF_PAGE) lpsi->nPage = pw->page;
if (lpsi->fMask & SIF_POS) { lpsi->nPos = pw->pos; }
if (lpsi->fMask & SIF_TRACKPOS) { if (pSBTrack && (pSBTrack->nBar == code) && (pSBTrack->spwndTrack == pwnd)) { // posNew is in the context of psbiSB's window and bar code
lpsi->nTrackPos = pSBTrack->posNew; } else { lpsi->nTrackPos = pw->pos; } } return ((lpsi->fMask & SIF_ALL) ? TRUE : FALSE); }
/***************************************************************************\
* GetWndSBDisableFlags * * This returns the scroll bar Disable flags of the scroll bars of a * given Window. * * * History: * 4-18-91 MikeHar Ported for the 31 merge \***************************************************************************/
UINT GetWndSBDisableFlags( PWND pwnd, // The window whose scroll bar Disable Flags are to be returned;
BOOL fVert) // If this is TRUE, it means Vertical scroll bar.
{ PSBINFO pw;
if ((pw = pwnd->pSBInfo) == NULL) { RIPERR0(ERROR_NO_SCROLLBARS, RIP_VERBOSE, ""); return 0; }
return (fVert ? (pw->WSBflags & WSB_VERT) >> 2 : pw->WSBflags & WSB_HORZ); }
/***************************************************************************\
* xxxEnableSBCtlArrows() * * This function can be used to selectively Enable/Disable * the arrows of a scroll bar Control * * History: * 04-18-91 MikeHar Ported for the 31 merge \***************************************************************************/
BOOL xxxEnableSBCtlArrows( PWND pwnd, UINT wArrows) { UINT wOldFlags; UINT wNewFlags;
CheckLock(pwnd); UserAssert(IsWinEventNotifyDeferredOK());
wOldFlags = ((PSBWND)pwnd)->wDisableFlags; // Get the original status
if (wArrows == ESB_ENABLE_BOTH) { // Enable both the arrows
((PSBWND)pwnd)->wDisableFlags &= ~SB_DISABLE_MASK; } else { ((PSBWND)pwnd)->wDisableFlags |= wArrows; }
/*
* Check if the status has changed because of this call */ if (wOldFlags == ((PSBWND)pwnd)->wDisableFlags) return FALSE;
/*
* Else, redraw the scroll bar control to reflect the new state */ if (IsVisible(pwnd)) xxxInvalidateRect(pwnd, NULL, TRUE);
wNewFlags = ((PSBWND)pwnd)->wDisableFlags;
/*
* state change notifications */ if ((wOldFlags & ESB_DISABLE_UP) != (wNewFlags & ESB_DISABLE_UP)) { xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_CLIENT, INDEX_SCROLLBAR_UP, WEF_USEPWNDTHREAD); }
if ((wOldFlags & ESB_DISABLE_DOWN) != (wNewFlags & ESB_DISABLE_DOWN)) { xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_CLIENT, INDEX_SCROLLBAR_DOWN, WEF_USEPWNDTHREAD); }
return TRUE; }
/***************************************************************************\
* xxxEnableWndSBArrows() * * This function can be used to selectively Enable/Disable * the arrows of a Window Scroll bar(s) * * History: * 4-18-91 MikeHar Ported for the 31 merge \***************************************************************************/
BOOL xxxEnableWndSBArrows( PWND pwnd, UINT wSBflags, UINT wArrows) { INT wOldFlags; PSBINFO pw; BOOL bRetValue = FALSE; HDC hdc;
CheckLock(pwnd); UserAssert(IsWinEventNotifyDeferredOK());
if ((pw = pwnd->pSBInfo) != NULL) { wOldFlags = pw->WSBflags; } else {
/*
* Originally everything is enabled; Check to see if this function is * asked to disable anything; Otherwise, no change in status; So, must * return immediately; */ if(!wArrows) return FALSE; // No change in status!
wOldFlags = 0; // Both are originally enabled;
if((pw = _InitPwSB(pwnd)) == NULL) // Allocate the pSBInfo for hWnd
return FALSE; }
if((hdc = _GetWindowDC(pwnd)) == NULL) return FALSE;
/*
* First Take care of the Horizontal Scroll bar, if one exists. */ if((wSBflags == SB_HORZ) || (wSBflags == SB_BOTH)) { if(wArrows == ESB_ENABLE_BOTH) // Enable both the arrows
pw->WSBflags &= ~SB_DISABLE_MASK; else pw->WSBflags |= wArrows;
/*
* Update the display of the Horizontal Scroll Bar; */ if(pw->WSBflags != wOldFlags) { bRetValue = TRUE; wOldFlags = pw->WSBflags; if (TestWF(pwnd, WFHPRESENT) && !TestWF(pwnd, WFMINIMIZED) && IsVisible(pwnd)) { xxxDrawScrollBar(pwnd, hdc, FALSE); // Horizontal Scroll Bar.
} } // Left button
if ((wOldFlags & ESB_DISABLE_LEFT) != (pw->WSBflags & ESB_DISABLE_LEFT)) { xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_HSCROLL, INDEX_SCROLLBAR_UP, WEF_USEPWNDTHREAD); }
// Right button
if ((wOldFlags & ESB_DISABLE_RIGHT) != (pw->WSBflags & ESB_DISABLE_RIGHT)) { xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_HSCROLL, INDEX_SCROLLBAR_DOWN, WEF_USEPWNDTHREAD); } }
/*
* Then take care of the Vertical Scroll bar, if one exists. */ if((wSBflags == SB_VERT) || (wSBflags == SB_BOTH)) { if(wArrows == ESB_ENABLE_BOTH) // Enable both the arrows
pw->WSBflags &= ~(SB_DISABLE_MASK << 2); else pw->WSBflags |= (wArrows << 2);
/*
* Update the display of the Vertical Scroll Bar; */ if(pw->WSBflags != wOldFlags) { bRetValue = TRUE; if (TestWF(pwnd, WFVPRESENT) && !TestWF(pwnd, WFMINIMIZED) && IsVisible(pwnd)) { xxxDrawScrollBar(pwnd, hdc, TRUE); // Vertical Scroll Bar
}
// Up button
if ((wOldFlags & (ESB_DISABLE_UP << 2)) != (pw->WSBflags & (ESB_DISABLE_UP << 2))) { xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_VSCROLL, INDEX_SCROLLBAR_UP, WEF_USEPWNDTHREAD); }
// Down button
if ((wOldFlags & (ESB_DISABLE_DOWN << 2)) != (pw->WSBflags & (ESB_DISABLE_DOWN << 2))) { xxxWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, OBJID_VSCROLL, INDEX_SCROLLBAR_DOWN, WEF_USEPWNDTHREAD); } } }
_ReleaseDC(hdc);
return bRetValue; }
/***************************************************************************\
* EnableScrollBar() * * This function can be used to selectively Enable/Disable * the arrows of a scroll bar; It could be used with Windows Scroll * bars as well as scroll bar controls * * History: * 4-18-91 MikeHar Ported for the 31 merge \***************************************************************************/
BOOL xxxEnableScrollBar( PWND pwnd, UINT wSBflags, // Whether it is a Window Scroll Bar; if so, HORZ or VERT?
// Possible values are SB_HORZ, SB_VERT, SB_CTL or SB_BOTH
UINT wArrows) // Which arrows must be enabled/disabled:
// ESB_ENABLE_BOTH = > Enable both arrows.
// ESB_DISABLE_LTUP = > Disable Left/Up arrow;
// ESB_DISABLE_RTDN = > DIsable Right/Down arrow;
// ESB_DISABLE_BOTH = > Disable both the arrows;
{ #define ES_NOTHING 0
#define ES_DISABLE 1
#define ES_ENABLE 2
UINT wOldFlags; UINT wEnableWindow;
CheckLock(pwnd);
if(wSBflags != SB_CTL) { return xxxEnableWndSBArrows(pwnd, wSBflags, wArrows); }
/*
* Let us assume that we don't have to call EnableWindow */ wEnableWindow = ES_NOTHING;
wOldFlags = ((PSBWND)pwnd)->wDisableFlags & (UINT)SB_DISABLE_MASK;
/*
* Check if the present state of the arrows is exactly the same * as what the caller wants: */ if (wOldFlags == wArrows) return FALSE ; // If so, nothing needs to be done;
/*
* Check if the caller wants to disable both the arrows */ if (wArrows == ESB_DISABLE_BOTH) { wEnableWindow = ES_DISABLE; // Yes! So, disable the whole SB Ctl.
} else {
/*
* Check if the caller wants to enable both the arrows */ if(wArrows == ESB_ENABLE_BOTH) {
/*
* We need to enable the SB Ctl only if it was already disabled. */ if(wOldFlags == ESB_DISABLE_BOTH) wEnableWindow = ES_ENABLE;// EnableWindow(.., TRUE);
} else {
/*
* Now, Caller wants to disable only one arrow; * Check if one of the arrows was already disabled and we want * to disable the other;If so, the whole SB Ctl will have to be * disabled; Check if this is the case: */ if((wOldFlags | wArrows) == ESB_DISABLE_BOTH) wEnableWindow = ES_DISABLE; // EnableWindow(, FALSE);
} } if(wEnableWindow != ES_NOTHING) {
/*
* EnableWindow returns old state of the window; We must return * TRUE only if the Old state is different from new state. */ if(xxxEnableWindow(pwnd, (BOOL)(wEnableWindow == ES_ENABLE))) { return !(TestWF(pwnd, WFDISABLED)); } else { return TestWF(pwnd, WFDISABLED); } }
return (BOOL)xxxSendMessage(pwnd, SBM_ENABLE_ARROWS, (DWORD)wArrows, 0); #undef ES_NOTHING
#undef ES_DISABLE
#undef ES_ENABLE
}
/***************************************************************************\
* * DrawSize() - * \***************************************************************************/ void FAR DrawSize(PWND pwnd, HDC hdc, int cxFrame,int cyFrame) { int x, y; //HBRUSH hbrSave;
if (TestWF(pwnd, WEFLEFTSCROLL)) { x = cxFrame; } else { x = pwnd->rcWindow.right - pwnd->rcWindow.left - cxFrame - SYSMET(CXVSCROLL); } y = pwnd->rcWindow.bottom - pwnd->rcWindow.top - cyFrame - SYSMET(CYHSCROLL);
// If we have a scrollbar control, or the sizebox is not associated with
// a sizeable window, draw the flat gray sizebox. Otherwise, use the
// sizing grip.
if (IsScrollBarControl(pwnd)) { if (TestWF(pwnd, SBFSIZEGRIP)) goto DrawSizeGrip; else goto DrawBox;
} else if (!SizeBoxHwnd(pwnd)) { DrawBox: { //hbrSave = GreSelectBrush(hdc, SYSHBR(3DFACE));
//GrePatBlt(hdc, x, y, SYSMET(CXVSCROLL), SYSMET(CYHSCROLL), PATCOPY);
//GreSelectBrush(hdc, hbrSave);
POLYPATBLT PolyData;
PolyData.x = x; PolyData.y = y; PolyData.cx = SYSMET(CXVSCROLL); PolyData.cy = SYSMET(CYHSCROLL); PolyData.BrClr.hbr = SYSHBR(3DFACE);
GrePolyPatBlt(hdc,PATCOPY,&PolyData,1,PPB_BRUSH);
} } else { DrawSizeGrip: // Blt out the grip bitmap.
BitBltSysBmp(hdc, x, y, TestWF(pwnd, WEFLEFTSCROLL) ? OBI_NCGRIP_L : OBI_NCGRIP); } }
/***************************************************************************\
* xxxSelectColorObjects * * * * History: \***************************************************************************/
HBRUSH xxxGetColorObjects( PWND pwnd, HDC hdc) { HBRUSH hbrRet;
CheckLock(pwnd);
// Use the scrollbar color even if the scrollbar is disabeld.
if (!IsScrollBarControl(pwnd)) hbrRet = (HBRUSH)xxxDefWindowProc(pwnd, WM_CTLCOLORSCROLLBAR, (WPARAM)hdc, (LPARAM)HWq(pwnd)); else { // B#12770 - GetControlBrush sends a WM_CTLCOLOR message to the
// owner. If the app doesn't process the message, DefWindowProc32
// will always return the appropriate system brush. If the app.
// returns an invalid object, GetControlBrush will call DWP for
// the default brush. Thus hbrRet doesn't need any validation
// here.
hbrRet = xxxGetControlBrush(pwnd, hdc, WM_CTLCOLORSCROLLBAR); }
return hbrRet; }
/***************************************************************************\
* * DrawGroove() * * Draws lines & middle of thumb groove * Note that pw points into prc. Moreover, note that both pw & prc are * NEAR pointers, so *prc better not be on the stack. * \***************************************************************************/ void NEAR DrawGroove(HDC hdc, HBRUSH hbr, LPRECT prc, BOOL fVert) { if ((hbr == SYSHBR(3DHILIGHT)) || (hbr == gpsi->hbrGray)) FillRect(hdc, prc, hbr); else { RECT rc;
// Draw sides
CopyRect(&rc, prc); DrawEdge(hdc, &rc, EDGE_SUNKEN, BF_ADJUST | BF_FLAT | (fVert ? BF_LEFT | BF_RIGHT : BF_TOP | BF_BOTTOM));
// Fill middle
FillRect(hdc, &rc, hbr); } }
/***************************************************************************\
* CalcTrackDragRect * * Give the rectangle for a scrollbar in pSBTrack->pSBCalc, * calculate pSBTrack->rcTrack, the rectangle where tracking * may occur without cancelling the thumbdrag operation. * \***************************************************************************/
void CalcTrackDragRect(PSBTRACK pSBTrack) {
int cx; int cy; LPINT pwX, pwY;
//
// Point pwX and pwY at the parts of the rectangle
// corresponding to pSBCalc->pxLeft, pxTop, etc.
//
// pSBTrack->pSBCalc->pxLeft is the left edge of a vertical
// scrollbar and the top edge of horizontal one.
// pSBTrack->pSBCalc->pxTop is the top of a vertical
// scrollbar and the left of horizontal one.
// etc...
//
// Point pwX and pwY to the corresponding parts
// of pSBTrack->rcTrack.
//
pwX = pwY = (LPINT)&pSBTrack->rcTrack;
if (pSBTrack->fTrackVert) { cy = SYSMET(CYVTHUMB); pwY++; } else { cy = SYSMET(CXHTHUMB); pwX++; } /*
* Later5.0 GerardoB: People keep complaining about this tracking region * being too narrow so let's make it wider while PM decides what to do * about it. * We also used to have some hard coded min and max values but that should * depend on some metric, if at all needed. */ cx = (pSBTrack->pSBCalc->pxRight - pSBTrack->pSBCalc->pxLeft) * 8; cy *= 2;
*(pwX + 0) = pSBTrack->pSBCalc->pxLeft - cx; *(pwY + 0) = pSBTrack->pSBCalc->pxTop - cy; *(pwX + 2) = pSBTrack->pSBCalc->pxRight + cx; *(pwY + 2) = pSBTrack->pSBCalc->pxBottom + cy; }
void RecalcTrackRect(PSBTRACK pSBTrack) { LPINT pwX, pwY; RECT rcSB;
if (!pSBTrack->fCtlSB) CalcSBStuff(pSBTrack->spwndTrack, pSBTrack->pSBCalc, pSBTrack->fTrackVert);
pwX = (LPINT)&rcSB; pwY = pwX + 1; if (!pSBTrack->fTrackVert) pwX = pwY--;
*(pwX + 0) = pSBTrack->pSBCalc->pxLeft; *(pwY + 0) = pSBTrack->pSBCalc->pxTop; *(pwX + 2) = pSBTrack->pSBCalc->pxRight; *(pwY + 2) = pSBTrack->pSBCalc->pxBottom;
switch(pSBTrack->cmdSB) { case SB_LINEUP: *(pwY + 2) = pSBTrack->pSBCalc->pxUpArrow; break; case SB_LINEDOWN: *(pwY + 0) = pSBTrack->pSBCalc->pxDownArrow; break; case SB_PAGEUP: *(pwY + 0) = pSBTrack->pSBCalc->pxUpArrow; *(pwY + 2) = pSBTrack->pSBCalc->pxThumbTop; break; case SB_THUMBPOSITION: CalcTrackDragRect(pSBTrack); break; case SB_PAGEDOWN: *(pwY + 0) = pSBTrack->pSBCalc->pxThumbBottom; *(pwY + 2) = pSBTrack->pSBCalc->pxDownArrow; break; }
if (pSBTrack->cmdSB != SB_THUMBPOSITION) { CopyRect(&pSBTrack->rcTrack, &rcSB); } }
/***************************************************************************\
* DrawThumb2 * * * * History: * 01-03-94 FritzS Chicago changes \***************************************************************************/
void DrawThumb2( PWND pwnd, PSBCALC pSBCalc, HDC hdc, HBRUSH hbr, BOOL fVert, UINT wDisable) /* Disabled flags for the scroll bar */ { int *pLength; int *pWidth; RECT rcSB; PSBTRACK pSBTrack;
//
// Bail out if the scrollbar has an empty rect
//
if ((pSBCalc->pxTop >= pSBCalc->pxBottom) || (pSBCalc->pxLeft >= pSBCalc->pxRight)) return; pLength = (LPINT)&rcSB; if (fVert) pWidth = pLength++; else pWidth = pLength + 1;
pWidth[0] = pSBCalc->pxLeft; pWidth[2] = pSBCalc->pxRight;
/*
* If both scroll bar arrows are disabled, then we should not draw * the thumb. So, quit now! */ if (((wDisable & LTUPFLAG) && (wDisable & RTDNFLAG)) || ((pSBCalc->pxDownArrow - pSBCalc->pxUpArrow) < pSBCalc->cpxThumb)) { pLength[0] = pSBCalc->pxUpArrow; pLength[2] = pSBCalc->pxDownArrow;
DrawGroove(hdc, hbr, &rcSB, fVert); return; }
if (pSBCalc->pxUpArrow < pSBCalc->pxThumbTop) { // Fill in space above Thumb
pLength[0] = pSBCalc->pxUpArrow; pLength[2] = pSBCalc->pxThumbTop;
DrawGroove(hdc, hbr, &rcSB, fVert); }
if (pSBCalc->pxThumbBottom < pSBCalc->pxDownArrow) { // Fill in space below Thumb
pLength[0] = pSBCalc->pxThumbBottom; pLength[2] = pSBCalc->pxDownArrow;
DrawGroove(hdc, hbr, &rcSB, fVert); }
//
// Draw elevator
//
pLength[0] = pSBCalc->pxThumbTop; pLength[2] = pSBCalc->pxThumbBottom;
// Not soft!
DrawPushButton(hdc, &rcSB, 0, 0);
/*
* If we're tracking a page scroll, then we've obliterated the hilite. * We need to correct the hiliting rectangle, and rehilite it. */ pSBTrack = PWNDTOPSBTRACK(pwnd);
if (pSBTrack && (pSBTrack->cmdSB == SB_PAGEUP || pSBTrack->cmdSB == SB_PAGEDOWN) && (pwnd == pSBTrack->spwndTrack) && (BOOL)pSBTrack->fTrackVert == fVert) {
if (pSBTrack->fTrackRecalc) { RecalcTrackRect(pSBTrack); pSBTrack->fTrackRecalc = FALSE; }
pLength = (int *)&pSBTrack->rcTrack;
if (fVert) pLength++;
if (pSBTrack->cmdSB == SB_PAGEUP) pLength[2] = pSBCalc->pxThumbTop; else pLength[0] = pSBCalc->pxThumbBottom;
if (pLength[0] < pLength[2]) InvertRect(hdc, &pSBTrack->rcTrack); } }
/***************************************************************************\
* xxxDrawSB2 * * * * History: \***************************************************************************/
void xxxDrawSB2( PWND pwnd, PSBCALC pSBCalc, HDC hdc, BOOL fVert, UINT wDisable) {
int cLength; int cWidth; int *pwX; int *pwY; HBRUSH hbr; HBRUSH hbrSave; int cpxArrow; RECT rc, rcSB; COLORREF crText, crBk;
CheckLock(pwnd);
cLength = (pSBCalc->pxBottom - pSBCalc->pxTop) / 2; cWidth = (pSBCalc->pxRight - pSBCalc->pxLeft);
if ((cLength <= 0) || (cWidth <= 0)) { return; } if (fVert) cpxArrow = SYSMET(CYVSCROLL); else cpxArrow = SYSMET(CXHSCROLL);
/*
* Save background and DC color, since they get changed in * xxxGetColorObjects. Restore before we return. */ crBk = GreGetBkColor(hdc); crText = GreGetTextColor(hdc);
hbr = xxxGetColorObjects(pwnd, hdc);
if (cLength > cpxArrow) cLength = cpxArrow; pwX = (int *)&rcSB; pwY = pwX + 1; if (!fVert) pwX = pwY--;
pwX[0] = pSBCalc->pxLeft; pwY[0] = pSBCalc->pxTop; pwX[2] = pSBCalc->pxRight; pwY[2] = pSBCalc->pxBottom;
hbrSave = GreSelectBrush(hdc, SYSHBR(BTNTEXT));
//
// BOGUS
// Draw scrollbar arrows as disabled if the scrollbar itself is
// disabled OR if the window it is a part of is disabled?
//
if (fVert) { if ((cLength == SYSMET(CYVSCROLL)) && (cWidth == SYSMET(CXVSCROLL))) { BitBltSysBmp(hdc, rcSB.left, rcSB.top, (wDisable & LTUPFLAG) ? OBI_UPARROW_I : OBI_UPARROW); BitBltSysBmp(hdc, rcSB.left, rcSB.bottom - cLength, (wDisable & RTDNFLAG) ? OBI_DNARROW_I : OBI_DNARROW); } else { CopyRect(&rc, &rcSB); rc.bottom = rc.top + cLength; DrawFrameControl(hdc, &rc, DFC_SCROLL, DFCS_SCROLLUP | ((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
rc.bottom = rcSB.bottom; rc.top = rcSB.bottom - cLength; DrawFrameControl(hdc, &rc, DFC_SCROLL, DFCS_SCROLLDOWN | ((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0)); } } else { if ((cLength == SYSMET(CXHSCROLL)) && (cWidth == SYSMET(CYHSCROLL))) { BitBltSysBmp(hdc, rcSB.left, rcSB.top, (wDisable & LTUPFLAG) ? OBI_LFARROW_I : OBI_LFARROW); BitBltSysBmp(hdc, rcSB.right - cLength, rcSB.top, (wDisable & RTDNFLAG) ? OBI_RGARROW_I : OBI_RGARROW); } else { CopyRect(&rc, &rcSB); rc.right = rc.left + cLength; DrawFrameControl(hdc, &rc, DFC_SCROLL, DFCS_SCROLLLEFT | ((wDisable & LTUPFLAG) ? DFCS_INACTIVE : 0));
rc.right = rcSB.right; rc.left = rcSB.right - cLength; DrawFrameControl(hdc, &rc, DFC_SCROLL, DFCS_SCROLLRIGHT | ((wDisable & RTDNFLAG) ? DFCS_INACTIVE : 0)); } }
hbrSave = GreSelectBrush(hdc, hbrSave); DrawThumb2(pwnd, pSBCalc, hdc, hbr, fVert, wDisable); GreSelectBrush(hdc, hbrSave);
GreSetBkColor(hdc, crBk); GreSetTextColor(hdc, crText); }
/***************************************************************************\
* zzzSetSBCaretPos * * * * History: \***************************************************************************/
void zzzSetSBCaretPos( PSBWND psbwnd) {
if ((PWND)psbwnd == PtiCurrent()->pq->spwndFocus) { zzzSetCaretPos((psbwnd->fVert ? psbwnd->SBCalc.pxLeft : psbwnd->SBCalc.pxThumbTop) + SYSMET(CXEDGE), (psbwnd->fVert ? psbwnd->SBCalc.pxThumbTop : psbwnd->SBCalc.pxLeft) + SYSMET(CYEDGE)); } }
/***************************************************************************\
* CalcSBStuff2 * * * * History: \***************************************************************************/
void CalcSBStuff2( PSBCALC pSBCalc, LPRECT lprc, CONST PSBDATA pw, BOOL fVert) { int cpx; DWORD dwRange; int denom;
if (fVert) { pSBCalc->pxTop = lprc->top; pSBCalc->pxBottom = lprc->bottom; pSBCalc->pxLeft = lprc->left; pSBCalc->pxRight = lprc->right; pSBCalc->cpxThumb = SYSMET(CYVSCROLL); } else {
/*
* For horiz scroll bars, "left" & "right" are "top" and "bottom", * and vice versa. */ pSBCalc->pxTop = lprc->left; pSBCalc->pxBottom = lprc->right; pSBCalc->pxLeft = lprc->top; pSBCalc->pxRight = lprc->bottom; pSBCalc->cpxThumb = SYSMET(CXHSCROLL); }
pSBCalc->pos = pw->pos; pSBCalc->page = pw->page; pSBCalc->posMin = pw->posMin; pSBCalc->posMax = pw->posMax;
dwRange = ((DWORD)(pSBCalc->posMax - pSBCalc->posMin)) + 1;
//
// 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
//
cpx = min((pSBCalc->pxBottom - pSBCalc->pxTop) / 2, pSBCalc->cpxThumb);
pSBCalc->pxUpArrow = pSBCalc->pxTop + cpx; pSBCalc->pxDownArrow = pSBCalc->pxBottom - cpx;
if ((pw->page != 0) && (dwRange != 0)) { // JEFFBOG -- This is the one and only place where we should
// see 'range'. Elsewhere it should be 'range - page'.
/*
* The minimun thumb size used to depend on the frame/edge metrics. * People that increase the scrollbar width/height expect the minimun * to grow with proportianally. So NT5 bases the minimun on * CXH/YVSCROLL, which is set by default in cpxThumb. */ /*
* i is used to keep the macro "max" from executing EngMulDiv twice. */ int i = EngMulDiv(pSBCalc->pxDownArrow - pSBCalc->pxUpArrow, pw->page, dwRange); pSBCalc->cpxThumb = max(pSBCalc->cpxThumb / 2, i); }
pSBCalc->pxMin = pSBCalc->pxTop + cpx; pSBCalc->cpx = pSBCalc->pxBottom - cpx - pSBCalc->cpxThumb - pSBCalc->pxMin;
denom = dwRange - (pw->page ? pw->page : 1); if (denom) pSBCalc->pxThumbTop = EngMulDiv(pw->pos - pw->posMin, pSBCalc->cpx, denom) + pSBCalc->pxMin; else pSBCalc->pxThumbTop = pSBCalc->pxMin - 1;
pSBCalc->pxThumbBottom = pSBCalc->pxThumbTop + pSBCalc->cpxThumb;
}
/***************************************************************************\
* SBCtlSetup * * * * History: \***************************************************************************/
void SBCtlSetup( PSBWND psbwnd) { RECT rc;
GetRect((PWND)psbwnd, &rc, GRECT_CLIENT | GRECT_CLIENTCOORDS); CalcSBStuff2(&psbwnd->SBCalc, &rc, (PSBDATA)&psbwnd->SBCalc, psbwnd->fVert); }
/***************************************************************************\
* HotTrackSB * \***************************************************************************/
#ifdef COLOR_HOTTRACKING
DWORD GetTrackFlags(int ht, BOOL fDraw) { if (fDraw) { switch(ht) { case HTSCROLLUP: case HTSCROLLUPPAGE: return LTUPFLAG;
case HTSCROLLDOWN: case HTSCROLLDOWNPAGE: return RTDNFLAG;
case HTSCROLLTHUMB: return LTUPFLAG | RTDNFLAG;
default: return 0; } } else { return 0; } }
BOOL xxxHotTrackSB(PWND pwnd, int htEx, BOOL fDraw) { SBCALC SBCalc; HDC hdc; BOOL fVert = HIWORD(htEx); int ht = LOWORD(htEx); DWORD dwTrack = GetTrackFlags(ht, fDraw);
CheckLock(pwnd);
/*
* xxxDrawSB2 does not callback or leave the critical section when it's * not a SB control and the window belongs to a different thread. It * calls xxxDefWindowProc which simply returns the brush color. */ CalcSBStuff(pwnd, &SBCalc, fVert); hdc = _GetDCEx(pwnd, NULL, DCX_WINDOW | DCX_USESTYLE | DCX_CACHE); xxxDrawSB2(pwnd, &SBCalc, hdc, fVert, GetWndSBDisableFlags(pwnd, fVert), dwTrack); _ReleaseDC(hdc); return TRUE; }
void xxxHotTrackSBCtl(PSBWND psbwnd, int ht, BOOL fDraw) { DWORD dwTrack = GetTrackFlags(ht, fDraw); HDC hdc;
CheckLock(psbwnd);
SBCtlSetup(psbwnd); hdc = _GetDCEx((PWND)psbwnd, NULL, DCX_WINDOW | DCX_USESTYLE | DCX_CACHE); xxxDrawSB2((PWND)psbwnd, &psbwnd->SBCalc, hdc, psbwnd->fVert, psbwnd->wDisableFlags, dwTrack); _ReleaseDC(hdc); } #endif // COLOR_HOTTRACKING
BOOL SBSetParms(PSBDATA pw, LPSCROLLINFO lpsi, LPBOOL lpfScroll, LPLONG lplres) { // 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 (lpsi->fMask & SIF_RETURNOLDPOS) // save previous position
*lplres = pw->pos;
if (lpsi->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 (lpsi->nMax < lpsi->nMin) lpsi->nMax = lpsi->nMin;
if ((pw->posMin != lpsi->nMin) || (pw->posMax != lpsi->nMax)) { pw->posMin = lpsi->nMin; pw->posMax = lpsi->nMax;
if (!(lpsi->fMask & SIF_PAGE)) { lpsi->fMask |= SIF_PAGE; lpsi->nPage = pw->page; }
if (!(lpsi->fMask & SIF_POS)) { lpsi->fMask |= SIF_POS; lpsi->nPos = pw->pos; }
fChanged = TRUE; } }
if (lpsi->fMask & SIF_PAGE) { DWORD dwMaxPage = (DWORD) abs(pw->posMax - pw->posMin) + 1;
// Clip page to 0, posMax - posMin + 1
if (lpsi->nPage > dwMaxPage) lpsi->nPage = dwMaxPage;
if (pw->page != (int)(lpsi->nPage)) { pw->page = lpsi->nPage;
if (!(lpsi->fMask & SIF_POS)) { lpsi->fMask |= SIF_POS; lpsi->nPos = pw->pos; }
fChanged = TRUE; } }
if (lpsi->fMask & SIF_POS) { int iMaxPos = pw->posMax - ((pw->page) ? pw->page - 1 : 0); // Clip pos to posMin, posMax - (page - 1).
if (lpsi->nPos < pw->posMin) lpsi->nPos = pw->posMin; else if (lpsi->nPos > iMaxPos) lpsi->nPos = iMaxPos;
if (pw->pos != lpsi->nPos) { pw->pos = lpsi->nPos; fChanged = TRUE; } }
if (!(lpsi->fMask & SIF_RETURNOLDPOS)) { // Return the new position
*lplres = pw->pos; }
/*
* This was added by JimA as Cairo merge but will conflict * with the documentation for SetScrollPos */ /*
else if (*lplres == pw->pos) *lplres = 0; */ if (lpsi->fMask & SIF_RANGE) { if (*lpfScroll = (pw->posMin != pw->posMax)) goto checkPage; } else if (lpsi->fMask & SIF_PAGE) checkPage: *lpfScroll = (pw->page <= (pw->posMax - pw->posMin));
return fChanged; }
/***************************************************************************\
* CalcSBStuff * * * * History: \***************************************************************************/
void CalcSBStuff( PWND pwnd, PSBCALC pSBCalc, BOOL fVert) { RECT rcT; RECT rcClient; int cx, iTemp;
//
// Get client rectangle. We know that scrollbars always align to the right
// and to the bottom of the client area.
//
GetRect(pwnd, &rcClient, GRECT_CLIENT | GRECT_WINDOWCOORDS); if (TestWF(pwnd, WEFLAYOUTRTL)) { cx = pwnd->rcWindow.right - pwnd->rcWindow.left; iTemp = rcClient.left; rcClient.left = cx - rcClient.right; rcClient.right = cx - iTemp; }
if (fVert) { // Only add on space if vertical scrollbar is really there.
if (TestWF(pwnd, WEFLEFTSCROLL)) { rcT.right = rcT.left = rcClient.left; if (TestWF(pwnd, WFVPRESENT)) rcT.left -= SYSMET(CXVSCROLL); } else { rcT.right = rcT.left = rcClient.right; if (TestWF(pwnd, WFVPRESENT)) rcT.right += SYSMET(CXVSCROLL); }
rcT.top = rcClient.top; rcT.bottom = rcClient.bottom; } else { // Only add on space if horizontal scrollbar is really there.
rcT.bottom = rcT.top = rcClient.bottom; if (TestWF(pwnd, WFHPRESENT)) rcT.bottom += SYSMET(CYHSCROLL);
rcT.left = rcClient.left; rcT.right = rcClient.right; }
// If InitPwSB stuff fails (due to our heap being full) there isn't anything reasonable
// we can do here, so just let it go through. We won't fault but the scrollbar won't work
// properly either...
if (_InitPwSB(pwnd)) CalcSBStuff2(pSBCalc, &rcT, (fVert) ? &pwnd->pSBInfo->Vert : &pwnd->pSBInfo->Horz, fVert);
}
/***************************************************************************\
* * DrawCtlThumb() * \***************************************************************************/ void DrawCtlThumb(PSBWND psb) { HBRUSH hbr, hbrSave; HDC hdc = (HDC) _GetWindowDC((PWND) psb);
SBCtlSetup(psb);
hbrSave = GreSelectBrush(hdc, hbr = xxxGetColorObjects((PWND) psb, hdc));
DrawThumb2((PWND) psb, &psb->SBCalc, hdc, hbr, psb->fVert, psb->wDisableFlags);
GreSelectBrush(hdc, hbrSave); _ReleaseDC(hdc); }
/***************************************************************************\
* xxxDrawThumb * * * * History: \***************************************************************************/
void xxxDrawThumb( PWND pwnd, PSBCALC pSBCalc, BOOL fVert) { HBRUSH hbr, hbrSave; HDC hdc; UINT wDisableFlags; SBCALC SBCalc;
CheckLock(pwnd);
if (!pSBCalc) pSBCalc = &SBCalc; hdc = (HDC)_GetWindowDC(pwnd);
CalcSBStuff(pwnd, &SBCalc, fVert); wDisableFlags = GetWndSBDisableFlags(pwnd, fVert);
hbrSave = GreSelectBrush(hdc, hbr = xxxGetColorObjects(pwnd, hdc));
DrawThumb2(pwnd, &SBCalc, hdc, hbr, fVert, wDisableFlags);
GreSelectBrush(hdc, hbrSave);
/*
* Won't hurt even if DC is already released (which happens automatically * if window is destroyed during xxxSelectColorObjects) */ _ReleaseDC(hdc); }
/***************************************************************************\
* xxxSetScrollBar * * * * History: \***************************************************************************/
LONG xxxSetScrollBar( PWND pwnd, int code, LPSCROLLINFO lpsi, BOOL fRedraw) { BOOL fVert; PSBDATA pw; PSBINFO pSBInfo; BOOL fOldScroll; BOOL fScroll; WORD wfScroll; LONG lres; BOOL fNewScroll;
CheckLock(pwnd); UserAssert(IsWinEventNotifyDeferredOK());
if (fRedraw) // window must be visible to redraw
fRedraw = IsVisible(pwnd);
if (code == SB_CTL) #ifdef FE_SB // xxxSetScrollBar()
// scroll bar control; send the control a message
if(GETPTI(pwnd)->TIF_flags & TIF_16BIT) { //
// If the target application is 16bit apps, we don't pass win40's message.
// This fix for Ichitaro v6.3. It eats the message. It never forwards
// the un-processed messages to original windows procedure via
// CallWindowProc().
//
// Is this from xxxSetScrollPos() ?
if(lpsi->fMask == (SIF_POS|SIF_RETURNOLDPOS)) { return (int)xxxSendMessage(pwnd, SBM_SETPOS, lpsi->nPos, fRedraw); // Is this from xxxSetScrollRange() ?
} else if(lpsi->fMask == SIF_RANGE) { xxxSendMessage(pwnd, SBM_SETRANGE, lpsi->nMin, lpsi->nMax); return TRUE; // Others...
} else { return (LONG)xxxSendMessage(pwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi); } } else { return (LONG)xxxSendMessage(pwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi); } #else
// scroll bar control; send the control a message
return (LONG)xxxSendMessage(pwnd, SBM_SETSCROLLINFO, (WPARAM) fRedraw, (LPARAM) lpsi); #endif // FE_SB
fVert = (code != SB_HORZ);
wfScroll = (fVert) ? WFVSCROLL : WFHSCROLL;
fScroll = fOldScroll = (TestWF(pwnd, wfScroll)) ? TRUE : FALSE;
/*
* Don't do anything if we're setting position of a nonexistent scroll bar. */ if (!(lpsi->fMask & SIF_RANGE) && !fOldScroll && (pwnd->pSBInfo == NULL)) { RIPERR0(ERROR_NO_SCROLLBARS, RIP_VERBOSE, ""); return 0; }
if (fNewScroll = !(pSBInfo = pwnd->pSBInfo)) { if ((pSBInfo = _InitPwSB(pwnd)) == NULL) return 0; }
pw = (fVert) ? &(pSBInfo->Vert) : &(pSBInfo->Horz);
if (!SBSetParms(pw, lpsi, &fScroll, &lres) && !fNewScroll) { // no change -- but if REDRAW is specified and there's a scrollbar,
// redraw the thumb
if (fOldScroll && fRedraw) goto redrawAfterSet;
return lres; }
ClrWF(pwnd, wfScroll);
if (fScroll) SetWF(pwnd, wfScroll); else if (!TestWF(pwnd, (WFHSCROLL | WFVSCROLL))) { // if neither scroll bar is set and both ranges are 0, then free up the
// scroll info
pSBInfo = pwnd->pSBInfo;
if ((pSBInfo->Horz.posMin == pSBInfo->Horz.posMax) && (pSBInfo->Vert.posMin == pSBInfo->Vert.posMax)) { DesktopFree(pwnd->head.rpdesk, (HANDLE)(pwnd->pSBInfo)); pwnd->pSBInfo = NULL; } }
if (lpsi->fMask & SIF_DISABLENOSCROLL) { if (fOldScroll) { SetWF(pwnd, wfScroll); xxxEnableWndSBArrows(pwnd, code, (fScroll) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH); } } else if (fOldScroll ^ fScroll) { PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd); if (pSBTrack && (pwnd == pSBTrack->spwndTrack)) { pSBTrack->fTrackRecalc = TRUE; } xxxRedrawFrame(pwnd); // Note: after xxx, pSBTrack may no longer be valid (but we return now)
return lres; }
if (fScroll && fRedraw && (fVert ? TestWF(pwnd, WFVPRESENT) : TestWF(pwnd, WFHPRESENT))) { PSBTRACK pSBTrack; redrawAfterSet: xxxWindowEvent(EVENT_OBJECT_VALUECHANGE, pwnd, (fVert ? OBJID_VSCROLL : OBJID_HSCROLL), INDEX_SCROLLBAR_SELF, WEF_USEPWNDTHREAD); pSBTrack = PWNDTOPSBTRACK(pwnd); // Bail out if the caller is trying to change the position of
// a scrollbar that is in the middle of tracking. We'll hose
// TrackThumb() otherwise.
if (pSBTrack && (pwnd == pSBTrack->spwndTrack) && ((BOOL)(pSBTrack->fTrackVert) == fVert) && (pSBTrack->xxxpfnSB == xxxTrackThumb)) { return lres; }
xxxDrawThumb(pwnd, NULL, fVert); // Note: after xxx, pSBTrack may no longer be valid (but we return now)
}
return lres; }
/***************************************************************************\
* xxxDrawScrollBar * * * * History: \***************************************************************************/
void xxxDrawScrollBar( PWND pwnd, HDC hdc, BOOL fVert) { SBCALC SBCalc; PSBCALC pSBCalc; PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
CheckLock(pwnd); if (pSBTrack && (pwnd == pSBTrack->spwndTrack) && (pSBTrack->fCtlSB == FALSE) && (fVert == (BOOL)pSBTrack->fTrackVert)) { pSBCalc = pSBTrack->pSBCalc; } else { pSBCalc = &SBCalc; } CalcSBStuff(pwnd, pSBCalc, fVert);
xxxDrawSB2(pwnd, pSBCalc, hdc, fVert, GetWndSBDisableFlags(pwnd, fVert)); }
/***************************************************************************\
* SBPosFromPx * * Compute scroll bar position from pixel location * * History: \***************************************************************************/
int SBPosFromPx( PSBCALC pSBCalc, int px) { if (px < pSBCalc->pxMin) { return pSBCalc->posMin; } if (px >= pSBCalc->pxMin + pSBCalc->cpx) { return (pSBCalc->posMax - (pSBCalc->page ? pSBCalc->page - 1 : 0)); } if (pSBCalc->cpx) return (pSBCalc->posMin + EngMulDiv(pSBCalc->posMax - pSBCalc->posMin - (pSBCalc->page ? pSBCalc->page - 1 : 0), px - pSBCalc->pxMin, pSBCalc->cpx)); else return (pSBCalc->posMin - 1); }
/***************************************************************************\
* InvertScrollHilite * * * * History: \***************************************************************************/
void InvertScrollHilite( PWND pwnd, PSBTRACK pSBTrack) { 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(&pSBTrack->rcTrack)) { if (pSBTrack->fTrackRecalc) { RecalcTrackRect(pSBTrack); pSBTrack->fTrackRecalc = FALSE; }
hdc = (HDC)_GetWindowDC(pwnd); InvertRect(hdc, &pSBTrack->rcTrack); _ReleaseDC(hdc); } }
/***************************************************************************\
* xxxDoScroll * * Sends scroll notification to the scroll bar owner * * History: \***************************************************************************/
void xxxDoScroll( PWND pwnd, PWND pwndNotify, int cmd, int pos, BOOL fVert ) { TL tlpwndNotify;
/*
* Special case!!!! this routine is always passed pwnds that are * not thread locked, so they need to be thread locked here. The * callers always know that by the time DoScroll() returns, * pwnd and pwndNotify could be invalid. */ ThreadLock(pwndNotify, &tlpwndNotify); xxxSendMessage(pwndNotify, (UINT)(fVert ? WM_VSCROLL : WM_HSCROLL), MAKELONG(cmd, pos), (LPARAM)HW(pwnd));
ThreadUnlock(&tlpwndNotify); }
// -------------------------------------------------------------------------
//
// CheckScrollRecalc()
//
// -------------------------------------------------------------------------
//void CheckScrollRecalc(PWND pwnd, PSBSTATE pSBState, PSBCALC pSBCalc)
//{
// if ((pSBState->pwndCalc != pwnd) || ((pSBState->nBar != SB_CTL) && (pSBState->nBar != ((pSBState->fVertSB) ? SB_VERT : SB_HORZ))))
// {
// // Calculate SB stuff based on whether it's a control or in a window
// if (pSBState->fCtlSB)
// SBCtlSetup((PSBWND) pwnd);
// else
// CalcSBStuff(pwnd, pSBCalc, pSBState->fVertSB);
// }
//}
/***************************************************************************\
* xxxMoveThumb * * History: \***************************************************************************/
void xxxMoveThumb( PWND pwnd, PSBCALC pSBCalc, int px) { HBRUSH hbr, hbrSave; HDC hdc; PSBTRACK pSBTrack;
CheckLock(pwnd);
pSBTrack = PWNDTOPSBTRACK(pwnd);
if ((pSBTrack == NULL) || (px == pSBTrack->pxOld)) return;
pxReCalc:
pSBTrack->posNew = SBPosFromPx(pSBCalc, px);
/* Tentative position changed -- notify the guy. */ if (pSBTrack->posNew != pSBTrack->posOld) { if (pSBTrack->spwndSBNotify != NULL) { xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify, SB_THUMBTRACK, pSBTrack->posNew, pSBTrack->fTrackVert );
} // After xxxDoScroll, re-evaluate pSBTrack
REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxMoveThumb(1)"); if ((pSBTrack == NULL) || (pSBTrack->xxxpfnSB == NULL)) return;
pSBTrack->posOld = pSBTrack->posNew;
//
// Anything can happen after the SendMessage above!
// Make sure that the SBINFO structure contains data for the
// window being tracked -- if not, recalculate data in SBINFO
//
// CheckScrollRecalc(pwnd, pSBState, pSBCalc);
// when we yield, our range can get messed with
// so make sure we handle this
if (px >= pSBCalc->pxMin + pSBCalc->cpx) { px = pSBCalc->pxMin + pSBCalc->cpx; goto pxReCalc; }
}
hdc = _GetWindowDC(pwnd);
pSBCalc->pxThumbTop = px; pSBCalc->pxThumbBottom = pSBCalc->pxThumbTop + pSBCalc->cpxThumb;
// at this point, the disable flags are always going to be 0 --
// we're in the middle of tracking.
hbrSave = GreSelectBrush(hdc, hbr = xxxGetColorObjects(pwnd, hdc));
// After xxxGetColorObjects, re-evaluate pSBTrack
REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxMoveThumb(2)"); if (pSBTrack == NULL) { RIPMSG1(RIP_ERROR, "Did we use to leak hdc %#p?", hdc) ; _ReleaseDC(hdc); return; } DrawThumb2(pwnd, pSBCalc, hdc, hbr, pSBTrack->fTrackVert, 0); GreSelectBrush(hdc, hbrSave); _ReleaseDC(hdc);
pSBTrack->pxOld = px; }
/***************************************************************************\
* zzzDrawInvertScrollArea * * * * History: \***************************************************************************/
void zzzDrawInvertScrollArea( PWND pwnd, PSBTRACK pSBTrack, BOOL fHit, UINT cmd) { HDC hdc; RECT rcTemp; int cx, cy; UINT bm;
if ((cmd != SB_LINEUP) && (cmd != SB_LINEDOWN)) { // not hitting on arrow -- just invert the area and return
InvertScrollHilite(pwnd, pSBTrack);
if (cmd == SB_PAGEUP) { if (fHit) SetWF(pwnd, WFPAGEUPBUTTONDOWN); else ClrWF(pwnd, WFPAGEUPBUTTONDOWN); } else { if (fHit) SetWF(pwnd, WFPAGEDNBUTTONDOWN); else ClrWF(pwnd, WFPAGEDNBUTTONDOWN); }
zzzWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)), ((cmd == SB_PAGEUP) ? INDEX_SCROLLBAR_UPPAGE : INDEX_SCROLLBAR_DOWNPAGE), WEF_USEPWNDTHREAD); // Note: after zzz, pSBTrack may no longer be valid (but we return now)
return; }
if (pSBTrack->fTrackRecalc) { RecalcTrackRect(pSBTrack); pSBTrack->fTrackRecalc = FALSE; }
CopyRect(&rcTemp, &pSBTrack->rcTrack);
hdc = _GetWindowDC(pwnd);
if (pSBTrack->fTrackVert) { cx = SYSMET(CXVSCROLL); cy = SYSMET(CYVSCROLL); } else { cx = SYSMET(CXHSCROLL); cy = SYSMET(CYHSCROLL); }
if ((cx == (rcTemp.right - rcTemp.left)) && (cy == (rcTemp.bottom - rcTemp.top))) { if (cmd == SB_LINEUP) bm = (pSBTrack->fTrackVert) ? OBI_UPARROW : OBI_LFARROW; else // SB_LINEDOWN
bm = (pSBTrack->fTrackVert) ? OBI_DNARROW : OBI_RGARROW;
if (fHit) bm += DOBI_PUSHED;
BitBltSysBmp(hdc, rcTemp.left, rcTemp.top, bm); } else { DrawFrameControl(hdc, &rcTemp, DFC_SCROLL, ((pSBTrack->fTrackVert) ? DFCS_SCROLLVERT : DFCS_SCROLLHORZ) | ((fHit) ? DFCS_PUSHED | DFCS_FLAT : 0) | ((cmd == SB_LINEUP) ? DFCS_SCROLLMIN : DFCS_SCROLLMAX)); }
_ReleaseDC(hdc);
if (cmd == SB_LINEUP) { if (fHit) SetWF(pwnd, WFLINEUPBUTTONDOWN); else ClrWF(pwnd, WFLINEUPBUTTONDOWN); } else { if (fHit) SetWF(pwnd, WFLINEDNBUTTONDOWN); else ClrWF(pwnd, WFLINEDNBUTTONDOWN); }
zzzWindowEvent(EVENT_OBJECT_STATECHANGE, pwnd, (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)), (cmd == SB_LINEUP ? INDEX_SCROLLBAR_UP : INDEX_SCROLLBAR_DOWN), WEF_USEPWNDTHREAD); // Note: after zzz, pSBTrack may no longer be valid (but we return now)
}
/***************************************************************************\
* xxxEndScroll * * * * History: \***************************************************************************/
void xxxEndScroll( PWND pwnd, BOOL fCancel) { UINT oldcmd; PSBTRACK pSBTrack; CheckLock(pwnd); UserAssert(!IsWinEventNotifyDeferred());
pSBTrack = PWNDTOPSBTRACK(pwnd); if (pSBTrack && PtiCurrent()->pq->spwndCapture == pwnd && pSBTrack->xxxpfnSB != NULL) {
oldcmd = pSBTrack->cmdSB; pSBTrack->cmdSB = 0; xxxReleaseCapture();
// After xxxReleaseCapture, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
if (pSBTrack->xxxpfnSB == xxxTrackThumb) {
if (fCancel) { pSBTrack->posOld = pSBTrack->pSBCalc->pos; }
/*
* DoScroll does thread locking on these two pwnds - * this is ok since they are not used after this * call. */ if (pSBTrack->spwndSBNotify != NULL) { xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify, SB_THUMBPOSITION, pSBTrack->posOld, pSBTrack->fTrackVert ); // After xxxDoScroll, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd); }
if (pSBTrack->fCtlSB) { DrawCtlThumb((PSBWND) pwnd); } else { xxxDrawThumb(pwnd, pSBTrack->pSBCalc, pSBTrack->fTrackVert); // Note: after xxx, pSBTrack may no longer be valid
}
} else if (pSBTrack->xxxpfnSB == xxxTrackBox) { DWORD lParam; POINT ptMsg;
if (pSBTrack->hTimerSB != 0) { _KillSystemTimer(pwnd, IDSYS_SCROLL); pSBTrack->hTimerSB = 0; } lParam = _GetMessagePos(); if (TestWF(pwnd, WEFLAYOUTRTL)) { ptMsg.x = pwnd->rcWindow.right - GET_X_LPARAM(lParam); } else { ptMsg.x = GET_X_LPARAM(lParam) - pwnd->rcWindow.left; } ptMsg.y = GET_Y_LPARAM(lParam) - pwnd->rcWindow.top; if (PtInRect(&pSBTrack->rcTrack, ptMsg)) { zzzDrawInvertScrollArea(pwnd, pSBTrack, FALSE, oldcmd); // Note: after zzz, pSBTrack may no longer be valid
} }
/*
* Always send SB_ENDSCROLL message. * * DoScroll does thread locking on these two pwnds - * this is ok since they are not used after this * call. */
// After xxxDrawThumb or zzzDrawInvertScrollArea, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
if (pSBTrack->spwndSBNotify != NULL) { xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify, SB_ENDSCROLL, 0, pSBTrack->fTrackVert); // After xxxDoScroll, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd); }
ClrWF(pwnd, WFSCROLLBUTTONDOWN); ClrWF(pwnd, WFVERTSCROLLTRACK);
xxxWindowEvent(EVENT_SYSTEM_SCROLLINGEND, pwnd, (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)), INDEXID_CONTAINER, 0); // After xxxWindowEvent, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
/*
* If this is a Scroll Bar Control, turn the caret back on. */ if (pSBTrack->spwndSB != NULL) { zzzShowCaret(pSBTrack->spwndSB); // After zzz, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd); }
pSBTrack->xxxpfnSB = NULL;
/*
* Unlock structure members so they are no longer holding down windows. */ Unlock(&pSBTrack->spwndSB); Unlock(&pSBTrack->spwndSBNotify); Unlock(&pSBTrack->spwndTrack); UserFreePool(pSBTrack); PWNDTOPSBTRACK(pwnd) = NULL; } }
/***************************************************************************\
* xxxContScroll * * * * History: \***************************************************************************/
VOID xxxContScroll( PWND pwnd, UINT message, UINT_PTR ID, LPARAM lParam) { LONG pt; PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd);
UNREFERENCED_PARAMETER(message); UNREFERENCED_PARAMETER(ID); UNREFERENCED_PARAMETER(lParam);
if (pSBTrack == NULL) return;
CheckLock(pwnd);
pt = _GetMessagePos();
if (TestWF(pwnd, WEFLAYOUTRTL)) { pt = MAKELONG(pwnd->rcWindow.right - GET_X_LPARAM(pt), GET_Y_LPARAM(pt) - pwnd->rcWindow.top); } else { pt = MAKELONG( GET_X_LPARAM(pt) - pwnd->rcWindow.left, GET_Y_LPARAM(pt) - pwnd->rcWindow.top); } xxxTrackBox(pwnd, WM_NULL, 0, pt, NULL); // After xxxTrackBox, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
if (pSBTrack->fHitOld) { pSBTrack->hTimerSB = _SetSystemTimer(pwnd, IDSYS_SCROLL, gpsi->dtScroll / 8, xxxContScroll);
/*
* DoScroll does thread locking on these two pwnds - * this is ok since they are not used after this * call. */ if (pSBTrack->spwndSBNotify != NULL) { xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify, pSBTrack->cmdSB, 0, pSBTrack->fTrackVert); // Note: after xxx, pSBTrack may no longer be valid (but we return now)
} }
return; }
/***************************************************************************\
* xxxTrackBox * * * * History: \***************************************************************************/
void xxxTrackBox( PWND pwnd, UINT message, WPARAM wParam, LPARAM lParam, PSBCALC pSBCalc) { BOOL fHit; POINT ptHit; PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd); int cmsTimer;
UNREFERENCED_PARAMETER(wParam); UNREFERENCED_PARAMETER(pSBCalc);
CheckLock(pwnd); UserAssert(IsWinEventNotifyDeferredOK());
if (pSBTrack == NULL) return;
if (message != WM_NULL && HIBYTE(message) != HIBYTE(WM_MOUSEFIRST)) return;
if (pSBTrack->fTrackRecalc) { RecalcTrackRect(pSBTrack); pSBTrack->fTrackRecalc = FALSE; }
ptHit.x = GET_X_LPARAM(lParam); ptHit.y = GET_Y_LPARAM(lParam); fHit = PtInRect(&pSBTrack->rcTrack, ptHit);
if (fHit != (BOOL)pSBTrack->fHitOld) { zzzDrawInvertScrollArea(pwnd, pSBTrack, fHit, pSBTrack->cmdSB); // After zzz, pSBTrack may no longer be valid
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd); }
cmsTimer = gpsi->dtScroll / 8;
switch (message) { case WM_LBUTTONUP: xxxEndScroll(pwnd, FALSE); // Note: after xxx, pSBTrack may no longer be valid
break;
case WM_LBUTTONDOWN: pSBTrack->hTimerSB = 0; cmsTimer = gpsi->dtScroll;
/*
*** FALL THRU ** */
case WM_MOUSEMOVE: if (fHit && fHit != (BOOL)pSBTrack->fHitOld) {
/*
* We moved back into the normal rectangle: reset timer */ pSBTrack->hTimerSB = _SetSystemTimer(pwnd, IDSYS_SCROLL, cmsTimer, xxxContScroll);
/*
* DoScroll does thread locking on these two pwnds - * this is ok since they are not used after this * call. */ if (pSBTrack->spwndSBNotify != NULL) { xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify, pSBTrack->cmdSB, 0, pSBTrack->fTrackVert); // Note: after xxx, pSBTrack may no longer be valid
} } } // After xxxDoScroll or xxxEndScroll, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd); pSBTrack->fHitOld = fHit; }
/***************************************************************************\
* xxxTrackThumb * * * * History: \***************************************************************************/
void xxxTrackThumb( PWND pwnd, UINT message, WPARAM wParam, LPARAM lParam, PSBCALC pSBCalc) { int px; PSBTRACK pSBTrack = PWNDTOPSBTRACK(pwnd); POINT pt;
UNREFERENCED_PARAMETER(wParam);
CheckLock(pwnd);
if (HIBYTE(message) != HIBYTE(WM_MOUSEFIRST)) return;
if (pSBTrack == NULL) return;
// Make sure that the SBINFO structure contains data for the
// window being tracked -- if not, recalculate data in SBINFO
// CheckScrollRecalc(pwnd, pSBState, pSBCalc);
if (pSBTrack->fTrackRecalc) { RecalcTrackRect(pSBTrack); pSBTrack->fTrackRecalc = FALSE; }
pt.y = GET_Y_LPARAM(lParam); pt.x = GET_X_LPARAM(lParam); if (!PtInRect(&pSBTrack->rcTrack, pt)) px = pSBCalc->pxStart; else { px = (pSBTrack->fTrackVert ? pt.y : pt.x) + pSBTrack->dpxThumb; if (px < pSBCalc->pxMin) px = pSBCalc->pxMin; else if (px >= pSBCalc->pxMin + pSBCalc->cpx) px = pSBCalc->pxMin + pSBCalc->cpx; }
xxxMoveThumb(pwnd, pSBCalc, px);
/*
* We won't get the WM_LBUTTONUP message if we got here through * the scroll menu, so test the button state directly. */ if (message == WM_LBUTTONUP || _GetKeyState(VK_LBUTTON) >= 0) { xxxEndScroll(pwnd, FALSE); }
}
/***************************************************************************\
* xxxSBTrackLoop * * * * History: \***************************************************************************/
void xxxSBTrackLoop( PWND pwnd, LPARAM lParam, PSBCALC pSBCalc) { MSG msg; UINT cmd; PTHREADINFO ptiCurrent; VOID (*xxxpfnSB)(PWND, UINT, WPARAM, LPARAM, PSBCALC); PSBTRACK pSBTrack;
CheckLock(pwnd); UserAssert(IsWinEventNotifyDeferredOK());
pSBTrack = PWNDTOPSBTRACK(pwnd);
if ((pSBTrack == NULL) || (NULL == (xxxpfnSB = pSBTrack->xxxpfnSB))) // mode cancelled -- exit track loop
return;
if (pSBTrack->fTrackVert) SetWF(pwnd, WFVERTSCROLLTRACK);
xxxWindowEvent(EVENT_SYSTEM_SCROLLINGSTART, pwnd, (pSBTrack->fCtlSB ? OBJID_CLIENT : (pSBTrack->fTrackVert ? OBJID_VSCROLL : OBJID_HSCROLL)), INDEXID_CONTAINER, 0); // Note: after xxx, pSBTrack may no longer be valid
(*xxxpfnSB)(pwnd, WM_LBUTTONDOWN, 0, lParam, pSBCalc); // Note: after xxx, pSBTrack may no longer be valid
ptiCurrent = PtiCurrent();
while (ptiCurrent->pq->spwndCapture == pwnd) { if (!xxxGetMessage(&msg, NULL, 0, 0)) { // Note: after xxx, pSBTrack may no longer be valid
break; }
if (!_CallMsgFilter(&msg, MSGF_SCROLLBAR)) { cmd = msg.message;
if (msg.hwnd == HWq(pwnd) && ((cmd >= WM_MOUSEFIRST && cmd <= WM_MOUSELAST) || (cmd >= WM_KEYFIRST && cmd <= WM_KEYLAST))) { cmd = SystoChar(cmd, msg.lParam);
// After xxxWindowEvent, xxxpfnSB, xxxTranslateMessage or
// xxxDispatchMessage, re-evaluate pSBTrack.
REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxTrackLoop"); if ((pSBTrack == NULL) || (NULL == (xxxpfnSB = pSBTrack->xxxpfnSB))) // mode cancelled -- exit track loop
return;
(*xxxpfnSB)(pwnd, cmd, msg.wParam, msg.lParam, pSBCalc); } else { xxxTranslateMessage(&msg, 0); xxxDispatchMessage(&msg); } } } }
/***************************************************************************\
* xxxSBTrackInit * * History: \***************************************************************************/
void xxxSBTrackInit( PWND pwnd, LPARAM lParam, int curArea, UINT uType) { int px; LPINT pwX; LPINT pwY; UINT wDisable; // Scroll bar disable flags;
SBCALC SBCalc; PSBCALC pSBCalc; RECT rcSB; PSBTRACK pSBTrack;
CheckLock(pwnd);
if (PWNDTOPSBTRACK(pwnd)) { RIPMSG1(RIP_WARNING, "xxxSBTrackInit: PWNDTOPSBTRACK(pwnd) == %#p", PWNDTOPSBTRACK(pwnd)); return; }
pSBTrack = (PSBTRACK)UserAllocPoolWithQuota(sizeof(*pSBTrack), TAG_SCROLLTRACK); if (pSBTrack == NULL) return;
pSBTrack->hTimerSB = 0; pSBTrack->fHitOld = FALSE;
pSBTrack->xxxpfnSB = xxxTrackBox;
pSBTrack->spwndTrack = NULL; pSBTrack->spwndSB = NULL; pSBTrack->spwndSBNotify = NULL; Lock(&pSBTrack->spwndTrack, pwnd); PWNDTOPSBTRACK(pwnd) = pSBTrack;
pSBTrack->fCtlSB = (!curArea); if (pSBTrack->fCtlSB) {
/*
* This is a scroll bar control. */ Lock(&pSBTrack->spwndSB, pwnd); pSBTrack->fTrackVert = ((PSBWND)pwnd)->fVert; Lock(&pSBTrack->spwndSBNotify, pwnd->spwndParent); wDisable = ((PSBWND)pwnd)->wDisableFlags; pSBCalc = &((PSBWND)pwnd)->SBCalc; pSBTrack->nBar = SB_CTL; } else {
/*
* This is a scroll bar that is part of the window frame. */
//
// Mirror the window coord of the scroll bar,
// if it is a mirrored one
//
if (TestWF(pwnd,WEFLAYOUTRTL)) { lParam = MAKELONG( pwnd->rcWindow.right - GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) - pwnd->rcWindow.top); } else { lParam = MAKELONG( GET_X_LPARAM(lParam) - pwnd->rcWindow.left, GET_Y_LPARAM(lParam) - pwnd->rcWindow.top); }
Lock(&pSBTrack->spwndSBNotify, pwnd); Lock(&pSBTrack->spwndSB, NULL); pSBTrack->fTrackVert = (curArea - HTHSCROLL); wDisable = GetWndSBDisableFlags(pwnd, pSBTrack->fTrackVert); pSBCalc = &SBCalc; pSBTrack->nBar = (curArea - HTHSCROLL) ? SB_VERT : SB_HORZ; }
pSBTrack->pSBCalc = pSBCalc; /*
* Check if the whole scroll bar is disabled */ if((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) { Unlock(&pSBTrack->spwndSBNotify); Unlock(&pSBTrack->spwndSB); Unlock(&pSBTrack->spwndTrack); UserFreePool(pSBTrack); PWNDTOPSBTRACK(pwnd) = NULL; return; // It is a disabled scroll bar; So, do not respond.
}
if (!pSBTrack->fCtlSB) { CalcSBStuff(pwnd, pSBCalc, pSBTrack->fTrackVert); }
pwX = (LPINT)&rcSB; pwY = pwX + 1; if (!pSBTrack->fTrackVert) pwX = pwY--;
px = (pSBTrack->fTrackVert ? GET_Y_LPARAM(lParam) : GET_X_LPARAM(lParam));
*(pwX + 0) = pSBCalc->pxLeft; *(pwY + 0) = pSBCalc->pxTop; *(pwX + 2) = pSBCalc->pxRight; *(pwY + 2) = pSBCalc->pxBottom; pSBTrack->cmdSB = (UINT)-1; if (px < pSBCalc->pxUpArrow) {
/*
* The click occurred on Left/Up arrow; Check if it is disabled */ if(wDisable & LTUPFLAG) { if(pSBTrack->fCtlSB) { // If this is a scroll bar control,
zzzShowCaret(pSBTrack->spwndSB); // show the caret before returning;
// After zzzShowCaret, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd); }
Unlock(&pSBTrack->spwndSBNotify); Unlock(&pSBTrack->spwndSB); Unlock(&pSBTrack->spwndTrack); UserFreePool(pSBTrack); PWNDTOPSBTRACK(pwnd) = NULL; return; // Yes! disabled. Do not respond.
}
// LINEUP -- make rcSB the Up Arrow's Rectangle
pSBTrack->cmdSB = SB_LINEUP; *(pwY + 2) = pSBCalc->pxUpArrow; } else if (px >= pSBCalc->pxDownArrow) {
/*
* The click occurred on Right/Down arrow; Check if it is disabled */ if (wDisable & RTDNFLAG) { if (pSBTrack->fCtlSB) { // If this is a scroll bar control,
zzzShowCaret(pSBTrack->spwndSB); // show the caret before returning;
// After zzzShowCaret, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd); }
Unlock(&pSBTrack->spwndSBNotify); Unlock(&pSBTrack->spwndSB); Unlock(&pSBTrack->spwndTrack); UserFreePool(pSBTrack); PWNDTOPSBTRACK(pwnd) = NULL; return;// Yes! disabled. Do not respond.
}
// LINEDOWN -- make rcSB the Down Arrow's Rectangle
pSBTrack->cmdSB = SB_LINEDOWN; *(pwY + 0) = pSBCalc->pxDownArrow; } else if (px < pSBCalc->pxThumbTop) { // PAGEUP -- make rcSB the rectangle between Up Arrow and Thumb
pSBTrack->cmdSB = SB_PAGEUP; *(pwY + 0) = pSBCalc->pxUpArrow; *(pwY + 2) = pSBCalc->pxThumbTop; } else if (px < pSBCalc->pxThumbBottom) {
DoThumbPos: /*
* Elevator isn't there if there's no room. */ if (pSBCalc->pxDownArrow - pSBCalc->pxUpArrow <= pSBCalc->cpxThumb) { Unlock(&pSBTrack->spwndSBNotify); Unlock(&pSBTrack->spwndSB); Unlock(&pSBTrack->spwndTrack); UserFreePool(pSBTrack); PWNDTOPSBTRACK(pwnd) = NULL; return; } // THUMBPOSITION -- we're tracking with the thumb
pSBTrack->cmdSB = SB_THUMBPOSITION; CalcTrackDragRect(pSBTrack);
pSBTrack->xxxpfnSB = xxxTrackThumb; pSBTrack->pxOld = pSBCalc->pxStart = pSBCalc->pxThumbTop; pSBTrack->posNew = pSBTrack->posOld = pSBCalc->pos; pSBTrack->dpxThumb = pSBCalc->pxStart - px;
xxxCapture(PtiCurrent(), pwnd, WINDOW_CAPTURE); // After xxxCapture, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
/*
* DoScroll does thread locking on these two pwnds - * this is ok since they are not used after this * call. */ if (pSBTrack->spwndSBNotify != NULL) { xxxDoScroll(pSBTrack->spwndSB, pSBTrack->spwndSBNotify, SB_THUMBTRACK, pSBTrack->posOld, pSBTrack->fTrackVert ); // Note: after xxx, pSBTrack may no longer be valid
} } else if (px < pSBCalc->pxDownArrow) { // PAGEDOWN -- make rcSB the rectangle between Thumb and Down Arrow
pSBTrack->cmdSB = SB_PAGEDOWN; *(pwY + 0) = pSBCalc->pxThumbBottom; *(pwY + 2) = pSBCalc->pxDownArrow; }
/*
* If the shift key is down, we'll position the thumb directly so it's * centered on the click point. */ if ((uType == SCROLL_DIRECT && pSBTrack->cmdSB != SB_LINEUP && pSBTrack->cmdSB != SB_LINEDOWN) || (uType == SCROLL_MENU)) { if (pSBTrack->cmdSB != SB_THUMBPOSITION) { goto DoThumbPos; } pSBTrack->dpxThumb = -(pSBCalc->cpxThumb / 2); }
xxxCapture(PtiCurrent(), pwnd, WINDOW_CAPTURE); // After xxxCapture, revalidate pSBTrack
RETURN_IF_PSBTRACK_INVALID(pSBTrack, pwnd);
if (pSBTrack->cmdSB != SB_THUMBPOSITION) { CopyRect(&pSBTrack->rcTrack, &rcSB); }
xxxSBTrackLoop(pwnd, lParam, pSBCalc);
// After xxx, re-evaluate pSBTrack
REEVALUATE_PSBTRACK(pSBTrack, pwnd, "xxxTrackLoop"); if (pSBTrack) { Unlock(&pSBTrack->spwndSBNotify); Unlock(&pSBTrack->spwndSB); Unlock(&pSBTrack->spwndTrack); UserFreePool(pSBTrack); PWNDTOPSBTRACK(pwnd) = NULL; } }
/***************************************************************************\
* GetScrollMenu * * History: \***************************************************************************/
PMENU xxxGetScrollMenu( PWND pwnd, BOOL fVert) { PMENU pMenu; PMENU *ppDesktopMenu;
/*
* Grab the menu from the desktop. If the desktop menu * has not been loaded and this is not a system thread, * load it now. Callbacks cannot be made from a system * thread or when a thread is in cleanup. */ if (fVert) { ppDesktopMenu = &pwnd->head.rpdesk->spmenuVScroll; } else { ppDesktopMenu = &pwnd->head.rpdesk->spmenuHScroll; } pMenu = *ppDesktopMenu; if (pMenu == NULL && !(PtiCurrent()->TIF_flags & (TIF_SYSTEMTHREAD | TIF_INCLEANUP))) { UNICODE_STRING strMenuName;
RtlInitUnicodeStringOrId(&strMenuName, fVert ? MAKEINTRESOURCE(ID_VSCROLLMENU) : MAKEINTRESOURCE(ID_HSCROLLMENU)); pMenu = xxxClientLoadMenu(NULL, &strMenuName); LockDesktopMenu(ppDesktopMenu, pMenu); }
/*
* Return the handle to the scroll menu. */ if (pMenu != NULL) { return _GetSubMenu(pMenu, 0); }
return NULL; }
/***************************************************************************\
* xxxDoScrollMenu * * History: \***************************************************************************/
VOID xxxDoScrollMenu( PWND pwndNotify, PWND pwndSB, BOOL fVert, LPARAM lParam) { PMENU pMenu; SBCALC SBCalc, *pSBCalc; UINT cmd; POINT pt; TL tlpmenu; UINT wDisable;
/*
* Check the compatibility flag. Word 6.0 AV's when selecting an item * in this menu. * NOTE: If this hack is to be extended for other apps we should use * another bit for GACF_NOSCROLLBARCTXMENU as the current one is re-used * MCostea #119380 */ if (GetAppCompatFlags(NULL) & GACF_NOSCROLLBARCTXMENU) { return; }
/*
* Initialize some stuff. */ POINTSTOPOINT(pt, lParam); if (pwndSB) { SBCtlSetup((PSBWND)pwndSB); pSBCalc = &(((PSBWND)pwndSB)->SBCalc); wDisable = ((PSBWND)pwndSB)->wDisableFlags; pt.x -= pwndSB->rcWindow.left; pt.y -= pwndSB->rcWindow.top; } else { pSBCalc = &SBCalc; CalcSBStuff(pwndNotify, pSBCalc, fVert); wDisable = GetWndSBDisableFlags(pwndNotify, fVert); pt.x -= pwndNotify->rcWindow.left; pt.y -= pwndNotify->rcWindow.top; }
/*
* Make sure the scrollbar isn't disabled. */ if ((wDisable & SB_DISABLE_MASK) == SB_DISABLE_MASK) { return; }
/*
* Put up a menu and scroll accordingly. */ if ((pMenu = xxxGetScrollMenu(pwndNotify, fVert)) != NULL) { ThreadLockAlways(pMenu, &tlpmenu); cmd = xxxTrackPopupMenuEx(pMenu, TPM_RIGHTBUTTON | TPM_RETURNCMD | TPM_NONOTIFY, GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam), pwndNotify, NULL); ThreadUnlock(&tlpmenu); if (cmd) { if ((cmd & 0x00FF) == SB_THUMBPOSITION) { if (pwndSB) { xxxSBTrackInit(pwndSB, MAKELPARAM(pt.x, pt.y), 0, SCROLL_MENU); } else { xxxSBTrackInit(pwndNotify, lParam, fVert ? HTVSCROLL : HTHSCROLL, SCROLL_MENU); } } else { xxxDoScroll(pwndSB, pwndNotify, cmd & 0x00FF, 0, fVert ); xxxDoScroll(pwndSB, pwndNotify, SB_ENDSCROLL, 0, fVert ); } } } }
/***************************************************************************\
* xxxSBWndProc * * History: * 08-15-95 jparsons Added guard against NULL lParam [51986] \***************************************************************************/
LRESULT xxxSBWndProc( PSBWND psbwnd, UINT message, WPARAM wParam, LPARAM lParam) { LONG l; LONG lres; int cx; int cy; UINT cmd; UINT uSide; HDC hdc; RECT rc; POINT pt; BOOL fSizeReal; HBRUSH hbrSave; BOOL fSize; PAINTSTRUCT ps; UINT style; TL tlpwndParent; SCROLLINFO si; LPSCROLLINFO lpsi = &si; BOOL fRedraw = FALSE; BOOL fScroll;
CheckLock(psbwnd); UserAssert(IsWinEventNotifyDeferredOK());
VALIDATECLASSANDSIZE(((PWND)psbwnd), message, wParam, lParam, FNID_SCROLLBAR, WM_CREATE);
style = LOBYTE(psbwnd->wnd.style); fSize = ((style & (SBS_SIZEBOX | SBS_SIZEGRIP)) != 0);
switch (message) { case WM_CREATE: /*
* Guard against lParam being NULL since the thunk allows it [51986] */ if (lParam) { rc.right = (rc.left = ((LPCREATESTRUCT)lParam)->x) + ((LPCREATESTRUCT)lParam)->cx; rc.bottom = (rc.top = ((LPCREATESTRUCT)lParam)->y) + ((LPCREATESTRUCT)lParam)->cy; // This is because we can't just rev CardFile -- we should fix the
// problem here in case anyone else happened to have some EXTRA
// scroll styles on their scroll bar controls (jeffbog 03/21/94)
if (!TestWF((PWND)psbwnd, WFWIN40COMPAT)) psbwnd->wnd.style &= ~(WS_HSCROLL | WS_VSCROLL);
if (!fSize) { l = PtrToLong(((LPCREATESTRUCT)lParam)->lpCreateParams); psbwnd->SBCalc.pos = psbwnd->SBCalc.posMin = LOWORD(l); psbwnd->SBCalc.posMax = HIWORD(l); psbwnd->fVert = ((LOBYTE(psbwnd->wnd.style) & SBS_VERT) != 0); psbwnd->SBCalc.page = 0; }
if (psbwnd->wnd.style & WS_DISABLED) psbwnd->wDisableFlags = SB_DISABLE_MASK;
if (style & (SBS_TOPALIGN | SBS_BOTTOMALIGN)) { if (fSize) { if (style & SBS_SIZEBOXBOTTOMRIGHTALIGN) { rc.left = rc.right - SYSMET(CXVSCROLL); rc.top = rc.bottom - SYSMET(CYHSCROLL); }
rc.right = rc.left + SYSMET(CXVSCROLL); rc.bottom = rc.top + SYSMET(CYHSCROLL); } else { if (style & SBS_VERT) { if (style & SBS_LEFTALIGN) rc.right = rc.left + SYSMET(CXVSCROLL); else rc.left = rc.right - SYSMET(CXVSCROLL); } else { if (style & SBS_TOPALIGN) rc.bottom = rc.top + SYSMET(CYHSCROLL); else rc.top = rc.bottom - SYSMET(CYHSCROLL); } }
xxxMoveWindow((PWND)psbwnd, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top, FALSE); } } /* if */
else { RIPERR0(ERROR_INVALID_PARAMETER, RIP_WARNING, "xxxSBWndProc - NULL lParam for WM_CREATE\n") ; } /* else */
break;
case WM_SIZE: if (PtiCurrent()->pq->spwndFocus != (PWND)psbwnd) break;
// scroll bar has the focus -- recalc it's thumb caret size
// no need to DeferWinEventNotify() - see xxxCreateCaret below.
zzzDestroyCaret();
// | |
// | FALL THRU |
// V V
case WM_SETFOCUS: SBCtlSetup(psbwnd);
cx = (psbwnd->fVert ? psbwnd->wnd.rcWindow.right - psbwnd->wnd.rcWindow.left : psbwnd->SBCalc.cpxThumb) - 2 * SYSMET(CXEDGE); cy = (psbwnd->fVert ? psbwnd->SBCalc.cpxThumb : psbwnd->wnd.rcWindow.bottom - psbwnd->wnd.rcWindow.top) - 2 * SYSMET(CYEDGE);
xxxCreateCaret((PWND)psbwnd, (HBITMAP)1, cx, cy); zzzSetSBCaretPos(psbwnd); zzzShowCaret((PWND)psbwnd); break;
case WM_KILLFOCUS: zzzDestroyCaret(); break;
case WM_ERASEBKGND:
/*
* Do nothing, but don't let DefWndProc() do it either. * It will be erased when its painted. */ return (LONG)TRUE;
case WM_PRINTCLIENT: case WM_PAINT: if ((hdc = (HDC)wParam) == NULL) { hdc = xxxBeginPaint((PWND)psbwnd, (LPPAINTSTRUCT)&ps); } if (!fSize) { SBCtlSetup(psbwnd); xxxDrawSB2((PWND)psbwnd, &psbwnd->SBCalc, hdc, psbwnd->fVert, psbwnd->wDisableFlags); } else { fSizeReal = TestWF((PWND)psbwnd, WFSIZEBOX); if (!fSizeReal) SetWF((PWND)psbwnd, WFSIZEBOX);
DrawSize((PWND)psbwnd, hdc, 0, 0);
if (!fSizeReal) ClrWF((PWND)psbwnd, WFSIZEBOX); }
if (wParam == 0L) xxxEndPaint((PWND)psbwnd, (LPPAINTSTRUCT)&ps); break;
case WM_GETDLGCODE: return DLGC_WANTARROWS;
case WM_CONTEXTMENU: ThreadLock(psbwnd->wnd.spwndParent, &tlpwndParent); xxxDoScrollMenu(psbwnd->wnd.spwndParent, (PWND)psbwnd, psbwnd->fVert, lParam); ThreadUnlock(&tlpwndParent); break;
case WM_NCHITTEST: if (style & SBS_SIZEGRIP) { /*
* If the scroll bar is RTL mirrored, then * mirror the hittest of the grip location. */ if (TestWF((PWND)psbwnd, WEFLAYOUTRTL)) { return HTBOTTOMLEFT; } else { return HTBOTTOMRIGHT; } } else { goto DoDefault; } break;
#ifdef COLOR_HOTTRACKING
case WM_MOUSELEAVE: xxxHotTrackSBCtl(psbwnd, 0, FALSE); psbwnd->ht = 0; break;
case WM_MOUSEMOVE: { int ht;
if (psbwnd->ht == 0) { TRACKMOUSEEVENT tme = {sizeof(TRACKMOUSEEVENT), TME_LEAVE, HWq(psbwnd), 0}; TrackMouseEvent(&tme); }
pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); ht = HitTestScrollBar((PWND)psbwnd, psbwnd->fVert, pt); if (psbwnd->ht != ht) { xxxHotTrackSBCtl(psbwnd, ht, TRUE); psbwnd->ht = ht; } } break; #endif // COLOR_HOTTRACKING
case WM_LBUTTONDBLCLK: cmd = SC_ZOOM; if (fSize) goto postmsg;
/*
*** FALL THRU ** */
case WM_LBUTTONDOWN: //
// Note that SBS_SIZEGRIP guys normally won't ever see button
// downs. This is because they return HTBOTTOMRIGHT to
// WindowHitTest handling. This will walk up the parent chain
// to the first sizeable ancestor, bailing out at caption windows
// of course. That dude, if he exists, will handle the sizing
// instead.
//
if (!fSize) { if (TestWF((PWND)psbwnd, WFTABSTOP)) { xxxSetFocus((PWND)psbwnd); }
zzzHideCaret((PWND)psbwnd); SBCtlSetup(psbwnd);
/*
* SBCtlSetup enters SEM_SB, and xxxSBTrackInit leaves it. */ xxxSBTrackInit((PWND)psbwnd, lParam, 0, (_GetKeyState(VK_SHIFT) < 0) ? SCROLL_DIRECT : SCROLL_NORMAL); break; } else { cmd = SC_SIZE; postmsg: pt.x = GET_X_LPARAM(lParam); pt.y = GET_Y_LPARAM(lParam); _ClientToScreen((PWND)psbwnd, &pt); lParam = MAKELONG(pt.x, pt.y);
/*
* convert HT value into a move value. This is bad, * but this is purely temporary. */ if (TestWF(((PWND)psbwnd)->spwndParent,WEFLAYOUTRTL)) { uSide = HTBOTTOMLEFT; } else { uSide = HTBOTTOMRIGHT; } ThreadLock(((PWND)psbwnd)->spwndParent, &tlpwndParent); xxxSendMessage(((PWND)psbwnd)->spwndParent, WM_SYSCOMMAND, (cmd | (uSide - HTSIZEFIRST + 1)), lParam); ThreadUnlock(&tlpwndParent); } break;
case WM_KEYUP: switch (wParam) { case VK_HOME: case VK_END: case VK_PRIOR: case VK_NEXT: case VK_LEFT: case VK_UP: case VK_RIGHT: case VK_DOWN:
/*
* Send end scroll message when user up clicks on keyboard * scrolling. * * DoScroll does thread locking on these two pwnds - * this is ok since they are not used after this * call. */ xxxDoScroll((PWND)psbwnd, psbwnd->wnd.spwndParent, SB_ENDSCROLL, 0, psbwnd->fVert ); break;
default: break; } break;
case WM_KEYDOWN: switch (wParam) { case VK_HOME: wParam = SB_TOP; goto KeyScroll;
case VK_END: wParam = SB_BOTTOM; goto KeyScroll;
case VK_PRIOR: wParam = SB_PAGEUP; goto KeyScroll;
case VK_NEXT: wParam = SB_PAGEDOWN; goto KeyScroll;
case VK_LEFT: case VK_UP: wParam = SB_LINEUP; goto KeyScroll;
case VK_RIGHT: case VK_DOWN: wParam = SB_LINEDOWN; KeyScroll:
/*
* DoScroll does thread locking on these two pwnds - * this is ok since they are not used after this * call. */ xxxDoScroll((PWND)psbwnd, psbwnd->wnd.spwndParent, (int)wParam, 0, psbwnd->fVert ); break;
default: break; } break;
case WM_ENABLE: return xxxSendMessage((PWND)psbwnd, SBM_ENABLE_ARROWS, (wParam ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH), 0);
case SBM_ENABLE_ARROWS:
/*
* This is used to enable/disable the arrows in a SB ctrl */ return (LONG)xxxEnableSBCtlArrows((PWND)psbwnd, (UINT)wParam);
case SBM_GETPOS: return (LONG)psbwnd->SBCalc.pos;
case SBM_GETRANGE: *((LPINT)wParam) = psbwnd->SBCalc.posMin; *((LPINT)lParam) = psbwnd->SBCalc.posMax; return MAKELRESULT(LOWORD(psbwnd->SBCalc.posMin), LOWORD(psbwnd->SBCalc.posMax));
case SBM_GETSCROLLINFO: return (LONG)_SBGetParms((PWND)psbwnd, SB_CTL, (PSBDATA)&psbwnd->SBCalc, (LPSCROLLINFO) lParam);
case SBM_SETRANGEREDRAW: fRedraw = TRUE;
case SBM_SETRANGE: // Save the old values of Min and Max for return value
si.cbSize = sizeof(si); // si.nMin = LOWORD(lParam);
// si.nMax = HIWORD(lParam);
si.nMin = (int)wParam; si.nMax = (int)lParam; si.fMask = SIF_RANGE | SIF_RETURNOLDPOS; goto SetInfo;
case SBM_SETPOS: fRedraw = (BOOL) lParam; si.cbSize = sizeof(si); si.fMask = SIF_POS | SIF_RETURNOLDPOS; si.nPos = (int)wParam; goto SetInfo;
case SBM_SETSCROLLINFO: lpsi = (LPSCROLLINFO) lParam; fRedraw = (BOOL) wParam; SetInfo: fScroll = TRUE;
if (SBSetParms((PSBDATA)&psbwnd->SBCalc, lpsi, &fScroll, &lres)) { xxxWindowEvent(EVENT_OBJECT_VALUECHANGE, (PWND)psbwnd, OBJID_CLIENT, INDEX_SCROLLBAR_SELF, WEF_USEPWNDTHREAD); }
if (!fRedraw) return lres;
/*
* We must set the new position of the caret irrespective of * whether the window is visible or not; * Still, this will work only if the app has done a xxxSetScrollPos * with fRedraw = TRUE; * Fix for Bug #5188 --SANKAR-- 10-15-89 * No need to DeferWinEventNotify since psbwnd is locked. */ zzzHideCaret((PWND)psbwnd); SBCtlSetup(psbwnd); zzzSetSBCaretPos(psbwnd);
/*
** The following zzzShowCaret() must be done after the DrawThumb2(), ** otherwise this caret will be erased by DrawThumb2() resulting ** in this bug: ** Fix for Bug #9263 --SANKAR-- 02-09-90 * */
/*
*********** zzzShowCaret((PWND)psbwnd); ****** */
if (_FChildVisible((PWND)psbwnd) && fRedraw) { UINT wDisable; HBRUSH hbrUse;
if (!fScroll) fScroll = !(lpsi->fMask & SIF_DISABLENOSCROLL);
wDisable = (fScroll) ? ESB_ENABLE_BOTH : ESB_DISABLE_BOTH; xxxEnableScrollBar((PWND) psbwnd, SB_CTL, wDisable);
hdc = _GetWindowDC((PWND)psbwnd); hbrSave = GreSelectBrush(hdc, hbrUse = xxxGetColorObjects((PWND)psbwnd, hdc));
/*
* Before we used to only hideshowthumb() if the mesage was * not SBM_SETPOS. I am not sure why but this case was ever * needed for win 3.x but on NT it resulted in trashing the border * of the scrollbar when the app called SetScrollPos() during * scrollbar tracking. - mikehar 8/26 */ DrawThumb2((PWND)psbwnd, &psbwnd->SBCalc, hdc, hbrUse, psbwnd->fVert, psbwnd->wDisableFlags); GreSelectBrush(hdc, hbrSave); _ReleaseDC(hdc); }
/*
* This zzzShowCaret() has been moved to this place from above * Fix for Bug #9263 --SANKAR-- 02-09-90 */ zzzShowCaret((PWND)psbwnd); return lres;
case SBM_GETSCROLLBARINFO: return (LONG)xxxGetScrollBarInfo((PWND)psbwnd, OBJID_CLIENT, (PSCROLLBARINFO)lParam);
default: DoDefault: return xxxDefWindowProc((PWND)psbwnd, message, wParam, lParam); }
return 0L; }
|