1 ///////////////////////////////////////////////////////////////////////////////
2 // Name:        src/aui/framemanager.cpp
3 // Purpose:     wxaui: wx advanced user interface - docking window manager
4 // Author:      Benjamin I. Williams
5 // Modified by:
6 // Created:     2005-05-17
7 // Copyright:   (C) Copyright 2005-2006, Kirix Corporation, All Rights Reserved
8 // Licence:     wxWindows Library Licence, Version 3.1
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 // ============================================================================
12 // declarations
13 // ============================================================================
14 
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18 
19 #include "wx/wxprec.h"
20 
21 
22 #if wxUSE_AUI
23 
24 #include "wx/aui/framemanager.h"
25 #include "wx/aui/dockart.h"
26 #include "wx/aui/floatpane.h"
27 #include "wx/aui/tabmdi.h"
28 #include "wx/aui/auibar.h"
29 #include "wx/mdi.h"
30 #include "wx/wupdlock.h"
31 
32 #ifndef WX_PRECOMP
33     #include "wx/panel.h"
34     #include "wx/settings.h"
35     #include "wx/app.h"
36     #include "wx/dcclient.h"
37     #include "wx/dcscreen.h"
38     #include "wx/toolbar.h"
39     #include "wx/image.h"
40     #include "wx/statusbr.h"
41 #endif
42 
43 WX_CHECK_BUILD_OPTIONS("wxAUI")
44 
45 #include "wx/arrimpl.cpp"
46 WX_DECLARE_OBJARRAY(wxRect, wxAuiRectArray);
47 WX_DEFINE_OBJARRAY(wxAuiRectArray)
48 WX_DEFINE_OBJARRAY(wxAuiDockUIPartArray)
49 WX_DEFINE_OBJARRAY(wxAuiDockInfoArray)
50 WX_DEFINE_OBJARRAY(wxAuiPaneInfoArray)
51 
52 wxAuiPaneInfo wxAuiNullPaneInfo;
53 wxAuiDockInfo wxAuiNullDockInfo;
54 wxDEFINE_EVENT( wxEVT_AUI_PANE_BUTTON, wxAuiManagerEvent );
55 wxDEFINE_EVENT( wxEVT_AUI_PANE_CLOSE, wxAuiManagerEvent );
56 wxDEFINE_EVENT( wxEVT_AUI_PANE_MAXIMIZE, wxAuiManagerEvent );
57 wxDEFINE_EVENT( wxEVT_AUI_PANE_RESTORE, wxAuiManagerEvent );
58 wxDEFINE_EVENT( wxEVT_AUI_PANE_ACTIVATED, wxAuiManagerEvent );
59 wxDEFINE_EVENT( wxEVT_AUI_RENDER, wxAuiManagerEvent );
60 wxDEFINE_EVENT( wxEVT_AUI_FIND_MANAGER, wxAuiManagerEvent );
61 
62 #ifdef __WXMAC__
63     // a few defines to avoid nameclashes
64     #define __MAC_OS_X_MEMORY_MANAGER_CLEAN__ 1
65     #define __AIFF__
66     #include "wx/osx/private.h"
67 #endif
68 
69 #ifdef __WXMSW__
70     #include "wx/msw/wrapwin.h"
71     #include "wx/msw/private.h"
72     #include "wx/msw/dc.h"
73 #endif
74 
75 wxIMPLEMENT_DYNAMIC_CLASS(wxAuiManagerEvent, wxEvent);
76 wxIMPLEMENT_CLASS(wxAuiManager, wxEvtHandler);
77 
78 
79 
80 const int auiToolBarLayer = 10;
81 
82 #ifndef __WXGTK20__
83 
84 
85 class wxPseudoTransparentFrame : public wxFrame
86 {
87 public:
wxPseudoTransparentFrame(wxWindow * parent=NULL,wxWindowID id=wxID_ANY,const wxString & title=wxEmptyString,const wxPoint & pos=wxDefaultPosition,const wxSize & size=wxDefaultSize,long style=wxDEFAULT_FRAME_STYLE,const wxString & name=wxT ("frame"))88     wxPseudoTransparentFrame(wxWindow* parent = NULL,
89                 wxWindowID id = wxID_ANY,
90                 const wxString& title = wxEmptyString,
91                 const wxPoint& pos = wxDefaultPosition,
92                 const wxSize& size = wxDefaultSize,
93                 long style = wxDEFAULT_FRAME_STYLE,
94                 const wxString &name = wxT("frame"))
95                     : wxFrame(parent, id, title, pos, size, style | wxFRAME_SHAPED, name)
96     {
97         SetBackgroundStyle(wxBG_STYLE_PAINT);
98         m_amount=0;
99         m_maxWidth=0;
100         m_maxHeight=0;
101         m_lastWidth=0;
102         m_lastHeight=0;
103 #ifdef __WXGTK__
104         m_canSetShape = false; // have to wait for window create event on GTK
105 #else
106         m_canSetShape = true;
107 #endif
108         m_region = wxRegion(0, 0, 0, 0);
109         SetTransparent(0);
110     }
111 
SetTransparent(wxByte alpha)112     virtual bool SetTransparent(wxByte alpha) wxOVERRIDE
113     {
114         if (m_canSetShape)
115         {
116             wxSize size = GetClientSize();
117 
118             m_maxWidth = size.x;
119             m_maxHeight = size.y;
120             m_amount = alpha;
121             m_region.Clear();
122 //            m_region.Union(0, 0, 1, m_maxWidth);
123             if (m_amount)
124             {
125                 for (int y=0; y<m_maxHeight; y++)
126                 {
127                     // Reverse the order of the bottom 4 bits
128                     int j=((y&8)?1:0)|((y&4)?2:0)|((y&2)?4:0)|((y&1)?8:0);
129                     if ((j*16+8)<m_amount)
130                         m_region.Union(0, y, m_maxWidth, 1);
131                 }
132             }
133             SetShape(m_region);
134             Refresh();
135         }
136         return true;
137     }
138 
OnPaint(wxPaintEvent & WXUNUSED (event))139     void OnPaint(wxPaintEvent& WXUNUSED(event))
140     {
141         wxPaintDC dc(this);
142 
143         if (m_region.IsEmpty())
144             return;
145 
146 #ifdef __WXMAC__
147         dc.SetBrush(wxColour(128, 192, 255));
148 #else
149         dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVECAPTION));
150 #endif
151         dc.SetPen(*wxTRANSPARENT_PEN);
152 
153         wxRegionIterator upd(GetUpdateRegion()); // get the update rect list
154 
155         while (upd)
156         {
157             wxRect rect(upd.GetRect());
158             dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height);
159 
160             ++upd;
161         }
162     }
163 
164 #ifdef __WXGTK__
OnWindowCreate(wxWindowCreateEvent & WXUNUSED (event))165     void OnWindowCreate(wxWindowCreateEvent& WXUNUSED(event))
166     {
167         m_canSetShape=true;
168         SetTransparent(0);
169     }
170 #endif
171 
OnSize(wxSizeEvent & event)172     void OnSize(wxSizeEvent& event)
173     {
174         // We sometimes get surplus size events
175         if ((event.GetSize().GetWidth() == m_lastWidth) &&
176             (event.GetSize().GetHeight() == m_lastHeight))
177         {
178             event.Skip();
179             return;
180         }
181         m_lastWidth = event.GetSize().GetWidth();
182         m_lastHeight = event.GetSize().GetHeight();
183 
184         SetTransparent(m_amount);
185         m_region.Intersect(0, 0, event.GetSize().GetWidth(),
186                            event.GetSize().GetHeight());
187         SetShape(m_region);
188         Refresh();
189         event.Skip();
190     }
191 
192 private:
193     wxByte m_amount;
194     int m_maxWidth;
195     int m_maxHeight;
196     bool m_canSetShape;
197     int m_lastWidth,m_lastHeight;
198 
199     wxRegion m_region;
200 
201     wxDECLARE_DYNAMIC_CLASS(wxPseudoTransparentFrame);
202     wxDECLARE_EVENT_TABLE();
203 };
204 
205 
206 wxIMPLEMENT_DYNAMIC_CLASS(wxPseudoTransparentFrame, wxFrame);
207 
wxBEGIN_EVENT_TABLE(wxPseudoTransparentFrame,wxFrame)208 wxBEGIN_EVENT_TABLE(wxPseudoTransparentFrame, wxFrame)
209     EVT_PAINT(wxPseudoTransparentFrame::OnPaint)
210     EVT_SIZE(wxPseudoTransparentFrame::OnSize)
211 #ifdef __WXGTK__
212     EVT_WINDOW_CREATE(wxPseudoTransparentFrame::OnWindowCreate)
213 #endif
214 wxEND_EVENT_TABLE()
215 
216 
217 #else
218   // __WXGTK20__
219 
220 #include "wx/gtk/private/wrapgtk.h"
221 
222 static void
223 gtk_pseudo_window_realized_callback( GtkWidget *m_widget, void *WXUNUSED(win) )
224 {
225         wxSize disp = wxGetDisplaySize();
226         int amount = 128;
227         wxRegion region;
228         for (int y=0; y<disp.y; y++)
229                 {
230                     // Reverse the order of the bottom 4 bits
231                     int j=((y&8)?1:0)|((y&4)?2:0)|((y&2)?4:0)|((y&1)?8:0);
232                     if ((j*16+8)<amount)
233                         region.Union(0, y, disp.x, 1);
234                 }
235         gdk_window_shape_combine_region(gtk_widget_get_window(m_widget), region.GetRegion(), 0, 0);
236 }
237 
238 
239 class wxPseudoTransparentFrame: public wxFrame
240 {
241 public:
242     wxPseudoTransparentFrame(wxWindow* parent = NULL,
243                 wxWindowID id = wxID_ANY,
244                 const wxString& title = wxEmptyString,
245                 const wxPoint& pos = wxDefaultPosition,
246                 const wxSize& size = wxDefaultSize,
247                 long style = wxDEFAULT_FRAME_STYLE,
248                 const wxString &name = wxT("frame"))
249     {
250          if (!CreateBase( parent, id, pos, size, style, wxDefaultValidator, name ))
251             return;
252 
253         m_title = title;
254 
255         m_widget = gtk_window_new( GTK_WINDOW_POPUP );
256         g_object_ref(m_widget);
257 
258         if (parent) parent->AddChild(this);
259 
260         g_signal_connect( m_widget, "realize",
261                       G_CALLBACK (gtk_pseudo_window_realized_callback), this );
262 
263         m_backgroundColour.Set(128, 192, 255);
264         GTKApplyWidgetStyle();
265     }
266 
267     bool SetTransparent(wxByte WXUNUSED(alpha)) wxOVERRIDE
268     {
269         return true;
270     }
271 
272 protected:
273     virtual void DoSetSizeHints( int minW, int minH,
274                                  int maxW, int maxH,
275                                  int incW, int incH) wxOVERRIDE
276     {
277         // the real wxFrame method doesn't work for us because we're not really
278         // a top level window so skip it
279         wxWindow::DoSetSizeHints(minW, minH, maxW, maxH, incW, incH);
280     }
281 
282 private:
283     wxDECLARE_DYNAMIC_CLASS(wxPseudoTransparentFrame);
284 };
285 
286 wxIMPLEMENT_DYNAMIC_CLASS(wxPseudoTransparentFrame, wxFrame);
287 
288 #endif
289  // __WXGTK20__
290 
291 
292 
293 // -- static utility functions --
294 
295 static wxBitmap wxPaneCreateStippleBitmap()
296 {
297     // TODO: Provide x1.5 and x2.0 versions.
298     unsigned char data[] = { 0,0,0,192,192,192, 192,192,192,0,0,0 };
299     wxImage img(2,2,data,true);
300     return wxBitmap(img);
301 }
302 
DrawResizeHint(wxDC & dc,const wxRect & rect)303 static void DrawResizeHint(wxDC& dc, const wxRect& rect)
304 {
305     wxBitmap stipple = wxPaneCreateStippleBitmap();
306     wxBrush brush(stipple);
307     dc.SetBrush(brush);
308 #ifdef __WXMSW__
309     wxMSWDCImpl *impl = (wxMSWDCImpl*) dc.GetImpl();
310     PatBlt(GetHdcOf(*impl), rect.GetX(), rect.GetY(), rect.GetWidth(), rect.GetHeight(), PATINVERT);
311 #else
312     dc.SetPen(*wxTRANSPARENT_PEN);
313 
314     dc.SetLogicalFunction(wxXOR);
315     dc.DrawRectangle(rect);
316 #endif
317 }
318 
319 
320 
321 // CopyDocksAndPanes() - this utility function creates copies of
322 // the dock and pane info.  wxAuiDockInfo's usually contain pointers
323 // to wxAuiPaneInfo classes, thus this function is necessary to reliably
324 // reconstruct that relationship in the new dock info and pane info arrays
325 
CopyDocksAndPanes(wxAuiDockInfoArray & dest_docks,wxAuiPaneInfoArray & dest_panes,const wxAuiDockInfoArray & src_docks,const wxAuiPaneInfoArray & src_panes)326 static void CopyDocksAndPanes(wxAuiDockInfoArray& dest_docks,
327                               wxAuiPaneInfoArray& dest_panes,
328                               const wxAuiDockInfoArray& src_docks,
329                               const wxAuiPaneInfoArray& src_panes)
330 {
331     dest_docks = src_docks;
332     dest_panes = src_panes;
333     int i, j, k, dock_count, pc1, pc2;
334     for (i = 0, dock_count = dest_docks.GetCount(); i < dock_count; ++i)
335     {
336         wxAuiDockInfo& dock = dest_docks.Item(i);
337         for (j = 0, pc1 = dock.panes.GetCount(); j < pc1; ++j)
338             for (k = 0, pc2 = src_panes.GetCount(); k < pc2; ++k)
339                 if (dock.panes.Item(j) == &src_panes.Item(k))
340                     dock.panes.Item(j) = &dest_panes.Item(k);
341     }
342 }
343 
344 // GetMaxLayer() is an internal function which returns
345 // the highest layer inside the specified dock
GetMaxLayer(const wxAuiDockInfoArray & docks,int dock_direction)346 static int GetMaxLayer(const wxAuiDockInfoArray& docks,
347                        int dock_direction)
348 {
349     int i, dock_count, max_layer = 0;
350     for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i)
351     {
352         wxAuiDockInfo& dock = docks.Item(i);
353         if (dock.dock_direction == dock_direction &&
354             dock.dock_layer > max_layer && !dock.fixed)
355                 max_layer = dock.dock_layer;
356     }
357     return max_layer;
358 }
359 
360 
361 // GetMaxRow() is an internal function which returns
362 // the highest layer inside the specified dock
GetMaxRow(const wxAuiPaneInfoArray & panes,int direction,int layer)363 static int GetMaxRow(const wxAuiPaneInfoArray& panes, int direction, int layer)
364 {
365     int i, pane_count, max_row = 0;
366     for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i)
367     {
368         wxAuiPaneInfo& pane = panes.Item(i);
369         if (pane.dock_direction == direction &&
370             pane.dock_layer == layer &&
371             pane.dock_row > max_row)
372                 max_row = pane.dock_row;
373     }
374     return max_row;
375 }
376 
377 
378 
379 // DoInsertDockLayer() is an internal function that inserts a new dock
380 // layer by incrementing all existing dock layer values by one
DoInsertDockLayer(wxAuiPaneInfoArray & panes,int dock_direction,int dock_layer)381 static void DoInsertDockLayer(wxAuiPaneInfoArray& panes,
382                               int dock_direction,
383                               int dock_layer)
384 {
385     int i, pane_count;
386     for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i)
387     {
388         wxAuiPaneInfo& pane = panes.Item(i);
389         if (!pane.IsFloating() &&
390             pane.dock_direction == dock_direction &&
391             pane.dock_layer >= dock_layer)
392                 pane.dock_layer++;
393     }
394 }
395 
396 // DoInsertDockLayer() is an internal function that inserts a new dock
397 // row by incrementing all existing dock row values by one
DoInsertDockRow(wxAuiPaneInfoArray & panes,int dock_direction,int dock_layer,int dock_row)398 static void DoInsertDockRow(wxAuiPaneInfoArray& panes,
399                             int dock_direction,
400                             int dock_layer,
401                             int dock_row)
402 {
403     int i, pane_count;
404     for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i)
405     {
406         wxAuiPaneInfo& pane = panes.Item(i);
407         if (!pane.IsFloating() &&
408             pane.dock_direction == dock_direction &&
409             pane.dock_layer == dock_layer &&
410             pane.dock_row >= dock_row)
411                 pane.dock_row++;
412     }
413 }
414 
415 // DoInsertDockLayer() is an internal function that inserts a space for
416 // another dock pane by incrementing all existing dock row values by one
DoInsertPane(wxAuiPaneInfoArray & panes,int dock_direction,int dock_layer,int dock_row,int dock_pos)417 static void DoInsertPane(wxAuiPaneInfoArray& panes,
418                          int dock_direction,
419                          int dock_layer,
420                          int dock_row,
421                          int dock_pos)
422 {
423     int i, pane_count;
424     for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i)
425     {
426         wxAuiPaneInfo& pane = panes.Item(i);
427         if (!pane.IsFloating() &&
428             pane.dock_direction == dock_direction &&
429             pane.dock_layer == dock_layer &&
430             pane.dock_row == dock_row &&
431             pane.dock_pos >= dock_pos)
432                 pane.dock_pos++;
433     }
434 }
435 
436 // FindDocks() is an internal function that returns a list of docks which meet
437 // the specified conditions in the parameters and returns a sorted array
438 // (sorted by layer and then row)
FindDocks(wxAuiDockInfoArray & docks,int dock_direction,int dock_layer,int dock_row,wxAuiDockInfoPtrArray & arr)439 static void FindDocks(wxAuiDockInfoArray& docks,
440                       int dock_direction,
441                       int dock_layer,
442                       int dock_row,
443                       wxAuiDockInfoPtrArray& arr)
444 {
445     int begin_layer = dock_layer;
446     int end_layer = dock_layer;
447     int begin_row = dock_row;
448     int end_row = dock_row;
449     int dock_count = docks.GetCount();
450     int layer, row, i, max_row = 0, max_layer = 0;
451 
452     // discover the maximum dock layer and the max row
453     for (i = 0; i < dock_count; ++i)
454     {
455         max_row = wxMax(max_row, docks.Item(i).dock_row);
456         max_layer = wxMax(max_layer, docks.Item(i).dock_layer);
457     }
458 
459     // if no dock layer was specified, search all dock layers
460     if (dock_layer == -1)
461     {
462         begin_layer = 0;
463         end_layer = max_layer;
464     }
465 
466     // if no dock row was specified, search all dock row
467     if (dock_row == -1)
468     {
469         begin_row = 0;
470         end_row = max_row;
471     }
472 
473     arr.Clear();
474 
475     for (layer = begin_layer; layer <= end_layer; ++layer)
476         for (row = begin_row; row <= end_row; ++row)
477             for (i = 0; i < dock_count; ++i)
478             {
479                 wxAuiDockInfo& d = docks.Item(i);
480                 if (dock_direction == -1 || dock_direction == d.dock_direction)
481                 {
482                     if (d.dock_layer == layer && d.dock_row == row)
483                         arr.Add(&d);
484                 }
485             }
486 }
487 
488 // FindPaneInDock() looks up a specified window pointer inside a dock.
489 // If found, the corresponding wxAuiPaneInfo pointer is returned, otherwise NULL.
FindPaneInDock(const wxAuiDockInfo & dock,wxWindow * window)490 static wxAuiPaneInfo* FindPaneInDock(const wxAuiDockInfo& dock, wxWindow* window)
491 {
492     int i, count = dock.panes.GetCount();
493     for (i = 0; i < count; ++i)
494     {
495         wxAuiPaneInfo* p = dock.panes.Item(i);
496         if (p->window == window)
497             return p;
498     }
499     return NULL;
500 }
501 
502 // RemovePaneFromDocks() removes a pane window from all docks
503 // with a possible exception specified by parameter "ex_cept"
RemovePaneFromDocks(wxAuiDockInfoArray & docks,wxAuiPaneInfo & pane,wxAuiDockInfo * ex_cept=NULL)504 static void RemovePaneFromDocks(wxAuiDockInfoArray& docks,
505                                 wxAuiPaneInfo& pane,
506                                 wxAuiDockInfo* ex_cept  = NULL  )
507 {
508     int i, dock_count;
509     for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i)
510     {
511         wxAuiDockInfo& d = docks.Item(i);
512         if (&d == ex_cept)
513             continue;
514         wxAuiPaneInfo* pi = FindPaneInDock(d, pane.window);
515         if (pi)
516             d.panes.Remove(pi);
517     }
518 }
519 
520 /*
521 // This function works fine, and may be used in the future
522 
523 // RenumberDockRows() takes a dock and assigns sequential numbers
524 // to existing rows.  Basically it takes out the gaps; so if a
525 // dock has rows with numbers 0,2,5, they will become 0,1,2
526 static void RenumberDockRows(wxAuiDockInfoPtrArray& docks)
527 {
528     int i, dock_count;
529     for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i)
530     {
531         wxAuiDockInfo& dock = *docks.Item(i);
532         dock.dock_row = i;
533 
534         int j, pane_count;
535         for (j = 0, pane_count = dock.panes.GetCount(); j < pane_count; ++j)
536             dock.panes.Item(j)->dock_row = i;
537     }
538 }
539 */
540 
541 
542 // SetActivePane() sets the active pane, as well as cycles through
543 // every other pane and makes sure that all others' active flags
544 // are turned off
SetActivePane(wxWindow * active_pane)545 void wxAuiManager::SetActivePane(wxWindow* active_pane)
546 {
547     int i, pane_count;
548     wxAuiPaneInfo* active_paneinfo = NULL;
549     for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i)
550     {
551         wxAuiPaneInfo& pane = m_panes.Item(i);
552         pane.state &= ~wxAuiPaneInfo::optionActive;
553         if (pane.window == active_pane)
554         {
555             pane.state |= wxAuiPaneInfo::optionActive;
556             active_paneinfo = &pane;
557         }
558     }
559 
560     // send the 'activated' event after all panes have been updated
561     if ( active_paneinfo )
562     {
563         wxAuiManagerEvent evt(wxEVT_AUI_PANE_ACTIVATED);
564         evt.SetManager(this);
565         evt.SetPane(active_paneinfo);
566         ProcessMgrEvent(evt);
567     }
568 }
569 
570 
571 // this function is used to sort panes by dock position
PaneSortFunc(wxAuiPaneInfo ** p1,wxAuiPaneInfo ** p2)572 static int PaneSortFunc(wxAuiPaneInfo** p1, wxAuiPaneInfo** p2)
573 {
574     return ((*p1)->dock_pos < (*p2)->dock_pos) ? -1 : 1;
575 }
576 
577 
IsValid() const578 bool wxAuiPaneInfo::IsValid() const
579 {
580     // Should this RTTI and function call be rewritten as
581     // sending a new event type to allow other window types
582     // to check the pane settings?
583     wxAuiToolBar* toolbar = wxDynamicCast(window, wxAuiToolBar);
584     return !toolbar || toolbar->IsPaneValid(*this);
585 }
586 
587 // -- wxAuiManager class implementation --
588 
589 
wxBEGIN_EVENT_TABLE(wxAuiManager,wxEvtHandler)590 wxBEGIN_EVENT_TABLE(wxAuiManager, wxEvtHandler)
591     EVT_AUI_PANE_BUTTON(wxAuiManager::OnPaneButton)
592     EVT_AUI_RENDER(wxAuiManager::OnRender)
593     EVT_WINDOW_DESTROY(wxAuiManager::OnDestroy)
594     EVT_PAINT(wxAuiManager::OnPaint)
595     EVT_ERASE_BACKGROUND(wxAuiManager::OnEraseBackground)
596     EVT_SIZE(wxAuiManager::OnSize)
597     EVT_SET_CURSOR(wxAuiManager::OnSetCursor)
598     EVT_LEFT_DOWN(wxAuiManager::OnLeftDown)
599     EVT_LEFT_UP(wxAuiManager::OnLeftUp)
600     EVT_MOTION(wxAuiManager::OnMotion)
601     EVT_LEAVE_WINDOW(wxAuiManager::OnLeaveWindow)
602     EVT_MOUSE_CAPTURE_LOST(wxAuiManager::OnCaptureLost)
603     EVT_CHILD_FOCUS(wxAuiManager::OnChildFocus)
604     EVT_AUI_FIND_MANAGER(wxAuiManager::OnFindManager)
605     EVT_SYS_COLOUR_CHANGED(wxAuiManager::OnSysColourChanged)
606 wxEND_EVENT_TABLE()
607 
608 
609 wxAuiManager::wxAuiManager(wxWindow* managed_wnd, unsigned int flags)
610 {
611     m_action = actionNone;
612     m_actionWindow = NULL;
613     m_hoverButton = NULL;
614     m_art = new wxAuiDefaultDockArt;
615     m_hintWnd = NULL;
616     m_flags = flags;
617     m_skipping = false;
618     m_hasMaximized = false;
619     m_frame = NULL;
620     m_dockConstraintX = 0.3;
621     m_dockConstraintY = 0.3;
622     m_reserved = NULL;
623     m_currentDragItem = -1;
624 
625     if (managed_wnd)
626     {
627         SetManagedWindow(managed_wnd);
628     }
629 }
630 
~wxAuiManager()631 wxAuiManager::~wxAuiManager()
632 {
633     UnInit();
634 
635     // NOTE: It's possible that the windows have already been destroyed by the
636     // time this dtor is called, so this loop can result in memory access via
637     // invalid pointers, resulting in a crash.  So it will be disabled while
638     // waiting for a better solution.
639 #if 0
640     for ( size_t i = 0; i < m_panes.size(); i++ )
641     {
642         wxAuiPaneInfo& pinfo = m_panes[i];
643         if (pinfo.window && !pinfo.window->GetParent())
644             delete pinfo.window;
645     }
646 #endif
647 
648     delete m_art;
649 }
650 
OnSysColourChanged(wxSysColourChangedEvent & event)651 void wxAuiManager::OnSysColourChanged(wxSysColourChangedEvent& event)
652 {
653     m_art->UpdateColoursFromSystem();
654     m_frame->Refresh();
655     event.Skip(true);
656 }
657 
658 // creates a floating frame for the windows
CreateFloatingFrame(wxWindow * parent,const wxAuiPaneInfo & paneInfo)659 wxAuiFloatingFrame* wxAuiManager::CreateFloatingFrame(wxWindow* parent,
660                                                       const wxAuiPaneInfo& paneInfo)
661 {
662     return new wxAuiFloatingFrame(parent, this, paneInfo);
663 }
664 
CanDockPanel(const wxAuiPaneInfo & WXUNUSED (p))665 bool wxAuiManager::CanDockPanel(const wxAuiPaneInfo & WXUNUSED(p))
666 {
667     // if a key modifier is pressed while dragging the frame,
668     // don't dock the window
669     return !(wxGetKeyState(WXK_CONTROL) || wxGetKeyState(WXK_ALT));
670 }
671 
672 // GetPane() looks up a wxAuiPaneInfo structure based
673 // on the supplied window pointer.  Upon failure, GetPane()
674 // returns an empty wxAuiPaneInfo, a condition which can be checked
675 // by calling wxAuiPaneInfo::IsOk().
676 //
677 // The pane info's structure may then be modified.  Once a pane's
678 // info is modified, wxAuiManager::Update() must be called to
679 // realize the changes in the UI.
680 
GetPane(wxWindow * window)681 wxAuiPaneInfo& wxAuiManager::GetPane(wxWindow* window)
682 {
683     int i, pane_count;
684     for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i)
685     {
686         wxAuiPaneInfo& p = m_panes.Item(i);
687         if (p.window == window)
688             return p;
689     }
690     return wxAuiNullPaneInfo;
691 }
692 
693 // this version of GetPane() looks up a pane based on a
694 // 'pane name', see above comment for more info
GetPane(const wxString & name)695 wxAuiPaneInfo& wxAuiManager::GetPane(const wxString& name)
696 {
697     int i, pane_count;
698     for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i)
699     {
700         wxAuiPaneInfo& p = m_panes.Item(i);
701         if (p.name == name)
702             return p;
703     }
704     return wxAuiNullPaneInfo;
705 }
706 
707 // GetAllPanes() returns a reference to all the pane info structures
GetAllPanes()708 wxAuiPaneInfoArray& wxAuiManager::GetAllPanes()
709 {
710     return m_panes;
711 }
712 
713 // HitTest() is an internal function which determines
714 // which UI item the specified coordinates are over
715 // (x,y) specify a position in client coordinates
HitTest(int x,int y)716 wxAuiDockUIPart* wxAuiManager::HitTest(int x, int y)
717 {
718     wxAuiDockUIPart* result = NULL;
719 
720     int i, part_count;
721     for (i = 0, part_count = m_uiParts.GetCount(); i < part_count; ++i)
722     {
723         wxAuiDockUIPart* item = &m_uiParts.Item(i);
724 
725         // we are not interested in typeDock, because this space
726         // isn't used to draw anything, just for measurements;
727         // besides, the entire dock area is covered with other
728         // rectangles, which we are interested in.
729         if (item->type == wxAuiDockUIPart::typeDock)
730             continue;
731 
732         // if we already have a hit on a more specific item, we are not
733         // interested in a pane hit.  If, however, we don't already have
734         // a hit, returning a pane hit is necessary for some operations
735         if ((item->type == wxAuiDockUIPart::typePane ||
736             item->type == wxAuiDockUIPart::typePaneBorder) && result)
737             continue;
738 
739         // if the point is inside the rectangle, we have a hit
740         if (item->rect.Contains(x,y))
741             result = item;
742     }
743 
744     return result;
745 }
746 
747 
748 // SetFlags() and GetFlags() allow the owner to set various
749 // options which are global to wxAuiManager
SetFlags(unsigned int flags)750 void wxAuiManager::SetFlags(unsigned int flags)
751 {
752     // find out if we have to call UpdateHintWindowConfig()
753     bool update_hint_wnd = false;
754     unsigned int hint_mask = wxAUI_MGR_TRANSPARENT_HINT |
755                              wxAUI_MGR_VENETIAN_BLINDS_HINT |
756                              wxAUI_MGR_RECTANGLE_HINT;
757     if ((flags & hint_mask) != (m_flags & hint_mask))
758         update_hint_wnd = true;
759 
760 
761     // set the new flags
762     m_flags = flags;
763 
764     if (update_hint_wnd)
765     {
766         UpdateHintWindowConfig();
767     }
768 }
769 
GetFlags() const770 unsigned int wxAuiManager::GetFlags() const
771 {
772     return m_flags;
773 }
774 
775 // With Core Graphics on Mac or GTK 3, it's not possible to show sash feedback,
776 // so we'll always use live update instead.
777 #if defined(__WXMAC__) || defined(__WXGTK3__)
778     #define wxUSE_AUI_LIVE_RESIZE_ALWAYS 1
779 #else
780     #define wxUSE_AUI_LIVE_RESIZE_ALWAYS 0
781 #endif
782 
AlwaysUsesLiveResize()783 /* static */ bool wxAuiManager::AlwaysUsesLiveResize()
784 {
785     return wxUSE_AUI_LIVE_RESIZE_ALWAYS;
786 }
787 
HasLiveResize() const788 bool wxAuiManager::HasLiveResize() const
789 {
790 #if wxUSE_AUI_LIVE_RESIZE_ALWAYS
791     return true;
792 #else
793     return (GetFlags() & wxAUI_MGR_LIVE_RESIZE) == wxAUI_MGR_LIVE_RESIZE;
794 #endif
795 }
796 
797 // don't use these anymore as they are deprecated
798 // use Set/GetManagedFrame() instead
SetFrame(wxFrame * frame)799 void wxAuiManager::SetFrame(wxFrame* frame)
800 {
801     SetManagedWindow((wxWindow*)frame);
802 }
803 
GetFrame() const804 wxFrame* wxAuiManager::GetFrame() const
805 {
806     return (wxFrame*)m_frame;
807 }
808 
809 
810 // this function will return the aui manager for a given
811 // window.  The |window| parameter should be any child window
812 // or grand-child window (and so on) of the frame/window
813 // managed by wxAuiManager.  The |window| parameter does not
814 // need to be managed by the manager itself.
GetManager(wxWindow * window)815 wxAuiManager* wxAuiManager::GetManager(wxWindow* window)
816 {
817     wxAuiManagerEvent evt(wxEVT_AUI_FIND_MANAGER);
818     evt.SetManager(NULL);
819     evt.ResumePropagation(wxEVENT_PROPAGATE_MAX);
820     if (!window->GetEventHandler()->ProcessEvent(evt))
821         return NULL;
822 
823     return evt.GetManager();
824 }
825 
826 
UpdateHintWindowConfig()827 void wxAuiManager::UpdateHintWindowConfig()
828 {
829     // find out if the system can do transparent frames
830     bool can_do_transparent = false;
831 
832     wxWindow* w = m_frame;
833     while (w)
834     {
835         if (wxDynamicCast(w, wxFrame))
836         {
837             wxFrame* f = static_cast<wxFrame*>(w);
838             can_do_transparent = f->CanSetTransparent();
839 
840             break;
841         }
842 
843         w = w->GetParent();
844     }
845 
846     // if there is an existing hint window, delete it
847     if (m_hintWnd)
848     {
849         m_hintWnd->Destroy();
850         m_hintWnd = NULL;
851     }
852 
853     m_hintFadeMax = 50;
854     m_hintWnd = NULL;
855 
856     if ((m_flags & wxAUI_MGR_TRANSPARENT_HINT) && can_do_transparent)
857     {
858         // Make a window to use for a transparent hint
859         #if defined(__WXMSW__) || defined(__WXGTK__) || defined(__WXQT__)
860             m_hintWnd = new wxFrame(m_frame, wxID_ANY, wxEmptyString,
861                                      wxDefaultPosition, wxSize(1,1),
862                                          wxFRAME_TOOL_WINDOW |
863                                          wxFRAME_FLOAT_ON_PARENT |
864                                          wxFRAME_NO_TASKBAR |
865                                          wxNO_BORDER);
866 
867             m_hintWnd->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVECAPTION));
868         #elif defined(__WXMAC__)
869             // Using a miniframe with float and tool styles keeps the parent
870             // frame activated and highlighted as such...
871             m_hintWnd = new wxMiniFrame(m_frame, wxID_ANY, wxEmptyString,
872                                          wxDefaultPosition, wxSize(1,1),
873                                          wxFRAME_FLOAT_ON_PARENT
874                                          | wxFRAME_TOOL_WINDOW );
875             m_hintWnd->Bind(wxEVT_ACTIVATE, &wxAuiManager::OnHintActivate, this);
876 
877             // Can't set the bg colour of a Frame in wxMac
878             wxPanel* p = new wxPanel(m_hintWnd);
879 
880             // The default wxSYS_COLOUR_ACTIVECAPTION colour is a light silver
881             // color that is really hard to see, especially transparent.
882             // Until a better system color is decided upon we'll just use
883             // blue.
884             p->SetBackgroundColour(*wxBLUE);
885         #endif
886 
887     }
888     else
889     {
890         if ((m_flags & wxAUI_MGR_TRANSPARENT_HINT) != 0 ||
891             (m_flags & wxAUI_MGR_VENETIAN_BLINDS_HINT) != 0)
892         {
893             // system can't support transparent fade, or the venetian
894             // blinds effect was explicitly requested
895             m_hintWnd = new wxPseudoTransparentFrame(m_frame,
896                                                       wxID_ANY,
897                                                       wxEmptyString,
898                                                       wxDefaultPosition,
899                                                       wxSize(1,1),
900                                                             wxFRAME_TOOL_WINDOW |
901                                                             wxFRAME_FLOAT_ON_PARENT |
902                                                             wxFRAME_NO_TASKBAR |
903                                                             wxNO_BORDER);
904             m_hintFadeMax = 128;
905         }
906     }
907 }
908 
909 
910 // SetManagedWindow() is usually called once when the frame
911 // manager class is being initialized.  "frame" specifies
912 // the frame which should be managed by the frame manager
SetManagedWindow(wxWindow * wnd)913 void wxAuiManager::SetManagedWindow(wxWindow* wnd)
914 {
915     wxASSERT_MSG(wnd, wxT("specified window must be non-NULL"));
916 
917     UnInit();
918 
919     m_frame = wnd;
920     m_frame->PushEventHandler(this);
921 
922 #if wxUSE_MDI
923     // if the owner is going to manage an MDI parent frame,
924     // we need to add the MDI client window as the default
925     // center pane
926 
927     if (wxDynamicCast(m_frame, wxMDIParentFrame))
928     {
929         wxMDIParentFrame* mdi_frame = (wxMDIParentFrame*)m_frame;
930         wxWindow* client_window = mdi_frame->GetClientWindow();
931 
932         wxASSERT_MSG(client_window, wxT("Client window is NULL!"));
933 
934         AddPane(client_window,
935                 wxAuiPaneInfo().Name(wxT("mdiclient")).
936                 CenterPane().PaneBorder(false));
937     }
938     else if (wxDynamicCast(m_frame, wxAuiMDIParentFrame))
939     {
940         wxAuiMDIParentFrame* mdi_frame = (wxAuiMDIParentFrame*)m_frame;
941         wxAuiMDIClientWindow* client_window = mdi_frame->GetClientWindow();
942         wxASSERT_MSG(client_window, wxT("Client window is NULL!"));
943 
944         AddPane(client_window,
945                 wxAuiPaneInfo().Name(wxT("mdiclient")).
946                 CenterPane().PaneBorder(false));
947     }
948 
949 #endif
950 
951     UpdateHintWindowConfig();
952 }
953 
954 
955 // UnInit() is called automatically by wxAuiManager itself when either the
956 // manager itself or its associated frame is destroyed, but can also be called
957 // explicitly, so make it safe to call it multiple times and just do nothing
958 // during any calls but the first one.
UnInit()959 void wxAuiManager::UnInit()
960 {
961     if (m_frame)
962     {
963         m_frame->RemoveEventHandler(this);
964         m_frame = NULL;
965     }
966 }
967 
968 // GetManagedWindow() returns the window pointer being managed
GetManagedWindow() const969 wxWindow* wxAuiManager::GetManagedWindow() const
970 {
971     return m_frame;
972 }
973 
GetArtProvider() const974 wxAuiDockArt* wxAuiManager::GetArtProvider() const
975 {
976     return m_art;
977 }
978 
ProcessMgrEvent(wxAuiManagerEvent & event)979 void wxAuiManager::ProcessMgrEvent(wxAuiManagerEvent& event)
980 {
981     // first, give the owner frame a chance to override
982     if (m_frame)
983     {
984         if (m_frame->GetEventHandler()->ProcessEvent(event))
985             return;
986     }
987 
988     ProcessEvent(event);
989 }
990 
991 // SetArtProvider() instructs wxAuiManager to use the
992 // specified art provider for all drawing calls.  This allows
993 // plugable look-and-feel features.  The pointer that is
994 // passed to this method subsequently belongs to wxAuiManager,
995 // and is deleted in the frame manager destructor
SetArtProvider(wxAuiDockArt * art_provider)996 void wxAuiManager::SetArtProvider(wxAuiDockArt* art_provider)
997 {
998     // delete the last art provider, if any
999     delete m_art;
1000 
1001     // assign the new art provider
1002     m_art = art_provider;
1003 }
1004 
1005 
AddPane(wxWindow * window,const wxAuiPaneInfo & paneInfo)1006 bool wxAuiManager::AddPane(wxWindow* window, const wxAuiPaneInfo& paneInfo)
1007 {
1008     wxASSERT_MSG(window, wxT("NULL window ptrs are not allowed"));
1009 
1010     // check if the pane has a valid window
1011     if (!window)
1012         return false;
1013 
1014     // check if the window is already managed by us
1015     if (GetPane(paneInfo.window).IsOk())
1016         return false;
1017 
1018     // check if the pane name already exists, this could reveal a
1019     // bug in the library user's application
1020     bool already_exists = false;
1021     if (!paneInfo.name.empty() && GetPane(paneInfo.name).IsOk())
1022     {
1023         wxFAIL_MSG(wxT("A pane with that name already exists in the manager!"));
1024         already_exists = true;
1025     }
1026 
1027     // if the new pane is docked then we should undo maximize
1028     if (paneInfo.IsDocked())
1029         RestoreMaximizedPane();
1030 
1031     // special case:  wxAuiToolBar style interacts with docking flags
1032     wxAuiPaneInfo test(paneInfo);
1033     wxAuiToolBar* toolbar = wxDynamicCast(window, wxAuiToolBar);
1034     if (toolbar)
1035     {
1036         // if pane has default docking flags
1037         const unsigned int dockMask = wxAuiPaneInfo::optionLeftDockable |
1038                                         wxAuiPaneInfo::optionRightDockable |
1039                                         wxAuiPaneInfo::optionTopDockable |
1040                                         wxAuiPaneInfo::optionBottomDockable;
1041         const unsigned int defaultDock = wxAuiPaneInfo().
1042                                             DefaultPane().state & dockMask;
1043         if ((test.state & dockMask) == defaultDock)
1044         {
1045             // set docking flags based on toolbar style
1046             if (toolbar->GetWindowStyleFlag() & wxAUI_TB_VERTICAL)
1047             {
1048                 test.TopDockable(false).BottomDockable(false);
1049             }
1050             else if (toolbar->GetWindowStyleFlag() & wxAUI_TB_HORIZONTAL)
1051             {
1052                 test.LeftDockable(false).RightDockable(false);
1053             }
1054         }
1055         else
1056         {
1057             // see whether non-default docking flags are valid
1058             test.window = window;
1059             wxCHECK_MSG(test.IsValid(), false,
1060                         "toolbar style and pane docking flags are incompatible");
1061         }
1062     }
1063 
1064     m_panes.Add(test);
1065 
1066     wxAuiPaneInfo& pinfo = m_panes.Last();
1067 
1068     // set the pane window
1069     pinfo.window = window;
1070 
1071 
1072     // if the pane's name identifier is blank, create a random string
1073     if (pinfo.name.empty() || already_exists)
1074     {
1075         pinfo.name.Printf(wxT("%08lx%08x%08x%08lx"),
1076              (unsigned long)(wxPtrToUInt(pinfo.window) & 0xffffffff),
1077              (unsigned int)time(NULL),
1078              (unsigned int)clock(),
1079              (unsigned long)m_panes.GetCount());
1080     }
1081 
1082     // set initial proportion (if not already set)
1083     if (pinfo.dock_proportion == 0)
1084         pinfo.dock_proportion = 100000;
1085 
1086     if (pinfo.HasGripper())
1087     {
1088         if (wxDynamicCast(pinfo.window, wxAuiToolBar))
1089         {
1090             // prevent duplicate gripper -- both wxAuiManager and wxAuiToolBar
1091             // have a gripper control.  The toolbar's built-in gripper
1092             // meshes better with the look and feel of the control than ours,
1093             // so turn wxAuiManager's gripper off, and the toolbar's on.
1094 
1095             wxAuiToolBar* tb = static_cast<wxAuiToolBar*>(pinfo.window);
1096             pinfo.SetFlag(wxAuiPaneInfo::optionGripper, false);
1097             tb->SetGripperVisible(true);
1098         }
1099     }
1100 
1101 
1102     if (pinfo.best_size == wxDefaultSize &&
1103         pinfo.window)
1104     {
1105         pinfo.best_size = pinfo.window->GetClientSize();
1106 
1107 #if wxUSE_TOOLBAR
1108         if (wxDynamicCast(pinfo.window, wxToolBar))
1109         {
1110             // GetClientSize() doesn't get the best size for
1111             // a toolbar under some newer versions of wxWidgets,
1112             // so use GetBestSize()
1113             pinfo.best_size = pinfo.window->GetBestSize();
1114         }
1115 #endif // wxUSE_TOOLBAR
1116 
1117         if (pinfo.min_size != wxDefaultSize)
1118         {
1119             if (pinfo.best_size.x < pinfo.min_size.x)
1120                 pinfo.best_size.x = pinfo.min_size.x;
1121             if (pinfo.best_size.y < pinfo.min_size.y)
1122                 pinfo.best_size.y = pinfo.min_size.y;
1123         }
1124     }
1125 
1126 
1127 
1128     return true;
1129 }
1130 
AddPane(wxWindow * window,int direction,const wxString & caption)1131 bool wxAuiManager::AddPane(wxWindow* window,
1132                            int direction,
1133                            const wxString& caption)
1134 {
1135     wxAuiPaneInfo pinfo;
1136     pinfo.Caption(caption);
1137     switch (direction)
1138     {
1139         case wxTOP:    pinfo.Top(); break;
1140         case wxBOTTOM: pinfo.Bottom(); break;
1141         case wxLEFT:   pinfo.Left(); break;
1142         case wxRIGHT:  pinfo.Right(); break;
1143         case wxCENTER: pinfo.CenterPane(); break;
1144     }
1145     return AddPane(window, pinfo);
1146 }
1147 
AddPane(wxWindow * window,const wxAuiPaneInfo & paneInfo,const wxPoint & drop_pos)1148 bool wxAuiManager::AddPane(wxWindow* window,
1149                            const wxAuiPaneInfo& paneInfo,
1150                            const wxPoint& drop_pos)
1151 {
1152     if (!AddPane(window, paneInfo))
1153         return false;
1154 
1155     wxAuiPaneInfo& pane = GetPane(window);
1156 
1157     DoDrop(m_docks, m_panes, pane, drop_pos, wxPoint(0,0));
1158 
1159     return true;
1160 }
1161 
InsertPane(wxWindow * window,const wxAuiPaneInfo & paneInfo,int insert_level)1162 bool wxAuiManager::InsertPane(wxWindow* window, const wxAuiPaneInfo& paneInfo,
1163                                 int insert_level)
1164 {
1165     wxASSERT_MSG(window, wxT("NULL window ptrs are not allowed"));
1166 
1167     // shift the panes around, depending on the insert level
1168     switch (insert_level)
1169     {
1170         case wxAUI_INSERT_PANE:
1171             DoInsertPane(m_panes,
1172                  paneInfo.dock_direction,
1173                  paneInfo.dock_layer,
1174                  paneInfo.dock_row,
1175                  paneInfo.dock_pos);
1176             break;
1177         case wxAUI_INSERT_ROW:
1178             DoInsertDockRow(m_panes,
1179                  paneInfo.dock_direction,
1180                  paneInfo.dock_layer,
1181                  paneInfo.dock_row);
1182             break;
1183         case wxAUI_INSERT_DOCK:
1184             DoInsertDockLayer(m_panes,
1185                  paneInfo.dock_direction,
1186                  paneInfo.dock_layer);
1187             break;
1188     }
1189 
1190     // if the window already exists, we are basically just moving/inserting the
1191     // existing window.  If it doesn't exist, we need to add it and insert it
1192     wxAuiPaneInfo& existing_pane = GetPane(window);
1193     if (!existing_pane.IsOk())
1194     {
1195         return AddPane(window, paneInfo);
1196     }
1197     else
1198     {
1199         if (paneInfo.IsFloating())
1200         {
1201             existing_pane.Float();
1202             if (paneInfo.floating_pos != wxDefaultPosition)
1203                 existing_pane.FloatingPosition(paneInfo.floating_pos);
1204             if (paneInfo.floating_size != wxDefaultSize)
1205                 existing_pane.FloatingSize(paneInfo.floating_size);
1206         }
1207         else
1208         {
1209             // if the new pane is docked then we should undo maximize
1210             RestoreMaximizedPane();
1211 
1212             existing_pane.Direction(paneInfo.dock_direction);
1213             existing_pane.Layer(paneInfo.dock_layer);
1214             existing_pane.Row(paneInfo.dock_row);
1215             existing_pane.Position(paneInfo.dock_pos);
1216         }
1217     }
1218 
1219     return true;
1220 }
1221 
1222 
1223 // DetachPane() removes a pane from the frame manager.  This
1224 // method will not destroy the window that is removed.
DetachPane(wxWindow * window)1225 bool wxAuiManager::DetachPane(wxWindow* window)
1226 {
1227     wxASSERT_MSG(window, wxT("NULL window ptrs are not allowed"));
1228 
1229     int i, count;
1230     for (i = 0, count = m_panes.GetCount(); i < count; ++i)
1231     {
1232         wxAuiPaneInfo& p = m_panes.Item(i);
1233         if (p.window == window)
1234         {
1235             if (p.frame)
1236             {
1237                 // we have a floating frame which is being detached. We need to
1238                 // reparent it to m_frame and destroy the floating frame
1239 
1240                 // reduce flicker
1241                 p.window->SetSize(1,1);
1242 
1243                 if (p.frame->IsShown())
1244                     p.frame->Show(false);
1245 
1246                 // reparent to m_frame and destroy the pane
1247                 if (m_actionWindow == p.frame)
1248                 {
1249                     m_actionWindow = NULL;
1250                 }
1251 
1252                 p.window->Reparent(m_frame);
1253                 p.frame->SetSizer(NULL);
1254                 p.frame->Destroy();
1255                 p.frame = NULL;
1256             }
1257 
1258             // make sure there are no references to this pane in our uiparts,
1259             // just in case the caller doesn't call Update() immediately after
1260             // the DetachPane() call.  This prevets obscure crashes which would
1261             // happen at window repaint if the caller forgets to call Update()
1262             int pi, part_count;
1263             for (pi = 0, part_count = (int)m_uiParts.GetCount(); pi < part_count; ++pi)
1264             {
1265                 wxAuiDockUIPart& part = m_uiParts.Item(pi);
1266                 if (part.pane == &p)
1267                 {
1268                     m_uiParts.RemoveAt(pi);
1269                     part_count--;
1270                     pi--;
1271                     continue;
1272                 }
1273             }
1274 
1275             m_panes.RemoveAt(i);
1276             return true;
1277         }
1278     }
1279     return false;
1280 }
1281 
1282 // ClosePane() destroys or hides the pane depending on its flags
ClosePane(wxAuiPaneInfo & paneInfo)1283 void wxAuiManager::ClosePane(wxAuiPaneInfo& paneInfo)
1284 {
1285     // if we were maximized, restore
1286     if (paneInfo.IsMaximized())
1287     {
1288         RestorePane(paneInfo);
1289     }
1290 
1291     // first, hide the window
1292     if (paneInfo.window && paneInfo.window->IsShown())
1293     {
1294         paneInfo.window->Show(false);
1295     }
1296 
1297     // make sure that we are the parent of this window
1298     if (paneInfo.window && paneInfo.window->GetParent() != m_frame)
1299     {
1300         paneInfo.window->Reparent(m_frame);
1301     }
1302 
1303     // if we have a frame, destroy it
1304     if (paneInfo.frame)
1305     {
1306         paneInfo.frame->Destroy();
1307         paneInfo.frame = NULL;
1308     }
1309 
1310     // now we need to either destroy or hide the pane
1311     if (paneInfo.IsDestroyOnClose())
1312     {
1313         wxWindow * window = paneInfo.window;
1314         DetachPane(window);
1315         if (window)
1316         {
1317             window->Destroy();
1318         }
1319     }
1320     else
1321     {
1322         paneInfo.Hide();
1323     }
1324 }
1325 
MaximizePane(wxAuiPaneInfo & paneInfo)1326 void wxAuiManager::MaximizePane(wxAuiPaneInfo& paneInfo)
1327 {
1328     int i, pane_count;
1329 
1330     // un-maximize and hide all other panes
1331     for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i)
1332     {
1333         wxAuiPaneInfo& p = m_panes.Item(i);
1334         if (!p.IsToolbar() && !p.IsFloating())
1335         {
1336             p.Restore();
1337 
1338             // save hidden state
1339             p.SetFlag(wxAuiPaneInfo::savedHiddenState,
1340                       p.HasFlag(wxAuiPaneInfo::optionHidden));
1341 
1342             // hide the pane, because only the newly
1343             // maximized pane should show
1344             p.Hide();
1345         }
1346     }
1347 
1348     // mark ourselves maximized
1349     paneInfo.Maximize();
1350     paneInfo.Show();
1351     m_hasMaximized = true;
1352 
1353     // last, show the window
1354     if (paneInfo.window && !paneInfo.window->IsShown())
1355     {
1356         paneInfo.window->Show(true);
1357     }
1358 }
1359 
RestorePane(wxAuiPaneInfo & paneInfo)1360 void wxAuiManager::RestorePane(wxAuiPaneInfo& paneInfo)
1361 {
1362     int i, pane_count;
1363 
1364     // restore all the panes
1365     for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i)
1366     {
1367         wxAuiPaneInfo& p = m_panes.Item(i);
1368         if (!p.IsToolbar() && !p.IsFloating())
1369         {
1370             p.SetFlag(wxAuiPaneInfo::optionHidden,
1371                       p.HasFlag(wxAuiPaneInfo::savedHiddenState));
1372         }
1373     }
1374 
1375     // mark ourselves non-maximized
1376     paneInfo.Restore();
1377     m_hasMaximized = false;
1378 
1379     // last, show the window
1380     if (paneInfo.window && !paneInfo.window->IsShown())
1381     {
1382         paneInfo.window->Show(true);
1383     }
1384 }
1385 
RestoreMaximizedPane()1386 void wxAuiManager::RestoreMaximizedPane()
1387 {
1388     int i, pane_count;
1389 
1390     // restore all the panes
1391     for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i)
1392     {
1393         wxAuiPaneInfo& p = m_panes.Item(i);
1394         if (p.IsMaximized())
1395         {
1396             RestorePane(p);
1397             break;
1398         }
1399     }
1400 }
1401 
1402 // EscapeDelimiters() changes ";" into "\;" and "|" into "\|"
1403 // in the input string.  This is an internal functions which is
1404 // used for saving perspectives
EscapeDelimiters(const wxString & s)1405 static wxString EscapeDelimiters(const wxString& s)
1406 {
1407     wxString result;
1408     result.Alloc(s.length());
1409     const wxChar* ch = s.c_str();
1410     while (*ch)
1411     {
1412         if (*ch == wxT(';') || *ch == wxT('|'))
1413             result += wxT('\\');
1414         result += *ch;
1415         ++ch;
1416     }
1417     return result;
1418 }
1419 
SavePaneInfo(const wxAuiPaneInfo & pane)1420 wxString wxAuiManager::SavePaneInfo(const wxAuiPaneInfo& pane)
1421 {
1422     wxString result = wxT("name=");
1423     result += EscapeDelimiters(pane.name);
1424     result += wxT(";");
1425 
1426     result += wxT("caption=");
1427     result += EscapeDelimiters(pane.caption);
1428     result += wxT(";");
1429 
1430     result += wxString::Format(wxT("state=%u;"), pane.state);
1431     result += wxString::Format(wxT("dir=%d;"), pane.dock_direction);
1432     result += wxString::Format(wxT("layer=%d;"), pane.dock_layer);
1433     result += wxString::Format(wxT("row=%d;"), pane.dock_row);
1434     result += wxString::Format(wxT("pos=%d;"), pane.dock_pos);
1435     result += wxString::Format(wxT("prop=%d;"), pane.dock_proportion);
1436     result += wxString::Format(wxT("bestw=%d;"), pane.best_size.x);
1437     result += wxString::Format(wxT("besth=%d;"), pane.best_size.y);
1438     result += wxString::Format(wxT("minw=%d;"), pane.min_size.x);
1439     result += wxString::Format(wxT("minh=%d;"), pane.min_size.y);
1440     result += wxString::Format(wxT("maxw=%d;"), pane.max_size.x);
1441     result += wxString::Format(wxT("maxh=%d;"), pane.max_size.y);
1442     result += wxString::Format(wxT("floatx=%d;"), pane.floating_pos.x);
1443     result += wxString::Format(wxT("floaty=%d;"), pane.floating_pos.y);
1444     result += wxString::Format(wxT("floatw=%d;"), pane.floating_size.x);
1445     result += wxString::Format(wxT("floath=%d"), pane.floating_size.y);
1446 
1447     return result;
1448 }
1449 
1450 // Load a "pane" with the pane information settings in pane_part
LoadPaneInfo(wxString pane_part,wxAuiPaneInfo & pane)1451 void wxAuiManager::LoadPaneInfo(wxString pane_part, wxAuiPaneInfo &pane)
1452 {
1453     // replace escaped characters so we can
1454     // split up the string easily
1455     pane_part.Replace(wxT("\\|"), wxT("\a"));
1456     pane_part.Replace(wxT("\\;"), wxT("\b"));
1457 
1458     while(1)
1459     {
1460         wxString val_part = pane_part.BeforeFirst(wxT(';'));
1461         pane_part = pane_part.AfterFirst(wxT(';'));
1462         wxString val_name = val_part.BeforeFirst(wxT('='));
1463         wxString value = val_part.AfterFirst(wxT('='));
1464         val_name.MakeLower();
1465         val_name.Trim(true);
1466         val_name.Trim(false);
1467         value.Trim(true);
1468         value.Trim(false);
1469 
1470         if (val_name.empty())
1471             break;
1472 
1473         if (val_name == wxT("name"))
1474             pane.name = value;
1475         else if (val_name == wxT("caption"))
1476             pane.caption = value;
1477         else if (val_name == wxT("state"))
1478             pane.state = (unsigned int)wxAtoi(value.c_str());
1479         else if (val_name == wxT("dir"))
1480             pane.dock_direction = wxAtoi(value.c_str());
1481         else if (val_name == wxT("layer"))
1482             pane.dock_layer = wxAtoi(value.c_str());
1483         else if (val_name == wxT("row"))
1484             pane.dock_row = wxAtoi(value.c_str());
1485         else if (val_name == wxT("pos"))
1486             pane.dock_pos = wxAtoi(value.c_str());
1487         else if (val_name == wxT("prop"))
1488             pane.dock_proportion = wxAtoi(value.c_str());
1489         else if (val_name == wxT("bestw"))
1490             pane.best_size.x = wxAtoi(value.c_str());
1491         else if (val_name == wxT("besth"))
1492             pane.best_size.y = wxAtoi(value.c_str());
1493         else if (val_name == wxT("minw"))
1494             pane.min_size.x = wxAtoi(value.c_str());
1495         else if (val_name == wxT("minh"))
1496             pane.min_size.y = wxAtoi(value.c_str());
1497         else if (val_name == wxT("maxw"))
1498             pane.max_size.x = wxAtoi(value.c_str());
1499         else if (val_name == wxT("maxh"))
1500             pane.max_size.y = wxAtoi(value.c_str());
1501         else if (val_name == wxT("floatx"))
1502             pane.floating_pos.x = wxAtoi(value.c_str());
1503         else if (val_name == wxT("floaty"))
1504             pane.floating_pos.y = wxAtoi(value.c_str());
1505         else if (val_name == wxT("floatw"))
1506             pane.floating_size.x = wxAtoi(value.c_str());
1507         else if (val_name == wxT("floath"))
1508             pane.floating_size.y = wxAtoi(value.c_str());
1509         else {
1510             wxFAIL_MSG(wxT("Bad Perspective String"));
1511         }
1512     }
1513 
1514     // replace escaped characters so we can
1515     // split up the string easily
1516     pane.name.Replace(wxT("\a"), wxT("|"));
1517     pane.name.Replace(wxT("\b"), wxT(";"));
1518     pane.caption.Replace(wxT("\a"), wxT("|"));
1519     pane.caption.Replace(wxT("\b"), wxT(";"));
1520     pane_part.Replace(wxT("\a"), wxT("|"));
1521     pane_part.Replace(wxT("\b"), wxT(";"));
1522 
1523     return;
1524 }
1525 
1526 
1527 // SavePerspective() saves all pane information as a single string.
1528 // This string may later be fed into LoadPerspective() to restore
1529 // all pane settings.  This save and load mechanism allows an
1530 // exact pane configuration to be saved and restored at a later time
1531 
SavePerspective()1532 wxString wxAuiManager::SavePerspective()
1533 {
1534     wxString result;
1535     result.Alloc(500);
1536     result = wxT("layout2|");
1537 
1538     int pane_i, pane_count = m_panes.GetCount();
1539     for (pane_i = 0; pane_i < pane_count; ++pane_i)
1540     {
1541         wxAuiPaneInfo& pane = m_panes.Item(pane_i);
1542         result += SavePaneInfo(pane)+wxT("|");
1543     }
1544 
1545     int dock_i, dock_count = m_docks.GetCount();
1546     for (dock_i = 0; dock_i < dock_count; ++dock_i)
1547     {
1548         wxAuiDockInfo& dock = m_docks.Item(dock_i);
1549 
1550         result += wxString::Format(wxT("dock_size(%d,%d,%d)=%d|"),
1551                                    dock.dock_direction, dock.dock_layer,
1552                                    dock.dock_row, dock.size);
1553     }
1554 
1555     return result;
1556 }
1557 
1558 // LoadPerspective() loads a layout which was saved with SavePerspective()
1559 // If the "update" flag parameter is true, the GUI will immediately be updated
1560 
LoadPerspective(const wxString & layout,bool update)1561 bool wxAuiManager::LoadPerspective(const wxString& layout, bool update)
1562 {
1563     wxString input = layout;
1564     wxString part;
1565 
1566     // check layout string version
1567     //    'layout1' = wxAUI 0.9.0 - wxAUI 0.9.2
1568     //    'layout2' = wxAUI 0.9.2 (wxWidgets 2.8)
1569     part = input.BeforeFirst(wxT('|'));
1570     input = input.AfterFirst(wxT('|'));
1571     part.Trim(true);
1572     part.Trim(false);
1573     if (part != wxT("layout2"))
1574         return false;
1575 
1576     // Mark all panes currently managed as hidden. Also, dock all panes that are dockable.
1577     int pane_i, pane_count = m_panes.GetCount();
1578     for (pane_i = 0; pane_i < pane_count; ++pane_i)
1579     {
1580         wxAuiPaneInfo& p = m_panes.Item(pane_i);
1581         if(p.IsDockable())
1582             p.Dock();
1583         p.Hide();
1584     }
1585 
1586     // clear out the dock array; this will be reconstructed
1587     m_docks.Clear();
1588 
1589     // replace escaped characters so we can
1590     // split up the string easily
1591     input.Replace(wxT("\\|"), wxT("\a"));
1592     input.Replace(wxT("\\;"), wxT("\b"));
1593 
1594     m_hasMaximized = false;
1595     while (1)
1596     {
1597         wxAuiPaneInfo pane;
1598 
1599         wxString pane_part = input.BeforeFirst(wxT('|'));
1600         input = input.AfterFirst(wxT('|'));
1601         pane_part.Trim(true);
1602 
1603         // if the string is empty, we're done parsing
1604         if (pane_part.empty())
1605             break;
1606 
1607         if (pane_part.Left(9) == wxT("dock_size"))
1608         {
1609             wxString val_name = pane_part.BeforeFirst(wxT('='));
1610             wxString value = pane_part.AfterFirst(wxT('='));
1611 
1612             long dir, layer, row, size;
1613             wxString piece = val_name.AfterFirst(wxT('('));
1614             piece = piece.BeforeLast(wxT(')'));
1615             piece.BeforeFirst(wxT(',')).ToLong(&dir);
1616             piece = piece.AfterFirst(wxT(','));
1617             piece.BeforeFirst(wxT(',')).ToLong(&layer);
1618             piece.AfterFirst(wxT(',')).ToLong(&row);
1619             value.ToLong(&size);
1620 
1621             wxAuiDockInfo dock;
1622             dock.dock_direction = dir;
1623             dock.dock_layer = layer;
1624             dock.dock_row = row;
1625             dock.size = size;
1626             m_docks.Add(dock);
1627             continue;
1628         }
1629 
1630         // Undo our escaping as LoadPaneInfo needs to take an unescaped
1631         // name so it can be called by external callers
1632         pane_part.Replace(wxT("\a"), wxT("|"));
1633         pane_part.Replace(wxT("\b"), wxT(";"));
1634 
1635         LoadPaneInfo(pane_part, pane);
1636 
1637         if ( pane.IsMaximized() )
1638             m_hasMaximized = true;
1639 
1640         wxAuiPaneInfo& p = GetPane(pane.name);
1641         if (!p.IsOk())
1642         {
1643             // the pane window couldn't be found
1644             // in the existing layout -- skip it
1645             continue;
1646         }
1647 
1648         p.SafeSet(pane);
1649     }
1650 
1651     if (update)
1652         Update();
1653 
1654     return true;
1655 }
1656 
GetPanePositionsAndSizes(wxAuiDockInfo & dock,wxArrayInt & positions,wxArrayInt & sizes)1657 void wxAuiManager::GetPanePositionsAndSizes(wxAuiDockInfo& dock,
1658                                             wxArrayInt& positions,
1659                                             wxArrayInt& sizes)
1660 {
1661     int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE);
1662     int pane_borderSize = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE);
1663     int gripperSize = m_art->GetMetric(wxAUI_DOCKART_GRIPPER_SIZE);
1664 
1665     positions.Empty();
1666     sizes.Empty();
1667 
1668     int action_pane = -1;
1669     int pane_i, pane_count = dock.panes.GetCount();
1670 
1671     // find the pane marked as our action pane
1672     for (pane_i = 0; pane_i < pane_count; ++pane_i)
1673     {
1674         wxAuiPaneInfo& pane = *(dock.panes.Item(pane_i));
1675 
1676         if (pane.HasFlag(wxAuiPaneInfo::actionPane))
1677         {
1678             wxASSERT_MSG(action_pane==-1, wxT("Too many fixed action panes"));
1679             action_pane = pane_i;
1680         }
1681     }
1682 
1683     // set up each panes default position, and
1684     // determine the size (width or height, depending
1685     // on the dock's orientation) of each pane
1686     for (pane_i = 0; pane_i < pane_count; ++pane_i)
1687     {
1688         wxAuiPaneInfo& pane = *(dock.panes.Item(pane_i));
1689         positions.Add(pane.dock_pos);
1690         int size = 0;
1691 
1692         if (pane.HasBorder())
1693             size += (pane_borderSize*2);
1694 
1695         if (dock.IsHorizontal())
1696         {
1697             if (pane.HasGripper() && !pane.HasGripperTop())
1698                 size += gripperSize;
1699             size += pane.best_size.x;
1700         }
1701         else
1702         {
1703             if (pane.HasGripper() && pane.HasGripperTop())
1704                 size += gripperSize;
1705 
1706             if (pane.HasCaption())
1707                 size += caption_size;
1708             size += pane.best_size.y;
1709         }
1710 
1711         sizes.Add(size);
1712     }
1713 
1714     // if there is no action pane, just return the default
1715     // positions (as specified in pane.pane_pos)
1716     if (action_pane == -1)
1717         return;
1718 
1719     for (pane_i = action_pane-1; pane_i >= 0; --pane_i)
1720     {
1721         int amount = positions[pane_i+1] - (positions[pane_i] + sizes[pane_i]);
1722 
1723         if (amount >= 0)
1724             ;
1725         else
1726             positions[pane_i] -= -amount;
1727     }
1728 
1729     // if the dock mode is fixed, make sure none of the panes
1730     // overlap; we will bump panes that overlap
1731     int offset = 0;
1732     for (pane_i = action_pane; pane_i < pane_count; ++pane_i)
1733     {
1734         int amount = positions[pane_i] - offset;
1735         if (amount >= 0)
1736             offset += amount;
1737         else
1738             positions[pane_i] += -amount;
1739 
1740         offset += sizes[pane_i];
1741     }
1742 }
1743 
1744 
LayoutAddPane(wxSizer * cont,wxAuiDockInfo & dock,wxAuiPaneInfo & pane,wxAuiDockUIPartArray & uiparts,bool spacer_only)1745 void wxAuiManager::LayoutAddPane(wxSizer* cont,
1746                                  wxAuiDockInfo& dock,
1747                                  wxAuiPaneInfo& pane,
1748                                  wxAuiDockUIPartArray& uiparts,
1749                                  bool spacer_only)
1750 {
1751     wxAuiDockUIPart part;
1752     wxSizerItem* sizer_item;
1753 
1754     int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE);
1755     int gripperSize = m_art->GetMetric(wxAUI_DOCKART_GRIPPER_SIZE);
1756     int pane_borderSize = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE);
1757     int pane_button_size = m_art->GetMetric(wxAUI_DOCKART_PANE_BUTTON_SIZE);
1758 
1759     // find out the orientation of the item (orientation for panes
1760     // is the same as the dock's orientation)
1761     int orientation;
1762     if (dock.IsHorizontal())
1763         orientation = wxHORIZONTAL;
1764     else
1765         orientation = wxVERTICAL;
1766 
1767     // this variable will store the proportion
1768     // value that the pane will receive
1769     int pane_proportion = pane.dock_proportion;
1770 
1771     wxBoxSizer* horz_pane_sizer = new wxBoxSizer(wxHORIZONTAL);
1772     wxBoxSizer* vert_pane_sizer = new wxBoxSizer(wxVERTICAL);
1773 
1774     if (pane.HasGripper())
1775     {
1776         if (pane.HasGripperTop())
1777             sizer_item = vert_pane_sizer ->Add(1, gripperSize, 0, wxEXPAND);
1778         else
1779             sizer_item = horz_pane_sizer ->Add(gripperSize, 1, 0, wxEXPAND);
1780 
1781         part.type = wxAuiDockUIPart::typeGripper;
1782         part.dock = &dock;
1783         part.pane = &pane;
1784         part.button = 0;
1785         part.orientation = orientation;
1786         part.cont_sizer = horz_pane_sizer;
1787         part.sizer_item = sizer_item;
1788         uiparts.Add(part);
1789     }
1790 
1791     if (pane.HasCaption())
1792     {
1793         // create the caption sizer
1794         wxBoxSizer* caption_sizer = new wxBoxSizer(wxHORIZONTAL);
1795 
1796         sizer_item = caption_sizer->Add(1, caption_size, 1, wxEXPAND);
1797 
1798         part.type = wxAuiDockUIPart::typeCaption;
1799         part.dock = &dock;
1800         part.pane = &pane;
1801         part.button = 0;
1802         part.orientation = orientation;
1803         part.cont_sizer = vert_pane_sizer;
1804         part.sizer_item = sizer_item;
1805         int caption_part_idx = uiparts.GetCount();
1806         uiparts.Add(part);
1807 
1808         // add pane buttons to the caption
1809         int button_count = 0;
1810         const int NUM_SUPPORTED_BUTTONS = 3;
1811         wxAuiButtonId buttons[NUM_SUPPORTED_BUTTONS] = {
1812             wxAUI_BUTTON_MAXIMIZE_RESTORE,
1813             wxAUI_BUTTON_PIN,
1814             wxAUI_BUTTON_CLOSE
1815         };
1816         int flags[NUM_SUPPORTED_BUTTONS] = {
1817             wxAuiPaneInfo::buttonMaximize,
1818             wxAuiPaneInfo::buttonPin,
1819             wxAuiPaneInfo::buttonClose
1820         };
1821 
1822         for (int i = 0; i < NUM_SUPPORTED_BUTTONS; ++i)
1823         {
1824             if (pane.HasFlag(flags[i]))
1825             {
1826                 sizer_item = caption_sizer->Add(pane_button_size,
1827                     caption_size,
1828                     0, wxEXPAND);
1829 
1830                 part.type = wxAuiDockUIPart::typePaneButton;
1831                 part.dock = &dock;
1832                 part.pane = &pane;
1833                 part.button = buttons[i];
1834                 part.orientation = orientation;
1835                 part.cont_sizer = caption_sizer;
1836                 part.sizer_item = sizer_item;
1837                 uiparts.Add(part);
1838                 button_count++;
1839             }
1840         }
1841 
1842         // if we have buttons, add a little space to the right
1843         // of them to ease visual crowding
1844         if (button_count >= 1)
1845         {
1846             caption_sizer->Add(m_frame->FromDIP(3),1);
1847         }
1848 
1849         // add the caption sizer
1850         sizer_item = vert_pane_sizer->Add(caption_sizer, 0, wxEXPAND);
1851 
1852         uiparts.Item(caption_part_idx).sizer_item = sizer_item;
1853     }
1854 
1855     // add the pane window itself
1856     if (spacer_only)
1857     {
1858         sizer_item = vert_pane_sizer->Add(1, 1, 1, wxEXPAND);
1859     }
1860     else
1861     {
1862         sizer_item = vert_pane_sizer->Add(pane.window, 1, wxEXPAND);
1863         // Don't do this because it breaks the pane size in floating windows
1864         // BIW: Right now commenting this out is causing problems with
1865         // an mdi client window as the center pane.
1866         vert_pane_sizer->SetItemMinSize(pane.window, 1, 1);
1867     }
1868 
1869     part.type = wxAuiDockUIPart::typePane;
1870     part.dock = &dock;
1871     part.pane = &pane;
1872     part.button = 0;
1873     part.orientation = orientation;
1874     part.cont_sizer = vert_pane_sizer;
1875     part.sizer_item = sizer_item;
1876     uiparts.Add(part);
1877 
1878 
1879     // determine if the pane should have a minimum size; if the pane is
1880     // non-resizable (fixed) then we must set a minimum size. Alternatively,
1881     // if the pane.min_size is set, we must use that value as well
1882 
1883     wxSize min_size = pane.min_size;
1884     if (pane.IsFixed())
1885     {
1886         if (min_size == wxDefaultSize)
1887         {
1888             min_size = pane.best_size;
1889             pane_proportion = 0;
1890         }
1891     }
1892 
1893     if (min_size != wxDefaultSize)
1894     {
1895         vert_pane_sizer->SetItemMinSize(
1896                         vert_pane_sizer->GetChildren().GetCount()-1,
1897                         min_size.x, min_size.y);
1898     }
1899 
1900 
1901     // add the vertical sizer (caption, pane window) to the
1902     // horizontal sizer (gripper, vertical sizer)
1903     horz_pane_sizer->Add(vert_pane_sizer, 1, wxEXPAND);
1904 
1905     // finally, add the pane sizer to the dock sizer
1906 
1907     if (pane.HasBorder())
1908     {
1909         // allowing space for the pane's border
1910         sizer_item = cont->Add(horz_pane_sizer, pane_proportion,
1911                                wxEXPAND | wxALL, pane_borderSize);
1912 
1913         part.type = wxAuiDockUIPart::typePaneBorder;
1914         part.dock = &dock;
1915         part.pane = &pane;
1916         part.button = 0;
1917         part.orientation = orientation;
1918         part.cont_sizer = cont;
1919         part.sizer_item = sizer_item;
1920         uiparts.Add(part);
1921     }
1922     else
1923     {
1924         cont->Add(horz_pane_sizer, pane_proportion, wxEXPAND);
1925     }
1926 }
1927 
LayoutAddDock(wxSizer * cont,wxAuiDockInfo & dock,wxAuiDockUIPartArray & uiparts,bool spacer_only)1928 void wxAuiManager::LayoutAddDock(wxSizer* cont,
1929                                  wxAuiDockInfo& dock,
1930                                  wxAuiDockUIPartArray& uiparts,
1931                                  bool spacer_only)
1932 {
1933     wxSizerItem* sizer_item;
1934     wxAuiDockUIPart part;
1935 
1936     int sashSize = m_art->GetMetric(wxAUI_DOCKART_SASH_SIZE);
1937     int orientation = dock.IsHorizontal() ? wxHORIZONTAL : wxVERTICAL;
1938 
1939     // resizable bottom and right docks have a sash before them
1940     if (!m_hasMaximized && !dock.fixed && (dock.dock_direction == wxAUI_DOCK_BOTTOM ||
1941                         dock.dock_direction == wxAUI_DOCK_RIGHT))
1942     {
1943         sizer_item = cont->Add(sashSize, sashSize, 0, wxEXPAND);
1944 
1945         part.type = wxAuiDockUIPart::typeDockSizer;
1946         part.orientation = orientation;
1947         part.dock = &dock;
1948         part.pane = NULL;
1949         part.button = 0;
1950         part.cont_sizer = cont;
1951         part.sizer_item = sizer_item;
1952         uiparts.Add(part);
1953     }
1954 
1955     // create the sizer for the dock
1956     wxSizer* dock_sizer = new wxBoxSizer(orientation);
1957 
1958     // add each pane to the dock
1959     bool has_maximized_pane = false;
1960     int pane_i, pane_count = dock.panes.GetCount();
1961 
1962     if (dock.fixed)
1963     {
1964         wxArrayInt pane_positions, pane_sizes;
1965 
1966         // figure out the real pane positions we will
1967         // use, without modifying the each pane's pane_pos member
1968         GetPanePositionsAndSizes(dock, pane_positions, pane_sizes);
1969 
1970         int offset = 0;
1971         for (pane_i = 0; pane_i < pane_count; ++pane_i)
1972         {
1973             wxAuiPaneInfo& pane = *(dock.panes.Item(pane_i));
1974             int pane_pos = pane_positions.Item(pane_i);
1975 
1976             if (pane.IsMaximized())
1977                 has_maximized_pane = true;
1978 
1979 
1980             int amount = pane_pos - offset;
1981             if (amount > 0)
1982             {
1983                 if (dock.IsVertical())
1984                     sizer_item = dock_sizer->Add(1, amount, 0, wxEXPAND);
1985                 else
1986                     sizer_item = dock_sizer->Add(amount, 1, 0, wxEXPAND);
1987 
1988                 part.type = wxAuiDockUIPart::typeBackground;
1989                 part.dock = &dock;
1990                 part.pane = NULL;
1991                 part.button = 0;
1992                 part.orientation = (orientation==wxHORIZONTAL) ? wxVERTICAL:wxHORIZONTAL;
1993                 part.cont_sizer = dock_sizer;
1994                 part.sizer_item = sizer_item;
1995                 uiparts.Add(part);
1996 
1997                 offset += amount;
1998             }
1999 
2000             LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only);
2001 
2002             offset += pane_sizes.Item(pane_i);
2003         }
2004 
2005         // at the end add a very small stretchable background area
2006         sizer_item = dock_sizer->Add(0,0, 1, wxEXPAND);
2007 
2008         part.type = wxAuiDockUIPart::typeBackground;
2009         part.dock = &dock;
2010         part.pane = NULL;
2011         part.button = 0;
2012         part.orientation = orientation;
2013         part.cont_sizer = dock_sizer;
2014         part.sizer_item = sizer_item;
2015         uiparts.Add(part);
2016     }
2017     else
2018     {
2019         for (pane_i = 0; pane_i < pane_count; ++pane_i)
2020         {
2021             wxAuiPaneInfo& pane = *(dock.panes.Item(pane_i));
2022 
2023             if (pane.IsMaximized())
2024                 has_maximized_pane = true;
2025 
2026             // if this is not the first pane being added,
2027             // we need to add a pane sizer
2028             if (!m_hasMaximized && pane_i > 0)
2029             {
2030                 sizer_item = dock_sizer->Add(sashSize, sashSize, 0, wxEXPAND);
2031 
2032                 part.type = wxAuiDockUIPart::typePaneSizer;
2033                 part.dock = &dock;
2034                 part.pane = dock.panes.Item(pane_i-1);
2035                 part.button = 0;
2036                 part.orientation = (orientation==wxHORIZONTAL) ? wxVERTICAL:wxHORIZONTAL;
2037                 part.cont_sizer = dock_sizer;
2038                 part.sizer_item = sizer_item;
2039                 uiparts.Add(part);
2040             }
2041 
2042             LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only);
2043         }
2044     }
2045 
2046     if (dock.dock_direction == wxAUI_DOCK_CENTER || has_maximized_pane)
2047         sizer_item = cont->Add(dock_sizer, 1, wxEXPAND);
2048     else
2049         sizer_item = cont->Add(dock_sizer, 0, wxEXPAND);
2050 
2051     part.type = wxAuiDockUIPart::typeDock;
2052     part.dock = &dock;
2053     part.pane = NULL;
2054     part.button = 0;
2055     part.orientation = orientation;
2056     part.cont_sizer = cont;
2057     part.sizer_item = sizer_item;
2058     uiparts.Add(part);
2059 
2060     if (dock.IsHorizontal())
2061         cont->SetItemMinSize(dock_sizer, 0, dock.size);
2062     else
2063         cont->SetItemMinSize(dock_sizer, dock.size, 0);
2064 
2065     //  top and left docks have a sash after them
2066     if (!m_hasMaximized &&
2067         !dock.fixed &&
2068           (dock.dock_direction == wxAUI_DOCK_TOP ||
2069            dock.dock_direction == wxAUI_DOCK_LEFT))
2070     {
2071         sizer_item = cont->Add(sashSize, sashSize, 0, wxEXPAND);
2072 
2073         part.type = wxAuiDockUIPart::typeDockSizer;
2074         part.dock = &dock;
2075         part.pane = NULL;
2076         part.button = 0;
2077         part.orientation = orientation;
2078         part.cont_sizer = cont;
2079         part.sizer_item = sizer_item;
2080         uiparts.Add(part);
2081     }
2082 }
2083 
LayoutAll(wxAuiPaneInfoArray & panes,wxAuiDockInfoArray & docks,wxAuiDockUIPartArray & uiparts,bool spacer_only)2084 wxSizer* wxAuiManager::LayoutAll(wxAuiPaneInfoArray& panes,
2085                                  wxAuiDockInfoArray& docks,
2086                                  wxAuiDockUIPartArray& uiparts,
2087                                  bool spacer_only)
2088 {
2089     wxBoxSizer* container = new wxBoxSizer(wxVERTICAL);
2090 
2091     int pane_borderSize = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE);
2092     int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE);
2093     wxSize cli_size = m_frame->GetClientSize();
2094     int i, dock_count, pane_count;
2095 
2096 
2097     // empty all docks out
2098     for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i)
2099     {
2100         wxAuiDockInfo& dock = docks.Item(i);
2101 
2102         // empty out all panes, as they will be readded below
2103         dock.panes.Empty();
2104 
2105         if (dock.fixed)
2106         {
2107             // always reset fixed docks' sizes, because
2108             // the contained windows may have been resized
2109             dock.size = 0;
2110         }
2111     }
2112 
2113 
2114     // iterate through all known panes, filing each
2115     // of them into the appropriate dock. If the
2116     // pane does not exist in the dock, add it
2117     for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i)
2118     {
2119         wxAuiPaneInfo& p = panes.Item(i);
2120 
2121         // find any docks with the same dock direction, dock layer, and
2122         // dock row as the pane we are working on
2123         wxAuiDockInfo* dock;
2124         wxAuiDockInfoPtrArray arr;
2125         FindDocks(docks, p.dock_direction, p.dock_layer, p.dock_row, arr);
2126 
2127         if (arr.GetCount() > 0)
2128         {
2129             // found the right dock
2130             dock = arr.Item(0);
2131         }
2132         else
2133         {
2134             // dock was not found, so we need to create a new one
2135             wxAuiDockInfo d;
2136             d.dock_direction = p.dock_direction;
2137             d.dock_layer = p.dock_layer;
2138             d.dock_row = p.dock_row;
2139             docks.Add(d);
2140             dock = &docks.Last();
2141         }
2142 
2143 
2144         if (p.IsDocked() && p.IsShown())
2145         {
2146             // remove the pane from any existing docks except this one
2147             RemovePaneFromDocks(docks, p, dock);
2148 
2149             // pane needs to be added to the dock,
2150             // if it doesn't already exist
2151             if (!FindPaneInDock(*dock, p.window))
2152                 dock->panes.Add(&p);
2153         }
2154         else
2155         {
2156             // remove the pane from any existing docks
2157             RemovePaneFromDocks(docks, p);
2158         }
2159 
2160     }
2161 
2162     // remove any empty docks
2163     for (i = docks.GetCount()-1; i >= 0; --i)
2164     {
2165         if (docks.Item(i).panes.GetCount() == 0)
2166             docks.RemoveAt(i);
2167     }
2168 
2169     // configure the docks further
2170     for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i)
2171     {
2172         wxAuiDockInfo& dock = docks.Item(i);
2173         int j, dock_pane_count = dock.panes.GetCount();
2174 
2175         // sort the dock pane array by the pane's
2176         // dock position (dock_pos), in ascending order
2177         dock.panes.Sort(PaneSortFunc);
2178 
2179         // for newly created docks, set up their initial size
2180         if (dock.size == 0)
2181         {
2182             int size = 0;
2183 
2184             for (j = 0; j < dock_pane_count; ++j)
2185             {
2186                 wxAuiPaneInfo& pane = *dock.panes.Item(j);
2187                 wxSize pane_size = pane.best_size;
2188                 if (pane_size == wxDefaultSize)
2189                     pane_size = pane.min_size;
2190                 if (pane_size == wxDefaultSize)
2191                     pane_size = pane.window->GetSize();
2192 
2193                 if (dock.IsHorizontal())
2194                     size = wxMax(pane_size.y, size);
2195                 else
2196                     size = wxMax(pane_size.x, size);
2197             }
2198 
2199             // add space for the border (two times), but only
2200             // if at least one pane inside the dock has a pane border
2201             for (j = 0; j < dock_pane_count; ++j)
2202             {
2203                 if (dock.panes.Item(j)->HasBorder())
2204                 {
2205                     size += (pane_borderSize*2);
2206                     break;
2207                 }
2208             }
2209 
2210             // if pane is on the top or bottom, add the caption height,
2211             // but only if at least one pane inside the dock has a caption
2212             if (dock.IsHorizontal())
2213             {
2214                 for (j = 0; j < dock_pane_count; ++j)
2215                 {
2216                     if (dock.panes.Item(j)->HasCaption())
2217                     {
2218                         size += caption_size;
2219                         break;
2220                     }
2221                 }
2222             }
2223 
2224 
2225             // new dock's size may not be more than the dock constraint
2226             // parameter specifies.  See SetDockSizeConstraint()
2227 
2228             int max_dock_x_size = (int)(m_dockConstraintX * ((double)cli_size.x));
2229             int max_dock_y_size = (int)(m_dockConstraintY * ((double)cli_size.y));
2230 
2231             if (dock.IsHorizontal())
2232                 size = wxMin(size, max_dock_y_size);
2233             else
2234                 size = wxMin(size, max_dock_x_size);
2235 
2236             // absolute minimum size for a dock is 10 pixels
2237             size = wxMax(size, m_frame->FromDIP(10));
2238 
2239             dock.size = size;
2240         }
2241 
2242 
2243         // determine the dock's minimum size
2244         bool plus_border = false;
2245         bool plus_caption = false;
2246         int dock_min_size = 0;
2247         for (j = 0; j < dock_pane_count; ++j)
2248         {
2249             wxAuiPaneInfo& pane = *dock.panes.Item(j);
2250             if (pane.min_size != wxDefaultSize)
2251             {
2252                 if (pane.HasBorder())
2253                     plus_border = true;
2254                 if (pane.HasCaption())
2255                     plus_caption = true;
2256                 if (dock.IsHorizontal())
2257                 {
2258                     if (pane.min_size.y > dock_min_size)
2259                         dock_min_size = pane.min_size.y;
2260                 }
2261                 else
2262                 {
2263                     if (pane.min_size.x > dock_min_size)
2264                         dock_min_size = pane.min_size.x;
2265                 }
2266             }
2267         }
2268 
2269         if (plus_border)
2270             dock_min_size += (pane_borderSize*2);
2271         if (plus_caption && dock.IsHorizontal())
2272             dock_min_size += (caption_size);
2273 
2274         dock.min_size = dock_min_size;
2275 
2276 
2277         // if the pane's current size is less than its
2278         // minimum, increase the dock's size to its minimum
2279         if (dock.size < dock.min_size)
2280             dock.size = dock.min_size;
2281 
2282 
2283         // determine the dock's mode (fixed or proportional);
2284         // determine whether the dock has only toolbars
2285         bool action_pane_marked = false;
2286         dock.fixed = true;
2287         dock.toolbar = true;
2288         for (j = 0; j < dock_pane_count; ++j)
2289         {
2290             wxAuiPaneInfo& pane = *dock.panes.Item(j);
2291             if (!pane.IsFixed())
2292                 dock.fixed = false;
2293             if (!pane.IsToolbar())
2294                 dock.toolbar = false;
2295             if (pane.HasFlag(wxAuiPaneInfo::optionDockFixed))
2296                 dock.fixed = true;
2297             if (pane.HasFlag(wxAuiPaneInfo::actionPane))
2298                 action_pane_marked = true;
2299         }
2300 
2301 
2302         // if the dock mode is proportional and not fixed-pixel,
2303         // reassign the dock_pos to the sequential 0, 1, 2, 3;
2304         // e.g. remove gaps like 1, 2, 30, 500
2305         if (!dock.fixed)
2306         {
2307             for (j = 0; j < dock_pane_count; ++j)
2308             {
2309                 wxAuiPaneInfo& pane = *dock.panes.Item(j);
2310                 pane.dock_pos = j;
2311             }
2312         }
2313 
2314         // if the dock mode is fixed, and none of the panes
2315         // are being moved right now, make sure the panes
2316         // do not overlap each other.  If they do, we will
2317         // adjust the positions of the panes
2318         if (dock.fixed && !action_pane_marked)
2319         {
2320             wxArrayInt pane_positions, pane_sizes;
2321             GetPanePositionsAndSizes(dock, pane_positions, pane_sizes);
2322 
2323             int offset = 0;
2324             for (j = 0; j < dock_pane_count; ++j)
2325             {
2326                 wxAuiPaneInfo& pane = *(dock.panes.Item(j));
2327                 pane.dock_pos = pane_positions[j];
2328 
2329                 int amount = pane.dock_pos - offset;
2330                 if (amount >= 0)
2331                     offset += amount;
2332                 else
2333                     pane.dock_pos += -amount;
2334 
2335                 offset += pane_sizes[j];
2336             }
2337         }
2338     }
2339 
2340     // discover the maximum dock layer
2341     int max_layer = 0;
2342     for (i = 0; i < dock_count; ++i)
2343         max_layer = wxMax(max_layer, docks.Item(i).dock_layer);
2344 
2345 
2346     // clear out uiparts
2347     uiparts.Empty();
2348 
2349     // create a bunch of box sizers,
2350     // from the innermost level outwards.
2351     wxSizer* cont = NULL;
2352     wxSizer* middle = NULL;
2353     int layer = 0;
2354     int row, row_count;
2355 
2356     for (layer = 0; layer <= max_layer; ++layer)
2357     {
2358         wxAuiDockInfoPtrArray arr;
2359 
2360         // find any docks in this layer
2361         FindDocks(docks, -1, layer, -1, arr);
2362 
2363         // if there aren't any, skip to the next layer
2364         if (arr.IsEmpty())
2365             continue;
2366 
2367         wxSizer* old_cont = cont;
2368 
2369         // create a container which will hold this layer's
2370         // docks (top, bottom, left, right)
2371         cont = new wxBoxSizer(wxVERTICAL);
2372 
2373 
2374         // find any top docks in this layer
2375         FindDocks(docks, wxAUI_DOCK_TOP, layer, -1, arr);
2376         if (!arr.IsEmpty())
2377         {
2378             for (row = 0, row_count = arr.GetCount(); row < row_count; ++row)
2379                 LayoutAddDock(cont, *arr.Item(row), uiparts, spacer_only);
2380         }
2381 
2382 
2383         // fill out the middle layer (which consists
2384         // of left docks, content area and right docks)
2385 
2386         middle = new wxBoxSizer(wxHORIZONTAL);
2387 
2388         // find any left docks in this layer
2389         FindDocks(docks, wxAUI_DOCK_LEFT, layer, -1, arr);
2390         if (!arr.IsEmpty())
2391         {
2392             for (row = 0, row_count = arr.GetCount(); row < row_count; ++row)
2393                 LayoutAddDock(middle, *arr.Item(row), uiparts, spacer_only);
2394         }
2395 
2396         // add content dock (or previous layer's sizer
2397         // to the middle
2398         if (!old_cont)
2399         {
2400             // find any center docks
2401             FindDocks(docks, wxAUI_DOCK_CENTER, -1, -1, arr);
2402             if (!arr.IsEmpty())
2403             {
2404                 for (row = 0,row_count = arr.GetCount(); row<row_count; ++row)
2405                    LayoutAddDock(middle, *arr.Item(row), uiparts, spacer_only);
2406             }
2407             else if (!m_hasMaximized)
2408             {
2409                 // there are no center docks, add a background area
2410                 wxSizerItem* sizer_item = middle->Add(1,1, 1, wxEXPAND);
2411                 wxAuiDockUIPart part;
2412                 part.type = wxAuiDockUIPart::typeBackground;
2413                 part.pane = NULL;
2414                 part.dock = NULL;
2415                 part.button = 0;
2416                 part.cont_sizer = middle;
2417                 part.sizer_item = sizer_item;
2418                 uiparts.Add(part);
2419             }
2420         }
2421         else
2422         {
2423             middle->Add(old_cont, 1, wxEXPAND);
2424         }
2425 
2426         // find any right docks in this layer
2427         FindDocks(docks, wxAUI_DOCK_RIGHT, layer, -1, arr);
2428         if (!arr.IsEmpty())
2429         {
2430             for (row = arr.GetCount()-1; row >= 0; --row)
2431                 LayoutAddDock(middle, *arr.Item(row), uiparts, spacer_only);
2432         }
2433 
2434         if (middle->GetChildren().GetCount() > 0)
2435             cont->Add(middle, 1, wxEXPAND);
2436              else
2437             delete middle;
2438 
2439 
2440 
2441         // find any bottom docks in this layer
2442         FindDocks(docks, wxAUI_DOCK_BOTTOM, layer, -1, arr);
2443         if (!arr.IsEmpty())
2444         {
2445             for (row = arr.GetCount()-1; row >= 0; --row)
2446                 LayoutAddDock(cont, *arr.Item(row), uiparts, spacer_only);
2447         }
2448 
2449     }
2450 
2451     if (!cont)
2452     {
2453         // no sizer available, because there are no docks,
2454         // therefore we will create a simple background area
2455         cont = new wxBoxSizer(wxVERTICAL);
2456         wxSizerItem* sizer_item = cont->Add(1,1, 1, wxEXPAND);
2457         wxAuiDockUIPart part;
2458         part.type = wxAuiDockUIPart::typeBackground;
2459         part.pane = NULL;
2460         part.dock = NULL;
2461         part.button = 0;
2462         part.cont_sizer = middle;
2463         part.sizer_item = sizer_item;
2464         uiparts.Add(part);
2465     }
2466 
2467     container->Add(cont, 1, wxEXPAND);
2468     return container;
2469 }
2470 
2471 
2472 // SetDockSizeConstraint() allows the dock constraints to be set.  For example,
2473 // specifying values of 0.5, 0.5 will mean that upon dock creation, a dock may
2474 // not be larger than half of the window's size
2475 
SetDockSizeConstraint(double width_pct,double height_pct)2476 void wxAuiManager::SetDockSizeConstraint(double width_pct, double height_pct)
2477 {
2478     m_dockConstraintX = wxMax(0.0, wxMin(1.0, width_pct));
2479     m_dockConstraintY = wxMax(0.0, wxMin(1.0, height_pct));
2480 }
2481 
GetDockSizeConstraint(double * width_pct,double * height_pct) const2482 void wxAuiManager::GetDockSizeConstraint(double* width_pct, double* height_pct) const
2483 {
2484     if (width_pct)
2485         *width_pct = m_dockConstraintX;
2486 
2487     if (height_pct)
2488         *height_pct = m_dockConstraintY;
2489 }
2490 
2491 
2492 
2493 // Update() updates the layout.  Whenever changes are made to
2494 // one or more panes, this function should be called.  It is the
2495 // external entry point for running the layout engine.
2496 
Update()2497 void wxAuiManager::Update()
2498 {
2499     m_hoverButton = NULL;
2500     m_actionPart = NULL;
2501 
2502     wxSizer* sizer;
2503     int i, pane_count = m_panes.GetCount();
2504 
2505 
2506     // destroy floating panes which have been
2507     // redocked or are becoming non-floating
2508     for (i = 0; i < pane_count; ++i)
2509     {
2510         wxAuiPaneInfo& p = m_panes.Item(i);
2511 
2512         if (!p.IsFloating() && p.frame)
2513         {
2514             // because the pane is no longer in a floating, we need to
2515             // reparent it to m_frame and destroy the floating frame
2516 
2517             // reduce flicker
2518             p.window->SetSize(1,1);
2519 
2520 
2521             // the following block is a workaround for bug #1531361
2522             // (see wxWidgets sourceforge page).  On wxGTK (only), when
2523             // a frame is shown/hidden, a move event unfortunately
2524             // also gets fired.  Because we may be dragging around
2525             // a pane, we need to cancel that action here to prevent
2526             // a spurious crash.
2527             if (m_actionWindow == p.frame)
2528             {
2529                 if (wxWindow::GetCapture() == m_frame)
2530                     m_frame->ReleaseMouse();
2531                 m_action = actionNone;
2532                 m_actionWindow = NULL;
2533             }
2534 
2535             // hide the frame
2536             if (p.frame->IsShown())
2537                 p.frame->Show(false);
2538 
2539             // reparent to m_frame and destroy the pane
2540             p.window->Reparent(m_frame);
2541             p.frame->SetSizer(NULL);
2542             p.frame->Destroy();
2543             p.frame = NULL;
2544         }
2545     }
2546 
2547     // Disable all updates until everything can be repainted at once at the end
2548     // when not using live resizing.
2549     //
2550     // Note that:
2551     //  - This is useless under Mac, where HasLiveResize() always returns false.
2552     //  - This is harmful under GTK, where it results in extra flicker (sic).
2553     //  - This results in display artefacts when using live resizing under MSW.
2554     //
2555     // So we only do this under MSW and only when not using live resizing.
2556 #ifdef __WXMSW__
2557     wxWindowUpdateLocker noUpdates;
2558     if (!HasLiveResize())
2559         noUpdates.Lock(m_frame);
2560 #endif // __WXMSW__
2561 
2562     // delete old sizer first
2563     m_frame->SetSizer(NULL);
2564 
2565     // create a layout for all of the panes
2566     sizer = LayoutAll(m_panes, m_docks, m_uiParts, false);
2567 
2568     // hide or show panes as necessary,
2569     // and float panes as necessary
2570     for (i = 0; i < pane_count; ++i)
2571     {
2572         wxAuiPaneInfo& p = m_panes.Item(i);
2573 
2574         if (p.IsFloating())
2575         {
2576             if (p.frame == NULL)
2577             {
2578                 // we need to create a frame for this
2579                 // pane, which has recently been floated
2580                 wxAuiFloatingFrame* frame = CreateFloatingFrame(m_frame, p);
2581 
2582                 // on MSW and Mac, if the owner desires transparent dragging, and
2583                 // the dragging is happening right now, then the floating
2584                 // window should have this style by default
2585                 if (m_action == actionDragFloatingPane &&
2586                     (m_flags & wxAUI_MGR_TRANSPARENT_DRAG))
2587                         frame->SetTransparent(150);
2588 
2589                 frame->SetPaneWindow(p);
2590                 p.frame = frame;
2591 
2592                 if (p.IsShown() && !frame->IsShown())
2593                     frame->Show();
2594             }
2595             else
2596             {
2597                 // frame already exists, make sure its position
2598                 // and size reflect the information in wxAuiPaneInfo
2599                 if ((p.frame->GetPosition() != p.floating_pos) || (p.frame->GetSize() != p.floating_size))
2600                 {
2601                     p.frame->SetSize(p.floating_pos.x, p.floating_pos.y,
2602                                      p.floating_size.x, p.floating_size.y,
2603                                      wxSIZE_USE_EXISTING);
2604                 /*
2605                     p.frame->SetSize(p.floating_pos.x, p.floating_pos.y,
2606                                      wxDefaultCoord, wxDefaultCoord,
2607                                      wxSIZE_USE_EXISTING);
2608                     //p.frame->Move(p.floating_pos.x, p.floating_pos.y);
2609                 */
2610                 }
2611 
2612                 // update whether the pane is resizable or not
2613                 long style = p.frame->GetWindowStyleFlag();
2614                 if (p.IsFixed())
2615                     style &= ~wxRESIZE_BORDER;
2616                 else
2617                     style |= wxRESIZE_BORDER;
2618                 p.frame->SetWindowStyleFlag(style);
2619 
2620                 if (p.frame->GetLabel() != p.caption)
2621                     p.frame->SetLabel(p.caption);
2622 
2623                 if (p.frame->IsShown() != p.IsShown())
2624                     p.frame->Show(p.IsShown());
2625             }
2626         }
2627         else
2628         {
2629             if (p.window->IsShown() != p.IsShown())
2630                 p.window->Show(p.IsShown());
2631         }
2632 
2633         // if "active panes" are no longer allowed, clear
2634         // any optionActive values from the pane states
2635         if ((m_flags & wxAUI_MGR_ALLOW_ACTIVE_PANE) == 0)
2636         {
2637             p.state &= ~wxAuiPaneInfo::optionActive;
2638         }
2639     }
2640 
2641 
2642     // keep track of the old window rectangles so we can
2643     // refresh those windows whose rect has changed
2644     wxAuiRectArray old_pane_rects;
2645     for (i = 0; i < pane_count; ++i)
2646     {
2647         wxRect r;
2648         wxAuiPaneInfo& p = m_panes.Item(i);
2649 
2650         if (p.window && p.IsShown() && p.IsDocked())
2651             r = p.rect;
2652 
2653         old_pane_rects.Add(r);
2654     }
2655 
2656 
2657 
2658 
2659     // apply the new sizer
2660     m_frame->SetSizer(sizer);
2661     m_frame->SetAutoLayout(false);
2662     DoFrameLayout();
2663 
2664 
2665 
2666     // now that the frame layout is done, we need to check
2667     // the new pane rectangles against the old rectangles that
2668     // we saved a few lines above here.  If the rectangles have
2669     // changed, the corresponding panes must also be updated
2670     for (i = 0; i < pane_count; ++i)
2671     {
2672         wxAuiPaneInfo& p = m_panes.Item(i);
2673         if (p.window && p.window->IsShown() && p.IsDocked())
2674         {
2675             if (p.rect != old_pane_rects[i])
2676             {
2677                 p.window->Refresh();
2678                 p.window->Update();
2679             }
2680         }
2681     }
2682 
2683 
2684     Repaint();
2685 
2686     // set frame's minimum size
2687 
2688 /*
2689     // N.B. More work needs to be done on frame minimum sizes;
2690     // this is some interesting code that imposes the minimum size,
2691     // but we may want to include a more flexible mechanism or
2692     // options for multiple minimum-size modes, e.g. strict or lax
2693     wxSize min_size = sizer->GetMinSize();
2694     wxSize frame_size = m_frame->GetSize();
2695     wxSize client_size = m_frame->GetClientSize();
2696 
2697     wxSize minframe_size(min_size.x+frame_size.x-client_size.x,
2698                          min_size.y+frame_size.y-client_size.y );
2699 
2700     m_frame->SetMinSize(minframe_size);
2701 
2702     if (frame_size.x < minframe_size.x ||
2703         frame_size.y < minframe_size.y)
2704             sizer->Fit(m_frame);
2705 */
2706 }
2707 
2708 
2709 // DoFrameLayout() is an internal function which invokes wxSizer::Layout
2710 // on the frame's main sizer, then measures all the various UI items
2711 // and updates their internal rectangles.  This should always be called
2712 // instead of calling m_frame->Layout() directly
2713 
DoFrameLayout()2714 void wxAuiManager::DoFrameLayout()
2715 {
2716     m_frame->Layout();
2717 
2718     int i, part_count;
2719     for (i = 0, part_count = m_uiParts.GetCount(); i < part_count; ++i)
2720     {
2721         wxAuiDockUIPart& part = m_uiParts.Item(i);
2722 
2723         // get the rectangle of the UI part
2724         // originally, this code looked like this:
2725         //    part.rect = wxRect(part.sizer_item->GetPosition(),
2726         //                       part.sizer_item->GetSize());
2727         // this worked quite well, with one exception: the mdi
2728         // client window had a "deferred" size variable
2729         // that returned the wrong size.  It looks like
2730         // a bug in wx, because the former size of the window
2731         // was being returned.  So, we will retrieve the part's
2732         // rectangle via other means
2733 
2734 
2735         part.rect = part.sizer_item->GetRect();
2736         int flag = part.sizer_item->GetFlag();
2737         int border = part.sizer_item->GetBorder();
2738         if (flag & wxTOP)
2739         {
2740             part.rect.y -= border;
2741             part.rect.height += border;
2742         }
2743         if (flag & wxLEFT)
2744         {
2745             part.rect.x -= border;
2746             part.rect.width += border;
2747         }
2748         if (flag & wxBOTTOM)
2749             part.rect.height += border;
2750         if (flag & wxRIGHT)
2751             part.rect.width += border;
2752 
2753 
2754         if (part.type == wxAuiDockUIPart::typeDock)
2755             part.dock->rect = part.rect;
2756         if (part.type == wxAuiDockUIPart::typePane)
2757             part.pane->rect = part.rect;
2758     }
2759 }
2760 
2761 // GetPanePart() looks up the pane the pane border UI part (or the regular
2762 // pane part if there is no border). This allows the caller to get the exact
2763 // rectangle of the pane in question, including decorations like
2764 // caption and border (if any).
2765 
GetPanePart(wxWindow * wnd)2766 wxAuiDockUIPart* wxAuiManager::GetPanePart(wxWindow* wnd)
2767 {
2768     int i, part_count;
2769     for (i = 0, part_count = m_uiParts.GetCount(); i < part_count; ++i)
2770     {
2771         wxAuiDockUIPart& part = m_uiParts.Item(i);
2772         if (part.type == wxAuiDockUIPart::typePaneBorder &&
2773             part.pane && part.pane->window == wnd)
2774                 return &part;
2775     }
2776     for (i = 0, part_count = m_uiParts.GetCount(); i < part_count; ++i)
2777     {
2778         wxAuiDockUIPart& part = m_uiParts.Item(i);
2779         if (part.type == wxAuiDockUIPart::typePane &&
2780             part.pane && part.pane->window == wnd)
2781                 return &part;
2782     }
2783     return NULL;
2784 }
2785 
2786 
2787 
2788 // GetDockPixelOffset() is an internal function which returns
2789 // a dock's offset in pixels from the left side of the window
2790 // (for horizontal docks) or from the top of the window (for
2791 // vertical docks).  This value is necessary for calculating
2792 // pixel-pane/toolbar offsets when they are dragged.
2793 
GetDockPixelOffset(wxAuiPaneInfo & test)2794 int wxAuiManager::GetDockPixelOffset(wxAuiPaneInfo& test)
2795 {
2796     // the only way to accurately calculate the dock's
2797     // offset is to actually run a theoretical layout
2798 
2799     int i, part_count, dock_count;
2800     wxAuiDockInfoArray docks;
2801     wxAuiPaneInfoArray panes;
2802     wxAuiDockUIPartArray uiparts;
2803     CopyDocksAndPanes(docks, panes, m_docks, m_panes);
2804     panes.Add(test);
2805 
2806     wxSizer* sizer = LayoutAll(panes, docks, uiparts, true);
2807     wxSize client_size = m_frame->GetClientSize();
2808     sizer->SetDimension(0, 0, client_size.x, client_size.y);
2809     sizer->Layout();
2810 
2811     for (i = 0, part_count = uiparts.GetCount(); i < part_count; ++i)
2812     {
2813         wxAuiDockUIPart& part = uiparts.Item(i);
2814         part.rect = wxRect(part.sizer_item->GetPosition(),
2815                            part.sizer_item->GetSize());
2816         if (part.type == wxAuiDockUIPart::typeDock)
2817             part.dock->rect = part.rect;
2818     }
2819 
2820     delete sizer;
2821 
2822     for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i)
2823     {
2824         wxAuiDockInfo& dock = docks.Item(i);
2825         if (test.dock_direction == dock.dock_direction &&
2826             test.dock_layer==dock.dock_layer && test.dock_row==dock.dock_row)
2827         {
2828             if (dock.IsVertical())
2829                 return dock.rect.y;
2830             else
2831                 return dock.rect.x;
2832         }
2833     }
2834 
2835     return 0;
2836 }
2837 
2838 
2839 
2840 // ProcessDockResult() is a utility function used by DoDrop() - it checks
2841 // if a dock operation is allowed, the new dock position is copied into
2842 // the target info.  If the operation was allowed, the function returns true.
2843 
ProcessDockResult(wxAuiPaneInfo & target,const wxAuiPaneInfo & new_pos)2844 bool wxAuiManager::ProcessDockResult(wxAuiPaneInfo& target,
2845                                      const wxAuiPaneInfo& new_pos)
2846 {
2847     bool allowed = false;
2848     switch (new_pos.dock_direction)
2849     {
2850         case wxAUI_DOCK_TOP:    allowed = target.IsTopDockable();    break;
2851         case wxAUI_DOCK_BOTTOM: allowed = target.IsBottomDockable(); break;
2852         case wxAUI_DOCK_LEFT:   allowed = target.IsLeftDockable();   break;
2853         case wxAUI_DOCK_RIGHT:  allowed = target.IsRightDockable();  break;
2854     }
2855 
2856     if (allowed)
2857     {
2858         target = new_pos;
2859         // Should this RTTI and function call be rewritten as
2860         // sending a new event type to allow other window types
2861         // to vary size based on dock location?
2862         wxAuiToolBar* toolbar = wxDynamicCast(target.window, wxAuiToolBar);
2863         if (toolbar)
2864         {
2865             wxSize hintSize = toolbar->GetHintSize(target.dock_direction);
2866             if (target.best_size != hintSize)
2867             {
2868                 target.best_size = hintSize;
2869                 target.floating_size = wxDefaultSize;
2870             }
2871         }
2872     }
2873 
2874     return allowed;
2875 }
2876 
2877 
2878 // DoDrop() is an important function.  It basically takes a mouse position,
2879 // and determines where the pane's new position would be.  If the pane is to be
2880 // dropped, it performs the drop operation using the specified dock and pane
2881 // arrays.  By specifying copied dock and pane arrays when calling, a "what-if"
2882 // scenario can be performed, giving precise coordinates for drop hints.
2883 // If, however, wxAuiManager:m_docks and wxAuiManager::m_panes are specified
2884 // as parameters, the changes will be made to the main state arrays
2885 
2886 const int auiInsertRowPixels = 10;
2887 const int auiNewRowPixels = 40;
2888 const int auiLayerInsertPixels = 40;
2889 const int auiLayerInsertOffset = 5;
2890 
DoDrop(wxAuiDockInfoArray & docks,wxAuiPaneInfoArray & panes,wxAuiPaneInfo & target,const wxPoint & pt,const wxPoint & offset)2891 bool wxAuiManager::DoDrop(wxAuiDockInfoArray& docks,
2892                           wxAuiPaneInfoArray& panes,
2893                           wxAuiPaneInfo& target,
2894                           const wxPoint& pt,
2895                           const wxPoint& offset)
2896 {
2897     wxSize cli_size = m_frame->GetClientSize();
2898 
2899     wxAuiPaneInfo drop = target;
2900 
2901 
2902     // The result should always be shown
2903     drop.Show();
2904 
2905 
2906     // Check to see if the pane has been dragged outside of the window
2907     // (or near to the outside of the window), if so, dock it along the edge
2908 
2909 
2910     wxSize layer_insert_offset;
2911     if (!drop.IsToolbar())
2912         layer_insert_offset = m_frame->FromDIP(wxSize(auiLayerInsertOffset, auiLayerInsertOffset));
2913 
2914     wxSize layer_insert_pixels = m_frame->FromDIP(wxSize(auiLayerInsertPixels, auiLayerInsertPixels));
2915 
2916     if (pt.x < layer_insert_offset.x &&
2917         pt.x > layer_insert_offset.x-layer_insert_pixels.x &&
2918         pt.y > 0 &&
2919         pt.y < cli_size.y)
2920     {
2921         int new_layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_LEFT),
2922                                 GetMaxLayer(docks, wxAUI_DOCK_BOTTOM)),
2923                                 GetMaxLayer(docks, wxAUI_DOCK_TOP)) + 1;
2924 
2925         if (drop.IsToolbar())
2926             new_layer = auiToolBarLayer;
2927 
2928         drop.Dock().Left().
2929              Layer(new_layer).
2930              Row(0).
2931              Position(pt.y - GetDockPixelOffset(drop) - offset.y);
2932         return ProcessDockResult(target, drop);
2933     }
2934     else if (pt.y < layer_insert_offset.y &&
2935              pt.y > layer_insert_offset.y-layer_insert_pixels.y &&
2936              pt.x > 0 &&
2937              pt.x < cli_size.x)
2938     {
2939         int new_layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_TOP),
2940                                 GetMaxLayer(docks, wxAUI_DOCK_LEFT)),
2941                                 GetMaxLayer(docks, wxAUI_DOCK_RIGHT)) + 1;
2942 
2943         if (drop.IsToolbar())
2944             new_layer = auiToolBarLayer;
2945 
2946         drop.Dock().Top().
2947              Layer(new_layer).
2948              Row(0).
2949              Position(pt.x - GetDockPixelOffset(drop) - offset.x);
2950         return ProcessDockResult(target, drop);
2951     }
2952     else if (pt.x >= cli_size.x - layer_insert_offset.x &&
2953              pt.x < cli_size.x - layer_insert_offset.x + layer_insert_pixels.x &&
2954              pt.y > 0 &&
2955              pt.y < cli_size.y)
2956     {
2957         int new_layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_RIGHT),
2958                                 GetMaxLayer(docks, wxAUI_DOCK_TOP)),
2959                                 GetMaxLayer(docks, wxAUI_DOCK_BOTTOM)) + 1;
2960 
2961         if (drop.IsToolbar())
2962             new_layer = auiToolBarLayer;
2963 
2964         drop.Dock().Right().
2965              Layer(new_layer).
2966              Row(0).
2967              Position(pt.y - GetDockPixelOffset(drop) - offset.y);
2968         return ProcessDockResult(target, drop);
2969     }
2970     else if (pt.y >= cli_size.y - layer_insert_offset.y &&
2971              pt.y < cli_size.y - layer_insert_offset.y + layer_insert_pixels.y &&
2972              pt.x > 0 &&
2973              pt.x < cli_size.x)
2974     {
2975         int new_layer = wxMax( wxMax( GetMaxLayer(docks, wxAUI_DOCK_BOTTOM),
2976                                       GetMaxLayer(docks, wxAUI_DOCK_LEFT)),
2977                                       GetMaxLayer(docks, wxAUI_DOCK_RIGHT)) + 1;
2978 
2979         if (drop.IsToolbar())
2980             new_layer = auiToolBarLayer;
2981 
2982         drop.Dock().Bottom().
2983              Layer(new_layer).
2984              Row(0).
2985              Position(pt.x - GetDockPixelOffset(drop) - offset.x);
2986         return ProcessDockResult(target, drop);
2987     }
2988 
2989 
2990     wxAuiDockUIPart* part = HitTest(pt.x, pt.y);
2991 
2992 
2993     if (drop.IsToolbar())
2994     {
2995         if (!part || !part->dock)
2996             return false;
2997 
2998         // calculate the offset from where the dock begins
2999         // to the point where the user dropped the pane
3000         int dock_drop_offset = 0;
3001         if (part->dock->IsHorizontal())
3002             dock_drop_offset = pt.x - part->dock->rect.x - offset.x;
3003         else
3004             dock_drop_offset = pt.y - part->dock->rect.y - offset.y;
3005 
3006 
3007         // toolbars may only be moved in and to fixed-pane docks,
3008         // otherwise we will try to float the pane.  Also, the pane
3009         // should float if being dragged over center pane windows
3010         if (!part->dock->fixed || part->dock->dock_direction == wxAUI_DOCK_CENTER ||
3011             pt.x >= cli_size.x || pt.x <= 0 || pt.y >= cli_size.y || pt.y <= 0)
3012         {
3013             if (m_lastRect.IsEmpty() || m_lastRect.Contains(pt.x, pt.y ))
3014             {
3015                 m_skipping = true;
3016             }
3017             else
3018             {
3019                 if ((m_flags & wxAUI_MGR_ALLOW_FLOATING) && drop.IsFloatable())
3020                 {
3021                     drop.Float();
3022                 }
3023 
3024                 m_skipping = false;
3025 
3026                 return ProcessDockResult(target, drop);
3027             }
3028 
3029             drop.Position(pt.x - GetDockPixelOffset(drop) - offset.x);
3030 
3031             return ProcessDockResult(target, drop);
3032         }
3033 
3034         m_skipping = false;
3035 
3036         m_lastRect = part->dock->rect;
3037         m_lastRect.Inflate( m_frame->FromDIP(wxSize(15, 15)) );
3038 
3039         drop.Dock().
3040              Direction(part->dock->dock_direction).
3041              Layer(part->dock->dock_layer).
3042              Row(part->dock->dock_row).
3043              Position(dock_drop_offset);
3044 
3045         if ((
3046             ((pt.y < part->dock->rect.y + 1) && part->dock->IsHorizontal()) ||
3047             ((pt.x < part->dock->rect.x + 1) && part->dock->IsVertical())
3048             ) && part->dock->panes.GetCount() > 1)
3049         {
3050             if ((part->dock->dock_direction == wxAUI_DOCK_TOP) ||
3051                 (part->dock->dock_direction == wxAUI_DOCK_LEFT))
3052             {
3053                 int row = drop.dock_row;
3054                 DoInsertDockRow(panes, part->dock->dock_direction,
3055                                 part->dock->dock_layer,
3056                                 part->dock->dock_row);
3057                 drop.dock_row = row;
3058             }
3059             else
3060             {
3061                 DoInsertDockRow(panes, part->dock->dock_direction,
3062                                 part->dock->dock_layer,
3063                                 part->dock->dock_row+1);
3064                 drop.dock_row = part->dock->dock_row+1;
3065             }
3066         }
3067 
3068         if ((
3069             ((pt.y > part->dock->rect.y + part->dock->rect.height - 2 ) && part->dock->IsHorizontal()) ||
3070             ((pt.x > part->dock->rect.x + part->dock->rect.width - 2 ) && part->dock->IsVertical())
3071             ) && part->dock->panes.GetCount() > 1)
3072         {
3073             if ((part->dock->dock_direction == wxAUI_DOCK_TOP) ||
3074                 (part->dock->dock_direction == wxAUI_DOCK_LEFT))
3075             {
3076                 DoInsertDockRow(panes, part->dock->dock_direction,
3077                                 part->dock->dock_layer,
3078                                 part->dock->dock_row+1);
3079                 drop.dock_row = part->dock->dock_row+1;
3080             }
3081             else
3082             {
3083                 int row = drop.dock_row;
3084                 DoInsertDockRow(panes, part->dock->dock_direction,
3085                                 part->dock->dock_layer,
3086                                 part->dock->dock_row);
3087                 drop.dock_row = row;
3088             }
3089         }
3090 
3091         return ProcessDockResult(target, drop);
3092     }
3093 
3094 
3095 
3096 
3097     if (!part)
3098         return false;
3099 
3100     if (part->type == wxAuiDockUIPart::typePaneBorder ||
3101         part->type == wxAuiDockUIPart::typeCaption ||
3102         part->type == wxAuiDockUIPart::typeGripper ||
3103         part->type == wxAuiDockUIPart::typePaneButton ||
3104         part->type == wxAuiDockUIPart::typePane ||
3105         part->type == wxAuiDockUIPart::typePaneSizer ||
3106         part->type == wxAuiDockUIPart::typeDockSizer ||
3107         part->type == wxAuiDockUIPart::typeBackground)
3108     {
3109         if (part->type == wxAuiDockUIPart::typeDockSizer)
3110         {
3111             if (part->dock->panes.GetCount() != 1)
3112                 return false;
3113             part = GetPanePart(part->dock->panes.Item(0)->window);
3114             if (!part)
3115                 return false;
3116         }
3117 
3118 
3119 
3120         // If a normal frame is being dragged over a toolbar, insert it
3121         // along the edge under the toolbar, but over all other panes.
3122         // (this could be done much better, but somehow factoring this
3123         // calculation with the one at the beginning of this function)
3124         if (part->dock && part->dock->toolbar)
3125         {
3126             int layer = 0;
3127 
3128             switch (part->dock->dock_direction)
3129             {
3130                 case wxAUI_DOCK_LEFT:
3131                     layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_LEFT),
3132                                       GetMaxLayer(docks, wxAUI_DOCK_BOTTOM)),
3133                                       GetMaxLayer(docks, wxAUI_DOCK_TOP));
3134                     break;
3135                 case wxAUI_DOCK_TOP:
3136                     layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_TOP),
3137                                       GetMaxLayer(docks, wxAUI_DOCK_LEFT)),
3138                                       GetMaxLayer(docks, wxAUI_DOCK_RIGHT));
3139                     break;
3140                 case wxAUI_DOCK_RIGHT:
3141                     layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_RIGHT),
3142                                       GetMaxLayer(docks, wxAUI_DOCK_TOP)),
3143                                       GetMaxLayer(docks, wxAUI_DOCK_BOTTOM));
3144                     break;
3145                 case wxAUI_DOCK_BOTTOM:
3146                     layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_BOTTOM),
3147                                       GetMaxLayer(docks, wxAUI_DOCK_LEFT)),
3148                                       GetMaxLayer(docks, wxAUI_DOCK_RIGHT));
3149                     break;
3150             }
3151 
3152             DoInsertDockRow(panes, part->dock->dock_direction,
3153                             layer, 0);
3154             drop.Dock().
3155                  Direction(part->dock->dock_direction).
3156                  Layer(layer).Row(0).Position(0);
3157             return ProcessDockResult(target, drop);
3158         }
3159 
3160 
3161         if (!part->pane)
3162             return false;
3163 
3164         part = GetPanePart(part->pane->window);
3165         if (!part)
3166             return false;
3167 
3168         bool insert_dock_row = false;
3169         int insert_row = part->pane->dock_row;
3170         int insert_dir = part->pane->dock_direction;
3171         int insert_layer = part->pane->dock_layer;
3172         wxSize insert_row_pixels = m_frame->FromDIP(wxSize(auiInsertRowPixels, auiInsertRowPixels));
3173 
3174         switch (part->pane->dock_direction)
3175         {
3176             case wxAUI_DOCK_TOP:
3177                 if (pt.y >= part->rect.y &&
3178                     pt.y < part->rect.y+insert_row_pixels.y)
3179                         insert_dock_row = true;
3180                 break;
3181             case wxAUI_DOCK_BOTTOM:
3182                 if (pt.y > part->rect.y+part->rect.height-insert_row_pixels.y &&
3183                     pt.y <= part->rect.y + part->rect.height)
3184                         insert_dock_row = true;
3185                 break;
3186             case wxAUI_DOCK_LEFT:
3187                 if (pt.x >= part->rect.x &&
3188                     pt.x < part->rect.x+insert_row_pixels.x)
3189                         insert_dock_row = true;
3190                 break;
3191             case wxAUI_DOCK_RIGHT:
3192                 if (pt.x > part->rect.x+part->rect.width-insert_row_pixels.x &&
3193                     pt.x <= part->rect.x+part->rect.width)
3194                         insert_dock_row = true;
3195                 break;
3196             case wxAUI_DOCK_CENTER:
3197             {
3198                 // "new row pixels" will be set to the default, but
3199                 // must never exceed 20% of the window size
3200                 wxSize new_row_pixels = m_frame->FromDIP(wxSize(auiNewRowPixels, auiNewRowPixels));
3201                 int new_row_pixels_x = new_row_pixels.x;
3202                 int new_row_pixels_y = new_row_pixels.y;
3203 
3204                 if (new_row_pixels_x > (part->rect.width*20)/100)
3205                     new_row_pixels_x = (part->rect.width*20)/100;
3206 
3207                 if (new_row_pixels_y > (part->rect.height*20)/100)
3208                     new_row_pixels_y = (part->rect.height*20)/100;
3209 
3210 
3211                 // determine if the mouse pointer is in a location that
3212                 // will cause a new row to be inserted.  The hot spot positions
3213                 // are along the borders of the center pane
3214 
3215                 insert_layer = 0;
3216                 insert_dock_row = true;
3217                 const wxRect& pr = part->rect;
3218                 if (pt.x >= pr.x && pt.x < pr.x + new_row_pixels_x)
3219                     insert_dir = wxAUI_DOCK_LEFT;
3220                 else if (pt.y >= pr.y && pt.y < pr.y + new_row_pixels_y)
3221                     insert_dir = wxAUI_DOCK_TOP;
3222                 else if (pt.x >= pr.x + pr.width - new_row_pixels_x &&
3223                          pt.x < pr.x + pr.width)
3224                     insert_dir = wxAUI_DOCK_RIGHT;
3225                 else if (pt.y >= pr.y+ pr.height - new_row_pixels_y &&
3226                          pt.y < pr.y + pr.height)
3227                     insert_dir = wxAUI_DOCK_BOTTOM;
3228                 else
3229                     return false;
3230 
3231                 insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1;
3232             }
3233         }
3234 
3235         if (insert_dock_row)
3236         {
3237             DoInsertDockRow(panes, insert_dir, insert_layer, insert_row);
3238             drop.Dock().Direction(insert_dir).
3239                         Layer(insert_layer).
3240                         Row(insert_row).
3241                         Position(0);
3242             return ProcessDockResult(target, drop);
3243         }
3244 
3245         // determine the mouse offset and the pane size, both in the
3246         // direction of the dock itself, and perpendicular to the dock
3247 
3248         int mouseOffset, size;
3249 
3250         if (part->orientation == wxVERTICAL)
3251         {
3252             mouseOffset = pt.y - part->rect.y;
3253             size = part->rect.GetHeight();
3254         }
3255         else
3256         {
3257             mouseOffset = pt.x - part->rect.x;
3258             size = part->rect.GetWidth();
3259         }
3260 
3261         int drop_position = part->pane->dock_pos;
3262 
3263         // if we are in the top/left part of the pane,
3264         // insert the pane before the pane being hovered over
3265         if (mouseOffset <= size/2)
3266         {
3267             drop_position = part->pane->dock_pos;
3268             DoInsertPane(panes,
3269                          part->pane->dock_direction,
3270                          part->pane->dock_layer,
3271                          part->pane->dock_row,
3272                          part->pane->dock_pos);
3273         }
3274 
3275         // if we are in the bottom/right part of the pane,
3276         // insert the pane before the pane being hovered over
3277         if (mouseOffset > size/2)
3278         {
3279             drop_position = part->pane->dock_pos+1;
3280             DoInsertPane(panes,
3281                          part->pane->dock_direction,
3282                          part->pane->dock_layer,
3283                          part->pane->dock_row,
3284                          part->pane->dock_pos+1);
3285         }
3286 
3287         drop.Dock().
3288              Direction(part->dock->dock_direction).
3289              Layer(part->dock->dock_layer).
3290              Row(part->dock->dock_row).
3291              Position(drop_position);
3292         return ProcessDockResult(target, drop);
3293     }
3294 
3295     return false;
3296 }
3297 
3298 
OnHintFadeTimer(wxTimerEvent & WXUNUSED (event))3299 void wxAuiManager::OnHintFadeTimer(wxTimerEvent& WXUNUSED(event))
3300 {
3301     if (!m_hintWnd || m_hintFadeAmt >= m_hintFadeMax)
3302     {
3303         m_hintFadeTimer.Stop();
3304         Unbind(wxEVT_TIMER, &wxAuiManager::OnHintFadeTimer, this,
3305                m_hintFadeTimer.GetId());
3306         return;
3307     }
3308 
3309     m_hintFadeAmt += 4;
3310     m_hintWnd->SetTransparent(m_hintFadeAmt);
3311 }
3312 
ShowHint(const wxRect & rect)3313 void wxAuiManager::ShowHint(const wxRect& rect)
3314 {
3315     if (m_hintWnd)
3316     {
3317         // if the hint rect is the same as last time, don't do anything
3318         if (m_lastHint == rect)
3319             return;
3320         m_lastHint = rect;
3321 
3322         m_hintFadeAmt = m_hintFadeMax;
3323 
3324         if ((m_flags & wxAUI_MGR_HINT_FADE)
3325             && !((wxDynamicCast(m_hintWnd, wxPseudoTransparentFrame)) &&
3326                  (m_flags & wxAUI_MGR_NO_VENETIAN_BLINDS_FADE))
3327             )
3328             m_hintFadeAmt = 0;
3329 
3330         m_hintWnd->SetSize(rect);
3331         m_hintWnd->SetTransparent(m_hintFadeAmt);
3332 
3333         if (!m_hintWnd->IsShown())
3334             m_hintWnd->Show();
3335 
3336         // if we are dragging a floating pane, set the focus
3337         // back to that floating pane (otherwise it becomes unfocused)
3338         if (m_action == actionDragFloatingPane && m_actionWindow)
3339             m_actionWindow->SetFocus();
3340 
3341         m_hintWnd->Raise();
3342 
3343 
3344         if (m_hintFadeAmt != m_hintFadeMax) //  Only fade if we need to
3345         {
3346             // start fade in timer
3347             m_hintFadeTimer.SetOwner(this);
3348             m_hintFadeTimer.Start(5);
3349             Bind(wxEVT_TIMER, &wxAuiManager::OnHintFadeTimer, this,
3350                  m_hintFadeTimer.GetId());
3351         }
3352     }
3353     else  // Not using a transparent hint window...
3354     {
3355         if (!(m_flags & wxAUI_MGR_RECTANGLE_HINT))
3356             return;
3357 
3358         if (m_lastHint != rect)
3359         {
3360             // remove the last hint rectangle
3361             m_lastHint = rect;
3362             m_frame->Refresh();
3363             m_frame->Update();
3364         }
3365 
3366         wxScreenDC screendc;
3367         wxRegion clip(1, 1, 10000, 10000);
3368 
3369         // clip all floating windows, so we don't draw over them
3370         int i, pane_count;
3371         for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i)
3372         {
3373             wxAuiPaneInfo& pane = m_panes.Item(i);
3374 
3375             if (pane.IsFloating() &&
3376                     pane.frame &&
3377                         pane.frame->IsShown())
3378             {
3379                 wxRect r = pane.frame->GetRect();
3380 #ifdef __WXGTK__
3381                 // wxGTK returns the client size, not the whole frame size
3382                 r.width += pane.frame->FromDIP(15);
3383                 r.height += pane.frame->FromDIP(35);
3384                 r.Inflate(pane.frame->FromDIP(wxSize(5, 5)));
3385 #endif
3386 
3387                 clip.Subtract(r);
3388             }
3389         }
3390 
3391         // As we can only hide the hint by redrawing the managed window, we
3392         // need to clip the region to the managed window too or we get
3393         // nasty redrawn problems.
3394         clip.Intersect(m_frame->GetRect());
3395 
3396         screendc.SetDeviceClippingRegion(clip);
3397 
3398         wxBitmap stipple = wxPaneCreateStippleBitmap();
3399         wxBrush brush(stipple);
3400         screendc.SetBrush(brush);
3401         screendc.SetPen(*wxTRANSPARENT_PEN);
3402 
3403         screendc.DrawRectangle(rect.x, rect.y, m_frame->FromDIP(5), rect.height);
3404         screendc.DrawRectangle(rect.x + m_frame->FromDIP(5), rect.y, rect.width - m_frame->FromDIP(10), m_frame->FromDIP(5));
3405         screendc.DrawRectangle(rect.x + rect.width - m_frame->FromDIP(5), rect.y, m_frame->FromDIP(5), rect.height);
3406         screendc.DrawRectangle(rect.x + m_frame->FromDIP(5), rect.y + rect.height - m_frame->FromDIP(5), rect.width - m_frame->FromDIP(10), m_frame->FromDIP(5));
3407     }
3408 }
3409 
HideHint()3410 void wxAuiManager::HideHint()
3411 {
3412     // hides a transparent window hint, if there is one
3413     if (m_hintWnd)
3414     {
3415         if (m_hintWnd->IsShown())
3416             m_hintWnd->Show(false);
3417         m_hintWnd->SetTransparent(0);
3418         m_hintFadeTimer.Stop();
3419         // In case this is called while a hint fade is going, we need to
3420         // disconnect the event handler.
3421         Unbind(wxEVT_TIMER, &wxAuiManager::OnHintFadeTimer, this,
3422                m_hintFadeTimer.GetId());
3423         m_lastHint = wxRect();
3424         return;
3425     }
3426 
3427     // hides a painted hint by redrawing the frame window
3428     if (!m_lastHint.IsEmpty())
3429     {
3430         m_frame->Refresh();
3431         m_frame->Update();
3432         m_lastHint = wxRect();
3433     }
3434 }
3435 
OnHintActivate(wxActivateEvent & WXUNUSED (event))3436 void wxAuiManager::OnHintActivate(wxActivateEvent& WXUNUSED(event))
3437 {
3438     // Do nothing so this event isn't handled in the base handlers.
3439 
3440     // Letting the hint window activate without this handler can lead to
3441     // weird behaviour on Mac where the menu is switched out to the top
3442     // window's menu in MDI applications when it shouldn't be. So since
3443     // we don't want user interaction with the hint window anyway, we just
3444     // prevent it from activating here.
3445 }
3446 
3447 
3448 
StartPaneDrag(wxWindow * pane_window,const wxPoint & offset)3449 void wxAuiManager::StartPaneDrag(wxWindow* pane_window,
3450                                  const wxPoint& offset)
3451 {
3452     wxAuiPaneInfo& pane = GetPane(pane_window);
3453     if (!pane.IsOk())
3454         return;
3455 
3456     if (pane.IsToolbar())
3457     {
3458         m_action = actionDragToolbarPane;
3459     }
3460     else
3461     {
3462         m_action = actionDragFloatingPane;
3463     }
3464 
3465     m_actionWindow = pane_window;
3466     m_actionOffset = offset;
3467     m_frame->CaptureMouse();
3468 
3469     if (pane.frame)
3470     {
3471         wxRect window_rect = pane.frame->GetRect();
3472         wxRect client_rect = pane.frame->GetClientRect();
3473         wxPoint client_pt = pane.frame->ClientToScreen(client_rect.GetTopLeft());
3474         wxPoint origin_pt = client_pt - window_rect.GetTopLeft();
3475         m_actionOffset += origin_pt;
3476     }
3477 }
3478 
3479 
3480 // CalculateHintRect() calculates the drop hint rectangle.  The method
3481 // first calls DoDrop() to determine the exact position the pane would
3482 // be at were if dropped.  If the pane would indeed become docked at the
3483 // specified drop point, the rectangle hint will be returned in
3484 // screen coordinates.  Otherwise, an empty rectangle is returned.
3485 // |pane_window| is the window pointer of the pane being dragged, |pt| is
3486 // the mouse position, in client coordinates.  |offset| describes the offset
3487 // that the mouse is from the upper-left corner of the item being dragged
3488 
CalculateHintRect(wxWindow * pane_window,const wxPoint & pt,const wxPoint & offset)3489 wxRect wxAuiManager::CalculateHintRect(wxWindow* pane_window,
3490                                        const wxPoint& pt,
3491                                        const wxPoint& offset)
3492 {
3493     wxRect rect;
3494 
3495     // we need to paint a hint rectangle; to find out the exact hint rectangle,
3496     // we will create a new temporary layout and then measure the resulting
3497     // rectangle; we will create a copy of the docking structures (m_dock)
3498     // so that we don't modify the real thing on screen
3499 
3500     int i, pane_count, part_count;
3501     wxAuiDockInfoArray docks;
3502     wxAuiPaneInfoArray panes;
3503     wxAuiDockUIPartArray uiparts;
3504     wxAuiPaneInfo hint = GetPane(pane_window);
3505     hint.name = wxT("__HINT__");
3506     hint.PaneBorder(true);
3507     hint.Show();
3508 
3509     if (!hint.IsOk())
3510         return rect;
3511 
3512     CopyDocksAndPanes(docks, panes, m_docks, m_panes);
3513 
3514     // remove any pane already there which bears the same window;
3515     // this happens when you are moving a pane around in a dock
3516     for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i)
3517     {
3518         if (panes.Item(i).window == pane_window)
3519         {
3520             RemovePaneFromDocks(docks, panes.Item(i));
3521             panes.RemoveAt(i);
3522             break;
3523         }
3524     }
3525 
3526     // find out where the new pane would be
3527     if (!DoDrop(docks, panes, hint, pt, offset))
3528     {
3529         return rect;
3530     }
3531 
3532     panes.Add(hint);
3533 
3534     wxSizer* sizer = LayoutAll(panes, docks, uiparts, true);
3535     wxSize client_size = m_frame->GetClientSize();
3536     sizer->SetDimension(0, 0, client_size.x, client_size.y);
3537     sizer->Layout();
3538 
3539     for (i = 0, part_count = uiparts.GetCount();
3540          i < part_count; ++i)
3541     {
3542         wxAuiDockUIPart& part = uiparts.Item(i);
3543 
3544         if (part.type == wxAuiDockUIPart::typePaneBorder &&
3545             part.pane && part.pane->name == wxT("__HINT__"))
3546         {
3547             rect = wxRect(part.sizer_item->GetPosition(),
3548                           part.sizer_item->GetSize());
3549             break;
3550         }
3551     }
3552 
3553     delete sizer;
3554 
3555     if (rect.IsEmpty())
3556     {
3557         return rect;
3558     }
3559 
3560     // actually show the hint rectangle on the screen
3561     m_frame->ClientToScreen(&rect.x, &rect.y);
3562 
3563     if ( m_frame->GetLayoutDirection() == wxLayout_RightToLeft )
3564     {
3565         // Mirror rectangle in RTL mode
3566         rect.x -= rect.GetWidth();
3567     }
3568 
3569     return rect;
3570 }
3571 
3572 // DrawHintRect() calculates the hint rectangle by calling
3573 // CalculateHintRect().  If there is a rectangle, it shows it
3574 // by calling ShowHint(), otherwise it hides any hint
3575 // rectangle currently shown
DrawHintRect(wxWindow * pane_window,const wxPoint & pt,const wxPoint & offset)3576 void wxAuiManager::DrawHintRect(wxWindow* pane_window,
3577                                 const wxPoint& pt,
3578                                 const wxPoint& offset)
3579 {
3580     wxRect rect = CalculateHintRect(pane_window, pt, offset);
3581 
3582     if (rect.IsEmpty())
3583     {
3584         HideHint();
3585     }
3586     else
3587     {
3588         ShowHint(rect);
3589     }
3590 }
3591 
OnFloatingPaneMoveStart(wxWindow * wnd)3592 void wxAuiManager::OnFloatingPaneMoveStart(wxWindow* wnd)
3593 {
3594     // try to find the pane
3595     wxAuiPaneInfo& pane = GetPane(wnd);
3596     wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
3597 
3598     if(!pane.frame)
3599         return;
3600 
3601     if (m_flags & wxAUI_MGR_TRANSPARENT_DRAG)
3602         pane.frame->SetTransparent(150);
3603 }
3604 
OnFloatingPaneMoving(wxWindow * wnd,wxDirection dir)3605 void wxAuiManager::OnFloatingPaneMoving(wxWindow* wnd, wxDirection dir)
3606 {
3607     // try to find the pane
3608     wxAuiPaneInfo& pane = GetPane(wnd);
3609     wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
3610 
3611     if(!pane.frame)
3612         return;
3613 
3614     wxPoint pt = ::wxGetMousePosition();
3615 
3616 #if 0
3617     // Adapt pt to direction
3618     if (dir == wxNORTH)
3619     {
3620         // move to pane's upper border
3621         wxPoint pos( 0,0 );
3622         pos = wnd->ClientToScreen( pos );
3623         pt.y = pos.y;
3624         // and some more pixels for the title bar
3625         pt.y -= wnd->FromDIP(5);
3626     }
3627     else if (dir == wxWEST)
3628     {
3629         // move to pane's left border
3630         wxPoint pos( 0,0 );
3631         pos = wnd->ClientToScreen( pos );
3632         pt.x = pos.x;
3633     }
3634     else if (dir == wxEAST)
3635     {
3636         // move to pane's right border
3637         wxPoint pos( wnd->GetSize().x, 0 );
3638         pos = wnd->ClientToScreen( pos );
3639         pt.x = pos.x;
3640     }
3641     else if (dir == wxSOUTH)
3642     {
3643         // move to pane's bottom border
3644         wxPoint pos( 0, wnd->GetSize().y );
3645         pos = wnd->ClientToScreen( pos );
3646         pt.y = pos.y;
3647     }
3648 #else
3649     wxUnusedVar(dir);
3650 #endif
3651 
3652     wxPoint client_pt = m_frame->ScreenToClient(pt);
3653 
3654     // calculate the offset from the upper left-hand corner
3655     // of the frame to the mouse pointer
3656     wxPoint frame_pos = pane.frame->GetPosition();
3657     wxPoint action_offset(pt.x-frame_pos.x, pt.y-frame_pos.y);
3658 
3659     // no hint for toolbar floating windows
3660     if (pane.IsToolbar() && m_action == actionDragFloatingPane)
3661     {
3662         wxAuiDockInfoArray docks;
3663         wxAuiPaneInfoArray panes;
3664         wxAuiDockUIPartArray uiparts;
3665         wxAuiPaneInfo hint = pane;
3666 
3667         CopyDocksAndPanes(docks, panes, m_docks, m_panes);
3668 
3669         // find out where the new pane would be
3670         if (!DoDrop(docks, panes, hint, client_pt))
3671             return;
3672         if (hint.IsFloating())
3673             return;
3674 
3675         pane = hint;
3676         m_action = actionDragToolbarPane;
3677         m_actionWindow = pane.window;
3678 
3679         Update();
3680 
3681         return;
3682     }
3683 
3684 
3685     // if a key modifier is pressed while dragging the frame,
3686     // don't dock the window
3687     if (!CanDockPanel(pane))
3688     {
3689         HideHint();
3690         return;
3691     }
3692 
3693 
3694     DrawHintRect(wnd, client_pt, action_offset);
3695 
3696 #ifdef __WXGTK__
3697     // this cleans up some screen artifacts that are caused on GTK because
3698     // we aren't getting the exact size of the window (see comment
3699     // in DrawHintRect)
3700     //Refresh();
3701 #endif
3702 
3703 
3704     // reduces flicker
3705     m_frame->Update();
3706 }
3707 
OnFloatingPaneMoved(wxWindow * wnd,wxDirection dir)3708 void wxAuiManager::OnFloatingPaneMoved(wxWindow* wnd, wxDirection dir)
3709 {
3710     // try to find the pane
3711     wxAuiPaneInfo& pane = GetPane(wnd);
3712     wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
3713 
3714     if(!pane.frame)
3715         return;
3716 
3717     wxPoint pt = ::wxGetMousePosition();
3718 
3719 #if 0
3720     // Adapt pt to direction
3721     if (dir == wxNORTH)
3722     {
3723         // move to pane's upper border
3724         wxPoint pos( 0,0 );
3725         pos = wnd->ClientToScreen( pos );
3726         pt.y = pos.y;
3727         // and some more pixels for the title bar
3728         pt.y -= wnd->FromDIP(10);
3729     }
3730     else if (dir == wxWEST)
3731     {
3732         // move to pane's left border
3733         wxPoint pos( 0,0 );
3734         pos = wnd->ClientToScreen( pos );
3735         pt.x = pos.x;
3736     }
3737     else if (dir == wxEAST)
3738     {
3739         // move to pane's right border
3740         wxPoint pos( wnd->GetSize().x, 0 );
3741         pos = wnd->ClientToScreen( pos );
3742         pt.x = pos.x;
3743     }
3744     else if (dir == wxSOUTH)
3745     {
3746         // move to pane's bottom border
3747         wxPoint pos( 0, wnd->GetSize().y );
3748         pos = wnd->ClientToScreen( pos );
3749         pt.y = pos.y;
3750     }
3751 #else
3752     wxUnusedVar(dir);
3753 #endif
3754 
3755     wxPoint client_pt = m_frame->ScreenToClient(pt);
3756 
3757     // calculate the offset from the upper left-hand corner
3758     // of the frame to the mouse pointer
3759     wxPoint frame_pos = pane.frame->GetPosition();
3760     wxPoint action_offset(pt.x-frame_pos.x, pt.y-frame_pos.y);
3761 
3762     // if a key modifier is pressed while dragging the frame,
3763     // don't dock the window
3764     if (CanDockPanel(pane))
3765     {
3766         // do the drop calculation
3767         DoDrop(m_docks, m_panes, pane, client_pt, action_offset);
3768     }
3769 
3770     // if the pane is still floating, update its floating
3771     // position (that we store)
3772     if (pane.IsFloating())
3773     {
3774         pane.floating_pos = pane.frame->GetPosition();
3775 
3776         if (m_flags & wxAUI_MGR_TRANSPARENT_DRAG)
3777             pane.frame->SetTransparent(255);
3778     }
3779     else if (m_hasMaximized)
3780     {
3781         RestoreMaximizedPane();
3782     }
3783 
3784     Update();
3785 
3786     HideHint();
3787 }
3788 
OnFloatingPaneResized(wxWindow * wnd,const wxRect & rect)3789 void wxAuiManager::OnFloatingPaneResized(wxWindow* wnd, const wxRect& rect)
3790 {
3791     // try to find the pane
3792     wxAuiPaneInfo& pane = GetPane(wnd);
3793     wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
3794 
3795     pane.FloatingSize(rect.GetWidth(), rect.GetHeight());
3796 
3797     // the top-left position may change as well as the size
3798     pane.FloatingPosition(rect.x, rect.y);
3799 }
3800 
3801 
OnFloatingPaneClosed(wxWindow * wnd,wxCloseEvent & evt)3802 void wxAuiManager::OnFloatingPaneClosed(wxWindow* wnd, wxCloseEvent& evt)
3803 {
3804     // try to find the pane
3805     wxAuiPaneInfo& pane = GetPane(wnd);
3806     wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
3807 
3808 
3809     // fire pane close event
3810     wxAuiManagerEvent e(wxEVT_AUI_PANE_CLOSE);
3811     e.SetPane(&pane);
3812     e.SetCanVeto(evt.CanVeto());
3813     ProcessMgrEvent(e);
3814 
3815     if (e.GetVeto())
3816     {
3817         evt.Veto();
3818         return;
3819     }
3820     else
3821     {
3822         // close the pane, but check that it
3823         // still exists in our pane array first
3824         // (the event handler above might have removed it)
3825 
3826         wxAuiPaneInfo& check = GetPane(wnd);
3827         if (check.IsOk())
3828         {
3829             ClosePane(pane);
3830         }
3831     }
3832 }
3833 
3834 
3835 
OnFloatingPaneActivated(wxWindow * wnd)3836 void wxAuiManager::OnFloatingPaneActivated(wxWindow* wnd)
3837 {
3838     if ((GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE) && GetPane(wnd).IsOk())
3839     {
3840         SetActivePane(wnd);
3841         Repaint();
3842     }
3843 }
3844 
3845 // OnRender() draws all of the pane captions, sashes,
3846 // backgrounds, captions, grippers, pane borders and buttons.
3847 // It renders the entire user interface.
3848 
OnRender(wxAuiManagerEvent & evt)3849 void wxAuiManager::OnRender(wxAuiManagerEvent& evt)
3850 {
3851     // if the frame is about to be deleted, don't bother
3852     if (!m_frame || wxPendingDelete.Member(m_frame))
3853         return;
3854 
3855     wxDC* dc = evt.GetDC();
3856 
3857 #ifdef __WXMAC__
3858     dc->Clear() ;
3859 #endif
3860     int i, part_count;
3861     for (i = 0, part_count = m_uiParts.GetCount();
3862          i < part_count; ++i)
3863     {
3864         wxAuiDockUIPart& part = m_uiParts.Item(i);
3865 
3866         // don't draw hidden pane items or items that aren't windows
3867         if (part.sizer_item &&
3868                 ((!part.sizer_item->IsWindow() &&
3869                   !part.sizer_item->IsSpacer() &&
3870                   !part.sizer_item->IsSizer()) ||
3871                   !part.sizer_item->IsShown() ||
3872                    part.rect.IsEmpty()))
3873             continue;
3874 
3875         switch (part.type)
3876         {
3877             case wxAuiDockUIPart::typeDockSizer:
3878             case wxAuiDockUIPart::typePaneSizer:
3879                 m_art->DrawSash(*dc, m_frame, part.orientation, part.rect);
3880                 break;
3881             case wxAuiDockUIPart::typeBackground:
3882                 m_art->DrawBackground(*dc, m_frame, part.orientation, part.rect);
3883                 break;
3884             case wxAuiDockUIPart::typeCaption:
3885                 m_art->DrawCaption(*dc, m_frame, part.pane->caption, part.rect, *part.pane);
3886                 break;
3887             case wxAuiDockUIPart::typeGripper:
3888                 m_art->DrawGripper(*dc, m_frame, part.rect, *part.pane);
3889                 break;
3890             case wxAuiDockUIPart::typePaneBorder:
3891                 m_art->DrawBorder(*dc, m_frame, part.rect, *part.pane);
3892                 break;
3893             case wxAuiDockUIPart::typePaneButton:
3894                 m_art->DrawPaneButton(*dc, m_frame, part.button,
3895                         wxAUI_BUTTON_STATE_NORMAL, part.rect, *part.pane);
3896                 break;
3897         }
3898     }
3899 }
3900 
3901 
3902 // Render() fire a render event, which is normally handled by
3903 // wxAuiManager::OnRender().  This allows the render function to
3904 // be overridden via the render event.  This can be useful for paintin
3905 // custom graphics in the main window. Default behaviour can be
3906 // invoked in the overridden function by calling OnRender()
3907 
Render(wxDC * dc)3908 void wxAuiManager::Render(wxDC* dc)
3909 {
3910     wxAuiManagerEvent e(wxEVT_AUI_RENDER);
3911     e.SetManager(this);
3912     e.SetDC(dc);
3913     ProcessMgrEvent(e);
3914 }
3915 
Repaint(wxDC * dc)3916 void wxAuiManager::Repaint(wxDC* dc)
3917 {
3918 #ifdef __WXMAC__
3919     if ( dc == NULL )
3920     {
3921         m_frame->Refresh() ;
3922         m_frame->Update() ;
3923         return ;
3924     }
3925 #endif
3926     int w, h;
3927     m_frame->GetClientSize(&w, &h);
3928 
3929     // figure out which dc to use; if one
3930     // has been specified, use it, otherwise
3931     // make a client dc
3932     wxClientDC* client_dc = NULL;
3933     if (!dc)
3934     {
3935         client_dc = new wxClientDC(m_frame);
3936         dc = client_dc;
3937     }
3938 
3939     // if the frame has a toolbar, the client area
3940     // origin will not be (0,0).
3941     wxPoint pt = m_frame->GetClientAreaOrigin();
3942     if (pt.x != 0 || pt.y != 0)
3943         dc->SetDeviceOrigin(pt.x, pt.y);
3944 
3945     // render all the items
3946     Render(dc);
3947 
3948     // if we created a client_dc, delete it
3949     if (client_dc)
3950         delete client_dc;
3951 }
3952 
OnDestroy(wxWindowDestroyEvent & event)3953 void wxAuiManager::OnDestroy(wxWindowDestroyEvent& event)
3954 {
3955     if ( event.GetEventObject() == m_frame )
3956     {
3957         wxWindow* const frame = m_frame;
3958 
3959         UnInit();
3960 
3961         // Just calling Skip() would be insufficient in this case, as by
3962         // removing the event handler from the event handlers chain in UnInit()
3963         // we'd still prevent the frame from getting this event, so we need to
3964         // forward it to it manually. Note that this must be done after calling
3965         // UnInit() to prevent infinite recursion.
3966         if ( frame )
3967             frame->ProcessWindowEventLocally(event);
3968     }
3969     else
3970     {
3971         event.Skip();
3972     }
3973 }
3974 
OnPaint(wxPaintEvent & WXUNUSED (event))3975 void wxAuiManager::OnPaint(wxPaintEvent& WXUNUSED(event))
3976 {
3977     wxPaintDC dc(m_frame);
3978 
3979     dc.SetBackground(GetArtProvider()->GetColor(wxAUI_DOCKART_BACKGROUND_COLOUR));
3980     dc.Clear();
3981 
3982     Repaint(&dc);
3983 }
3984 
OnEraseBackground(wxEraseEvent & event)3985 void wxAuiManager::OnEraseBackground(wxEraseEvent& event)
3986 {
3987 #ifdef __WXMAC__
3988     event.Skip() ;
3989 #else
3990     wxUnusedVar(event);
3991 #endif
3992 }
3993 
OnSize(wxSizeEvent & event)3994 void wxAuiManager::OnSize(wxSizeEvent& event)
3995 {
3996     if (m_frame)
3997     {
3998         DoFrameLayout();
3999         Repaint();
4000 
4001 #if wxUSE_MDI
4002         if (wxDynamicCast(m_frame, wxMDIParentFrame))
4003         {
4004             // for MDI parent frames, this event must not
4005             // be "skipped".  In other words, the parent frame
4006             // must not be allowed to resize the client window
4007             // after we are finished processing sizing changes
4008             return;
4009         }
4010 #endif
4011     }
4012     event.Skip();
4013 }
4014 
OnFindManager(wxAuiManagerEvent & evt)4015 void wxAuiManager::OnFindManager(wxAuiManagerEvent& evt)
4016 {
4017     // get the window we are managing, if none, return NULL
4018     wxWindow* window = GetManagedWindow();
4019     if (!window)
4020     {
4021         evt.SetManager(NULL);
4022         return;
4023     }
4024 
4025     // if we are managing a child frame, get the 'real' manager
4026     if (wxDynamicCast(window, wxAuiFloatingFrame))
4027     {
4028         wxAuiFloatingFrame* float_frame = static_cast<wxAuiFloatingFrame*>(window);
4029         evt.SetManager(float_frame->GetOwnerManager());
4030         return;
4031     }
4032 
4033     // return pointer to ourself
4034     evt.SetManager(this);
4035 }
4036 
OnSetCursor(wxSetCursorEvent & event)4037 void wxAuiManager::OnSetCursor(wxSetCursorEvent& event)
4038 {
4039     // determine cursor
4040     wxAuiDockUIPart* part = HitTest(event.GetX(), event.GetY());
4041     wxCursor cursor;
4042 
4043     if (part)
4044     {
4045         if (part->type == wxAuiDockUIPart::typeDockSizer ||
4046             part->type == wxAuiDockUIPart::typePaneSizer)
4047         {
4048             // a dock may not be resized if it has a single
4049             // pane which is not resizable
4050             if (part->type == wxAuiDockUIPart::typeDockSizer && part->dock &&
4051                 part->dock->panes.GetCount() == 1 &&
4052                 part->dock->panes.Item(0)->IsFixed())
4053                     return;
4054 
4055             // panes that may not be resized do not get a sizing cursor
4056             if (part->pane && part->pane->IsFixed())
4057                 return;
4058 
4059             if (part->orientation == wxVERTICAL)
4060                 cursor = wxCursor(wxCURSOR_SIZEWE);
4061             else
4062                 cursor = wxCursor(wxCURSOR_SIZENS);
4063         }
4064         else if (part->type == wxAuiDockUIPart::typeGripper)
4065         {
4066             cursor = wxCursor(wxCURSOR_SIZING);
4067         }
4068     }
4069 
4070     event.SetCursor(cursor);
4071 }
4072 
4073 
4074 
UpdateButtonOnScreen(wxAuiDockUIPart * button_ui_part,const wxMouseEvent & event)4075 void wxAuiManager::UpdateButtonOnScreen(wxAuiDockUIPart* button_ui_part,
4076                                         const wxMouseEvent& event)
4077 {
4078     wxAuiDockUIPart* hit_test = HitTest(event.GetX(), event.GetY());
4079     if (!hit_test || !button_ui_part)
4080         return;
4081 
4082     int state = wxAUI_BUTTON_STATE_NORMAL;
4083 
4084     if (hit_test == button_ui_part)
4085     {
4086         if (event.LeftDown())
4087             state = wxAUI_BUTTON_STATE_PRESSED;
4088         else
4089             state = wxAUI_BUTTON_STATE_HOVER;
4090     }
4091     else
4092     {
4093         if (event.LeftDown())
4094             state = wxAUI_BUTTON_STATE_HOVER;
4095     }
4096 
4097     // now repaint the button with hover state
4098     wxClientDC cdc(m_frame);
4099 
4100     // if the frame has a toolbar, the client area
4101     // origin will not be (0,0).
4102     wxPoint pt = m_frame->GetClientAreaOrigin();
4103     if (pt.x != 0 || pt.y != 0)
4104         cdc.SetDeviceOrigin(pt.x, pt.y);
4105 
4106     if (hit_test->pane)
4107     {
4108         m_art->DrawPaneButton(cdc, m_frame,
4109                   button_ui_part->button,
4110                   state,
4111                   button_ui_part->rect,
4112                   *hit_test->pane);
4113     }
4114 }
4115 
OnLeftDown(wxMouseEvent & event)4116 void wxAuiManager::OnLeftDown(wxMouseEvent& event)
4117 {
4118     m_currentDragItem = -1;
4119 
4120     wxAuiDockUIPart* part = HitTest(event.GetX(), event.GetY());
4121     if (part)
4122     {
4123         if (part->type == wxAuiDockUIPart::typeDockSizer ||
4124             part->type == wxAuiDockUIPart::typePaneSizer)
4125         {
4126             // Removing this restriction so that a centre pane can be resized
4127             //if (part->dock && part->dock->dock_direction == wxAUI_DOCK_CENTER)
4128             //    return;
4129 
4130             // a dock may not be resized if it has a single
4131             // pane which is not resizable
4132             if (part->type == wxAuiDockUIPart::typeDockSizer && part->dock &&
4133                 part->dock->panes.GetCount() == 1 &&
4134                 part->dock->panes.Item(0)->IsFixed())
4135                     return;
4136 
4137             // panes that may not be resized should be ignored here
4138             if (part->pane && part->pane->IsFixed())
4139                 return;
4140 
4141             m_action = actionResize;
4142             m_actionPart = part;
4143             m_actionHintRect = wxRect();
4144             m_actionStart = wxPoint(event.m_x, event.m_y);
4145             m_actionOffset = wxPoint(event.m_x - part->rect.x,
4146                                       event.m_y - part->rect.y);
4147             m_frame->CaptureMouse();
4148         }
4149         else if (part->type == wxAuiDockUIPart::typePaneButton)
4150         {
4151             m_action = actionClickButton;
4152             m_actionPart = part;
4153             m_actionStart = wxPoint(event.m_x, event.m_y);
4154             m_frame->CaptureMouse();
4155 
4156             UpdateButtonOnScreen(part, event);
4157         }
4158         else if (part->type == wxAuiDockUIPart::typeCaption ||
4159                   part->type == wxAuiDockUIPart::typeGripper)
4160         {
4161             // if we are managing a wxAuiFloatingFrame window, then
4162             // we are an embedded wxAuiManager inside the wxAuiFloatingFrame.
4163             // We want to initiate a toolbar drag in our owner manager
4164             wxWindow* managed_wnd = GetManagedWindow();
4165 
4166             if (part->pane &&
4167                 part->pane->window &&
4168                 managed_wnd &&
4169                 wxDynamicCast(managed_wnd, wxAuiFloatingFrame))
4170             {
4171                 wxAuiFloatingFrame* floating_frame = (wxAuiFloatingFrame*)managed_wnd;
4172                 wxAuiManager* owner_mgr = floating_frame->GetOwnerManager();
4173                 owner_mgr->StartPaneDrag(part->pane->window,
4174                                              wxPoint(event.m_x - part->rect.x,
4175                                                      event.m_y - part->rect.y));
4176                 return;
4177             }
4178 
4179 
4180 
4181             if (GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE)
4182             {
4183                 // set the caption as active
4184                 SetActivePane(part->pane->window);
4185                 Repaint();
4186             }
4187 
4188             if (part->dock && part->dock->dock_direction == wxAUI_DOCK_CENTER)
4189                 return;
4190 
4191             m_action = actionClickCaption;
4192             m_actionPart = part;
4193             m_actionStart = wxPoint(event.m_x, event.m_y);
4194             m_actionOffset = wxPoint(event.m_x - part->rect.x,
4195                                       event.m_y - part->rect.y);
4196             m_frame->CaptureMouse();
4197         }
4198         else
4199         {
4200             event.Skip();
4201         }
4202     }
4203     else
4204     {
4205         event.Skip();
4206     }
4207 }
4208 
4209 /// Ends a resize action, or for live update, resizes the sash
DoEndResizeAction(wxMouseEvent & event)4210 bool wxAuiManager::DoEndResizeAction(wxMouseEvent& event)
4211 {
4212     // resize the dock or the pane
4213     if (m_actionPart && m_actionPart->type==wxAuiDockUIPart::typeDockSizer)
4214     {
4215         // first, we must calculate the maximum size the dock may be
4216         int sashSize = m_art->GetMetric(wxAUI_DOCKART_SASH_SIZE);
4217 
4218         int used_width = 0, used_height = 0;
4219 
4220         wxSize client_size = m_frame->GetClientSize();
4221 
4222         size_t dock_i, dock_count = m_docks.GetCount();
4223         for (dock_i = 0; dock_i < dock_count; ++dock_i)
4224         {
4225             wxAuiDockInfo& dock = m_docks.Item(dock_i);
4226             if (dock.dock_direction == wxAUI_DOCK_TOP ||
4227                 dock.dock_direction == wxAUI_DOCK_BOTTOM)
4228             {
4229                 used_height += dock.size;
4230             }
4231             if (dock.dock_direction == wxAUI_DOCK_LEFT ||
4232                 dock.dock_direction == wxAUI_DOCK_RIGHT)
4233             {
4234                 used_width += dock.size;
4235             }
4236             if (dock.resizable)
4237                 used_width += sashSize;
4238         }
4239 
4240 
4241         int available_width = client_size.GetWidth() - used_width;
4242         int available_height = client_size.GetHeight() - used_height;
4243 
4244 
4245 #if wxUSE_STATUSBAR
4246         // if there's a status control, the available
4247         // height decreases accordingly
4248         if (wxDynamicCast(m_frame, wxFrame))
4249         {
4250             wxFrame* frame = static_cast<wxFrame*>(m_frame);
4251             wxStatusBar* status = frame->GetStatusBar();
4252             if (status)
4253             {
4254                 wxSize status_client_size = status->GetClientSize();
4255                 available_height -= status_client_size.GetHeight();
4256             }
4257         }
4258 #endif
4259 
4260         wxRect& rect = m_actionPart->dock->rect;
4261 
4262         wxPoint new_pos(event.m_x - m_actionOffset.x,
4263             event.m_y - m_actionOffset.y);
4264         int new_size, old_size = m_actionPart->dock->size;
4265 
4266         switch (m_actionPart->dock->dock_direction)
4267         {
4268         case wxAUI_DOCK_LEFT:
4269             new_size = new_pos.x - rect.x;
4270             if (new_size-old_size > available_width)
4271                 new_size = old_size+available_width;
4272             m_actionPart->dock->size = new_size;
4273             break;
4274         case wxAUI_DOCK_TOP:
4275             new_size = new_pos.y - rect.y;
4276             if (new_size-old_size > available_height)
4277                 new_size = old_size+available_height;
4278             m_actionPart->dock->size = new_size;
4279             break;
4280         case wxAUI_DOCK_RIGHT:
4281             new_size = rect.x + rect.width - new_pos.x -
4282                        m_actionPart->rect.GetWidth();
4283             if (new_size-old_size > available_width)
4284                 new_size = old_size+available_width;
4285             m_actionPart->dock->size = new_size;
4286             break;
4287         case wxAUI_DOCK_BOTTOM:
4288             new_size = rect.y + rect.height -
4289                 new_pos.y - m_actionPart->rect.GetHeight();
4290             if (new_size-old_size > available_height)
4291                 new_size = old_size+available_height;
4292             m_actionPart->dock->size = new_size;
4293             break;
4294         }
4295 
4296         Update();
4297     }
4298     else if (m_actionPart &&
4299         m_actionPart->type == wxAuiDockUIPart::typePaneSizer)
4300     {
4301         wxAuiDockInfo& dock = *m_actionPart->dock;
4302         wxAuiPaneInfo& pane = *m_actionPart->pane;
4303 
4304         int total_proportion = 0;
4305         int dock_pixels = 0;
4306         int new_pixsize = 0;
4307 
4308         int caption_size = m_art->GetMetric(wxAUI_DOCKART_CAPTION_SIZE);
4309         int pane_borderSize = m_art->GetMetric(wxAUI_DOCKART_PANE_BORDER_SIZE);
4310         int sashSize = m_art->GetMetric(wxAUI_DOCKART_SASH_SIZE);
4311 
4312         wxPoint new_pos(event.m_x - m_actionOffset.x,
4313             event.m_y - m_actionOffset.y);
4314 
4315         // determine the pane rectangle by getting the pane part
4316         wxAuiDockUIPart* pane_part = GetPanePart(pane.window);
4317         wxASSERT_MSG(pane_part,
4318             wxT("Pane border part not found -- shouldn't happen"));
4319 
4320         // determine the new pixel size that the user wants;
4321         // this will help us recalculate the pane's proportion
4322         if (dock.IsHorizontal())
4323             new_pixsize = new_pos.x - pane_part->rect.x;
4324         else
4325             new_pixsize = new_pos.y - pane_part->rect.y;
4326 
4327         // determine the size of the dock, based on orientation
4328         if (dock.IsHorizontal())
4329             dock_pixels = dock.rect.GetWidth();
4330         else
4331             dock_pixels = dock.rect.GetHeight();
4332 
4333         // determine the total proportion of all resizable panes,
4334         // and the total size of the dock minus the size of all
4335         // the fixed panes
4336         int i, dock_pane_count = dock.panes.GetCount();
4337         int pane_position = -1;
4338         for (i = 0; i < dock_pane_count; ++i)
4339         {
4340             wxAuiPaneInfo& p = *dock.panes.Item(i);
4341             if (p.window == pane.window)
4342                 pane_position = i;
4343 
4344             // while we're at it, subtract the pane sash
4345             // width from the dock width, because this would
4346             // skew our proportion calculations
4347             if (i > 0)
4348                 dock_pixels -= sashSize;
4349 
4350             // also, the whole size (including decorations) of
4351             // all fixed panes must also be subtracted, because they
4352             // are not part of the proportion calculation
4353             if (p.IsFixed())
4354             {
4355                 if (dock.IsHorizontal())
4356                     dock_pixels -= p.best_size.x;
4357                 else
4358                     dock_pixels -= p.best_size.y;
4359             }
4360             else
4361             {
4362                 total_proportion += p.dock_proportion;
4363             }
4364         }
4365 
4366         // new size can never be more than the number of dock pixels
4367         if (new_pixsize > dock_pixels)
4368             new_pixsize = dock_pixels;
4369 
4370 
4371         // find a pane in our dock to 'steal' space from or to 'give'
4372         // space to -- this is essentially what is done when a pane is
4373         // resized; the pane should usually be the first non-fixed pane
4374         // to the right of the action pane
4375         int borrow_pane = -1;
4376         for (i = pane_position+1; i < dock_pane_count; ++i)
4377         {
4378             wxAuiPaneInfo& p = *dock.panes.Item(i);
4379             if (!p.IsFixed())
4380             {
4381                 borrow_pane = i;
4382                 break;
4383             }
4384         }
4385 
4386 
4387         // demand that the pane being resized is found in this dock
4388         // (this assert really never should be raised)
4389         wxASSERT_MSG(pane_position != -1, wxT("Pane not found in dock"));
4390 
4391         // prevent division by zero
4392         if (dock_pixels == 0 || total_proportion == 0 || borrow_pane == -1)
4393         {
4394             m_action = actionNone;
4395             return false;
4396         }
4397 
4398         // calculate the new proportion of the pane
4399         int new_proportion = (new_pixsize*total_proportion)/dock_pixels;
4400 
4401         // default minimum size
4402         int min_size = 0;
4403 
4404         // check against the pane's minimum size, if specified. please note
4405         // that this is not enough to ensure that the minimum size will
4406         // not be violated, because the whole frame might later be shrunk,
4407         // causing the size of the pane to violate its minimum size
4408         if (pane.min_size.IsFullySpecified())
4409         {
4410             min_size = 0;
4411 
4412             if (pane.HasBorder())
4413                 min_size += (pane_borderSize*2);
4414 
4415             // calculate minimum size with decorations (border,caption)
4416             if (pane_part->orientation == wxVERTICAL)
4417             {
4418                 min_size += pane.min_size.y;
4419                 if (pane.HasCaption())
4420                     min_size += caption_size;
4421             }
4422             else
4423             {
4424                 min_size += pane.min_size.x;
4425             }
4426         }
4427 
4428 
4429         // for some reason, an arithmetic error somewhere is causing
4430         // the proportion calculations to always be off by 1 pixel;
4431         // for now we will add the 1 pixel on, but we really should
4432         // determine what's causing this.
4433         min_size++;
4434 
4435         int min_proportion = (min_size*total_proportion)/dock_pixels;
4436 
4437         if (new_proportion < min_proportion)
4438             new_proportion = min_proportion;
4439 
4440 
4441 
4442         int prop_diff = new_proportion - pane.dock_proportion;
4443 
4444         // borrow the space from our neighbor pane to the
4445         // right or bottom (depending on orientation);
4446         // also make sure we don't make the neighbor too small
4447         int prop_borrow = dock.panes.Item(borrow_pane)->dock_proportion;
4448 
4449         if (prop_borrow - prop_diff < 0)
4450         {
4451             // borrowing from other pane would make it too small,
4452             // so cancel the resize operation
4453             prop_borrow = min_proportion;
4454         }
4455          else
4456         {
4457             prop_borrow -= prop_diff;
4458         }
4459 
4460 
4461         dock.panes.Item(borrow_pane)->dock_proportion = prop_borrow;
4462         pane.dock_proportion = new_proportion;
4463 
4464         Update();
4465     }
4466 
4467     return true;
4468 }
4469 
OnLeftUp(wxMouseEvent & event)4470 void wxAuiManager::OnLeftUp(wxMouseEvent& event)
4471 {
4472     if (m_action == actionResize)
4473     {
4474         m_frame->ReleaseMouse();
4475 
4476         if (!HasLiveResize())
4477         {
4478             // get rid of the hint rectangle
4479             wxScreenDC dc;
4480             DrawResizeHint(dc, m_actionHintRect);
4481         }
4482         if (m_currentDragItem != -1 && HasLiveResize())
4483             m_actionPart = & (m_uiParts.Item(m_currentDragItem));
4484 
4485         DoEndResizeAction(event);
4486 
4487         m_currentDragItem = -1;
4488 
4489     }
4490     else if (m_action == actionClickButton)
4491     {
4492         m_hoverButton = NULL;
4493         m_frame->ReleaseMouse();
4494 
4495         if (m_actionPart)
4496         {
4497             UpdateButtonOnScreen(m_actionPart, event);
4498 
4499             // make sure we're still over the item that was originally clicked
4500             if (m_actionPart == HitTest(event.GetX(), event.GetY()))
4501             {
4502                 // fire button-click event
4503                 wxAuiManagerEvent e(wxEVT_AUI_PANE_BUTTON);
4504                 e.SetManager(this);
4505                 e.SetPane(m_actionPart->pane);
4506                 e.SetButton(m_actionPart->button);
4507                 ProcessMgrEvent(e);
4508             }
4509         }
4510     }
4511     else if (m_action == actionClickCaption)
4512     {
4513         m_frame->ReleaseMouse();
4514     }
4515     else if (m_action == actionDragFloatingPane)
4516     {
4517         m_frame->ReleaseMouse();
4518     }
4519     else if (m_action == actionDragToolbarPane)
4520     {
4521         m_frame->ReleaseMouse();
4522 
4523         wxAuiPaneInfo& pane = GetPane(m_actionWindow);
4524         wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
4525 
4526         // save the new positions
4527         wxAuiDockInfoPtrArray docks;
4528         FindDocks(m_docks, pane.dock_direction,
4529                   pane.dock_layer, pane.dock_row, docks);
4530         if (docks.GetCount() == 1)
4531         {
4532             wxAuiDockInfo& dock = *docks.Item(0);
4533 
4534             wxArrayInt pane_positions, pane_sizes;
4535             GetPanePositionsAndSizes(dock, pane_positions, pane_sizes);
4536 
4537             int i, dock_pane_count = dock.panes.GetCount();
4538             for (i = 0; i < dock_pane_count; ++i)
4539                 dock.panes.Item(i)->dock_pos = pane_positions[i];
4540         }
4541 
4542         pane.state &= ~wxAuiPaneInfo::actionPane;
4543         Update();
4544     }
4545     else
4546     {
4547         event.Skip();
4548     }
4549 
4550     m_action = actionNone;
4551     m_lastMouseMove = wxPoint(); // see comment in OnMotion()
4552 }
4553 
4554 
OnMotion(wxMouseEvent & event)4555 void wxAuiManager::OnMotion(wxMouseEvent& event)
4556 {
4557     // sometimes when Update() is called from inside this method,
4558     // a spurious mouse move event is generated; this check will make
4559     // sure that only real mouse moves will get anywhere in this method;
4560     // this appears to be a bug somewhere, and I don't know where the
4561     // mouse move event is being generated.  only verified on MSW
4562 
4563     wxPoint mouse_pos = event.GetPosition();
4564     if (m_lastMouseMove == mouse_pos)
4565         return;
4566     m_lastMouseMove = mouse_pos;
4567 
4568 
4569     if (m_action == actionResize)
4570     {
4571         // It's necessary to reset m_actionPart since it destroyed
4572         // by the Update within DoEndResizeAction.
4573         if (m_currentDragItem != -1)
4574             m_actionPart = & (m_uiParts.Item(m_currentDragItem));
4575         else
4576             m_currentDragItem = m_uiParts.Index(* m_actionPart);
4577 
4578         if (m_actionPart)
4579         {
4580             wxPoint pos = m_actionPart->rect.GetPosition();
4581             if (m_actionPart->orientation == wxHORIZONTAL)
4582                 pos.y = wxMax(0, event.m_y - m_actionOffset.y);
4583             else
4584                 pos.x = wxMax(0, event.m_x - m_actionOffset.x);
4585 
4586             if (HasLiveResize())
4587             {
4588                 m_frame->ReleaseMouse();
4589                 DoEndResizeAction(event);
4590                 m_frame->CaptureMouse();
4591             }
4592             else
4593             {
4594                 wxRect rect(m_frame->ClientToScreen(pos),
4595                     m_actionPart->rect.GetSize());
4596                 wxScreenDC dc;
4597 
4598                 if (!m_actionHintRect.IsEmpty())
4599                 {
4600                     // remove old resize hint
4601                     DrawResizeHint(dc, m_actionHintRect);
4602                     m_actionHintRect = wxRect();
4603                 }
4604 
4605                 // draw new resize hint, if it's inside the managed frame
4606                 wxRect frameScreenRect = m_frame->GetScreenRect();
4607                 if (frameScreenRect.Contains(rect))
4608                 {
4609                     DrawResizeHint(dc, rect);
4610                     m_actionHintRect = rect;
4611                 }
4612             }
4613         }
4614     }
4615     else if (m_action == actionClickCaption)
4616     {
4617         int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X, m_frame);
4618         int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y, m_frame);
4619 
4620         // caption has been clicked.  we need to check if the mouse
4621         // is now being dragged. if it is, we need to change the
4622         // mouse action to 'drag'
4623         if (m_actionPart &&
4624             (abs(event.m_x - m_actionStart.x) > drag_x_threshold ||
4625              abs(event.m_y - m_actionStart.y) > drag_y_threshold))
4626         {
4627             wxAuiPaneInfo* paneInfo = m_actionPart->pane;
4628 
4629             if (!paneInfo->IsToolbar())
4630             {
4631                 if ((m_flags & wxAUI_MGR_ALLOW_FLOATING) &&
4632                     paneInfo->IsFloatable())
4633                 {
4634                     m_action = actionDragFloatingPane;
4635 
4636                     // set initial float position
4637                     wxPoint pt = m_frame->ClientToScreen(event.GetPosition());
4638                     paneInfo->floating_pos = wxPoint(pt.x - m_actionOffset.x,
4639                                                       pt.y - m_actionOffset.y);
4640 
4641                     // float the window
4642                     if (paneInfo->IsMaximized())
4643                         RestorePane(*paneInfo);
4644                     paneInfo->Float();
4645                     Update();
4646 
4647                     m_actionWindow = paneInfo->frame;
4648 
4649                     // action offset is used here to make it feel "natural" to the user
4650                     // to drag a docked pane and suddenly have it become a floating frame.
4651                     // Sometimes, however, the offset where the user clicked on the docked
4652                     // caption is bigger than the width of the floating frame itself, so
4653                     // in that case we need to set the action offset to a sensible value
4654                     wxSize frame_size = m_actionWindow->GetSize();
4655                     if (frame_size.x <= m_actionOffset.x)
4656                         m_actionOffset.x = paneInfo->frame->FromDIP(30);
4657                 }
4658             }
4659             else
4660             {
4661                 m_action = actionDragToolbarPane;
4662                 m_actionWindow = paneInfo->window;
4663             }
4664         }
4665     }
4666     else if (m_action == actionDragFloatingPane)
4667     {
4668         if (m_actionWindow)
4669         {
4670             // We can't move the child window so we need to get the frame that
4671             // we want to be really moving. This is probably not the best place
4672             // to do this but at least it fixes the bug (#13177) for now.
4673             if (!wxDynamicCast(m_actionWindow, wxAuiFloatingFrame))
4674             {
4675                 wxAuiPaneInfo& pane = GetPane(m_actionWindow);
4676                 m_actionWindow = pane.frame;
4677             }
4678 
4679             wxPoint pt = m_frame->ClientToScreen(event.GetPosition());
4680             m_actionWindow->Move(pt.x - m_actionOffset.x,
4681                                 pt.y - m_actionOffset.y);
4682         }
4683     }
4684     else if (m_action == actionDragToolbarPane)
4685     {
4686         wxAuiPaneInfo& pane = GetPane(m_actionWindow);
4687         wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
4688 
4689         pane.SetFlag(wxAuiPaneInfo::actionPane, true);
4690 
4691         wxPoint point = event.GetPosition();
4692         DoDrop(m_docks, m_panes, pane, point, m_actionOffset);
4693 
4694         // if DoDrop() decided to float the pane, set up
4695         // the floating pane's initial position
4696         if (pane.IsFloating())
4697         {
4698             wxPoint pt = m_frame->ClientToScreen(event.GetPosition());
4699             pane.floating_pos = wxPoint(pt.x - m_actionOffset.x,
4700                                         pt.y - m_actionOffset.y);
4701         }
4702 
4703         // this will do the actual move operation;
4704         // in the case that the pane has been floated,
4705         // this call will create the floating pane
4706         // and do the reparenting
4707         Update();
4708 
4709         // if the pane has been floated, change the mouse
4710         // action actionDragFloatingPane so that subsequent
4711         // EVT_MOTION() events will move the floating pane
4712         if (pane.IsFloating())
4713         {
4714             pane.state &= ~wxAuiPaneInfo::actionPane;
4715             m_action = actionDragFloatingPane;
4716             m_actionWindow = pane.frame;
4717         }
4718     }
4719     else
4720     {
4721         wxAuiDockUIPart* part = HitTest(event.GetX(), event.GetY());
4722         if (part && part->type == wxAuiDockUIPart::typePaneButton)
4723         {
4724             if (part != m_hoverButton)
4725             {
4726                 // make the old button normal
4727                 if (m_hoverButton)
4728                 {
4729                     UpdateButtonOnScreen(m_hoverButton, event);
4730                     Repaint();
4731                 }
4732 
4733                 // mouse is over a button, so repaint the
4734                 // button in hover mode
4735                 UpdateButtonOnScreen(part, event);
4736                 m_hoverButton = part;
4737 
4738             }
4739         }
4740         else
4741         {
4742             if (m_hoverButton)
4743             {
4744                 m_hoverButton = NULL;
4745                 Repaint();
4746             }
4747             else
4748             {
4749                 event.Skip();
4750             }
4751         }
4752     }
4753 }
4754 
OnLeaveWindow(wxMouseEvent & WXUNUSED (event))4755 void wxAuiManager::OnLeaveWindow(wxMouseEvent& WXUNUSED(event))
4756 {
4757     if (m_hoverButton)
4758     {
4759         m_hoverButton = NULL;
4760         Repaint();
4761     }
4762 }
4763 
OnCaptureLost(wxMouseCaptureLostEvent & WXUNUSED (event))4764 void wxAuiManager::OnCaptureLost(wxMouseCaptureLostEvent& WXUNUSED(event))
4765 {
4766     // cancel the operation in progress, if any
4767     if ( m_action != actionNone )
4768     {
4769         m_action = actionNone;
4770         HideHint();
4771     }
4772 }
4773 
OnChildFocus(wxChildFocusEvent & event)4774 void wxAuiManager::OnChildFocus(wxChildFocusEvent& event)
4775 {
4776     // when a child pane has its focus set, we should change the
4777     // pane's active state to reflect this. (this is only true if
4778     // active panes are allowed by the owner)
4779     if (GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE)
4780     {
4781         wxAuiPaneInfo& pane = GetPane(event.GetWindow());
4782         if (pane.IsOk() && (pane.state & wxAuiPaneInfo::optionActive) == 0)
4783         {
4784             SetActivePane(event.GetWindow());
4785             m_frame->Refresh();
4786         }
4787     }
4788 
4789     event.Skip();
4790 }
4791 
4792 
4793 // OnPaneButton() is an event handler that is called
4794 // when a pane button has been pressed.
OnPaneButton(wxAuiManagerEvent & evt)4795 void wxAuiManager::OnPaneButton(wxAuiManagerEvent& evt)
4796 {
4797     wxASSERT_MSG(evt.pane, wxT("Pane Info passed to wxAuiManager::OnPaneButton must be non-null"));
4798 
4799     wxAuiPaneInfo& pane = *(evt.pane);
4800 
4801     if (evt.button == wxAUI_BUTTON_CLOSE)
4802     {
4803         // fire pane close event
4804         wxAuiManagerEvent e(wxEVT_AUI_PANE_CLOSE);
4805         e.SetManager(this);
4806         e.SetPane(evt.pane);
4807         ProcessMgrEvent(e);
4808 
4809         if (!e.GetVeto())
4810         {
4811             // close the pane, but check that it
4812             // still exists in our pane array first
4813             // (the event handler above might have removed it)
4814 
4815             wxAuiPaneInfo& check = GetPane(pane.window);
4816             if (check.IsOk())
4817             {
4818                 ClosePane(pane);
4819             }
4820 
4821             Update();
4822         }
4823     }
4824     else if (evt.button == wxAUI_BUTTON_MAXIMIZE_RESTORE && !pane.IsMaximized())
4825     {
4826         // fire pane maximize event
4827         wxAuiManagerEvent e(wxEVT_AUI_PANE_MAXIMIZE);
4828         e.SetManager(this);
4829         e.SetPane(evt.pane);
4830         ProcessMgrEvent(e);
4831 
4832         if (!e.GetVeto())
4833         {
4834             MaximizePane(pane);
4835             Update();
4836         }
4837     }
4838     else if (evt.button == wxAUI_BUTTON_MAXIMIZE_RESTORE && pane.IsMaximized())
4839     {
4840         // fire pane restore event
4841         wxAuiManagerEvent e(wxEVT_AUI_PANE_RESTORE);
4842         e.SetManager(this);
4843         e.SetPane(evt.pane);
4844         ProcessMgrEvent(e);
4845 
4846         if (!e.GetVeto())
4847         {
4848             RestorePane(pane);
4849             Update();
4850         }
4851     }
4852     else if (evt.button == wxAUI_BUTTON_PIN &&
4853                 (m_flags & wxAUI_MGR_ALLOW_FLOATING) && pane.IsFloatable())
4854     {
4855         if (pane.IsMaximized())
4856         {
4857             // If the pane is maximized, the original state must be restored
4858             // before trying to float the pane, otherwise the other panels
4859             // wouldn't appear correctly when it becomes floating.
4860             wxAuiManagerEvent e(wxEVT_AUI_PANE_RESTORE);
4861             e.SetManager(this);
4862             e.SetPane(evt.pane);
4863             ProcessMgrEvent(e);
4864 
4865             if (e.GetVeto())
4866             {
4867                 // If it can't be restored, it can't be floated neither.
4868                 return;
4869             }
4870 
4871             RestorePane(pane);
4872         }
4873 
4874         pane.Float();
4875         Update();
4876     }
4877 }
4878 
4879 #endif // wxUSE_AUI
4880