1 /////////////////////////////////////////////////////////////////////////////
2 // Name:        gcupdatesmgr.cpp
3 // Purpose:     cbGCUpdatesMgr class, optimizing refresh using GarbageCollector
4 // Author:      Aleksandras Gluchovas
5 // Modified by:
6 // Created:     19/10/98
7 // RCS-ID:      $Id: gcupdatesmgr.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/gcupdatesmgr.h"
24 
25 // helper function
26 
rect_hits_rect(const wxRect & r1,const wxRect & r2)27 static inline bool rect_hits_rect( const wxRect& r1, const wxRect& r2 )
28 {
29     if ( ( r2.x >= r1.x && r2.x <= r1.x + r1.width ) ||
30          ( r1.x >= r2.x && r1.x <= r2.x + r2.width ) )
31 
32         if ( ( r2.y >= r1.y && r2.y <= r1.y + r1.height ) ||
33              ( r1.y >= r2.y && r1.y <= r2.y + r2.height ) )
34 
35             return 1;
36 
37     return 0;
38 }
39 
40 // helper structure
41 
42 struct cbRectInfo
43 {
44     cbBarInfo*  mpBar;
45     cbDockPane* mpPane;
46     wxRect*     mpCurBounds;
47     wxRect*     mpPrevBounds;
48 };
49 
node_to_rect_info(wxNode * pNode)50 static inline cbRectInfo& node_to_rect_info( wxNode* pNode )
51 {
52     return *( (cbRectInfo*) (pNode->GetData()) );
53 }
54 
55 /***** Implementation for class cbSimpleUpdatesMgr *****/
56 
IMPLEMENT_DYNAMIC_CLASS(cbGCUpdatesMgr,cbSimpleUpdatesMgr)57 IMPLEMENT_DYNAMIC_CLASS( cbGCUpdatesMgr, cbSimpleUpdatesMgr )
58 
59 cbGCUpdatesMgr::cbGCUpdatesMgr( wxFrameLayout* pPanel )
60     : cbSimpleUpdatesMgr( pPanel )
61 {}
62 
AddItem(wxList & itemList,cbBarInfo * pBar,cbDockPane * pPane,wxRect & curBounds,wxRect & prevBounds)63 void cbGCUpdatesMgr::AddItem( wxList&     itemList,
64                               cbBarInfo*  pBar,
65                               cbDockPane* pPane,
66                               wxRect&     curBounds,
67                               wxRect&     prevBounds )
68 {
69     cbRectInfo* pInfo = new cbRectInfo();
70 
71     pInfo->mpBar     = pBar;
72     pInfo->mpPane       = pPane;
73     pInfo->mpCurBounds  = &curBounds;
74     pInfo->mpPrevBounds = &prevBounds;
75 
76     itemList.Append( (wxObject*) pInfo );
77 }
78 
OnStartChanges()79 void cbGCUpdatesMgr::OnStartChanges()
80 {
81     // memorize states of ALL items in the layout -
82     // this is quite excessive, but OK for the decent
83     // implementation of updates manager
84 
85     mpLayout->GetPrevClientRect() = mpLayout->GetClientRect();
86 
87     cbDockPane** panes = mpLayout->GetPanesArray();
88 
89     for( int n = 0; n != MAX_PANES; ++n )
90     {
91         cbDockPane& pane = *(panes[n]);
92 
93         // store pane state
94         pane.mUMgrData.StoreItemState( pane.mBoundsInParent );
95         pane.mUMgrData.SetDirty( false );
96 
97         cbRowInfo* pRow = pane.GetFirstRow();
98 
99         while ( pRow )
100         {
101             cbBarInfo* pBar = pRow->GetFirstBar();
102 
103             // store row state
104             pRow->mUMgrData.StoreItemState( pRow->mBoundsInParent );
105             pRow->mUMgrData.SetDirty( false );
106 
107             while( pBar )
108             {
109                 // store bar state
110                 pBar->mUMgrData.StoreItemState( pBar->mBoundsInParent );
111                 pBar->mUMgrData.SetDirty( false );
112 
113                 pBar = pBar->mpNext;
114             }
115 
116             pRow = pRow->mpNext;
117         }
118     }
119 }
120 
UpdateNow()121 void cbGCUpdatesMgr::UpdateNow()
122 {
123     cbDockPane** panes = mpLayout->GetPanesArray();
124 
125     wxRect& r1 = mpLayout->GetClientRect();
126     wxRect& r2 = mpLayout->GetPrevClientRect();
127 
128     // detect changes in client window's area
129 
130     bool clientWindowChanged = ( r1.x      != r2.x     ||
131                                  r1.y      != r2.y     ||
132                                  r1.width  != r2.width ||
133                                  r1.height != r2.height );
134 
135     // step #1 - detect changes in each row of each pane,
136     //           and repaint decorations around changed windows
137 
138     wxList mBarsToResize;
139 
140     int n;
141     for ( n = 0; n != MAX_PANES; ++n )
142     {
143         cbDockPane& pane = *(panes[n]);
144 
145         bool paneChanged = WasChanged( pane.mUMgrData, pane.mBoundsInParent );
146 
147         if ( paneChanged )
148         {
149             wxClientDC dc( &mpLayout->GetParentFrame() );
150             pane.PaintPaneBackground( dc );
151         }
152 
153         wxRect realBounds;
154 
155         cbRowInfo* pRow = pane.GetFirstRow();
156 
157         while ( pRow )
158         {
159             wxDC* pDc = 0;
160 
161             cbBarInfo* pBar = pRow->GetFirstBar();
162 
163             bool rowChanged = false;
164 //            bool rowBkPainted  = false;
165 
166             // FIXME:: the below should not be fixed
167             cbBarInfo* barsToRepaint[128];
168             // number of bars, that were changed in the current row
169             int nBars = 0;
170 
171             //wxRect r1 = pRow->mUMgrData.mPrevBounds;
172             //wxRect r2 = pRow->mBoundsInParent;
173 
174             if ( WasChanged( pRow->mUMgrData, pRow->mBoundsInParent ) )
175 
176                 rowChanged = true;
177             else
178                 while( pBar )
179                 {
180                     if ( WasChanged( pBar->mUMgrData, pBar->mBoundsInParent ) )
181 
182                         barsToRepaint[nBars++] = pBar;
183 
184                     pBar = pBar->mpNext;
185                 }
186 
187             if ( nBars || rowChanged )
188             {
189                 realBounds = pRow->mBoundsInParent;
190 
191                 // include 1-pixel thick shades around the row
192                 realBounds.x -= 1;
193                 realBounds.y -= 1;
194                 realBounds.width  += 2;
195                 realBounds.height += 2;
196 
197                 pDc = pane.StartDrawInArea( realBounds );
198             }
199 
200             if ( rowChanged )
201             {
202                 // postphone the resizement and refreshing the changed
203                 // bar windows
204 
205                 cbBarInfo* pCurBar = pRow->GetFirstBar();
206 
207                 while ( pCurBar )
208                 {
209                     if ( WasChanged( pCurBar->mUMgrData,
210                                      pCurBar->mBoundsInParent ) )
211 
212                         AddItem( mBarsToResize, pCurBar, &pane,
213                                  pCurBar->mBoundsInParent,
214                                  pCurBar->mUMgrData.mPrevBounds );
215 
216                     pCurBar = pCurBar->mpNext;
217                 }
218 
219                 // draw only their decorations now
220 
221                 pane.PaintRow( pRow, *pDc );
222             }
223             else
224             if ( nBars != 0 )
225             {
226                 for ( int i = 0; i != nBars; ++i )
227 
228                     // postphone the resizement and refreshing the changed
229                     // bar windows
230 
231                     AddItem( mBarsToResize,
232                              barsToRepaint[i],
233                              &pane,
234                              barsToRepaint[i]->mBoundsInParent,
235                              barsToRepaint[i]->mUMgrData.mPrevBounds );
236 
237                 // redraw decorations of entire row, regardless of how much
238                 // of the bars were changed
239 
240                 pane.PaintRow( pRow, *pDc );
241             }
242 
243             if ( pDc )
244 
245                 pane.FinishDrawInArea( realBounds );
246 
247             pRow = pRow->mpNext;
248 
249         } // end of while
250 
251         if ( paneChanged )
252         {
253             wxClientDC dc( &mpLayout->GetParentFrame() );
254             pane.PaintPaneDecorations( dc );
255         }
256 
257     } // end of for
258 
259     if ( clientWindowChanged && !mpLayout->mClientWndRefreshPending )
260     {
261         // ptr to client-window object is "marked" as NULL
262 
263         AddItem( mBarsToResize, NULL, NULL,
264                  mpLayout->GetClientRect(),
265                  mpLayout->GetPrevClientRect() );
266     }
267 
268     // step #2 - do ordered refreshing and resizing of bar window objects now
269 
270     DoRepositionItems( mBarsToResize );
271 }
272 
DoRepositionItems(wxList & items)273 void cbGCUpdatesMgr::DoRepositionItems( wxList& items )
274 {
275     wxNode* pNode1 = items.GetFirst();
276 
277     while( pNode1 )
278     {
279         cbRectInfo& info = node_to_rect_info( pNode1 );
280 
281         wxNode* pNode2 = items.GetFirst();
282 
283         // and node itself
284 
285         mGC.AddObject( &info );
286 
287         while( pNode2 )
288         {
289             if ( pNode2 != pNode1 ) // node should not depend on itself
290             {
291                 // Add references to objects on which this object
292                 // depends. Dependency here indicates intersection of current
293                 // bounds of this object with the initial bounds of the
294                 // other object.
295 
296                 cbRectInfo& otherInfo = node_to_rect_info( pNode2 );
297 
298                 if ( rect_hits_rect( *info.mpCurBounds, *otherInfo.mpPrevBounds ) )
299 
300                                     // the node    depends on node
301                     mGC.AddDependency( &info,      &otherInfo      );
302             }
303 
304             pNode2 = pNode2->GetNext();
305         }
306 
307         pNode1 = pNode1->GetNext();
308     }
309 
310     mGC.ArrangeCollection(); // order nodes according "least-dependency" rule,
311                              // and find out cycled chains
312 
313     // Regular item nodes need to be resized, but not repainted (since
314     // they stand in linear (not cyclic) dependency with other
315     // regular nodes).
316 
317     wxNode* pNode = mGC.GetRegularObjects().GetFirst();
318 
319     while ( pNode )
320     {
321         cbRectInfo& info = *((cbRectInfo*)gc_node_to_obj(pNode));
322 
323         if ( info.mpBar == NULL )
324 
325             mpLayout->PositionClientWindow();
326         else
327             info.mpPane->SizeBar( info.mpBar );
328 
329         pNode = pNode->GetNext();
330     }
331 
332     // cycled item nodes, need to be both resized and repainted
333 
334     pNode = mGC.GetCycledObjects().GetFirst();
335 
336     while ( pNode )
337     {
338         cbRectInfo& info = *((cbRectInfo*)gc_node_to_obj(pNode));
339 
340         if ( info.mpBar == NULL )
341         {
342             wxWindow* pClntWnd = mpLayout->GetFrameClient();
343 
344             mpLayout->PositionClientWindow();
345 
346             // FIXME FIXME:: excessive!
347 
348             pClntWnd->Show( false );
349             pClntWnd->Show( true  );
350 
351             // OLD STUFF:: mpLayout->PositionClientWindow();
352         }
353         else
354         if ( info.mpBar->mpBarWnd )
355         {
356             wxWindow* pWnd = info.mpBar->mpBarWnd;
357 
358             // resize
359             info.mpPane->SizeBar( info.mpBar );
360 
361             // repaint
362 
363             /* OLD STUFF:: bool isChoice = info.mpBar->IsKindOf( CLASSINFO( wxChoice ) );
364 
365             //#ifdef __WINDOWS__
366             //int result = ::SendMessage( (HWND)pWnd->m_hWnd, WM_NCPAINT, 0, 0 );
367             //#endif
368             */
369 
370             // FIXME FIXME:: there's no other way to repaint non-client area of the wxWindow!!
371             //                 so we do *excessive* "hide 'n show"
372 
373             pWnd->Show(false);
374             pWnd->Show(true);
375 
376             pWnd->Refresh();
377         }
378 
379         pNode = pNode->GetNext();
380     }
381 
382     // release data prepared for GC alg.
383 
384     pNode = items.GetFirst();
385 
386     while( pNode )
387     {
388         cbRectInfo* pInfo = (cbRectInfo*)(pNode->GetData());
389 
390         delete pInfo;
391 
392         pNode = pNode->GetNext();
393     }
394 
395     mGC.Reset(); // reinit GC
396 
397     // FIXME:: this is a dirty-workaround for messy client-area,
398     //         as a result of docking bar out of floated-container window
399 
400     if ( mpLayout->mClientWndRefreshPending )
401     {
402         mpLayout->PositionClientWindow();
403         mpLayout->GetFrameClient()->Refresh();
404     }
405 }
406 
407