1 /////////////////////////////////////////////////////////////////////////////// 
   2 // Name:        src/aui/framemanager.cpp 
   3 // Purpose:     wxaui: wx advanced user interface - docking window manager 
   4 // Author:      Benjamin I. Williams 
   8 // Copyright:   (C) Copyright 2005-2006, Kirix Corporation, All Rights Reserved 
   9 // Licence:     wxWindows Library Licence, Version 3.1 
  10 /////////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #include "wx/wxprec.h" 
  28 #include "wx/aui/framemanager.h" 
  29 #include "wx/aui/dockart.h" 
  30 #include "wx/aui/floatpane.h" 
  33     #include "wx/settings.h" 
  35     #include "wx/dcclient.h" 
  36     #include "wx/dcscreen.h" 
  37     #include "wx/toolbar.h" 
  42 WX_CHECK_BUILD_OPTIONS("wxAUI") 
  44 #include "wx/arrimpl.cpp" 
  45 WX_DECLARE_OBJARRAY(wxRect
, wxAuiRectArray
); 
  46 WX_DEFINE_OBJARRAY(wxAuiRectArray
) 
  47 WX_DEFINE_OBJARRAY(wxDockUIPartArray
) 
  48 WX_DEFINE_OBJARRAY(wxDockInfoArray
) 
  49 WX_DEFINE_OBJARRAY(wxPaneButtonArray
) 
  50 WX_DEFINE_OBJARRAY(wxPaneInfoArray
) 
  52 wxPaneInfo wxNullPaneInfo
; 
  53 wxDockInfo wxNullDockInfo
; 
  54 DEFINE_EVENT_TYPE(wxEVT_AUI_PANEBUTTON
) 
  57     // a few defines to avoid nameclashes 
  58     #define __MAC_OS_X_MEMORY_MANAGER_CLEAN__ 1 
  60     #include "wx/mac/private.h" 
  64 // -- static utility functions -- 
  66 static wxBitmap 
wxPaneCreateStippleBitmap() 
  68     unsigned char data
[] = { 0,0,0,192,192,192, 192,192,192,0,0,0 }; 
  69     wxImage 
img(2,2,data
,true); 
  73 static void DrawResizeHint(wxDC
& dc
, const wxRect
& rect
) 
  75     wxBitmap stipple 
= wxPaneCreateStippleBitmap(); 
  76     wxBrush 
brush(stipple
); 
  78     dc
.SetPen(*wxTRANSPARENT_PEN
); 
  80     dc
.SetLogicalFunction(wxXOR
); 
  81     dc
.DrawRectangle(rect
); 
  86 // on supported windows systems (Win2000 and greater), this function 
  87 // will make a frame window transparent by a certain amount 
  88 static void MakeWindowTransparent(wxWindow
* wnd
, int amount
) 
  90     // this API call is not in all SDKs, only the newer ones, so 
  91     // we will runtime bind this 
  92     typedef DWORD (WINAPI 
*PSETLAYEREDWINDOWATTR
)(HWND
, DWORD
, BYTE
, DWORD
); 
  93     static PSETLAYEREDWINDOWATTR pSetLayeredWindowAttributes 
= NULL
; 
  94     static HMODULE h 
= NULL
; 
  95     HWND hwnd 
= (HWND
)wnd
->GetHWND(); 
  98         h 
= LoadLibrary(_T("user32")); 
 100     if (!pSetLayeredWindowAttributes
) 
 102         pSetLayeredWindowAttributes 
= 
 103          (PSETLAYEREDWINDOWATTR
)GetProcAddress(h
,"SetLayeredWindowAttributes"); 
 106     if (pSetLayeredWindowAttributes 
== NULL
) 
 109     LONG exstyle 
= GetWindowLong(hwnd
, GWL_EXSTYLE
); 
 110     if (0 == (exstyle 
& 0x80000) /*WS_EX_LAYERED*/) 
 111         SetWindowLong(hwnd
, GWL_EXSTYLE
, exstyle 
| 0x80000 /*WS_EX_LAYERED*/); 
 113     pSetLayeredWindowAttributes(hwnd
, 0, (BYTE
)amount
, 2 /*LWA_ALPHA*/); 
 119 // CopyDocksAndPanes() - this utility function creates copies of 
 120 // the dock and pane info.  wxDockInfo's usually contain pointers 
 121 // to wxPaneInfo classes, thus this function is necessary to reliably 
 122 // reconstruct that relationship in the new dock info and pane info arrays 
 124 static void CopyDocksAndPanes(wxDockInfoArray
& dest_docks
, 
 125                               wxPaneInfoArray
& dest_panes
, 
 126                               const wxDockInfoArray
& src_docks
, 
 127                               const wxPaneInfoArray
& src_panes
) 
 129     dest_docks 
= src_docks
; 
 130     dest_panes 
= src_panes
; 
 131     int i
, j
, k
, dock_count
, pc1
, pc2
; 
 132     for (i 
= 0, dock_count 
= dest_docks
.GetCount(); i 
< dock_count
; ++i
) 
 134         wxDockInfo
& dock 
= dest_docks
.Item(i
); 
 135         for (j 
= 0, pc1 
= dock
.panes
.GetCount(); j 
< pc1
; ++j
) 
 136             for (k 
= 0, pc2 
= src_panes
.GetCount(); k 
< pc2
; ++k
) 
 137                 if (dock
.panes
.Item(j
) == &src_panes
.Item(k
)) 
 138                     dock
.panes
.Item(j
) = &dest_panes
.Item(k
); 
 142 // GetMaxLayer() is an internal function which returns 
 143 // the highest layer inside the specified dock 
 144 static int GetMaxLayer(const wxDockInfoArray
& docks
, int dock_direction
) 
 146     int i
, dock_count
, max_layer 
= 0; 
 147     for (i 
= 0, dock_count 
= docks
.GetCount(); i 
< dock_count
; ++i
) 
 149         wxDockInfo
& dock 
= docks
.Item(i
); 
 150         if (dock
.dock_direction 
== dock_direction 
&& 
 151             dock
.dock_layer 
> max_layer 
&& !dock
.fixed
) 
 152                 max_layer 
= dock
.dock_layer
; 
 158 // GetMaxRow() is an internal function which returns 
 159 // the highest layer inside the specified dock 
 160 static int GetMaxRow(const wxPaneInfoArray
& panes
, int direction
, int layer
) 
 162     int i
, pane_count
, max_row 
= 0; 
 163     for (i 
= 0, pane_count 
= panes
.GetCount(); i 
< pane_count
; ++i
) 
 165         wxPaneInfo
& pane 
= panes
.Item(i
); 
 166         if (pane
.dock_direction 
== direction 
&& 
 167             pane
.dock_layer 
== layer 
&& 
 168             pane
.dock_row 
> max_row
) 
 169                 max_row 
= pane
.dock_row
; 
 176 // DoInsertDockLayer() is an internal function that inserts a new dock 
 177 // layer by incrementing all existing dock layer values by one 
 178 static void DoInsertDockLayer(wxPaneInfoArray
& panes
, 
 183     for (i 
= 0, pane_count 
= panes
.GetCount(); i 
< pane_count
; ++i
) 
 185         wxPaneInfo
& pane 
= panes
.Item(i
); 
 186         if (!pane
.IsFloating() && 
 187             pane
.dock_direction 
== dock_direction 
&& 
 188             pane
.dock_layer 
>= dock_layer
) 
 193 // DoInsertDockLayer() is an internal function that inserts a new dock 
 194 // row by incrementing all existing dock row values by one 
 195 static void DoInsertDockRow(wxPaneInfoArray
& panes
, 
 201     for (i 
= 0, pane_count 
= panes
.GetCount(); i 
< pane_count
; ++i
) 
 203         wxPaneInfo
& pane 
= panes
.Item(i
); 
 204         if (!pane
.IsFloating() && 
 205             pane
.dock_direction 
== dock_direction 
&& 
 206             pane
.dock_layer 
== dock_layer 
&& 
 207             pane
.dock_row 
>= dock_row
) 
 212 // DoInsertDockLayer() is an internal function that inserts a space for 
 213 // another dock pane by incrementing all existing dock row values by one 
 214 static void DoInsertPane(wxPaneInfoArray
& panes
, 
 221     for (i 
= 0, pane_count 
= panes
.GetCount(); i 
< pane_count
; ++i
) 
 223         wxPaneInfo
& pane 
= panes
.Item(i
); 
 224         if (!pane
.IsFloating() && 
 225             pane
.dock_direction 
== dock_direction 
&& 
 226             pane
.dock_layer 
== dock_layer 
&& 
 227             pane
.dock_row 
== dock_row 
&& 
 228             pane
.dock_pos 
>= dock_pos
) 
 233 // FindDocks() is an internal function that returns a list of docks which meet 
 234 // the specified conditions in the parameters and returns a sorted array 
 235 // (sorted by layer and then row) 
 236 static void FindDocks(wxDockInfoArray
& docks
, 
 240                       wxDockInfoPtrArray
& arr
) 
 242     int begin_layer 
= dock_layer
; 
 243     int end_layer 
= dock_layer
; 
 244     int begin_row 
= dock_row
; 
 245     int end_row 
= dock_row
; 
 246     int dock_count 
= docks
.GetCount(); 
 247     int layer
, row
, i
, max_row 
= 0, max_layer 
= 0; 
 249     // discover the maximum dock layer and the max row 
 250     for (i 
= 0; i 
< dock_count
; ++i
) 
 252         max_row 
= wxMax(max_row
, docks
.Item(i
).dock_row
); 
 253         max_layer 
= wxMax(max_layer
, docks
.Item(i
).dock_layer
); 
 256     // if no dock layer was specified, search all dock layers 
 257     if (dock_layer 
== -1) 
 260         end_layer 
= max_layer
; 
 263     // if no dock row was specified, search all dock row 
 272     for (layer 
= begin_layer
; layer 
<= end_layer
; ++layer
) 
 273         for (row 
= begin_row
; row 
<= end_row
; ++row
) 
 274             for (i 
= 0; i 
< dock_count
; ++i
) 
 276                 wxDockInfo
& d 
= docks
.Item(i
); 
 277                 if (dock_direction 
== -1 || dock_direction 
== d
.dock_direction
) 
 279                     if (d
.dock_layer 
== layer 
&& d
.dock_row 
== row
) 
 285 // FindPaneInDock() looks up a specified window pointer inside a dock. 
 286 // If found, the corresponding wxPaneInfo pointer is returned, otherwise NULL. 
 287 static wxPaneInfo
* FindPaneInDock(const wxDockInfo
& dock
, wxWindow
* window
) 
 289     int i
, count 
= dock
.panes
.GetCount(); 
 290     for (i 
= 0; i 
< count
; ++i
) 
 292         wxPaneInfo
* p 
= dock
.panes
.Item(i
); 
 293         if (p
->window 
== window
) 
 299 // RemovePaneFromDocks() removes a pane window from all docks 
 300 // with a possible exception specified by parameter "except" 
 301 static void RemovePaneFromDocks(wxDockInfoArray
& docks
, 
 303                                 wxDockInfo
* except 
= NULL
) 
 306     for (i 
= 0, dock_count 
= docks
.GetCount(); i 
< dock_count
; ++i
) 
 308         wxDockInfo
& d 
= docks
.Item(i
); 
 311         wxPaneInfo
* pi 
= FindPaneInDock(d
, pane
.window
); 
 317 // RenumberDockRows() takes a dock and assigns sequential numbers 
 318 // to existing rows.  Basically it takes out the gaps; so if a 
 319 // dock has rows with numbers 0,2,5, they will become 0,1,2 
 320 static void RenumberDockRows(wxDockInfoPtrArray
& docks
) 
 322     int i
, dock_count
, j
, pane_count
; 
 323     for (i 
= 0, dock_count 
= docks
.GetCount(); i 
< dock_count
; ++i
) 
 325         wxDockInfo
& dock 
= *docks
.Item(i
); 
 327         for (j 
= 0, pane_count 
= dock
.panes
.GetCount(); j 
< pane_count
; ++j
) 
 328             dock
.panes
.Item(j
)->dock_row 
= i
; 
 333 // SetActivePane() sets the active pane, as well as cycles through 
 334 // every other pane and makes sure that all others' active flags 
 336 static void SetActivePane(wxPaneInfoArray
& panes
, wxWindow
* active_pane
) 
 339     for (i 
= 0, pane_count 
= panes
.GetCount(); i 
< pane_count
; ++i
) 
 341         wxPaneInfo
& pane 
= panes
.Item(i
); 
 342         pane
.state 
&= ~wxPaneInfo::optionActive
; 
 343         if (pane
.window 
== active_pane
) 
 344             pane
.state 
|= wxPaneInfo::optionActive
; 
 349 // this function is used to sort panes by dock position 
 350 static int PaneSortFunc(wxPaneInfo
** p1
, wxPaneInfo
** p2
) 
 352     return ((*p1
)->dock_pos 
< (*p2
)->dock_pos
) ? -1 : 1; 
 356 // -- wxFrameManager class implementation -- 
 359 BEGIN_EVENT_TABLE(wxFrameManager
, wxEvtHandler
) 
 360     EVT_AUI_PANEBUTTON(wxFrameManager::OnPaneButton
) 
 361     EVT_PAINT(wxFrameManager::OnPaint
) 
 362     EVT_ERASE_BACKGROUND(wxFrameManager::OnEraseBackground
) 
 363     EVT_SIZE(wxFrameManager::OnSize
) 
 364     EVT_SET_CURSOR(wxFrameManager::OnSetCursor
) 
 365     EVT_LEFT_DOWN(wxFrameManager::OnLeftDown
) 
 366     EVT_LEFT_UP(wxFrameManager::OnLeftUp
) 
 367     EVT_MOTION(wxFrameManager::OnMotion
) 
 368     EVT_LEAVE_WINDOW(wxFrameManager::OnLeaveWindow
) 
 369     EVT_CHILD_FOCUS(wxFrameManager::OnChildFocus
) 
 370     EVT_TIMER(101, wxFrameManager::OnHintFadeTimer
) 
 374 wxFrameManager::wxFrameManager(wxFrame
* frame
, unsigned int flags
) 
 376     m_action 
= actionNone
; 
 377     m_last_mouse_move 
= wxPoint(); 
 378     m_hover_button 
= NULL
; 
 379     m_art 
= new wxDefaultDockArt
; 
 389 wxFrameManager::~wxFrameManager() 
 394 // GetPane() looks up a wxPaneInfo structure based 
 395 // on the supplied window pointer.  Upon failure, GetPane() 
 396 // returns an empty wxPaneInfo, a condition which can be checked 
 397 // by calling wxPaneInfo::IsOk(). 
 399 // The pane info's structure may then be modified.  Once a pane's 
 400 // info is modified, wxFrameManager::Update() must be called to 
 401 // realize the changes in the UI. 
 403 wxPaneInfo
& wxFrameManager::GetPane(wxWindow
* window
) 
 406     for (i 
= 0, pane_count 
= m_panes
.GetCount(); i 
< pane_count
; ++i
) 
 408         wxPaneInfo
& p 
= m_panes
.Item(i
); 
 409         if (p
.window 
== window
) 
 412     return wxNullPaneInfo
; 
 415 // this version of GetPane() looks up a pane based on a 
 416 // 'pane name', see above comment for more info 
 417 wxPaneInfo
& wxFrameManager::GetPane(const wxString
& name
) 
 420     for (i 
= 0, pane_count 
= m_panes
.GetCount(); i 
< pane_count
; ++i
) 
 422         wxPaneInfo
& p 
= m_panes
.Item(i
); 
 426     return wxNullPaneInfo
; 
 429 // GetAllPanes() returns a reference to all the pane info structures 
 430 wxPaneInfoArray
& wxFrameManager::GetAllPanes() 
 435 // HitTest() is an internal function which determines 
 436 // which UI item the specified coordinates are over 
 437 // (x,y) specify a position in client coordinates 
 438 wxDockUIPart
* wxFrameManager::HitTest(int x
, int y
) 
 440     wxDockUIPart
* result 
= NULL
; 
 443     for (i 
= 0, part_count 
= m_uiparts
.GetCount(); i 
< part_count
; ++i
) 
 445         wxDockUIPart
* item 
= &m_uiparts
.Item(i
); 
 447         // we are not interested in typeDock, because this space 
 448         // isn't used to draw anything, just for measurements; 
 449         // besides, the entire dock area is covered with other 
 450         // rectangles, which we are interested in. 
 451         if (item
->type 
== wxDockUIPart::typeDock
) 
 454         // if we already have a hit on a more specific item, we are not 
 455         // interested in a pane hit.  If, however, we don't already have 
 456         // a hit, returning a pane hit is necessary for some operations 
 457         if ((item
->type 
== wxDockUIPart::typePane 
|| 
 458             item
->type 
== wxDockUIPart::typePaneBorder
) && result
) 
 461         // if the point is inside the rectangle, we have a hit 
 462         if (item
->rect
.Inside(x
,y
)) 
 470 // SetFlags() and GetFlags() allow the owner to set various 
 471 // options which are global to wxFrameManager 
 472 void wxFrameManager::SetFlags(unsigned int flags
) 
 477 unsigned int wxFrameManager::GetFlags() const 
 483 // SetFrame() is usually called once when the frame 
 484 // manager class is being initialized.  "frame" specifies 
 485 // the frame which should be managed by the frame mananger 
 486 void wxFrameManager::SetFrame(wxFrame
* frame
) 
 488     wxASSERT_MSG(frame
, wxT("specified frame must be non-NULL")); 
 491     m_frame
->PushEventHandler(this); 
 494     // if the owner is going to manage an MDI parent frame, 
 495     // we need to add the MDI client window as the default 
 498     if (frame
->IsKindOf(CLASSINFO(wxMDIParentFrame
))) 
 500         wxMDIParentFrame
* mdi_frame 
= (wxMDIParentFrame
*)frame
; 
 501         wxWindow
* client_window 
= mdi_frame
->GetClientWindow(); 
 503         wxASSERT_MSG(client_window
, wxT("Client window is NULL!")); 
 505         AddPane(client_window
, 
 506                 wxPaneInfo().Name(wxT("mdiclient")). 
 507                 CenterPane().PaneBorder(false)); 
 513 // UnInit() must be called, usually in the destructor 
 514 // of the frame class.   If it is not called, usually this 
 515 // will result in a crash upon program exit 
 516 void wxFrameManager::UnInit() 
 518     m_frame
->RemoveEventHandler(this); 
 521 // GetFrame() returns the frame pointer being managed by wxFrameManager 
 522 wxFrame
* wxFrameManager::GetFrame() const 
 527 wxDockArt
* wxFrameManager::GetArtProvider() const 
 532 void wxFrameManager::ProcessMgrEvent(wxFrameManagerEvent
& event
) 
 534     // first, give the owner frame a chance to override 
 537         if (m_frame
->ProcessEvent(event
)) 
 544 // SetArtProvider() instructs wxFrameManager to use the 
 545 // specified art provider for all drawing calls.  This allows 
 546 // plugable look-and-feel features.  The pointer that is 
 547 // passed to this method subsequently belongs to wxFrameManager, 
 548 // and is deleted in the frame manager destructor 
 549 void wxFrameManager::SetArtProvider(wxDockArt
* art_provider
) 
 551     // delete the last art provider, if any 
 554     // assign the new art provider 
 555     m_art 
= art_provider
; 
 559 bool wxFrameManager::AddPane(wxWindow
* window
, const wxPaneInfo
& pane_info
) 
 561     // check if the pane has a valid window 
 565     // check if the pane already exists 
 566     if (GetPane(pane_info
.window
).IsOk()) 
 569     m_panes
.Add(pane_info
); 
 571     wxPaneInfo
& pinfo 
= m_panes
.Last(); 
 573     // set the pane window 
 574     pinfo
.window 
= window
; 
 576     // if the pane's name identifier is blank, create a random string 
 577     if (pinfo
.name
.empty()) 
 579         pinfo
.name
.Printf(wxT("%08lx%08x%08x%08lx"), 
 580              ((unsigned long)pinfo
.window
) & 0xffffffff, 
 581              (unsigned int)time(NULL
), 
 582              (unsigned int)clock(), 
 583              (unsigned long)m_panes
.GetCount()); 
 586     // set initial proportion (if not already set) 
 587     if (pinfo
.dock_proportion 
== 0) 
 588         pinfo
.dock_proportion 
= 100000; 
 590     if (pinfo
.HasCloseButton() && 
 591         pinfo
.buttons
.size() == 0) 
 594         button
.button_id 
= wxPaneInfo::buttonClose
; 
 595         pinfo
.buttons
.Add(button
); 
 598     if (pinfo
.best_size 
== wxDefaultSize 
&& 
 601         pinfo
.best_size 
= pinfo
.window
->GetClientSize(); 
 603         if (pinfo
.window
->IsKindOf(CLASSINFO(wxToolBar
))) 
 605             // GetClientSize() doesn't get the best size for 
 606             // a toolbar under some newer versions of wxWidgets, 
 607             // so use GetBestSize() 
 608             pinfo
.best_size 
= pinfo
.window
->GetBestSize(); 
 610             // for some reason, wxToolBar::GetBestSize() is returning 
 611             // a size that is a pixel shy of the correct amount. 
 612             // I believe this to be the correct action, until 
 613             // wxToolBar::GetBestSize() is fixed.  Is this assumption 
 618         if (pinfo
.min_size 
!= wxDefaultSize
) 
 620             if (pinfo
.best_size
.x 
< pinfo
.min_size
.x
) 
 621                 pinfo
.best_size
.x 
= pinfo
.min_size
.x
; 
 622             if (pinfo
.best_size
.y 
< pinfo
.min_size
.y
) 
 623                 pinfo
.best_size
.y 
= pinfo
.min_size
.y
; 
 630 bool wxFrameManager::AddPane(wxWindow
* window
, 
 632                              const wxString
& caption
) 
 635     pinfo
.Caption(caption
); 
 638         case wxTOP
:    pinfo
.Top(); break; 
 639         case wxBOTTOM
: pinfo
.Bottom(); break; 
 640         case wxLEFT
:   pinfo
.Left(); break; 
 641         case wxRIGHT
:  pinfo
.Right(); break; 
 642         case wxCENTER
: pinfo
.CenterPane(); break; 
 644     return AddPane(window
, pinfo
); 
 647 bool wxFrameManager::InsertPane(wxWindow
* window
, const wxPaneInfo
& pane_info
, 
 650     // shift the panes around, depending on the insert level 
 651     switch (insert_level
) 
 653         case wxAUI_INSERT_PANE
: 
 654             DoInsertPane(m_panes
, 
 655                  pane_info
.dock_direction
, 
 656                  pane_info
.dock_layer
, 
 660         case wxAUI_INSERT_ROW
: 
 661             DoInsertDockRow(m_panes
, 
 662                  pane_info
.dock_direction
, 
 663                  pane_info
.dock_layer
, 
 666         case wxAUI_INSERT_DOCK
: 
 667             DoInsertDockLayer(m_panes
, 
 668                  pane_info
.dock_direction
, 
 669                  pane_info
.dock_layer
); 
 673     // if the window already exists, we are basically just moving/inserting the 
 674     // existing window.  If it doesn't exist, we need to add it and insert it 
 675     wxPaneInfo
& existing_pane 
= GetPane(window
); 
 676     if (!existing_pane
.IsOk()) 
 678         return AddPane(window
, pane_info
); 
 682         if (pane_info
.IsFloating()) 
 684             existing_pane
.Float(); 
 685             if (pane_info
.floating_pos 
!= wxDefaultPosition
) 
 686                 existing_pane
.FloatingPosition(pane_info
.floating_pos
); 
 687             if (pane_info
.floating_size 
!= wxDefaultSize
) 
 688                 existing_pane
.FloatingSize(pane_info
.floating_size
); 
 692             existing_pane
.Direction(pane_info
.dock_direction
); 
 693             existing_pane
.Layer(pane_info
.dock_layer
); 
 694             existing_pane
.Row(pane_info
.dock_row
); 
 695             existing_pane
.Position(pane_info
.dock_pos
); 
 703 // DetachPane() removes a pane from the frame manager.  This 
 704 // method will not destroy the window that is removed. 
 705 bool wxFrameManager::DetachPane(wxWindow
* window
) 
 708     for (i 
= 0, count 
= m_panes
.GetCount(); i 
< count
; ++i
) 
 710         wxPaneInfo
& p 
= m_panes
.Item(i
); 
 711         if (p
.window 
== window
) 
 715                 // we have a floating frame which is being detached. We need to 
 716                 // reparent it to m_frame and destroy the floating frame 
 719                 p
.window
->SetSize(1,1); 
 720                 p
.frame
->Show(false); 
 722                 // reparent to m_frame and destroy the pane 
 723                 p
.window
->Reparent(m_frame
); 
 724                 p
.frame
->SetSizer(NULL
); 
 736 // EscapeDelimiters() changes ";" into "\;" and "|" into "\|" 
 737 // in the input string.  This is an internal functions which is 
 738 // used for saving perspectives 
 739 static wxString 
EscapeDelimiters(const wxString
& s
) 
 742     result
.Alloc(s
.length()); 
 743     const wxChar
* ch 
= s
.c_str(); 
 746         if (*ch 
== wxT(';') || *ch 
== wxT('|')) 
 755 // SavePerspective() saves all pane information as a single string. 
 756 // This string may later be fed into LoadPerspective() to restore 
 757 // all pane settings.  This save and load mechanism allows an 
 758 // exact pane configuration to be saved and restored at a later time 
 760 wxString 
wxFrameManager::SavePerspective() 
 764     result 
= wxT("layout1|"); 
 766     int pane_i
, pane_count 
= m_panes
.GetCount(); 
 767     for (pane_i 
= 0; pane_i 
< pane_count
; ++pane_i
) 
 769         wxPaneInfo
& pane 
= m_panes
.Item(pane_i
); 
 771         result 
+= wxT("name="); 
 772         result 
+= EscapeDelimiters(pane
.name
); 
 775         result 
+= wxT("caption="); 
 776         result 
+= EscapeDelimiters(pane
.caption
); 
 779         result 
+= wxString::Format(wxT("state=%u;"), pane
.state
); 
 780         result 
+= wxString::Format(wxT("dir=%d;"), pane
.dock_direction
); 
 781         result 
+= wxString::Format(wxT("layer=%d;"), pane
.dock_layer
); 
 782         result 
+= wxString::Format(wxT("row=%d;"), pane
.dock_row
); 
 783         result 
+= wxString::Format(wxT("pos=%d;"), pane
.dock_pos
); 
 784         result 
+= wxString::Format(wxT("prop=%d;"), pane
.dock_proportion
); 
 785         result 
+= wxString::Format(wxT("bestw=%d;"), pane
.best_size
.x
); 
 786         result 
+= wxString::Format(wxT("besth=%d;"), pane
.best_size
.y
); 
 787         result 
+= wxString::Format(wxT("minw=%d;"), pane
.min_size
.x
); 
 788         result 
+= wxString::Format(wxT("minh=%d;"), pane
.min_size
.y
); 
 789         result 
+= wxString::Format(wxT("maxw=%d;"), pane
.max_size
.x
); 
 790         result 
+= wxString::Format(wxT("maxh=%d;"), pane
.max_size
.y
); 
 791         result 
+= wxString::Format(wxT("floatx=%d;"), pane
.floating_pos
.x
); 
 792         result 
+= wxString::Format(wxT("floaty=%d;"), pane
.floating_pos
.y
); 
 793         result 
+= wxString::Format(wxT("floatw=%d;"), pane
.floating_size
.x
); 
 794         result 
+= wxString::Format(wxT("floath=%d"), pane
.floating_size
.y
); 
 798     int dock_i
, dock_count 
= m_docks
.GetCount(); 
 799     for (dock_i 
= 0; dock_i 
< dock_count
; ++dock_i
) 
 801         wxDockInfo
& dock 
= m_docks
.Item(dock_i
); 
 803         result 
+= wxString::Format(wxT("dock_size(%d,%d,%d)=%d|"), 
 804                                    dock
.dock_direction
, dock
.dock_layer
, 
 805                                    dock
.dock_row
, dock
.size
); 
 811 // LoadPerspective() loads a layout which was saved with SavePerspective() 
 812 // If the "update" flag parameter is true, the GUI will immediately be updated 
 814 bool wxFrameManager::LoadPerspective(const wxString
& layout
, bool update
) 
 816     wxString input 
= layout
; 
 819     // check layout string version 
 820     part 
= input
.BeforeFirst(wxT('|')); 
 821     input 
= input
.AfterFirst(wxT('|')); 
 824     if (part 
!= wxT("layout1")) 
 828     // mark all panes currently managed as docked and hidden 
 829     int pane_i
, pane_count 
= m_panes
.GetCount(); 
 830     for (pane_i 
= 0; pane_i 
< pane_count
; ++pane_i
) 
 831         m_panes
.Item(pane_i
).Dock().Hide(); 
 833     // clear out the dock array; this will be reconstructed 
 836     // replace escaped characters so we can 
 837     // split up the string easily 
 838     input
.Replace(wxT("\\|"), wxT("\a")); 
 839     input
.Replace(wxT("\\;"), wxT("\b")); 
 845         wxString pane_part 
= input
.BeforeFirst(wxT('|')); 
 846         input 
= input
.AfterFirst(wxT('|')); 
 847         pane_part
.Trim(true); 
 849         // if the string is empty, we're done parsing 
 850         if (pane_part
.empty()) 
 854         if (pane_part
.Left(9) == wxT("dock_size")) 
 856             wxString val_name 
= pane_part
.BeforeFirst(wxT('=')); 
 857             wxString value 
= pane_part
.AfterFirst(wxT('=')); 
 859             long dir
, layer
, row
, size
; 
 860             wxString piece 
= val_name
.AfterFirst(wxT('(')); 
 861             piece 
= piece
.BeforeLast(wxT(')')); 
 862             piece
.BeforeFirst(wxT(',')).ToLong(&dir
); 
 863             piece 
= piece
.AfterFirst(wxT(',')); 
 864             piece
.BeforeFirst(wxT(',')).ToLong(&layer
); 
 865             piece
.AfterFirst(wxT(',')).ToLong(&row
); 
 869             dock
.dock_direction 
= dir
; 
 870             dock
.dock_layer 
= layer
; 
 879             wxString val_part 
= pane_part
.BeforeFirst(wxT(';')); 
 880             pane_part 
= pane_part
.AfterFirst(wxT(';')); 
 881             wxString val_name 
= val_part
.BeforeFirst(wxT('=')); 
 882             wxString value 
= val_part
.AfterFirst(wxT('=')); 
 883             val_name
.MakeLower(); 
 885             val_name
.Trim(false); 
 889             if (val_name
.empty()) 
 892             if (val_name 
== wxT("name")) 
 894             else if (val_name 
== wxT("caption")) 
 895                 pane
.caption 
= value
; 
 896             else if (val_name 
== wxT("state")) 
 897                 pane
.state 
= (unsigned int)wxAtoi(value
.c_str()); 
 898             else if (val_name 
== wxT("dir")) 
 899                 pane
.dock_direction 
= wxAtoi(value
.c_str()); 
 900             else if (val_name 
== wxT("layer")) 
 901                 pane
.dock_layer 
= wxAtoi(value
.c_str()); 
 902             else if (val_name 
== wxT("row")) 
 903                 pane
.dock_row 
= wxAtoi(value
.c_str()); 
 904             else if (val_name 
== wxT("pos")) 
 905                 pane
.dock_pos 
= wxAtoi(value
.c_str()); 
 906             else if (val_name 
== wxT("prop")) 
 907                 pane
.dock_proportion 
= wxAtoi(value
.c_str()); 
 908             else if (val_name 
== wxT("bestw")) 
 909                 pane
.best_size
.x 
= wxAtoi(value
.c_str()); 
 910             else if (val_name 
== wxT("besth")) 
 911                 pane
.best_size
.y 
= wxAtoi(value
.c_str()); 
 912             else if (val_name 
== wxT("minw")) 
 913                 pane
.min_size
.x 
= wxAtoi(value
.c_str()); 
 914             else if (val_name 
== wxT("minh")) 
 915                 pane
.min_size
.y 
= wxAtoi(value
.c_str()); 
 916             else if (val_name 
== wxT("maxw")) 
 917                 pane
.max_size
.x 
= wxAtoi(value
.c_str()); 
 918             else if (val_name 
== wxT("maxh")) 
 919                 pane
.max_size
.y 
= wxAtoi(value
.c_str()); 
 920             else if (val_name 
== wxT("floatx")) 
 921                 pane
.floating_pos
.x 
= wxAtoi(value
.c_str()); 
 922             else if (val_name 
== wxT("floaty")) 
 923                 pane
.floating_pos
.y 
= wxAtoi(value
.c_str()); 
 924             else if (val_name 
== wxT("floatw")) 
 925                 pane
.floating_size
.x 
= wxAtoi(value
.c_str()); 
 926             else if (val_name 
== wxT("floath")) 
 927                 pane
.floating_size
.y 
= wxAtoi(value
.c_str()); 
 929                 wxFAIL_MSG(wxT("Bad Perspective String")); 
 933         // replace escaped characters so we can 
 934         // split up the string easily 
 935         pane
.name
.Replace(wxT("\a"), wxT("|")); 
 936         pane
.name
.Replace(wxT("\b"), wxT(";")); 
 937         pane
.caption
.Replace(wxT("\a"), wxT("|")); 
 938         pane
.caption
.Replace(wxT("\b"), wxT(";")); 
 940         wxPaneInfo
& p 
= GetPane(pane
.name
); 
 943             // the pane window couldn't be found 
 944             // in the existing layout 
 948         pane
.window 
= p
.window
; 
 949         pane
.frame 
= p
.frame
; 
 950         pane
.buttons 
= p
.buttons
; 
 961 void wxFrameManager::GetPanePositionsAndSizes(wxDockInfo
& dock
, 
 962                                               wxArrayInt
& positions
, 
 965     int caption_size 
= m_art
->GetMetric(wxAUI_ART_CAPTION_SIZE
); 
 966     int pane_border_size 
= m_art
->GetMetric(wxAUI_ART_PANE_BORDER_SIZE
); 
 967     int gripper_size 
= m_art
->GetMetric(wxAUI_ART_GRIPPER_SIZE
); 
 972     int offset
, action_pane 
= -1; 
 973     int pane_i
, pane_count 
= dock
.panes
.GetCount(); 
 975     // find the pane marked as our action pane 
 976     for (pane_i 
= 0; pane_i 
< pane_count
; ++pane_i
) 
 978         wxPaneInfo
& pane 
= *(dock
.panes
.Item(pane_i
)); 
 980         if (pane
.state 
& wxPaneInfo::actionPane
) 
 982             wxASSERT_MSG(action_pane
==-1, wxT("Too many fixed action panes")); 
 983             action_pane 
= pane_i
; 
 987     // set up each panes default position, and 
 988     // determine the size (width or height, depending 
 989     // on the dock's orientation) of each pane 
 990     for (pane_i 
= 0; pane_i 
< pane_count
; ++pane_i
) 
 992         wxPaneInfo
& pane 
= *(dock
.panes
.Item(pane_i
)); 
 993         positions
.Add(pane
.dock_pos
); 
 996         if (pane
.HasBorder()) 
 997             size 
+= (pane_border_size
*2); 
 999         if (dock
.IsHorizontal()) 
1001             if (pane
.HasGripper() && !pane
.HasGripperTop()) 
1002                 size 
+= gripper_size
; 
1003             size 
+= pane
.best_size
.x
; 
1007             if (pane
.HasGripper() && pane
.HasGripperTop()) 
1008                 size 
+= gripper_size
; 
1010             if (pane
.HasCaption()) 
1011                 size 
+= caption_size
; 
1012             size 
+= pane
.best_size
.y
; 
1018     // if there is no action pane, just return the default 
1019     // positions (as specified in pane.pane_pos) 
1020     if (action_pane 
== -1) 
1024     for (pane_i 
= action_pane
-1; pane_i 
>= 0; --pane_i
) 
1026         int amount 
= positions
[pane_i
+1] - (positions
[pane_i
] + sizes
[pane_i
]); 
1031             positions
[pane_i
] -= -amount
; 
1033         offset 
+= sizes
[pane_i
]; 
1036     // if the dock mode is fixed, make sure none of the panes 
1037     // overlap; we will bump panes that overlap 
1039     for (pane_i 
= action_pane
; pane_i 
< pane_count
; ++pane_i
) 
1041         int amount 
= positions
[pane_i
] - offset
; 
1045             positions
[pane_i
] += -amount
; 
1047         offset 
+= sizes
[pane_i
]; 
1052 void wxFrameManager::LayoutAddPane(wxSizer
* cont
, 
1055                                    wxDockUIPartArray
& uiparts
, 
1059     wxSizerItem
* sizer_item
; 
1061     int caption_size 
= m_art
->GetMetric(wxAUI_ART_CAPTION_SIZE
); 
1062     int gripper_size 
= m_art
->GetMetric(wxAUI_ART_GRIPPER_SIZE
); 
1063     int pane_border_size 
= m_art
->GetMetric(wxAUI_ART_PANE_BORDER_SIZE
); 
1064     int pane_button_size 
= m_art
->GetMetric(wxAUI_ART_PANE_BUTTON_SIZE
); 
1066     // find out the orientation of the item (orientation for panes 
1067     // is the same as the dock's orientation) 
1069     if (dock
.IsHorizontal()) 
1070         orientation 
= wxHORIZONTAL
; 
1072         orientation 
= wxVERTICAL
; 
1074     // this variable will store the proportion 
1075     // value that the pane will receive 
1076     int pane_proportion 
= pane
.dock_proportion
; 
1078     wxBoxSizer
* horz_pane_sizer 
= new wxBoxSizer(wxHORIZONTAL
); 
1079     wxBoxSizer
* vert_pane_sizer 
= new wxBoxSizer(wxVERTICAL
); 
1081     if (pane
.HasGripper()) 
1083         if (pane
.HasGripperTop()) 
1084             sizer_item 
= vert_pane_sizer 
->Add(1, gripper_size
, 0, wxEXPAND
); 
1086             sizer_item 
= horz_pane_sizer 
->Add(gripper_size
, 1, 0, wxEXPAND
); 
1088         part
.type 
= wxDockUIPart::typeGripper
; 
1092         part
.orientation 
= orientation
; 
1093         part
.cont_sizer 
= horz_pane_sizer
; 
1094         part
.sizer_item 
= sizer_item
; 
1098     if (pane
.HasCaption()) 
1100         // create the caption sizer 
1101         wxBoxSizer
* caption_sizer 
= new wxBoxSizer(wxHORIZONTAL
); 
1103         sizer_item 
= caption_sizer
->Add(1, caption_size
, 1, wxEXPAND
); 
1105         part
.type 
= wxDockUIPart::typeCaption
; 
1109         part
.orientation 
= orientation
; 
1110         part
.cont_sizer 
= vert_pane_sizer
; 
1111         part
.sizer_item 
= sizer_item
; 
1112         int caption_part_idx 
= uiparts
.GetCount(); 
1115         // add pane buttons to the caption 
1116         int i
, button_count
; 
1117         for (i 
= 0, button_count 
= pane
.buttons
.GetCount(); 
1118              i 
< button_count
; ++i
) 
1120             wxPaneButton
& button 
= pane
.buttons
.Item(i
); 
1122             sizer_item 
= caption_sizer
->Add(pane_button_size
, 
1126             part
.type 
= wxDockUIPart::typePaneButton
; 
1129             part
.button 
= &button
; 
1130             part
.orientation 
= orientation
; 
1131             part
.cont_sizer 
= caption_sizer
; 
1132             part
.sizer_item 
= sizer_item
; 
1136         // add the caption sizer 
1137         sizer_item 
= vert_pane_sizer
->Add(caption_sizer
, 0, wxEXPAND
); 
1139         uiparts
.Item(caption_part_idx
).sizer_item 
= sizer_item
; 
1142     // add the pane window itself 
1145         sizer_item 
= vert_pane_sizer
->Add(1, 1, 1, wxEXPAND
); 
1149         sizer_item 
= vert_pane_sizer
->Add(pane
.window
, 1, wxEXPAND
); 
1150         vert_pane_sizer
->SetItemMinSize(pane
.window
, 1, 1); 
1153     part
.type 
= wxDockUIPart::typePane
; 
1157     part
.orientation 
= orientation
; 
1158     part
.cont_sizer 
= vert_pane_sizer
; 
1159     part
.sizer_item 
= sizer_item
; 
1163     // determine if the pane should have a minimum size; if the pane is 
1164     // non-resizable (fixed) then we must set a minimum size. Alternitavely, 
1165     // if the pane.min_size is set, we must use that value as well 
1167     wxSize min_size 
= pane
.min_size
; 
1170         if (min_size 
== wxDefaultSize
) 
1172             min_size 
= pane
.best_size
; 
1173             pane_proportion 
= 0; 
1177     if (min_size 
!= wxDefaultSize
) 
1179         vert_pane_sizer
->SetItemMinSize( 
1180                         vert_pane_sizer
->GetChildren().GetCount()-1, 
1181                         min_size
.x
, min_size
.y
); 
1185     // add the verticle sizer (caption, pane window) to the 
1186     // horizontal sizer (gripper, verticle sizer) 
1187     horz_pane_sizer
->Add(vert_pane_sizer
, 1, wxEXPAND
); 
1189     // finally, add the pane sizer to the dock sizer 
1191     if (pane
.HasBorder()) 
1193         // allowing space for the pane's border 
1194         sizer_item 
= cont
->Add(horz_pane_sizer
, pane_proportion
, 
1195                                wxEXPAND 
| wxALL
, pane_border_size
); 
1197         part
.type 
= wxDockUIPart::typePaneBorder
; 
1201         part
.orientation 
= orientation
; 
1202         part
.cont_sizer 
= cont
; 
1203         part
.sizer_item 
= sizer_item
; 
1208         sizer_item 
= cont
->Add(horz_pane_sizer
, pane_proportion
, wxEXPAND
); 
1212 void wxFrameManager::LayoutAddDock(wxSizer
* cont
, 
1214                                    wxDockUIPartArray
& uiparts
, 
1217     wxSizerItem
* sizer_item
; 
1220     int sash_size 
= m_art
->GetMetric(wxAUI_ART_SASH_SIZE
); 
1221     int orientation 
= dock
.IsHorizontal() ? wxHORIZONTAL 
: wxVERTICAL
; 
1223     // resizable bottom and right docks have a sash before them 
1224     if (!dock
.fixed 
&& (dock
.dock_direction 
== wxAUI_DOCK_BOTTOM 
|| 
1225                         dock
.dock_direction 
== wxAUI_DOCK_RIGHT
)) 
1227         sizer_item 
= cont
->Add(sash_size
, sash_size
, 0, wxEXPAND
); 
1229         part
.type 
= wxDockUIPart::typeDockSizer
; 
1230         part
.orientation 
= orientation
; 
1234         part
.cont_sizer 
= cont
; 
1235         part
.sizer_item 
= sizer_item
; 
1239     // create the sizer for the dock 
1240     wxSizer
* dock_sizer 
= new wxBoxSizer(orientation
); 
1242     // add each pane to the dock 
1243     int pane_i
, pane_count 
= dock
.panes
.GetCount(); 
1247         wxArrayInt pane_positions
, pane_sizes
; 
1249         // figure out the real pane positions we will 
1250         // use, without modifying the each pane's pane_pos member 
1251         GetPanePositionsAndSizes(dock
, pane_positions
, pane_sizes
); 
1254         for (pane_i 
= 0; pane_i 
< pane_count
; ++pane_i
) 
1256             wxPaneInfo
& pane 
= *(dock
.panes
.Item(pane_i
)); 
1257             int pane_pos 
= pane_positions
.Item(pane_i
); 
1259             int amount 
= pane_pos 
- offset
; 
1262                 if (dock
.IsVertical()) 
1263                     sizer_item 
= dock_sizer
->Add(1, amount
, 0, wxEXPAND
); 
1265                     sizer_item 
= dock_sizer
->Add(amount
, 1, 0, wxEXPAND
); 
1267                 part
.type 
= wxDockUIPart::typeBackground
; 
1271                 part
.orientation 
= (orientation
==wxHORIZONTAL
) ? wxVERTICAL
:wxHORIZONTAL
; 
1272                 part
.cont_sizer 
= dock_sizer
; 
1273                 part
.sizer_item 
= sizer_item
; 
1279             LayoutAddPane(dock_sizer
, dock
, pane
, uiparts
, spacer_only
); 
1281             offset 
+= pane_sizes
.Item(pane_i
); 
1284         // at the end add a very small stretchable background area 
1285         sizer_item 
= dock_sizer
->Add(1,1, 1, wxEXPAND
); 
1287         part
.type 
= wxDockUIPart::typeBackground
; 
1291         part
.orientation 
= orientation
; 
1292         part
.cont_sizer 
= dock_sizer
; 
1293         part
.sizer_item 
= sizer_item
; 
1298         for (pane_i 
= 0; pane_i 
< pane_count
; ++pane_i
) 
1300             wxPaneInfo
& pane 
= *(dock
.panes
.Item(pane_i
)); 
1302             // if this is not the first pane being added, 
1303             // we need to add a pane sizer 
1306                 sizer_item 
= dock_sizer
->Add(sash_size
, sash_size
, 0, wxEXPAND
); 
1308                 part
.type 
= wxDockUIPart::typePaneSizer
; 
1310                 part
.pane 
= dock
.panes
.Item(pane_i
-1); 
1312                 part
.orientation 
= (orientation
==wxHORIZONTAL
) ? wxVERTICAL
:wxHORIZONTAL
; 
1313                 part
.cont_sizer 
= dock_sizer
; 
1314                 part
.sizer_item 
= sizer_item
; 
1318             LayoutAddPane(dock_sizer
, dock
, pane
, uiparts
, spacer_only
); 
1322     if (dock
.dock_direction 
== wxAUI_DOCK_CENTER
) 
1323         sizer_item 
= cont
->Add(dock_sizer
, 1, wxEXPAND
); 
1325         sizer_item 
= cont
->Add(dock_sizer
, 0, wxEXPAND
); 
1327     part
.type 
= wxDockUIPart::typeDock
; 
1331     part
.orientation 
= orientation
; 
1332     part
.cont_sizer 
= cont
; 
1333     part
.sizer_item 
= sizer_item
; 
1336     if (dock
.IsHorizontal()) 
1337         cont
->SetItemMinSize(dock_sizer
, 0, dock
.size
); 
1339         cont
->SetItemMinSize(dock_sizer
, dock
.size
, 0); 
1341     //  top and left docks have a sash after them 
1342     if (!dock
.fixed 
&& (dock
.dock_direction 
== wxAUI_DOCK_TOP 
|| 
1343                         dock
.dock_direction 
== wxAUI_DOCK_LEFT
)) 
1345         sizer_item 
= cont
->Add(sash_size
, sash_size
, 0, wxEXPAND
); 
1347         part
.type 
= wxDockUIPart::typeDockSizer
; 
1351         part
.orientation 
= orientation
; 
1352         part
.cont_sizer 
= cont
; 
1353         part
.sizer_item 
= sizer_item
; 
1358 wxSizer
* wxFrameManager::LayoutAll(wxPaneInfoArray
& panes
, 
1359                                    wxDockInfoArray
& docks
, 
1360                                    wxDockUIPartArray
& uiparts
, 
1363     wxBoxSizer
* container 
= new wxBoxSizer(wxVERTICAL
); 
1365     int pane_border_size 
= m_art
->GetMetric(wxAUI_ART_PANE_BORDER_SIZE
); 
1366     int caption_size 
= m_art
->GetMetric(wxAUI_ART_CAPTION_SIZE
); 
1367     wxSize cli_size 
= m_frame
->GetClientSize(); 
1368     int i
, dock_count
, pane_count
; 
1371     // empty all docks out 
1372     for (i 
= 0, dock_count 
= docks
.GetCount(); i 
< dock_count
; ++i
) 
1373         docks
.Item(i
).panes
.Empty(); 
1375     // iterate through all known panes, filing each 
1376     // of them into the appropriate dock. If the 
1377     // pane does not exist in the dock, add it 
1378     for (i 
= 0, pane_count 
= panes
.GetCount(); i 
< pane_count
; ++i
) 
1380         wxPaneInfo
& p 
= panes
.Item(i
); 
1382         // find any docks in this layer 
1384         wxDockInfoPtrArray arr
; 
1385         FindDocks(docks
, p
.dock_direction
, p
.dock_layer
, p
.dock_row
, arr
); 
1387         if (arr
.GetCount() > 0) 
1393             // dock was not found, so we need to create a new one 
1395             d
.dock_direction 
= p
.dock_direction
; 
1396             d
.dock_layer 
= p
.dock_layer
; 
1397             d
.dock_row 
= p
.dock_row
; 
1399             dock 
= &docks
.Last(); 
1403         if (p
.IsDocked() && p
.IsShown()) 
1405             // remove the pane from any existing docks except this one 
1406             RemovePaneFromDocks(docks
, p
, dock
); 
1408             // pane needs to be added to the dock, 
1409             // if it doesn't already exist 
1410             if (!FindPaneInDock(*dock
, p
.window
)) 
1411                 dock
->panes
.Add(&p
); 
1415             // remove the pane from any existing docks 
1416             RemovePaneFromDocks(docks
, p
); 
1421     // remove any empty docks 
1422     for (i 
= docks
.GetCount()-1; i 
>= 0; --i
) 
1424         if (docks
.Item(i
).panes
.GetCount() == 0) 
1428     // configure the docks further 
1429     for (i 
= 0, dock_count 
= docks
.GetCount(); i 
< dock_count
; ++i
) 
1431         wxDockInfo
& dock 
= docks
.Item(i
); 
1432         int j
, dock_pane_count 
= dock
.panes
.GetCount(); 
1434         // sort the dock pane array by the pane's 
1435         // dock position (dock_pos), in ascending order 
1436         dock
.panes
.Sort(PaneSortFunc
); 
1438         // for newly created docks, set up their initial size 
1443             for (j 
= 0; j 
< dock_pane_count
; ++j
) 
1445                 wxPaneInfo
& pane 
= *dock
.panes
.Item(j
); 
1446                 wxSize pane_size 
= pane
.best_size
; 
1447                 if (pane_size 
== wxDefaultSize
) 
1448                     pane_size 
= pane
.min_size
; 
1449                 if (pane_size 
== wxDefaultSize
) 
1450                     pane_size 
= pane
.window
->GetSize(); 
1452                 if (dock
.IsHorizontal()) 
1453                     size 
= wxMax(pane_size
.y
, size
); 
1455                     size 
= wxMax(pane_size
.x
, size
); 
1458             // add space for the border (two times), but only 
1459             // if at least one pane inside the dock has a pane border 
1460             for (j 
= 0; j 
< dock_pane_count
; ++j
) 
1462                 if (dock
.panes
.Item(j
)->HasBorder()) 
1464                     size 
+= (pane_border_size
*2); 
1469             // if pane is on the top or bottom, add the caption height, 
1470             // but only if at least one pane inside the dock has a caption 
1471             if (dock
.IsHorizontal()) 
1473                 for (j 
= 0; j 
< dock_pane_count
; ++j
) 
1475                     if (dock
.panes
.Item(j
)->HasCaption()) 
1477                         size 
+= caption_size
; 
1483             // new dock's size may not be more than 1/3 of the frame size 
1484             if (dock
.IsHorizontal()) 
1485                 size 
= wxMin(size
, cli_size
.y
/3); 
1487                 size 
= wxMin(size
, cli_size
.x
/3); 
1495         // determine the dock's minimum size 
1496         bool plus_border 
= false; 
1497         bool plus_caption 
= false; 
1498         int dock_min_size 
= 0; 
1499         for (j 
= 0; j 
< dock_pane_count
; ++j
) 
1501             wxPaneInfo
& pane 
= *dock
.panes
.Item(j
); 
1502             if (pane
.min_size 
!= wxDefaultSize
) 
1504                 if (pane
.HasBorder()) 
1506                 if (pane
.HasCaption()) 
1507                     plus_caption 
= true; 
1508                 if (dock
.IsHorizontal()) 
1510                     if (pane
.min_size
.y 
> dock_min_size
) 
1511                         dock_min_size 
= pane
.min_size
.y
; 
1515                     if (pane
.min_size
.x 
> dock_min_size
) 
1516                         dock_min_size 
= pane
.min_size
.x
; 
1522             dock_min_size 
+= (pane_border_size
*2); 
1523         if (plus_caption 
&& dock
.IsHorizontal()) 
1524             dock_min_size 
+= (caption_size
); 
1526         dock
.min_size 
= dock_min_size
; 
1529         // if the pane's current size is less than it's 
1530         // minimum, increase the dock's size to it's minimum 
1531         if (dock
.size 
< dock
.min_size
) 
1532             dock
.size 
= dock
.min_size
; 
1535         // determine the dock's mode (fixed or proportional); 
1536         // determine whether the dock has only toolbars 
1537         bool action_pane_marked 
= false; 
1539         dock
.toolbar 
= true; 
1540         for (j 
= 0; j 
< dock_pane_count
; ++j
) 
1542             wxPaneInfo
& pane 
= *dock
.panes
.Item(j
); 
1543             if (!pane
.IsFixed()) 
1545             if (!pane
.IsToolbar()) 
1546                 dock
.toolbar 
= false; 
1547             if (pane
.state 
& wxPaneInfo::actionPane
) 
1548                 action_pane_marked 
= true; 
1552         // if the dock mode is proportional and not fixed-pixel, 
1553         // reassign the dock_pos to the sequential 0, 1, 2, 3; 
1554         // e.g. remove gaps like 1, 2, 30, 500 
1557             for (j 
= 0; j 
< dock_pane_count
; ++j
) 
1559                 wxPaneInfo
& pane 
= *dock
.panes
.Item(j
); 
1564         // if the dock mode is fixed, and none of the panes 
1565         // are being moved right now, make sure the panes 
1566         // do not overlap each other.  If they do, we will 
1567         // adjust the panes' positions 
1568         if (dock
.fixed 
&& !action_pane_marked
) 
1570             wxArrayInt pane_positions
, pane_sizes
; 
1571             GetPanePositionsAndSizes(dock
, pane_positions
, pane_sizes
); 
1574             for (j 
= 0; j 
< dock_pane_count
; ++j
) 
1576                 wxPaneInfo
& pane 
= *(dock
.panes
.Item(j
)); 
1577                 pane
.dock_pos 
= pane_positions
[j
]; 
1579                 int amount 
= pane
.dock_pos 
- offset
; 
1583                     pane
.dock_pos 
+= -amount
; 
1585                 offset 
+= pane_sizes
[j
]; 
1590     // discover the maximum dock layer 
1592     for (i 
= 0; i 
< dock_count
; ++i
) 
1593         max_layer 
= wxMax(max_layer
, docks
.Item(i
).dock_layer
); 
1596     // clear out uiparts 
1599     // create a bunch of box sizers, 
1600     // from the innermost level outwards. 
1601     wxSizer
* cont 
= NULL
; 
1602     wxSizer
* middle 
= NULL
; 
1606     for (layer 
= 0; layer 
<= max_layer
; ++layer
) 
1608         wxDockInfoPtrArray arr
; 
1610         // find any docks in this layer 
1611         FindDocks(docks
, -1, layer
, -1, arr
); 
1613         // if there aren't any, skip to the next layer 
1617         wxSizer
* old_cont 
= cont
; 
1619         // create a container which will hold this layer's 
1620         // docks (top, bottom, left, right) 
1621         cont 
= new wxBoxSizer(wxVERTICAL
); 
1624         // find any top docks in this layer 
1625         FindDocks(docks
, wxAUI_DOCK_TOP
, layer
, -1, arr
); 
1626         RenumberDockRows(arr
); 
1629             for (row 
= 0, row_count 
= arr
.GetCount(); row 
< row_count
; ++row
) 
1630                 LayoutAddDock(cont
, *arr
.Item(row
), uiparts
, spacer_only
); 
1634         // fill out the middle layer (which consists 
1635         // of left docks, content area and right docks) 
1637         middle 
= new wxBoxSizer(wxHORIZONTAL
); 
1639         // find any left docks in this layer 
1640         FindDocks(docks
, wxAUI_DOCK_LEFT
, layer
, -1, arr
); 
1641         RenumberDockRows(arr
); 
1644             for (row 
= 0, row_count 
= arr
.GetCount(); row 
< row_count
; ++row
) 
1645                 LayoutAddDock(middle
, *arr
.Item(row
), uiparts
, spacer_only
); 
1648         // add content dock (or previous layer's sizer 
1652             // find any center docks 
1653             FindDocks(docks
, wxAUI_DOCK_CENTER
, -1, -1, arr
); 
1656                 for (row 
= 0,row_count 
= arr
.GetCount(); row
<row_count
; ++row
) 
1657                    LayoutAddDock(middle
, *arr
.Item(row
), uiparts
, spacer_only
); 
1661                 // there are no center docks, add a background area 
1662                 wxSizerItem
* sizer_item 
= middle
->Add(1,1, 1, wxEXPAND
); 
1664                 part
.type 
= wxDockUIPart::typeBackground
; 
1668                 part
.cont_sizer 
= middle
; 
1669                 part
.sizer_item 
= sizer_item
; 
1675             middle
->Add(old_cont
, 1, wxEXPAND
); 
1678         // find any right docks in this layer 
1679         FindDocks(docks
, wxAUI_DOCK_RIGHT
, layer
, -1, arr
); 
1680         RenumberDockRows(arr
); 
1683             for (row 
= arr
.GetCount()-1; row 
>= 0; --row
) 
1684                 LayoutAddDock(middle
, *arr
.Item(row
), uiparts
, spacer_only
); 
1687         cont
->Add(middle
, 1, wxEXPAND
); 
1691         // find any bottom docks in this layer 
1692         FindDocks(docks
, wxAUI_DOCK_BOTTOM
, layer
, -1, arr
); 
1693         RenumberDockRows(arr
); 
1696             for (row 
= arr
.GetCount()-1; row 
>= 0; --row
) 
1697                 LayoutAddDock(cont
, *arr
.Item(row
), uiparts
, spacer_only
); 
1704         // no sizer available, because there are no docks, 
1705         // therefore we will create a simple background area 
1706         cont 
= new wxBoxSizer(wxVERTICAL
); 
1707         wxSizerItem
* sizer_item 
= cont
->Add(1,1, 1, wxEXPAND
); 
1709         part
.type 
= wxDockUIPart::typeBackground
; 
1713         part
.cont_sizer 
= middle
; 
1714         part
.sizer_item 
= sizer_item
; 
1718     container
->Add(cont
, 1, wxEXPAND
); 
1723 // Update() updates the layout.  Whenever changes are made to 
1724 // one or more panes, this function should be called.  It is the 
1725 // external entry point for running the layout engine. 
1727 void wxFrameManager::Update() 
1730     int i
, pane_count 
= m_panes
.GetCount(); 
1732     // delete old sizer first 
1733     m_frame
->SetSizer(NULL
); 
1735     // destroy floating panes which have been 
1736     // redocked or are becoming non-floating 
1737     for (i 
= 0; i 
< pane_count
; ++i
) 
1739         wxPaneInfo
& p 
= m_panes
.Item(i
); 
1741         if (!p
.IsFloating() && p
.frame
) 
1743             // because the pane is no longer in a floating, we need to 
1744             // reparent it to m_frame and destroy the floating frame 
1747             p
.window
->SetSize(1,1); 
1748             p
.frame
->Show(false); 
1750             // reparent to m_frame and destroy the pane 
1751             p
.window
->Reparent(m_frame
); 
1752             p
.frame
->SetSizer(NULL
); 
1759     // create a layout for all of the panes 
1760     sizer 
= LayoutAll(m_panes
, m_docks
, m_uiparts
, false); 
1762     // hide or show panes as necessary, 
1763     // and float panes as necessary 
1764     for (i 
= 0; i 
< pane_count
; ++i
) 
1766         wxPaneInfo
& p 
= m_panes
.Item(i
); 
1770             if (p
.frame 
== NULL
) 
1772                 // we need to create a frame for this 
1773                 // pane, which has recently been floated 
1774                 wxFloatingPane
* frame 
= new wxFloatingPane(m_frame
, 
1779                 // on MSW, if the owner desires transparent dragging, and 
1780                 // the dragging is happening right now, then the floating 
1781                 // window should have this style by default 
1783                 if (m_action 
== actionDragFloatingPane 
&& 
1784                     (m_flags 
& wxAUI_MGR_TRANSPARENT_DRAG
)) 
1785                         MakeWindowTransparent(frame
, 150); 
1788                 frame
->SetPaneWindow(p
); 
1798                 // frame already exists, make sure it's position 
1799                 // and size reflect the information in wxPaneInfo 
1800                 if (p
.frame
->GetPosition() != p
.floating_pos
) 
1802                     p
.frame
->SetSize(p
.floating_pos
.x
, p
.floating_pos
.y
, 
1803                                      -1, -1, wxSIZE_USE_EXISTING
); 
1804                     //p.frame->Move(p.floating_pos.x, p.floating_pos.y); 
1807                  p
.frame
->Show(p
.IsShown()); 
1812             p
.window
->Show(p
.IsShown()); 
1815         // if "active panes" are no longer allowed, clear 
1816         // any optionActive values from the pane states 
1817         if ((m_flags 
& wxAUI_MGR_ALLOW_ACTIVE_PANE
) == 0) 
1819             p
.state 
&= ~wxPaneInfo::optionActive
; 
1824     // keep track of the old window rectangles so we can 
1825     // refresh those windows whose rect has changed 
1826     wxAuiRectArray old_pane_rects
; 
1827     for (i 
= 0; i 
< pane_count
; ++i
) 
1830         wxPaneInfo
& p 
= m_panes
.Item(i
); 
1832         if (p
.window 
&& p
.IsShown() && p
.IsDocked()) 
1835         old_pane_rects
.Add(r
); 
1841     // apply the new sizer 
1842     m_frame
->SetSizer(sizer
); 
1843     m_frame
->SetAutoLayout(false); 
1848     // now that the frame layout is done, we need to check 
1849     // the new pane rectangles against the old rectangles that 
1850     // we saved a few lines above here.  If the rectangles have 
1851     // changed, the corresponding panes must also be updated 
1852     for (i 
= 0; i 
< pane_count
; ++i
) 
1854         wxPaneInfo
& p 
= m_panes
.Item(i
); 
1855         if (p
.window 
&& p
.window
->IsShown() && p
.IsDocked()) 
1857             if (p
.rect 
!= old_pane_rects
[i
]) 
1859                 p
.window
->Refresh(); 
1868     // set frame's minimum size 
1871     // N.B. More work needs to be done on frame minimum sizes; 
1872     // this is some intresting code that imposes the minimum size, 
1873     // but we may want to include a more flexible mechanism or 
1874     // options for multiple minimum-size modes, e.g. strict or lax 
1875     wxSize min_size = sizer->GetMinSize(); 
1876     wxSize frame_size = m_frame->GetSize(); 
1877     wxSize client_size = m_frame->GetClientSize(); 
1879     wxSize minframe_size(min_size.x+frame_size.x-client_size.x, 
1880                          min_size.y+frame_size.y-client_size.y ); 
1882     m_frame->SetMinSize(minframe_size); 
1884     if (frame_size.x < minframe_size.x || 
1885         frame_size.y < minframe_size.y) 
1886             sizer->Fit(m_frame); 
1891 // DoFrameLayout() is an internal function which invokes wxSizer::Layout 
1892 // on the frame's main sizer, then measures all the various UI items 
1893 // and updates their internal rectangles.  This should always be called 
1894 // instead of calling m_frame->Layout() directly 
1896 void wxFrameManager::DoFrameLayout() 
1901     for (i 
= 0, part_count 
= m_uiparts
.GetCount(); i 
< part_count
; ++i
) 
1903         wxDockUIPart
& part 
= m_uiparts
.Item(i
); 
1905         // get the rectangle of the UI part 
1906         // originally, this code looked like this: 
1907         //    part.rect = wxRect(part.sizer_item->GetPosition(), 
1908         //                       part.sizer_item->GetSize()); 
1909         // this worked quite well, with one exception: the mdi 
1910         // client window had a "deferred" size variable 
1911         // that returned the wrong size.  It looks like 
1912         // a bug in wx, because the former size of the window 
1913         // was being returned.  So, we will retrieve the part's 
1914         // rectangle via other means 
1917         part
.rect 
= part
.sizer_item
->GetRect(); 
1918         int flag 
= part
.sizer_item
->GetFlag(); 
1919         int border 
= part
.sizer_item
->GetBorder(); 
1922             part
.rect
.y 
-= border
; 
1923             part
.rect
.height 
+= border
; 
1927             part
.rect
.x 
-= border
; 
1928             part
.rect
.width 
+= border
; 
1930         if (flag 
& wxBOTTOM
) 
1931             part
.rect
.height 
+= border
; 
1933             part
.rect
.width 
+= border
; 
1936         if (part
.type 
== wxDockUIPart::typeDock
) 
1937             part
.dock
->rect 
= part
.rect
; 
1938         if (part
.type 
== wxDockUIPart::typePane
) 
1939             part
.pane
->rect 
= part
.rect
; 
1943 // GetPanePart() looks up the pane the pane border UI part (or the regular 
1944 // pane part if there is no border). This allows the caller to get the exact 
1945 // rectangle of the pane in question, including decorations like 
1946 // caption and border (if any). 
1948 wxDockUIPart
* wxFrameManager::GetPanePart(wxWindow
* wnd
) 
1951     for (i 
= 0, part_count 
= m_uiparts
.GetCount(); i 
< part_count
; ++i
) 
1953         wxDockUIPart
& part 
= m_uiparts
.Item(i
); 
1954         if (part
.type 
== wxDockUIPart::typePaneBorder 
&& 
1955             part
.pane 
&& part
.pane
->window 
== wnd
) 
1958     for (i 
= 0, part_count 
= m_uiparts
.GetCount(); i 
< part_count
; ++i
) 
1960         wxDockUIPart
& part 
= m_uiparts
.Item(i
); 
1961         if (part
.type 
== wxDockUIPart::typePane 
&& 
1962             part
.pane 
&& part
.pane
->window 
== wnd
) 
1970 // GetDockPixelOffset() is an internal function which returns 
1971 // a dock's offset in pixels from the left side of the window 
1972 // (for horizontal docks) or from the top of the window (for 
1973 // vertical docks).  This value is necessary for calculating 
1974 // fixel-pane/toolbar offsets when they are dragged. 
1976 int wxFrameManager::GetDockPixelOffset(wxPaneInfo
& test
) 
1978     // the only way to accurately calculate the dock's 
1979     // offset is to actually run a theoretical layout 
1981     int i
, part_count
, dock_count
; 
1982     wxDockInfoArray docks
; 
1983     wxPaneInfoArray panes
; 
1984     wxDockUIPartArray uiparts
; 
1985     CopyDocksAndPanes(docks
, panes
, m_docks
, m_panes
); 
1988     wxSizer
* sizer 
= LayoutAll(panes
, docks
, uiparts
, true); 
1989     wxSize client_size 
= m_frame
->GetClientSize(); 
1990     sizer
->SetDimension(0, 0, client_size
.x
, client_size
.y
); 
1993     for (i 
= 0, part_count 
= uiparts
.GetCount(); i 
< part_count
; ++i
) 
1995         wxDockUIPart
& part 
= uiparts
.Item(i
); 
1996         part
.rect 
= wxRect(part
.sizer_item
->GetPosition(), 
1997                            part
.sizer_item
->GetSize()); 
1998         if (part
.type 
== wxDockUIPart::typeDock
) 
1999             part
.dock
->rect 
= part
.rect
; 
2004     for (i 
= 0, dock_count 
= docks
.GetCount(); i 
< dock_count
; ++i
) 
2006         wxDockInfo
& dock 
= docks
.Item(i
); 
2007         if (test
.dock_direction 
== dock
.dock_direction 
&& 
2008             test
.dock_layer
==dock
.dock_layer 
&& test
.dock_row
==dock
.dock_row
) 
2010             if (dock
.IsVertical()) 
2022 // ProcessDockResult() is a utility function used by DoDrop() - it checks 
2023 // if a dock operation is allowed, the new dock position is copied into 
2024 // the target info.  If the operation was allowed, the function returns true. 
2026 static bool ProcessDockResult(wxPaneInfo
& target
, 
2027                               const wxPaneInfo
& new_pos
) 
2029     bool allowed 
= false; 
2030     switch (new_pos
.dock_direction
) 
2032         case wxAUI_DOCK_TOP
:    allowed 
= target
.IsTopDockable();    break; 
2033         case wxAUI_DOCK_BOTTOM
: allowed 
= target
.IsBottomDockable(); break; 
2034         case wxAUI_DOCK_LEFT
:   allowed 
= target
.IsLeftDockable();   break; 
2035         case wxAUI_DOCK_RIGHT
:  allowed 
= target
.IsRightDockable();  break; 
2045 // DoDrop() is an important function.  It basically takes a mouse position, 
2046 // and determines where the pane's new position would be.  If the pane is to be 
2047 // dropped, it performs the drop operation using the specified dock and pane 
2048 // arrays.  By specifying copied dock and pane arrays when calling, a "what-if" 
2049 // scenario can be performed, giving precise coordinates for drop hints. 
2050 // If, however, wxFrameManager:m_docks and wxFrameManager::m_panes are specified 
2051 // as parameters, the changes will be made to the main state arrays 
2053 const int auiInsertRowPixels 
= 10; 
2054 const int auiNewRowPixels 
= 40; 
2055 const int auiLayerInsertPixels 
= 40; 
2056 const int auiLayerInsertOffset 
= 5; 
2058 bool wxFrameManager::DoDrop(wxDockInfoArray
& docks
, 
2059                             wxPaneInfoArray
& panes
, 
2062                             const wxPoint
& offset
) 
2064     wxSize cli_size 
= m_frame
->GetClientSize(); 
2066     wxPaneInfo drop 
= target
; 
2069     // The result should always be shown 
2073     // Check to see if the pane has been dragged outside of the window 
2074     // (or near to the outside of the window), if so, dock it along the edge 
2077     int layer_insert_offset 
= auiLayerInsertOffset
; 
2078     if (target
.IsToolbar()) 
2079         layer_insert_offset 
= 0; 
2081     if (pt
.x 
< layer_insert_offset 
&& 
2082         pt
.x 
> layer_insert_offset
-auiLayerInsertPixels
) 
2084         int new_layer 
= wxMax(wxMax(GetMaxLayer(docks
, wxAUI_DOCK_LEFT
), 
2085                                     GetMaxLayer(docks
, wxAUI_DOCK_BOTTOM
)), 
2086                                     GetMaxLayer(docks
, wxAUI_DOCK_TOP
)) + 1; 
2090              Position(pt
.y 
- GetDockPixelOffset(drop
) - offset
.y
); 
2091         return ProcessDockResult(target
, drop
); 
2093     else if (pt
.y 
< layer_insert_offset 
&& 
2094              pt
.y 
> layer_insert_offset
-auiLayerInsertPixels
) 
2096         int new_layer 
= wxMax(wxMax(GetMaxLayer(docks
, wxAUI_DOCK_TOP
), 
2097                                     GetMaxLayer(docks
, wxAUI_DOCK_LEFT
)), 
2098                                     GetMaxLayer(docks
, wxAUI_DOCK_RIGHT
)) + 1; 
2102              Position(pt
.x 
- GetDockPixelOffset(drop
) - offset
.x
); 
2103         return ProcessDockResult(target
, drop
); 
2105     else if (pt
.x 
>= cli_size
.x 
- layer_insert_offset 
&& 
2106              pt
.x 
< cli_size
.x 
- layer_insert_offset 
+ auiLayerInsertPixels
) 
2108         int new_layer 
= wxMax(wxMax(GetMaxLayer(docks
, wxAUI_DOCK_RIGHT
), 
2109                                     GetMaxLayer(docks
, wxAUI_DOCK_TOP
)), 
2110                                     GetMaxLayer(docks
, wxAUI_DOCK_BOTTOM
)) + 1; 
2111         drop
.Dock().Right(). 
2114              Position(pt
.y 
- GetDockPixelOffset(drop
) - offset
.y
); 
2115         return ProcessDockResult(target
, drop
); 
2117     else if (pt
.y 
>= cli_size
.y 
- layer_insert_offset 
&& 
2118              pt
.y 
< cli_size
.y 
- layer_insert_offset 
+ auiLayerInsertPixels
) 
2120         int new_layer 
= wxMax(wxMax(GetMaxLayer(docks
, wxAUI_DOCK_BOTTOM
), 
2121                                     GetMaxLayer(docks
, wxAUI_DOCK_LEFT
)), 
2122                                     GetMaxLayer(docks
, wxAUI_DOCK_RIGHT
)) + 1; 
2123         drop
.Dock().Bottom(). 
2126              Position(pt
.x 
- GetDockPixelOffset(drop
) - offset
.x
); 
2127         return ProcessDockResult(target
, drop
); 
2131     wxDockUIPart
* part 
= HitTest(pt
.x
, pt
.y
); 
2134     if (drop
.IsToolbar()) 
2136         if (!part 
|| !part
->dock
) 
2140         // calculate the offset from where the dock begins 
2141         // to the point where the user dropped the pane 
2142         int dock_drop_offset 
= 0; 
2143         if (part
->dock
->IsHorizontal()) 
2144             dock_drop_offset 
= pt
.x 
- part
->dock
->rect
.x 
- offset
.x
; 
2146             dock_drop_offset 
= pt
.y 
- part
->dock
->rect
.y 
- offset
.y
; 
2149         // toolbars may only be moved in and to fixed-pane docks, 
2150         // otherwise we will try to float the pane.  Also, the pane 
2151         // should float if being dragged over center pane windows 
2152         if (!part
->dock
->fixed 
|| part
->dock
->dock_direction 
== wxAUI_DOCK_CENTER
) 
2154             if ((m_flags 
& wxAUI_MGR_ALLOW_FLOATING
) && 
2155                    (drop
.IsFloatable() || 
2156                     (part
->dock
->dock_direction 
!= wxAUI_DOCK_CENTER 
&& 
2157                      part
->dock
->dock_direction 
!= wxAUI_DOCK_NONE
))) 
2162             return ProcessDockResult(target
, drop
); 
2166              Direction(part
->dock
->dock_direction
). 
2167              Layer(part
->dock
->dock_layer
). 
2168              Row(part
->dock
->dock_row
). 
2169              Position(dock_drop_offset
); 
2172             ((pt
.y 
< part
->dock
->rect
.y 
+ 2) && part
->dock
->IsHorizontal()) || 
2173             ((pt
.x 
< part
->dock
->rect
.x 
+ 2) && part
->dock
->IsVertical()) 
2174             ) && part
->dock
->panes
.GetCount() > 1) 
2176             int row 
= drop
.dock_row
; 
2177             DoInsertDockRow(panes
, part
->dock
->dock_direction
, 
2178                             part
->dock
->dock_layer
, 
2179                             part
->dock
->dock_row
); 
2180             drop
.dock_row 
= row
; 
2184             ((pt
.y 
> part
->dock
->rect
.y 
+ part
->dock
->rect
.height 
- 2 ) && part
->dock
->IsHorizontal()) || 
2185             ((pt
.x 
> part
->dock
->rect
.x 
+ part
->dock
->rect
.width 
- 2 ) && part
->dock
->IsVertical()) 
2186             ) && part
->dock
->panes
.GetCount() > 1) 
2188             DoInsertDockRow(panes
, part
->dock
->dock_direction
, 
2189                             part
->dock
->dock_layer
, 
2190                             part
->dock
->dock_row
+1); 
2191             drop
.dock_row 
= part
->dock
->dock_row
+1; 
2194         return ProcessDockResult(target
, drop
); 
2203     if (part
->type 
== wxDockUIPart::typePaneBorder 
|| 
2204         part
->type 
== wxDockUIPart::typeCaption 
|| 
2205         part
->type 
== wxDockUIPart::typeGripper 
|| 
2206         part
->type 
== wxDockUIPart::typePaneButton 
|| 
2207         part
->type 
== wxDockUIPart::typePane 
|| 
2208         part
->type 
== wxDockUIPart::typePaneSizer 
|| 
2209         part
->type 
== wxDockUIPart::typeDockSizer 
|| 
2210         part
->type 
== wxDockUIPart::typeBackground
) 
2212         if (part
->type 
== wxDockUIPart::typeDockSizer
) 
2214             if (part
->dock
->panes
.GetCount() != 1) 
2216             part 
= GetPanePart(part
->dock
->panes
.Item(0)->window
); 
2223         // If a normal frame is being dragged over a toolbar, insert it 
2224         // along the edge under the toolbar, but over all other panes. 
2225         // (this could be done much better, but somehow factoring this 
2226         // calculation with the one at the beginning of this function) 
2227         if (part
->dock 
&& part
->dock
->toolbar
) 
2231             switch (part
->dock
->dock_direction
) 
2233                 case wxAUI_DOCK_LEFT
: 
2234                     layer 
= wxMax(wxMax(GetMaxLayer(docks
, wxAUI_DOCK_LEFT
), 
2235                                       GetMaxLayer(docks
, wxAUI_DOCK_BOTTOM
)), 
2236                                       GetMaxLayer(docks
, wxAUI_DOCK_TOP
)); 
2238                 case wxAUI_DOCK_TOP
: 
2239                     layer 
= wxMax(wxMax(GetMaxLayer(docks
, wxAUI_DOCK_TOP
), 
2240                                       GetMaxLayer(docks
, wxAUI_DOCK_LEFT
)), 
2241                                       GetMaxLayer(docks
, wxAUI_DOCK_RIGHT
)); 
2243                 case wxAUI_DOCK_RIGHT
: 
2244                     layer 
= wxMax(wxMax(GetMaxLayer(docks
, wxAUI_DOCK_RIGHT
), 
2245                                       GetMaxLayer(docks
, wxAUI_DOCK_TOP
)), 
2246                                       GetMaxLayer(docks
, wxAUI_DOCK_BOTTOM
)); 
2248                 case wxAUI_DOCK_BOTTOM
: 
2249                     layer 
= wxMax(wxMax(GetMaxLayer(docks
, wxAUI_DOCK_BOTTOM
), 
2250                                       GetMaxLayer(docks
, wxAUI_DOCK_LEFT
)), 
2251                                       GetMaxLayer(docks
, wxAUI_DOCK_RIGHT
)); 
2255             DoInsertDockRow(panes
, part
->dock
->dock_direction
, 
2258                  Direction(part
->dock
->dock_direction
). 
2259                  Layer(layer
).Row(0).Position(0); 
2260             return ProcessDockResult(target
, drop
); 
2267         part 
= GetPanePart(part
->pane
->window
); 
2271         bool insert_dock_row 
= false; 
2272         int insert_row 
= part
->pane
->dock_row
; 
2273         int insert_dir 
= part
->pane
->dock_direction
; 
2274         int insert_layer 
= part
->pane
->dock_layer
; 
2276         switch (part
->pane
->dock_direction
) 
2278             case wxAUI_DOCK_TOP
: 
2279                 if (pt
.y 
>= part
->rect
.y 
&& 
2280                     pt
.y 
< part
->rect
.y
+auiInsertRowPixels
) 
2281                         insert_dock_row 
= true; 
2283             case wxAUI_DOCK_BOTTOM
: 
2284                 if (pt
.y 
> part
->rect
.y
+part
->rect
.height
-auiInsertRowPixels 
&& 
2285                     pt
.y 
<= part
->rect
.y 
+ part
->rect
.height
) 
2286                         insert_dock_row 
= true; 
2288             case wxAUI_DOCK_LEFT
: 
2289                 if (pt
.x 
>= part
->rect
.x 
&& 
2290                     pt
.x 
< part
->rect
.x
+auiInsertRowPixels
) 
2291                         insert_dock_row 
= true; 
2293             case wxAUI_DOCK_RIGHT
: 
2294                 if (pt
.x 
> part
->rect
.x
+part
->rect
.width
-auiInsertRowPixels 
&& 
2295                     pt
.x 
<= part
->rect
.x
+part
->rect
.width
) 
2296                         insert_dock_row 
= true; 
2298             case wxAUI_DOCK_CENTER
: 
2300                 // "new row pixels" will be set to the default, but 
2301                 // must never exceed 20% of the window size 
2302                 int new_row_pixels_x 
= auiNewRowPixels
; 
2303                 int new_row_pixels_y 
= auiNewRowPixels
; 
2305                 if (new_row_pixels_x 
> (part
->rect
.width
*20)/100) 
2306                     new_row_pixels_x 
= (part
->rect
.width
*20)/100; 
2308                 if (new_row_pixels_y 
> (part
->rect
.height
*20)/100) 
2309                     new_row_pixels_y 
= (part
->rect
.height
*20)/100; 
2312                 // determine if the mouse pointer is in a location that 
2313                 // will cause a new row to be inserted.  The hot spot positions 
2314                 // are along the borders of the center pane 
2317                 insert_dock_row 
= true; 
2318                 if (pt
.x 
>= part
->rect
.x 
&& 
2319                     pt
.x 
< part
->rect
.x
+new_row_pixels_x
) 
2320                         insert_dir 
= wxAUI_DOCK_LEFT
; 
2322                 if (pt
.y 
>= part
->rect
.y 
&& 
2323                     pt
.y 
< part
->rect
.y
+new_row_pixels_y
) 
2324                         insert_dir 
= wxAUI_DOCK_TOP
; 
2326                 if (pt
.x 
>= part
->rect
.x 
+ part
->rect
.width
-new_row_pixels_x 
&& 
2327                     pt
.x 
< part
->rect
.x 
+ part
->rect
.width
) 
2328                         insert_dir 
= wxAUI_DOCK_RIGHT
; 
2330                 if (pt
.y 
>= part
->rect
.y
+ part
->rect
.height
-new_row_pixels_y 
&& 
2331                     pt
.y 
< part
->rect
.y 
+ part
->rect
.height
) 
2332                         insert_dir 
= wxAUI_DOCK_BOTTOM
; 
2336                 insert_row 
= GetMaxRow(panes
, insert_dir
, insert_layer
) + 1; 
2340         if (insert_dock_row
) 
2342             DoInsertDockRow(panes
, insert_dir
, insert_layer
, insert_row
); 
2343             drop
.Dock().Direction(insert_dir
). 
2344                         Layer(insert_layer
). 
2347             return ProcessDockResult(target
, drop
); 
2350         // determine the mouse offset and the pane size, both in the 
2351         // direction of the dock itself, and perpendicular to the dock 
2355         if (part
->orientation 
== wxVERTICAL
) 
2357             offset 
= pt
.y 
- part
->rect
.y
; 
2358             size 
= part
->rect
.GetHeight(); 
2362             offset 
= pt
.x 
- part
->rect
.x
; 
2363             size 
= part
->rect
.GetWidth(); 
2366         int drop_position 
= part
->pane
->dock_pos
; 
2368         // if we are in the top/left part of the pane, 
2369         // insert the pane before the pane being hovered over 
2370         if (offset 
<= size
/2) 
2372             drop_position 
= part
->pane
->dock_pos
; 
2374                          part
->pane
->dock_direction
, 
2375                          part
->pane
->dock_layer
, 
2376                          part
->pane
->dock_row
, 
2377                          part
->pane
->dock_pos
); 
2380         // if we are in the bottom/right part of the pane, 
2381         // insert the pane before the pane being hovered over 
2382         if (offset 
> size
/2) 
2384             drop_position 
= part
->pane
->dock_pos
+1; 
2386                          part
->pane
->dock_direction
, 
2387                          part
->pane
->dock_layer
, 
2388                          part
->pane
->dock_row
, 
2389                          part
->pane
->dock_pos
+1); 
2393              Direction(part
->dock
->dock_direction
). 
2394              Layer(part
->dock
->dock_layer
). 
2395              Row(part
->dock
->dock_row
). 
2396              Position(drop_position
); 
2397         return ProcessDockResult(target
, drop
); 
2404 void wxFrameManager::OnHintFadeTimer(wxTimerEvent
& WXUNUSED(event
)) 
2407     if (!m_hint_wnd 
|| m_hint_fadeamt 
>= 50) 
2409         m_hint_fadetimer
.Stop(); 
2413     m_hint_fadeamt 
+= 5; 
2414     MakeWindowTransparent(m_hint_wnd
, m_hint_fadeamt
); 
2418 void wxFrameManager::ShowHint(const wxRect
& rect
) 
2422     // First, determine if the operating system can handle transparency. 
2423     // Transparency is available on Win2000 and above 
2425     static int os_type 
= -1; 
2426     static int ver_major 
= -1; 
2429         os_type 
= ::wxGetOsVersion(&ver_major
); 
2431     // If the transparent flag is set, and the OS supports it, 
2432     // go ahead and use a transparent hint 
2434     if ((m_flags 
& wxAUI_MGR_TRANSPARENT_HINT
) != 0 && 
2435         os_type 
== wxWINDOWS_NT 
&& ver_major 
>= 5) 
2437         if (m_last_hint 
== rect
) 
2441         int initial_fade 
= 50; 
2442         if (m_flags 
& wxAUI_MGR_TRANSPARENT_HINT_FADE
) 
2445         if (m_hint_wnd 
== NULL
) 
2447             wxPoint pt 
= rect
.GetPosition(); 
2448             wxSize size 
= rect
.GetSize(); 
2449             m_hint_wnd 
= new wxFrame(m_frame
, -1, wxEmptyString
, pt
, size
, 
2450                                      wxFRAME_TOOL_WINDOW 
| 
2451                                      wxFRAME_FLOAT_ON_PARENT 
| 
2452                                      wxFRAME_NO_TASKBAR 
| 
2455             MakeWindowTransparent(m_hint_wnd
, initial_fade
); 
2456             m_hint_wnd
->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVECAPTION
)); 
2459             // if we are dragging a floating pane, set the focus 
2460             // back to that floating pane (otherwise it becomes unfocused) 
2461             if (m_action 
== actionDragFloatingPane 
&& m_action_window
) 
2462                 m_action_window
->SetFocus(); 
2467             MakeWindowTransparent(m_hint_wnd
, initial_fade
); 
2468             m_hint_wnd
->SetSize(rect
); 
2471         if (m_flags 
& wxAUI_MGR_TRANSPARENT_HINT_FADE
) 
2473             // start fade in timer 
2475             m_hint_fadetimer
.SetOwner(this, 101); 
2476             m_hint_fadetimer
.Start(5); 
2483     if (m_last_hint 
!= rect
) 
2485         // remove the last hint rectangle 
2491     wxScreenDC screendc
; 
2492     wxRegion 
clip(1, 1, 10000, 10000); 
2494     // clip all floating windows, so we don't draw over them 
2496     for (i 
= 0, pane_count 
= m_panes
.GetCount(); i 
< pane_count
; ++i
) 
2498         wxPaneInfo
& pane 
= m_panes
.Item(i
); 
2500         if (pane
.IsFloating() && 
2501             pane
.frame
->IsShown()) 
2503             wxRect rect 
= pane
.frame
->GetRect(); 
2505             // wxGTK returns the client size, not the whole frame size 
2511             clip
.Subtract(rect
); 
2515     screendc
.SetClippingRegion(clip
); 
2517     wxBitmap stipple 
= wxPaneCreateStippleBitmap(); 
2518     wxBrush 
brush(stipple
); 
2519     screendc
.SetBrush(brush
); 
2520     screendc
.SetPen(*wxTRANSPARENT_PEN
); 
2522     screendc
.DrawRectangle(rect
.x
, rect
.y
, 5, rect
.height
); 
2523     screendc
.DrawRectangle(rect
.x
+5, rect
.y
, rect
.width
-10, 5); 
2524     screendc
.DrawRectangle(rect
.x
+rect
.width
-5, rect
.y
, 5, rect
.height
); 
2525     screendc
.DrawRectangle(rect
.x
+5, rect
.y
+rect
.height
-5, rect
.width
-10, 5); 
2528 void wxFrameManager::HideHint() 
2530     // hides a transparent window hint (currently wxMSW only) 
2534         MakeWindowTransparent(m_hint_wnd
, 0); 
2535         m_hint_fadetimer
.Stop(); 
2536         m_last_hint 
= wxRect(); 
2541     // hides a painted hint by redrawing the frame window 
2542     if (!m_last_hint
.IsEmpty()) 
2546         m_last_hint 
= wxRect(); 
2552 // DrawHintRect() draws a drop hint rectangle. First calls DoDrop() to 
2553 // determine the exact position the pane would be at were if dropped.  If 
2554 // the pame would indeed become docked at the specified drop point, 
2555 // DrawHintRect() then calls ShowHint() to indicate this drop rectangle. 
2556 // "pane_window" is the window pointer of the pane being dragged, pt is 
2557 // the mouse position, in client coordinates 
2558 void wxFrameManager::DrawHintRect(wxWindow
* pane_window
, 
2560                                   const wxPoint
& offset
) 
2564     // we need to paint a hint rectangle; to find out the exact hint rectangle, 
2565     // we will create a new temporary layout and then measure the resulting 
2566     // rectangle; we will create a copy of the docking structures (m_dock) 
2567     // so that we don't modify the real thing on screen 
2569     int i
, pane_count
, part_count
; 
2570     wxDockInfoArray docks
; 
2571     wxPaneInfoArray panes
; 
2572     wxDockUIPartArray uiparts
; 
2573     wxPaneInfo hint 
= GetPane(pane_window
); 
2574     hint
.name 
= wxT("__HINT__"); 
2579     CopyDocksAndPanes(docks
, panes
, m_docks
, m_panes
); 
2581     // remove any pane already there which bears the same window; 
2582     // this happens when you are moving a pane around in a dock 
2583     for (i 
= 0, pane_count 
= panes
.GetCount(); i 
< pane_count
; ++i
) 
2585         if (panes
.Item(i
).window 
== pane_window
) 
2587             RemovePaneFromDocks(docks
, panes
.Item(i
)); 
2593     // find out where the new pane would be 
2594     if (!DoDrop(docks
, panes
, hint
, pt
, offset
)) 
2602     wxSizer
* sizer 
= LayoutAll(panes
, docks
, uiparts
, true); 
2603     wxSize client_size 
= m_frame
->GetClientSize(); 
2604     sizer
->SetDimension(0, 0, client_size
.x
, client_size
.y
); 
2607     for (i 
= 0, part_count 
= uiparts
.GetCount(); 
2608          i 
< part_count
; ++i
) 
2610         wxDockUIPart
& part 
= uiparts
.Item(i
); 
2612         if (part
.type 
== wxDockUIPart::typePaneBorder 
&& 
2613             part
.pane 
&& part
.pane
->name 
== wxT("__HINT__")) 
2615             rect 
= wxRect(part
.sizer_item
->GetPosition(), 
2616                           part
.sizer_item
->GetSize()); 
2629     // actually show the hint rectangle on the screen 
2630     m_frame
->ClientToScreen(&rect
.x
, &rect
.y
); 
2634 void wxFrameManager::OnFloatingPaneMoveStart(wxWindow
* wnd
) 
2636     // try to find the pane 
2637     wxPaneInfo
& pane 
= GetPane(wnd
); 
2638     wxASSERT_MSG(pane
.IsOk(), wxT("Pane window not found")); 
2641     if (m_flags 
& wxAUI_MGR_TRANSPARENT_DRAG
) 
2642         MakeWindowTransparent(pane
.frame
, 150); 
2646 void wxFrameManager::OnFloatingPaneMoving(wxWindow
* wnd
) 
2648     // try to find the pane 
2649     wxPaneInfo
& pane 
= GetPane(wnd
); 
2650     wxASSERT_MSG(pane
.IsOk(), wxT("Pane window not found")); 
2652     wxPoint pt 
= ::wxGetMousePosition(); 
2653     wxPoint client_pt 
= m_frame
->ScreenToClient(pt
); 
2655     // calculate the offset from the upper left-hand corner 
2656     // of the frame to the mouse pointer 
2657     wxPoint frame_pos 
= pane
.frame
->GetPosition(); 
2658     wxPoint 
action_offset(pt
.x
-frame_pos
.x
, pt
.y
-frame_pos
.y
); 
2660     // no hint for toolbar floating windows 
2661     if (pane
.IsToolbar() && m_action 
== actionDragFloatingPane
) 
2663         if (m_action 
== actionDragFloatingPane
) 
2665             wxDockInfoArray docks
; 
2666             wxPaneInfoArray panes
; 
2667             wxDockUIPartArray uiparts
; 
2668             wxPaneInfo hint 
= pane
; 
2670             CopyDocksAndPanes(docks
, panes
, m_docks
, m_panes
); 
2672             // find out where the new pane would be 
2673             if (!DoDrop(docks
, panes
, hint
, client_pt
)) 
2675             if (hint
.IsFloating()) 
2679             m_action 
= actionDragToolbarPane
; 
2680             m_action_window 
= pane
.window
; 
2689     // if a key modifier is pressed while dragging the frame, 
2690     // don't dock the window 
2691     if (wxGetKeyState(WXK_CONTROL
) || wxGetKeyState(WXK_ALT
)) 
2698     DrawHintRect(wnd
, client_pt
, action_offset
); 
2701     // this cleans up some screen artifacts that are caused on GTK because 
2702     // we aren't getting the exact size of the window (see comment 
2712 void wxFrameManager::OnFloatingPaneMoved(wxWindow
* wnd
) 
2714     // try to find the pane 
2715     wxPaneInfo
& pane 
= GetPane(wnd
); 
2716     wxASSERT_MSG(pane
.IsOk(), wxT("Pane window not found")); 
2718     wxPoint pt 
= ::wxGetMousePosition(); 
2719     wxPoint client_pt 
= m_frame
->ScreenToClient(pt
); 
2721     // calculate the offset from the upper left-hand corner 
2722     // of the frame to the mouse pointer 
2723     wxPoint frame_pos 
= pane
.frame
->GetPosition(); 
2724     wxPoint 
action_offset(pt
.x
-frame_pos
.x
, pt
.y
-frame_pos
.y
); 
2727     // if a key modifier is pressed while dragging the frame, 
2728     // don't dock the window 
2729     if (wxGetKeyState(WXK_CONTROL
) || wxGetKeyState(WXK_ALT
)) 
2736     // do the drop calculation 
2737     DoDrop(m_docks
, m_panes
, pane
, client_pt
, action_offset
); 
2739     // if the pane is still floating, update it's floating 
2740     // position (that we store) 
2741     if (pane
.IsFloating()) 
2743         pane
.floating_pos 
= pane
.frame
->GetPosition(); 
2746         if (m_flags 
& wxAUI_MGR_TRANSPARENT_DRAG
) 
2747             MakeWindowTransparent(pane
.frame
, 255); 
2756 void wxFrameManager::OnFloatingPaneResized(wxWindow
* wnd
, const wxSize
& size
) 
2758     // try to find the pane 
2759     wxPaneInfo
& pane 
= GetPane(wnd
); 
2760     wxASSERT_MSG(pane
.IsOk(), wxT("Pane window not found")); 
2762     pane
.floating_size 
= size
; 
2765 void wxFrameManager::OnFloatingPaneClosed(wxWindow
* wnd
) 
2767     // try to find the pane 
2768     wxPaneInfo
& pane 
= GetPane(wnd
); 
2769     wxASSERT_MSG(pane
.IsOk(), wxT("Pane window not found")); 
2771     // reparent the pane window back to us and 
2772     // prepare the frame window for destruction 
2773     pane
.window
->Show(false); 
2774     pane
.window
->Reparent(m_frame
); 
2779 void wxFrameManager::OnFloatingPaneActivated(wxWindow
* wnd
) 
2781     if (GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE
) 
2783         // try to find the pane 
2784         wxPaneInfo
& pane 
= GetPane(wnd
); 
2785         wxASSERT_MSG(pane
.IsOk(), wxT("Pane window not found")); 
2787         SetActivePane(m_panes
, wnd
); 
2792 // Render() draws all of the pane captions, sashes, 
2793 // backgrounds, captions, grippers, pane borders and buttons. 
2794 // It renders the entire user interface. 
2796 void wxFrameManager::Render(wxDC
* dc
) 
2802     for (i 
= 0, part_count 
= m_uiparts
.GetCount(); 
2803          i 
< part_count
; ++i
) 
2805         wxDockUIPart
& part 
= m_uiparts
.Item(i
); 
2807         // don't draw hidden pane items 
2808         if (part
.sizer_item 
&& !part
.sizer_item
->IsShown()) 
2813             case wxDockUIPart::typeDockSizer
: 
2814             case wxDockUIPart::typePaneSizer
: 
2815                 m_art
->DrawSash(*dc
, part
.orientation
, part
.rect
); 
2817             case wxDockUIPart::typeBackground
: 
2818                 m_art
->DrawBackground(*dc
, part
.orientation
, part
.rect
); 
2820             case wxDockUIPart::typeCaption
: 
2821                 m_art
->DrawCaption(*dc
, part
.pane
->caption
, part
.rect
, *part
.pane
); 
2823             case wxDockUIPart::typeGripper
: 
2824                 m_art
->DrawGripper(*dc
, part
.rect
, *part
.pane
); 
2826             case wxDockUIPart::typePaneBorder
: 
2827                 m_art
->DrawBorder(*dc
, part
.rect
, *part
.pane
); 
2829             case wxDockUIPart::typePaneButton
: 
2830                 m_art
->DrawPaneButton(*dc
, part
.button
->button_id
, 
2831                         wxAUI_BUTTON_STATE_NORMAL
, part
.rect
, *part
.pane
); 
2837 void wxFrameManager::Repaint(wxDC
* dc
) 
2842         m_frame
->Refresh() ; 
2848     m_frame
->GetClientSize(&w
, &h
); 
2850     // figure out which dc to use; if one 
2851     // has been specified, use it, otherwise 
2853     wxClientDC
* client_dc 
= NULL
; 
2856         client_dc 
= new wxClientDC(m_frame
); 
2860     // if the frame has a toolbar, the client area 
2861     // origin will not be (0,0). 
2862     wxPoint pt 
= m_frame
->GetClientAreaOrigin(); 
2863     if (pt
.x 
!= 0 || pt
.y 
!= 0) 
2864         dc
->SetDeviceOrigin(pt
.x
, pt
.y
); 
2866     // render all the items 
2869     // if we created a client_dc, delete it 
2874 void wxFrameManager::OnPaint(wxPaintEvent
& WXUNUSED(event
)) 
2876     wxPaintDC 
dc(m_frame
); 
2880 void wxFrameManager::OnEraseBackground(wxEraseEvent
& event
) 
2889 void wxFrameManager::OnSize(wxSizeEvent
& WXUNUSED(event
)) 
2899 void wxFrameManager::OnSetCursor(wxSetCursorEvent
& event
) 
2902     wxDockUIPart
* part 
= HitTest(event
.GetX(), event
.GetY()); 
2903     wxCursor cursor 
= wxNullCursor
; 
2907         if (part
->type 
== wxDockUIPart::typeDockSizer 
|| 
2908             part
->type 
== wxDockUIPart::typePaneSizer
) 
2910             // a dock may not be resized if it has a single 
2911             // pane which is not resizable 
2912             if (part
->type 
== wxDockUIPart::typeDockSizer 
&& part
->dock 
&& 
2913                 part
->dock
->panes
.GetCount() == 1 && 
2914                 part
->dock
->panes
.Item(0)->IsFixed()) 
2917             // panes that may not be resized do not get a sizing cursor 
2918             if (part
->pane 
&& part
->pane
->IsFixed()) 
2921             if (part
->orientation 
== wxVERTICAL
) 
2922                 cursor 
= wxCursor(wxCURSOR_SIZEWE
); 
2924                 cursor 
= wxCursor(wxCURSOR_SIZENS
); 
2926          else if (part
->type 
== wxDockUIPart::typeGripper
) 
2928             cursor 
= wxCursor(wxCURSOR_SIZING
); 
2932     event
.SetCursor(cursor
); 
2937 void wxFrameManager::UpdateButtonOnScreen(wxDockUIPart
* button_ui_part
, 
2938                                           const wxMouseEvent
& event
) 
2940     wxDockUIPart
* hit_test 
= HitTest(event
.GetX(), event
.GetY()); 
2942     int state 
= wxAUI_BUTTON_STATE_NORMAL
; 
2944     if (hit_test 
== button_ui_part
) 
2946         if (event
.LeftDown()) 
2947             state 
= wxAUI_BUTTON_STATE_PRESSED
; 
2949             state 
= wxAUI_BUTTON_STATE_HOVER
; 
2953         if (event
.LeftDown()) 
2954             state 
= wxAUI_BUTTON_STATE_HOVER
; 
2957     // now repaint the button with hover state 
2958     wxClientDC 
cdc(m_frame
); 
2960     // if the frame has a toolbar, the client area 
2961     // origin will not be (0,0). 
2962     wxPoint pt 
= m_frame
->GetClientAreaOrigin(); 
2963     if (pt
.x 
!= 0 || pt
.y 
!= 0) 
2964         cdc
.SetDeviceOrigin(pt
.x
, pt
.y
); 
2966     m_art
->DrawPaneButton(cdc
, 
2967               button_ui_part
->button
->button_id
, 
2969               button_ui_part
->rect
, 
2973 void wxFrameManager::OnLeftDown(wxMouseEvent
& event
) 
2975     wxDockUIPart
* part 
= HitTest(event
.GetX(), event
.GetY()); 
2978         if (part
->dock 
&& part
->dock
->dock_direction 
== wxAUI_DOCK_CENTER
) 
2981         if (part
->type 
== wxDockUIPart::typeDockSizer 
|| 
2982             part
->type 
== wxDockUIPart::typePaneSizer
) 
2984             // a dock may not be resized if it has a single 
2985             // pane which is not resizable 
2986             if (part
->type 
== wxDockUIPart::typeDockSizer 
&& part
->dock 
&& 
2987                 part
->dock
->panes
.GetCount() == 1 && 
2988                 part
->dock
->panes
.Item(0)->IsFixed()) 
2991             // panes that may not be resized should be ignored here 
2992             if (part
->pane 
&& part
->pane
->IsFixed()) 
2995             m_action 
= actionResize
; 
2996             m_action_part 
= part
; 
2997             m_action_hintrect 
= wxRect(); 
2998             m_action_start 
= wxPoint(event
.m_x
, event
.m_y
); 
2999             m_action_offset 
= wxPoint(event
.m_x 
- part
->rect
.x
, 
3000                                       event
.m_y 
- part
->rect
.y
); 
3001             m_frame
->CaptureMouse(); 
3003          else if (part
->type 
== wxDockUIPart::typePaneButton
) 
3005             m_action 
= actionClickButton
; 
3006             m_action_part 
= part
; 
3007             m_action_start 
= wxPoint(event
.m_x
, event
.m_y
); 
3008             m_frame
->CaptureMouse(); 
3010             UpdateButtonOnScreen(part
, event
); 
3012          else if (part
->type 
== wxDockUIPart::typeCaption 
|| 
3013                   part
->type 
== wxDockUIPart::typeGripper
) 
3015             if (GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE
) 
3017                 // set the caption as active 
3018                 SetActivePane(m_panes
, part
->pane
->window
); 
3022             m_action 
= actionClickCaption
; 
3023             m_action_part 
= part
; 
3024             m_action_start 
= wxPoint(event
.m_x
, event
.m_y
); 
3025             m_action_offset 
= wxPoint(event
.m_x 
- part
->rect
.x
, 
3026                                       event
.m_y 
- part
->rect
.y
); 
3027             m_frame
->CaptureMouse(); 
3047 void wxFrameManager::OnLeftUp(wxMouseEvent
& event
) 
3049     if (m_action 
== actionResize
) 
3051         m_frame
->ReleaseMouse(); 
3053         // get rid of the hint rectangle 
3055         DrawResizeHint(dc
, m_action_hintrect
); 
3057         // resize the dock or the pane 
3058         if (m_action_part 
&& m_action_part
->type
==wxDockUIPart::typeDockSizer
) 
3060             wxRect
& rect 
= m_action_part
->dock
->rect
; 
3062             wxPoint 
new_pos(event
.m_x 
- m_action_offset
.x
, 
3063                             event
.m_y 
- m_action_offset
.y
); 
3065             switch (m_action_part
->dock
->dock_direction
) 
3067                 case wxAUI_DOCK_LEFT
: 
3068                     m_action_part
->dock
->size 
= new_pos
.x 
- rect
.x
; 
3070                 case wxAUI_DOCK_TOP
: 
3071                     m_action_part
->dock
->size 
= new_pos
.y 
- rect
.y
; 
3073                 case wxAUI_DOCK_RIGHT
: 
3074                     m_action_part
->dock
->size 
= rect
.x 
+ rect
.width 
- 
3075                                   new_pos
.x 
- m_action_part
->rect
.GetWidth(); 
3077                 case wxAUI_DOCK_BOTTOM
: 
3078                     m_action_part
->dock
->size 
= rect
.y 
+ rect
.height 
- 
3079                                   new_pos
.y 
- m_action_part
->rect
.GetHeight(); 
3086          else if (m_action_part 
&& 
3087                   m_action_part
->type 
== wxDockUIPart::typePaneSizer
) 
3089             wxDockInfo
& dock 
= *m_action_part
->dock
; 
3090             wxPaneInfo
& pane 
= *m_action_part
->pane
; 
3092             int total_proportion 
= 0; 
3093             int dock_pixels 
= 0; 
3094             int new_pixsize 
= 0; 
3096             int caption_size 
= m_art
->GetMetric(wxAUI_ART_CAPTION_SIZE
); 
3097             int pane_border_size 
= m_art
->GetMetric(wxAUI_ART_PANE_BORDER_SIZE
); 
3098             int sash_size 
= m_art
->GetMetric(wxAUI_ART_SASH_SIZE
); 
3100             wxPoint 
new_pos(event
.m_x 
- m_action_offset
.x
, 
3101                             event
.m_y 
- m_action_offset
.y
); 
3103             // determine the pane rectangle by getting the pane part 
3104             wxDockUIPart
* pane_part 
= GetPanePart(pane
.window
); 
3105             wxASSERT_MSG(pane_part
, 
3106                        wxT("Pane border part not found -- shouldn't happen")); 
3108             // determine the new pixel size that the user wants; 
3109             // this will help us recalculate the pane's proportion 
3110             if (dock
.IsHorizontal()) 
3111                 new_pixsize 
= new_pos
.x 
- pane_part
->rect
.x
; 
3113                 new_pixsize 
= new_pos
.y 
- pane_part
->rect
.y
; 
3115             // determine the size of the dock, based on orientation 
3116             if (dock
.IsHorizontal()) 
3117                 dock_pixels 
= dock
.rect
.GetWidth(); 
3119                 dock_pixels 
= dock
.rect
.GetHeight(); 
3121             // determine the total proportion of all resizable panes, 
3122             // and the total size of the dock minus the size of all 
3124             int i
, dock_pane_count 
= dock
.panes
.GetCount(); 
3125             int pane_position 
= -1; 
3126             for (i 
= 0; i 
< dock_pane_count
; ++i
) 
3128                 wxPaneInfo
& p 
= *dock
.panes
.Item(i
); 
3129                 if (p
.window 
== pane
.window
) 
3132                 // while we're at it, subtract the pane sash 
3133                 // width from the dock width, because this would 
3134                 // skew our proportion calculations 
3136                     dock_pixels 
-= sash_size
; 
3138                 // also, the whole size (including decorations) of 
3139                 // all fixed panes must also be subtracted, because they 
3140                 // are not part of the proportion calculation 
3143                     if (dock
.IsHorizontal()) 
3144                         dock_pixels 
-= p
.best_size
.x
; 
3146                         dock_pixels 
-= p
.best_size
.y
; 
3150                     total_proportion 
+= p
.dock_proportion
; 
3154             // find a pane in our dock to 'steal' space from or to 'give' 
3155             // space to -- this is essentially what is done when a pane is 
3156             // resized; the pane should usually be the first non-fixed pane 
3157             // to the right of the action pane 
3158             int borrow_pane 
= -1; 
3159             for (i 
= pane_position
+1; i 
< dock_pane_count
; ++i
) 
3161                 wxPaneInfo
& p 
= *dock
.panes
.Item(i
); 
3170             // demand that the pane being resized is found in this dock 
3171             // (this assert really never should be raised) 
3172             wxASSERT_MSG(pane_position 
!= -1, wxT("Pane not found in dock")); 
3174             // prevent division by zero 
3175             if (dock_pixels 
== 0 || total_proportion 
== 0 || borrow_pane 
== -1) 
3177                 m_action 
= actionNone
; 
3181             // calculate the new proportion of the pane 
3182             int new_proportion 
= (new_pixsize
*total_proportion
)/dock_pixels
; 
3184             // default minimum size 
3187             // check against the pane's minimum size, if specified. please note 
3188             // that this is not enough to ensure that the minimum size will 
3189             // not be violated, because the whole frame might later be shrunk, 
3190             // causing the size of the pane to violate it's minimum size 
3191             if (pane
.min_size
.IsFullySpecified()) 
3195                 if (pane
.HasBorder()) 
3196                     min_size 
+= (pane_border_size
*2); 
3198                 // calculate minimum size with decorations (border,caption) 
3199                 if (pane_part
->orientation 
== wxVERTICAL
) 
3201                     min_size 
+= pane
.min_size
.y
; 
3202                     if (pane
.HasCaption()) 
3203                         min_size 
+= caption_size
; 
3207                     min_size 
+= pane
.min_size
.x
; 
3212             // for some reason, an arithmatic error somewhere is causing 
3213             // the proportion calculations to always be off by 1 pixel; 
3214             // for now we will add the 1 pixel on, but we really should 
3215             // determine what's causing this. 
3218             int min_proportion 
= (min_size
*total_proportion
)/dock_pixels
; 
3220             if (new_proportion 
< min_proportion
) 
3221                 new_proportion 
= min_proportion
; 
3225             int prop_diff 
= new_proportion 
- pane
.dock_proportion
; 
3227             // borrow the space from our neighbor pane to the 
3228             // right or bottom (depending on orientation) 
3229             dock
.panes
.Item(borrow_pane
)->dock_proportion 
-= prop_diff
; 
3230             pane
.dock_proportion 
= new_proportion
; 
3237     else if (m_action 
== actionClickButton
) 
3239         m_hover_button 
= NULL
; 
3240         m_frame
->ReleaseMouse(); 
3241         UpdateButtonOnScreen(m_action_part
, event
); 
3243         // make sure we're still over the item that was originally clicked 
3244         if (m_action_part 
== HitTest(event
.GetX(), event
.GetY())) 
3246             // fire button-click event 
3247             wxFrameManagerEvent 
e(wxEVT_AUI_PANEBUTTON
); 
3248             e
.SetPane(m_action_part
->pane
); 
3249             e
.SetButton(m_action_part
->button
->button_id
); 
3253     else if (m_action 
== actionClickCaption
) 
3255         m_frame
->ReleaseMouse(); 
3257     else if (m_action 
== actionDragFloatingPane
) 
3259         m_frame
->ReleaseMouse(); 
3261     else if (m_action 
== actionDragToolbarPane
) 
3263         m_frame
->ReleaseMouse(); 
3265         wxPaneInfo
& pane 
= GetPane(m_action_window
); 
3266         wxASSERT_MSG(pane
.IsOk(), wxT("Pane window not found")); 
3268         // save the new positions 
3269         wxDockInfoPtrArray docks
; 
3270         FindDocks(m_docks
, pane
.dock_direction
, 
3271                   pane
.dock_layer
, pane
.dock_row
, docks
); 
3272         if (docks
.GetCount() == 1) 
3274             wxDockInfo
& dock 
= *docks
.Item(0); 
3276             wxArrayInt pane_positions
, pane_sizes
; 
3277             GetPanePositionsAndSizes(dock
, pane_positions
, pane_sizes
); 
3279             int i
, dock_pane_count 
= dock
.panes
.GetCount(); 
3280             for (i 
= 0; i 
< dock_pane_count
; ++i
) 
3281                 dock
.panes
.Item(i
)->dock_pos 
= pane_positions
[i
]; 
3284         pane
.state 
&= ~wxPaneInfo::actionPane
; 
3292     m_action 
= actionNone
; 
3293     m_last_mouse_move 
= wxPoint(); // see comment in OnMotion() 
3297 void wxFrameManager::OnMotion(wxMouseEvent
& event
) 
3299     // sometimes when Update() is called from inside this method, 
3300     // a spurious mouse move event is generated; this check will make 
3301     // sure that only real mouse moves will get anywhere in this method; 
3302     // this appears to be a bug somewhere, and I don't know where the 
3303     // mouse move event is being generated.  only verified on MSW 
3305     wxPoint mouse_pos 
= event
.GetPosition(); 
3306     if (m_last_mouse_move 
== mouse_pos
) 
3308     m_last_mouse_move 
= mouse_pos
; 
3311     if (m_action 
== actionResize
) 
3313         wxPoint pos 
= m_action_part
->rect
.GetPosition(); 
3314         if (m_action_part
->orientation 
== wxHORIZONTAL
) 
3315             pos
.y 
= wxMax(0, event
.m_y 
- m_action_offset
.y
); 
3317             pos
.x 
= wxMax(0, event
.m_x 
- m_action_offset
.x
); 
3319         wxRect 
rect(m_frame
->ClientToScreen(pos
), 
3320                     m_action_part
->rect
.GetSize()); 
3323         if (!m_action_hintrect
.IsEmpty()) 
3324             DrawResizeHint(dc
, m_action_hintrect
); 
3325         DrawResizeHint(dc
, rect
); 
3326         m_action_hintrect 
= rect
; 
3328     else if (m_action 
== actionClickCaption
) 
3330         int drag_x_threshold 
= wxSystemSettings::GetMetric(wxSYS_DRAG_X
); 
3331         int drag_y_threshold 
= wxSystemSettings::GetMetric(wxSYS_DRAG_Y
); 
3333         // caption has been clicked.  we need to check if the mouse 
3334         // is now being dragged. if it is, we need to change the 
3335         // mouse action to 'drag' 
3336         if (abs(event
.m_x 
- m_action_start
.x
) > drag_x_threshold 
|| 
3337             abs(event
.m_y 
- m_action_start
.y
) > drag_y_threshold
) 
3339             wxPaneInfo
* pane_info 
= m_action_part
->pane
; 
3341             if (!pane_info
->IsToolbar()) 
3343                 if ((m_flags 
& wxAUI_MGR_ALLOW_FLOATING
) && 
3344                     pane_info
->IsFloatable()) 
3346                     m_action 
= actionDragFloatingPane
; 
3348                     // set initial float position 
3349                     wxPoint pt 
= m_frame
->ClientToScreen(event
.GetPosition()); 
3350                     pane_info
->floating_pos 
= wxPoint(pt
.x 
- m_action_offset
.x
, 
3351                                                       pt
.y 
- m_action_offset
.y
); 
3356                     m_action_window 
= pane_info
->frame
; 
3358                     // action offset is used here to make it feel "natural" to the user 
3359                     // to drag a docked pane and suddenly have it become a floating frame. 
3360                     // Sometimes, however, the offset where the user clicked on the docked 
3361                     // caption is bigger than the width of the floating frame itself, so 
3362                     // in that case we need to set the action offset to a sensible value 
3363                     wxSize frame_size 
= m_action_window
->GetSize(); 
3364                     if (frame_size
.x 
<= m_action_offset
.x
) 
3365                         m_action_offset
.x 
= 30; 
3370                 m_action 
= actionDragToolbarPane
; 
3371                 m_action_window 
= pane_info
->window
; 
3375     else if (m_action 
== actionDragFloatingPane
) 
3377         wxPoint pt 
= m_frame
->ClientToScreen(event
.GetPosition()); 
3378         m_action_window
->Move(pt
.x 
- m_action_offset
.x
, 
3379                              pt
.y 
- m_action_offset
.y
); 
3381     else if (m_action 
== actionDragToolbarPane
) 
3383         wxPaneInfo
& pane 
= GetPane(m_action_window
); 
3384         wxASSERT_MSG(pane
.IsOk(), wxT("Pane window not found")); 
3386         pane
.state 
|= wxPaneInfo::actionPane
; 
3388         wxPoint pt 
= event
.GetPosition(); 
3389         DoDrop(m_docks
, m_panes
, pane
, pt
, m_action_offset
); 
3391         // if DoDrop() decided to float the pane, set up 
3392         // the floating pane's initial position 
3393         if (pane
.IsFloating()) 
3395             wxPoint pt 
= m_frame
->ClientToScreen(event
.GetPosition()); 
3396             pane
.floating_pos 
= wxPoint(pt
.x 
- m_action_offset
.x
, 
3397                                         pt
.y 
- m_action_offset
.y
); 
3400         // this will do the actiual move operation; 
3401         // in the case that the pane has been floated, 
3402         // this call will create the floating pane 
3403         // and do the reparenting 
3406         // if the pane has been floated, change the mouse 
3407         // action actionDragFloatingPane so that subsequent 
3408         // EVT_MOTION() events will move the floating pane 
3409         if (pane
.IsFloating()) 
3411             pane
.state 
&= ~wxPaneInfo::actionPane
; 
3412             m_action 
= actionDragFloatingPane
; 
3413             m_action_window 
= pane
.frame
; 
3418         wxDockUIPart
* part 
= HitTest(event
.GetX(), event
.GetY()); 
3419         if (part 
&& part
->type 
== wxDockUIPart::typePaneButton
) 
3421             if (part 
!= m_hover_button
) 
3423                 // make the old button normal 
3425                     UpdateButtonOnScreen(m_hover_button
, event
); 
3427                 // mouse is over a button, so repaint the 
3428                 // button in hover mode 
3429                 UpdateButtonOnScreen(part
, event
); 
3430                 m_hover_button 
= part
; 
3437                 m_hover_button 
= NULL
; 
3448 void wxFrameManager::OnLeaveWindow(wxMouseEvent
& WXUNUSED(event
)) 
3452         m_hover_button 
= NULL
; 
3457 void wxFrameManager::OnChildFocus(wxChildFocusEvent
& event
) 
3459     // when a child pane has it's focus set, we should change the 
3460     // pane's active state to reflect this. (this is only true if 
3461     // active panes are allowed by the owner) 
3462     if (GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE
) 
3464         if (GetPane(event
.GetWindow()).IsOk()) 
3466             SetActivePane(m_panes
, event
.GetWindow()); 
3473 // OnPaneButton() is an event handler that is called 
3474 // when a pane button has been pressed. 
3475 void wxFrameManager::OnPaneButton(wxFrameManagerEvent
& event
) 
3477     wxPaneInfo
& pane 
= *(event
.pane
); 
3479     if (event
.button 
== wxPaneInfo::buttonClose
) 
3484     else if (event
.button 
== wxPaneInfo::buttonPin
) 
3486         if ((m_flags 
& wxAUI_MGR_ALLOW_FLOATING
) &&