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