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