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
/
controlbar.cpp
< prev
next >
Wrap
C/C++ Source or Header
|
2002-08-16
|
88KB
|
3,562 lines
/////////////////////////////////////////////////////////////////////////////
// Name: controlbar.cpp
// Purpose: Implementation for main controlbar classes.
// Author: Aleksandras Gluchovas
// Modified by:
// Created: 06/09/98
// RCS-ID: $Id: controlbar.cpp,v 1.12 2002/08/16 10:31:53 JS Exp $
// Copyright: (c) Aleksandras Gluchovas
// Licence: wxWindows license
/////////////////////////////////////////////////////////////////////////////
#ifdef __GNUG__
#pragma implementation "controlbar.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 <math.h>
#include <stdlib.h>
#include "wx/string.h"
#include "wx/utils.h" // import wxMin,wxMax macros
#include "wx/minifram.h"
#include "wx/fl/controlbar.h"
// import classes of default plugins
#include "wx/fl/panedrawpl.h"
#include "wx/fl/rowlayoutpl.h"
#include "wx/fl/antiflickpl.h"
#include "wx/fl/bardragpl.h"
#include "wx/fl/cbcustom.h"
#include "wx/fl/gcupdatesmgr.h" // import default updates manager class ("garbage-collecting" one)
#include "wx/fl/updatesmgr.h"
#include "wx/fl/toolwnd.h"
// These are the event IDs being initialized to a value to
// meet the new event paradigm as of wx2.3.0. Probably we
// should find a way to make these be non-global, but this
// works for right now.
wxEventType cbEVT_PL_LEFT_DOWN = wxNewEventType();
wxEventType cbEVT_PL_LEFT_UP = wxNewEventType();
wxEventType cbEVT_PL_RIGHT_DOWN = wxNewEventType();
wxEventType cbEVT_PL_RIGHT_UP = wxNewEventType();
wxEventType cbEVT_PL_MOTION = wxNewEventType();
wxEventType cbEVT_PL_LEFT_DCLICK = wxNewEventType();
wxEventType cbEVT_PL_LAYOUT_ROW = wxNewEventType();
wxEventType cbEVT_PL_RESIZE_ROW = wxNewEventType();
wxEventType cbEVT_PL_LAYOUT_ROWS = wxNewEventType();
wxEventType cbEVT_PL_INSERT_BAR = wxNewEventType();
wxEventType cbEVT_PL_RESIZE_BAR = wxNewEventType();
wxEventType cbEVT_PL_REMOVE_BAR = wxNewEventType();
wxEventType cbEVT_PL_SIZE_BAR_WND = wxNewEventType();
wxEventType cbEVT_PL_DRAW_BAR_DECOR = wxNewEventType();
wxEventType cbEVT_PL_DRAW_ROW_DECOR = wxNewEventType();
wxEventType cbEVT_PL_DRAW_PANE_DECOR = wxNewEventType();
wxEventType cbEVT_PL_DRAW_BAR_HANDLES = wxNewEventType();
wxEventType cbEVT_PL_DRAW_ROW_HANDLES = wxNewEventType();
wxEventType cbEVT_PL_DRAW_ROW_BKGROUND = wxNewEventType();
wxEventType cbEVT_PL_DRAW_PANE_BKGROUND = wxNewEventType();
wxEventType cbEVT_PL_START_BAR_DRAGGING = wxNewEventType();
wxEventType cbEVT_PL_DRAW_HINT_RECT = wxNewEventType();
wxEventType cbEVT_PL_START_DRAW_IN_AREA = wxNewEventType();
wxEventType cbEVT_PL_FINISH_DRAW_IN_AREA = wxNewEventType();
wxEventType cbEVT_PL_CUSTOMIZE_BAR = wxNewEventType();
wxEventType cbEVT_PL_CUSTOMIZE_LAYOUT = wxNewEventType();
wxEventType wxCUSTOM_CB_PLUGIN_EVENTS_START_AT = wxNewEventType();
// some ascii-art, still can't get these *nice* cursors working on wx... :-(
static const char* _gHorizCursorImg[] =
{
"............XX....XX............",
"............XX....XX............",
"............XX....XX............",
"............XX....XX............",
"............XX....XX............",
"...X........XX....XX........X...",
"..XX........XX....XX........XX..",
".XXX........XX....XX........XXX.",
"XXXXXXXXXXXXXX....XXXXXXXXXXXXXX",
".XXX........XX....XX........XXX.",
"..XX........XX....XX........XX..",
"...X........XX....XX........X...",
"............XX....XX............",
"............XX....XX............",
"............XX....XX............",
"............XX....XX............"
};
static const char* _gVertCursorImg[] =
{
"................X...............",
"...............XXX..............",
"..............XXXXX.............",
".............XXXXXXX............",
"................X...............",
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"................................",
"................................",
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"................X...............",
".............XXXXXXX............",
"..............XXXXX.............",
"...............XXX..............",
"................X..............."
};
// helper inline functions
static inline bool rect_contains_point( const wxRect& rect, int x, int y )
{
return ( x >= rect.x &&
y >= rect.y &&
x < rect.x + rect.width &&
y < rect.y + rect.height );
}
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;
}
static inline void hide_rect( wxRect& r )
{
r.x = 32768;
r.y = 32768;
r.width = 1;
r.height = 1;
}
static inline void clip_rect_against_rect( wxRect& r1, const wxRect& r2 )
{
if ( r1.x < r2.x ||
r1.y < r2.y ||
r1.x >= r2.x + r2.width ||
r1.y >= r2.y + r2.height
)
{
hide_rect( r1 );
return;
}
else
{
if ( r1.x + r1.width > r2.x + r2.width )
r1.width = r2.x + r2.width - r1.x;
if ( r1.y + r1.height > r2.y + r2.height )
r1.height = r2.y + r2.height - r1.y;
}
}
/***** Implementation for class cbBarSpy *****/
IMPLEMENT_DYNAMIC_CLASS( cbBarSpy, wxEvtHandler )
cbBarSpy::cbBarSpy(void)
: mpLayout(0),
mpBarWnd(0)
{}
cbBarSpy::cbBarSpy( wxFrameLayout* pPanel )
: mpLayout(pPanel),
mpBarWnd(0)
{}
void cbBarSpy::SetBarWindow( wxWindow* pWnd )
{
mpBarWnd = pWnd;
}
bool cbBarSpy::ProcessEvent(wxEvent& event)
{
bool handled = wxEvtHandler::ProcessEvent( event );
int type = event.GetEventType();
if ( !handled && ( type == wxEVT_LEFT_DOWN ||
type == wxEVT_LEFT_DCLICK ) )
{
wxMouseEvent& mevent = *((wxMouseEvent*)&event);
int x = mevent.m_x;
int y = mevent.m_y;
mpBarWnd->ClientToScreen( &x, &y );
mpLayout->GetParentFrame().ScreenToClient( &x, &y );
mevent.m_x = x;
mevent.m_y = y;
// forwared not-handled event to frame-layout
if ( type == wxEVT_LEFT_DOWN )
{
//mpLayout->OnLButtonDown( mevent );
event.Skip();
}
else
mpLayout->OnLDblClick( mevent );
//event.Skip(FALSE);
}
return handled;
}
/***** Implementation for class wxFrameLayout *****/
IMPLEMENT_DYNAMIC_CLASS( wxFrameLayout, wxEvtHandler )
BEGIN_EVENT_TABLE( wxFrameLayout, wxEvtHandler )
EVT_PAINT ( wxFrameLayout::OnPaint )
EVT_SIZE ( wxFrameLayout::OnSize )
EVT_LEFT_DOWN ( wxFrameLayout::OnLButtonDown )
EVT_LEFT_UP ( wxFrameLayout::OnLButtonUp )
EVT_RIGHT_DOWN ( wxFrameLayout::OnRButtonDown )
EVT_RIGHT_UP ( wxFrameLayout::OnRButtonUp )
EVT_MOTION ( wxFrameLayout::OnMouseMove )
EVT_LEFT_DCLICK( wxFrameLayout::OnLDblClick )
EVT_IDLE ( wxFrameLayout::OnIdle )
EVT_SET_FOCUS ( wxFrameLayout::OnSetFocus )
EVT_KILL_FOCUS ( wxFrameLayout::OnKillFocus )
EVT_ACTIVATE ( wxFrameLayout::OnActivate )
EVT_ERASE_BACKGROUND( wxFrameLayout::OnEraseBackground )
END_EVENT_TABLE()
// FIXME:: how to eliminate these cut&pasted constructors?
wxFrameLayout::wxFrameLayout(void)
: mpFrame ( NULL ),
mpFrameClient( NULL ),
mDarkPen ( wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID ),
mLightPen ( wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT), 1, wxSOLID ),
mGrayPen ( wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE), 1, wxSOLID ),
mBlackPen ( wxColour( 0, 0, 0), 1, wxSOLID ),
mBorderPen( wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE), 1, wxSOLID ),
mNullPen( wxColour(0,0,0), 1, wxTRANSPARENT ),
mpPaneInFocus( NULL ),
mpLRUPane ( NULL ),
mpTopPlugin ( NULL ),
mpCaputesInput( NULL ),
mClientWndRefreshPending( FALSE ),
mRecalcPending( TRUE ),
mCheckFocusWhenIdle( FALSE )
{
CreateCursors();
int i;
for ( i = 0; i != MAX_PANES; ++i )
mPanes[i] = NULL;
mFloatingOn = CanReparent();
}
wxFrameLayout::wxFrameLayout( wxWindow* pParentFrame, wxWindow* pFrameClient, bool activateNow )
: mpFrame( pParentFrame ),
mpFrameClient(pFrameClient),
mDarkPen ( wxSystemSettings::GetColour(wxSYS_COLOUR_3DSHADOW), 1, wxSOLID ),
mLightPen ( wxSystemSettings::GetColour(wxSYS_COLOUR_3DHILIGHT), 1, wxSOLID ),
mGrayPen ( wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE), 1, wxSOLID ),
mBlackPen ( wxColour( 0, 0, 0), 1, wxSOLID ),
mBorderPen( wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE), 1, wxSOLID ),
mNullPen( wxColour(0,0,0), 1, wxTRANSPARENT ),
mpPaneInFocus( NULL ),
mpLRUPane ( NULL ),
mFloatingOn ( TRUE ),
mpTopPlugin ( NULL ),
mpCaputesInput( NULL ),
mClientWndRefreshPending( FALSE ),
mRecalcPending( TRUE ),
mCheckFocusWhenIdle( FALSE ),
mpUpdatesMgr( NULL )
{
CreateCursors();
int i;
for ( i = 0; i != MAX_PANES; ++i )
mPanes[i] = new cbDockPane( i, this );
if ( activateNow )
{
HookUpToFrame();
// FOR NOW::
// DBG:: set RED color of frame's background for the
// prurpose of tracking engine bugs "visually"
GetParentFrame().SetBackgroundColour( wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE) );
}
mFloatingOn = CanReparent();
}
// NOTE:: below are the only platform-check "ifdef"s in the docking system!
bool wxFrameLayout::CanReparent()
{
#ifdef __WXMSW__
return TRUE;
#elif defined (__WXGTK__)
//return TRUE;
return FALSE;
#else
return FALSE; // reparenting is not yet supported by Motif and others
#endif
}
/*
#ifdef __WXMSW__
#inlcude "windows.h"
#endif
*/
void wxFrameLayout::ReparentWindow( wxWindow* pChild, wxWindow* pNewParent )
{
#ifdef __WXMSW__
#if 0
if ( pChild->GetParent() )
{
bool success = pChild->GetParent()->GetChildren().DeleteObject( pChild );
wxASSERT( success ); // DBG::
}
::SetParent( (HWND)pChild->m_hWnd, (HWND)pNewParent->m_hWnd );
pNewParent->GetChildren().Append( pChild );
pChild->SetParent( pNewParent );
#endif
pChild->Reparent(pNewParent);
return;
#elif defined(__WXGTK__) || defined(__WXX11__)
// FOR NOW:: floating with wxGtk still very buggy
return;
//pChild->ReParent( pNewParent );
//return;
#else
wxMessageBox( "Sorry, docking is not supported for ports other than MSW and wxGTK" );
#endif
}
void wxFrameLayout::DestroyBarWindows()
{
wxNode* pSpy = mBarSpyList.First();
while( pSpy )
{
cbBarSpy& spy = *((cbBarSpy*)pSpy->Data());
if ( spy.mpBarWnd->GetEventHandler() == &spy )
spy.mpBarWnd->PopEventHandler();
delete &spy;
pSpy = pSpy->Next();
}
mBarSpyList.Clear();
size_t i;
for ( i = 0; i != mAllBars.Count(); ++i )
{
if ( mAllBars[i]->mpBarWnd )
{
mAllBars[i]->mpBarWnd->Destroy();
mAllBars[i]->mpBarWnd = NULL;
}
}
}
void wxFrameLayout::ShowFloatedWindows( bool show )
{
wxNode* pNode = mFloatedFrames.First();
while( pNode )
{
cbFloatedBarWindow* pFFrm = ((cbFloatedBarWindow*)pNode->Data());
pFFrm->Show( show );
pNode = pNode->Next();
}
}
wxFrameLayout::~wxFrameLayout()
{
UnhookFromFrame();
if ( mpUpdatesMgr )
delete mpUpdatesMgr;
PopAllPlugins();
// destoy the chain of plugins from left to right
wxEvtHandler* pCur = mpTopPlugin;
if ( pCur )
while ( pCur->GetPreviousHandler() )
pCur = pCur->GetPreviousHandler();
while ( pCur )
{
wxEvtHandler* pNext = pCur->GetNextHandler();
delete pCur;
pCur = pNext;
}
// destroy contents of arrays and lists
size_t i = 0;
for ( i = 0; i != MAX_PANES; ++i )
{
if ( mPanes[i] )
delete mPanes[i];
}
if ( mpHorizCursor )
delete mpHorizCursor;
if ( mpVertCursor )
delete mpVertCursor;
if ( mpNormalCursor )
delete mpNormalCursor;
if ( mpDragCursor )
delete mpDragCursor;
if ( mpNECursor )
delete mpNECursor;
wxNode* pSpy = mBarSpyList.First();
while( pSpy )
{
cbBarSpy& spy = *((cbBarSpy*)pSpy->Data());
if ( spy.mpBarWnd->GetEventHandler() == &spy )
spy.mpBarWnd->PopEventHandler();
delete &spy;
pSpy = pSpy->Next();
}
for ( i = 0; i != mAllBars.Count(); ++i )
delete mAllBars[i];
}
void wxFrameLayout::EnableFloating( bool enable )
{
mFloatingOn = enable && CanReparent();
}
void wxFrameLayout::Activate()
{
HookUpToFrame();
RefreshNow( TRUE );
ShowFloatedWindows( TRUE );
}
void wxFrameLayout::Deactivate()
{
ShowFloatedWindows( FALSE );
UnhookFromFrame();
HideBarWindows();
}
void wxFrameLayout::SetFrameClient( wxWindow* pFrameClient )
{
mpFrameClient = pFrameClient;
}
wxWindow* wxFrameLayout::GetFrameClient()
{
return mpFrameClient;
}
cbUpdatesManagerBase& wxFrameLayout::GetUpdatesManager()
{
if ( !mpUpdatesMgr )
mpUpdatesMgr = CreateUpdatesManager();
return *mpUpdatesMgr;
}
void wxFrameLayout::SetUpdatesManager( cbUpdatesManagerBase* pUMgr )
{
if ( mpUpdatesMgr )
delete mpUpdatesMgr;
mpUpdatesMgr = pUMgr;
mpUpdatesMgr->SetLayout( this );
}
cbUpdatesManagerBase* wxFrameLayout::CreateUpdatesManager()
{
return new cbGCUpdatesMgr( this );
//return new cbSimpleUpdatesMgr( this );
}
void wxFrameLayout::AddBar( wxWindow* pBarWnd,
const cbDimInfo& dimInfo,
int alignment,
int rowNo,
int columnPos,
const wxString& name,
bool spyEvents,
int state
)
{
if ( pBarWnd && spyEvents )
{
// hook up spy to bar window
cbBarSpy* pSpy = new cbBarSpy( this );
pSpy->SetBarWindow( pBarWnd );
pBarWnd->PushEventHandler( pSpy );
mBarSpyList.Append( pSpy );
}
cbBarInfo* pInfo = new cbBarInfo();
pInfo->mName = name;
pInfo->mpBarWnd = pBarWnd;
pInfo->mDimInfo = dimInfo;
pInfo->mState = state;
pInfo->mAlignment = alignment;
pInfo->mRowNo = rowNo;
pInfo->mBounds.x = columnPos;
mAllBars.Add( pInfo );
DoSetBarState( pInfo );
}
bool wxFrameLayout::RedockBar( cbBarInfo* pBar,
const wxRect& shapeInParent,
cbDockPane* pToPane,
bool updateNow )
{
if ( !pToPane )
pToPane = HitTestPanes( shapeInParent, NULL );
if ( !pToPane )
return FALSE; // bar's shape does not hit any pane
// - redocking is NOT possible
cbDockPane* pBarPane = GetBarPane( pBar );
if ( updateNow )
GetUpdatesManager().OnStartChanges();
pBarPane->RemoveBar( pBar );
// FIXME FIXME:: the recalculation below may be a *huge* performance
// hit, it could be eliminated though...
// but first the "pane-postion-changed" problem
// has to be fixed
RecalcLayout( FALSE );
pToPane->InsertBar( pBar, shapeInParent );
RecalcLayout( FALSE );
// finish update "transaction"
if ( updateNow )
{
GetUpdatesManager().OnFinishChanges();
GetUpdatesManager().UpdateNow();
}
return TRUE;
}
cbBarInfo* wxFrameLayout::FindBarByName( const wxString& name )
{
size_t i;
for ( i = 0; i != mAllBars.Count(); ++i )
if ( mAllBars[i]->mName == name )
return mAllBars[i];
return NULL;
}
cbBarInfo* wxFrameLayout::FindBarByWindow( const wxWindow* pWnd )
{
size_t i;
for ( i = 0; i != mAllBars.Count(); ++i )
if ( mAllBars[i]->mpBarWnd == pWnd )
return mAllBars[i];
return NULL;
}
BarArrayT& wxFrameLayout::GetBars()
{
return mAllBars;
}
void wxFrameLayout::SetBarState( cbBarInfo* pBar, int newState, bool updateNow )
{
if ( newState == wxCBAR_FLOATING && !mFloatingOn )
return;
if ( updateNow )
GetUpdatesManager().OnStartChanges();
pBar->mUMgrData.SetDirty(TRUE);
// check bar's previous state
if ( pBar->mState != wxCBAR_HIDDEN && pBar->mState != wxCBAR_FLOATING )
{
cbDockPane* pPane;
cbRowInfo* pRow;
bool success = LocateBar( pBar, &pRow, &pPane );
wxASSERT( success ); // DBG::
// save LRU-dim info before removing bar
pBar->mDimInfo.mLRUPane = pPane->GetAlignment();
pBar->mDimInfo.mBounds[ pPane->GetAlignment() ] = pBar->mBounds;
// remove it from the pane it was docked on
pPane->RemoveBar( pBar );
}
if ( pBar->mState == wxCBAR_FLOATING && newState != wxCBAR_FLOATING )
{
// remove bar's window from the containing mini-frame
// and set its parent to be layout's parent frame
if ( pBar->mpBarWnd )
{
pBar->mpBarWnd->Show(FALSE); // to avoid flicker upon reparenting
wxNode* pNode = mFloatedFrames.First();
while( pNode )
{
cbFloatedBarWindow* pFFrm = ((cbFloatedBarWindow*)pNode->Data());
if ( pFFrm->GetBar() == pBar )
{
pFFrm->Show( FALSE ); // reduces flicker sligthly
ReparentWindow( pBar->mpBarWnd, &GetParentFrame() );
pBar->mBounds = pBar->mDimInfo.mBounds[ pBar->mDimInfo.mLRUPane ];
if ( newState != wxCBAR_HIDDEN )
pBar->mAlignment = pBar->mDimInfo.mLRUPane;
mFloatedFrames.DeleteNode( pNode );
pFFrm->Show( FALSE );
pFFrm->Destroy(); break;
}
pNode = pNode->Next();
}
// FOR NOW:: excessive!
//if ( mpFrameClient ) mpFrameClient->Refresh();
if ( mpFrameClient )
mClientWndRefreshPending = TRUE;
}
}
if ( pBar->mDimInfo.GetDimHandler() )
{
pBar->mDimInfo.GetDimHandler()->OnChangeBarState( pBar, newState );
}
pBar->mState = newState;
DoSetBarState( pBar );
if ( updateNow )
{
RecalcLayout(FALSE);
GetUpdatesManager().OnFinishChanges();
GetUpdatesManager().UpdateNow();
}
}
void wxFrameLayout::InverseVisibility( cbBarInfo* pBar )
{
wxASSERT( pBar ); // DBG::
// "inverse" bar-visibility of the selected bar
int newState = 0;
if ( pBar->mState == wxCBAR_HIDDEN )
{
if ( pBar->mAlignment == -1 )
{
pBar->mAlignment = 0; // just remove "-1" marking
newState = wxCBAR_FLOATING;
}
else
if ( pBar->mAlignment == FL_ALIGN_TOP ||
pBar->mAlignment == FL_ALIGN_BOTTOM )
newState = wxCBAR_DOCKED_HORIZONTALLY;
else
newState = wxCBAR_DOCKED_VERTICALLY;
}
else
{
newState = wxCBAR_HIDDEN;
if ( pBar->mState == wxCBAR_FLOATING )
pBar->mAlignment = -1;
}
this->SetBarState( pBar, newState, TRUE );
if ( newState == wxCBAR_FLOATING )
this->RepositionFloatedBar( pBar );
}
void wxFrameLayout::ApplyBarProperties( cbBarInfo* pBar )
{
if ( pBar->mState == wxCBAR_FLOATING )
{
RepositionFloatedBar( pBar );
}
else
if ( pBar->mState == wxCBAR_DOCKED_HORIZONTALLY ||
pBar->mState == wxCBAR_DOCKED_VERTICALLY
)
{
// FOR NOW:: nothing
}
}
void wxFrameLayout::RepositionFloatedBar( cbBarInfo* pBar )
{
if ( !mFloatingOn ) return;
wxNode* pNode = mFloatedFrames.First();
while( pNode )
{
cbFloatedBarWindow* pFFrm = ((cbFloatedBarWindow*)pNode->Data());
if ( pFFrm->GetBar() == pBar )
{
wxRect& bounds = pBar->mDimInfo.mBounds[wxCBAR_FLOATING];
int x = bounds.x,
y = bounds.y;
GetParentFrame().ClientToScreen( &x, &y );
pFFrm->PositionFloatedWnd( x,y,
bounds.width,
bounds.height );
break;
}
pNode = pNode->Next();
}
}
void wxFrameLayout::DoSetBarState( cbBarInfo* pBar )
{
if ( pBar->mState != wxCBAR_FLOATING &&
pBar->mState != wxCBAR_HIDDEN )
// dock it
mPanes[pBar->mAlignment]->InsertBar( pBar );
else
if ( pBar->mState == wxCBAR_HIDDEN )
{
// hide it
if ( pBar->mpBarWnd )
pBar->mpBarWnd->Show( FALSE );
}
else
{
if ( !mFloatingOn ) return;
// float it
if ( pBar->mpBarWnd == NULL || !CanReparent() )
{
// FOR NOW:: just hide it
if ( pBar->mpBarWnd )
pBar->mpBarWnd->Show( FALSE );
pBar->mState = wxCBAR_HIDDEN;
return;
}
cbFloatedBarWindow* pMiniFrm = new cbFloatedBarWindow();
pMiniFrm->SetBar( pBar );
pMiniFrm->SetLayout( this );
pMiniFrm->Create( &GetParentFrame(), -1, pBar->mName,
wxPoint( 50,50 ),
wxSize ( 0, 0 ),
wxFRAME_FLOAT_ON_PARENT |
wxFRAME_TOOL_WINDOW |
wxFRAME_NO_TASKBAR
);
pMiniFrm->SetClient( pBar->mpBarWnd );
ReparentWindow( pBar->mpBarWnd, pMiniFrm );
mFloatedFrames.Append( pMiniFrm );
wxRect& bounds = pBar->mDimInfo.mBounds[wxCBAR_FLOATING];
// check if it wasn't floated anytime before
if ( bounds.width == -1 )
{
wxRect& clntRect = GetClientRect();
// adjust position into which the next floated bar will be placed
if ( mNextFloatedWndPos.x + bounds.width > clntRect.width )
mNextFloatedWndPos.x = mFloatingPosStep.x;
if ( mNextFloatedWndPos.y + bounds.height > clntRect.height )
mNextFloatedWndPos.y = mFloatingPosStep.y;
bounds.x = mNextFloatedWndPos.x + clntRect.x;
bounds.y = mNextFloatedWndPos.y + clntRect.y;
bounds.width = pBar->mDimInfo.mSizes[wxCBAR_FLOATING].x;
bounds.height = pBar->mDimInfo.mSizes[wxCBAR_FLOATING].y;
mNextFloatedWndPos.x += mFloatingPosStep.x;
mNextFloatedWndPos.y += mFloatingPosStep.y;
}
pMiniFrm->Show( TRUE );
// FIXME:: this is excessive
pBar->mpBarWnd->Show(TRUE);
}
}
void wxFrameLayout::RemoveBar( cbBarInfo* pBarInfo )
{
// first, try to "guess" what was the perviouse state of the bar
cbDockPane* pPane;
cbRowInfo* pRow;
if ( LocateBar( pBarInfo, &pRow, &pPane ) )
{
// ...aha, bar was docked into one of the panes,
// remove it from there
pPane->RemoveBar( pBarInfo );
}
size_t i;
for ( i = 0; i != mAllBars.Count(); ++i )
{
if ( mAllBars[i] == pBarInfo )
{
#if wxCHECK_VERSION(2,3,2)
mAllBars.RemoveAt(i);
#else
mAllBars.Remove(i);
#endif
if ( pBarInfo->mpBarWnd ) // hides it's window
pBarInfo->mpBarWnd->Show( FALSE );
delete pBarInfo;
return;
}
}
wxFAIL_MSG("bar info should be present in the list of all bars of all panes");
}
bool wxFrameLayout::LocateBar( cbBarInfo* pBarInfo,
cbRowInfo** ppRow,
cbDockPane** ppPane )
{
(*ppRow) = NULL;
(*ppPane) = NULL;
int n;
for ( n = 0; n != MAX_PANES; ++n )
{
wxBarIterator i( mPanes[n]->GetRowList() );
while ( i.Next() )
if ( &i.BarInfo() == pBarInfo )
{
(*ppPane) = mPanes[n];
(*ppRow ) = &i.RowInfo();
return TRUE;
}
}
return FALSE;
}
void wxFrameLayout::RecalcLayout( bool repositionBarsNow )
{
mRecalcPending = FALSE;
int frmWidth, frmHeight;
mpFrame->GetClientSize( &frmWidth, &frmHeight );
int paneHeight = 0;
int curY = 0;
int curX = 0;
wxRect rect;
// pane positioning priorities in decreasing order:
// top, bottom, left, right
// setup TOP pane
cbDockPane* pPane = mPanes[ FL_ALIGN_TOP ];
pPane->SetPaneWidth( frmWidth );
pPane->RecalcLayout();
paneHeight = pPane->GetPaneHeight();
rect.x = curX;
rect.y = curY;
rect.width = frmWidth;
rect.height = wxMin( paneHeight, frmHeight - curY );
pPane->SetBoundsInParent( rect );
curY += paneHeight;
// setup BOTTOM pane
pPane = mPanes[ FL_ALIGN_BOTTOM ];
pPane->SetPaneWidth( frmWidth );
pPane->RecalcLayout();
paneHeight = pPane->GetPaneHeight();
rect.x = curX;
rect.y = wxMax( frmHeight - paneHeight, curY );
rect.width = frmWidth;
rect.height = frmHeight - rect.y;
pPane->SetBoundsInParent( rect );
// setup LEFT pane
pPane = mPanes[ FL_ALIGN_LEFT ];
// bottom pane's y
pPane->SetPaneWidth( rect.y - curY );
pPane->RecalcLayout();
paneHeight = pPane->GetPaneHeight();
// bottom rect's y
rect.height = rect.y - curY;
rect.x = curX;
rect.y = curY;
rect.width = wxMin( paneHeight, frmWidth );
pPane->SetBoundsInParent( rect );
curX += rect.width;
// setup RIGHT pane
pPane = mPanes[ FL_ALIGN_RIGHT ];
// left pane's height
pPane->SetPaneWidth( rect.height );
pPane->RecalcLayout();
paneHeight = pPane->GetPaneHeight();
// left pane's height
rect.height = rect.height;
rect.x = wxMax( frmWidth - paneHeight, curX );
rect.y = curY;
rect.width = frmWidth - rect.x;
pPane->SetBoundsInParent( rect );
// recalc bounds of the client-window
mClntWndBounds.x = mPanes[FL_ALIGN_LEFT]->mBoundsInParent.x +
mPanes[FL_ALIGN_LEFT]->mBoundsInParent.width;
mClntWndBounds.y = mPanes[FL_ALIGN_TOP ]->mBoundsInParent.y +
mPanes[FL_ALIGN_TOP ]->mBoundsInParent.height;
mClntWndBounds.width = mPanes[FL_ALIGN_RIGHT]->mBoundsInParent.x -
mClntWndBounds.x;
mClntWndBounds.height = mPanes[FL_ALIGN_BOTTOM]->mBoundsInParent.y -
mClntWndBounds.y;
if ( repositionBarsNow )
PositionPanes();
}
int wxFrameLayout::GetClientHeight()
{
// for better portablility wxWindow::GetSzie() is not used here
return mClntWndBounds.height;
}
int wxFrameLayout::GetClientWidth()
{
// for better portablility wxWindow::GetSzie() is not used here
return mClntWndBounds.width;
}
void wxFrameLayout::PositionClientWindow()
{
if ( mpFrameClient )
{
if ( mClntWndBounds.width >= 1 && mClntWndBounds.height >= 1 )
{
mpFrameClient->SetSize( mClntWndBounds.x, mClntWndBounds.y,
mClntWndBounds.width, mClntWndBounds.height, 0 );
if ( !mpFrameClient->IsShown() )
mpFrameClient->Show( TRUE );
}
else
mpFrameClient->Show( FALSE );
}
}
void wxFrameLayout::PositionPanes()
{
PositionClientWindow();
// FOR NOW:: excessive updates!
// reposition bars within all panes
int i;
for ( i = 0; i != MAX_PANES; ++i )
mPanes[i]->SizePaneObjects();
}
void wxFrameLayout::OnSize( wxSizeEvent& event )
{
if ( event.GetEventObject() == (wxObject*) mpFrame )
{
GetUpdatesManager().OnStartChanges();
RecalcLayout(TRUE);
GetUpdatesManager().OnFinishChanges();
GetUpdatesManager().UpdateNow();
}
}
/*** protected members ***/
void wxFrameLayout::HideBarWindows()
{
size_t i;
for ( i = 0; i != mAllBars.Count(); ++i )
if ( mAllBars[i]->mpBarWnd && mAllBars[i]->mState != wxCBAR_FLOATING )
mAllBars[i]->mpBarWnd->Show( FALSE );
// then floated frames
ShowFloatedWindows( FALSE );
if ( mpFrameClient )
mpFrameClient->Show( FALSE );
}
void wxFrameLayout::UnhookFromFrame()
{
// NOTE:: the SetEvtHandlerEnabled() method is not used
// here, since it is assumed that unhooking layout
// from window may result destroying of the layout itself
//
// BUG BUG BUG (wx):: this would not be a problem if
// wxEvtHandler's destructor checked if
// this handler is currently the top-most
// handler of some window, and additionally
// to the reconnecting itself from the chain.
// It would also re-setup current event handler
// of the window using wxWindow::SetEventHandler()
// FOR NOW::
if ( mpFrame->GetEventHandler() == this )
{
mpFrame->PopEventHandler();
return;
}
if ( mpFrame )
{
if ( this == mpFrame->GetEventHandler() )
{
mpFrame->SetEventHandler( this->GetNextHandler() );
}
else
{
wxEvtHandler* pCur = mpFrame->GetEventHandler();
while ( pCur )
{
if ( pCur == this )
break;
pCur = pCur->GetNextHandler();
}
// do not try to unhook ourselves if we're not hooked yet
if ( !pCur )
return;
}
if ( GetPreviousHandler() )
GetPreviousHandler()->SetNextHandler( GetNextHandler() );
else
{
mpFrame->PopEventHandler();
return;
}
if ( GetNextHandler() )
GetNextHandler()->SetPreviousHandler( GetPreviousHandler() );
SetNextHandler( NULL );
SetPreviousHandler( NULL );
}
}
void wxFrameLayout::HookUpToFrame()
{
// unhook us first, we're already hooked up
UnhookFromFrame();
// put ourselves on top
mpFrame->PushEventHandler( this );
}
cbDockPane* wxFrameLayout::GetBarPane( cbBarInfo* pBar )
{
int i;
for ( i = 0; i != MAX_PANES; ++i )
if ( mPanes[i]->BarPresent( pBar ) )
return mPanes[i];
return NULL;
}
void wxFrameLayout::CreateCursors()
{
/*
// FIXME:: The below code somehow doesn't work - cursors remain unchanged
char bits[64];
set_cursor_bits( _gHorizCursorImg, bits, 32, 16 );
mpHorizCursor = new wxCursor( bits, 32, 16 );
set_cursor_bits( _gVertCursorImg, bits, 32, 16 );
mpVertCursor = new wxCursor( bits, 32, 16 );
*/
// FOR NOW:: use standard ones
mpHorizCursor = new wxCursor(wxCURSOR_SIZEWE);
mpVertCursor = new wxCursor(wxCURSOR_SIZENS);
mpNormalCursor = new wxCursor(wxCURSOR_ARROW );
mpDragCursor = new wxCursor(wxCURSOR_CROSS );
mpNECursor = new wxCursor(wxCURSOR_NO_ENTRY);
mFloatingPosStep.x = 25;
mFloatingPosStep.y = 25;
mNextFloatedWndPos.x = mFloatingPosStep.x;
mNextFloatedWndPos.y = mFloatingPosStep.y;
}
bool wxFrameLayout::HitTestPane( cbDockPane* pPane, int x, int y )
{
return rect_contains_point( pPane->GetRealRect(), x, y );
}
cbDockPane* wxFrameLayout::HitTestPanes( const wxRect& rect,
cbDockPane* pCurPane )
{
// first, give the privilege to the current pane
if ( pCurPane && rect_hits_rect( pCurPane->GetRealRect(), rect ) )
return pCurPane;
int i;
for ( i = 0; i != MAX_PANES; ++i )
{
if ( pCurPane != mPanes[i] &&
rect_hits_rect( mPanes[i]->GetRealRect(), rect ) )
{
return mPanes[i];
}
}
return 0;
}
void wxFrameLayout::ForwardMouseEvent( wxMouseEvent& event,
cbDockPane* pToPane,
int eventType )
{
wxPoint pos( event.m_x, event.m_y );
pToPane->FrameToPane( &pos.x, &pos.y );
if ( eventType == cbEVT_PL_LEFT_DOWN )
{
cbLeftDownEvent evt( pos, pToPane );
FirePluginEvent( evt );
}
else if ( eventType == cbEVT_PL_LEFT_DCLICK )
{
cbLeftDClickEvent evt( pos, pToPane );
FirePluginEvent( evt );
}
else if ( eventType == cbEVT_PL_LEFT_UP )
{
cbLeftUpEvent evt( pos, pToPane );
FirePluginEvent( evt );
}
else if ( eventType == cbEVT_PL_RIGHT_DOWN )
{
cbRightDownEvent evt( pos, pToPane );
FirePluginEvent( evt );
}
else if ( eventType == cbEVT_PL_RIGHT_UP )
{
cbRightUpEvent evt( pos, pToPane );
FirePluginEvent( evt );
}
else if ( eventType == cbEVT_PL_MOTION )
{
cbMotionEvent evt( pos, pToPane );
FirePluginEvent( evt );
}
else
{
int avoidCompilerWarning = 0;
wxASSERT(avoidCompilerWarning); // DBG::
}
} // wxFrameLayout::ForwardMouseEvent()
void wxFrameLayout::RouteMouseEvent( wxMouseEvent& event, int pluginEvtType )
{
if ( mpPaneInFocus )
ForwardMouseEvent( event, mpPaneInFocus, pluginEvtType );
else
{
int i;
for ( i = 0; i != MAX_PANES; ++i )
{
if ( HitTestPane( mPanes[i], event.m_x, event.m_y ) )
{
ForwardMouseEvent( event, mPanes[i], pluginEvtType );
return;
}
}
}
}
/*** event handlers ***/
void wxFrameLayout::OnRButtonDown( wxMouseEvent& event )
{
RouteMouseEvent( event, cbEVT_PL_RIGHT_DOWN );
}
void wxFrameLayout::OnRButtonUp( wxMouseEvent& event )
{
RouteMouseEvent( event, cbEVT_PL_RIGHT_UP );
}
void wxFrameLayout::OnLButtonDown( wxMouseEvent& event )
{
RouteMouseEvent( event, cbEVT_PL_LEFT_DOWN );
}
void wxFrameLayout::OnLDblClick( wxMouseEvent& event )
{
RouteMouseEvent( event, cbEVT_PL_LEFT_DCLICK );
}
void wxFrameLayout::OnLButtonUp( wxMouseEvent& event )
{
RouteMouseEvent( event, cbEVT_PL_LEFT_UP );
}
void wxFrameLayout::OnMouseMove( wxMouseEvent& event )
{
if ( mpPaneInFocus )
ForwardMouseEvent( event, mpPaneInFocus, cbEVT_PL_MOTION );
else
{
int i;
for ( i = 0; i != MAX_PANES; ++i )
{
if ( HitTestPane( mPanes[i], event.m_x, event.m_y ) )
{
if ( mpLRUPane && mpLRUPane != mPanes[i] )
{
// simulate "mouse-leave" event
ForwardMouseEvent( event, mpLRUPane, cbEVT_PL_MOTION );
}
ForwardMouseEvent( event, mPanes[i], cbEVT_PL_MOTION );
mpLRUPane = mPanes[i];
return;
}
}
}
if ( mpLRUPane )
{
// simulate "mouse-leave" event
ForwardMouseEvent( event, mpLRUPane, cbEVT_PL_MOTION );
mpLRUPane = 0;
}
}
void wxFrameLayout::OnPaint( wxPaintEvent& event )
{
if ( mRecalcPending )
RecalcLayout( TRUE );
wxPaintDC dc(mpFrame);
int i;
for ( i = 0; i != MAX_PANES; ++i )
{
wxRect& rect = mPanes[i]->mBoundsInParent;
dc.SetClippingRegion( rect.x, rect.y, rect.width, rect.height );
mPanes[i]->PaintPane(dc);
dc.DestroyClippingRegion();
}
event.Skip();
}
void wxFrameLayout::OnEraseBackground( wxEraseEvent& event )
{
// do nothing
}
void wxFrameLayout::OnIdle( wxIdleEvent& event )
{
wxWindow* focus = wxWindow::FindFocus();
if ( !focus && mCheckFocusWhenIdle )
{
wxMessageBox( "Hi, no more focus in this app!" );
mCheckFocusWhenIdle = FALSE;
//ShowFloatedWindows( FALSE );
}
mCheckFocusWhenIdle = FALSE;
event.Skip();
}
void wxFrameLayout::OnKillFocus( wxFocusEvent& event )
{
//wxMessageBox( "wxFrameLayoutGot Kill Focus!" );
//ShowFloatedWindows( FALSE );
}
void wxFrameLayout::OnSetFocus( wxFocusEvent& event )
{
//ShowFloatedWindows( TRUE );
}
void wxFrameLayout::OnActivate( wxActivateEvent& event )
{
#if 0
if ( event.GetActive() == FALSE )
{
wxWindow* focus = wxWindow::FindFocus();
if ( !focus || focus == &GetParentFrame() )
{
mCheckFocusWhenIdle = TRUE;
if ( !focus )
wxMessageBox("Deactivated!" );
}
}
#endif
}
void wxFrameLayout::GetPaneProperties( cbCommonPaneProperties& props, int alignment )
{
props = mPanes[alignment]->mProps;
}
void wxFrameLayout::SetPaneProperties( const cbCommonPaneProperties& props, int paneMask )
{
int i;
for ( i = 0; i != MAX_PANES; ++i )
{
if ( mPanes[i]->MatchesMask( paneMask ) )
mPanes[i]->mProps = props;
}
}
void wxFrameLayout::SetMargins( int top, int bottom, int left, int right,
int paneMask )
{
int i;
for ( i = 0; i != MAX_PANES; ++i )
{
cbDockPane& pane = *mPanes[i];
if ( pane.MatchesMask( paneMask ) )
{
pane.mTopMargin = top;
pane.mBottomMargin = bottom;
pane.mLeftMargin = left;
pane.mRightMargin = right;
}
}
}
void wxFrameLayout::SetPaneBackground( const wxColour& colour )
{
mBorderPen.SetColour( colour );
}
void wxFrameLayout::RefreshNow( bool recalcLayout )
{
if ( recalcLayout )
RecalcLayout( TRUE );
if ( mpFrame )
mpFrame->Refresh();
}
/*** plugin-related methods ***/
void wxFrameLayout::FirePluginEvent( cbPluginEvent& event )
{
// check state of input capture, before processing the event
if ( mpCaputesInput )
{
bool isInputEvt = TRUE;
#if wxCHECK_VERSION(2,3,0)
if ( event.m_eventType != cbEVT_PL_LEFT_DOWN &&
event.m_eventType != cbEVT_PL_LEFT_UP &&
event.m_eventType != cbEVT_PL_RIGHT_DOWN &&
event.m_eventType != cbEVT_PL_RIGHT_UP &&
event.m_eventType != cbEVT_PL_MOTION )
isInputEvt = FALSE;
#else
switch ( event.m_eventType )
{
case cbEVT_PL_LEFT_DOWN : break;
case cbEVT_PL_LEFT_UP : break;
case cbEVT_PL_RIGHT_DOWN : break;
case cbEVT_PL_RIGHT_UP : break;
case cbEVT_PL_MOTION : break;
default : isInputEvt = FALSE; break;
}
#endif // #if wxCHECK_VERSION(2,3,0)
if ( isInputEvt )
{
mpCaputesInput->ProcessEvent( event );
return;
}
}
GetTopPlugin().ProcessEvent( event );
}
void wxFrameLayout::CaptureEventsForPlugin ( cbPluginBase* pPlugin )
{
// cannot capture events for more than one plugin at a time
wxASSERT( mpCaputesInput == NULL );
mpCaputesInput = pPlugin;
}
void wxFrameLayout::ReleaseEventsFromPlugin( cbPluginBase* pPlugin )
{
// events should be captured first
wxASSERT( mpCaputesInput != NULL );
mpCaputesInput = NULL;
}
void wxFrameLayout::CaptureEventsForPane( cbDockPane* toPane )
{
// cannot capture events twice (without releasing)
wxASSERT( mpPaneInFocus == NULL );
mpFrame->CaptureMouse();
mpPaneInFocus = toPane;
}
void wxFrameLayout::ReleaseEventsFromPane( cbDockPane* fromPane )
{
// cannot release events without capturing them
wxASSERT( mpPaneInFocus != NULL );
mpFrame->ReleaseMouse();
mpPaneInFocus = NULL;
}
cbPluginBase& wxFrameLayout::GetTopPlugin()
{
if ( !mpTopPlugin )
PushDefaultPlugins(); // automatic configuration
return *mpTopPlugin;
}
void wxFrameLayout::SetTopPlugin( cbPluginBase* pPlugin )
{
mpTopPlugin = pPlugin;
}
bool wxFrameLayout::HasTopPlugin()
{
return ( mpTopPlugin != NULL );
}
void wxFrameLayout::PushPlugin( cbPluginBase* pPlugin )
{
if ( !mpTopPlugin )
mpTopPlugin = pPlugin;
else
{
pPlugin->SetNextHandler( mpTopPlugin );
mpTopPlugin->SetPreviousHandler( pPlugin );
mpTopPlugin = pPlugin;
}
mpTopPlugin->OnInitPlugin(); // notification
}
void wxFrameLayout::PopPlugin()
{
wxASSERT( mpTopPlugin ); // DBG:: at least one plugin should be present
cbPluginBase* pPopped = mpTopPlugin;
mpTopPlugin = (cbPluginBase*)mpTopPlugin->GetNextHandler();
delete pPopped;
}
void wxFrameLayout::PopAllPlugins()
{
while( mpTopPlugin ) PopPlugin();
}
void wxFrameLayout::PushDefaultPlugins()
{
// FIXME:: to much of the stuff for the default...
AddPlugin( CLASSINFO( cbRowLayoutPlugin ) );
AddPlugin( CLASSINFO( cbBarDragPlugin ) );
AddPlugin( CLASSINFO( cbPaneDrawPlugin ) );
}
void wxFrameLayout::AddPlugin( wxClassInfo* pPlInfo, int paneMask )
{
if ( FindPlugin ( pPlInfo ) ) return; // same type of plugin cannot be added twice
cbPluginBase* pObj = (cbPluginBase*)pPlInfo->CreateObject();
wxASSERT(pObj); // DBG:: plugin's class should be dynamic
pObj->mPaneMask = paneMask;
pObj->mpLayout = this;
PushPlugin( pObj );
}
void wxFrameLayout::AddPluginBefore( wxClassInfo* pNextPlInfo, wxClassInfo* pPlInfo,
int paneMask )
{
wxASSERT( pNextPlInfo != pPlInfo ); // DBG:: no sense
cbPluginBase* pNextPl = FindPlugin( pNextPlInfo );
if ( !pNextPl )
{
AddPlugin( pPlInfo, paneMask );
return;
}
// remove existing one if present
cbPluginBase* pExistingPl = FindPlugin( pPlInfo );
if ( pExistingPl ) RemovePlugin( pPlInfo );
// create an instance
cbPluginBase* pNewPl = (cbPluginBase*)pPlInfo->CreateObject();
wxASSERT(pNewPl); // DBG:: plugin's class should be dynamic
// insert it to the chain
if ( pNextPl->GetPreviousHandler() )
pNextPl->GetPreviousHandler()->SetNextHandler( pNewPl );
else
mpTopPlugin = pNewPl;
pNewPl->SetNextHandler( pNextPl );
pNewPl->SetPreviousHandler( pNextPl->GetPreviousHandler() );
pNextPl->SetPreviousHandler( pNewPl );
// set it up
pNewPl->mPaneMask = paneMask;
pNewPl->mpLayout = this;
pNewPl->OnInitPlugin();
}
void wxFrameLayout::RemovePlugin( wxClassInfo* pPlInfo )
{
cbPluginBase* pPlugin = FindPlugin( pPlInfo );
if ( !pPlugin ) return; // it's OK to remove not-existing plugin ;-)
if ( pPlugin->GetPreviousHandler() == NULL )
mpTopPlugin = (cbPluginBase*)pPlugin->GetNextHandler();
delete pPlugin;
}
cbPluginBase* wxFrameLayout::FindPlugin( wxClassInfo* pPlInfo )
{
cbPluginBase *pCur = mpTopPlugin;
while( pCur )
{
// NOTE:: it might appear useful matching plugin
// classes "polymorphically":
if ( pCur->GetClassInfo()->IsKindOf( pPlInfo ) )
return pCur;
pCur = (cbPluginBase*)pCur->GetNextHandler();
}
return NULL;
}
/***** Implementation for class cbUpdateMgrData *****/
IMPLEMENT_DYNAMIC_CLASS( cbUpdateMgrData, wxObject )
cbUpdateMgrData::cbUpdateMgrData()
: mPrevBounds( -1,-1,0,0 ),
mIsDirty( TRUE ) // inidicate initial change
{}
void cbUpdateMgrData::StoreItemState( const wxRect& boundsInParent )
{
mPrevBounds = boundsInParent;
}
void cbUpdateMgrData::SetDirty( bool isDirty )
{
mIsDirty = isDirty;
}
void cbUpdateMgrData::SetCustomData( wxObject* pCustomData )
{
mpCustomData = pCustomData;
}
/***** Implementation for class cbDockPane *****/
void wxBarIterator::Reset()
{
mpRow = ( mpRows->Count() ) ? (*mpRows)[0] : NULL;
mpBar = NULL;
}
wxBarIterator::wxBarIterator( RowArrayT& rows )
: mpRows( &rows ),
mpRow ( NULL ),
mpBar ( NULL )
{
Reset();
}
bool wxBarIterator::Next()
{
if ( mpRow )
{
if ( mpBar )
mpBar = mpBar->mpNext;
else
{
if ( mpRow->mBars.GetCount() == 0 )
{
return FALSE;
}
mpBar = mpRow->mBars[0];
}
if ( !mpBar )
{
// skip to the next row
mpRow = mpRow->mpNext;
if ( mpRow )
mpBar = mpRow->mBars[0];
else
return FALSE;
}
return TRUE;
}
else
return FALSE;
}
cbBarInfo& wxBarIterator::BarInfo()
{
return *mpBar;
}
cbRowInfo& wxBarIterator::RowInfo()
{
return *mpRow;
}
/***** Implementation for class cbBarDimHandlerBase *****/
IMPLEMENT_ABSTRACT_CLASS( cbBarDimHandlerBase, wxObject )
cbBarDimHandlerBase::cbBarDimHandlerBase()
: mRefCount(0)
{}
void cbBarDimHandlerBase::AddRef()
{
++mRefCount;
}
void cbBarDimHandlerBase::RemoveRef()
{
if ( --mRefCount <= 0 ) delete this;
}
/***** Implementation for class cbDimInfo *****/
IMPLEMENT_DYNAMIC_CLASS( cbDimInfo, wxObject )
cbDimInfo::cbDimInfo()
: mVertGap ( 0 ),
mHorizGap( 0 ),
mIsFixed(TRUE),
mpHandler( NULL )
{
size_t i;
for ( i = 0; i != MAX_BAR_STATES; ++i )
{
mSizes[i].x = 20;
mSizes[i].y = 20;
mBounds[i] = wxRect( -1,-1,-1,-1 );
}
}
cbDimInfo::cbDimInfo( cbBarDimHandlerBase* pDimHandler,
bool isFixed )
: mVertGap ( 0 ),
mHorizGap( 0 ),
mIsFixed ( isFixed ),
mpHandler( pDimHandler )
{
if ( mpHandler )
{
// int vtad = *((int*)mpHandler);
mpHandler->AddRef();
}
size_t i;
for ( i = 0; i != MAX_BAR_STATES; ++i )
{
mSizes[i].x = -1;
mSizes[i].y = -1;
mBounds[i] = wxRect( -1,-1,-1,-1 );
}
}
cbDimInfo::cbDimInfo( int dh_x, int dh_y,
int dv_x, int dv_y,
int f_x, int f_y,
bool isFixed,
int horizGap,
int vertGap,
cbBarDimHandlerBase* pDimHandler
)
: mVertGap ( vertGap ),
mHorizGap ( horizGap ),
mIsFixed ( isFixed ),
mpHandler( pDimHandler )
{
if ( mpHandler )
{
// int vtad = *((int*)mpHandler);
mpHandler->AddRef();
}
mSizes[wxCBAR_DOCKED_HORIZONTALLY].x = dh_x;
mSizes[wxCBAR_DOCKED_HORIZONTALLY].y = dh_y;
mSizes[wxCBAR_DOCKED_VERTICALLY ].x = dv_x;
mSizes[wxCBAR_DOCKED_VERTICALLY ].y = dv_y;
mSizes[wxCBAR_FLOATING ].x = f_x;
mSizes[wxCBAR_FLOATING ].y = f_y;
size_t i;
for ( i = 0; i != MAX_BAR_STATES; ++i )
mBounds[i] = wxRect( -1,-1,-1,-1 );
}
cbDimInfo::cbDimInfo( int x, int y,
bool isFixed, int gap,
cbBarDimHandlerBase* pDimHandler)
: mVertGap ( gap ),
mHorizGap ( gap ),
mIsFixed ( isFixed ),
mpHandler( pDimHandler )
{
if ( mpHandler )
{
// int vtad = *((int*)mpHandler);
mpHandler->AddRef();
}
mSizes[wxCBAR_DOCKED_HORIZONTALLY].x = x;
mSizes[wxCBAR_DOCKED_HORIZONTALLY].y = y;
mSizes[wxCBAR_DOCKED_VERTICALLY ].x = x;
mSizes[wxCBAR_DOCKED_VERTICALLY ].y = y;
mSizes[wxCBAR_FLOATING ].x = x;
mSizes[wxCBAR_FLOATING ].y = y;
size_t i;
for ( i = 0; i != MAX_BAR_STATES; ++i )
mBounds[i] = wxRect( -1,-1,-1,-1 );
}
cbDimInfo::~cbDimInfo()
{
if ( mpHandler )
mpHandler->RemoveRef();
}
const cbDimInfo& cbDimInfo::operator=( const cbDimInfo& other )
{
if ( this == &other )
return *this;
int i;
for ( i = 0; i != MAX_BAR_STATES; ++i )
mSizes[i] = other.mSizes[i];
mIsFixed = other.mIsFixed;
mpHandler = other.mpHandler;
mVertGap = other.mVertGap;
mHorizGap = other.mHorizGap;
if ( mpHandler )
mpHandler->AddRef();
return *this;
}
/***** Implementation for structure cbCommonPaneProperties *****/
IMPLEMENT_DYNAMIC_CLASS( cbCommonPaneProperties, wxObject )
cbCommonPaneProperties::cbCommonPaneProperties(void)
: mRealTimeUpdatesOn ( TRUE ),
mOutOfPaneDragOn ( TRUE ),
mExactDockPredictionOn( FALSE ),
mNonDestructFrictionOn( FALSE ),
mShow3DPaneBorderOn ( TRUE ),
mBarFloatingOn ( FALSE ),
mRowProportionsOn ( FALSE ),
mColProportionsOn ( TRUE ),
mBarCollapseIconsOn ( FALSE ),
mBarDragHintsOn ( FALSE ),
mMinCBarDim( 16, 16 ),
mResizeHandleSize( 4 )
{}
cbCommonPaneProperties::cbCommonPaneProperties(const cbCommonPaneProperties& props)
: wxObject(),
mRealTimeUpdatesOn (props.mRealTimeUpdatesOn),
mOutOfPaneDragOn (props.mOutOfPaneDragOn),
mExactDockPredictionOn(props.mExactDockPredictionOn),
mNonDestructFrictionOn(props.mNonDestructFrictionOn),
mShow3DPaneBorderOn (props.mShow3DPaneBorderOn),
mBarFloatingOn (props.mBarFloatingOn),
mRowProportionsOn (props.mRowProportionsOn),
mColProportionsOn (props.mColProportionsOn),
mBarCollapseIconsOn (props.mBarCollapseIconsOn),
mBarDragHintsOn (props.mBarDragHintsOn),
mMinCBarDim(props.mMinCBarDim),
mResizeHandleSize(props.mResizeHandleSize)
{}
cbCommonPaneProperties& cbCommonPaneProperties::operator=(const cbCommonPaneProperties& props)
{
mRealTimeUpdatesOn = props.mRealTimeUpdatesOn;
mOutOfPaneDragOn = props.mOutOfPaneDragOn;
mExactDockPredictionOn = props.mExactDockPredictionOn;
mNonDestructFrictionOn = props.mNonDestructFrictionOn;
mShow3DPaneBorderOn = props.mShow3DPaneBorderOn;
mBarFloatingOn = props.mBarFloatingOn;
mRowProportionsOn = props.mRowProportionsOn;
mColProportionsOn = props.mColProportionsOn;
mBarCollapseIconsOn = props.mBarCollapseIconsOn;
mBarDragHintsOn = props.mBarDragHintsOn;
mMinCBarDim = props.mMinCBarDim;
mResizeHandleSize = props.mResizeHandleSize;
return *this;
}
/***** Implementation for class cbRowInfo *****/
IMPLEMENT_DYNAMIC_CLASS( cbRowInfo, wxObject )
cbRowInfo::cbRowInfo(void)
: mNotFixedBarsCnt( FALSE ),
mpNext ( NULL ),
mpPrev ( NULL ),
mpExpandedBar ( NULL )
{}
cbRowInfo::~cbRowInfo()
{
// nothing! all bars are removed using global bar
// list in wxFrameLayout class
}
/***** Implementation for class cbBarInfo *****/
IMPLEMENT_DYNAMIC_CLASS( cbBarInfo, wxObject )
cbBarInfo::cbBarInfo(void)
: mpRow( NULL ),
mpNext( NULL ),
mpPrev( NULL )
{}
cbBarInfo::~cbBarInfo()
{
// nothing
}
/***** Implementation for class cbDockPane *****/
IMPLEMENT_DYNAMIC_CLASS( cbDockPane, wxObject )
// FIXME:: how to eliminate these cut&pasted constructors?
cbDockPane::cbDockPane(void)
: mLeftMargin ( 1 ),
mRightMargin ( 1 ),
mTopMargin ( 1 ),
mBottomMargin( 1 ),
mPaneWidth ( 32768 ), // fake-up very large pane dims,
// since the real dimensions of the pane may not
// be known, while inserting bars initially
mPaneHeight( 32768 ),
mAlignment ( -1 ),
mpLayout ( 0 ),
mpStoredRow( NULL )
{}
cbDockPane::cbDockPane( int alignment, wxFrameLayout* pPanel )
: mLeftMargin ( 1 ),
mRightMargin ( 1 ),
mTopMargin ( 1 ),
mBottomMargin( 1 ),
mPaneWidth ( 32768 ), // fake-up very large pane dims,
// since the real dimensions of the pane may not
// be known, while inserting bars initially
mPaneHeight( 32768 ),
mAlignment ( alignment ),
mpLayout ( pPanel ),
mpStoredRow( NULL )
{}
cbDockPane::~cbDockPane()
{
size_t i;
for ( i = 0; i != mRows.Count(); ++i )
delete mRows[i];
mRowShapeData.DeleteContents( TRUE );
// NOTE:: control bar infromation structures are cleaned-up
// in wxFrameLayout's destructor, using global control-bar list
}
void cbDockPane::SetMargins( int top, int bottom, int left, int right )
{
mTopMargin = top;
mBottomMargin = bottom;
mLeftMargin = left;
mRightMargin = right;
}
/*** helpers of cbDockPane ***/
void cbDockPane::PaintBarDecorations( cbBarInfo* pBar, wxDC& dc )
{
cbDrawBarDecorEvent evt( pBar, dc, this );
mpLayout->FirePluginEvent( evt );
}
void cbDockPane::PaintBarHandles( cbBarInfo* pBar, wxDC& dc )
{
cbDrawBarHandlesEvent evt( pBar, dc, this );
mpLayout->FirePluginEvent( evt );
}
void cbDockPane::PaintBar( cbBarInfo* pBar, wxDC& dc )
{
PaintBarDecorations( pBar, dc );
PaintBarHandles( pBar, dc );
}
void cbDockPane::PaintRowHandles( cbRowInfo* pRow, wxDC& dc )
{
cbDrawRowHandlesEvent evt( pRow, dc, this );
mpLayout->FirePluginEvent( evt );
cbDrawRowDecorEvent evt1( pRow, dc, this );
mpLayout->FirePluginEvent( evt1 );
}
void cbDockPane::PaintRowBackground ( cbRowInfo* pRow, wxDC& dc )
{
cbDrawRowBkGroundEvent evt( pRow, dc, this );
mpLayout->FirePluginEvent( evt );
}
void cbDockPane::PaintRowDecorations( cbRowInfo* pRow, wxDC& dc )
{
size_t i = 0;
// decorations first
for ( i = 0; i != pRow->mBars.Count(); ++i )
PaintBarDecorations( pRow->mBars[i], dc );
// then handles if present
for ( i = 0; i != pRow->mBars.Count(); ++i )
PaintBarHandles( pRow->mBars[i], dc );
}
void cbDockPane::PaintRow( cbRowInfo* pRow, wxDC& dc )
{
PaintRowBackground ( pRow, dc );
PaintRowDecorations( pRow, dc );
PaintRowHandles ( pRow, dc );
}
void cbDockPane::PaintPaneBackground( wxDC& dc )
{
cbDrawPaneBkGroundEvent evt( dc, this );
mpLayout->FirePluginEvent( evt );
}
void cbDockPane::PaintPaneDecorations( wxDC& dc )
{
cbDrawPaneDecorEvent evt( dc, this );
mpLayout->FirePluginEvent( evt );
}
void cbDockPane::PaintPane( wxDC& dc )
{
PaintPaneBackground( dc );
size_t i = 0;
// first decorations
for ( i = 0; i != mRows.Count(); ++i )
{
PaintRowBackground( mRows[i], dc );
PaintRowDecorations( mRows[i], dc );
}
// than handles
for ( i = 0; i != mRows.Count(); ++i )
PaintRowHandles( mRows[i], dc );
// and finally
PaintPaneDecorations( dc );
}
void cbDockPane::SizeBar( cbBarInfo* pBar )
{
cbSizeBarWndEvent evt( pBar, this );
mpLayout->FirePluginEvent( evt );
return;
}
void cbDockPane::SizeRowObjects( cbRowInfo* pRow )
{
size_t i;
for ( i = 0; i != pRow->mBars.Count(); ++i )
SizeBar( pRow->mBars[i] );
}
void cbDockPane::SizePaneObjects()
{
size_t i;
for ( i = 0; i != mRows.Count(); ++i )
SizeRowObjects( mRows[i] );
}
wxDC* cbDockPane::StartDrawInArea( const wxRect& area )
{
wxDC* pDc = 0;
cbStartDrawInAreaEvent evt( area, &pDc, this );
mpLayout->FirePluginEvent( evt );
return pDc;
}
void cbDockPane::FinishDrawInArea( const wxRect& area )
{
cbFinishDrawInAreaEvent evt( area, this );
mpLayout->FirePluginEvent( evt );
}
bool cbDockPane::IsFixedSize( cbBarInfo* pInfo )
{
return ( pInfo->mDimInfo.mIsFixed );
}
int cbDockPane::GetNotFixedBarsCount( cbRowInfo* pRow )
{
int cnt = 0;
size_t i;
for ( i = 0; i != pRow->mBars.Count(); ++i )
{
if ( !pRow->mBars[i]->IsFixed() )
++cnt;
}
return cnt;
}
void cbDockPane::RemoveBar( cbBarInfo* pBar )
{
bool needsRestoring = mProps.mNonDestructFrictionOn &&
mpStoredRow == pBar->mpRow;
cbRemoveBarEvent evt( pBar, this );
mpLayout->FirePluginEvent( evt );
if ( needsRestoring )
{
SetRowShapeData( mpStoredRow, &mRowShapeData );
mpStoredRow = NULL;
}
}
void cbDockPane::SyncRowFlags( cbRowInfo* pRow )
{
// setup mHasOnlyFixedBars flag for the row information
pRow->mHasOnlyFixedBars = TRUE;
pRow->mNotFixedBarsCnt = 0;
size_t i;
for ( i = 0; i != pRow->mBars.Count(); ++i )
{
cbBarInfo& bar = *pRow->mBars[i];
bar.mpRow = pRow;
if ( !bar.IsFixed() )
{
pRow->mHasOnlyFixedBars = FALSE;
++pRow->mNotFixedBarsCnt;
}
}
}
void cbDockPane::FrameToPane( int* x, int* y )
{
*x -= mLeftMargin;
*y -= mTopMargin;
if ( mAlignment == FL_ALIGN_TOP ||
mAlignment == FL_ALIGN_BOTTOM
)
{
*x -= mBoundsInParent.x;
*y -= mBoundsInParent.y;
}
else
{
int rx = *x, ry = *y;
*x = ry - mBoundsInParent.y;
*y = rx - mBoundsInParent.x;
}
}
void cbDockPane::PaneToFrame( int* x, int* y )
{
if ( mAlignment == FL_ALIGN_TOP ||
mAlignment == FL_ALIGN_BOTTOM
)
{
*x += mBoundsInParent.x;
*y += mBoundsInParent.y;
}
else
{
int rx = *x, ry = *y;
*x = ry + mBoundsInParent.x;
*y = mBoundsInParent.y + rx;
}
*x += mLeftMargin;
*y += mTopMargin;
}
void cbDockPane::FrameToPane( wxRect* pRect )
{
wxPoint upperLeft ( pRect->x, pRect->y );
wxPoint lowerRight( pRect->x + pRect->width,
pRect->y + pRect->height );
FrameToPane( &upperLeft.x, &upperLeft.y );
FrameToPane( &lowerRight.x, &lowerRight.y );
pRect->x = wxMin(upperLeft.x,lowerRight.x);
pRect->y = wxMin(upperLeft.y,lowerRight.y);
pRect->width = abs( lowerRight.x - upperLeft.x );
pRect->height = abs( lowerRight.y - upperLeft.y );
}
void cbDockPane::PaneToFrame( wxRect* pRect )
{
wxPoint upperLeft ( pRect->x, pRect->y );
wxPoint lowerRight( pRect->x + pRect->width,
pRect->y + pRect->height );
PaneToFrame( &upperLeft.x, &upperLeft.y );
PaneToFrame( &lowerRight.x, &lowerRight.y );
//wxRect newRect = wxRect( upperLeft, lowerRight );
pRect->x = wxMin(upperLeft.x,lowerRight.x);
pRect->y = wxMin(upperLeft.y,lowerRight.y);
pRect->width = abs( lowerRight.x - upperLeft.x );
pRect->height = abs( lowerRight.y - upperLeft.y );
}
int cbDockPane::GetRowAt( int paneY )
{
if ( paneY < 0 )
return -1;
int curY = 0;
size_t i = 0;
for ( ; i != mRows.Count(); ++i )
{
int rowHeight = mRows[i]->mRowHeight;
int third = rowHeight/3;
if ( paneY >= curY && paneY < curY + third )
return i-1;
if ( paneY >= curY + third && paneY < curY + rowHeight - third )
return i;
curY += rowHeight;
}
return i;
}
int cbDockPane::GetRowAt( int upperY, int lowerY )
{
/*
// OLD STUFF::
int range = lowerY - upperY;
int oneThird = range / 3;
wxNode* pRow = mRows.First();
int row = 0;
int curY = 0;
if ( lowerY <= 0 ) return -1;
while( pRow )
{
int rowHeight = GetRowHeight( (wxList*)pRow->Data() );
if ( upperY >= curY &&
lowerY < curY ) return row;
if ( upperY <= curY &&
lowerY >= curY &&
curY - upperY >= oneThird ) return row-1;
if ( ( upperY < curY + rowHeight &&
lowerY >= curY + rowHeight &&
curY + rowHeight - lowerY >= oneThird )
)
return row+1;
if ( lowerY <= curY + rowHeight ) return row;
++row;
curY += rowHeight;
pRow = pRow->Next();
}
*/
int mid = upperY + (lowerY - upperY)/2;
if ( mid < 0 )
return -1;
int curY = 0;
size_t i = 0;
for ( ; i != mRows.Count(); ++i )
{
int rowHeight = mRows[i]->mRowHeight;
if ( mid >= curY && mid < curY + rowHeight ) return i;
curY += rowHeight;
}
return i;
}
int cbDockPane::GetRowY( cbRowInfo* pRow )
{
int curY = 0;
size_t i;
for ( i = 0; i != mRows.Count(); ++i )
{
if ( mRows[i] == pRow )
break;
curY += mRows[i]->mRowHeight;
}
return curY;
}
bool cbDockPane::HasNotFixedRowsAbove( cbRowInfo* pRow )
{
while ( pRow->mpPrev )
{
pRow = pRow->mpPrev;
if ( pRow->mHasOnlyFixedBars )
return TRUE;
}
return FALSE;
}
bool cbDockPane::HasNotFixedRowsBelow( cbRowInfo* pRow )
{
while( pRow->mpNext )
{
pRow = pRow->mpNext;
if ( pRow->mHasOnlyFixedBars )
return TRUE;
}
return FALSE;
}
bool cbDockPane::HasNotFixedBarsLeft( cbBarInfo* pBar )
{
while( pBar->mpPrev )
{
pBar = pBar->mpPrev;
if ( pBar->IsFixed() )
return TRUE;
}
return FALSE;
}
bool cbDockPane::HasNotFixedBarsRight( cbBarInfo* pBar )
{
while( pBar->mpNext )
{
pBar = pBar->mpNext;
if ( pBar->IsFixed() )
return TRUE;
}
return FALSE;
}
void cbDockPane::CalcLengthRatios( cbRowInfo* pInRow )
{
int totalWidth = 0;
size_t i = 0;
// calc current-maximal-total-length of all maximized bars
for ( i = 0; i != pInRow->mBars.GetCount(); ++i )
{
cbBarInfo& bar = *pInRow->mBars[i];
if ( !bar.IsFixed() )
totalWidth += bar.mBounds.width;
}
// set up percentages of occupied space for each maximized bar
for ( i = 0; i != pInRow->mBars.Count(); ++i )
{
cbBarInfo& bar = *pInRow->mBars[i];
if ( !bar.IsFixed() )
bar.mLenRatio = double(bar.mBounds.width)/double(totalWidth);
}
}
void cbDockPane::RecalcRowLayout( cbRowInfo* pRow )
{
cbLayoutRowEvent evt( pRow, this );
mpLayout->FirePluginEvent( evt );
}
void cbDockPane::ExpandBar( cbBarInfo* pBar )
{
mpLayout->GetUpdatesManager().OnStartChanges();
if ( !pBar->mpRow->mpExpandedBar )
{
// save ratios only when there arent any bars expanded yet
cbArrayFloat& ratios = pBar->mpRow->mSavedRatios;
ratios.Clear();
ratios.Alloc( pBar->mpRow->mNotFixedBarsCnt );
cbBarInfo* pCur = pBar->mpRow->mBars[0];
while( pCur )
{
if ( !pCur->IsFixed() )
{
ratios.Add( 0.0 );
ratios[ ratios.GetCount() - 1 ] = pCur->mLenRatio;
}
pCur = pCur->mpNext;
}
}
cbBarInfo* pCur = pBar->mpRow->mBars[0];
while( pCur )
{
pCur->mLenRatio = 0.0; // minimize the rest
pCur = pCur->mpNext;
}
pBar->mLenRatio = 1.0; // 100%
pBar->mBounds.width = 0;
pBar->mpRow->mpExpandedBar = pBar;
mpLayout->RecalcLayout( FALSE );
mpLayout->GetUpdatesManager().OnFinishChanges();
mpLayout->GetUpdatesManager().UpdateNow();
}
void cbDockPane::ContractBar( cbBarInfo* pBar )
{
mpLayout->GetUpdatesManager().OnStartChanges();
// FIXME: What's the purpose of this???
// double ratio = 1.0/ double( pBar->mpRow->mNotFixedBarsCnt );
// restore ratios which were present before expansion
cbBarInfo* pCur = pBar->mpRow->mBars[0];
cbArrayFloat& ratios = pBar->mpRow->mSavedRatios;
size_t i = 0;
while( pCur )
{
if ( !pCur->IsFixed() )
{
pCur->mLenRatio = ratios[i];
++i;
}
pCur = pCur->mpNext;
}
ratios.Clear();
ratios.Shrink();
pBar->mpRow->mpExpandedBar = NULL;
mpLayout->RecalcLayout( FALSE );
mpLayout->GetUpdatesManager().OnFinishChanges();
mpLayout->GetUpdatesManager().UpdateNow();
}
void cbDockPane::InitLinksForRow( cbRowInfo* pRow )
{
size_t i;
for ( i = 0; i != pRow->mBars.Count(); ++i )
{
cbBarInfo& bar = *pRow->mBars[i];
if ( i == 0 )
bar.mpPrev = NULL;
else
bar.mpPrev = pRow->mBars[i-1];
if ( i == pRow->mBars.Count() - 1 )
bar.mpNext = NULL;
else
bar.mpNext = pRow->mBars[i+1];
}
}
void cbDockPane::InitLinksForRows()
{
size_t i;
for ( i = 0; i != mRows.Count(); ++i )
{
cbRowInfo& row = *mRows[i];
if ( i == 0 )
row.mpPrev = NULL;
else
row.mpPrev = mRows[i-1];
if ( i == mRows.Count() - 1 )
row.mpNext = NULL;
else
row.mpNext = mRows[i+1];
}
}
void cbDockPane::DoInsertBar( cbBarInfo* pBar, int rowNo )
{
cbRowInfo* pRow = NULL;
if ( rowNo == -1 || rowNo >= (int)mRows.Count() )
{
pRow = new cbRowInfo();
if ( rowNo == -1 && mRows.Count() )
mRows.Insert( pRow, 0 );
else
mRows.Add( pRow );
InitLinksForRows();
}
else
{
pRow = mRows[rowNo];
if ( mProps.mNonDestructFrictionOn == TRUE )
{
// store original shape of the row (before the bar is inserted)
mpStoredRow = pRow;
GetRowShapeData( mpStoredRow, &mRowShapeData );
}
}
if ( pRow->mBars.Count() )
pRow->mpExpandedBar = NULL;
cbInsertBarEvent insEvt( pBar, pRow, this );
mpLayout->FirePluginEvent( insEvt );
mpLayout->GetUpdatesManager().OnRowWillChange( pRow, this );
}
void cbDockPane::InsertBar( cbBarInfo* pBarInfo, const wxRect& atRect )
{
wxRect rect = atRect;
FrameToPane( &rect );
pBarInfo->mBounds.x = rect.x;
pBarInfo->mBounds.width = rect.width;
pBarInfo->mBounds.height = rect.height;
int row = GetRowAt( rect.y, rect.y + rect.height );
DoInsertBar( pBarInfo, row );
}
void cbDockPane::InsertBar( cbBarInfo* pBar, cbRowInfo* pIntoRow )
{
cbInsertBarEvent insEvt( pBar, pIntoRow, this );
mpLayout->FirePluginEvent( insEvt );
mpLayout->GetUpdatesManager().OnRowWillChange( pIntoRow, this );
}
void cbDockPane::InsertBar( cbBarInfo* pBarInfo )
{
// set transient properties
pBarInfo->mpRow = NULL;
pBarInfo->mHasLeftHandle = FALSE;
pBarInfo->mHasRightHandle = FALSE;
pBarInfo->mLenRatio = 0.0;
// set preferred bar dimensions, according to the state in which
// the bar is being inserted
pBarInfo->mBounds.width = pBarInfo->mDimInfo.mSizes[ pBarInfo->mState ].x;
pBarInfo->mBounds.height = pBarInfo->mDimInfo.mSizes[ pBarInfo->mState ].y;
DoInsertBar( pBarInfo, pBarInfo->mRowNo );
}
void cbDockPane::RemoveRow( cbRowInfo* pRow )
{
size_t i;
// first, hide all bar-windows in the removed row
for ( i = 0; i != pRow->mBars.Count(); ++i )
{
if ( pRow->mBars[i]->mpBarWnd )
pRow->mBars[i]->mpBarWnd->Show( FALSE );
}
mRows.Remove( pRow );
pRow->mUMgrData.SetDirty(TRUE);
}
void cbDockPane::InsertRow( cbRowInfo* pRow, cbRowInfo* pBeforeRow )
{
if ( !pBeforeRow )
mRows.Add( pRow );
else
mRows.Insert( pRow, mRows.Index( pBeforeRow ) );
InitLinksForRows();
pRow->mUMgrData.SetDirty(TRUE);
size_t i;
for ( i = 0; i != pRow->mBars.Count(); ++i )
pRow->mBars[i]->mUMgrData.SetDirty( TRUE );
SyncRowFlags( pRow );
}
void cbDockPane::SetPaneWidth(int width)
{
if ( IsHorizontal() )
mPaneWidth = width - mLeftMargin - mRightMargin;
else
mPaneWidth = width - mTopMargin - mBottomMargin;
}
void cbDockPane::SetBoundsInParent( const wxRect& rect )
{
mBoundsInParent = rect;
// set pane dimensions in local coordinates
if ( IsHorizontal() )
{
mPaneWidth = mBoundsInParent.width - ( mRightMargin + mLeftMargin );
mPaneHeight = mBoundsInParent.height - ( mTopMargin + mBottomMargin );
}
else
{
mPaneWidth = mBoundsInParent.height - ( mTopMargin + mBottomMargin );
mPaneHeight = mBoundsInParent.width - ( mRightMargin + mLeftMargin );
}
// convert bounding rectangles of all pane items into parent frame's coordinates
wxBarIterator i( mRows );
wxRect noMarginsRect = mBoundsInParent;
noMarginsRect.x += mLeftMargin;
noMarginsRect.y += mTopMargin;
noMarginsRect.width -= ( mLeftMargin + mRightMargin );
noMarginsRect.height -= ( mTopMargin + mBottomMargin );
// hide the whole pane, if it's bounds became reverted (i.e. pane vanished)
if ( mBoundsInParent.width < 0 ||
mBoundsInParent.height < 0 )
hide_rect( mBoundsInParent );
if ( noMarginsRect.width < 0 ||
noMarginsRect.height < 0 )
hide_rect( noMarginsRect );
// calculate mBoundsInParent for each item in the pane
while( i.Next() )
{
cbBarInfo& bar = i.BarInfo();
cbRowInfo* pRowInfo = bar.mpRow;
// set up row info, if this is first bar in the row
if ( pRowInfo && bar.mpPrev == NULL )
{
pRowInfo->mBoundsInParent.y = pRowInfo->mRowY;
pRowInfo->mBoundsInParent.x = 0;
pRowInfo->mBoundsInParent.width = mPaneWidth;
pRowInfo->mBoundsInParent.height = pRowInfo->mRowHeight;
PaneToFrame( &pRowInfo->mBoundsInParent );
clip_rect_against_rect( pRowInfo->mBoundsInParent, noMarginsRect );
}
wxRect bounds = bar.mBounds;
// exclude dimensions of handles, when calculating
// bar's bounds in parent (i.e. "visual bounds")
if ( bar.mHasLeftHandle )
{
bounds.x += mProps.mResizeHandleSize;
bounds.width -= mProps.mResizeHandleSize;
}
if ( bar.mHasRightHandle )
bounds.width -= mProps.mResizeHandleSize;
PaneToFrame( &bounds );
clip_rect_against_rect( bounds, noMarginsRect );
bar.mBoundsInParent = bounds;
}
}
bool cbDockPane::BarPresent( cbBarInfo* pBar )
{
wxBarIterator iter( mRows );
while( iter.Next() )
if ( &iter.BarInfo() == pBar ) return TRUE;
return FALSE;
}
cbRowInfo* cbDockPane::GetRow( int row )
{
if ( row >= (int)mRows.Count() ) return NULL;
return mRows[ row ];
}
int cbDockPane::GetRowIndex( cbRowInfo* pRow )
{
size_t i;
for ( i = 0; i != mRows.Count(); ++i )
{
if ( mRows[i] == pRow )
return i;
}
wxFAIL_MSG("Row must be present to call cbDockPane::GetRowIndex()");
return 0;
}
int cbDockPane::GetPaneHeight()
{
// first, recalculate row heights and the Y-positions
cbLayoutRowsEvent evt( this );
mpLayout->FirePluginEvent( evt );
int height = 0;
if ( IsHorizontal() )
height += mTopMargin + mBottomMargin;
else
height += mLeftMargin + mRightMargin;
int count = mRows.Count();
if ( count )
height += mRows[count-1]->mRowY + mRows[count-1]->mRowHeight;
return height;
}
int cbDockPane::GetAlignment()
{
return mAlignment;
}
bool cbDockPane::MatchesMask( int paneMask )
{
int thisMask = 0;
// FIXME:: use array instead of switch()
switch (mAlignment)
{
case FL_ALIGN_TOP : thisMask = FL_ALIGN_TOP_PANE; break;
case FL_ALIGN_BOTTOM : thisMask = FL_ALIGN_BOTTOM_PANE;break;
case FL_ALIGN_LEFT : thisMask = FL_ALIGN_LEFT_PANE; break;
case FL_ALIGN_RIGHT : thisMask = FL_ALIGN_RIGHT_PANE; break;
default:
wxFAIL_MSG("Bad FL alignment type detected in cbDockPane::MatchesMask()");
}
return ( thisMask & paneMask ) != 0;
}
void cbDockPane::RecalcLayout()
{
// first, reposition rows and items vertically
cbLayoutRowsEvent evt( this );
mpLayout->FirePluginEvent( evt );
// then horizontally in each row
size_t i;
for ( i = 0; i != mRows.Count(); ++i )
RecalcRowLayout( mRows[i] );
}
int cbDockPane::GetDockingState()
{
if ( mAlignment == FL_ALIGN_TOP ||
mAlignment == FL_ALIGN_BOTTOM )
{
return wxCBAR_DOCKED_HORIZONTALLY;
}
else
return wxCBAR_DOCKED_VERTICALLY;
}
inline bool cbDockPane::HasPoint( const wxPoint& pos, int x, int y,
int width, int height )
{
return ( pos.x >= x &&
pos.y >= y &&
pos.x < x + width &&
pos.y < y + height );
}
int cbDockPane::HitTestPaneItems( const wxPoint& pos,
cbRowInfo** ppRow,
cbBarInfo** ppBar
)
{
(*ppRow) = NULL;
(*ppBar) = NULL;
size_t i;
for ( i = 0; i != mRows.Count(); ++i )
{
cbRowInfo& row = *mRows[i];
*ppRow = &row;
// hit-test handles of the row, if present
if ( row.mHasUpperHandle )
{
if ( HasPoint( pos, 0, row.mRowY,
row.mRowWidth, mProps.mResizeHandleSize ) )
return CB_UPPER_ROW_HANDLE_HITTED;
}
else
if ( row.mHasLowerHandle )
{
if ( HasPoint( pos, 0, row.mRowY + row.mRowHeight - mProps.mResizeHandleSize,
row.mRowWidth, mProps.mResizeHandleSize ) )
return CB_LOWER_ROW_HANDLE_HITTED;
}
// hit-test bar handles and bar content
size_t k;
for ( k = 0; k != row.mBars.Count(); ++k )
{
cbBarInfo& bar = *row.mBars[k];
wxRect& bounds = bar.mBounds;
*ppBar = &bar;
if ( bar.mHasLeftHandle )
{
if ( HasPoint( pos, bounds.x, bounds.y,
mProps.mResizeHandleSize, bounds.height ) )
return CB_LEFT_BAR_HANDLE_HITTED;
}
else
if ( bar.mHasRightHandle )
{
if ( HasPoint( pos, bounds.x + bounds.width - mProps.mResizeHandleSize, bounds.y,
mProps.mResizeHandleSize, bounds.height ) )
return CB_RIGHT_BAR_HANDLE_HITTED;
}
if ( HasPoint( pos, bounds.x, bounds.y, bounds.width, bounds.height ) )
return CB_BAR_CONTENT_HITTED;
} // hit-test next bar
} // next row
return CB_NO_ITEMS_HITTED;
}
void cbDockPane::GetBarResizeRange( cbBarInfo* pBar, int* from, int *till,
bool forLeftHandle )
{
cbBarInfo* pGivenBar = pBar;
int notFree = 0;
// calc unavailable space from the left
while( pBar->mpPrev )
{
pBar = pBar->mpPrev;
if ( !pBar->IsFixed() ) notFree += mProps.mMinCBarDim.x;
else notFree += pBar->mBounds.width;
}
*from = notFree;
pBar = pGivenBar;
notFree = 0;
// calc unavailable space from the right
while( pBar->mpNext )
{
pBar = pBar->mpNext;
if ( pBar->mBounds.x >= mPaneWidth ) break;
// treat not-fixed bars as minimized
if ( !pBar->IsFixed() )
notFree += mProps.mMinCBarDim.x;
else
{
if ( pBar->mBounds.x + pBar->mBounds.width >= mPaneWidth )
{
notFree += mPaneWidth - pBar->mBounds.x;
break;
}
else
notFree += pBar->mBounds.width;
}
}
*till = mPaneWidth - notFree;
// do not let resizing totally deform the bar itself
if ( forLeftHandle )
(*till) -= mProps.mMinCBarDim.x;
else
(*from) += mProps.mMinCBarDim.x;
}
int cbDockPane::GetMinimalRowHeight( cbRowInfo* pRow )
{
int height = mProps.mMinCBarDim.y;
size_t i;
for ( i = 0; i != pRow->mBars.Count(); ++i )
{
if ( pRow->mBars[i]->IsFixed() )
height = wxMax( height, pRow->mBars[i]->mBounds.height );
}
if ( pRow->mHasUpperHandle )
height += mProps.mResizeHandleSize;
if ( pRow->mHasLowerHandle )
height += mProps.mResizeHandleSize;
return height;
}
void cbDockPane::SetRowHeight( cbRowInfo* pRow, int newHeight )
{
if ( pRow->mHasUpperHandle )
newHeight -= mProps.mResizeHandleSize;
if ( pRow->mHasLowerHandle )
newHeight -= mProps.mResizeHandleSize;
size_t i;
for ( i = 0; i != pRow->mBars.Count(); ++i )
{
if ( !pRow->mBars[i]->IsFixed() )
pRow->mBars[i]->mBounds.height = newHeight;
}
}
void cbDockPane::GetRowResizeRange( cbRowInfo* pRow, int* from, int* till,
bool forUpperHandle )
{
cbRowInfo* pGivenRow = pRow;
// calc unavailable space from above
int notFree = 0;
while( pRow->mpPrev )
{
pRow = pRow->mpPrev;
notFree += GetMinimalRowHeight( pRow );
};
*from = notFree;
// allow accupy the client window space by resizing pane rows
if ( mAlignment == FL_ALIGN_BOTTOM )
*from -= mpLayout->GetClientHeight();
else
if ( mAlignment == FL_ALIGN_RIGHT )
*from -= mpLayout->GetClientWidth();
// calc unavailable space from below
pRow = pGivenRow;
notFree = 0;
while( pRow->mpNext )
{
pRow = pRow->mpNext;
notFree += GetMinimalRowHeight( pRow );
}
*till = mPaneHeight - notFree;
// allow adjustinig pane space vs. client window space by resizing pane row heights
if ( mAlignment == FL_ALIGN_TOP )
*till += mpLayout->GetClientHeight();
else
if ( mAlignment == FL_ALIGN_LEFT )
*till += mpLayout->GetClientWidth();
// do not let the resizing of the row totally squeeze the row itself
cbRowInfo& row = *pGivenRow;
if ( forUpperHandle )
{
*till = row.mRowY + row.mRowHeight - GetMinimalRowHeight( pGivenRow );
if ( row.mHasUpperHandle )
*till -= mProps.mResizeHandleSize;
}
else
{
*from += GetMinimalRowHeight( pGivenRow );
if ( row.mHasLowerHandle )
*from -= mProps.mResizeHandleSize;
}
}
void cbDockPane::ResizeRow( cbRowInfo* pRow, int ofs,
bool forUpperHandle )
{
cbResizeRowEvent evt( pRow, ofs, forUpperHandle, this );
mpLayout->FirePluginEvent( evt );
}
void cbDockPane::ResizeBar( cbBarInfo* pBar, int ofs,
bool forLeftHandle )
{
pBar->mpRow->mpExpandedBar = NULL;
mpLayout->GetUpdatesManager().OnStartChanges();
wxRect& bounds = pBar->mBounds;
if ( forLeftHandle )
{
// do not allow bar width become less then minimal
if ( bounds.x + ofs > bounds.x + bounds.width - mProps.mMinCBarDim.x )
{
bounds.width = mProps.mMinCBarDim.x;
bounds.x += ofs;
}
else
{
bounds.x += ofs;
bounds.width -= ofs;
}
}
else
{
// move bar left if necessary
if ( bounds.width + ofs < mProps.mMinCBarDim.x )
{
bounds.x = bounds.x + bounds.width + ofs - mProps.mMinCBarDim.x;
bounds.width = mProps.mMinCBarDim.x;
}
else
// resize right border only
bounds.width += ofs;
}
cbRowInfo* pToRow = pBar->mpRow;
this->RemoveBar( pBar );
InsertBar( pBar, pToRow );
mpLayout->RecalcLayout(FALSE);
mpLayout->GetUpdatesManager().OnFinishChanges();
mpLayout->GetUpdatesManager().UpdateNow();
}
/*** row/bar resizing related methods ***/
void cbDockPane::DrawVertHandle( wxDC& dc, int x, int y, int height )
{
int lower = y + height;
dc.SetPen( mpLayout->mLightPen );
dc.DrawLine( x,y, x, lower );
dc.SetPen( mpLayout->mGrayPen );
int i;
for ( i = 0; i != mProps.mResizeHandleSize-1; ++i )
{
++x;
dc.DrawLine( x,y, x, lower );
}
dc.SetPen( mpLayout->mDarkPen );
++x;
dc.DrawLine( x,y, x, lower );
dc.SetPen( mpLayout->mBlackPen );
++x;
dc.DrawLine( x,y, x, lower );
}
void cbDockPane::DrawHorizHandle( wxDC& dc, int x, int y, int width )
{
int right = x + width;
dc.SetPen( mpLayout->mLightPen );
dc.DrawLine( x,y, right, y );
dc.SetPen( mpLayout->mGrayPen );
int i;
for ( i = 0; i != mProps.mResizeHandleSize-1; ++i )
{
++y;
dc.DrawLine( x,y, right, y );
}
dc.SetPen( mpLayout->mDarkPen );
dc.DrawLine( x,y, right, ++y );
dc.SetPen( mpLayout->mBlackPen );
dc.DrawLine( x,y, right, ++y );
}
cbBarInfo* cbDockPane::GetBarInfoByWindow( wxWindow* pBarWnd )
{
wxBarIterator i( mRows );
while( i.Next() )
if ( i.BarInfo().mpBarWnd == pBarWnd )
return &i.BarInfo();
return NULL;
}
void cbDockPane::GetRowShapeData( cbRowInfo* pRow, wxList* pLst )
{
pLst->DeleteContents( TRUE );
pLst->Clear();
size_t i;
for ( i = 0; i != pRow->mBars.Count(); ++i )
{
cbBarInfo& bar = *pRow->mBars[i];
cbBarShapeData* pData = new cbBarShapeData();
pLst->Append( (wxObject*)pData );
pData->mBounds = bar.mBounds;
pData->mLenRatio = bar.mLenRatio;
}
}
void cbDockPane::SetRowShapeData( cbRowInfo* pRow, wxList* pLst )
{
if ( pLst->First() == NULL )
return;
wxNode* pData = pLst->First();
size_t i;
for ( i = 0; i != pRow->mBars.Count(); ++i )
{
wxASSERT( pData ); // DBG::
cbBarInfo& bar = *pRow->mBars[i];;
cbBarShapeData& data = *((cbBarShapeData*)pData->Data());
bar.mBounds = data.mBounds;
bar.mLenRatio = data.mLenRatio;
pData = pData->Next();
}
}
/***** Implementation for class cbUpdatesManagerBase *****/
IMPLEMENT_ABSTRACT_CLASS( cbUpdatesManagerBase, wxObject )
/***** Implementation for class cbPluginBase *****/
IMPLEMENT_ABSTRACT_CLASS( cbPluginBase, wxEvtHandler )
cbPluginBase::~cbPluginBase()
{
// nothing
}
bool cbPluginBase::ProcessEvent(wxEvent& event)
{
if ( mPaneMask == wxALL_PANES )
return wxEvtHandler::ProcessEvent( event );
// extract mask info. from received event
cbPluginEvent& evt = *( (cbPluginEvent*)&event );
if ( evt.mpPane == 0 &&
mPaneMask == wxALL_PANES )
return wxEvtHandler::ProcessEvent( event );
int mask = 0;
switch ( evt.mpPane->mAlignment )
{
case FL_ALIGN_TOP : mask = FL_ALIGN_TOP_PANE; break;
case FL_ALIGN_BOTTOM : mask = FL_ALIGN_BOTTOM_PANE;break;
case FL_ALIGN_LEFT : mask = FL_ALIGN_LEFT_PANE; break;
case FL_ALIGN_RIGHT : mask = FL_ALIGN_RIGHT_PANE; break;
}
// if event's pane maks matches the plugin's mask
if ( mPaneMask & mask )
return wxEvtHandler::ProcessEvent( event );
// otherwise pass to the next handler if present
if ( GetNextHandler() && GetNextHandler()->ProcessEvent( event ) )
return TRUE;
else
return FALSE;
}