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