]> git.saurik.com Git - wxWidgets.git/blobdiff - utils/framelayout/src/gcupdatesmgr.cpp
Added Aleksandras' framelayout code, with more or less working Linux Makefiles
[wxWidgets.git] / utils / framelayout / src / gcupdatesmgr.cpp
diff --git a/utils/framelayout/src/gcupdatesmgr.cpp b/utils/framelayout/src/gcupdatesmgr.cpp
new file mode 100644 (file)
index 0000000..33fee9e
--- /dev/null
@@ -0,0 +1,409 @@
+/////////////////////////////////////////////////////////////////////////////
+// Name:        No names yet.
+// Purpose:     Contrib. demo
+// Author:      Aleksandras Gluchovas
+// Modified by:
+// Created:     19/10/98
+// RCS-ID:      $Id$
+// Copyright:   (c) Aleksandras Gluchovas 
+// Licence:    wxWindows license
+/////////////////////////////////////////////////////////////////////////////
+
+#ifdef __GNUG__
+#pragma implementation "updatesmgr.h"
+// #pragma interface
+#endif
+
+// For compilers that support precompilation, includes "wx.h".
+#include "wx/wxprec.h"
+
+#ifdef __BORLANDC__
+#pragma hdrstop
+#endif
+
+#ifndef WX_PRECOMP
+#include "wx/wx.h"
+#endif
+
+#include "gcupdatesmgr.h"
+
+// helper function
+
+static inline bool rect_hits_rect( const wxRect& r1, const wxRect& r2 )
+{
+       if ( ( r2.x >= r1.x && r2.x <= r1.x + r1.width ) ||
+                ( r1.x >= r2.x && r1.x <= r2.x + r2.width ) )
+
+               if ( ( r2.y >= r1.y && r2.y <= r1.y + r1.height ) ||
+                        ( r1.y >= r2.y && r1.y <= r2.y + r2.height ) )
+                        
+                       return 1;
+
+       return 0;
+}
+
+// helper structure
+
+struct cbRectInfo
+{
+       cbBarInfo*  mpBar;
+       cbDockPane* mpPane;
+       wxRect*     mpCurBounds;
+       wxRect*     mpPrevBounds;
+};
+
+static inline cbRectInfo& node_to_rect_info( wxNode* pNode )
+{
+       return *( (cbRectInfo*) (pNode->Data()) );
+}
+
+/***** Implementation for class cbSimpleUpdatesMgr *****/
+
+IMPLEMENT_DYNAMIC_CLASS( cbGCUpdatesMgr, cbSimpleUpdatesMgr )
+
+cbGCUpdatesMgr::cbGCUpdatesMgr( wxFrameLayout* pPanel )
+       : cbSimpleUpdatesMgr( pPanel )
+{}
+
+void cbGCUpdatesMgr::AddItem( wxList&     itemList,
+                                                     cbBarInfo*  pBar, 
+                                                         cbDockPane* pPane,
+                                                         wxRect&     curBounds,
+                                                         wxRect&     prevBounds )
+{
+       cbRectInfo* pInfo = new cbRectInfo();
+
+       pInfo->mpBar     = pBar;
+       pInfo->mpPane       = pPane;
+       pInfo->mpCurBounds  = &curBounds;
+       pInfo->mpPrevBounds = &prevBounds;
+
+       itemList.Append( (wxObject*) pInfo );
+}
+
+void cbGCUpdatesMgr::OnStartChanges()
+{
+       // memorize states of ALL items in the layout -
+       // this is quite excessive, but OK for the decent 
+       // implementation of updates manager
+
+       mpLayout->GetPrevClientRect() = mpLayout->GetClientRect();
+
+       cbDockPane** panes = mpLayout->GetPanesArray();
+
+       for( int n = 0; n != MAX_PANES; ++n )
+       {
+               cbDockPane& pane = *(panes[n]);
+
+               // store pane state
+               pane.mUMgrData.StoreItemState( pane.mBoundsInParent );
+               pane.mUMgrData.SetDirty( FALSE );
+
+               cbRowInfo* pRow = pane.GetFirstRow();
+
+               while ( pRow )
+               {
+                       cbBarInfo* pBar = pRow->GetFirstBar();
+
+                       // store row state
+                       pRow->mUMgrData.StoreItemState( pRow->mBoundsInParent );
+                       pRow->mUMgrData.SetDirty( FALSE );
+
+                       while( pBar )
+                       {
+                               // store bar state
+                               pBar->mUMgrData.StoreItemState( pBar->mBoundsInParent );
+                               pBar->mUMgrData.SetDirty( FALSE );
+
+                               pBar = pBar->mpNext;
+                       }
+
+                       pRow = pRow->mpNext;
+               }
+       }
+}
+
+void cbGCUpdatesMgr::UpdateNow()
+{
+       cbDockPane** panes = mpLayout->GetPanesArray();
+
+       wxRect& r1 = mpLayout->GetClientRect();
+       wxRect& r2 = mpLayout->GetPrevClientRect();
+
+       // detect changes in client window's area
+
+       bool clientWindowChanged = ( r1.x      != r2.x     ||
+                                        r1.y      != r2.y     ||
+                                                                r1.width  != r2.width ||
+                                                                r1.height != r2.height );
+
+       // step #1 - detect changes in each row of each pane,
+       //           and repaint decorations around changed windows
+
+       wxList mBarsToResize;
+
+       for( int n = 0; n != MAX_PANES; ++n )
+       {
+               cbDockPane& pane = *(panes[n]);
+
+               bool paneChanged = WasChanged( pane.mUMgrData, pane.mBoundsInParent );
+
+               if ( paneChanged )
+               {
+                       wxClientDC dc( &mpLayout->GetParentFrame() );
+                       pane.PaintPaneBackground( dc );
+               }
+
+               wxRect realBounds;
+
+               cbRowInfo* pRow = pane.GetFirstRow();
+
+               while ( pRow )
+               {
+                       wxDC* pDc = 0;
+
+                       cbBarInfo* pBar = pRow->GetFirstBar();
+
+                       bool rowChanged = FALSE;
+                       bool rowBkPainted  = FALSE;
+
+                       // FIXME:: the below should not be fixed
+                       cbBarInfo* barsToRepaint[128];
+                       // number of bars, that were changed in the current row
+                       int nBars = 0; 
+
+                       wxRect r1 = pRow->mUMgrData.mPrevBounds;
+                       wxRect r2 = pRow->mBoundsInParent;
+
+                       if ( WasChanged( pRow->mUMgrData, pRow->mBoundsInParent ) )
+                       
+                               rowChanged = TRUE;
+                       else
+                               while( pBar )
+                               {
+                                       if ( WasChanged( pBar->mUMgrData, pBar->mBoundsInParent ) )
+                                       
+                                               barsToRepaint[nBars++] = pBar;
+
+                                       pBar = pBar->mpNext;
+                               }
+
+                       if ( nBars || rowChanged )
+                       {
+                               realBounds = pRow->mBoundsInParent;
+
+                               // include 1-pixel thick shades around the row
+                               realBounds.x -= 1;
+                               realBounds.y -= 1;
+                               realBounds.width  += 2;
+                               realBounds.height += 2;
+
+                               pDc = pane.StartDrawInArea( realBounds );
+                       }
+
+                       if ( rowChanged )
+                       {
+                               // postphone the resizement and refreshing the changed
+                               // bar windows
+
+                               cbBarInfo* pCurBar = pRow->GetFirstBar();
+
+                               while( pCurBar )
+                               {
+                                       if ( WasChanged( pCurBar->mUMgrData, 
+                                                                        pCurBar->mBoundsInParent ) )
+
+                                               AddItem( mBarsToResize, pCurBar, &pane, 
+                                                                pCurBar->mBoundsInParent,
+                                                                pCurBar->mUMgrData.mPrevBounds );
+
+                                       pCurBar = pCurBar->mpNext;
+                               }
+
+                               // draw only their decorations now
+
+                               pane.PaintRow( pRow, *pDc );
+                       }
+                       else
+                       if ( nBars != 0 )
+                       {
+                               for( int i = 0; i != nBars; ++i )
+
+                                       // postphone the resizement and refreshing the changed
+                                       // bar windows
+
+                                       AddItem( mBarsToResize, 
+                                                        barsToRepaint[i], 
+                                                        &pane, 
+                                                    barsToRepaint[i]->mBoundsInParent,
+                                                        barsToRepaint[i]->mUMgrData.mPrevBounds );
+
+                               // redraw decorations of entire row, regardless of how much
+                               // of the bars were changed
+
+                               pane.PaintRow( pRow, *pDc );
+                       }
+
+                       if ( pDc )
+               
+                               pane.FinishDrawInArea( realBounds );
+
+                       pRow = pRow->mpNext;
+
+               } // end of while
+
+               if ( paneChanged )
+               {
+                       wxClientDC dc( &mpLayout->GetParentFrame() );
+                       pane.PaintPaneDecorations( dc );
+               }
+
+       } // end of for
+
+       if ( clientWindowChanged && !mpLayout->mClientWndRefreshPending )
+       {
+               // ptr to client-window object is "marked" as NULL
+
+               AddItem( mBarsToResize, NULL, NULL, 
+                            mpLayout->GetClientRect(),
+                                mpLayout->GetPrevClientRect() );
+       }
+
+       // step #2 - do ordered refreshing and resizing of bar window objects now
+
+       DoRepositionItems( mBarsToResize );
+}
+
+void cbGCUpdatesMgr::DoRepositionItems( wxList& items )
+{
+       wxNode* pNode1 = items.First();
+
+       while( pNode1 )
+       {
+               cbRectInfo& info = node_to_rect_info( pNode1 );
+
+               wxNode* pNode2 = items.First();
+
+               // and node itself
+
+               mGC.AddObject( &info );
+
+               while( pNode2 )
+               {
+                       if ( pNode2 != pNode1 ) // node should not depend on itself
+                       {
+                               // add references to objects, on which this object
+                               // depends. Dependecy here indicates intersection of current
+                               // bounds of this object with the initial bounds of the
+                               // other object
+
+                               cbRectInfo& otherInfo = node_to_rect_info( pNode2 );
+
+                               if ( rect_hits_rect( *info.mpCurBounds, *otherInfo.mpPrevBounds ) )
+                               
+                                                                       // the node    depends on node
+                                       mGC.AddDependency( &info,      &otherInfo      );
+                       }
+
+                       pNode2 = pNode2->Next();
+               }
+
+               pNode1 = pNode1->Next();
+       }
+
+       mGC.ArrangeCollection(); // order nodes according "least-dependency" rule,
+                                    // and find out cycled chains
+
+       // regular item nodes need to be resized, but not repainted (since
+       // they stand in linear (not cyclic) dependency with other
+       // regular nodes)
+
+       wxNode* pNode = mGC.GetRegularObjects().First();
+
+       while ( pNode )
+       {
+               cbRectInfo& info = *((cbRectInfo*)gc_node_to_obj(pNode));
+
+               if ( info.mpBar == NULL ) 
+                       
+                       mpLayout->PositionClientWindow();
+               else
+                       info.mpPane->SizeBar( info.mpBar );
+
+               pNode = pNode->Next();
+       }
+
+       // cycled item nodes, need to be both resized and repainted
+
+       pNode = mGC.GetCycledObjects().First();
+
+       while ( pNode )
+       {
+               cbRectInfo& info = *((cbRectInfo*)gc_node_to_obj(pNode));
+
+               if ( info.mpBar == NULL ) 
+               {
+                       wxWindow* pClntWnd = mpLayout->GetFrameClient();
+
+                       mpLayout->PositionClientWindow();
+
+                       // FIXME FIXME:: excessive!
+
+                       pClntWnd->Show( FALSE );
+                       pClntWnd->Show( TRUE  );
+
+                       // OLD STUFF:: mpLayout->PositionClientWindow();
+               }
+               else
+               if ( info.mpBar->mpBarWnd )
+               {
+                       wxWindow* pWnd = info.mpBar->mpBarWnd;
+
+                       // resize
+                       info.mpPane->SizeBar( info.mpBar );
+
+                       // repaint
+
+                       /* OLD STUFF:: bool isChoice = info.mpBar->IsKindOf( CLASSINFO( wxChoice ) );
+
+                       //#ifdef __WINDOWS__
+                       //int result = ::SendMessage( (HWND)pWnd->m_hWnd, WM_NCPAINT, 0, 0 );
+                       //#endif
+                       */
+
+                       // FIXME FIXME:: there's no other way to repaint non-client area of the wxWindow!!
+                       //                               so we do *excessive* "hide 'n show"
+
+                       pWnd->Show(FALSE);
+                       pWnd->Show(TRUE);
+                               
+                       pWnd->Refresh();
+               }
+
+               pNode = pNode->Next();
+       }
+
+       // release data prepared for GC alg.
+
+       pNode = items.First();
+
+       while( pNode )
+       {
+               cbRectInfo* pInfo = (cbRectInfo*)(pNode->Data());
+
+               delete pInfo;
+
+               pNode = pNode->Next();
+       }
+
+       mGC.Reset(); // reinit GC
+
+       // FIXME:: this is a dirty-workaround for messy client-area,
+       //         as a result of docking bar out of floated-container window
+
+       if ( mpLayout->mClientWndRefreshPending )
+       {
+               mpLayout->PositionClientWindow();
+               mpLayout->GetFrameClient()->Refresh();
+       }
+}
\ No newline at end of file