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