home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
OS/2 Shareware BBS: 10 Tools
/
10-Tools.zip
/
wxos2233.zip
/
wxOS2-2_3_3.zip
/
wxWindows-2.3.3
/
contrib
/
src
/
fl
/
gcupdatesmgr.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2002-01-21
|
12KB
|
411 lines
/////////////////////////////////////////////////////////////////////////////
// Name: gcupdatesmgr.cpp
// Purpose: cbGCUpdatesMgr class, optimizing refresh using GarbageCollector
// Author: Aleksandras Gluchovas
// Modified by:
// Created: 19/10/98
// RCS-ID: $Id: gcupdatesmgr.cpp,v 1.3 2002/01/21 22:34:42 JS Exp $
// Copyright: (c) Aleksandras Gluchovas
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#ifdef __GNUG__
#pragma implementation "gcupdatesmgr.h"
#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 "wx/fl/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;
int n;
for ( 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. Dependency 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();
}
}