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