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 27static 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 42struct cbRectInfo 43{ 44 cbBarInfo* mpBar; 45 cbDockPane* mpPane; 46 wxRect* mpCurBounds; 47 wxRect* mpPrevBounds; 48}; 49 50static inline cbRectInfo& node_to_rect_info( wxNode* pNode ) 51{ 52 return *( (cbRectInfo*) (pNode->GetData()) ); 53} 54 55/***** Implementation for class cbSimpleUpdatesMgr *****/ 56 57IMPLEMENT_DYNAMIC_CLASS( cbGCUpdatesMgr, cbSimpleUpdatesMgr ) 58 59cbGCUpdatesMgr::cbGCUpdatesMgr( wxFrameLayout* pPanel ) 60 : cbSimpleUpdatesMgr( pPanel ) 61{} 62 63void 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 79void 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 121void 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 273void 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