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