1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        antiflickpl.cpp
3 // Purpose:     Double-buffering plugin class for reducing flickering.
4 // Author:      Aleksandras Gluchovas (@Lithuania)
5 // Modified by:
6 // Created:     23/10/98
7 // RCS-ID:      $Id: antiflickpl.cpp 35650 2005-09-23 12:56:45Z MR $
8 // Copyright:   (c) Aleksandras Gluchovas
9 // Licence:     wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11 
12 // For compilers that support precompilation, includes "wx.h".
13 #include "wx/wxprec.h"
14 
15 #ifdef __BORLANDC__
16 #pragma hdrstop
17 #endif
18 
19 #ifndef WX_PRECOMP
20 #include "wx/wx.h"
21 #endif
22 
23 #include "wx/fl/antiflickpl.h"
24 
25 /***** Implementation for class cbAntiflickerPlugin *****/
26 
27 IMPLEMENT_DYNAMIC_CLASS( cbAntiflickerPlugin, cbPluginBase )
28 
29 BEGIN_EVENT_TABLE( cbAntiflickerPlugin, cbPluginBase )
30 
31     EVT_PL_START_DRAW_IN_AREA  ( cbAntiflickerPlugin::OnStartDrawInArea  )
32     EVT_PL_FINISH_DRAW_IN_AREA ( cbAntiflickerPlugin::OnFinishDrawInArea )
33 
34 END_EVENT_TABLE()
35 
36 // initialization of static members
37 
38 int cbAntiflickerPlugin::mRefCount    = 0;
39 
40 wxBitmap*   cbAntiflickerPlugin::mpVertBuf    = 0;
41 wxBitmap*   cbAntiflickerPlugin::mpHorizBuf   = 0;
42 wxMemoryDC* cbAntiflickerPlugin::mpVertBufDc  = 0;
43 wxMemoryDC* cbAntiflickerPlugin::mpHorizBufDc = 0;
44 
45 // constructors
46 
cbAntiflickerPlugin(void)47 cbAntiflickerPlugin::cbAntiflickerPlugin(void)
48     : mpLRUBufDc  ( NULL ),
49       mLRUArea    ( -1,-1, -1,-1 )
50 {
51     ++mRefCount;
52 }
53 
cbAntiflickerPlugin(wxFrameLayout * pPanel,int paneMask)54 cbAntiflickerPlugin::cbAntiflickerPlugin( wxFrameLayout* pPanel, int paneMask )
55 
56     : cbPluginBase( pPanel, paneMask ),
57       mpLRUBufDc  ( NULL ),
58       mLRUArea    ( -1,-1, -1,-1 )
59 {
60     ++mRefCount;
61 }
62 
~cbAntiflickerPlugin()63 cbAntiflickerPlugin::~cbAntiflickerPlugin()
64 {
65     if ( --mRefCount == 0 )
66     {
67         if ( mpHorizBuf )
68         {
69             mpHorizBufDc->SelectObject( wxNullBitmap );
70             delete mpHorizBuf;
71             delete mpHorizBufDc;
72             mpHorizBuf   = 0;
73             mpHorizBufDc = 0;
74         }
75 
76         if ( mpVertBuf )
77         {
78             mpVertBufDc->SelectObject( wxNullBitmap );
79             delete mpVertBuf;
80             delete mpVertBufDc;
81             mpVertBuf   = 0;
82             mpVertBufDc = 0;
83         }
84     }
85 }
86 
FindSuitableBuffer(const wxRect & forArea)87 wxDC* cbAntiflickerPlugin::FindSuitableBuffer( const wxRect& forArea )
88 {
89     if ( mpVertBuf )
90     {
91         if ( mpVertBuf->GetHeight() >= forArea.height &&
92              mpVertBuf->GetWidth()  >= forArea.width )
93             return mpVertBufDc;
94     }
95     else
96         if ( mpHorizBuf )
97         {
98             if ( mpHorizBuf->GetHeight() >= forArea.height &&
99                  mpHorizBuf->GetWidth()  >= forArea.width )
100                 return mpHorizBufDc;
101         }
102 
103     return 0;
104 }
105 
AllocNewBuffer(const wxRect & forArea)106 wxDC* cbAntiflickerPlugin::AllocNewBuffer( const wxRect& forArea )
107 {
108     // TBD:: preallocate bit larger bitmap at once, to avoid
109     //       excessive realocations later
110 
111     // check whether the given area is oriented horizontally
112     // or vertically and choose corresponding bitmap to create or
113     // recreate
114 
115     if ( forArea.height > forArea.width )
116     {
117         wxSize prevDim( 0,0 );
118 
119         if ( mpVertBuf )
120         {
121             prevDim.x = mpVertBuf->GetWidth();
122             prevDim.y = mpVertBuf->GetHeight();
123 
124             mpVertBufDc->SelectObject( wxNullBitmap );
125             delete mpVertBuf;
126         }
127         else
128             mpVertBufDc = new wxMemoryDC();
129 
130         mpVertBuf = new wxBitmap( int( wxMax(forArea.width,  prevDim.x ) ),
131                                   int( wxMax(forArea.height, prevDim.y ) )
132                                 );
133 
134         mpVertBufDc->SelectObject( *mpVertBuf );
135 
136         return mpVertBufDc;
137     }
138     else
139     {
140         wxSize prevDim( 0,0 );
141 
142         if ( mpHorizBuf )
143         {
144             prevDim.x = mpHorizBuf->GetWidth();
145             prevDim.y = mpHorizBuf->GetHeight();
146 
147             mpHorizBufDc->SelectObject( wxNullBitmap );
148             delete mpHorizBuf;
149         }
150         else
151             mpHorizBufDc = new wxMemoryDC();
152 
153         mpHorizBuf = new wxBitmap( int( wxMax(forArea.width,  prevDim.x ) ),
154                                    int( wxMax(forArea.height, prevDim.y ) )
155                                  );
156 
157         mpHorizBufDc->SelectObject( *mpHorizBuf );
158 
159         return mpHorizBufDc;
160     }
161 }
162 
OnStartDrawInArea(cbStartDrawInAreaEvent & event)163 void cbAntiflickerPlugin::OnStartDrawInArea( cbStartDrawInAreaEvent& event )
164 {
165     wxASSERT( mpLRUBufDc == NULL ); // DBG:: see comments in OnFinishDrawInArea(..) method
166 
167     // short-cut
168     wxRect& area = event.mArea;
169 
170     if ( event.mArea.width  < 0 ||
171          event.mArea.height < 0 ) return;
172 
173     // memorize given area
174     mLRUArea.x      = area.x;
175     mLRUArea.y      = area.y;
176     mLRUArea.width  = area.width;
177     mLRUArea.height = area.height;
178 
179     wxDC* pBufDc = FindSuitableBuffer( area );
180 
181     if ( !pBufDc )
182         pBufDc = AllocNewBuffer( area );
183 
184     pBufDc->SetDeviceOrigin( -area.x, -area.y );
185 
186     pBufDc->SetClippingRegion( area.x,     area.y,
187                                area.width, area.height );
188 
189     wxClientDC clntDc( &mpLayout->GetParentFrame() );
190 
191     (*event.mppDc) = pBufDc;
192 
193     mpLRUBufDc = pBufDc; // memorize buffer, which will be flushed to screen
194                          // upon "commiting" the drawing
195 
196     /*
197     // OLD STUFF::
198     mpLRUBufDc->Blit( pos.x, pos.y, size.x, size.y,
199                       &clntDc, pos.x, pos.y, wxCOPY );
200                     */
201 }
202 
OnFinishDrawInArea(cbFinishDrawInAreaEvent & event)203 void cbAntiflickerPlugin::OnFinishDrawInArea( cbFinishDrawInAreaEvent& event )
204 {
205     wxRect& area = event.mArea;
206 
207     if ( event.mArea.width  < 0 ||
208          event.mArea.height < 0 ) return;
209 
210     wxASSERT( mpLRUBufDc ); // DBG:: OnStartDrawInArea should be called first
211 
212     // FOR NOW:: OnStartDrawInArea(..) should be immediately followed
213     //           by OnFinishDrawInArea(..) for the same area
214 
215     wxASSERT( mLRUArea.x      == area.x      );
216     wxASSERT( mLRUArea.y      == area.y      );
217     wxASSERT( mLRUArea.width  == area.width  );
218     wxASSERT( mLRUArea.height == area.height );
219 
220     wxClientDC clntDc( &mpLayout->GetParentFrame() );
221 
222     // "commit" drawings in one-shot
223     clntDc.Blit( area.x, area.y, area.width, area.height,
224                  mpLRUBufDc, area.x, area.y, wxCOPY );
225 
226     mpLRUBufDc->DestroyClippingRegion();
227     mpLRUBufDc = 0;
228 }
229 
230