]> git.saurik.com Git - wxWidgets.git/blob - contrib/src/fl/gcupdatesmgr.cpp
glibc's vswprintf doesn't nul terminate on truncation.
[wxWidgets.git] / contrib / src / fl / gcupdatesmgr.cpp
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$
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
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
50 static inline cbRectInfo& node_to_rect_info( wxNode* pNode )
51 {
52 return *( (cbRectInfo*) (pNode->GetData()) );
53 }
54
55 /***** Implementation for class cbSimpleUpdatesMgr *****/
56
57 IMPLEMENT_DYNAMIC_CLASS( cbGCUpdatesMgr, cbSimpleUpdatesMgr )
58
59 cbGCUpdatesMgr::cbGCUpdatesMgr( wxFrameLayout* pPanel )
60 : cbSimpleUpdatesMgr( pPanel )
61 {}
62
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
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
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
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