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