WindowsXP-SP1/windows/oleacc/oleacc/scroll.cpp
2020-09-30 16:53:49 +02:00

1832 lines
48 KiB
C++

// Copyright (c) 1996-1999 Microsoft Corporation
// --------------------------------------------------------------------------
//
// SCROLL.CPP
//
// Scroll bar class.
//
// OUTSTANDING ISSUES:
// Internationalize scrollbar placement for RtoL languages in window.
//
// --------------------------------------------------------------------------
#include "oleacc_p.h"
#include "default.h"
#include "window.h"
#include "client.h"
#include "scroll.h"
#include "propmgr_util.h"
/////////////////////////////////////////////////////////////////////////////
//
// SCROLLBAR (in a Window)
//
/////////////////////////////////////////////////////////////////////////////
// --------------------------------------------------------------------------
//
// CreateScrollBarObject()
//
// --------------------------------------------------------------------------
HRESULT CreateScrollBarObject(HWND hwnd, long idObject, REFIID riid, void** ppvScroll)
{
return(CreateScrollBarThing(hwnd, idObject, 0, riid, ppvScroll));
}
// --------------------------------------------------------------------------
//
// CreateScrollBarThing()
//
// --------------------------------------------------------------------------
HRESULT CreateScrollBarThing(HWND hwnd, long idObject, long iItem, REFIID riid, void** ppvScroll)
{
CScrollBar * pscroll;
HRESULT hr;
InitPv(ppvScroll);
pscroll = new CScrollBar();
if (pscroll)
{
if (! pscroll->FInitialize(hwnd, idObject, iItem))
{
delete pscroll;
return(E_FAIL);
}
}
else
return(E_OUTOFMEMORY);
hr = pscroll->QueryInterface(riid, ppvScroll);
if (!SUCCEEDED(hr))
delete pscroll;
return(hr);
}
// --------------------------------------------------------------------------
//
// CScrollBar::Clone()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollBar::Clone(IEnumVARIANT** ppenum)
{
return(CreateScrollBarThing(m_hwnd, (m_fVertical ? OBJID_VSCROLL : OBJID_HSCROLL),
m_idChildCur, IID_IEnumVARIANT, (void**)ppenum));
}
// --------------------------------------------------------------------------
//
// CScrollBar::FInitialize()
//
// --------------------------------------------------------------------------
BOOL CScrollBar::FInitialize(HWND hwndScrollBar, LONG idObject, LONG iChildCur)
{
if (! IsWindow(hwndScrollBar))
return(FALSE);
m_hwnd = hwndScrollBar;
m_cChildren = CCHILDREN_SCROLLBAR;
m_idChildCur = iChildCur;
m_fVertical = (idObject == OBJID_VSCROLL);
return(TRUE);
}
// --------------------------------------------------------------------------
//
// GetScrollMask()
//
// Gets present elements (may or may not be offscreen)
//
// --------------------------------------------------------------------------
void FixUpScrollBarInfo(LPSCROLLBARINFO lpsbi)
{
if (lpsbi->rgstate[INDEX_SCROLLBAR_SELF] & STATE_SYSTEM_UNAVAILABLE)
{
lpsbi->rgstate[INDEX_SCROLLBAR_UPPAGE] |= STATE_SYSTEM_INVISIBLE;
lpsbi->rgstate[INDEX_SCROLLBAR_THUMB] |= STATE_SYSTEM_INVISIBLE;
lpsbi->rgstate[INDEX_SCROLLBAR_DOWNPAGE] |= STATE_SYSTEM_INVISIBLE;
}
}
// --------------------------------------------------------------------------
//
// CScrollBar::get_accName()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollBar::get_accName(VARIANT varChild, BSTR* pszName)
{
InitPv(pszName);
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
return(HrCreateString(STR_SCROLLBAR_NAME + varChild.lVal +
(m_fVertical ? 0 : INDEX_SCROLLBAR_HORIZONTAL), pszName));
}
// --------------------------------------------------------------------------
//
// CScrollBar::get_accValue()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollBar::get_accValue(VARIANT varChild, BSTR* pszValue)
{
long lPos;
InitPv(pszValue);
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
if (varChild.lVal)
return(E_NOT_APPLICABLE);
//
// The value is the position.
//
lPos = GetScrollPos(m_hwnd, (m_fVertical ? SB_VERT : SB_HORZ));
int Min, Max;
GetScrollRange( m_hwnd, (m_fVertical ? SB_VERT : SB_HORZ), & Min, & Max );
// work out a percent value...
if( Min != Max )
lPos = ( ( lPos - Min ) * 100 ) / ( Max - Min );
else
lPos = 0; // Prevent div-by-0
return(VarBstrFromI4(lPos, 0, 0, pszValue));
}
// --------------------------------------------------------------------------
//
// CScrollBar::get_accDescription()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollBar::get_accDescription(VARIANT varChild, BSTR* pszDesc)
{
InitPv(pszDesc);
//
// Validate the params
//
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
return(HrCreateString(STR_SCROLLBAR_DESCRIPTION + varChild.lVal +
(m_fVertical ? 0 : INDEX_SCROLLBAR_HORIZONTAL), pszDesc));
}
// --------------------------------------------------------------------------
//
// CScrollBar::get_accRole()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollBar::get_accRole(VARIANT varChild, VARIANT* pvarRole)
{
InitPvar(pvarRole);
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
pvarRole->vt = VT_I4;
switch (varChild.lVal)
{
case INDEX_SCROLLBAR_SELF:
pvarRole->lVal = ROLE_SYSTEM_SCROLLBAR;
break;
case INDEX_SCROLLBAR_UP:
case INDEX_SCROLLBAR_DOWN:
case INDEX_SCROLLBAR_UPPAGE:
case INDEX_SCROLLBAR_DOWNPAGE:
pvarRole->lVal = ROLE_SYSTEM_PUSHBUTTON;
break;
case INDEX_SCROLLBAR_THUMB:
pvarRole->lVal = ROLE_SYSTEM_INDICATOR;
break;
default:
AssertStr( TEXT("Invalid ChildID for child of scroll bar") );
}
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CScrollBar::get_accState()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollBar::get_accState(VARIANT varChild, VARIANT* pvarState)
{
SCROLLBARINFO sbi;
InitPvar(pvarState);
//
// Validate parameters
//
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
pvarState->vt = VT_I4;
pvarState->lVal = 0;
//
// Get our information
//
if (! MyGetScrollBarInfo(m_hwnd, (m_fVertical ? OBJID_VSCROLL : OBJID_HSCROLL),
&sbi) ||
(sbi.rgstate[INDEX_SCROLLBAR_SELF] & STATE_SYSTEM_INVISIBLE))
{
//
// If scrollbar isn't there period, fail.
//
pvarState->lVal |= STATE_SYSTEM_INVISIBLE;
return(S_OK);
}
//
// If unavailable or offscreen, everything is.
//
FixUpScrollBarInfo(&sbi);
pvarState->lVal |= sbi.rgstate[INDEX_SCROLLBAR_SELF];
pvarState->lVal |= sbi.rgstate[varChild.lVal];
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CScrollBar::get_accDefaultAction()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollBar::get_accDefaultAction(VARIANT varChild,
BSTR * pszDefAction)
{
InitPv(pszDefAction);
//
// Validate the params
//
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
switch (varChild.lVal)
{
case INDEX_SCROLLBAR_UP:
case INDEX_SCROLLBAR_UPPAGE:
case INDEX_SCROLLBAR_DOWNPAGE:
case INDEX_SCROLLBAR_DOWN:
return(HrCreateString(STR_BUTTON_PUSH, pszDefAction));
}
return(E_NOT_APPLICABLE);
}
// --------------------------------------------------------------------------
//
// CScrollBar::accLocation()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollBar::accLocation(long* pxLeft, long* pyTop, long* pcxWidth,
long* pcyHeight, VARIANT varChild)
{
SCROLLBARINFO sbi;
int dxyButton;
InitAccLocation(pxLeft, pyTop, pcxWidth, pcyHeight);
//
// Validate params
//
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
if (! MyGetScrollBarInfo(m_hwnd, (m_fVertical ? OBJID_VSCROLL : OBJID_HSCROLL),
&sbi) ||
(sbi.rgstate[INDEX_TITLEBAR_SELF] & (STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_OFFSCREEN)))
{
return(S_FALSE);
}
FixUpScrollBarInfo(&sbi);
if (sbi.rgstate[varChild.lVal] & (STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_OFFSCREEN))
return(S_FALSE);
if (m_fVertical)
dxyButton = sbi.rcScrollBar.right - sbi.rcScrollBar.left;
else
dxyButton = sbi.rcScrollBar.bottom - sbi.rcScrollBar.top;
switch (varChild.lVal)
{
case INDEX_SCROLLBAR_SELF:
*pxLeft = sbi.rcScrollBar.left;
*pyTop = sbi.rcScrollBar.top;
*pcxWidth = sbi.rcScrollBar.right - sbi.rcScrollBar.left;
*pcyHeight = sbi.rcScrollBar.bottom - sbi.rcScrollBar.top;
break;
case INDEX_SCROLLBAR_UP:
case INDEX_SCROLLBAR_DOWN:
if (m_fVertical)
{
*pxLeft = sbi.rcScrollBar.left;
*pcxWidth = dxyButton;
*pcyHeight = sbi.dxyLineButton;
if (varChild.lVal == INDEX_SCROLLBAR_UP)
*pyTop = sbi.rcScrollBar.top;
else
*pyTop = sbi.rcScrollBar.bottom - *pcyHeight;
}
else
{
*pyTop = sbi.rcScrollBar.top;
*pcyHeight = dxyButton;
*pcxWidth = sbi.dxyLineButton;
if (varChild.lVal == INDEX_SCROLLBAR_UP)
*pxLeft = sbi.rcScrollBar.left;
else
*pxLeft = sbi.rcScrollBar.right - *pcxWidth;
}
break;
case INDEX_SCROLLBAR_UPPAGE:
if (m_fVertical)
{
*pxLeft = sbi.rcScrollBar.left;
*pcxWidth = dxyButton;
*pyTop = sbi.rcScrollBar.top + sbi.dxyLineButton;
*pcyHeight = sbi.xyThumbTop - sbi.dxyLineButton;
}
else
{
*pyTop = sbi.rcScrollBar.top;
*pcyHeight = dxyButton;
*pxLeft = sbi.rcScrollBar.left + sbi.dxyLineButton;
*pcxWidth = sbi.xyThumbTop - sbi.dxyLineButton;
}
break;
case INDEX_SCROLLBAR_DOWNPAGE:
if (m_fVertical)
{
*pxLeft = sbi.rcScrollBar.left;
*pcxWidth = dxyButton;
*pyTop = sbi.rcScrollBar.top + sbi.xyThumbBottom;
*pcyHeight = (sbi.rcScrollBar.bottom - sbi.rcScrollBar.top) -
sbi.xyThumbBottom - sbi.dxyLineButton;
}
else
{
*pyTop = sbi.rcScrollBar.top;
*pcyHeight = dxyButton;
*pxLeft = sbi.rcScrollBar.left + sbi.xyThumbBottom;
*pcxWidth = (sbi.rcScrollBar.right - sbi.rcScrollBar.left) -
sbi.xyThumbBottom - sbi.dxyLineButton;
}
break;
case INDEX_SCROLLBAR_THUMB:
if (m_fVertical)
{
*pxLeft = sbi.rcScrollBar.left;
*pcxWidth = dxyButton;
*pyTop = sbi.rcScrollBar.top + sbi.xyThumbTop;
*pcyHeight = sbi.xyThumbBottom - sbi.xyThumbTop;
}
else
{
*pyTop = sbi.rcScrollBar.top;
*pcyHeight = dxyButton;
*pxLeft = sbi.rcScrollBar.left + sbi.xyThumbTop;
*pcxWidth = sbi.xyThumbBottom - sbi.xyThumbTop;
}
break;
default:
AssertStr( TEXT("Invalid ChildID for child of scroll bar") );
}
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CScrollBar::accNavigate()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollBar::accNavigate(long dwNavDir, VARIANT varStart,
VARIANT * pvarEnd)
{
long lEndUp = 0;
SCROLLBARINFO sbi;
InitPvar(pvarEnd);
//
// Validate params
//
if (! ValidateChild(&varStart) ||
! ValidateNavDir(dwNavDir, varStart.lVal))
return(E_INVALIDARG);
if (! MyGetScrollBarInfo(m_hwnd, (m_fVertical ? OBJID_VSCROLL : OBJID_HSCROLL),
&sbi))
{
return(S_FALSE);
}
if (dwNavDir == NAVDIR_FIRSTCHILD)
{
dwNavDir = NAVDIR_NEXT;
}
else if (dwNavDir == NAVDIR_LASTCHILD)
{
dwNavDir = NAVDIR_PREVIOUS;
varStart.lVal = m_cChildren + 1;
}
else if (varStart.lVal == INDEX_SCROLLBAR_SELF)
return(GetParentToNavigate((m_fVertical ? OBJID_VSCROLL : OBJID_HSCROLL),
m_hwnd, OBJID_WINDOW, dwNavDir, pvarEnd));
FixUpScrollBarInfo(&sbi);
switch (dwNavDir)
{
case NAVDIR_NEXT:
FindNext:
lEndUp = varStart.lVal;
while (++lEndUp <= INDEX_SCROLLBAR_MAC)
{
if (!(sbi.rgstate[lEndUp] & STATE_SYSTEM_INVISIBLE))
break;
}
if (lEndUp > INDEX_SCROLLBAR_MAC)
lEndUp = 0;
break;
case NAVDIR_PREVIOUS:
FindPrevious:
lEndUp = varStart.lVal;
while (--lEndUp >= INDEX_SCROLLBAR_MIC)
{
if (!(sbi.rgstate[lEndUp] & STATE_SYSTEM_INVISIBLE))
break;
}
if (lEndUp < INDEX_SCROLLBAR_MIC)
lEndUp = 0;
break;
case NAVDIR_UP:
lEndUp = 0;
if (m_fVertical)
goto FindPrevious;
break;
case NAVDIR_LEFT:
lEndUp = 0;
if (!m_fVertical)
goto FindPrevious;
break;
case NAVDIR_DOWN:
lEndUp = 0;
if (m_fVertical)
goto FindNext;
break;
case NAVDIR_RIGHT:
lEndUp = 0;
if (!m_fVertical)
goto FindNext;
break;
default:
AssertStr( TEXT("Invalid NavDir") );
}
if (lEndUp != INDEX_SCROLLBAR_SELF)
{
pvarEnd->vt = VT_I4;
pvarEnd->lVal = lEndUp;
return(S_OK);
}
else
return(S_FALSE);
}
// --------------------------------------------------------------------------
//
// CScrollBar::accHitTest()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollBar::accHitTest(long xLeft, long yTop, VARIANT * pvarChild)
{
POINT pt;
SCROLLBARINFO sbi;
int xyPtAxis;
int xyScrollEnd;
long lHit;
InitPvar(pvarChild);
if (! MyGetScrollBarInfo(m_hwnd, (m_fVertical ? OBJID_VSCROLL : OBJID_HSCROLL),
&sbi) ||
(sbi.rgstate[INDEX_SCROLLBAR_SELF] & (STATE_SYSTEM_OFFSCREEN | STATE_SYSTEM_INVISIBLE)))
{
return(S_FALSE);
}
pt.x = xLeft;
pt.y = yTop;
if (! PtInRect(&sbi.rcScrollBar, pt))
return(S_FALSE);
FixUpScrollBarInfo(&sbi);
//
// Convert to scrollbar coords.
//
if (m_fVertical)
{
xyPtAxis = yTop - sbi.rcScrollBar.top;
xyScrollEnd = sbi.rcScrollBar.bottom - sbi.rcScrollBar.top;
}
else
{
xyPtAxis = xLeft - sbi.rcScrollBar.left;
xyScrollEnd = sbi.rcScrollBar.right - sbi.rcScrollBar.left;
}
lHit = INDEX_SCROLLBAR_SELF;
if (xyPtAxis < sbi.dxyLineButton)
{
Assert(!(sbi.rgstate[INDEX_SCROLLBAR_UP] & STATE_SYSTEM_INVISIBLE));
lHit = INDEX_SCROLLBAR_UP;
}
else if (xyPtAxis >= xyScrollEnd - sbi.dxyLineButton)
{
Assert(!(sbi.rgstate[INDEX_SCROLLBAR_DOWN] & STATE_SYSTEM_INVISIBLE));
lHit = INDEX_SCROLLBAR_DOWN;
}
else if (!(sbi.rgstate[INDEX_SCROLLBAR_SELF] & STATE_SYSTEM_UNAVAILABLE))
{
if (xyPtAxis < sbi.xyThumbTop)
{
Assert(!(sbi.rgstate[INDEX_SCROLLBAR_UPPAGE] & STATE_SYSTEM_INVISIBLE));
lHit = INDEX_SCROLLBAR_UPPAGE;
}
else if (xyPtAxis >= sbi.xyThumbBottom)
{
Assert(!(sbi.rgstate[INDEX_SCROLLBAR_DOWNPAGE] & STATE_SYSTEM_INVISIBLE));
lHit = INDEX_SCROLLBAR_DOWNPAGE;
}
else
{
Assert(!(sbi.rgstate[INDEX_SCROLLBAR_THUMB] & STATE_SYSTEM_INVISIBLE));
lHit = INDEX_SCROLLBAR_THUMB;
}
}
pvarChild->vt = VT_I4;
pvarChild->lVal = lHit;
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CScrollBar::accDoDefaultAction()
//
// Only works if the element is visible and available!
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollBar::accDoDefaultAction(VARIANT varChild)
{
WPARAM wpAction;
SCROLLBARINFO sbi;
//
// Validate params
//
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
//
// Is child available and present?
//
if (!MyGetScrollBarInfo(m_hwnd, (m_fVertical ? OBJID_VSCROLL : OBJID_HSCROLL),
&sbi) ||
(sbi.rgstate[INDEX_SCROLLBAR_SELF] & (STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_UNAVAILABLE)))
{
return(S_FALSE);
}
FixUpScrollBarInfo(&sbi);
if (sbi.rgstate[varChild.lVal] & STATE_SYSTEM_UNAVAILABLE)
return(S_FALSE);
switch (varChild.lVal)
{
case INDEX_SCROLLBAR_UP:
wpAction = SB_LINEUP;
break;
case INDEX_SCROLLBAR_UPPAGE:
wpAction = SB_PAGEUP;
break;
case INDEX_SCROLLBAR_DOWNPAGE:
wpAction = SB_PAGEDOWN;
break;
case INDEX_SCROLLBAR_DOWN:
wpAction = SB_LINEDOWN;
break;
default:
return(E_NOT_APPLICABLE);
}
PostMessage(m_hwnd, (m_fVertical ? WM_VSCROLL : WM_HSCROLL),
wpAction, (LPARAM)m_hwnd);
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CScrollBar::put_accValue()
//
// CALLER frees the string
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollBar::put_accValue(VARIANT varChild, BSTR szValue)
{
long lPos;
HRESULT hr;
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
if (varChild.lVal)
return(E_NOT_APPLICABLE);
hr = VarI4FromStr(szValue, 0, 0, &lPos);
if (!SUCCEEDED(hr))
return(hr);
// Verify that we've got a valid percent value
if( lPos < 0 || lPos > 100 )
return E_INVALIDARG;
int Min, Max;
GetScrollRange( m_hwnd, SB_CTL, & Min, & Max );
// work out value from percentage...
lPos = Min + ( ( Max - Min ) * lPos ) / 100;
SetScrollPos(m_hwnd, (m_fVertical ? SB_VERT : SB_HORZ), lPos, TRUE);
return(S_OK);
}
STDMETHODIMP CScrollBar::GetIdentityString (
DWORD dwIDChild,
BYTE ** ppIDString,
DWORD * pdwIDStringLen
)
{
// Unlike the other HWND-based proxies, this one has two associated
// objids - OBJID_VSCROLL or OBJID_HSCROLL, dpending on whether it represents
// the horizontal or vertival non-client scrollbar.
// Because of this, the default implementation of GetIdentityString in
// the CAccessible base class can't handle this for us, since it can't
// determin that this is a CScrollBar nor check what our m_fVertical flag is.
//
// Instead, we override GetIdentityString, and implement it here where we
// have the information we need.
// TODO - should probably verify that idChild is valid.
// (we can do this for some classes - eg. where the number of children is
// fixed and known - but it may not be preactical to do it in general.)
*ppIDString = NULL;
*pdwIDStringLen = 0;
BYTE * pKeyData = (BYTE *) CoTaskMemAlloc( HWNDKEYSIZE );
if( ! pKeyData )
{
return E_OUTOFMEMORY;
}
DWORD idObject = m_fVertical ? OBJID_VSCROLL : OBJID_HSCROLL;
MakeHwndKey( pKeyData, m_hwnd, idObject, dwIDChild );
*ppIDString = pKeyData;
*pdwIDStringLen = HWNDKEYSIZE;
return S_OK;
}
/////////////////////////////////////////////////////////////////////////////
//
// GRIP
//
/////////////////////////////////////////////////////////////////////////////
// --------------------------------------------------------------------------
//
// CreateSizeGripObject()
//
// EXTERNAL
//
// --------------------------------------------------------------------------
HRESULT CreateSizeGripObject(HWND hwnd, long idObject, REFIID riid, void** ppvGrip)
{
return(CreateSizeGripThing(hwnd, idObject, riid, ppvGrip));
}
// --------------------------------------------------------------------------
//
// CreateSizeGripThing()
//
// INTERNAL
//
// --------------------------------------------------------------------------
HRESULT CreateSizeGripThing(HWND hwnd, long idObject, REFIID riid, void** ppvGrip)
{
CSizeGrip * psizegrip;
HRESULT hr;
UNUSED(idObject);
InitPv(ppvGrip);
psizegrip = new CSizeGrip();
if (psizegrip)
{
if (! psizegrip->FInitialize(hwnd))
{
delete psizegrip;
return(E_FAIL);
}
}
else
return(E_OUTOFMEMORY);
hr = psizegrip->QueryInterface(riid, ppvGrip);
if (!SUCCEEDED(hr))
delete psizegrip;
return(hr);
}
// --------------------------------------------------------------------------
//
// CSizeGrip::FInitialize()
//
// --------------------------------------------------------------------------
BOOL CSizeGrip::FInitialize(HWND hwnd)
{
m_hwnd = hwnd;
return(IsWindow(hwnd));
}
// --------------------------------------------------------------------------
//
// CSizeGrip::IsActive()
//
// Returns TRUE if the size grip can actually be used to size a window.
// Sometimes size grips are present, but do not allow sizing - eg.
// present on a control because horiz+vert scrollbars are present, but the
// control is fixed in a dialog.
//
// See ntuser\rtl\winmgr.c:SizeBoxHwnd() for the corresponding USER code
// that does this.
//
// --------------------------------------------------------------------------
BOOL CSizeGrip::IsActive()
{
// sizable if:
// size grip is present...
WINDOWINFO wi;
if( ! MyGetWindowInfo( m_hwnd, & wi )
|| ! ( wi.dwStyle & WS_VSCROLL )
|| ! ( wi.dwStyle & WS_HSCROLL ) )
{
return FALSE;
}
// Find first ancestor or self that is sizable and non-maximized...
HWND hwndSizable = m_hwnd;
HWND hwndDesktop = GetDesktopWindow();
for( ; ; )
{
DWORD dwStyle = GetWindowLong( hwndSizable, GWL_STYLE );
if( dwStyle & WS_THICKFRAME )
{
// Got it!
break;
}
// try next level up...
hwndSizable = MyGetAncestor( hwndSizable, GA_PARENT );
if( ! hwndSizable || hwndSizable == hwndDesktop )
{
// Didn't find any sizable ancestors - so not active.
return FALSE;
}
}
// We should really do this check along with checking the THICKFRAME
// abive - ie. "find the first sizable and non-zoomed window"; instead of
// this which is "find the first sizable window, and then check that it
// is non-zoomed".
// This version is consistent with USER's behavior, which disallows a
// maximized MDI child from sizing its parent.
if( IsZoomed( hwndSizable ) )
{
return FALSE;
}
// If the window we're sizing is different than this window, then check
// that the size grip is within SM_C[X|Y]EDGE of the sizable window...
if( hwndSizable != m_hwnd )
{
// sizable window's scrollbars must NOT be showing...
if( ! MyGetWindowInfo( hwndSizable, & wi )
|| ( wi.dwStyle & WS_VSCROLL )
|| ( wi.dwStyle & WS_HSCROLL ) )
{
return FALSE;
}
// check if bottom-right aligns with top-level window...
RECT rcInner;
GetWindowRect( m_hwnd, & rcInner );
RECT rcTopLevel;
GetClientRect( hwndSizable, & rcTopLevel );
MapWindowPoints( NULL, hwndSizable, (POINT *) & rcInner, 2 );
if( rcInner.right < rcTopLevel.right - GetSystemMetrics( SM_CXEDGE )
|| rcInner.bottom < rcTopLevel.bottom - GetSystemMetrics( SM_CYEDGE ) )
{
return FALSE;
}
}
return TRUE;
}
// --------------------------------------------------------------------------
//
// CSizeGrip::get_accName()
//
// --------------------------------------------------------------------------
STDMETHODIMP CSizeGrip::get_accName(VARIANT varChild, BSTR * pszName)
{
InitPv(pszName);
//
// Validate parameters
//
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
if( IsActive() )
{
return HrCreateString( STR_SCROLLBAR_NAME + INDEX_SCROLLBAR_GRIP, pszName );
}
else
{
return S_FALSE;
}
}
// --------------------------------------------------------------------------
//
// CSizeGrip::get_accDescription()
//
// --------------------------------------------------------------------------
STDMETHODIMP CSizeGrip::get_accDescription(VARIANT varChild, BSTR * pszDesc)
{
InitPv(pszDesc);
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
if( IsActive() )
{
return HrCreateString( STR_SCROLLBAR_DESCRIPTION + INDEX_SCROLLBAR_GRIP, pszDesc );
}
else
{
return S_FALSE;
}
}
// --------------------------------------------------------------------------
//
// CSizeGrip::get_accRole()
//
// --------------------------------------------------------------------------
STDMETHODIMP CSizeGrip::get_accRole(VARIANT varChild, VARIANT * pvarRole)
{
InitPvar(pvarRole);
//
// Validate parameters
//
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
pvarRole->vt = VT_I4;
pvarRole->lVal = ROLE_SYSTEM_GRIP;
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CSizeGrip::get_accState()
//
// --------------------------------------------------------------------------
STDMETHODIMP CSizeGrip::get_accState(VARIANT varChild, VARIANT * pvarState)
{
WINDOWINFO wi;
InitPvar(pvarState);
//
// Validate parameters
//
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
pvarState->vt = VT_I4;
pvarState->lVal = 0;
//
// We are only visible if both scrollbars are present.
//
if (! MyGetWindowInfo(m_hwnd, &wi) ||
!(wi.dwStyle & WS_VSCROLL) ||
!(wi.dwStyle & WS_HSCROLL))
{
pvarState->lVal |= STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_UNAVAILABLE;
}
else if( ! IsActive() )
{
pvarState->lVal |= STATE_SYSTEM_UNAVAILABLE;
}
return S_OK;
}
// --------------------------------------------------------------------------
//
// CSizeGrip::accLocation()
//
// --------------------------------------------------------------------------
STDMETHODIMP CSizeGrip::accLocation(long* pxLeft, long* pyTop, long* pcxWidth,
long* pcyHeight, VARIANT varChild)
{
WINDOWINFO wi;
InitAccLocation(pxLeft, pyTop, pcxWidth, pcyHeight);
//
// Validate parameters
//
if (! ValidateChild(&varChild))
return(E_INVALIDARG);
if (MyGetWindowInfo(m_hwnd, &wi) &&
(wi.dwStyle & WS_VSCROLL) &&
(wi.dwStyle & WS_HSCROLL))
{
*pxLeft = wi.rcClient.right;
*pyTop = wi.rcClient.bottom;
*pcxWidth = GetSystemMetrics(SM_CXVSCROLL);
*pcyHeight = GetSystemMetrics(SM_CYHSCROLL);
}
else
return(S_FALSE);
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CSizeGrip::accHitTest()
//
// --------------------------------------------------------------------------
STDMETHODIMP CSizeGrip::accHitTest(long xLeft, long yTop, VARIANT * pvarChild)
{
WINDOWINFO wi;
InitPvar(pvarChild);
if (MyGetWindowInfo(m_hwnd, &wi) &&
(wi.dwStyle & WS_VSCROLL) &&
(wi.dwStyle & WS_HSCROLL))
{
if ((xLeft >= wi.rcClient.right) &&
(xLeft < wi.rcClient.right + GetSystemMetrics(SM_CXVSCROLL)) &&
(yTop >= wi.rcClient.bottom) &&
(yTop < wi.rcClient.bottom + GetSystemMetrics(SM_CYHSCROLL)))
{
pvarChild->vt = VT_I4;
pvarChild->lVal = CHILDID_SELF;
return(S_OK);
}
}
return(S_FALSE);
}
// --------------------------------------------------------------------------
//
// CSizeGrip::accNavigate()
//
// --------------------------------------------------------------------------
STDMETHODIMP CSizeGrip::accNavigate(long dwNavFlags, VARIANT varStart,
VARIANT * pvarEnd)
{
InitPvar(pvarEnd);
//
// Validate parameters
//
if (! ValidateChild(&varStart) ||
! ValidateNavDir(dwNavFlags, varStart.lVal))
return(E_INVALIDARG);
if (dwNavFlags >= NAVDIR_FIRSTCHILD)
return(S_FALSE);
//
// Navigation among peers only
//
return(GetParentToNavigate(OBJID_SIZEGRIP, m_hwnd, OBJID_WINDOW,
dwNavFlags, pvarEnd));
}
// --------------------------------------------------------------------------
//
// CSizeGrip::Clone()
//
// --------------------------------------------------------------------------
STDMETHODIMP CSizeGrip::Clone(IEnumVARIANT** ppenum)
{
return(CreateSizeGripThing(m_hwnd, OBJID_SIZEGRIP, IID_IEnumVARIANT, (void**)ppenum));
}
/////////////////////////////////////////////////////////////////////////////
//
// SCROLL CONTROL (Can be bar or grip)
//
/////////////////////////////////////////////////////////////////////////////
// --------------------------------------------------------------------------
//
// CreateScrollBarClient()
//
// Called from CClient creation
//
// --------------------------------------------------------------------------
HRESULT CreateScrollBarClient(HWND hwnd, long idChildCur, REFIID riid,
void** ppvScroll)
{
CScrollCtl * pscroll;
HRESULT hr;
InitPv(ppvScroll);
pscroll = new CScrollCtl(hwnd, idChildCur);
if (!pscroll)
return(E_OUTOFMEMORY);
hr = pscroll->QueryInterface(riid, ppvScroll);
if (!SUCCEEDED(hr))
delete pscroll;
return(hr);
}
// --------------------------------------------------------------------------
//
// CScrollCtl::CScrollCtl
//
// --------------------------------------------------------------------------
CScrollCtl::CScrollCtl(HWND hwnd, long idChildCur)
: CClient( CLASS_ScrollBarClient )
{
long lStyle;
Initialize(hwnd, idChildCur);
lStyle = GetWindowLong(hwnd, GWL_STYLE);
if (lStyle & (SBS_SIZEBOX| SBS_SIZEGRIP))
{
m_fGrip = TRUE;
m_cChildren = 0;
}
else
{
m_fUseLabel = TRUE;
m_cChildren = CCHILDREN_SCROLLBAR;
if (lStyle & SBS_VERT)
m_fVertical = TRUE;
}
}
// --------------------------------------------------------------------------
//
// CScrollCtl::get_accName()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollCtl::get_accName(VARIANT varChild, BSTR* pszName)
{
InitPv(pszName);
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (!varChild.lVal)
return(CClient::get_accName(varChild, pszName));
Assert(!m_fGrip);
return(HrCreateString(STR_SCROLLBAR_NAME + varChild.lVal +
(m_fVertical ? 0 : INDEX_SCROLLBAR_HORIZONTAL), pszName));
}
// --------------------------------------------------------------------------
//
// CScrollCtl::get_accValue()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollCtl::get_accValue(VARIANT varChild, BSTR* pszValue)
{
long lPos;
InitPv(pszValue);
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (varChild.lVal || m_fGrip)
return(E_NOT_APPLICABLE);
lPos = GetScrollPos(m_hwnd, SB_CTL);
int Min, Max;
GetScrollRange( m_hwnd, SB_CTL, & Min, & Max );
// work out a percent value...
if( Min != Max )
lPos = ( ( lPos - Min ) * 100 ) / ( Max - Min );
else
lPos = 0; // Prevent div-by-0
return(VarBstrFromI4(lPos, 0, 0, pszValue));
}
// --------------------------------------------------------------------------
//
// CScrollCtl::get_accDescription()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollCtl::get_accDescription(VARIANT varChild, BSTR* pszDesc)
{
InitPv(pszDesc);
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (!varChild.lVal)
return(CClient::get_accDescription(varChild, pszDesc));
Assert(!m_fGrip);
return(HrCreateString(STR_SCROLLBAR_DESCRIPTION + varChild.lVal +
(m_fVertical ? 0 : INDEX_SCROLLBAR_HORIZONTAL), pszDesc));
}
// --------------------------------------------------------------------------
//
// CScrollCtl::get_accRole()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollCtl::get_accRole(VARIANT varChild, VARIANT* pvarRole)
{
InitPvar(pvarRole);
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
pvarRole->vt = VT_I4;
switch (varChild.lVal)
{
case 0:
if (m_fGrip)
pvarRole->lVal = ROLE_SYSTEM_GRIP;
else
pvarRole->lVal = ROLE_SYSTEM_SCROLLBAR;
break;
case INDEX_SCROLLBAR_UP:
case INDEX_SCROLLBAR_DOWN:
case INDEX_SCROLLBAR_UPPAGE:
case INDEX_SCROLLBAR_DOWNPAGE:
pvarRole->lVal = ROLE_SYSTEM_PUSHBUTTON;
break;
case INDEX_SCROLLBAR_THUMB:
pvarRole->lVal = ROLE_SYSTEM_INDICATOR;
break;
default:
AssertStr( TEXT("Invalid ChildID for child of scroll bar") );
}
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CScrollCtl::get_accState()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollCtl::get_accState(VARIANT varChild, VARIANT* pvarState)
{
SCROLLBARINFO sbi;
InitPvar(pvarState);
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (!varChild.lVal)
return(CClient::get_accState(varChild, pvarState));
Assert(!m_fGrip);
pvarState->vt = VT_I4;
pvarState->lVal = 0;
if (!MyGetScrollBarInfo(m_hwnd, OBJID_CLIENT, &sbi))
{
pvarState->lVal |= STATE_SYSTEM_INVISIBLE;
return(S_OK);
}
FixUpScrollBarInfo(&sbi);
pvarState->lVal |= sbi.rgstate[INDEX_SCROLLBAR_SELF];
pvarState->lVal |= sbi.rgstate[varChild.lVal];
if ((varChild.lVal == INDEX_SCROLLBAR_THUMB) && (MyGetFocus() == m_hwnd))
pvarState->lVal |= STATE_SYSTEM_FOCUSED;
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CScrollCtl::get_accDefaultAction()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollCtl::get_accDefaultAction(VARIANT varChild, BSTR* pszDefA)
{
InitPv(pszDefA);
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
switch (varChild.lVal)
{
case INDEX_SCROLLBAR_UP:
case INDEX_SCROLLBAR_UPPAGE:
case INDEX_SCROLLBAR_DOWNPAGE:
case INDEX_SCROLLBAR_DOWN:
return(HrCreateString(STR_BUTTON_PUSH, pszDefA));
}
return(E_NOT_APPLICABLE);
}
// --------------------------------------------------------------------------
//
// CScrollCtl::accLocation()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollCtl::accLocation(long* pxLeft, long* pyTop, long* pcxWidth,
long* pcyHeight, VARIANT varChild)
{
SCROLLBARINFO sbi;
int dxyButton;
InitAccLocation(pxLeft, pyTop, pcxWidth, pcyHeight);
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (!varChild.lVal)
return(CClient::accLocation(pxLeft, pyTop, pcxWidth, pcyHeight, varChild));
Assert(!m_fGrip);
if (!MyGetScrollBarInfo(m_hwnd, OBJID_CLIENT, &sbi))
return(S_FALSE);
FixUpScrollBarInfo(&sbi);
if (sbi.rgstate[varChild.lVal] & (STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_OFFSCREEN))
return(S_FALSE);
if (m_fVertical)
dxyButton = sbi.rcScrollBar.right - sbi.rcScrollBar.left;
else
dxyButton = sbi.rcScrollBar.bottom - sbi.rcScrollBar.top;
switch (varChild.lVal)
{
case INDEX_SCROLLBAR_UP:
case INDEX_SCROLLBAR_DOWN:
if (m_fVertical)
{
*pxLeft = sbi.rcScrollBar.left;
*pcxWidth = dxyButton;
*pcyHeight = sbi.dxyLineButton;
if (varChild.lVal == INDEX_SCROLLBAR_UP)
*pyTop = sbi.rcScrollBar.top;
else
*pyTop = sbi.rcScrollBar.bottom - *pcyHeight;
}
else
{
*pyTop = sbi.rcScrollBar.top;
*pcyHeight = dxyButton;
*pcxWidth = sbi.dxyLineButton;
if (varChild.lVal == INDEX_SCROLLBAR_UP)
*pxLeft = sbi.rcScrollBar.left;
else
*pxLeft = sbi.rcScrollBar.right - *pcxWidth;
}
break;
case INDEX_SCROLLBAR_UPPAGE:
if (m_fVertical)
{
*pxLeft = sbi.rcScrollBar.left;
*pcxWidth = dxyButton;
*pyTop = sbi.rcScrollBar.top + sbi.dxyLineButton;
*pcyHeight = sbi.xyThumbTop - sbi.dxyLineButton;
}
else
{
*pyTop = sbi.rcScrollBar.top;
*pcyHeight = dxyButton;
*pxLeft = sbi.rcScrollBar.left + sbi.dxyLineButton;
*pcxWidth = sbi.xyThumbTop - sbi.dxyLineButton;
}
break;
case INDEX_SCROLLBAR_DOWNPAGE:
if (m_fVertical)
{
*pxLeft = sbi.rcScrollBar.left;
*pcxWidth = dxyButton;
*pyTop = sbi.rcScrollBar.top + sbi.xyThumbBottom;
*pcyHeight = (sbi.rcScrollBar.bottom - sbi.rcScrollBar.top) -
sbi.xyThumbBottom - sbi.dxyLineButton;
}
else
{
*pyTop = sbi.rcScrollBar.top;
*pcyHeight = dxyButton;
*pxLeft = sbi.rcScrollBar.left + sbi.xyThumbBottom;
*pcxWidth = (sbi.rcScrollBar.right - sbi.rcScrollBar.left) -
sbi.xyThumbBottom - sbi.dxyLineButton;
}
break;
case INDEX_SCROLLBAR_THUMB:
if (m_fVertical)
{
*pxLeft = sbi.rcScrollBar.left;
*pcxWidth = dxyButton;
*pyTop = sbi.rcScrollBar.top + sbi.xyThumbTop;
*pcyHeight = sbi.xyThumbBottom - sbi.xyThumbTop;
}
else
{
*pyTop = sbi.rcScrollBar.top;
*pcyHeight = dxyButton;
*pxLeft = sbi.rcScrollBar.left + sbi.xyThumbTop;
*pcxWidth = sbi.xyThumbBottom - sbi.xyThumbTop;
}
break;
default:
AssertStr( TEXT("Invalid ChildID for child of scroll bar") );
}
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CScrollCtl::accNavigate()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollCtl::accNavigate(long dwNavDir, VARIANT varStart, VARIANT* pvarEnd)
{
long lEndUp = 0;
SCROLLBARINFO sbi;
InitPvar(pvarEnd);
if (!ValidateChild(&varStart) || !ValidateNavDir(dwNavDir, varStart.lVal))
return(E_INVALIDARG);
if (!varStart.lVal)
{
if (dwNavDir < NAVDIR_FIRSTCHILD)
return(CClient::accNavigate(dwNavDir, varStart, pvarEnd));
if (!m_fGrip)
return(S_FALSE);
if (dwNavDir == NAVDIR_FIRSTCHILD)
dwNavDir = NAVDIR_NEXT;
else
{
dwNavDir = NAVDIR_PREVIOUS;
varStart.lVal = m_cChildren + 1;
}
}
Assert(!m_fGrip);
if (!MyGetScrollBarInfo(m_hwnd, OBJID_CLIENT, &sbi))
return(S_FALSE);
FixUpScrollBarInfo(&sbi);
switch (dwNavDir)
{
case NAVDIR_NEXT:
FindNext:
lEndUp = varStart.lVal;
while (++lEndUp <= INDEX_SCROLLBAR_MAC)
{
if (!(sbi.rgstate[lEndUp] & STATE_SYSTEM_INVISIBLE))
break;
}
if (lEndUp > INDEX_SCROLLBAR_MAC)
lEndUp = 0;
break;
case NAVDIR_PREVIOUS:
FindPrevious:
lEndUp = varStart.lVal;
while (--lEndUp >= INDEX_SCROLLBAR_MIC)
{
if (!(sbi.rgstate[lEndUp] & STATE_SYSTEM_INVISIBLE))
break;
}
if (lEndUp < INDEX_SCROLLBAR_MIC)
lEndUp = 0;
break;
case NAVDIR_UP:
lEndUp = 0;
if (m_fVertical)
goto FindPrevious;
break;
case NAVDIR_LEFT:
lEndUp = 0;
if (!m_fVertical)
goto FindPrevious;
break;
case NAVDIR_DOWN:
lEndUp = 0;
if (m_fVertical)
goto FindNext;
break;
case NAVDIR_RIGHT:
lEndUp = 0;
if (!m_fVertical)
goto FindNext;
break;
default:
AssertStr( TEXT("Invalid NavDir") );
}
if (lEndUp != INDEX_SCROLLBAR_SELF)
{
pvarEnd->vt = VT_I4;
pvarEnd->lVal = lEndUp;
return(S_OK);
}
else
return(S_FALSE);
}
// --------------------------------------------------------------------------
//
// CScrollCtl::accHitTest()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollCtl::accHitTest(long xLeft, long yTop, VARIANT* pvarHit)
{
HRESULT hr;
SCROLLBARINFO sbi;
int xyPtAxis;
int xyScrollEnd;
//
// Is this in our client area at all?
//
hr = CClient::accHitTest(xLeft, yTop, pvarHit);
// #11150, CWO, 1/27/97, Replaced !SUCCEEDED with !S_OK
if ((hr != S_OK) || (pvarHit->vt != VT_I4) || (pvarHit->lVal != 0) || m_fGrip)
return(hr);
//
// We only get here if this is a scrollbar control (not a grip)
//
if (!MyGetScrollBarInfo(m_hwnd, OBJID_CLIENT, &sbi))
return(S_OK);
FixUpScrollBarInfo(&sbi);
//
// Convert to scrollbar coords.
//
if (m_fVertical)
{
xyPtAxis = yTop - sbi.rcScrollBar.top;
xyScrollEnd = sbi.rcScrollBar.bottom - sbi.rcScrollBar.top;
}
else
{
xyPtAxis = xLeft - sbi.rcScrollBar.left;
xyScrollEnd = sbi.rcScrollBar.right - sbi.rcScrollBar.left;
}
if (xyPtAxis < sbi.dxyLineButton)
{
Assert(!(sbi.rgstate[INDEX_SCROLLBAR_UP] & STATE_SYSTEM_INVISIBLE));
pvarHit->lVal = INDEX_SCROLLBAR_UP;
}
else if (xyPtAxis >= xyScrollEnd - sbi.dxyLineButton)
{
Assert(!(sbi.rgstate[INDEX_SCROLLBAR_DOWN] & STATE_SYSTEM_INVISIBLE));
pvarHit->lVal = INDEX_SCROLLBAR_DOWN;
}
else if (!(sbi.rgstate[INDEX_SCROLLBAR_SELF] & STATE_SYSTEM_UNAVAILABLE))
{
if (xyPtAxis < sbi.xyThumbTop)
{
Assert(!(sbi.rgstate[INDEX_SCROLLBAR_UPPAGE] & STATE_SYSTEM_INVISIBLE));
pvarHit->lVal = INDEX_SCROLLBAR_UPPAGE;
}
else if (xyPtAxis >= sbi.xyThumbBottom)
{
Assert(!(sbi.rgstate[INDEX_SCROLLBAR_DOWNPAGE] & STATE_SYSTEM_INVISIBLE));
pvarHit->lVal = INDEX_SCROLLBAR_DOWNPAGE;
}
else
{
Assert(!(sbi.rgstate[INDEX_SCROLLBAR_THUMB] & STATE_SYSTEM_INVISIBLE));
pvarHit->lVal = INDEX_SCROLLBAR_THUMB;
}
}
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CScrollCtl::accDoDefaultAction()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollCtl::accDoDefaultAction(VARIANT varChild)
{
WPARAM wpAction = 0;
SCROLLBARINFO sbi;
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (!varChild.lVal || (varChild.lVal == INDEX_SCROLLBAR_THUMB))
return(E_NOT_APPLICABLE);
Assert(!m_fGrip);
if (!MyGetScrollBarInfo(m_hwnd, OBJID_CLIENT, &sbi) ||
(sbi.rgstate[INDEX_SCROLLBAR_SELF] & (STATE_SYSTEM_INVISIBLE | STATE_SYSTEM_UNAVAILABLE)))
{
return(S_FALSE);
}
FixUpScrollBarInfo(&sbi);
if (sbi.rgstate[varChild.lVal] & STATE_SYSTEM_UNAVAILABLE)
return(S_FALSE);
switch (varChild.lVal)
{
case INDEX_SCROLLBAR_UP:
wpAction = SB_LINEUP;
break;
case INDEX_SCROLLBAR_UPPAGE:
wpAction = SB_PAGEUP;
break;
case INDEX_SCROLLBAR_DOWNPAGE:
wpAction = SB_PAGEDOWN;
break;
case INDEX_SCROLLBAR_DOWN:
wpAction = SB_LINEDOWN;
break;
default:
AssertStr( TEXT("Invalid ChildID for child of scroll bar") );
}
SendMessage(GetParent(m_hwnd), (m_fVertical ? WM_VSCROLL : WM_HSCROLL),
wpAction, (LPARAM)m_hwnd);
return(S_OK);
}
// --------------------------------------------------------------------------
//
// CScrollCtl::put_accValue()
//
// --------------------------------------------------------------------------
STDMETHODIMP CScrollCtl::put_accValue(VARIANT varChild, BSTR szValue)
{
long lPos;
HRESULT hr;
if (!ValidateChild(&varChild))
return(E_INVALIDARG);
if (varChild.lVal || m_fGrip)
return(E_NOT_APPLICABLE);
hr = VarI4FromStr(szValue, 0, 0, &lPos);
if (!SUCCEEDED(hr))
return(hr);
// Verify that we've got a valid percent value
if( lPos < 0 || lPos > 100 )
return E_INVALIDARG;
int Min, Max;
GetScrollRange( m_hwnd, SB_CTL, & Min, & Max );
// work out value from percentage...
lPos = Min + ( ( Max - Min ) * lPos ) / 100;
SetScrollPos(m_hwnd, SB_CTL, lPos, TRUE);
return(S_OK);
}