// ListView.cpp : Implementation of cListView #include "stdafx.h" #include "DecalControls.h" #include "ListView.h" #include "List.h" ///////////////////////////////////////////////////////////////////////////// // cListView cListView::cListView() : m_nRowHeight( 20 ), m_nRowCache( 0 ), m_nValidFrom( 0 ), m_nValidTo( 0 ) { } STDMETHODIMP cListView::put_Area(LPSIZE newVal) { RECT rc = { 0, 0, newVal->cx, newVal->cy }; m_pSite->put_Position( &rc ); return S_OK; } STDMETHODIMP cListView::SetCacheInfo(long nRowHeight, long nRowsToCache) { m_nRowHeight = nRowHeight; m_nRowCache = nRowsToCache; m_pSite->Reformat(); return S_OK; } void cListView::onCreate() { CComPtr< IPluginSite > pPlugin; m_pSite->get_PluginSite( &pPlugin ); pPlugin->LoadBitmapPortal( 0x0600128A, &m_pBackground ); m_pSite->put_Transparent( VARIANT_FALSE ); } void cListView::onDestroy() { m_pBackground.Release(); if( m_pCache.p != NULL ) m_pCache.Release(); } STDMETHODIMP cListView::Reformat() { RECT rcPos; m_pSite->get_Position( &rcPos ); SIZE szCache = { rcPos.right - rcPos.left, m_nRowHeight * m_nRowCache }; if( m_pCache.p != NULL ) m_pCache->put_Size( &szCache ); else { CComPtr< IPluginSite > pPlugin; m_pSite->get_PluginSite( &pPlugin ); pPlugin->CreateCanvas( &szCache, &m_pCache ); } _ASSERTMEM( _CrtCheckMemory( ) ); return S_OK; } STDMETHODIMP cListView::Render(ICanvas *pCanvas) { _ASSERTMEM( _CrtCheckMemory( ) ); // First, draw the Background pattern VARIANT_BOOL bLost; m_pCache->get_WasLost( &bLost ); if( bLost ) // There is no valid range - we must redraw // the entire rowset m_nValidFrom = m_nValidTo; ClipParams cp; pCanvas->GetClipParams( &cp ); SIZE szCache; m_pCache->get_Size( &szCache ); // We have the clipping rectangle now - calculate the range // of rows we want to draw long nDrawFrom = cp.org.y / m_nRowHeight, nDrawTo = nDrawFrom + m_nRowCache, nRowCount = m_pList->m_rows.size(); // Ok, now draw all of the rows either out of range // or invalid for( long nDraw = nDrawFrom; nDraw < nDrawTo; ++ nDraw ) { // Determine how much we need to draw bool bHasData = ( nDraw >= 0 && nDraw < nRowCount ); if( nDraw < m_nValidFrom || nDraw >= m_nValidTo || ( bHasData && m_pList->m_rows[ nDraw ].m_bInvalid ) ) { // Redraw this row long nRowPos = nDraw % m_nRowCache; RECT rcRow = { 0, nRowPos * m_nRowHeight, szCache.cx, ( nRowPos + 1 ) * m_nRowHeight }; // Fill the background with the background image POINT ptBackgroundOrg = { 0, nDraw * m_nRowHeight }; m_pBackground->PatBlt( m_pCache, &rcRow, &ptBackgroundOrg ); if( bHasData ) { // This row is visible and there's data - so use the // column objects to render the data for( cList::cColumnList::iterator i_col = m_pList->m_cols.begin(); i_col != m_pList->m_cols.end(); ++ i_col ) { RECT rcCell = { i_col->m_nLeft, rcRow.top, i_col->m_nRight, rcRow.bottom }; VARIANT_BOOL bVisible; m_pCache->PushClipRect( &rcCell, &bVisible ); // All our clippings should be completely visible _ASSERTE( bVisible ); long nColor; POINT ptCell = { i_col - m_pList->m_cols.begin(), nDraw }; get_Color(ptCell.x, ptCell.y, &nColor); i_col->m_pColumn->Render( m_pCache, &ptCell, nColor); m_pCache->PopClipRect(); _ASSERTMEM( _CrtCheckMemory( ) ); } m_pList->m_rows[ nDraw ].m_bInvalid = false; } } } // Now that our cache is updated, we can tranfer it to the surface m_nValidFrom = nDrawFrom; m_nValidTo = nDrawTo; long nBltFrom = nDrawFrom % m_nRowCache; RECT rcTop = { 0, nBltFrom * m_nRowHeight, szCache.cx, m_nRowHeight * m_nRowCache }; POINT ptDest = { 0, nDrawFrom * m_nRowHeight }; pCanvas->Blt( &rcTop, m_pCache, &ptDest ); if( nBltFrom != 0 ) { // Transfer the bottom part RECT rcBottom = { 0, 0, szCache.cx, nBltFrom * m_nRowHeight }; POINT ptDestBottom = { 0, ( nDrawFrom + m_nRowCache - nBltFrom ) * m_nRowHeight }; pCanvas->Blt( &rcBottom, m_pCache, &ptDestBottom ); } _ASSERTMEM( _CrtCheckMemory( ) ); return S_OK; } STDMETHODIMP cListView::MouseDown( MouseState *pMS ) { // Hit test to find what cell POINT ptHit = { 0, pMS->client.y / m_nRowHeight }; if( ptHit.y >= m_pList->m_rows.size() ) // We did not hit any rows return S_OK; for( cList::cColumnList::iterator i_col = m_pList->m_cols.begin(); i_col != m_pList->m_cols.end(); ++ i_col ) { if( pMS->client.x >= i_col->m_nLeft && pMS->client.x < i_col->m_nRight ) { ptHit.x = ( i_col - m_pList->m_cols.begin() ); i_col->m_pColumn->Activate( &ptHit ); long nID; m_pList->m_pSite->get_ID( &nID ); m_pList->Fire_Change( nID, ptHit.x, ptHit.y ); break; } } return S_OK; } STDMETHODIMP cListView::InvalidateFrom(long nRow) { if( nRow < m_nValidTo ) m_nValidTo = nRow; if( nRow < m_nValidFrom ) m_nValidFrom = nRow; return S_OK; } STDMETHODIMP cListView::get_Color(long nCol, long nRow, long *pVal) { m_pList->get_Color(nCol, nRow, pVal); return S_OK; } STDMETHODIMP cListView::put_Color(long nCol, long nRow, long newVal) { m_pList->put_Color(nCol, nRow, newVal); return S_OK; }