///////////////////////////////////////////////////////////////////////////// // Name: antiflickpl.cpp // Purpose: Double-buffering plugin class for reducing flickering. // Author: Aleksandras Gluchovas (@Lithuania) // Modified by: // Created: 23/10/98 // RCS-ID: $Id: antiflickpl.cpp 35650 2005-09-23 12:56:45Z MR $ // Copyright: (c) Aleksandras Gluchovas // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #ifndef WX_PRECOMP #include "wx/wx.h" #endif #include "wx/fl/antiflickpl.h" /***** Implementation for class cbAntiflickerPlugin *****/ IMPLEMENT_DYNAMIC_CLASS( cbAntiflickerPlugin, cbPluginBase ) BEGIN_EVENT_TABLE( cbAntiflickerPlugin, cbPluginBase ) EVT_PL_START_DRAW_IN_AREA ( cbAntiflickerPlugin::OnStartDrawInArea ) EVT_PL_FINISH_DRAW_IN_AREA ( cbAntiflickerPlugin::OnFinishDrawInArea ) END_EVENT_TABLE() // initialization of static members int cbAntiflickerPlugin::mRefCount = 0; wxBitmap* cbAntiflickerPlugin::mpVertBuf = 0; wxBitmap* cbAntiflickerPlugin::mpHorizBuf = 0; wxMemoryDC* cbAntiflickerPlugin::mpVertBufDc = 0; wxMemoryDC* cbAntiflickerPlugin::mpHorizBufDc = 0; // constructors cbAntiflickerPlugin::cbAntiflickerPlugin(void) : mpLRUBufDc ( NULL ), mLRUArea ( -1,-1, -1,-1 ) { ++mRefCount; } cbAntiflickerPlugin::cbAntiflickerPlugin( wxFrameLayout* pPanel, int paneMask ) : cbPluginBase( pPanel, paneMask ), mpLRUBufDc ( NULL ), mLRUArea ( -1,-1, -1,-1 ) { ++mRefCount; } cbAntiflickerPlugin::~cbAntiflickerPlugin() { if ( --mRefCount == 0 ) { if ( mpHorizBuf ) { mpHorizBufDc->SelectObject( wxNullBitmap ); delete mpHorizBuf; delete mpHorizBufDc; mpHorizBuf = 0; mpHorizBufDc = 0; } if ( mpVertBuf ) { mpVertBufDc->SelectObject( wxNullBitmap ); delete mpVertBuf; delete mpVertBufDc; mpVertBuf = 0; mpVertBufDc = 0; } } } wxDC* cbAntiflickerPlugin::FindSuitableBuffer( const wxRect& forArea ) { if ( mpVertBuf ) { if ( mpVertBuf->GetHeight() >= forArea.height && mpVertBuf->GetWidth() >= forArea.width ) return mpVertBufDc; } else if ( mpHorizBuf ) { if ( mpHorizBuf->GetHeight() >= forArea.height && mpHorizBuf->GetWidth() >= forArea.width ) return mpHorizBufDc; } return 0; } wxDC* cbAntiflickerPlugin::AllocNewBuffer( const wxRect& forArea ) { // TBD:: preallocate bit larger bitmap at once, to avoid // excessive realocations later // check whether the given area is oriented horizontally // or vertically and choose corresponding bitmap to create or // recreate if ( forArea.height > forArea.width ) { wxSize prevDim( 0,0 ); if ( mpVertBuf ) { prevDim.x = mpVertBuf->GetWidth(); prevDim.y = mpVertBuf->GetHeight(); mpVertBufDc->SelectObject( wxNullBitmap ); delete mpVertBuf; } else mpVertBufDc = new wxMemoryDC(); mpVertBuf = new wxBitmap( int( wxMax(forArea.width, prevDim.x ) ), int( wxMax(forArea.height, prevDim.y ) ) ); mpVertBufDc->SelectObject( *mpVertBuf ); return mpVertBufDc; } else { wxSize prevDim( 0,0 ); if ( mpHorizBuf ) { prevDim.x = mpHorizBuf->GetWidth(); prevDim.y = mpHorizBuf->GetHeight(); mpHorizBufDc->SelectObject( wxNullBitmap ); delete mpHorizBuf; } else mpHorizBufDc = new wxMemoryDC(); mpHorizBuf = new wxBitmap( int( wxMax(forArea.width, prevDim.x ) ), int( wxMax(forArea.height, prevDim.y ) ) ); mpHorizBufDc->SelectObject( *mpHorizBuf ); return mpHorizBufDc; } } void cbAntiflickerPlugin::OnStartDrawInArea( cbStartDrawInAreaEvent& event ) { wxASSERT( mpLRUBufDc == NULL ); // DBG:: see comments in OnFinishDrawInArea(..) method // short-cut wxRect& area = event.mArea; if ( event.mArea.width < 0 || event.mArea.height < 0 ) return; // memorize given area mLRUArea.x = area.x; mLRUArea.y = area.y; mLRUArea.width = area.width; mLRUArea.height = area.height; wxDC* pBufDc = FindSuitableBuffer( area ); if ( !pBufDc ) pBufDc = AllocNewBuffer( area ); pBufDc->SetDeviceOrigin( -area.x, -area.y ); pBufDc->SetClippingRegion( area.x, area.y, area.width, area.height ); wxClientDC clntDc( &mpLayout->GetParentFrame() ); (*event.mppDc) = pBufDc; mpLRUBufDc = pBufDc; // memorize buffer, which will be flushed to screen // upon "commiting" the drawing /* // OLD STUFF:: mpLRUBufDc->Blit( pos.x, pos.y, size.x, size.y, &clntDc, pos.x, pos.y, wxCOPY ); */ } void cbAntiflickerPlugin::OnFinishDrawInArea( cbFinishDrawInAreaEvent& event ) { wxRect& area = event.mArea; if ( event.mArea.width < 0 || event.mArea.height < 0 ) return; wxASSERT( mpLRUBufDc ); // DBG:: OnStartDrawInArea should be called first // FOR NOW:: OnStartDrawInArea(..) should be immediately followed // by OnFinishDrawInArea(..) for the same area wxASSERT( mLRUArea.x == area.x ); wxASSERT( mLRUArea.y == area.y ); wxASSERT( mLRUArea.width == area.width ); wxASSERT( mLRUArea.height == area.height ); wxClientDC clntDc( &mpLayout->GetParentFrame() ); // "commit" drawings in one-shot clntDc.Blit( area.x, area.y, area.width, area.height, mpLRUBufDc, area.x, area.y, wxCOPY ); mpLRUBufDc->DestroyClippingRegion(); mpLRUBufDc = 0; }