00001
00002
00003
00004
00005
00006
00007
00008
00009
00011
00012 #include <wx/dockhost.h>
00013 #include <wx/dockwindow.h>
00014 #include <wx/dockpanel.h>
00015 #include <wx/gdi.h>
00016 #include <wx/exsplitter.h>
00017
00018 #include <wx/list.h>
00019 #include <wx/listimpl.cpp>
00020
00021
00022
00023
00024
00025 IMPLEMENT_CLASS( wxDockHost, wxPanel )
00026
00027 BEGIN_EVENT_TABLE( wxDockHost, wxPanel )
00028 EVT_SIZE( wxDockHost::OnSize )
00029 EVT_SPLITTER_MOVED( wxDockHost::OnSplitterMoved )
00030 EVT_CALCULATE_LAYOUT( wxDockHost::OnCalculateLayout )
00031 END_EVENT_TABLE()
00032
00033 WX_DEFINE_LIST( DockWindowList );
00034 WX_DEFINE_LIST( SplitterList );
00035
00036
00037
00038
00039
00040 wxDockHost::~wxDockHost() {
00041 delete pSizingSplitter_;
00042 }
00043
00044 void wxDockHost::Init() {
00045 dir_ = wxALL;
00046 areaSize_ = wxINITIAL_HOST_SIZE;
00047 panelArea_ = 0;
00048 lockPanelValue_ = false;
00049 internalSizeEvent_ = false;
00050 pLayoutManager_ = NULL;
00051 pos_.x = 0;
00052 pos_.y = 0;
00053 size_.x = 0;
00054 size_.y = 0;
00055 numPanels_ = 0;
00056 numSplitters_ = 0;
00057 splitterFlags_ = 0x0000;
00058 pSizingSplitter_ = NULL;
00059 splitters_.Clear();
00060 dockWindows_.Clear();
00061 }
00062
00063 bool wxDockHost::Create( wxWindow *parent, wxWindowID id, wxDirection dir, const wxString& name ) {
00064 wxASSERT(parent);
00065 dir_ = dir;
00066 bool r = wxPanel::Create( parent, id, pos_, size_, wxTAB_TRAVERSAL | wxCLIP_CHILDREN, name );
00067
00068 return r;
00069 }
00070
00071 void wxDockHost::SetLayoutManager( wxLayoutManager * pLayoutManager ) {
00072 pLayoutManager_ = pLayoutManager;
00073
00074
00075 wxWindow * win1 = (dir_ == wxLEFT || dir_ == wxTOP) ? this : NULL;
00076 wxWindow * win2 = (dir_ == wxRIGHT || dir_ == wxBOTTOM) ? this : NULL;
00077 wxOrientation orientation = (GetOrientation() == wxHORIZONTAL) ? wxVERTICAL : wxHORIZONTAL;
00078 pSizingSplitter_ = new wxExSplitter( this, orientation, win1, win2, 0x0000 );
00079 SettingsChanged();
00080 }
00081
00082 wxLayoutManager * wxDockHost::GetLayoutManager() {
00083 return pLayoutManager_;
00084 }
00085
00086 void wxDockHost::SetAreaSize( int size ) {
00087 areaSize_ = size;
00088 }
00089
00090 int wxDockHost::GetAreaSize() {
00091 return areaSize_;
00092 }
00093
00094 DockWindowList & wxDockHost::GetDockWindowList() {
00095 DockWindowList dockWindows;
00096
00097 wxWindowList & children = GetChildren();
00098 dockWindows_.Clear();
00099 for( int c=0; c<(int)children.GetCount(); c++ ) {
00100
00101 wxWindowListNode * pChildNode = children.Item( c );
00102 wxASSERT(pChildNode);
00103 wxWindow * pChild = pChildNode->GetData();
00104 wxASSERT(pChild);
00105
00106
00107 wxDockPanel * pPanel = wxDynamicCast( pChild, wxDockPanel );
00108 if( pPanel ) {
00109
00110 dockWindows_.Append( pPanel->GetDockWindow() );
00111 }
00112 }
00113
00114 return dockWindows_;
00115 }
00116
00117 void wxDockHost::OnSize( wxSizeEvent &event ) {
00118 if( !pLayoutManager_ ) {
00119
00120 return;
00121 }
00122
00123 wxSize newSize = event.GetSize();
00124 if( !IsEmpty() ) {
00125
00126 if( GetOrientation() == wxHORIZONTAL ) {
00127 areaSize_ = newSize.GetHeight();
00128 }
00129 else {
00130 areaSize_ = newSize.GetWidth();
00131 }
00132
00133 if( !internalSizeEvent_ ) {
00134 pLayoutManager_->UpdateAllHosts( true, this );
00135 }
00136 }
00137 UpdateSize( true );
00138 }
00139
00140 void wxDockHost::OnSplitterMoved( wxCommandEvent &event ) {
00141 if( event.GetEventObject() != pSizingSplitter_ ) {
00142
00143 RecalcPanelAreas();
00144 }
00145 }
00146
00147 void wxDockHost::UpdateSize( bool useProportions ) {
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157 calcPanelPlacement( useProportions );
00158 }
00159
00160 void wxDockHost::DockPanel( wxDockPanel * pDockPanel, wxHostInfo &hi ) {
00161 if( hi.pPanel == pDockPanel ) {
00162
00163 return;
00164 }
00165
00166
00167 pDockPanel->Reparent( this );
00168
00169 wxWindowList & children = GetChildren();
00170
00171
00172 if( hi.pPanel ) {
00173 int insertIndex = children.IndexOf( hi.pPanel );
00174 if( insertIndex == wxNOT_FOUND ) {
00175
00176 hi.pPanel = NULL;
00177 }
00178 }
00179
00180
00181 wxWindowListNode * pNode = children.Find( pDockPanel );
00182 children.DeleteNode( pNode );
00183
00184 int insertIndex = children.IndexOf( hi.pPanel );
00185 if( insertIndex != wxNOT_FOUND ) {
00186
00187 if( hi.placement == wxHIP_BACK ) {
00188 insertIndex++;
00189 }
00190 children.Insert( insertIndex, pDockPanel );
00191 }
00192 else {
00193
00194 int count = getAssetCount();
00195 if( count > 0 ) {
00196 wxWindowListNode * pChildNode = children.Item( count-1 );
00197 wxASSERT(pChildNode);
00198 hi.pPanel = wxDynamicCast( pChildNode->GetData(), wxDockPanel );
00199 hi.placement = wxHIP_BACK;
00200 }
00201 children.Append( pDockPanel );
00202 }
00203
00204 RecalcPanelAreas();
00205
00206
00207
00208
00209
00210
00211
00212
00213
00214
00215
00216
00217
00218 pDockPanel->SetDockedHost( this );
00219 }
00220
00221 void wxDockHost::UndockPanel( wxDockPanel * pDockPanel ) {
00222
00223 wxWindowList & children = GetChildren();
00224
00225
00226 wxWindowListNode * pNode = children.Find( pDockPanel );
00227 assert(pNode);
00228 wxDockPanel * pGivePanel = NULL;
00229
00230
00231 if( getAssetCount() > 1 ) {
00232 int lastIndex = children.GetCount()-1;
00233 wxWindowListNode * pLastNode = children.Item( lastIndex );
00234 wxASSERT(pLastNode);
00235 if( pNode == pLastNode ) {
00236
00237 do {
00238 pNode = children.Item( --lastIndex );
00239 pGivePanel = wxDynamicCast( pNode->GetData(), wxDockPanel );
00240 } while( !pGivePanel );
00241 }
00242 else {
00243
00244 int currentIndex = children.IndexOf( pDockPanel );
00245 do {
00246 pNode = children.Item( ++currentIndex );
00247 pGivePanel = wxDynamicCast( pNode->GetData(), wxDockPanel );
00248 } while( !pGivePanel );
00249 }
00250 }
00251
00252
00253 if( pGivePanel ) {
00254 int newArea = pDockPanel->GetArea() + pGivePanel->GetArea() + wxSPLITTER_SIZE;
00255 pGivePanel->SetArea( newArea );
00256 }
00257
00258
00259 wxDockWindowBase * pDockWindow = pDockPanel->GetDockWindow();
00260 pDockPanel->Reparent( pDockWindow );
00261
00262 pDockPanel->SetDockedHost( NULL );
00263 }
00264
00265 wxRect wxDockHost::GetScreenArea() {
00266
00267 wxRect hp = CalcHostPlacement( true );
00268 if( pLayoutManager_ ) {
00269 hp = pLayoutManager_->TrimDockArea( this, hp );
00270 }
00271
00272 return pLayoutManager_->RectToScreen( hp );
00273 }
00274
00275 wxRect wxDockHost::GetScreenArea( wxHostInfo &hi ) {
00276
00277 if( !hi.pPanel ) {
00278 return GetScreenArea();
00279 }
00280 else {
00281 return hi.pPanel->GetScreenArea( hi );
00282 }
00283 }
00284
00285 wxRect wxDockHost::GetClientArea() {
00286
00287 return CalcHostPlacement();
00288 }
00289
00290 wxOrientation wxDockHost::GetOrientation() {
00291 switch( dir_ ) {
00292 case wxLEFT:
00293 case wxRIGHT:
00294 return wxVERTICAL;
00295 break;
00296
00297 case wxTOP:
00298 case wxBOTTOM:
00299 return wxHORIZONTAL;
00300 break;
00301 case wxALL:
00302 wxASSERT_MSG( false, wxT("wxALL is not valid") );
00303 break;
00304 }
00305
00306 return wxHORIZONTAL;
00307 }
00308 wxDirection wxDockHost::GetDirection() {
00309 return dir_;
00310 }
00311
00312 wxRect wxDockHost::CalcHostPlacement( bool hitTest ) {
00313 int area = areaSize_;
00314 if( IsEmpty() ) {
00315
00316 if( !hitTest ) {
00317
00318 area = 0;
00319 }
00320 }
00321
00322
00323 wxRect pcr = pLayoutManager_->GetDockArea();
00324 switch( dir_ ) {
00325 case wxLEFT:
00326 pos_.x = pcr.x;
00327 pos_.y = pcr.y;
00328 size_.x = area;
00329 size_.y = pcr.height;
00330 break;
00331 case wxTOP:
00332 pos_.x = pcr.x;
00333 pos_.y = pcr.y;
00334 size_.x = pcr.width;
00335 size_.y = area;
00336 break;
00337 case wxBOTTOM:
00338 pos_.x = pcr.x;
00339 pos_.y = pcr.GetBottom() - area;
00340 size_.x = pcr.width;
00341 size_.y = area;
00342 break;
00343 case wxRIGHT:
00344 pos_.x = pcr.GetRight() - area;
00345 pos_.y = pcr.y;
00346 size_.x = area;
00347 size_.y = pcr.height;
00348 break;
00349 case wxALL:
00350
00351 break;
00352 }
00353 wxRect t( pos_, size_ );
00354 return t;
00355 }
00356
00357 bool wxDockHost::IsEmpty() {
00358 return getAssetCount() == 0;
00359 }
00360
00361 bool wxDockHost::TestForPanel( int sx, int sy, wxHostInfo &hi ) {
00362 if( IsEmpty() ) {
00363
00364 wxRect hRect = GetScreenArea();
00365 if( hRect.Inside( sx, sy ) ) {
00366 hi = this;
00367 return true;
00368 }
00369 }
00370
00371 wxWindowList & children = GetChildren();
00372 for( int c=0; c<(int)children.GetCount(); c++ ) {
00373
00374 wxWindowListNode * pChildNode = children.Item( c );
00375 wxASSERT(pChildNode);
00376 wxWindow * pChild = pChildNode->GetData();
00377 wxASSERT(pChild);
00378
00379
00380 wxDockPanel * pPanel = wxDynamicCast( pChild, wxDockPanel );
00381 if( pPanel ) {
00382 wxRect localRect = pPanel->GetRect();
00383 wxRect screenRect = RectToScreen( localRect );
00384 if( screenRect.Inside( sx, sy ) ) {
00385
00386 hi = this;
00387 hi.pPanel = pPanel;
00388 hi.placement = pPanel->TestForPlacement( sx, sy );
00389 return true;
00390 }
00391 }
00392 }
00393 return false;
00394 }
00395
00396 wxRect wxDockHost::RectToScreen( wxRect &rect ) {
00397
00398 wxRect tRect( rect );
00399 wxPoint pos = ClientToScreen( tRect.GetPosition() );
00400 tRect.SetPosition( pos );
00401 return tRect;
00402 }
00403
00404 void wxDockHost::RecalcPanelAreas() {
00405
00406 wxRect cr = GetClientRect();
00407
00408
00409 int hostArea = GetOrientation() == wxHORIZONTAL ? cr.width : cr.height;
00410
00411 int splittersArea = (numSplitters_ * wxSPLITTER_SIZE);
00412 if( !lockPanelValue_ ) {
00413 panelArea_ = (hostArea - splittersArea);
00414 }
00415
00416 wxWindowList & children = GetChildren();
00417 int childCount = children.GetCount();
00418
00419
00420 int equalArea = panelArea_ / ((childCount + 1) / 2);
00421
00422 for( int c=0; c<childCount; c++ ) {
00423
00424 wxWindowListNode * pChildNode = children.Item( c );
00425 wxASSERT(pChildNode);
00426 wxWindow * pChild = pChildNode->GetData();
00427 wxASSERT(pChild);
00428
00429
00430 wxDockPanel * pPanel = wxDynamicCast( pChild, wxDockPanel );
00431 if( pPanel ) {
00432
00433 pPanel->SetArea( equalArea );
00434 }
00435 }
00436 }
00437
00438 void wxDockHost::OnCalculateLayout( wxCalculateLayoutEvent &event ) {
00439
00440 bool queryMode = false;
00441 if( (event.GetFlags() & wxLAYOUT_QUERY) != 0 ) {
00442 queryMode = true;
00443 }
00444
00445 wxRect areaRect = event.GetRect();
00446
00447
00448 if( pLayoutManager_->IsPrimaryDockHost( this ) ) {
00449 pLayoutManager_->SetDockArea( areaRect );
00450 }
00451
00452 if( IsEmpty() ) {
00453
00454 SetSize( 0,0,0,0 );
00455 return;
00456 }
00457
00458 internalSizeEvent_ = true;
00459
00460
00461 switch( GetDirection() ) {
00462 case wxLEFT:
00463 if( !queryMode ) SetSize( areaRect.GetX(), areaRect.GetY(), areaSize_, areaRect.GetHeight() );
00464 areaRect.SetX( areaRect.GetX() + areaSize_ );
00465 areaRect.SetWidth( areaRect.GetWidth() - areaSize_ );
00466 break;
00467 case wxTOP:
00468 if( !queryMode ) SetSize( areaRect.GetX(), areaRect.GetY(), areaRect.GetWidth(), areaSize_ );
00469 areaRect.SetY( areaRect.GetY() + areaSize_ );
00470 areaRect.SetHeight( areaRect.GetHeight() - areaSize_ );
00471 break;
00472 case wxBOTTOM:
00473 if( !queryMode ) SetSize( areaRect.GetX(), areaRect.GetY() + (areaRect.GetHeight() - areaSize_), areaRect.GetWidth(), areaSize_ );
00474 areaRect.SetHeight( areaRect.GetHeight() - areaSize_ );
00475 break;
00476 case wxRIGHT:
00477 if( !queryMode ) SetSize( areaRect.GetX() + (areaRect.GetWidth() - areaSize_), areaRect.GetY(), areaSize_, areaRect.GetHeight() );
00478 areaRect.SetWidth( areaRect.GetWidth() - areaSize_ );
00479 break;
00480 break;
00481 case wxALL:
00482
00483 break;
00484 }
00485 event.SetRect( areaRect );
00486
00487 internalSizeEvent_ = false;
00488 }
00489
00490 void wxDockHost::SettingsChanged() {
00491 unsigned int dwFlags = pLayoutManager_->GetFlags();
00492 bool liveUpdate = (dwFlags & wxDWF_LIVE_UPDATE) == wxDWF_LIVE_UPDATE;
00493 bool splitterBorders = (dwFlags & wxDWF_SPLITTER_BORDERS) == wxDWF_SPLITTER_BORDERS;
00494
00495 unsigned int flags = liveUpdate ? wxESF_LIVE_UPDATE : 0;
00496 flags |= splitterBorders ? wxESF_DRAW_GRIPPER : 0;
00497
00498
00499 for( unsigned int i=0; i<splitters_.GetCount(); ++i ) {
00500 wxExSplitter * pSplitter = splitters_[i];
00501 pSplitter->SetFlags( flags );
00502 }
00503 pSizingSplitter_->SetFlags( flags );
00504 splitterFlags_ = flags;
00505 }
00506
00507 void wxDockHost::calcPanelPlacement( bool useProportions ) {
00508 updateSplitters();
00509
00510 wxWindowList & children = GetChildren();
00511 int childCount = children.GetCount();
00512 if( IsEmpty() ) {
00513 return;
00514 }
00515
00516
00517 wxRect cr = GetClientRect();
00518
00519 int areaRemaining = GetOrientation() == wxHORIZONTAL ? cr.width : cr.height;
00520 int splittersArea = (numSplitters_ * wxSPLITTER_SIZE);
00521 int panelArea = (areaRemaining - splittersArea);
00522 int panelAllowance = panelArea;
00523 int areaPos = 0;
00524 int panelCount = 0;
00525 for( int c=0; c<childCount; c++ ) {
00526
00527 wxWindowListNode * pChildNode = children.Item( c );
00528 wxASSERT(pChildNode);
00529 wxWindow * pChild = pChildNode->GetData();
00530 wxASSERT(pChild);
00531
00532 if( pChild == pSizingSplitter_ ) {
00533
00534 continue;
00535 }
00536
00537
00538 wxDockPanel * pPanel = wxDynamicCast( pChild, wxDockPanel );
00539
00540 int childChunk = 0;
00541 if( !pPanel ) {
00542
00543 childChunk = wxSPLITTER_SIZE;
00544 }
00545 else {
00546 panelCount++;
00547
00548
00549 if( panelCount < numPanels_ ) {
00550 if( useProportions ) {
00551
00552 float proportion = (float)pPanel->GetArea() / panelArea_;
00553 childChunk = (int)((float)proportion * panelArea);
00554 }
00555 else {
00556
00557 childChunk = pPanel->GetArea();
00558 }
00559 panelAllowance -= childChunk;
00560 }
00561 else {
00562
00563 childChunk = panelAllowance;
00564 panelAllowance = 0;
00565 }
00566 }
00567
00568
00569 if( GetOrientation() == wxHORIZONTAL ) {
00570 int top = (dir_ == wxTOP) ? 0 : wxSPLITTER_SIZE;
00571 int height = cr.height - wxSPLITTER_SIZE;
00572 pChild->SetSize( areaPos, top, childChunk, height );
00573 }
00574 else {
00575 int left = (dir_ == wxLEFT) ? 0 : wxSPLITTER_SIZE;
00576 int width = cr.width - wxSPLITTER_SIZE;
00577 pChild->SetSize( left, areaPos, width, childChunk );
00578 }
00579 areaPos += childChunk + 1;
00580 }
00581
00582 assert(pSizingSplitter_);
00583
00584
00585 if( GetOrientation() == wxHORIZONTAL ) {
00586 int areaHeight = cr.height - wxSPLITTER_SIZE;
00587 int splitterTop = (dir_ == wxTOP) ? areaHeight : 0;
00588 pSizingSplitter_->SetSize( 0, splitterTop, cr.width, wxSPLITTER_SIZE );
00589 }
00590 else {
00591 int areaWidth = cr.width - wxSPLITTER_SIZE;
00592 int splitterLeft = (dir_ == wxLEFT) ? areaWidth : 0;
00593 pSizingSplitter_->SetSize( splitterLeft, 0, wxSPLITTER_SIZE, cr.height );
00594 }
00595
00596 if( lockPanelValue_ ) {
00597
00598 RecalcPanelAreas();
00599 }
00600 }
00601
00602 int wxDockHost::getAssetCount() {
00603 wxWindowList & children = GetChildren();
00604 int childCount = children.GetCount();
00605
00606
00607 return childCount-1;
00608 }
00609
00610 void wxDockHost::updateSplitters() {
00611
00612
00613 wxWindowList & children = GetChildren();
00614 int childCount = children.GetCount();
00615
00616 eChildType lastChildType = CT_NONE;
00617 wxWindow * pLastChild = NULL;
00618 numPanels_ = 0;
00619 numSplitters_ = 0;
00620 wxWindowList newChildList;
00621 SplitterList toDeleteSplitters;
00622 splitters_.Clear();
00623
00624 int c;
00625 for( c=0; c<childCount; c++ ) {
00626
00627 wxWindowListNode * pChildNode = children.Item( c );
00628 wxASSERT(pChildNode);
00629 wxWindow * pChild = pChildNode->GetData();
00630 wxASSERT(pChild);
00631
00632 if( pChild == pSizingSplitter_ ) {
00633 newChildList.Append( pSizingSplitter_ );
00634
00635
00636 continue;
00637 }
00638
00639
00640 wxDockPanel * pPanel = wxDynamicCast( pChild, wxDockPanel );
00641 if( pPanel ) {
00642 if( lastChildType == CT_PANEL ) {
00643
00644 wxASSERT(pLastChild);
00645
00646 wxExSplitter * pSplitter = new wxExSplitter( this, GetOrientation(), pLastChild, pPanel, splitterFlags_ );
00647
00648 newChildList.Append( pSplitter );
00649 numSplitters_++;
00650 splitters_.Append( pSplitter );
00651 }
00652
00653 newChildList.Append( pPanel );
00654 numPanels_++;
00655
00656
00657 lastChildType = CT_PANEL;
00658 pLastChild = (wxWindow *)pPanel;
00659 }
00660 else {
00661 if( lastChildType == CT_SPLITTER || c == 1 || c == (childCount-1) ) {
00662
00663 wxExSplitter * pPanelSplitter = wxDynamicCast( pChildNode->GetData(), wxExSplitter );
00664 toDeleteSplitters.Append( pPanelSplitter );
00665 }
00666 else {
00667
00668 pLastChild = wxDynamicCast( pChildNode->GetData(), wxExSplitter );
00669 newChildList.Append( pLastChild );
00670 numSplitters_++;
00671 splitters_.Append( (wxExSplitter *)pLastChild );
00672 }
00673
00674 lastChildType = CT_SPLITTER;
00675 }
00676 }
00677
00678
00679 for ( SplitterList::Node *node = toDeleteSplitters.GetFirst(); node; node = node->GetNext() ) {
00680 delete node->GetData();
00681 }
00682
00683
00684 children = newChildList;
00685
00686
00687 int newChildCount = children.GetCount();
00688 for( c=0; c<newChildCount; c++ ) {
00689
00690 wxWindowListNode * pChildNode = children.Item( c );
00691 wxASSERT(pChildNode);
00692
00693 wxExSplitter * pPanelSplitter = wxDynamicCast( pChildNode->GetData(), wxExSplitter );
00694 if( pPanelSplitter == pSizingSplitter_ ) {
00695
00696 continue;
00697 }
00698
00699 if( pPanelSplitter ) {
00700
00701 wxASSERT(c>1);
00702 wxASSERT(c<(newChildCount-1));
00703 wxDockPanel * pFrontPanel = wxDynamicCast( children.Item( c-1 )->GetData(), wxDockPanel );
00704 wxASSERT(pFrontPanel);
00705 wxDockPanel * pBackPanel = wxDynamicCast( children.Item( c+1 )->GetData(), wxDockPanel );
00706 wxASSERT(pBackPanel);
00707 pPanelSplitter->SetWindows( pFrontPanel, pBackPanel );
00708 }
00709 }
00710 }