openDecal/Native/DecalControls/Scroller.cpp
erik d1442e3747 Initial commit: Complete open-source Decal rebuild
All 5 phases of the open-source Decal rebuild:

Phase 1: 14 decompiled .NET projects (Interop.*, Adapter, FileService, DecalUtil)
Phase 2: 10 native DLLs rewritten as C# COM servers with matching GUIDs
  - DecalDat, DHS, SpellFilter, DecalInput, DecalNet, DecalFilters
  - Decal.Core, DecalControls, DecalRender, D3DService
Phase 3: C++ shims for Inject.DLL (D3D9 hooking) and LauncherHook.DLL
Phase 4: DenAgent WinForms tray application
Phase 5: WiX installer and build script

25 C# projects building with 0 errors.
Native C++ projects require VS 2022 + Windows SDK (x86).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 18:27:56 +01:00

863 lines
22 KiB
C++

// Scroller.cpp : Implementation of cScroller
#include "stdafx.h"
#include "DecalControls.h"
#include "Scroller.h"
enum eScrollChildren
{
eScrollerUp = 1,
eScrollerDown = 2,
eScrollerRight = 3,
eScrollerLeft = 4,
eScrollerPager = 5,
eScrollerPageUp = 6,
eScrollerPageDown = 7,
eScrollerPageLeft = 8,
eScrollerPageRight = 9,
eScrollerClient = 10,
eScrollerHThumb = 11,
eScrollerVThumb = 12
};
/////////////////////////////////////////////////////////////////////////////
// cScroller
void cScroller::onCreate()
{
// Initialize our layout options
m_szArea.cx = 0;
m_szArea.cy = 0;
m_szIncrement.cx = 100;
m_szIncrement.cy = 20;
m_ptThumb.x = 0;
m_ptThumb.y = 0;
m_bHScroll = VARIANT_FALSE;
m_bVScroll = VARIANT_FALSE;
CComPtr< ILayer > pLayerPager;
HRESULT hRes = ::CoCreateInstance( __uuidof( Pager ), NULL, CLSCTX_INPROC_SERVER, __uuidof( ILayer ),
reinterpret_cast< void ** >( &pLayerPager ) );
_ASSERTE( SUCCEEDED( hRes ) );
LayerParams p = { eScrollerPager, { 0, 0, 0, 0 }, eRenderClipped };
m_pSite->CreateChild( &p, pLayerPager );
pLayerPager->QueryInterface( &m_pPager );
IPagerEventsImpl< PAGER_CLIENT, cScroller >::advise( m_pPager );
CComPtr< ILayer > pLayerUp;
hRes = ::CoCreateInstance( __uuidof( Button ), NULL, CLSCTX_INPROC_SERVER, __uuidof( ILayer ),
reinterpret_cast< void ** >( &pLayerUp ) );
_ASSERTE( SUCCEEDED( hRes ) );
p.ID = eScrollerUp;
CComPtr< IButton > pUp;
m_pSite->CreateChild( &p, pLayerUp );
pLayerUp->QueryInterface( &pUp);
ICommandEventsImpl< BUTTON_UP, cScroller >::advise( pUp );
pUp->SetImages( 0, 0x06001261, 0x06001262 );
pUp->put_Matte( RGB( 0, 0, 0 ) );
CComPtr< ILayer > pLayerDown;
hRes = ::CoCreateInstance( __uuidof( Button ), NULL, CLSCTX_INPROC_SERVER, __uuidof( ILayer ),
reinterpret_cast< void ** >( &pLayerDown ) );
_ASSERTE( SUCCEEDED( hRes ) );
p.ID = eScrollerDown;
CComPtr< IButton > pDown;
m_pSite->CreateChild( &p, pLayerDown );
pLayerDown->QueryInterface( &pDown );
ICommandEventsImpl< BUTTON_DOWN, cScroller >::advise( pDown );
pDown->SetImages( 0, 0x0600125E, 0x0600125F );
pDown->put_Matte( RGB( 0, 0, 0 ) );
CComPtr< ILayer > pLayerLeft;
hRes = ::CoCreateInstance( __uuidof( Button ), NULL, CLSCTX_INPROC_SERVER, __uuidof( ILayer ),
reinterpret_cast< void ** >( &pLayerLeft ) );
_ASSERTE( SUCCEEDED( hRes ) );
p.ID = eScrollerLeft;
CComPtr< IButton > pLeft;
m_pSite->CreateChild( &p, pLayerLeft );
pLayerLeft->QueryInterface( &pLeft );
ICommandEventsImpl< BUTTON_LEFT, cScroller >::advise( pLeft );
pLeft->SetImages( 0, 0x06001295, 0x06001296 );
pLeft->put_Matte( RGB( 0, 0, 0 ) );
CComPtr< ILayer > pLayerRight;
hRes = ::CoCreateInstance( __uuidof( Button ), NULL, CLSCTX_INPROC_SERVER, __uuidof( ILayer ),
reinterpret_cast< void ** >( &pLayerRight ) );
_ASSERTE( SUCCEEDED( hRes ) );
p.ID = eScrollerRight;
CComPtr< IButton > pRight;
m_pSite->CreateChild( &p, pLayerRight );
pLayerRight->QueryInterface( &pRight );
ICommandEventsImpl< BUTTON_RIGHT, cScroller >::advise( pRight );
pRight->SetImages( 0, 0x06001298, 0x06001299 );
pRight->put_Matte( RGB( 0, 0, 0 ) );
// Positioning will occur during Reformat
// Load the images
CComPtr< IPluginSite > pPlugin;
m_pSite->get_PluginSite( &pPlugin );
pPlugin->LoadBitmapPortal( 0x06001260, &m_pVScrollBack );
pPlugin->LoadBitmapPortal( 0x06001297, &m_pHScrollBack );
}
void cScroller::onDestroy()
{
m_pPager.Release();
}
void cScroller::constrainOffset( LPPOINT ppt )
{
// First check for overflow, furthest scroll should be allowed is less a
// page size
POINT ptMax = { m_szArea.cx, m_szArea.cy };
SIZE szViewport;
get_Viewport( &szViewport );
if((szViewport.cx % m_szIncrement.cx)==0)
ptMax.x -= szViewport.cx;
else
ptMax.x -= ( szViewport.cx / m_szIncrement.cx + 1) * m_szIncrement.cx;
if((szViewport.cy % m_szIncrement.cy)==0)
ptMax.y -= szViewport.cy;
else
ptMax.y -= ( szViewport.cy / m_szIncrement.cy + 1) * m_szIncrement.cy;
// substract the viewport (rounded up a notch) from the max scroll area
// ptMax.x -= ( szViewport.cx / m_szIncrement.cx + 1) * m_szIncrement.cx;
// ptMax.y -= ( szViewport.cy / m_szIncrement.cy + 1) * m_szIncrement.cy;
if( ppt->x > ptMax.x )
ppt->x = ptMax.x;
if( ppt->y > ptMax.y )
ppt->y = ptMax.y;
// Check for underflow (either because it was assigned too low
// or or max is too low)
if( ppt->x < 0 )
ppt->x = 0;
if( ppt->y < 0 )
ppt->y = 0;
}
#define BTN_SIZE 16
long cScroller::hitTest( MouseState *pMS )
{
if( pMS->over != this )
return -1;
SIZE szViewport;
get_Viewport( &szViewport );
RECT rcScroll = { BTN_SIZE, BTN_SIZE, szViewport.cx - BTN_SIZE, szViewport.cy - BTN_SIZE };
// Check if it's on the horizontal bar
if( m_bHScroll )
{
if( pMS->client.x > rcScroll.left && pMS->client.x < rcScroll.right && pMS->client.y > szViewport.cy )
{
if( m_szArea.cx == szViewport.cx )
// Special case, no scrolling if the area is the minimum size
return -1;
// We hit the horizontal bar
if( pMS->client.x < ( m_ptThumb.x + BTN_SIZE ) )
// Hit before the thumb
return eScrollerPageLeft;
else if( pMS->client.x > ( m_ptThumb.x + BTN_SIZE * 2 ) )
// Hit after the thumb
return eScrollerPageRight;
// Hit the thumb
return eScrollerHThumb;
}
}
// Check if it's on the vertical bar
if( m_bVScroll )
{
if( pMS->client.y > rcScroll.top && pMS->client.y < rcScroll.bottom && pMS->client.x > szViewport.cx )
{
if( m_szArea.cy == szViewport.cy )
// Special case, no scrolling if the area is the minimum size
return -1;
// We hit the vertical bar
if( pMS->client.y < ( m_ptThumb.y + BTN_SIZE ) )
// Hit above the thumb
return eScrollerPageUp;
else if( pMS->client.y > ( m_ptThumb.y + BTN_SIZE * 2 ) )
// Hit below thumb
return eScrollerPageDown;
// Hit the v thumb
return eScrollerVThumb;
}
}
return -1;
}
STDMETHODIMP cScroller::Render(ICanvas *pCanvas)
{
SIZE szViewport;
get_Viewport( &szViewport );
// Fill in the scrollbars as neccessary
static POINT ptOff = { 0, 0 };
CComPtr< IPluginSite > pPluginSite;
m_pSite->get_PluginSite( &pPluginSite );
SIZE szIcon = { BTN_SIZE, BTN_SIZE };
CComPtr< IIconCache > pIconCache;
pPluginSite->GetIconCache( &szIcon, &pIconCache );
if( m_bHScroll )
{
RECT rcHScroll = { BTN_SIZE, szViewport.cy, szViewport.cx - BTN_SIZE, szViewport.cy + BTN_SIZE };
m_pHScrollBack->PatBlt( pCanvas, &rcHScroll, &ptOff );
if( m_szArea.cx != szViewport.cx )
{
// Draw the H thumb
POINT ptHThumb = { BTN_SIZE + m_ptThumb.x, szViewport.cy };
RECT rcThumb = { ptHThumb.x, ptHThumb.y, ptHThumb.x + BTN_SIZE, ptHThumb.y + BTN_SIZE };
pCanvas->Fill( &rcThumb, RGB( 0, 0, 0 ) );
pIconCache->DrawIcon( &ptHThumb, ( m_nCurrentCommand == eScrollerHThumb ) ? 0x06001264 : 0x06001263, 0, pCanvas );
}
}
if( m_bVScroll )
{
RECT rcVScroll = { szViewport.cx, BTN_SIZE, szViewport.cx + BTN_SIZE, szViewport.cy - BTN_SIZE };
m_pVScrollBack->PatBlt( pCanvas, &rcVScroll, &ptOff );
if( m_szArea.cy != szViewport.cy )
{
// Draw the V thumb
POINT ptVThumb = { szViewport.cx, BTN_SIZE + m_ptThumb.y };
RECT rcThumb = { ptVThumb.x, ptVThumb.y, ptVThumb.x + BTN_SIZE, ptVThumb.y + BTN_SIZE };
pCanvas->Fill( &rcThumb, RGB( 0, 0, 0 ) );
pIconCache->DrawIcon( &ptVThumb, ( m_nCurrentCommand == eScrollerVThumb ) ? 0x06001264 : 0x06001263, 0, pCanvas );
}
}
if( m_bHScroll && m_bVScroll )
{
// Draw the little corner piece
RECT rcCorner = { szViewport.cx, szViewport.cy, szViewport.cx + BTN_SIZE, szViewport.cy + BTN_SIZE };
pCanvas->Fill( &rcCorner, RGB( 130, 100, 80 ) );
}
return S_OK;
}
STDMETHODIMP cScroller::Reformat()
{
SIZE szViewport;
get_Viewport( &szViewport );
CComPtr< ILayerSite > pPagerSite;
HRESULT hRes = m_pSite->get_Child( eScrollerPager, ePositionByID, &pPagerSite );
RECT rcPager = { 0, 0, szViewport.cx, szViewport.cy };
pPagerSite->put_Position( &rcPager );
CComPtr< ILayerSite > pClientSite;
pPagerSite->get_Child( eScrollerClient, ePositionByID, &pClientSite );
RECT rcClient = { 0, 0, m_szArea.cx, m_szArea.cy };
pClientSite->put_Position( &rcClient );
CComPtr< ILayerSite > pUp, pDown, pLeft, pRight;
m_pSite->get_Child( eScrollerUp, ePositionByID, &pUp );
m_pSite->get_Child( eScrollerDown, ePositionByID, &pDown );
m_pSite->get_Child( eScrollerLeft, ePositionByID, &pLeft );
m_pSite->get_Child( eScrollerRight, ePositionByID, &pRight );
static RECT rcHidden = { 0, 0, 0, 0 };
if( m_bHScroll )
{
RECT rcLeft = { 0, szViewport.cy, BTN_SIZE, szViewport.cy + BTN_SIZE },
rcRight = { szViewport.cx - BTN_SIZE, szViewport.cy, szViewport.cx, szViewport.cy + BTN_SIZE };
pLeft->put_Position( &rcLeft );
pRight->put_Position( &rcRight );
}
else
{
pLeft->put_Position( &rcHidden );
pRight->put_Position( &rcHidden );
}
if( m_bVScroll )
{
RECT rcUp = { szViewport.cx, 0, szViewport.cx + BTN_SIZE, BTN_SIZE },
rcDown = { szViewport.cx, szViewport.cy - BTN_SIZE, szViewport.cx + BTN_SIZE, szViewport.cy };
pUp->put_Position( &rcUp );
pDown->put_Position( &rcDown );
}
else
{
pUp->put_Position( &rcHidden );
pDown->put_Position( &rcHidden );
}
// Calculate the size of the page increments
m_szPage.cx = ( szViewport.cx / m_szIncrement.cx ) * m_szIncrement.cx;
m_szPage.cy = ( szViewport.cy / m_szIncrement.cy ) * m_szIncrement.cy;
return S_OK;
}
void cScroller::onButtonHit(long nID)
{
m_pPager->put_Command( nID );
}
void cScroller::onButtonUnhit(long)
{
m_pPager->FinishCommand();
}
VARIANT_BOOL cScroller::onClientGetNextPosition(long nID, long nCommand, long *pnX, long *pnY)
{
POINT ptDest;
m_pPager->get_Offset( &ptDest );
POINT ptOriginal = ptDest;
switch( nCommand )
{
case eScrollerUp:
ptDest.y -= m_szIncrement.cy;
break;
case eScrollerDown:
ptDest.y += m_szIncrement.cy;
break;
case eScrollerPageUp:
ptDest.y -= m_szPage.cy;
break;
case eScrollerPageDown:
ptDest.y += m_szPage.cy;
break;
case eScrollerLeft:
ptDest.x -= m_szIncrement.cx;
break;
case eScrollerRight:
ptDest.x += m_szIncrement.cx;
break;
case eScrollerPageLeft:
ptDest.x -= m_szPage.cx;
break;
case eScrollerPageRight:
ptDest.x += m_szPage.cx;
break;
default:
// Unknown scrolling command
_ASSERTE( FALSE );
}
constrainOffset( &ptDest );
if( ptDest.x == ptOriginal.x && ptDest.y == ptOriginal.y )
// We didn't move this cycle - do not continue
return VARIANT_FALSE;
*pnX = ptDest.x;
*pnY = ptDest.y;
return VARIANT_TRUE;
}
void cScroller::onClientChange( long nID, long, long nX, long nY )
{
_ASSERTE( nID == eScrollerPager );
// Convert these values to a thumb-like position
SIZE szViewport;
get_Viewport( &szViewport );
SIZE szScroll = szViewport;
szScroll.cx -= BTN_SIZE * 3;
szScroll.cy -= BTN_SIZE * 3;
// The viewport is now the size of the thumb ranges
m_ptThumb.x = static_cast< long >( ( ( m_szArea.cx - szViewport.cx ) != 0 ) ? static_cast< double >( nX * szScroll.cx ) / static_cast< double >( m_szArea.cx - szViewport.cx ) : 0.0 );
m_ptThumb.y = static_cast< long >( ( ( m_szArea.cy - szViewport.cy ) != 0 ) ? static_cast< double >( nY * szScroll.cy ) / static_cast< double >( m_szArea.cy - szViewport.cy ) : 0.0 );
if( m_ptThumb.x > szScroll.cx || nX >= ( m_szArea.cx - szViewport.cx - m_szIncrement.cy ) )
m_ptThumb.x = szScroll.cx;
if( m_ptThumb.y > szScroll.cy || nY >= ( m_szArea.cy - szViewport.cy - m_szIncrement.cy ) )
m_ptThumb.y = szScroll.cy;
if( m_ptThumb.x < 0 )
m_ptThumb.x = 0;
if( m_ptThumb.y < 0 )
m_ptThumb.y = 0;
// Check if the thumb moving has canceled a mouse action
switch( m_nCurrentCommand )
{
case eScrollerPageUp:
case eScrollerPageDown:
case eScrollerPageLeft:
case eScrollerPageRight:
{
MouseState ms = { this, { 0, 0 }, { m_ptMouseLast.x, m_ptMouseLast.y }, VARIANT_FALSE, VARIANT_FALSE };
if( hitTest( &ms ) != m_nCurrentCommand )
m_pPager->FinishCommand();
}
break;
}
// Draw next frame
m_pSite->Invalidate();
long nIDThis;
m_pSite->get_ID( &nIDThis );
Fire_Change( nIDThis, nX, nY );
}
STDMETHODIMP cScroller::get_Viewport(LPSIZE pVal)
{
_ASSERTE( pVal != NULL );
RECT rc;
m_pSite->get_Position( &rc );
pVal->cx = ( rc.right - rc.left ) - ( ( m_bVScroll ) ? BTN_SIZE : 0 );
pVal->cy = ( rc.bottom - rc.top ) - ( ( m_bHScroll ) ? BTN_SIZE : 0 );
return S_OK;
}
STDMETHODIMP cScroller::get_Area(LPSIZE pVal)
{
_ASSERTE( pVal != NULL );
*pVal = m_szArea;
return S_OK;
}
STDMETHODIMP cScroller::put_Area(LPSIZE newVal)
{
_ASSERTE( newVal != NULL );
//_ASSERTE( newVal->cx >= 0 && newVal->cy >= 0 );
// Now this area will have to be rounded up to an increment or
// a page size
SIZE szViewport;
get_Viewport( &szViewport );
if( newVal->cx < szViewport.cx )
// This view is thinner than the viewport, set it to the minimum
newVal->cx = szViewport.cx;
else if( m_bHScroll )
if((szViewport.cx % m_szIncrement.cx)!=0)
newVal->cx += m_szIncrement.cx - ( newVal->cx % m_szIncrement.cx ); // Make sure there is an extra line so we don't scroll off the edge
// Repeat for y-scoord
if( newVal->cy < szViewport.cy )
newVal->cy = szViewport.cy;
else if( m_bVScroll )
if((szViewport.cy % m_szIncrement.cy)!=0)
newVal->cy += m_szIncrement.cy - ( newVal->cy % m_szIncrement.cy );
m_szArea = *newVal;
m_pSite->Reformat();
return S_OK;
}
STDMETHODIMP cScroller::get_HorizontalEnabled(VARIANT_BOOL *pVal)
{
_ASSERTE( pVal != NULL );
*pVal = m_bHScroll;
return S_OK;
}
STDMETHODIMP cScroller::put_HorizontalEnabled(VARIANT_BOOL newVal)
{
if( newVal != m_bHScroll )
{
m_bHScroll = newVal;
m_pSite->Reformat();
}
return S_OK;
}
STDMETHODIMP cScroller::get_VerticalEnabled(VARIANT_BOOL *pVal)
{
_ASSERTE( pVal != NULL );
*pVal = m_bVScroll;
return S_OK;
}
STDMETHODIMP cScroller::put_VerticalEnabled(VARIANT_BOOL newVal)
{
if( newVal != m_bVScroll )
{
m_bVScroll = newVal;
m_pSite->Reformat();
}
return S_OK;
}
STDMETHODIMP cScroller::CreateClient(ILayer *pChild)
{
CComPtr< ILayerSite > pPagerSite;
HRESULT hRes = m_pSite->get_Child( eScrollerPager, ePositionByID, &pPagerSite );
_ASSERTE( SUCCEEDED( hRes ) );
LayerParams lp = { eScrollerClient, { 0, 0, 0, 0 }, eRenderClipped };
return pPagerSite->CreateChild( &lp, pChild );
}
STDMETHODIMP cScroller::get_Offset(LPPOINT pVal)
{
_ASSERTE( pVal != NULL );
POINT ptTrueOff;
m_pPager->get_Offset( &ptTrueOff );
pVal->x = ptTrueOff.x / m_szIncrement.cx;
pVal->y = ptTrueOff.y / m_szIncrement.cy;
return S_OK;
}
STDMETHODIMP cScroller::put_Offset(LPPOINT newVal)
{
_ASSERTE( newVal != NULL );
_ASSERTE( newVal->x >= 0 && newVal->y >= 0 );
POINT ptTrueOff = { newVal->x * m_szIncrement.cx, newVal->y * m_szIncrement.cy };
constrainOffset( &ptTrueOff );
m_pPager->put_Offset( &ptTrueOff );
return S_OK;
}
STDMETHODIMP cScroller::ScrollTo(LPPOINT ptOffset)
{
_ASSERTE( ptOffset != NULL );
_ASSERTE( ptOffset->x >= 0 && ptOffset->y >= 0 );
POINT ptTrueOff = { ptOffset->x * m_szIncrement.cx, ptOffset->y * m_szIncrement.cy };
constrainOffset( &ptTrueOff );
m_pPager->ScrollTo( &ptTrueOff );
return S_OK;
}
STDMETHODIMP cScroller::get_Increments(LPSIZE pVal)
{
_ASSERTE( pVal != NULL );
*pVal = m_szIncrement;
return S_OK;
}
STDMETHODIMP cScroller::put_Increments(LPSIZE newVal)
{
_ASSERTE( newVal != NULL );
_ASSERTE( newVal->cx > 0 && newVal->cy > 0 );
// Assign the new increments
m_szIncrement = *newVal;
// Align the current position to the new position
POINT ptCurrent;
m_pPager->get_Offset( &ptCurrent );
ptCurrent.x = ( ptCurrent.x / newVal->cx ) * newVal->cx;
ptCurrent.y = ( ptCurrent.y / newVal->cy ) * newVal->cy;
constrainOffset( &ptCurrent );
m_pPager->put_Offset( &ptCurrent );
m_pSite->Reformat();
return S_OK;
}
STDMETHODIMP cScroller::MouseDown( MouseState *pMS )
{
m_nCurrentCommand = hitTest( pMS );
if( m_nCurrentCommand == -1 )
return S_OK;
switch( m_nCurrentCommand )
{
case eScrollerHThumb:
m_nScreenStart = pMS->screen.x;
m_nThumbStart = m_ptThumb.x;
break;
case eScrollerVThumb:
m_nScreenStart = pMS->screen.y;
m_nThumbStart = m_ptThumb.y;
break;
case eScrollerPageUp:
case eScrollerPageDown:
case eScrollerPageLeft:
case eScrollerPageRight:
m_ptMouseLast = pMS->client;
m_pPager->put_Command( m_nCurrentCommand );
break;
}
m_pSite->Invalidate();
return S_OK;
}
STDMETHODIMP cScroller::MouseUp( MouseState *pMS )
{
m_nCurrentCommand = -1;
// Make sure there are no more commands in the pager
m_pPager->FinishCommand();
m_pSite->Invalidate();
return S_OK;
}
STDMETHODIMP cScroller::MouseMove( MouseState *pMS )
{
if( m_nCurrentCommand == -1 )
// No command, so nothgin to do
return S_OK;
SIZE szViewport;
get_Viewport( &szViewport );
SIZE szScroller = { szViewport.cx - BTN_SIZE * 3, szViewport.cy - BTN_SIZE * 3 };
POINT ptOffset;
m_pPager->get_Offset( &ptOffset );
switch( m_nCurrentCommand )
{
case eScrollerPageUp:
case eScrollerPageDown:
case eScrollerPageLeft:
case eScrollerPageRight:
{
if( hitTest( pMS ) == m_nCurrentCommand )
m_pPager->put_Command( m_nCurrentCommand );
else
m_pPager->FinishCommand();
m_ptMouseLast = pMS->client;
}
break;
case eScrollerHThumb:
{
long nPos = m_nThumbStart + ( pMS->screen.x - m_nScreenStart );
// Make sure it's bigger than 0
if( nPos < 0 )
nPos = 0;
// Convert this to an actual position
ptOffset.x = nPos * ( m_szArea.cx - szViewport.cx ) / szScroller.cx;
// Align to the nearest line
ptOffset.x -= ptOffset.x % m_szIncrement.cx;
// Set the position, pager callback will set the thumb position
constrainOffset( &ptOffset );
m_pPager->put_Offset( &ptOffset );
}
break;
case eScrollerVThumb:
{
long nPos = m_nThumbStart + ( pMS->screen.y - m_nScreenStart );
// Make sure it's bigger than 0
if( nPos < 0 )
nPos = 0;
// Convert this to an actual position
ptOffset.y = nPos * ( m_szArea.cy - szViewport.cy ) / szScroller.cy;
// Align to the nearest line
ptOffset.y -= ptOffset.y % m_szIncrement.cy;
// Set the position, pager callback will set the thumb position
constrainOffset( &ptOffset );
m_pPager->put_Offset( &ptOffset );
}
break;
}
return S_OK;
}
HRESULT cScroller::SchemaLoad( IView *pView, IUnknown *pXMLElement )
{
MSXML::IXMLDOMElementPtr pElement = pXMLElement;
_variant_t vHScroll = pElement->getAttribute( _T( "hscroll" ) ),
vVScroll = pElement->getAttribute( _T( "vscroll" ) ),
vAreaWidth = pElement->getAttribute( _T( "areawidth" ) ),
vAreaHeight = pElement->getAttribute( _T( "areaheight" ) ),
vIncrementX = pElement->getAttribute( _T( "incrementx" ) ),
vIncrementY = pElement->getAttribute( _T( "incrementy" ) );
// Do the client
MSXML::IXMLDOMElementPtr pClient = pElement->selectSingleNode( _T( "control" ) );
if( pClient.GetInterfacePtr() != NULL )
{
// Recurse and load the client
CComPtr< ILayerSite > pPager;
m_pSite->get_Child( eScrollerPager, ePositionByID, &pPager );
long nAssigned;
pView->LoadControl( pPager, eScrollerClient, pClient, &nAssigned );
}
// First enable the scroll bars
if( vHScroll.vt != VT_NULL )
{
try
{
m_bHScroll = static_cast< bool >( vHScroll ) ? VARIANT_TRUE : VARIANT_FALSE;
}
catch( ... )
{
// Type conversion error
_ASSERTE( FALSE );
}
}
if( vVScroll.vt != VT_NULL )
{
try
{
m_bVScroll = static_cast< bool >( vVScroll ) ? VARIANT_TRUE : VARIANT_FALSE;
}
catch( ... )
{
// Type conversion error
_ASSERTE( FALSE );
}
}
// Next set the increment sizes
if( vIncrementX.vt != VT_NULL )
{
try
{
m_szIncrement.cx = static_cast< long >( vIncrementX );
}
catch( ... )
{
// Type conversion error
_ASSERTE( FALSE );
}
}
if( vIncrementY.vt != VT_NULL )
{
try
{
m_szIncrement.cy = static_cast< long >( vIncrementY );
}
catch( ... )
{
// Type conversion error
_ASSERTE( FALSE );
}
}
// Last, set the area
SIZE szArea = m_szArea;
if( vAreaWidth.vt != VT_NULL )
{
try
{
szArea.cx = static_cast< long >( vAreaWidth );
}
catch( ... )
{
// Type conversion error
_ASSERTE( FALSE );
}
}
if( vAreaHeight.vt != VT_NULL )
{
try
{
szArea.cy = static_cast< long >( vAreaHeight );
}
catch( ... )
{
// Type conversion error
_ASSERTE( FALSE );
}
}
put_Area( &szArea );
return S_OK;
}
STDMETHODIMP cScroller::ResetScroller()
{
POINT ptCurrent;
ptCurrent.x = 0;
ptCurrent.y = 0;
constrainOffset( &ptCurrent );
m_pPager->put_Offset( &ptCurrent );
m_ptThumb.x =0;
m_ptThumb.y =0;
return S_OK;
}