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
27IMPLEMENT_DYNAMIC_CLASS( cbAntiflickerPlugin, cbPluginBase )
28
29BEGIN_EVENT_TABLE( cbAntiflickerPlugin, cbPluginBase )
30
31    EVT_PL_START_DRAW_IN_AREA  ( cbAntiflickerPlugin::OnStartDrawInArea  )
32    EVT_PL_FINISH_DRAW_IN_AREA ( cbAntiflickerPlugin::OnFinishDrawInArea )
33
34END_EVENT_TABLE()
35
36// initialization of static members
37
38int cbAntiflickerPlugin::mRefCount    = 0;
39
40wxBitmap*   cbAntiflickerPlugin::mpVertBuf    = 0;
41wxBitmap*   cbAntiflickerPlugin::mpHorizBuf   = 0;
42wxMemoryDC* cbAntiflickerPlugin::mpVertBufDc  = 0;
43wxMemoryDC* cbAntiflickerPlugin::mpHorizBufDc = 0;
44
45// constructors
46
47cbAntiflickerPlugin::cbAntiflickerPlugin(void)
48    : mpLRUBufDc  ( NULL ),
49      mLRUArea    ( -1,-1, -1,-1 )
50{
51    ++mRefCount;
52}
53
54cbAntiflickerPlugin::cbAntiflickerPlugin( wxFrameLayout* pPanel, int paneMask )
55
56    : cbPluginBase( pPanel, paneMask ),
57      mpLRUBufDc  ( NULL ),
58      mLRUArea    ( -1,-1, -1,-1 )
59{
60    ++mRefCount;
61}
62
63cbAntiflickerPlugin::~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
87wxDC* 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
106wxDC* 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
163void 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
203void 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