]> git.saurik.com Git - wxWidgets.git/blob - src/aui/framemanager.cpp
286df116e54e64dfe6e9f74eb9c2d7f30f6e51ef
[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/settings.h"
34 #include "wx/app.h"
35 #include "wx/dcclient.h"
36 #include "wx/dcscreen.h"
37 #include "wx/toolbar.h"
38 #include "wx/mdi.h"
39 #include "wx/image.h"
40 #endif
41
42 WX_CHECK_BUILD_OPTIONS("wxAUI")
43
44 #include "wx/arrimpl.cpp"
45 WX_DECLARE_OBJARRAY(wxRect, wxAuiRectArray);
46 WX_DEFINE_OBJARRAY(wxAuiRectArray)
47 WX_DEFINE_OBJARRAY(wxDockUIPartArray)
48 WX_DEFINE_OBJARRAY(wxDockInfoArray)
49 WX_DEFINE_OBJARRAY(wxPaneButtonArray)
50 WX_DEFINE_OBJARRAY(wxPaneInfoArray)
51
52 wxPaneInfo wxNullPaneInfo;
53 wxDockInfo wxNullDockInfo;
54 DEFINE_EVENT_TYPE(wxEVT_AUI_PANEBUTTON)
55 DEFINE_EVENT_TYPE(wxEVT_AUI_PANECLOSE)
56 DEFINE_EVENT_TYPE(wxEVT_AUI_RENDER)
57
58 #ifdef __WXMAC__
59 // a few defines to avoid nameclashes
60 #define __MAC_OS_X_MEMORY_MANAGER_CLEAN__ 1
61 #define __AIFF__
62 #include "wx/mac/private.h"
63 #endif
64
65 IMPLEMENT_DYNAMIC_CLASS(wxFrameManagerEvent, wxEvent)
66
67
68 // -- static utility functions --
69
70 static wxBitmap wxPaneCreateStippleBitmap()
71 {
72 unsigned char data[] = { 0,0,0,192,192,192, 192,192,192,0,0,0 };
73 wxImage img(2,2,data,true);
74 return wxBitmap(img);
75 }
76
77 static void DrawResizeHint(wxDC& dc, const wxRect& rect)
78 {
79 wxBitmap stipple = wxPaneCreateStippleBitmap();
80 wxBrush brush(stipple);
81 dc.SetBrush(brush);
82 dc.SetPen(*wxTRANSPARENT_PEN);
83
84 dc.SetLogicalFunction(wxXOR);
85 dc.DrawRectangle(rect);
86 }
87
88
89
90 // CopyDocksAndPanes() - this utility function creates copies of
91 // the dock and pane info. wxDockInfo's usually contain pointers
92 // to wxPaneInfo classes, thus this function is necessary to reliably
93 // reconstruct that relationship in the new dock info and pane info arrays
94
95 static void CopyDocksAndPanes(wxDockInfoArray& dest_docks,
96 wxPaneInfoArray& dest_panes,
97 const wxDockInfoArray& src_docks,
98 const wxPaneInfoArray& src_panes)
99 {
100 dest_docks = src_docks;
101 dest_panes = src_panes;
102 int i, j, k, dock_count, pc1, pc2;
103 for (i = 0, dock_count = dest_docks.GetCount(); i < dock_count; ++i)
104 {
105 wxDockInfo& dock = dest_docks.Item(i);
106 for (j = 0, pc1 = dock.panes.GetCount(); j < pc1; ++j)
107 for (k = 0, pc2 = src_panes.GetCount(); k < pc2; ++k)
108 if (dock.panes.Item(j) == &src_panes.Item(k))
109 dock.panes.Item(j) = &dest_panes.Item(k);
110 }
111 }
112
113 // GetMaxLayer() is an internal function which returns
114 // the highest layer inside the specified dock
115 static int GetMaxLayer(const wxDockInfoArray& docks, int dock_direction)
116 {
117 int i, dock_count, max_layer = 0;
118 for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i)
119 {
120 wxDockInfo& dock = docks.Item(i);
121 if (dock.dock_direction == dock_direction &&
122 dock.dock_layer > max_layer && !dock.fixed)
123 max_layer = dock.dock_layer;
124 }
125 return max_layer;
126 }
127
128
129 // GetMaxRow() is an internal function which returns
130 // the highest layer inside the specified dock
131 static int GetMaxRow(const wxPaneInfoArray& panes, int direction, int layer)
132 {
133 int i, pane_count, max_row = 0;
134 for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i)
135 {
136 wxPaneInfo& pane = panes.Item(i);
137 if (pane.dock_direction == direction &&
138 pane.dock_layer == layer &&
139 pane.dock_row > max_row)
140 max_row = pane.dock_row;
141 }
142 return max_row;
143 }
144
145
146
147 // DoInsertDockLayer() is an internal function that inserts a new dock
148 // layer by incrementing all existing dock layer values by one
149 static void DoInsertDockLayer(wxPaneInfoArray& panes,
150 int dock_direction,
151 int dock_layer)
152 {
153 int i, pane_count;
154 for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i)
155 {
156 wxPaneInfo& pane = panes.Item(i);
157 if (!pane.IsFloating() &&
158 pane.dock_direction == dock_direction &&
159 pane.dock_layer >= dock_layer)
160 pane.dock_layer++;
161 }
162 }
163
164 // DoInsertDockLayer() is an internal function that inserts a new dock
165 // row by incrementing all existing dock row values by one
166 static void DoInsertDockRow(wxPaneInfoArray& panes,
167 int dock_direction,
168 int dock_layer,
169 int dock_row)
170 {
171 int i, pane_count;
172 for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i)
173 {
174 wxPaneInfo& pane = panes.Item(i);
175 if (!pane.IsFloating() &&
176 pane.dock_direction == dock_direction &&
177 pane.dock_layer == dock_layer &&
178 pane.dock_row >= dock_row)
179 pane.dock_row++;
180 }
181 }
182
183 // DoInsertDockLayer() is an internal function that inserts a space for
184 // another dock pane by incrementing all existing dock row values by one
185 static void DoInsertPane(wxPaneInfoArray& panes,
186 int dock_direction,
187 int dock_layer,
188 int dock_row,
189 int dock_pos)
190 {
191 int i, pane_count;
192 for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i)
193 {
194 wxPaneInfo& pane = panes.Item(i);
195 if (!pane.IsFloating() &&
196 pane.dock_direction == dock_direction &&
197 pane.dock_layer == dock_layer &&
198 pane.dock_row == dock_row &&
199 pane.dock_pos >= dock_pos)
200 pane.dock_pos++;
201 }
202 }
203
204 // FindDocks() is an internal function that returns a list of docks which meet
205 // the specified conditions in the parameters and returns a sorted array
206 // (sorted by layer and then row)
207 static void FindDocks(wxDockInfoArray& docks,
208 int dock_direction,
209 int dock_layer,
210 int dock_row,
211 wxDockInfoPtrArray& arr)
212 {
213 int begin_layer = dock_layer;
214 int end_layer = dock_layer;
215 int begin_row = dock_row;
216 int end_row = dock_row;
217 int dock_count = docks.GetCount();
218 int layer, row, i, max_row = 0, max_layer = 0;
219
220 // discover the maximum dock layer and the max row
221 for (i = 0; i < dock_count; ++i)
222 {
223 max_row = wxMax(max_row, docks.Item(i).dock_row);
224 max_layer = wxMax(max_layer, docks.Item(i).dock_layer);
225 }
226
227 // if no dock layer was specified, search all dock layers
228 if (dock_layer == -1)
229 {
230 begin_layer = 0;
231 end_layer = max_layer;
232 }
233
234 // if no dock row was specified, search all dock row
235 if (dock_row == -1)
236 {
237 begin_row = 0;
238 end_row = max_row;
239 }
240
241 arr.Clear();
242
243 for (layer = begin_layer; layer <= end_layer; ++layer)
244 for (row = begin_row; row <= end_row; ++row)
245 for (i = 0; i < dock_count; ++i)
246 {
247 wxDockInfo& d = docks.Item(i);
248 if (dock_direction == -1 || dock_direction == d.dock_direction)
249 {
250 if (d.dock_layer == layer && d.dock_row == row)
251 arr.Add(&d);
252 }
253 }
254 }
255
256 // FindPaneInDock() looks up a specified window pointer inside a dock.
257 // If found, the corresponding wxPaneInfo pointer is returned, otherwise NULL.
258 static wxPaneInfo* FindPaneInDock(const wxDockInfo& dock, wxWindow* window)
259 {
260 int i, count = dock.panes.GetCount();
261 for (i = 0; i < count; ++i)
262 {
263 wxPaneInfo* p = dock.panes.Item(i);
264 if (p->window == window)
265 return p;
266 }
267 return NULL;
268 }
269
270 // RemovePaneFromDocks() removes a pane window from all docks
271 // with a possible exception specified by parameter "except"
272 static void RemovePaneFromDocks(wxDockInfoArray& docks,
273 wxPaneInfo& pane,
274 wxDockInfo* except = NULL)
275 {
276 int i, dock_count;
277 for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i)
278 {
279 wxDockInfo& d = docks.Item(i);
280 if (&d == except)
281 continue;
282 wxPaneInfo* pi = FindPaneInDock(d, pane.window);
283 if (pi)
284 d.panes.Remove(pi);
285 }
286 }
287
288 // RenumberDockRows() takes a dock and assigns sequential numbers
289 // to existing rows. Basically it takes out the gaps; so if a
290 // dock has rows with numbers 0,2,5, they will become 0,1,2
291 static void RenumberDockRows(wxDockInfoPtrArray& docks)
292 {
293 int i, dock_count, j, pane_count;
294 for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i)
295 {
296 wxDockInfo& dock = *docks.Item(i);
297 dock.dock_row = i;
298 for (j = 0, pane_count = dock.panes.GetCount(); j < pane_count; ++j)
299 dock.panes.Item(j)->dock_row = i;
300 }
301 }
302
303
304 // SetActivePane() sets the active pane, as well as cycles through
305 // every other pane and makes sure that all others' active flags
306 // are turned off
307 static void SetActivePane(wxPaneInfoArray& panes, wxWindow* active_pane)
308 {
309 int i, pane_count;
310 for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i)
311 {
312 wxPaneInfo& pane = panes.Item(i);
313 pane.state &= ~wxPaneInfo::optionActive;
314 if (pane.window == active_pane)
315 pane.state |= wxPaneInfo::optionActive;
316 }
317 }
318
319
320 // this function is used to sort panes by dock position
321 static int PaneSortFunc(wxPaneInfo** p1, wxPaneInfo** p2)
322 {
323 return ((*p1)->dock_pos < (*p2)->dock_pos) ? -1 : 1;
324 }
325
326
327 // -- wxFrameManager class implementation --
328
329
330 BEGIN_EVENT_TABLE(wxFrameManager, wxEvtHandler)
331 EVT_AUI_PANEBUTTON(wxFrameManager::OnPaneButton)
332 EVT_AUI_RENDER(wxFrameManager::OnRender)
333 EVT_PAINT(wxFrameManager::OnPaint)
334 EVT_ERASE_BACKGROUND(wxFrameManager::OnEraseBackground)
335 EVT_SIZE(wxFrameManager::OnSize)
336 EVT_SET_CURSOR(wxFrameManager::OnSetCursor)
337 EVT_LEFT_DOWN(wxFrameManager::OnLeftDown)
338 EVT_LEFT_UP(wxFrameManager::OnLeftUp)
339 EVT_MOTION(wxFrameManager::OnMotion)
340 EVT_LEAVE_WINDOW(wxFrameManager::OnLeaveWindow)
341 EVT_CHILD_FOCUS(wxFrameManager::OnChildFocus)
342 EVT_TIMER(101, wxFrameManager::OnHintFadeTimer)
343 END_EVENT_TABLE()
344
345
346 wxFrameManager::wxFrameManager(wxWindow* managed_wnd, unsigned int flags)
347 {
348 m_action = actionNone;
349 m_last_mouse_move = wxPoint();
350 m_hover_button = NULL;
351 m_art = new wxDefaultDockArt;
352 m_hint_wnd = NULL;
353 m_flags = flags;
354
355 if (managed_wnd)
356 {
357 SetManagedWindow(managed_wnd);
358 }
359 }
360
361 wxFrameManager::~wxFrameManager()
362 {
363 delete m_art;
364 }
365
366 // GetPane() looks up a wxPaneInfo structure based
367 // on the supplied window pointer. Upon failure, GetPane()
368 // returns an empty wxPaneInfo, a condition which can be checked
369 // by calling wxPaneInfo::IsOk().
370 //
371 // The pane info's structure may then be modified. Once a pane's
372 // info is modified, wxFrameManager::Update() must be called to
373 // realize the changes in the UI.
374
375 wxPaneInfo& wxFrameManager::GetPane(wxWindow* window)
376 {
377 int i, pane_count;
378 for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i)
379 {
380 wxPaneInfo& p = m_panes.Item(i);
381 if (p.window == window)
382 return p;
383 }
384 return wxNullPaneInfo;
385 }
386
387 // this version of GetPane() looks up a pane based on a
388 // 'pane name', see above comment for more info
389 wxPaneInfo& wxFrameManager::GetPane(const wxString& name)
390 {
391 int i, pane_count;
392 for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i)
393 {
394 wxPaneInfo& p = m_panes.Item(i);
395 if (p.name == name)
396 return p;
397 }
398 return wxNullPaneInfo;
399 }
400
401 // GetAllPanes() returns a reference to all the pane info structures
402 wxPaneInfoArray& wxFrameManager::GetAllPanes()
403 {
404 return m_panes;
405 }
406
407 // HitTest() is an internal function which determines
408 // which UI item the specified coordinates are over
409 // (x,y) specify a position in client coordinates
410 wxDockUIPart* wxFrameManager::HitTest(int x, int y)
411 {
412 wxDockUIPart* result = NULL;
413
414 int i, part_count;
415 for (i = 0, part_count = m_uiparts.GetCount(); i < part_count; ++i)
416 {
417 wxDockUIPart* item = &m_uiparts.Item(i);
418
419 // we are not interested in typeDock, because this space
420 // isn't used to draw anything, just for measurements;
421 // besides, the entire dock area is covered with other
422 // rectangles, which we are interested in.
423 if (item->type == wxDockUIPart::typeDock)
424 continue;
425
426 // if we already have a hit on a more specific item, we are not
427 // interested in a pane hit. If, however, we don't already have
428 // a hit, returning a pane hit is necessary for some operations
429 if ((item->type == wxDockUIPart::typePane ||
430 item->type == wxDockUIPart::typePaneBorder) && result)
431 continue;
432
433 // if the point is inside the rectangle, we have a hit
434 if (item->rect.Inside(x,y))
435 result = item;
436 }
437
438 return result;
439 }
440
441
442 // SetFlags() and GetFlags() allow the owner to set various
443 // options which are global to wxFrameManager
444 void wxFrameManager::SetFlags(unsigned int flags)
445 {
446 m_flags = flags;
447 }
448
449 unsigned int wxFrameManager::GetFlags() const
450 {
451 return m_flags;
452 }
453
454
455 // don't use these anymore as they are deprecated
456 // use Set/GetManagedFrame() instead
457 void wxFrameManager::SetFrame(wxFrame* frame)
458 {
459 SetManagedWindow((wxWindow*)frame);
460 }
461
462 wxFrame* wxFrameManager::GetFrame() const
463 {
464 return (wxFrame*)m_frame;
465 }
466
467
468
469
470 // SetManagedWindow() is usually called once when the frame
471 // manager class is being initialized. "frame" specifies
472 // the frame which should be managed by the frame mananger
473 void wxFrameManager::SetManagedWindow(wxWindow* frame)
474 {
475 wxASSERT_MSG(frame, wxT("specified frame must be non-NULL"));
476
477 m_frame = frame;
478 m_frame->PushEventHandler(this);
479
480 #if wxUSE_MDI
481 // if the owner is going to manage an MDI parent frame,
482 // we need to add the MDI client window as the default
483 // center pane
484
485 if (frame->IsKindOf(CLASSINFO(wxMDIParentFrame)))
486 {
487 wxMDIParentFrame* mdi_frame = (wxMDIParentFrame*)frame;
488 wxWindow* client_window = mdi_frame->GetClientWindow();
489
490 wxASSERT_MSG(client_window, wxT("Client window is NULL!"));
491
492 AddPane(client_window,
493 wxPaneInfo().Name(wxT("mdiclient")).
494 CenterPane().PaneBorder(false));
495 }
496 #endif
497
498 // Make a window to use for a translucent hint
499 #if defined(__WXMSW__)
500 m_hint_wnd = new wxFrame(m_frame, -1, wxEmptyString, wxDefaultPosition, wxSize(1,1),
501 wxFRAME_TOOL_WINDOW |
502 wxFRAME_FLOAT_ON_PARENT |
503 wxFRAME_NO_TASKBAR |
504 wxNO_BORDER);
505
506 m_hint_wnd->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_ACTIVECAPTION));
507
508 #elif defined(__WXMAC__)
509 // Using a miniframe with float and tool styles keeps the parent
510 // frame activated and highlighted as such...
511 m_hint_wnd = new wxMiniFrame(m_frame, -1, wxEmptyString, wxDefaultPosition, wxSize(1,1),
512 wxFRAME_FLOAT_ON_PARENT
513 | wxFRAME_TOOL_WINDOW
514 | wxCAPTION );
515
516 // Can't set the bg colour of a Frame in wxMac
517 wxPanel* p = new wxPanel(m_hint_wnd);
518
519 // The default wxSYS_COLOUR_ACTIVECAPTION colour is a light silver
520 // color that is really hard to see, especially transparent.
521 // Until a better system color is decided upon we'll just use
522 // blue.
523 p->SetBackgroundColour(*wxBLUE);
524 #endif
525
526 if (m_hint_wnd && !m_hint_wnd->CanSetTranslucency())
527 {
528 m_hint_wnd->Close();
529 m_hint_wnd = NULL;
530 }
531 }
532
533
534 // UnInit() must be called, usually in the destructor
535 // of the frame class. If it is not called, usually this
536 // will result in a crash upon program exit
537 void wxFrameManager::UnInit()
538 {
539 m_frame->RemoveEventHandler(this);
540 }
541
542 // GetManagedWindow() returns the window pointer being managed
543 wxWindow* wxFrameManager::GetManagedWindow() const
544 {
545 return m_frame;
546 }
547
548 wxDockArt* wxFrameManager::GetArtProvider() const
549 {
550 return m_art;
551 }
552
553 void wxFrameManager::ProcessMgrEvent(wxFrameManagerEvent& event)
554 {
555 // first, give the owner frame a chance to override
556 if (m_frame)
557 {
558 if (m_frame->ProcessEvent(event))
559 return;
560 }
561
562 ProcessEvent(event);
563 }
564
565 // SetArtProvider() instructs wxFrameManager to use the
566 // specified art provider for all drawing calls. This allows
567 // plugable look-and-feel features. The pointer that is
568 // passed to this method subsequently belongs to wxFrameManager,
569 // and is deleted in the frame manager destructor
570 void wxFrameManager::SetArtProvider(wxDockArt* art_provider)
571 {
572 // delete the last art provider, if any
573 delete m_art;
574
575 // assign the new art provider
576 m_art = art_provider;
577 }
578
579
580 bool wxFrameManager::AddPane(wxWindow* window, const wxPaneInfo& pane_info)
581 {
582 // check if the pane has a valid window
583 if (!window)
584 return false;
585
586 // check if the pane already exists
587 if (GetPane(pane_info.window).IsOk())
588 return false;
589
590 m_panes.Add(pane_info);
591
592 wxPaneInfo& pinfo = m_panes.Last();
593
594 // set the pane window
595 pinfo.window = window;
596
597 // if the pane's name identifier is blank, create a random string
598 if (pinfo.name.empty())
599 {
600 pinfo.name.Printf(wxT("%08lx%08x%08x%08lx"),
601 ((unsigned long)pinfo.window) & 0xffffffff,
602 (unsigned int)time(NULL),
603 #ifdef __WXWINCE__
604 (unsigned int)GetTickCount(),
605 #else
606 (unsigned int)clock(),
607 #endif
608 (unsigned long)m_panes.GetCount());
609 }
610
611 // set initial proportion (if not already set)
612 if (pinfo.dock_proportion == 0)
613 pinfo.dock_proportion = 100000;
614
615 if (pinfo.HasCloseButton() &&
616 pinfo.buttons.size() == 0)
617 {
618 wxPaneButton button;
619 button.button_id = wxPaneInfo::buttonClose;
620 pinfo.buttons.Add(button);
621 }
622
623 if (pinfo.best_size == wxDefaultSize &&
624 pinfo.window)
625 {
626 pinfo.best_size = pinfo.window->GetClientSize();
627
628 if (pinfo.window->IsKindOf(CLASSINFO(wxToolBar)))
629 {
630 // GetClientSize() doesn't get the best size for
631 // a toolbar under some newer versions of wxWidgets,
632 // so use GetBestSize()
633 pinfo.best_size = pinfo.window->GetBestSize();
634
635 // for some reason, wxToolBar::GetBestSize() is returning
636 // a size that is a pixel shy of the correct amount.
637 // I believe this to be the correct action, until
638 // wxToolBar::GetBestSize() is fixed. Is this assumption
639 // correct?
640 pinfo.best_size.y++;
641 }
642
643 if (pinfo.min_size != wxDefaultSize)
644 {
645 if (pinfo.best_size.x < pinfo.min_size.x)
646 pinfo.best_size.x = pinfo.min_size.x;
647 if (pinfo.best_size.y < pinfo.min_size.y)
648 pinfo.best_size.y = pinfo.min_size.y;
649 }
650 }
651
652 return true;
653 }
654
655 bool wxFrameManager::AddPane(wxWindow* window,
656 int direction,
657 const wxString& caption)
658 {
659 wxPaneInfo pinfo;
660 pinfo.Caption(caption);
661 switch (direction)
662 {
663 case wxTOP: pinfo.Top(); break;
664 case wxBOTTOM: pinfo.Bottom(); break;
665 case wxLEFT: pinfo.Left(); break;
666 case wxRIGHT: pinfo.Right(); break;
667 case wxCENTER: pinfo.CenterPane(); break;
668 }
669 return AddPane(window, pinfo);
670 }
671
672 bool wxFrameManager::InsertPane(wxWindow* window, const wxPaneInfo& pane_info,
673 int insert_level)
674 {
675 // shift the panes around, depending on the insert level
676 switch (insert_level)
677 {
678 case wxAUI_INSERT_PANE:
679 DoInsertPane(m_panes,
680 pane_info.dock_direction,
681 pane_info.dock_layer,
682 pane_info.dock_row,
683 pane_info.dock_pos);
684 break;
685 case wxAUI_INSERT_ROW:
686 DoInsertDockRow(m_panes,
687 pane_info.dock_direction,
688 pane_info.dock_layer,
689 pane_info.dock_row);
690 break;
691 case wxAUI_INSERT_DOCK:
692 DoInsertDockLayer(m_panes,
693 pane_info.dock_direction,
694 pane_info.dock_layer);
695 break;
696 }
697
698 // if the window already exists, we are basically just moving/inserting the
699 // existing window. If it doesn't exist, we need to add it and insert it
700 wxPaneInfo& existing_pane = GetPane(window);
701 if (!existing_pane.IsOk())
702 {
703 return AddPane(window, pane_info);
704 }
705 else
706 {
707 if (pane_info.IsFloating())
708 {
709 existing_pane.Float();
710 if (pane_info.floating_pos != wxDefaultPosition)
711 existing_pane.FloatingPosition(pane_info.floating_pos);
712 if (pane_info.floating_size != wxDefaultSize)
713 existing_pane.FloatingSize(pane_info.floating_size);
714 }
715 else
716 {
717 existing_pane.Direction(pane_info.dock_direction);
718 existing_pane.Layer(pane_info.dock_layer);
719 existing_pane.Row(pane_info.dock_row);
720 existing_pane.Position(pane_info.dock_pos);
721 }
722 }
723
724 return true;
725 }
726
727
728 // DetachPane() removes a pane from the frame manager. This
729 // method will not destroy the window that is removed.
730 bool wxFrameManager::DetachPane(wxWindow* window)
731 {
732 int i, count;
733 for (i = 0, count = m_panes.GetCount(); i < count; ++i)
734 {
735 wxPaneInfo& p = m_panes.Item(i);
736 if (p.window == window)
737 {
738 if (p.frame)
739 {
740 // we have a floating frame which is being detached. We need to
741 // reparent it to m_frame and destroy the floating frame
742
743 // reduce flicker
744 p.window->SetSize(1,1);
745 p.frame->Show(false);
746
747 // reparent to m_frame and destroy the pane
748 p.window->Reparent(m_frame);
749 p.frame->SetSizer(NULL);
750 p.frame->Destroy();
751 p.frame = NULL;
752 }
753 m_panes.RemoveAt(i);
754 return true;
755 }
756 }
757 return false;
758 }
759
760
761 // EscapeDelimiters() changes ";" into "\;" and "|" into "\|"
762 // in the input string. This is an internal functions which is
763 // used for saving perspectives
764 static wxString EscapeDelimiters(const wxString& s)
765 {
766 wxString result;
767 result.Alloc(s.length());
768 const wxChar* ch = s.c_str();
769 while (*ch)
770 {
771 if (*ch == wxT(';') || *ch == wxT('|'))
772 result += wxT('\\');
773 result += *ch;
774 ++ch;
775 }
776 return result;
777 }
778
779
780 // SavePerspective() saves all pane information as a single string.
781 // This string may later be fed into LoadPerspective() to restore
782 // all pane settings. This save and load mechanism allows an
783 // exact pane configuration to be saved and restored at a later time
784
785 wxString wxFrameManager::SavePerspective()
786 {
787 wxString result;
788 result.Alloc(500);
789 result = wxT("layout1|");
790
791 int pane_i, pane_count = m_panes.GetCount();
792 for (pane_i = 0; pane_i < pane_count; ++pane_i)
793 {
794 wxPaneInfo& pane = m_panes.Item(pane_i);
795
796 result += wxT("name=");
797 result += EscapeDelimiters(pane.name);
798 result += wxT(";");
799
800 result += wxT("caption=");
801 result += EscapeDelimiters(pane.caption);
802 result += wxT(";");
803
804 result += wxString::Format(wxT("state=%u;"), pane.state);
805 result += wxString::Format(wxT("dir=%d;"), pane.dock_direction);
806 result += wxString::Format(wxT("layer=%d;"), pane.dock_layer);
807 result += wxString::Format(wxT("row=%d;"), pane.dock_row);
808 result += wxString::Format(wxT("pos=%d;"), pane.dock_pos);
809 result += wxString::Format(wxT("prop=%d;"), pane.dock_proportion);
810 result += wxString::Format(wxT("bestw=%d;"), pane.best_size.x);
811 result += wxString::Format(wxT("besth=%d;"), pane.best_size.y);
812 result += wxString::Format(wxT("minw=%d;"), pane.min_size.x);
813 result += wxString::Format(wxT("minh=%d;"), pane.min_size.y);
814 result += wxString::Format(wxT("maxw=%d;"), pane.max_size.x);
815 result += wxString::Format(wxT("maxh=%d;"), pane.max_size.y);
816 result += wxString::Format(wxT("floatx=%d;"), pane.floating_pos.x);
817 result += wxString::Format(wxT("floaty=%d;"), pane.floating_pos.y);
818 result += wxString::Format(wxT("floatw=%d;"), pane.floating_size.x);
819 result += wxString::Format(wxT("floath=%d"), pane.floating_size.y);
820 result += wxT("|");
821 }
822
823 int dock_i, dock_count = m_docks.GetCount();
824 for (dock_i = 0; dock_i < dock_count; ++dock_i)
825 {
826 wxDockInfo& dock = m_docks.Item(dock_i);
827
828 result += wxString::Format(wxT("dock_size(%d,%d,%d)=%d|"),
829 dock.dock_direction, dock.dock_layer,
830 dock.dock_row, dock.size);
831 }
832
833 return result;
834 }
835
836 // LoadPerspective() loads a layout which was saved with SavePerspective()
837 // If the "update" flag parameter is true, the GUI will immediately be updated
838
839 bool wxFrameManager::LoadPerspective(const wxString& layout, bool update)
840 {
841 wxString input = layout;
842 wxString part;
843
844 // check layout string version
845 part = input.BeforeFirst(wxT('|'));
846 input = input.AfterFirst(wxT('|'));
847 part.Trim(true);
848 part.Trim(false);
849 if (part != wxT("layout1"))
850 return false;
851
852
853 // mark all panes currently managed as docked and hidden
854 int pane_i, pane_count = m_panes.GetCount();
855 for (pane_i = 0; pane_i < pane_count; ++pane_i)
856 m_panes.Item(pane_i).Dock().Hide();
857
858 // clear out the dock array; this will be reconstructed
859 m_docks.Clear();
860
861 // replace escaped characters so we can
862 // split up the string easily
863 input.Replace(wxT("\\|"), wxT("\a"));
864 input.Replace(wxT("\\;"), wxT("\b"));
865
866 while (1)
867 {
868 wxPaneInfo pane;
869
870 wxString pane_part = input.BeforeFirst(wxT('|'));
871 input = input.AfterFirst(wxT('|'));
872 pane_part.Trim(true);
873
874 // if the string is empty, we're done parsing
875 if (pane_part.empty())
876 break;
877
878
879 if (pane_part.Left(9) == wxT("dock_size"))
880 {
881 wxString val_name = pane_part.BeforeFirst(wxT('='));
882 wxString value = pane_part.AfterFirst(wxT('='));
883
884 long dir, layer, row, size;
885 wxString piece = val_name.AfterFirst(wxT('('));
886 piece = piece.BeforeLast(wxT(')'));
887 piece.BeforeFirst(wxT(',')).ToLong(&dir);
888 piece = piece.AfterFirst(wxT(','));
889 piece.BeforeFirst(wxT(',')).ToLong(&layer);
890 piece.AfterFirst(wxT(',')).ToLong(&row);
891 value.ToLong(&size);
892
893 wxDockInfo dock;
894 dock.dock_direction = dir;
895 dock.dock_layer = layer;
896 dock.dock_row = row;
897 dock.size = size;
898 m_docks.Add(dock);
899 continue;
900 }
901
902 while (1)
903 {
904 wxString val_part = pane_part.BeforeFirst(wxT(';'));
905 pane_part = pane_part.AfterFirst(wxT(';'));
906 wxString val_name = val_part.BeforeFirst(wxT('='));
907 wxString value = val_part.AfterFirst(wxT('='));
908 val_name.MakeLower();
909 val_name.Trim(true);
910 val_name.Trim(false);
911 value.Trim(true);
912 value.Trim(false);
913
914 if (val_name.empty())
915 break;
916
917 if (val_name == wxT("name"))
918 pane.name = value;
919 else if (val_name == wxT("caption"))
920 pane.caption = value;
921 else if (val_name == wxT("state"))
922 pane.state = (unsigned int)wxAtoi(value.c_str());
923 else if (val_name == wxT("dir"))
924 pane.dock_direction = wxAtoi(value.c_str());
925 else if (val_name == wxT("layer"))
926 pane.dock_layer = wxAtoi(value.c_str());
927 else if (val_name == wxT("row"))
928 pane.dock_row = wxAtoi(value.c_str());
929 else if (val_name == wxT("pos"))
930 pane.dock_pos = wxAtoi(value.c_str());
931 else if (val_name == wxT("prop"))
932 pane.dock_proportion = wxAtoi(value.c_str());
933 else if (val_name == wxT("bestw"))
934 pane.best_size.x = wxAtoi(value.c_str());
935 else if (val_name == wxT("besth"))
936 pane.best_size.y = wxAtoi(value.c_str());
937 else if (val_name == wxT("minw"))
938 pane.min_size.x = wxAtoi(value.c_str());
939 else if (val_name == wxT("minh"))
940 pane.min_size.y = wxAtoi(value.c_str());
941 else if (val_name == wxT("maxw"))
942 pane.max_size.x = wxAtoi(value.c_str());
943 else if (val_name == wxT("maxh"))
944 pane.max_size.y = wxAtoi(value.c_str());
945 else if (val_name == wxT("floatx"))
946 pane.floating_pos.x = wxAtoi(value.c_str());
947 else if (val_name == wxT("floaty"))
948 pane.floating_pos.y = wxAtoi(value.c_str());
949 else if (val_name == wxT("floatw"))
950 pane.floating_size.x = wxAtoi(value.c_str());
951 else if (val_name == wxT("floath"))
952 pane.floating_size.y = wxAtoi(value.c_str());
953 else {
954 wxFAIL_MSG(wxT("Bad Perspective String"));
955 }
956 }
957
958 // replace escaped characters so we can
959 // split up the string easily
960 pane.name.Replace(wxT("\a"), wxT("|"));
961 pane.name.Replace(wxT("\b"), wxT(";"));
962 pane.caption.Replace(wxT("\a"), wxT("|"));
963 pane.caption.Replace(wxT("\b"), wxT(";"));
964
965 wxPaneInfo& p = GetPane(pane.name);
966 if (!p.IsOk())
967 {
968 // the pane window couldn't be found
969 // in the existing layout
970 return false;
971 }
972
973 pane.window = p.window;
974 pane.frame = p.frame;
975 pane.buttons = p.buttons;
976 p = pane;
977 }
978
979 if (update)
980 Update();
981
982 return true;
983 }
984
985
986 void wxFrameManager::GetPanePositionsAndSizes(wxDockInfo& dock,
987 wxArrayInt& positions,
988 wxArrayInt& sizes)
989 {
990 int caption_size = m_art->GetMetric(wxAUI_ART_CAPTION_SIZE);
991 int pane_border_size = m_art->GetMetric(wxAUI_ART_PANE_BORDER_SIZE);
992 int gripper_size = m_art->GetMetric(wxAUI_ART_GRIPPER_SIZE);
993
994 positions.Empty();
995 sizes.Empty();
996
997 int offset, action_pane = -1;
998 int pane_i, pane_count = dock.panes.GetCount();
999
1000 // find the pane marked as our action pane
1001 for (pane_i = 0; pane_i < pane_count; ++pane_i)
1002 {
1003 wxPaneInfo& pane = *(dock.panes.Item(pane_i));
1004
1005 if (pane.state & wxPaneInfo::actionPane)
1006 {
1007 wxASSERT_MSG(action_pane==-1, wxT("Too many fixed action panes"));
1008 action_pane = pane_i;
1009 }
1010 }
1011
1012 // set up each panes default position, and
1013 // determine the size (width or height, depending
1014 // on the dock's orientation) of each pane
1015 for (pane_i = 0; pane_i < pane_count; ++pane_i)
1016 {
1017 wxPaneInfo& pane = *(dock.panes.Item(pane_i));
1018 positions.Add(pane.dock_pos);
1019 int size = 0;
1020
1021 if (pane.HasBorder())
1022 size += (pane_border_size*2);
1023
1024 if (dock.IsHorizontal())
1025 {
1026 if (pane.HasGripper() && !pane.HasGripperTop())
1027 size += gripper_size;
1028 size += pane.best_size.x;
1029 }
1030 else
1031 {
1032 if (pane.HasGripper() && pane.HasGripperTop())
1033 size += gripper_size;
1034
1035 if (pane.HasCaption())
1036 size += caption_size;
1037 size += pane.best_size.y;
1038 }
1039
1040 sizes.Add(size);
1041 }
1042
1043 // if there is no action pane, just return the default
1044 // positions (as specified in pane.pane_pos)
1045 if (action_pane == -1)
1046 return;
1047
1048 offset = 0;
1049 for (pane_i = action_pane-1; pane_i >= 0; --pane_i)
1050 {
1051 int amount = positions[pane_i+1] - (positions[pane_i] + sizes[pane_i]);
1052
1053 if (amount >= 0)
1054 offset += amount;
1055 else
1056 positions[pane_i] -= -amount;
1057
1058 offset += sizes[pane_i];
1059 }
1060
1061 // if the dock mode is fixed, make sure none of the panes
1062 // overlap; we will bump panes that overlap
1063 offset = 0;
1064 for (pane_i = action_pane; pane_i < pane_count; ++pane_i)
1065 {
1066 int amount = positions[pane_i] - offset;
1067 if (amount >= 0)
1068 offset += amount;
1069 else
1070 positions[pane_i] += -amount;
1071
1072 offset += sizes[pane_i];
1073 }
1074 }
1075
1076
1077 void wxFrameManager::LayoutAddPane(wxSizer* cont,
1078 wxDockInfo& dock,
1079 wxPaneInfo& pane,
1080 wxDockUIPartArray& uiparts,
1081 bool spacer_only)
1082 {
1083 wxDockUIPart part;
1084 wxSizerItem* sizer_item;
1085
1086 int caption_size = m_art->GetMetric(wxAUI_ART_CAPTION_SIZE);
1087 int gripper_size = m_art->GetMetric(wxAUI_ART_GRIPPER_SIZE);
1088 int pane_border_size = m_art->GetMetric(wxAUI_ART_PANE_BORDER_SIZE);
1089 int pane_button_size = m_art->GetMetric(wxAUI_ART_PANE_BUTTON_SIZE);
1090
1091 // find out the orientation of the item (orientation for panes
1092 // is the same as the dock's orientation)
1093 int orientation;
1094 if (dock.IsHorizontal())
1095 orientation = wxHORIZONTAL;
1096 else
1097 orientation = wxVERTICAL;
1098
1099 // this variable will store the proportion
1100 // value that the pane will receive
1101 int pane_proportion = pane.dock_proportion;
1102
1103 wxBoxSizer* horz_pane_sizer = new wxBoxSizer(wxHORIZONTAL);
1104 wxBoxSizer* vert_pane_sizer = new wxBoxSizer(wxVERTICAL);
1105
1106 if (pane.HasGripper())
1107 {
1108 if (pane.HasGripperTop())
1109 sizer_item = vert_pane_sizer ->Add(1, gripper_size, 0, wxEXPAND);
1110 else
1111 sizer_item = horz_pane_sizer ->Add(gripper_size, 1, 0, wxEXPAND);
1112
1113 part.type = wxDockUIPart::typeGripper;
1114 part.dock = &dock;
1115 part.pane = &pane;
1116 part.button = NULL;
1117 part.orientation = orientation;
1118 part.cont_sizer = horz_pane_sizer;
1119 part.sizer_item = sizer_item;
1120 uiparts.Add(part);
1121 }
1122
1123 if (pane.HasCaption())
1124 {
1125 // create the caption sizer
1126 wxBoxSizer* caption_sizer = new wxBoxSizer(wxHORIZONTAL);
1127
1128 sizer_item = caption_sizer->Add(1, caption_size, 1, wxEXPAND);
1129
1130 part.type = wxDockUIPart::typeCaption;
1131 part.dock = &dock;
1132 part.pane = &pane;
1133 part.button = NULL;
1134 part.orientation = orientation;
1135 part.cont_sizer = vert_pane_sizer;
1136 part.sizer_item = sizer_item;
1137 int caption_part_idx = uiparts.GetCount();
1138 uiparts.Add(part);
1139
1140 // add pane buttons to the caption
1141 int i, button_count;
1142 for (i = 0, button_count = pane.buttons.GetCount();
1143 i < button_count; ++i)
1144 {
1145 wxPaneButton& button = pane.buttons.Item(i);
1146
1147 sizer_item = caption_sizer->Add(pane_button_size,
1148 caption_size,
1149 0, wxEXPAND);
1150
1151 part.type = wxDockUIPart::typePaneButton;
1152 part.dock = &dock;
1153 part.pane = &pane;
1154 part.button = &button;
1155 part.orientation = orientation;
1156 part.cont_sizer = caption_sizer;
1157 part.sizer_item = sizer_item;
1158 uiparts.Add(part);
1159 }
1160
1161 // add the caption sizer
1162 sizer_item = vert_pane_sizer->Add(caption_sizer, 0, wxEXPAND);
1163
1164 uiparts.Item(caption_part_idx).sizer_item = sizer_item;
1165 }
1166
1167 // add the pane window itself
1168 if (spacer_only)
1169 {
1170 sizer_item = vert_pane_sizer->Add(1, 1, 1, wxEXPAND);
1171 }
1172 else
1173 {
1174 sizer_item = vert_pane_sizer->Add(pane.window, 1, wxEXPAND);
1175 // Don't do this because it breaks the pane size in floating windows
1176 // BIW: Right now commenting this out is causing problems with
1177 // an mdi client window as the center pane.
1178 vert_pane_sizer->SetItemMinSize(pane.window, 1, 1);
1179 }
1180
1181 part.type = wxDockUIPart::typePane;
1182 part.dock = &dock;
1183 part.pane = &pane;
1184 part.button = NULL;
1185 part.orientation = orientation;
1186 part.cont_sizer = vert_pane_sizer;
1187 part.sizer_item = sizer_item;
1188 uiparts.Add(part);
1189
1190
1191 // determine if the pane should have a minimum size; if the pane is
1192 // non-resizable (fixed) then we must set a minimum size. Alternitavely,
1193 // if the pane.min_size is set, we must use that value as well
1194
1195 wxSize min_size = pane.min_size;
1196 if (pane.IsFixed())
1197 {
1198 if (min_size == wxDefaultSize)
1199 {
1200 min_size = pane.best_size;
1201 pane_proportion = 0;
1202 }
1203 }
1204
1205 if (min_size != wxDefaultSize)
1206 {
1207 vert_pane_sizer->SetItemMinSize(
1208 vert_pane_sizer->GetChildren().GetCount()-1,
1209 min_size.x, min_size.y);
1210 }
1211
1212
1213 // add the verticle sizer (caption, pane window) to the
1214 // horizontal sizer (gripper, verticle sizer)
1215 horz_pane_sizer->Add(vert_pane_sizer, 1, wxEXPAND);
1216
1217 // finally, add the pane sizer to the dock sizer
1218
1219 if (pane.HasBorder())
1220 {
1221 // allowing space for the pane's border
1222 sizer_item = cont->Add(horz_pane_sizer, pane_proportion,
1223 wxEXPAND | wxALL, pane_border_size);
1224
1225 part.type = wxDockUIPart::typePaneBorder;
1226 part.dock = &dock;
1227 part.pane = &pane;
1228 part.button = NULL;
1229 part.orientation = orientation;
1230 part.cont_sizer = cont;
1231 part.sizer_item = sizer_item;
1232 uiparts.Add(part);
1233 }
1234 else
1235 {
1236 sizer_item = cont->Add(horz_pane_sizer, pane_proportion, wxEXPAND);
1237 }
1238 }
1239
1240 void wxFrameManager::LayoutAddDock(wxSizer* cont,
1241 wxDockInfo& dock,
1242 wxDockUIPartArray& uiparts,
1243 bool spacer_only)
1244 {
1245 wxSizerItem* sizer_item;
1246 wxDockUIPart part;
1247
1248 int sash_size = m_art->GetMetric(wxAUI_ART_SASH_SIZE);
1249 int orientation = dock.IsHorizontal() ? wxHORIZONTAL : wxVERTICAL;
1250
1251 // resizable bottom and right docks have a sash before them
1252 if (!dock.fixed && (dock.dock_direction == wxAUI_DOCK_BOTTOM ||
1253 dock.dock_direction == wxAUI_DOCK_RIGHT))
1254 {
1255 sizer_item = cont->Add(sash_size, sash_size, 0, wxEXPAND);
1256
1257 part.type = wxDockUIPart::typeDockSizer;
1258 part.orientation = orientation;
1259 part.dock = &dock;
1260 part.pane = NULL;
1261 part.button = NULL;
1262 part.cont_sizer = cont;
1263 part.sizer_item = sizer_item;
1264 uiparts.Add(part);
1265 }
1266
1267 // create the sizer for the dock
1268 wxSizer* dock_sizer = new wxBoxSizer(orientation);
1269
1270 // add each pane to the dock
1271 int pane_i, pane_count = dock.panes.GetCount();
1272
1273 if (dock.fixed)
1274 {
1275 wxArrayInt pane_positions, pane_sizes;
1276
1277 // figure out the real pane positions we will
1278 // use, without modifying the each pane's pane_pos member
1279 GetPanePositionsAndSizes(dock, pane_positions, pane_sizes);
1280
1281 int offset = 0;
1282 for (pane_i = 0; pane_i < pane_count; ++pane_i)
1283 {
1284 wxPaneInfo& pane = *(dock.panes.Item(pane_i));
1285 int pane_pos = pane_positions.Item(pane_i);
1286
1287 int amount = pane_pos - offset;
1288 if (amount > 0)
1289 {
1290 if (dock.IsVertical())
1291 sizer_item = dock_sizer->Add(1, amount, 0, wxEXPAND);
1292 else
1293 sizer_item = dock_sizer->Add(amount, 1, 0, wxEXPAND);
1294
1295 part.type = wxDockUIPart::typeBackground;
1296 part.dock = &dock;
1297 part.pane = NULL;
1298 part.button = NULL;
1299 part.orientation = (orientation==wxHORIZONTAL) ? wxVERTICAL:wxHORIZONTAL;
1300 part.cont_sizer = dock_sizer;
1301 part.sizer_item = sizer_item;
1302 uiparts.Add(part);
1303
1304 offset += amount;
1305 }
1306
1307 LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only);
1308
1309 offset += pane_sizes.Item(pane_i);
1310 }
1311
1312 // at the end add a very small stretchable background area
1313 sizer_item = dock_sizer->Add(1,1, 1, wxEXPAND);
1314
1315 part.type = wxDockUIPart::typeBackground;
1316 part.dock = &dock;
1317 part.pane = NULL;
1318 part.button = NULL;
1319 part.orientation = orientation;
1320 part.cont_sizer = dock_sizer;
1321 part.sizer_item = sizer_item;
1322 uiparts.Add(part);
1323 }
1324 else
1325 {
1326 for (pane_i = 0; pane_i < pane_count; ++pane_i)
1327 {
1328 wxPaneInfo& pane = *(dock.panes.Item(pane_i));
1329
1330 // if this is not the first pane being added,
1331 // we need to add a pane sizer
1332 if (pane_i > 0)
1333 {
1334 sizer_item = dock_sizer->Add(sash_size, sash_size, 0, wxEXPAND);
1335
1336 part.type = wxDockUIPart::typePaneSizer;
1337 part.dock = &dock;
1338 part.pane = dock.panes.Item(pane_i-1);
1339 part.button = NULL;
1340 part.orientation = (orientation==wxHORIZONTAL) ? wxVERTICAL:wxHORIZONTAL;
1341 part.cont_sizer = dock_sizer;
1342 part.sizer_item = sizer_item;
1343 uiparts.Add(part);
1344 }
1345
1346 LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only);
1347 }
1348 }
1349
1350 if (dock.dock_direction == wxAUI_DOCK_CENTER)
1351 sizer_item = cont->Add(dock_sizer, 1, wxEXPAND);
1352 else
1353 sizer_item = cont->Add(dock_sizer, 0, wxEXPAND);
1354
1355 part.type = wxDockUIPart::typeDock;
1356 part.dock = &dock;
1357 part.pane = NULL;
1358 part.button = NULL;
1359 part.orientation = orientation;
1360 part.cont_sizer = cont;
1361 part.sizer_item = sizer_item;
1362 uiparts.Add(part);
1363
1364 if (dock.IsHorizontal())
1365 cont->SetItemMinSize(dock_sizer, 0, dock.size);
1366 else
1367 cont->SetItemMinSize(dock_sizer, dock.size, 0);
1368
1369 // top and left docks have a sash after them
1370 if (!dock.fixed && (dock.dock_direction == wxAUI_DOCK_TOP ||
1371 dock.dock_direction == wxAUI_DOCK_LEFT))
1372 {
1373 sizer_item = cont->Add(sash_size, sash_size, 0, wxEXPAND);
1374
1375 part.type = wxDockUIPart::typeDockSizer;
1376 part.dock = &dock;
1377 part.pane = NULL;
1378 part.button = NULL;
1379 part.orientation = orientation;
1380 part.cont_sizer = cont;
1381 part.sizer_item = sizer_item;
1382 uiparts.Add(part);
1383 }
1384 }
1385
1386 wxSizer* wxFrameManager::LayoutAll(wxPaneInfoArray& panes,
1387 wxDockInfoArray& docks,
1388 wxDockUIPartArray& uiparts,
1389 bool spacer_only)
1390 {
1391 wxBoxSizer* container = new wxBoxSizer(wxVERTICAL);
1392
1393 int pane_border_size = m_art->GetMetric(wxAUI_ART_PANE_BORDER_SIZE);
1394 int caption_size = m_art->GetMetric(wxAUI_ART_CAPTION_SIZE);
1395 wxSize cli_size = m_frame->GetClientSize();
1396 int i, dock_count, pane_count;
1397
1398
1399 // empty all docks out
1400 for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i)
1401 docks.Item(i).panes.Empty();
1402
1403 // iterate through all known panes, filing each
1404 // of them into the appropriate dock. If the
1405 // pane does not exist in the dock, add it
1406 for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i)
1407 {
1408 wxPaneInfo& p = panes.Item(i);
1409
1410 // find any docks in this layer
1411 wxDockInfo* dock;
1412 wxDockInfoPtrArray arr;
1413 FindDocks(docks, p.dock_direction, p.dock_layer, p.dock_row, arr);
1414
1415 if (arr.GetCount() > 0)
1416 {
1417 dock = arr.Item(0);
1418 }
1419 else
1420 {
1421 // dock was not found, so we need to create a new one
1422 wxDockInfo d;
1423 d.dock_direction = p.dock_direction;
1424 d.dock_layer = p.dock_layer;
1425 d.dock_row = p.dock_row;
1426 docks.Add(d);
1427 dock = &docks.Last();
1428 }
1429
1430
1431 if (p.IsDocked() && p.IsShown())
1432 {
1433 // remove the pane from any existing docks except this one
1434 RemovePaneFromDocks(docks, p, dock);
1435
1436 // pane needs to be added to the dock,
1437 // if it doesn't already exist
1438 if (!FindPaneInDock(*dock, p.window))
1439 dock->panes.Add(&p);
1440 }
1441 else
1442 {
1443 // remove the pane from any existing docks
1444 RemovePaneFromDocks(docks, p);
1445 }
1446
1447 }
1448
1449 // remove any empty docks
1450 for (i = docks.GetCount()-1; i >= 0; --i)
1451 {
1452 if (docks.Item(i).panes.GetCount() == 0)
1453 docks.RemoveAt(i);
1454 }
1455
1456 // configure the docks further
1457 for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i)
1458 {
1459 wxDockInfo& dock = docks.Item(i);
1460 int j, dock_pane_count = dock.panes.GetCount();
1461
1462 // sort the dock pane array by the pane's
1463 // dock position (dock_pos), in ascending order
1464 dock.panes.Sort(PaneSortFunc);
1465
1466 // for newly created docks, set up their initial size
1467 if (dock.size == 0)
1468 {
1469 int size = 0;
1470
1471 for (j = 0; j < dock_pane_count; ++j)
1472 {
1473 wxPaneInfo& pane = *dock.panes.Item(j);
1474 wxSize pane_size = pane.best_size;
1475 if (pane_size == wxDefaultSize)
1476 pane_size = pane.min_size;
1477 if (pane_size == wxDefaultSize)
1478 pane_size = pane.window->GetSize();
1479
1480 if (dock.IsHorizontal())
1481 size = wxMax(pane_size.y, size);
1482 else
1483 size = wxMax(pane_size.x, size);
1484 }
1485
1486 // add space for the border (two times), but only
1487 // if at least one pane inside the dock has a pane border
1488 for (j = 0; j < dock_pane_count; ++j)
1489 {
1490 if (dock.panes.Item(j)->HasBorder())
1491 {
1492 size += (pane_border_size*2);
1493 break;
1494 }
1495 }
1496
1497 // if pane is on the top or bottom, add the caption height,
1498 // but only if at least one pane inside the dock has a caption
1499 if (dock.IsHorizontal())
1500 {
1501 for (j = 0; j < dock_pane_count; ++j)
1502 {
1503 if (dock.panes.Item(j)->HasCaption())
1504 {
1505 size += caption_size;
1506 break;
1507 }
1508 }
1509 }
1510
1511 // new dock's size may not be more than 1/3 of the frame size
1512 if (dock.IsHorizontal())
1513 size = wxMin(size, cli_size.y/3);
1514 else
1515 size = wxMin(size, cli_size.x/3);
1516
1517 if (size < 10)
1518 size = 10;
1519 dock.size = size;
1520 }
1521
1522
1523 // determine the dock's minimum size
1524 bool plus_border = false;
1525 bool plus_caption = false;
1526 int dock_min_size = 0;
1527 for (j = 0; j < dock_pane_count; ++j)
1528 {
1529 wxPaneInfo& pane = *dock.panes.Item(j);
1530 if (pane.min_size != wxDefaultSize)
1531 {
1532 if (pane.HasBorder())
1533 plus_border = true;
1534 if (pane.HasCaption())
1535 plus_caption = true;
1536 if (dock.IsHorizontal())
1537 {
1538 if (pane.min_size.y > dock_min_size)
1539 dock_min_size = pane.min_size.y;
1540 }
1541 else
1542 {
1543 if (pane.min_size.x > dock_min_size)
1544 dock_min_size = pane.min_size.x;
1545 }
1546 }
1547 }
1548
1549 if (plus_border)
1550 dock_min_size += (pane_border_size*2);
1551 if (plus_caption && dock.IsHorizontal())
1552 dock_min_size += (caption_size);
1553
1554 dock.min_size = dock_min_size;
1555
1556
1557 // if the pane's current size is less than it's
1558 // minimum, increase the dock's size to it's minimum
1559 if (dock.size < dock.min_size)
1560 dock.size = dock.min_size;
1561
1562
1563 // determine the dock's mode (fixed or proportional);
1564 // determine whether the dock has only toolbars
1565 bool action_pane_marked = false;
1566 dock.fixed = true;
1567 dock.toolbar = true;
1568 for (j = 0; j < dock_pane_count; ++j)
1569 {
1570 wxPaneInfo& pane = *dock.panes.Item(j);
1571 if (!pane.IsFixed())
1572 dock.fixed = false;
1573 if (!pane.IsToolbar())
1574 dock.toolbar = false;
1575 if (pane.state & wxPaneInfo::actionPane)
1576 action_pane_marked = true;
1577 }
1578
1579
1580 // if the dock mode is proportional and not fixed-pixel,
1581 // reassign the dock_pos to the sequential 0, 1, 2, 3;
1582 // e.g. remove gaps like 1, 2, 30, 500
1583 if (!dock.fixed)
1584 {
1585 for (j = 0; j < dock_pane_count; ++j)
1586 {
1587 wxPaneInfo& pane = *dock.panes.Item(j);
1588 pane.dock_pos = j;
1589 }
1590 }
1591
1592 // if the dock mode is fixed, and none of the panes
1593 // are being moved right now, make sure the panes
1594 // do not overlap each other. If they do, we will
1595 // adjust the panes' positions
1596 if (dock.fixed && !action_pane_marked)
1597 {
1598 wxArrayInt pane_positions, pane_sizes;
1599 GetPanePositionsAndSizes(dock, pane_positions, pane_sizes);
1600
1601 int offset = 0;
1602 for (j = 0; j < dock_pane_count; ++j)
1603 {
1604 wxPaneInfo& pane = *(dock.panes.Item(j));
1605 pane.dock_pos = pane_positions[j];
1606
1607 int amount = pane.dock_pos - offset;
1608 if (amount >= 0)
1609 offset += amount;
1610 else
1611 pane.dock_pos += -amount;
1612
1613 offset += pane_sizes[j];
1614 }
1615 }
1616 }
1617
1618 // discover the maximum dock layer
1619 int max_layer = 0;
1620 for (i = 0; i < dock_count; ++i)
1621 max_layer = wxMax(max_layer, docks.Item(i).dock_layer);
1622
1623
1624 // clear out uiparts
1625 uiparts.Empty();
1626
1627 // create a bunch of box sizers,
1628 // from the innermost level outwards.
1629 wxSizer* cont = NULL;
1630 wxSizer* middle = NULL;
1631 int layer = 0;
1632 int row, row_count;
1633
1634 for (layer = 0; layer <= max_layer; ++layer)
1635 {
1636 wxDockInfoPtrArray arr;
1637
1638 // find any docks in this layer
1639 FindDocks(docks, -1, layer, -1, arr);
1640
1641 // if there aren't any, skip to the next layer
1642 if (arr.IsEmpty())
1643 continue;
1644
1645 wxSizer* old_cont = cont;
1646
1647 // create a container which will hold this layer's
1648 // docks (top, bottom, left, right)
1649 cont = new wxBoxSizer(wxVERTICAL);
1650
1651
1652 // find any top docks in this layer
1653 FindDocks(docks, wxAUI_DOCK_TOP, layer, -1, arr);
1654 RenumberDockRows(arr);
1655 if (!arr.IsEmpty())
1656 {
1657 for (row = 0, row_count = arr.GetCount(); row < row_count; ++row)
1658 LayoutAddDock(cont, *arr.Item(row), uiparts, spacer_only);
1659 }
1660
1661
1662 // fill out the middle layer (which consists
1663 // of left docks, content area and right docks)
1664
1665 middle = new wxBoxSizer(wxHORIZONTAL);
1666
1667 // find any left docks in this layer
1668 FindDocks(docks, wxAUI_DOCK_LEFT, layer, -1, arr);
1669 RenumberDockRows(arr);
1670 if (!arr.IsEmpty())
1671 {
1672 for (row = 0, row_count = arr.GetCount(); row < row_count; ++row)
1673 LayoutAddDock(middle, *arr.Item(row), uiparts, spacer_only);
1674 }
1675
1676 // add content dock (or previous layer's sizer
1677 // to the middle
1678 if (!old_cont)
1679 {
1680 // find any center docks
1681 FindDocks(docks, wxAUI_DOCK_CENTER, -1, -1, arr);
1682 if (!arr.IsEmpty())
1683 {
1684 for (row = 0,row_count = arr.GetCount(); row<row_count; ++row)
1685 LayoutAddDock(middle, *arr.Item(row), uiparts, spacer_only);
1686 }
1687 else
1688 {
1689 // there are no center docks, add a background area
1690 wxSizerItem* sizer_item = middle->Add(1,1, 1, wxEXPAND);
1691 wxDockUIPart part;
1692 part.type = wxDockUIPart::typeBackground;
1693 part.pane = NULL;
1694 part.dock = NULL;
1695 part.button = NULL;
1696 part.cont_sizer = middle;
1697 part.sizer_item = sizer_item;
1698 uiparts.Add(part);
1699 }
1700 }
1701 else
1702 {
1703 middle->Add(old_cont, 1, wxEXPAND);
1704 }
1705
1706 // find any right docks in this layer
1707 FindDocks(docks, wxAUI_DOCK_RIGHT, layer, -1, arr);
1708 RenumberDockRows(arr);
1709 if (!arr.IsEmpty())
1710 {
1711 for (row = arr.GetCount()-1; row >= 0; --row)
1712 LayoutAddDock(middle, *arr.Item(row), uiparts, spacer_only);
1713 }
1714
1715 cont->Add(middle, 1, wxEXPAND);
1716
1717
1718
1719 // find any bottom docks in this layer
1720 FindDocks(docks, wxAUI_DOCK_BOTTOM, layer, -1, arr);
1721 RenumberDockRows(arr);
1722 if (!arr.IsEmpty())
1723 {
1724 for (row = arr.GetCount()-1; row >= 0; --row)
1725 LayoutAddDock(cont, *arr.Item(row), uiparts, spacer_only);
1726 }
1727
1728 }
1729
1730 if (!cont)
1731 {
1732 // no sizer available, because there are no docks,
1733 // therefore we will create a simple background area
1734 cont = new wxBoxSizer(wxVERTICAL);
1735 wxSizerItem* sizer_item = cont->Add(1,1, 1, wxEXPAND);
1736 wxDockUIPart part;
1737 part.type = wxDockUIPart::typeBackground;
1738 part.pane = NULL;
1739 part.dock = NULL;
1740 part.button = NULL;
1741 part.cont_sizer = middle;
1742 part.sizer_item = sizer_item;
1743 uiparts.Add(part);
1744 }
1745
1746 container->Add(cont, 1, wxEXPAND);
1747 return container;
1748 }
1749
1750
1751 // Update() updates the layout. Whenever changes are made to
1752 // one or more panes, this function should be called. It is the
1753 // external entry point for running the layout engine.
1754
1755 void wxFrameManager::Update()
1756 {
1757 wxSizer* sizer;
1758 int i, pane_count = m_panes.GetCount();
1759
1760 // delete old sizer first
1761 m_frame->SetSizer(NULL);
1762
1763 // destroy floating panes which have been
1764 // redocked or are becoming non-floating
1765 for (i = 0; i < pane_count; ++i)
1766 {
1767 wxPaneInfo& p = m_panes.Item(i);
1768
1769 if (!p.IsFloating() && p.frame)
1770 {
1771 // because the pane is no longer in a floating, we need to
1772 // reparent it to m_frame and destroy the floating frame
1773
1774 // reduce flicker
1775 p.window->SetSize(1,1);
1776 p.frame->Show(false);
1777
1778 // reparent to m_frame and destroy the pane
1779 p.window->Reparent(m_frame);
1780 p.frame->SetSizer(NULL);
1781 p.frame->Destroy();
1782 p.frame = NULL;
1783 }
1784 }
1785
1786
1787 // create a layout for all of the panes
1788 sizer = LayoutAll(m_panes, m_docks, m_uiparts, false);
1789
1790 // hide or show panes as necessary,
1791 // and float panes as necessary
1792 for (i = 0; i < pane_count; ++i)
1793 {
1794 wxPaneInfo& p = m_panes.Item(i);
1795
1796 if (p.IsFloating())
1797 {
1798 if (p.frame == NULL)
1799 {
1800 // we need to create a frame for this
1801 // pane, which has recently been floated
1802 wxFloatingPane* frame = new wxFloatingPane(m_frame,
1803 this,
1804 p);
1805
1806 // on MSW and Mac, if the owner desires transparent dragging, and
1807 // the dragging is happening right now, then the floating
1808 // window should have this style by default
1809 if (m_action == actionDragFloatingPane &&
1810 (m_flags & wxAUI_MGR_TRANSPARENT_DRAG))
1811 frame->SetTranslucency(150);
1812
1813 frame->SetPaneWindow(p);
1814 p.frame = frame;
1815
1816 if (p.IsShown())
1817 {
1818 frame->Show();
1819 }
1820 }
1821 else
1822 {
1823 // frame already exists, make sure it's position
1824 // and size reflect the information in wxPaneInfo
1825 if (p.frame->GetPosition() != p.floating_pos)
1826 {
1827 p.frame->SetSize(p.floating_pos.x, p.floating_pos.y,
1828 wxDefaultCoord, wxDefaultCoord,
1829 wxSIZE_USE_EXISTING);
1830 //p.frame->Move(p.floating_pos.x, p.floating_pos.y);
1831 }
1832
1833 p.frame->Show(p.IsShown());
1834 }
1835 }
1836 else
1837 {
1838 p.window->Show(p.IsShown());
1839 }
1840
1841 // if "active panes" are no longer allowed, clear
1842 // any optionActive values from the pane states
1843 if ((m_flags & wxAUI_MGR_ALLOW_ACTIVE_PANE) == 0)
1844 {
1845 p.state &= ~wxPaneInfo::optionActive;
1846 }
1847 }
1848
1849
1850 // keep track of the old window rectangles so we can
1851 // refresh those windows whose rect has changed
1852 wxAuiRectArray old_pane_rects;
1853 for (i = 0; i < pane_count; ++i)
1854 {
1855 wxRect r;
1856 wxPaneInfo& p = m_panes.Item(i);
1857
1858 if (p.window && p.IsShown() && p.IsDocked())
1859 r = p.rect;
1860
1861 old_pane_rects.Add(r);
1862 }
1863
1864
1865
1866
1867 // apply the new sizer
1868 m_frame->SetSizer(sizer);
1869 m_frame->SetAutoLayout(false);
1870 DoFrameLayout();
1871
1872
1873
1874 // now that the frame layout is done, we need to check
1875 // the new pane rectangles against the old rectangles that
1876 // we saved a few lines above here. If the rectangles have
1877 // changed, the corresponding panes must also be updated
1878 for (i = 0; i < pane_count; ++i)
1879 {
1880 wxPaneInfo& p = m_panes.Item(i);
1881 if (p.window && p.window->IsShown() && p.IsDocked())
1882 {
1883 if (p.rect != old_pane_rects[i])
1884 {
1885 p.window->Refresh();
1886 p.window->Update();
1887 }
1888 }
1889 }
1890
1891
1892 Repaint();
1893
1894 // set frame's minimum size
1895
1896 /*
1897 // N.B. More work needs to be done on frame minimum sizes;
1898 // this is some intresting code that imposes the minimum size,
1899 // but we may want to include a more flexible mechanism or
1900 // options for multiple minimum-size modes, e.g. strict or lax
1901 wxSize min_size = sizer->GetMinSize();
1902 wxSize frame_size = m_frame->GetSize();
1903 wxSize client_size = m_frame->GetClientSize();
1904
1905 wxSize minframe_size(min_size.x+frame_size.x-client_size.x,
1906 min_size.y+frame_size.y-client_size.y );
1907
1908 m_frame->SetMinSize(minframe_size);
1909
1910 if (frame_size.x < minframe_size.x ||
1911 frame_size.y < minframe_size.y)
1912 sizer->Fit(m_frame);
1913 */
1914 }
1915
1916
1917 // DoFrameLayout() is an internal function which invokes wxSizer::Layout
1918 // on the frame's main sizer, then measures all the various UI items
1919 // and updates their internal rectangles. This should always be called
1920 // instead of calling m_frame->Layout() directly
1921
1922 void wxFrameManager::DoFrameLayout()
1923 {
1924 m_frame->Layout();
1925
1926 int i, part_count;
1927 for (i = 0, part_count = m_uiparts.GetCount(); i < part_count; ++i)
1928 {
1929 wxDockUIPart& part = m_uiparts.Item(i);
1930
1931 // get the rectangle of the UI part
1932 // originally, this code looked like this:
1933 // part.rect = wxRect(part.sizer_item->GetPosition(),
1934 // part.sizer_item->GetSize());
1935 // this worked quite well, with one exception: the mdi
1936 // client window had a "deferred" size variable
1937 // that returned the wrong size. It looks like
1938 // a bug in wx, because the former size of the window
1939 // was being returned. So, we will retrieve the part's
1940 // rectangle via other means
1941
1942
1943 part.rect = part.sizer_item->GetRect();
1944 int flag = part.sizer_item->GetFlag();
1945 int border = part.sizer_item->GetBorder();
1946 if (flag & wxTOP)
1947 {
1948 part.rect.y -= border;
1949 part.rect.height += border;
1950 }
1951 if (flag & wxLEFT)
1952 {
1953 part.rect.x -= border;
1954 part.rect.width += border;
1955 }
1956 if (flag & wxBOTTOM)
1957 part.rect.height += border;
1958 if (flag & wxRIGHT)
1959 part.rect.width += border;
1960
1961
1962 if (part.type == wxDockUIPart::typeDock)
1963 part.dock->rect = part.rect;
1964 if (part.type == wxDockUIPart::typePane)
1965 part.pane->rect = part.rect;
1966 }
1967 }
1968
1969 // GetPanePart() looks up the pane the pane border UI part (or the regular
1970 // pane part if there is no border). This allows the caller to get the exact
1971 // rectangle of the pane in question, including decorations like
1972 // caption and border (if any).
1973
1974 wxDockUIPart* wxFrameManager::GetPanePart(wxWindow* wnd)
1975 {
1976 int i, part_count;
1977 for (i = 0, part_count = m_uiparts.GetCount(); i < part_count; ++i)
1978 {
1979 wxDockUIPart& part = m_uiparts.Item(i);
1980 if (part.type == wxDockUIPart::typePaneBorder &&
1981 part.pane && part.pane->window == wnd)
1982 return &part;
1983 }
1984 for (i = 0, part_count = m_uiparts.GetCount(); i < part_count; ++i)
1985 {
1986 wxDockUIPart& part = m_uiparts.Item(i);
1987 if (part.type == wxDockUIPart::typePane &&
1988 part.pane && part.pane->window == wnd)
1989 return &part;
1990 }
1991 return NULL;
1992 }
1993
1994
1995
1996 // GetDockPixelOffset() is an internal function which returns
1997 // a dock's offset in pixels from the left side of the window
1998 // (for horizontal docks) or from the top of the window (for
1999 // vertical docks). This value is necessary for calculating
2000 // fixel-pane/toolbar offsets when they are dragged.
2001
2002 int wxFrameManager::GetDockPixelOffset(wxPaneInfo& test)
2003 {
2004 // the only way to accurately calculate the dock's
2005 // offset is to actually run a theoretical layout
2006
2007 int i, part_count, dock_count;
2008 wxDockInfoArray docks;
2009 wxPaneInfoArray panes;
2010 wxDockUIPartArray uiparts;
2011 CopyDocksAndPanes(docks, panes, m_docks, m_panes);
2012 panes.Add(test);
2013
2014 wxSizer* sizer = LayoutAll(panes, docks, uiparts, true);
2015 wxSize client_size = m_frame->GetClientSize();
2016 sizer->SetDimension(0, 0, client_size.x, client_size.y);
2017 sizer->Layout();
2018
2019 for (i = 0, part_count = uiparts.GetCount(); i < part_count; ++i)
2020 {
2021 wxDockUIPart& part = uiparts.Item(i);
2022 part.rect = wxRect(part.sizer_item->GetPosition(),
2023 part.sizer_item->GetSize());
2024 if (part.type == wxDockUIPart::typeDock)
2025 part.dock->rect = part.rect;
2026 }
2027
2028 delete sizer;
2029
2030 for (i = 0, dock_count = docks.GetCount(); i < dock_count; ++i)
2031 {
2032 wxDockInfo& dock = docks.Item(i);
2033 if (test.dock_direction == dock.dock_direction &&
2034 test.dock_layer==dock.dock_layer && test.dock_row==dock.dock_row)
2035 {
2036 if (dock.IsVertical())
2037 return dock.rect.y;
2038 else
2039 return dock.rect.x;
2040 }
2041 }
2042
2043 return 0;
2044 }
2045
2046
2047
2048 // ProcessDockResult() is a utility function used by DoDrop() - it checks
2049 // if a dock operation is allowed, the new dock position is copied into
2050 // the target info. If the operation was allowed, the function returns true.
2051
2052 bool wxFrameManager::ProcessDockResult(wxPaneInfo& target,
2053 const wxPaneInfo& new_pos)
2054 {
2055 bool allowed = false;
2056 switch (new_pos.dock_direction)
2057 {
2058 case wxAUI_DOCK_TOP: allowed = target.IsTopDockable(); break;
2059 case wxAUI_DOCK_BOTTOM: allowed = target.IsBottomDockable(); break;
2060 case wxAUI_DOCK_LEFT: allowed = target.IsLeftDockable(); break;
2061 case wxAUI_DOCK_RIGHT: allowed = target.IsRightDockable(); break;
2062 }
2063
2064 if (allowed)
2065 target = new_pos;
2066
2067 return allowed;
2068 }
2069
2070
2071 // DoDrop() is an important function. It basically takes a mouse position,
2072 // and determines where the pane's new position would be. If the pane is to be
2073 // dropped, it performs the drop operation using the specified dock and pane
2074 // arrays. By specifying copied dock and pane arrays when calling, a "what-if"
2075 // scenario can be performed, giving precise coordinates for drop hints.
2076 // If, however, wxFrameManager:m_docks and wxFrameManager::m_panes are specified
2077 // as parameters, the changes will be made to the main state arrays
2078
2079 const int auiInsertRowPixels = 10;
2080 const int auiNewRowPixels = 40;
2081 const int auiLayerInsertPixels = 40;
2082 const int auiLayerInsertOffset = 5;
2083
2084 bool wxFrameManager::DoDrop(wxDockInfoArray& docks,
2085 wxPaneInfoArray& panes,
2086 wxPaneInfo& target,
2087 const wxPoint& pt,
2088 const wxPoint& offset)
2089 {
2090 wxSize cli_size = m_frame->GetClientSize();
2091
2092 wxPaneInfo drop = target;
2093
2094
2095 // The result should always be shown
2096 drop.Show();
2097
2098
2099 // Check to see if the pane has been dragged outside of the window
2100 // (or near to the outside of the window), if so, dock it along the edge
2101
2102
2103 int layer_insert_offset = auiLayerInsertOffset;
2104 if (target.IsToolbar())
2105 layer_insert_offset = 0;
2106
2107 if (pt.x < layer_insert_offset &&
2108 pt.x > layer_insert_offset-auiLayerInsertPixels)
2109 {
2110 int new_layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_LEFT),
2111 GetMaxLayer(docks, wxAUI_DOCK_BOTTOM)),
2112 GetMaxLayer(docks, wxAUI_DOCK_TOP)) + 1;
2113 drop.Dock().Left().
2114 Layer(new_layer).
2115 Row(0).
2116 Position(pt.y - GetDockPixelOffset(drop) - offset.y);
2117 return ProcessDockResult(target, drop);
2118 }
2119 else if (pt.y < layer_insert_offset &&
2120 pt.y > layer_insert_offset-auiLayerInsertPixels)
2121 {
2122 int new_layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_TOP),
2123 GetMaxLayer(docks, wxAUI_DOCK_LEFT)),
2124 GetMaxLayer(docks, wxAUI_DOCK_RIGHT)) + 1;
2125 drop.Dock().Top().
2126 Layer(new_layer).
2127 Row(0).
2128 Position(pt.x - GetDockPixelOffset(drop) - offset.x);
2129 return ProcessDockResult(target, drop);
2130 }
2131 else if (pt.x >= cli_size.x - layer_insert_offset &&
2132 pt.x < cli_size.x - layer_insert_offset + auiLayerInsertPixels)
2133 {
2134 int new_layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_RIGHT),
2135 GetMaxLayer(docks, wxAUI_DOCK_TOP)),
2136 GetMaxLayer(docks, wxAUI_DOCK_BOTTOM)) + 1;
2137 drop.Dock().Right().
2138 Layer(new_layer).
2139 Row(0).
2140 Position(pt.y - GetDockPixelOffset(drop) - offset.y);
2141 return ProcessDockResult(target, drop);
2142 }
2143 else if (pt.y >= cli_size.y - layer_insert_offset &&
2144 pt.y < cli_size.y - layer_insert_offset + auiLayerInsertPixels)
2145 {
2146 int new_layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_BOTTOM),
2147 GetMaxLayer(docks, wxAUI_DOCK_LEFT)),
2148 GetMaxLayer(docks, wxAUI_DOCK_RIGHT)) + 1;
2149 drop.Dock().Bottom().
2150 Layer(new_layer).
2151 Row(0).
2152 Position(pt.x - GetDockPixelOffset(drop) - offset.x);
2153 return ProcessDockResult(target, drop);
2154 }
2155
2156
2157 wxDockUIPart* part = HitTest(pt.x, pt.y);
2158
2159
2160 if (drop.IsToolbar())
2161 {
2162 if (!part || !part->dock)
2163 return false;
2164
2165
2166 // calculate the offset from where the dock begins
2167 // to the point where the user dropped the pane
2168 int dock_drop_offset = 0;
2169 if (part->dock->IsHorizontal())
2170 dock_drop_offset = pt.x - part->dock->rect.x - offset.x;
2171 else
2172 dock_drop_offset = pt.y - part->dock->rect.y - offset.y;
2173
2174
2175 // toolbars may only be moved in and to fixed-pane docks,
2176 // otherwise we will try to float the pane. Also, the pane
2177 // should float if being dragged over center pane windows
2178 if (!part->dock->fixed || part->dock->dock_direction == wxAUI_DOCK_CENTER)
2179 {
2180 if ((m_flags & wxAUI_MGR_ALLOW_FLOATING) &&
2181 (drop.IsFloatable() ||
2182 (part->dock->dock_direction != wxAUI_DOCK_CENTER &&
2183 part->dock->dock_direction != wxAUI_DOCK_NONE)))
2184 {
2185 drop.Float();
2186 }
2187
2188 return ProcessDockResult(target, drop);
2189 }
2190
2191 drop.Dock().
2192 Direction(part->dock->dock_direction).
2193 Layer(part->dock->dock_layer).
2194 Row(part->dock->dock_row).
2195 Position(dock_drop_offset);
2196
2197 if ((
2198 ((pt.y < part->dock->rect.y + 2) && part->dock->IsHorizontal()) ||
2199 ((pt.x < part->dock->rect.x + 2) && part->dock->IsVertical())
2200 ) && part->dock->panes.GetCount() > 1)
2201 {
2202 int row = drop.dock_row;
2203 DoInsertDockRow(panes, part->dock->dock_direction,
2204 part->dock->dock_layer,
2205 part->dock->dock_row);
2206 drop.dock_row = row;
2207 }
2208
2209 if ((
2210 ((pt.y > part->dock->rect.y + part->dock->rect.height - 2 ) && part->dock->IsHorizontal()) ||
2211 ((pt.x > part->dock->rect.x + part->dock->rect.width - 2 ) && part->dock->IsVertical())
2212 ) && part->dock->panes.GetCount() > 1)
2213 {
2214 DoInsertDockRow(panes, part->dock->dock_direction,
2215 part->dock->dock_layer,
2216 part->dock->dock_row+1);
2217 drop.dock_row = part->dock->dock_row+1;
2218 }
2219
2220 return ProcessDockResult(target, drop);
2221 }
2222
2223
2224
2225
2226 if (!part)
2227 return false;
2228
2229 if (part->type == wxDockUIPart::typePaneBorder ||
2230 part->type == wxDockUIPart::typeCaption ||
2231 part->type == wxDockUIPart::typeGripper ||
2232 part->type == wxDockUIPart::typePaneButton ||
2233 part->type == wxDockUIPart::typePane ||
2234 part->type == wxDockUIPart::typePaneSizer ||
2235 part->type == wxDockUIPart::typeDockSizer ||
2236 part->type == wxDockUIPart::typeBackground)
2237 {
2238 if (part->type == wxDockUIPart::typeDockSizer)
2239 {
2240 if (part->dock->panes.GetCount() != 1)
2241 return false;
2242 part = GetPanePart(part->dock->panes.Item(0)->window);
2243 if (!part)
2244 return false;
2245 }
2246
2247
2248
2249 // If a normal frame is being dragged over a toolbar, insert it
2250 // along the edge under the toolbar, but over all other panes.
2251 // (this could be done much better, but somehow factoring this
2252 // calculation with the one at the beginning of this function)
2253 if (part->dock && part->dock->toolbar)
2254 {
2255 int layer = 0;
2256
2257 switch (part->dock->dock_direction)
2258 {
2259 case wxAUI_DOCK_LEFT:
2260 layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_LEFT),
2261 GetMaxLayer(docks, wxAUI_DOCK_BOTTOM)),
2262 GetMaxLayer(docks, wxAUI_DOCK_TOP));
2263 break;
2264 case wxAUI_DOCK_TOP:
2265 layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_TOP),
2266 GetMaxLayer(docks, wxAUI_DOCK_LEFT)),
2267 GetMaxLayer(docks, wxAUI_DOCK_RIGHT));
2268 break;
2269 case wxAUI_DOCK_RIGHT:
2270 layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_RIGHT),
2271 GetMaxLayer(docks, wxAUI_DOCK_TOP)),
2272 GetMaxLayer(docks, wxAUI_DOCK_BOTTOM));
2273 break;
2274 case wxAUI_DOCK_BOTTOM:
2275 layer = wxMax(wxMax(GetMaxLayer(docks, wxAUI_DOCK_BOTTOM),
2276 GetMaxLayer(docks, wxAUI_DOCK_LEFT)),
2277 GetMaxLayer(docks, wxAUI_DOCK_RIGHT));
2278 break;
2279 }
2280
2281 DoInsertDockRow(panes, part->dock->dock_direction,
2282 layer, 0);
2283 drop.Dock().
2284 Direction(part->dock->dock_direction).
2285 Layer(layer).Row(0).Position(0);
2286 return ProcessDockResult(target, drop);
2287 }
2288
2289
2290 if (!part->pane)
2291 return false;
2292
2293 part = GetPanePart(part->pane->window);
2294 if (!part)
2295 return false;
2296
2297 bool insert_dock_row = false;
2298 int insert_row = part->pane->dock_row;
2299 int insert_dir = part->pane->dock_direction;
2300 int insert_layer = part->pane->dock_layer;
2301
2302 switch (part->pane->dock_direction)
2303 {
2304 case wxAUI_DOCK_TOP:
2305 if (pt.y >= part->rect.y &&
2306 pt.y < part->rect.y+auiInsertRowPixels)
2307 insert_dock_row = true;
2308 break;
2309 case wxAUI_DOCK_BOTTOM:
2310 if (pt.y > part->rect.y+part->rect.height-auiInsertRowPixels &&
2311 pt.y <= part->rect.y + part->rect.height)
2312 insert_dock_row = true;
2313 break;
2314 case wxAUI_DOCK_LEFT:
2315 if (pt.x >= part->rect.x &&
2316 pt.x < part->rect.x+auiInsertRowPixels)
2317 insert_dock_row = true;
2318 break;
2319 case wxAUI_DOCK_RIGHT:
2320 if (pt.x > part->rect.x+part->rect.width-auiInsertRowPixels &&
2321 pt.x <= part->rect.x+part->rect.width)
2322 insert_dock_row = true;
2323 break;
2324 case wxAUI_DOCK_CENTER:
2325 {
2326 // "new row pixels" will be set to the default, but
2327 // must never exceed 20% of the window size
2328 int new_row_pixels_x = auiNewRowPixels;
2329 int new_row_pixels_y = auiNewRowPixels;
2330
2331 if (new_row_pixels_x > (part->rect.width*20)/100)
2332 new_row_pixels_x = (part->rect.width*20)/100;
2333
2334 if (new_row_pixels_y > (part->rect.height*20)/100)
2335 new_row_pixels_y = (part->rect.height*20)/100;
2336
2337
2338 // determine if the mouse pointer is in a location that
2339 // will cause a new row to be inserted. The hot spot positions
2340 // are along the borders of the center pane
2341
2342 insert_layer = 0;
2343 insert_dock_row = true;
2344 if (pt.x >= part->rect.x &&
2345 pt.x < part->rect.x+new_row_pixels_x)
2346 insert_dir = wxAUI_DOCK_LEFT;
2347 else
2348 if (pt.y >= part->rect.y &&
2349 pt.y < part->rect.y+new_row_pixels_y)
2350 insert_dir = wxAUI_DOCK_TOP;
2351 else
2352 if (pt.x >= part->rect.x + part->rect.width-new_row_pixels_x &&
2353 pt.x < part->rect.x + part->rect.width)
2354 insert_dir = wxAUI_DOCK_RIGHT;
2355 else
2356 if (pt.y >= part->rect.y+ part->rect.height-new_row_pixels_y &&
2357 pt.y < part->rect.y + part->rect.height)
2358 insert_dir = wxAUI_DOCK_BOTTOM;
2359 else
2360 return false;
2361
2362 insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1;
2363 }
2364 }
2365
2366 if (insert_dock_row)
2367 {
2368 DoInsertDockRow(panes, insert_dir, insert_layer, insert_row);
2369 drop.Dock().Direction(insert_dir).
2370 Layer(insert_layer).
2371 Row(insert_row).
2372 Position(0);
2373 return ProcessDockResult(target, drop);
2374 }
2375
2376 // determine the mouse offset and the pane size, both in the
2377 // direction of the dock itself, and perpendicular to the dock
2378
2379 int offset, size;
2380
2381 if (part->orientation == wxVERTICAL)
2382 {
2383 offset = pt.y - part->rect.y;
2384 size = part->rect.GetHeight();
2385 }
2386 else
2387 {
2388 offset = pt.x - part->rect.x;
2389 size = part->rect.GetWidth();
2390 }
2391
2392 int drop_position = part->pane->dock_pos;
2393
2394 // if we are in the top/left part of the pane,
2395 // insert the pane before the pane being hovered over
2396 if (offset <= size/2)
2397 {
2398 drop_position = part->pane->dock_pos;
2399 DoInsertPane(panes,
2400 part->pane->dock_direction,
2401 part->pane->dock_layer,
2402 part->pane->dock_row,
2403 part->pane->dock_pos);
2404 }
2405
2406 // if we are in the bottom/right part of the pane,
2407 // insert the pane before the pane being hovered over
2408 if (offset > size/2)
2409 {
2410 drop_position = part->pane->dock_pos+1;
2411 DoInsertPane(panes,
2412 part->pane->dock_direction,
2413 part->pane->dock_layer,
2414 part->pane->dock_row,
2415 part->pane->dock_pos+1);
2416 }
2417
2418 drop.Dock().
2419 Direction(part->dock->dock_direction).
2420 Layer(part->dock->dock_layer).
2421 Row(part->dock->dock_row).
2422 Position(drop_position);
2423 return ProcessDockResult(target, drop);
2424 }
2425
2426 return false;
2427 }
2428
2429
2430 void wxFrameManager::OnHintFadeTimer(wxTimerEvent& WXUNUSED(event))
2431 {
2432 if (!m_hint_wnd || m_hint_fadeamt >= 50)
2433 {
2434 m_hint_fadetimer.Stop();
2435 return;
2436 }
2437
2438 m_hint_fadeamt += 5;
2439 m_hint_wnd->SetTranslucency(m_hint_fadeamt);
2440 }
2441
2442 void wxFrameManager::ShowHint(const wxRect& rect)
2443 {
2444 if ((m_flags & wxAUI_MGR_TRANSPARENT_HINT) != 0 && m_hint_wnd)
2445 {
2446 if (m_last_hint == rect)
2447 return;
2448 m_last_hint = rect;
2449
2450 int initial_fade = 50;
2451 if (m_flags & wxAUI_MGR_TRANSPARENT_HINT_FADE)
2452 initial_fade = 0;
2453
2454 if (! m_hint_wnd->IsShown())
2455 m_hint_wnd->Show();
2456
2457 // if we are dragging a floating pane, set the focus
2458 // back to that floating pane (otherwise it becomes unfocused)
2459 if (m_action == actionDragFloatingPane && m_action_window)
2460 m_action_window->SetFocus();
2461
2462 m_hint_wnd->SetTranslucency(initial_fade);
2463 m_hint_wnd->SetSize(rect);
2464 m_hint_wnd->Raise();
2465
2466
2467 if (m_flags & wxAUI_MGR_TRANSPARENT_HINT_FADE)
2468 {
2469 // start fade in timer
2470 m_hint_fadeamt = 0;
2471 m_hint_fadetimer.SetOwner(this, 101);
2472 m_hint_fadetimer.Start(5);
2473 }
2474 }
2475
2476 else // Not using a translucent hint window...
2477 {
2478
2479 if (m_last_hint != rect)
2480 {
2481 // remove the last hint rectangle
2482 m_last_hint = rect;
2483 m_frame->Refresh();
2484 m_frame->Update();
2485 }
2486
2487 wxScreenDC screendc;
2488 wxRegion clip(1, 1, 10000, 10000);
2489
2490 // clip all floating windows, so we don't draw over them
2491 int i, pane_count;
2492 for (i = 0, pane_count = m_panes.GetCount(); i < pane_count; ++i)
2493 {
2494 wxPaneInfo& pane = m_panes.Item(i);
2495
2496 if (pane.IsFloating() &&
2497 pane.frame->IsShown())
2498 {
2499 wxRect rect = pane.frame->GetRect();
2500 #ifdef __WXGTK__
2501 // wxGTK returns the client size, not the whole frame size
2502 rect.width += 15;
2503 rect.height += 35;
2504 rect.Inflate(5);
2505 #endif
2506
2507 clip.Subtract(rect);
2508 }
2509 }
2510
2511 screendc.SetClippingRegion(clip);
2512
2513 wxBitmap stipple = wxPaneCreateStippleBitmap();
2514 wxBrush brush(stipple);
2515 screendc.SetBrush(brush);
2516 screendc.SetPen(*wxTRANSPARENT_PEN);
2517
2518 screendc.DrawRectangle(rect.x, rect.y, 5, rect.height);
2519 screendc.DrawRectangle(rect.x+5, rect.y, rect.width-10, 5);
2520 screendc.DrawRectangle(rect.x+rect.width-5, rect.y, 5, rect.height);
2521 screendc.DrawRectangle(rect.x+5, rect.y+rect.height-5, rect.width-10, 5);
2522 }
2523 }
2524
2525 void wxFrameManager::HideHint()
2526 {
2527 // hides a transparent window hint, if there is one
2528 if (m_hint_wnd)
2529 {
2530 m_hint_wnd->SetTranslucency(0);
2531 m_hint_fadetimer.Stop();
2532 m_last_hint = wxRect();
2533 return;
2534 }
2535
2536 // hides a painted hint by redrawing the frame window
2537 if (!m_last_hint.IsEmpty())
2538 {
2539 m_frame->Refresh();
2540 m_frame->Update();
2541 m_last_hint = wxRect();
2542 }
2543 }
2544
2545
2546
2547 // DrawHintRect() draws a drop hint rectangle. First calls DoDrop() to
2548 // determine the exact position the pane would be at were if dropped. If
2549 // the pame would indeed become docked at the specified drop point,
2550 // DrawHintRect() then calls ShowHint() to indicate this drop rectangle.
2551 // "pane_window" is the window pointer of the pane being dragged, pt is
2552 // the mouse position, in client coordinates
2553 void wxFrameManager::DrawHintRect(wxWindow* pane_window,
2554 const wxPoint& pt,
2555 const wxPoint& offset)
2556 {
2557 wxRect rect;
2558
2559 // we need to paint a hint rectangle; to find out the exact hint rectangle,
2560 // we will create a new temporary layout and then measure the resulting
2561 // rectangle; we will create a copy of the docking structures (m_dock)
2562 // so that we don't modify the real thing on screen
2563
2564 int i, pane_count, part_count;
2565 wxDockInfoArray docks;
2566 wxPaneInfoArray panes;
2567 wxDockUIPartArray uiparts;
2568 wxPaneInfo hint = GetPane(pane_window);
2569 hint.name = wxT("__HINT__");
2570 hint.Show();
2571
2572 if (!hint.IsOk())
2573 return;
2574
2575 CopyDocksAndPanes(docks, panes, m_docks, m_panes);
2576
2577 // remove any pane already there which bears the same window;
2578 // this happens when you are moving a pane around in a dock
2579 for (i = 0, pane_count = panes.GetCount(); i < pane_count; ++i)
2580 {
2581 if (panes.Item(i).window == pane_window)
2582 {
2583 RemovePaneFromDocks(docks, panes.Item(i));
2584 panes.RemoveAt(i);
2585 break;
2586 }
2587 }
2588
2589 // find out where the new pane would be
2590 if (!DoDrop(docks, panes, hint, pt, offset))
2591 {
2592 HideHint();
2593 return;
2594 }
2595
2596 panes.Add(hint);
2597
2598 wxSizer* sizer = LayoutAll(panes, docks, uiparts, true);
2599 wxSize client_size = m_frame->GetClientSize();
2600 sizer->SetDimension(0, 0, client_size.x, client_size.y);
2601 sizer->Layout();
2602
2603 for (i = 0, part_count = uiparts.GetCount();
2604 i < part_count; ++i)
2605 {
2606 wxDockUIPart& part = uiparts.Item(i);
2607
2608 if (part.type == wxDockUIPart::typePaneBorder &&
2609 part.pane && part.pane->name == wxT("__HINT__"))
2610 {
2611 rect = wxRect(part.sizer_item->GetPosition(),
2612 part.sizer_item->GetSize());
2613 break;
2614 }
2615 }
2616
2617 delete sizer;
2618
2619 if (rect.IsEmpty())
2620 {
2621 HideHint();
2622 return;
2623 }
2624
2625 // actually show the hint rectangle on the screen
2626 m_frame->ClientToScreen(&rect.x, &rect.y);
2627 ShowHint(rect);
2628 }
2629
2630 void wxFrameManager::OnFloatingPaneMoveStart(wxWindow* wnd)
2631 {
2632 // try to find the pane
2633 wxPaneInfo& pane = GetPane(wnd);
2634 wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
2635
2636 if (m_flags & wxAUI_MGR_TRANSPARENT_DRAG)
2637 pane.frame->SetTranslucency(150);
2638 }
2639
2640 void wxFrameManager::OnFloatingPaneMoving(wxWindow* wnd)
2641 {
2642 // try to find the pane
2643 wxPaneInfo& pane = GetPane(wnd);
2644 wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
2645
2646 wxPoint pt = ::wxGetMousePosition();
2647 wxPoint client_pt = m_frame->ScreenToClient(pt);
2648
2649 // calculate the offset from the upper left-hand corner
2650 // of the frame to the mouse pointer
2651 wxPoint frame_pos = pane.frame->GetPosition();
2652 wxPoint action_offset(pt.x-frame_pos.x, pt.y-frame_pos.y);
2653
2654 // no hint for toolbar floating windows
2655 if (pane.IsToolbar() && m_action == actionDragFloatingPane)
2656 {
2657 if (m_action == actionDragFloatingPane)
2658 {
2659 wxDockInfoArray docks;
2660 wxPaneInfoArray panes;
2661 wxDockUIPartArray uiparts;
2662 wxPaneInfo hint = pane;
2663
2664 CopyDocksAndPanes(docks, panes, m_docks, m_panes);
2665
2666 // find out where the new pane would be
2667 if (!DoDrop(docks, panes, hint, client_pt))
2668 return;
2669 if (hint.IsFloating())
2670 return;
2671
2672 pane = hint;
2673 m_action = actionDragToolbarPane;
2674 m_action_window = pane.window;
2675
2676 Update();
2677 }
2678
2679 return;
2680 }
2681
2682
2683 // if a key modifier is pressed while dragging the frame,
2684 // don't dock the window
2685 if (wxGetKeyState(WXK_CONTROL) || wxGetKeyState(WXK_ALT))
2686 {
2687 HideHint();
2688 return;
2689 }
2690
2691
2692 DrawHintRect(wnd, client_pt, action_offset);
2693
2694 #ifdef __WXGTK__
2695 // this cleans up some screen artifacts that are caused on GTK because
2696 // we aren't getting the exact size of the window (see comment
2697 // in DrawHintRect)
2698 //Refresh();
2699 #endif
2700
2701
2702 // reduces flicker
2703 m_frame->Update();
2704 }
2705
2706 void wxFrameManager::OnFloatingPaneMoved(wxWindow* wnd)
2707 {
2708 // try to find the pane
2709 wxPaneInfo& pane = GetPane(wnd);
2710 wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
2711
2712 wxPoint pt = ::wxGetMousePosition();
2713 wxPoint client_pt = m_frame->ScreenToClient(pt);
2714
2715 // calculate the offset from the upper left-hand corner
2716 // of the frame to the mouse pointer
2717 wxPoint frame_pos = pane.frame->GetPosition();
2718 wxPoint action_offset(pt.x-frame_pos.x, pt.y-frame_pos.y);
2719
2720
2721 // if a key modifier is pressed while dragging the frame,
2722 // don't dock the window
2723 if (!wxGetKeyState(WXK_CONTROL) && !wxGetKeyState(WXK_ALT))
2724 {
2725 // do the drop calculation
2726 DoDrop(m_docks, m_panes, pane, client_pt, action_offset);
2727 }
2728
2729 // if the pane is still floating, update it's floating
2730 // position (that we store)
2731 if (pane.IsFloating())
2732 {
2733 pane.floating_pos = pane.frame->GetPosition();
2734
2735 if (m_flags & wxAUI_MGR_TRANSPARENT_DRAG)
2736 pane.frame->SetTranslucency(255);
2737 }
2738
2739 Update();
2740
2741 HideHint();
2742 }
2743
2744 void wxFrameManager::OnFloatingPaneResized(wxWindow* wnd, const wxSize& size)
2745 {
2746 // try to find the pane
2747 wxPaneInfo& pane = GetPane(wnd);
2748 wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
2749
2750 pane.floating_size = size;
2751 }
2752
2753
2754 void wxFrameManager::OnFloatingPaneClosed(wxWindow* wnd, wxCloseEvent& evt)
2755 {
2756 // try to find the pane
2757 wxPaneInfo& pane = GetPane(wnd);
2758 wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
2759
2760
2761 // fire pane close event
2762 wxFrameManagerEvent e(wxEVT_AUI_PANECLOSE);
2763 e.SetPane(&pane);
2764 e.SetCanVeto(evt.CanVeto());
2765 ProcessMgrEvent(e);
2766
2767 if (e.GetVeto())
2768 {
2769 evt.Veto();
2770 return;
2771 }
2772 else
2773 {
2774 // reparent the pane window back to us and
2775 // prepare the frame window for destruction
2776 pane.window->Show(false);
2777 pane.window->Reparent(m_frame);
2778 pane.frame = NULL;
2779 pane.Hide();
2780 }
2781 }
2782
2783
2784
2785 void wxFrameManager::OnFloatingPaneActivated(wxWindow* wnd)
2786 {
2787 if (GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE)
2788 {
2789 // try to find the pane
2790 wxASSERT_MSG(GetPane(wnd).IsOk(), wxT("Pane window not found"));
2791
2792 SetActivePane(m_panes, wnd);
2793 Repaint();
2794 }
2795 }
2796
2797 // OnRender() draws all of the pane captions, sashes,
2798 // backgrounds, captions, grippers, pane borders and buttons.
2799 // It renders the entire user interface.
2800
2801 void wxFrameManager::OnRender(wxFrameManagerEvent& evt)
2802 {
2803 wxDC* dc = evt.GetDC();
2804
2805 #ifdef __WXMAC__
2806 dc->Clear() ;
2807 #endif
2808 int i, part_count;
2809 for (i = 0, part_count = m_uiparts.GetCount();
2810 i < part_count; ++i)
2811 {
2812 wxDockUIPart& part = m_uiparts.Item(i);
2813
2814 // don't draw hidden pane items
2815 if (part.sizer_item && !part.sizer_item->IsShown())
2816 continue;
2817
2818 switch (part.type)
2819 {
2820 case wxDockUIPart::typeDockSizer:
2821 case wxDockUIPart::typePaneSizer:
2822 m_art->DrawSash(*dc, part.orientation, part.rect);
2823 break;
2824 case wxDockUIPart::typeBackground:
2825 m_art->DrawBackground(*dc, part.orientation, part.rect);
2826 break;
2827 case wxDockUIPart::typeCaption:
2828 m_art->DrawCaption(*dc, part.pane->caption, part.rect, *part.pane);
2829 break;
2830 case wxDockUIPart::typeGripper:
2831 m_art->DrawGripper(*dc, part.rect, *part.pane);
2832 break;
2833 case wxDockUIPart::typePaneBorder:
2834 m_art->DrawBorder(*dc, part.rect, *part.pane);
2835 break;
2836 case wxDockUIPart::typePaneButton:
2837 m_art->DrawPaneButton(*dc, part.button->button_id,
2838 wxAUI_BUTTON_STATE_NORMAL, part.rect, *part.pane);
2839 break;
2840 }
2841 }
2842 }
2843
2844
2845 // Render() fire a render event, which is normally handled by
2846 // wxFrameManager::OnRender(). This allows the render function to
2847 // be overridden via the render event. This can be useful for paintin
2848 // custom graphics in the main window. Default behavior can be
2849 // invoked in the overridden function by calling OnRender()
2850
2851 void wxFrameManager::Render(wxDC* dc)
2852 {
2853 wxFrameManagerEvent e(wxEVT_AUI_RENDER);
2854 e.SetDC(dc);
2855 ProcessMgrEvent(e);
2856 }
2857
2858 void wxFrameManager::Repaint(wxDC* dc)
2859 {
2860 #ifdef __WXMAC__
2861 if ( dc == NULL )
2862 {
2863 m_frame->Refresh() ;
2864 m_frame->Update() ;
2865 return ;
2866 }
2867 #endif
2868 int w, h;
2869 m_frame->GetClientSize(&w, &h);
2870
2871 // figure out which dc to use; if one
2872 // has been specified, use it, otherwise
2873 // make a client dc
2874 wxClientDC* client_dc = NULL;
2875 if (!dc)
2876 {
2877 client_dc = new wxClientDC(m_frame);
2878 dc = client_dc;
2879 }
2880
2881 // if the frame has a toolbar, the client area
2882 // origin will not be (0,0).
2883 wxPoint pt = m_frame->GetClientAreaOrigin();
2884 if (pt.x != 0 || pt.y != 0)
2885 dc->SetDeviceOrigin(pt.x, pt.y);
2886
2887 // render all the items
2888 Render(dc);
2889
2890 // if we created a client_dc, delete it
2891 if (client_dc)
2892 delete client_dc;
2893 }
2894
2895 void wxFrameManager::OnPaint(wxPaintEvent& WXUNUSED(event))
2896 {
2897 wxPaintDC dc(m_frame);
2898 Repaint(&dc);
2899 }
2900
2901 void wxFrameManager::OnEraseBackground(wxEraseEvent& event)
2902 {
2903 #ifdef __WXMAC__
2904 event.Skip() ;
2905 #else
2906 wxUnusedVar(event);
2907 #endif
2908 }
2909
2910 void wxFrameManager::OnSize(wxSizeEvent& WXUNUSED(event))
2911 {
2912 if (m_frame)
2913 {
2914 DoFrameLayout();
2915 Repaint();
2916 }
2917 }
2918
2919
2920 void wxFrameManager::OnSetCursor(wxSetCursorEvent& event)
2921 {
2922 // determine cursor
2923 wxDockUIPart* part = HitTest(event.GetX(), event.GetY());
2924 wxCursor cursor = wxNullCursor;
2925
2926 if (part)
2927 {
2928 if (part->type == wxDockUIPart::typeDockSizer ||
2929 part->type == wxDockUIPart::typePaneSizer)
2930 {
2931 // a dock may not be resized if it has a single
2932 // pane which is not resizable
2933 if (part->type == wxDockUIPart::typeDockSizer && part->dock &&
2934 part->dock->panes.GetCount() == 1 &&
2935 part->dock->panes.Item(0)->IsFixed())
2936 return;
2937
2938 // panes that may not be resized do not get a sizing cursor
2939 if (part->pane && part->pane->IsFixed())
2940 return;
2941
2942 if (part->orientation == wxVERTICAL)
2943 cursor = wxCursor(wxCURSOR_SIZEWE);
2944 else
2945 cursor = wxCursor(wxCURSOR_SIZENS);
2946 }
2947 else if (part->type == wxDockUIPart::typeGripper)
2948 {
2949 cursor = wxCursor(wxCURSOR_SIZING);
2950 }
2951 }
2952
2953 event.SetCursor(cursor);
2954 }
2955
2956
2957
2958 void wxFrameManager::UpdateButtonOnScreen(wxDockUIPart* button_ui_part,
2959 const wxMouseEvent& event)
2960 {
2961 wxDockUIPart* hit_test = HitTest(event.GetX(), event.GetY());
2962
2963 int state = wxAUI_BUTTON_STATE_NORMAL;
2964
2965 if (hit_test == button_ui_part)
2966 {
2967 if (event.LeftDown())
2968 state = wxAUI_BUTTON_STATE_PRESSED;
2969 else
2970 state = wxAUI_BUTTON_STATE_HOVER;
2971 }
2972 else
2973 {
2974 if (event.LeftDown())
2975 state = wxAUI_BUTTON_STATE_HOVER;
2976 }
2977
2978 // now repaint the button with hover state
2979 wxClientDC cdc(m_frame);
2980
2981 // if the frame has a toolbar, the client area
2982 // origin will not be (0,0).
2983 wxPoint pt = m_frame->GetClientAreaOrigin();
2984 if (pt.x != 0 || pt.y != 0)
2985 cdc.SetDeviceOrigin(pt.x, pt.y);
2986
2987 m_art->DrawPaneButton(cdc,
2988 button_ui_part->button->button_id,
2989 state,
2990 button_ui_part->rect,
2991 *hit_test->pane);
2992 }
2993
2994 void wxFrameManager::OnLeftDown(wxMouseEvent& event)
2995 {
2996 wxDockUIPart* part = HitTest(event.GetX(), event.GetY());
2997 if (part)
2998 {
2999 if (part->dock && part->dock->dock_direction == wxAUI_DOCK_CENTER)
3000 return;
3001
3002 if (part->type == wxDockUIPart::typeDockSizer ||
3003 part->type == wxDockUIPart::typePaneSizer)
3004 {
3005 // a dock may not be resized if it has a single
3006 // pane which is not resizable
3007 if (part->type == wxDockUIPart::typeDockSizer && part->dock &&
3008 part->dock->panes.GetCount() == 1 &&
3009 part->dock->panes.Item(0)->IsFixed())
3010 return;
3011
3012 // panes that may not be resized should be ignored here
3013 if (part->pane && part->pane->IsFixed())
3014 return;
3015
3016 m_action = actionResize;
3017 m_action_part = part;
3018 m_action_hintrect = wxRect();
3019 m_action_start = wxPoint(event.m_x, event.m_y);
3020 m_action_offset = wxPoint(event.m_x - part->rect.x,
3021 event.m_y - part->rect.y);
3022 m_frame->CaptureMouse();
3023 }
3024 else if (part->type == wxDockUIPart::typePaneButton)
3025 {
3026 m_action = actionClickButton;
3027 m_action_part = part;
3028 m_action_start = wxPoint(event.m_x, event.m_y);
3029 m_frame->CaptureMouse();
3030
3031 UpdateButtonOnScreen(part, event);
3032 }
3033 else if (part->type == wxDockUIPart::typeCaption ||
3034 part->type == wxDockUIPart::typeGripper)
3035 {
3036 if (GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE)
3037 {
3038 // set the caption as active
3039 SetActivePane(m_panes, part->pane->window);
3040 Repaint();
3041 }
3042
3043 m_action = actionClickCaption;
3044 m_action_part = part;
3045 m_action_start = wxPoint(event.m_x, event.m_y);
3046 m_action_offset = wxPoint(event.m_x - part->rect.x,
3047 event.m_y - part->rect.y);
3048 m_frame->CaptureMouse();
3049 }
3050 #ifdef __WXMAC__
3051 else
3052 {
3053 event.Skip();
3054 }
3055 #endif
3056 }
3057 #ifdef __WXMAC__
3058 else
3059 {
3060 event.Skip();
3061 }
3062 #else
3063 event.Skip();
3064 #endif
3065 }
3066
3067
3068 void wxFrameManager::OnLeftUp(wxMouseEvent& event)
3069 {
3070 if (m_action == actionResize)
3071 {
3072 m_frame->ReleaseMouse();
3073
3074 // get rid of the hint rectangle
3075 wxScreenDC dc;
3076 DrawResizeHint(dc, m_action_hintrect);
3077
3078 // resize the dock or the pane
3079 if (m_action_part && m_action_part->type==wxDockUIPart::typeDockSizer)
3080 {
3081 wxRect& rect = m_action_part->dock->rect;
3082
3083 wxPoint new_pos(event.m_x - m_action_offset.x,
3084 event.m_y - m_action_offset.y);
3085
3086 switch (m_action_part->dock->dock_direction)
3087 {
3088 case wxAUI_DOCK_LEFT:
3089 m_action_part->dock->size = new_pos.x - rect.x;
3090 break;
3091 case wxAUI_DOCK_TOP:
3092 m_action_part->dock->size = new_pos.y - rect.y;
3093 break;
3094 case wxAUI_DOCK_RIGHT:
3095 m_action_part->dock->size = rect.x + rect.width -
3096 new_pos.x - m_action_part->rect.GetWidth();
3097 break;
3098 case wxAUI_DOCK_BOTTOM:
3099 m_action_part->dock->size = rect.y + rect.height -
3100 new_pos.y - m_action_part->rect.GetHeight();
3101 break;
3102 }
3103
3104 Update();
3105 Repaint(NULL);
3106 }
3107 else if (m_action_part &&
3108 m_action_part->type == wxDockUIPart::typePaneSizer)
3109 {
3110 wxDockInfo& dock = *m_action_part->dock;
3111 wxPaneInfo& pane = *m_action_part->pane;
3112
3113 int total_proportion = 0;
3114 int dock_pixels = 0;
3115 int new_pixsize = 0;
3116
3117 int caption_size = m_art->GetMetric(wxAUI_ART_CAPTION_SIZE);
3118 int pane_border_size = m_art->GetMetric(wxAUI_ART_PANE_BORDER_SIZE);
3119 int sash_size = m_art->GetMetric(wxAUI_ART_SASH_SIZE);
3120
3121 wxPoint new_pos(event.m_x - m_action_offset.x,
3122 event.m_y - m_action_offset.y);
3123
3124 // determine the pane rectangle by getting the pane part
3125 wxDockUIPart* pane_part = GetPanePart(pane.window);
3126 wxASSERT_MSG(pane_part,
3127 wxT("Pane border part not found -- shouldn't happen"));
3128
3129 // determine the new pixel size that the user wants;
3130 // this will help us recalculate the pane's proportion
3131 if (dock.IsHorizontal())
3132 new_pixsize = new_pos.x - pane_part->rect.x;
3133 else
3134 new_pixsize = new_pos.y - pane_part->rect.y;
3135
3136 // determine the size of the dock, based on orientation
3137 if (dock.IsHorizontal())
3138 dock_pixels = dock.rect.GetWidth();
3139 else
3140 dock_pixels = dock.rect.GetHeight();
3141
3142 // determine the total proportion of all resizable panes,
3143 // and the total size of the dock minus the size of all
3144 // the fixed panes
3145 int i, dock_pane_count = dock.panes.GetCount();
3146 int pane_position = -1;
3147 for (i = 0; i < dock_pane_count; ++i)
3148 {
3149 wxPaneInfo& p = *dock.panes.Item(i);
3150 if (p.window == pane.window)
3151 pane_position = i;
3152
3153 // while we're at it, subtract the pane sash
3154 // width from the dock width, because this would
3155 // skew our proportion calculations
3156 if (i > 0)
3157 dock_pixels -= sash_size;
3158
3159 // also, the whole size (including decorations) of
3160 // all fixed panes must also be subtracted, because they
3161 // are not part of the proportion calculation
3162 if (p.IsFixed())
3163 {
3164 if (dock.IsHorizontal())
3165 dock_pixels -= p.best_size.x;
3166 else
3167 dock_pixels -= p.best_size.y;
3168 }
3169 else
3170 {
3171 total_proportion += p.dock_proportion;
3172 }
3173 }
3174
3175 // find a pane in our dock to 'steal' space from or to 'give'
3176 // space to -- this is essentially what is done when a pane is
3177 // resized; the pane should usually be the first non-fixed pane
3178 // to the right of the action pane
3179 int borrow_pane = -1;
3180 for (i = pane_position+1; i < dock_pane_count; ++i)
3181 {
3182 wxPaneInfo& p = *dock.panes.Item(i);
3183 if (!p.IsFixed())
3184 {
3185 borrow_pane = i;
3186 break;
3187 }
3188 }
3189
3190
3191 // demand that the pane being resized is found in this dock
3192 // (this assert really never should be raised)
3193 wxASSERT_MSG(pane_position != -1, wxT("Pane not found in dock"));
3194
3195 // prevent division by zero
3196 if (dock_pixels == 0 || total_proportion == 0 || borrow_pane == -1)
3197 {
3198 m_action = actionNone;
3199 return;
3200 }
3201
3202 // calculate the new proportion of the pane
3203 int new_proportion = (new_pixsize*total_proportion)/dock_pixels;
3204
3205 // default minimum size
3206 int min_size = 0;
3207
3208 // check against the pane's minimum size, if specified. please note
3209 // that this is not enough to ensure that the minimum size will
3210 // not be violated, because the whole frame might later be shrunk,
3211 // causing the size of the pane to violate it's minimum size
3212 if (pane.min_size.IsFullySpecified())
3213 {
3214 min_size = 0;
3215
3216 if (pane.HasBorder())
3217 min_size += (pane_border_size*2);
3218
3219 // calculate minimum size with decorations (border,caption)
3220 if (pane_part->orientation == wxVERTICAL)
3221 {
3222 min_size += pane.min_size.y;
3223 if (pane.HasCaption())
3224 min_size += caption_size;
3225 }
3226 else
3227 {
3228 min_size += pane.min_size.x;
3229 }
3230 }
3231
3232
3233 // for some reason, an arithmatic error somewhere is causing
3234 // the proportion calculations to always be off by 1 pixel;
3235 // for now we will add the 1 pixel on, but we really should
3236 // determine what's causing this.
3237 min_size++;
3238
3239 int min_proportion = (min_size*total_proportion)/dock_pixels;
3240
3241 if (new_proportion < min_proportion)
3242 new_proportion = min_proportion;
3243
3244
3245
3246 int prop_diff = new_proportion - pane.dock_proportion;
3247
3248 // borrow the space from our neighbor pane to the
3249 // right or bottom (depending on orientation)
3250 dock.panes.Item(borrow_pane)->dock_proportion -= prop_diff;
3251 pane.dock_proportion = new_proportion;
3252
3253 // repaint
3254 Update();
3255 Repaint(NULL);
3256 }
3257 }
3258 else if (m_action == actionClickButton)
3259 {
3260 m_hover_button = NULL;
3261 m_frame->ReleaseMouse();
3262 UpdateButtonOnScreen(m_action_part, event);
3263
3264 // make sure we're still over the item that was originally clicked
3265 if (m_action_part == HitTest(event.GetX(), event.GetY()))
3266 {
3267 // fire button-click event
3268 wxFrameManagerEvent e(wxEVT_AUI_PANEBUTTON);
3269 e.SetPane(m_action_part->pane);
3270 e.SetButton(m_action_part->button->button_id);
3271 ProcessMgrEvent(e);
3272 }
3273 }
3274 else if (m_action == actionClickCaption)
3275 {
3276 m_frame->ReleaseMouse();
3277 }
3278 else if (m_action == actionDragFloatingPane)
3279 {
3280 m_frame->ReleaseMouse();
3281 }
3282 else if (m_action == actionDragToolbarPane)
3283 {
3284 m_frame->ReleaseMouse();
3285
3286 wxPaneInfo& pane = GetPane(m_action_window);
3287 wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
3288
3289 // save the new positions
3290 wxDockInfoPtrArray docks;
3291 FindDocks(m_docks, pane.dock_direction,
3292 pane.dock_layer, pane.dock_row, docks);
3293 if (docks.GetCount() == 1)
3294 {
3295 wxDockInfo& dock = *docks.Item(0);
3296
3297 wxArrayInt pane_positions, pane_sizes;
3298 GetPanePositionsAndSizes(dock, pane_positions, pane_sizes);
3299
3300 int i, dock_pane_count = dock.panes.GetCount();
3301 for (i = 0; i < dock_pane_count; ++i)
3302 dock.panes.Item(i)->dock_pos = pane_positions[i];
3303 }
3304
3305 pane.state &= ~wxPaneInfo::actionPane;
3306 Update();
3307 }
3308 else
3309 {
3310 event.Skip();
3311 }
3312
3313 m_action = actionNone;
3314 m_last_mouse_move = wxPoint(); // see comment in OnMotion()
3315 }
3316
3317
3318 void wxFrameManager::OnMotion(wxMouseEvent& event)
3319 {
3320 // sometimes when Update() is called from inside this method,
3321 // a spurious mouse move event is generated; this check will make
3322 // sure that only real mouse moves will get anywhere in this method;
3323 // this appears to be a bug somewhere, and I don't know where the
3324 // mouse move event is being generated. only verified on MSW
3325
3326 wxPoint mouse_pos = event.GetPosition();
3327 if (m_last_mouse_move == mouse_pos)
3328 return;
3329 m_last_mouse_move = mouse_pos;
3330
3331
3332 if (m_action == actionResize)
3333 {
3334 wxPoint pos = m_action_part->rect.GetPosition();
3335 if (m_action_part->orientation == wxHORIZONTAL)
3336 pos.y = wxMax(0, event.m_y - m_action_offset.y);
3337 else
3338 pos.x = wxMax(0, event.m_x - m_action_offset.x);
3339
3340 wxRect rect(m_frame->ClientToScreen(pos),
3341 m_action_part->rect.GetSize());
3342
3343 wxScreenDC dc;
3344 if (!m_action_hintrect.IsEmpty())
3345 DrawResizeHint(dc, m_action_hintrect);
3346 DrawResizeHint(dc, rect);
3347 m_action_hintrect = rect;
3348 }
3349 else if (m_action == actionClickCaption)
3350 {
3351 int drag_x_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_X);
3352 int drag_y_threshold = wxSystemSettings::GetMetric(wxSYS_DRAG_Y);
3353
3354 // caption has been clicked. we need to check if the mouse
3355 // is now being dragged. if it is, we need to change the
3356 // mouse action to 'drag'
3357 if (abs(event.m_x - m_action_start.x) > drag_x_threshold ||
3358 abs(event.m_y - m_action_start.y) > drag_y_threshold)
3359 {
3360 wxPaneInfo* pane_info = m_action_part->pane;
3361
3362 if (!pane_info->IsToolbar())
3363 {
3364 if ((m_flags & wxAUI_MGR_ALLOW_FLOATING) &&
3365 pane_info->IsFloatable())
3366 {
3367 m_action = actionDragFloatingPane;
3368
3369 // set initial float position
3370 wxPoint pt = m_frame->ClientToScreen(event.GetPosition());
3371 pane_info->floating_pos = wxPoint(pt.x - m_action_offset.x,
3372 pt.y - m_action_offset.y);
3373 // float the window
3374 pane_info->Float();
3375 Update();
3376
3377 m_action_window = pane_info->frame;
3378
3379 // action offset is used here to make it feel "natural" to the user
3380 // to drag a docked pane and suddenly have it become a floating frame.
3381 // Sometimes, however, the offset where the user clicked on the docked
3382 // caption is bigger than the width of the floating frame itself, so
3383 // in that case we need to set the action offset to a sensible value
3384 wxSize frame_size = m_action_window->GetSize();
3385 if (frame_size.x <= m_action_offset.x)
3386 m_action_offset.x = 30;
3387 }
3388 }
3389 else
3390 {
3391 m_action = actionDragToolbarPane;
3392 m_action_window = pane_info->window;
3393 }
3394 }
3395 }
3396 else if (m_action == actionDragFloatingPane)
3397 {
3398 wxPoint pt = m_frame->ClientToScreen(event.GetPosition());
3399 m_action_window->Move(pt.x - m_action_offset.x,
3400 pt.y - m_action_offset.y);
3401 }
3402 else if (m_action == actionDragToolbarPane)
3403 {
3404 wxPaneInfo& pane = GetPane(m_action_window);
3405 wxASSERT_MSG(pane.IsOk(), wxT("Pane window not found"));
3406
3407 pane.state |= wxPaneInfo::actionPane;
3408
3409 wxPoint pt = event.GetPosition();
3410 DoDrop(m_docks, m_panes, pane, pt, m_action_offset);
3411
3412 // if DoDrop() decided to float the pane, set up
3413 // the floating pane's initial position
3414 if (pane.IsFloating())
3415 {
3416 wxPoint pt = m_frame->ClientToScreen(event.GetPosition());
3417 pane.floating_pos = wxPoint(pt.x - m_action_offset.x,
3418 pt.y - m_action_offset.y);
3419 }
3420
3421 // this will do the actiual move operation;
3422 // in the case that the pane has been floated,
3423 // this call will create the floating pane
3424 // and do the reparenting
3425 Update();
3426
3427 // if the pane has been floated, change the mouse
3428 // action actionDragFloatingPane so that subsequent
3429 // EVT_MOTION() events will move the floating pane
3430 if (pane.IsFloating())
3431 {
3432 pane.state &= ~wxPaneInfo::actionPane;
3433 m_action = actionDragFloatingPane;
3434 m_action_window = pane.frame;
3435 }
3436 }
3437 else
3438 {
3439 wxDockUIPart* part = HitTest(event.GetX(), event.GetY());
3440 if (part && part->type == wxDockUIPart::typePaneButton)
3441 {
3442 if (part != m_hover_button)
3443 {
3444 // make the old button normal
3445 if (m_hover_button)
3446 UpdateButtonOnScreen(m_hover_button, event);
3447
3448 // mouse is over a button, so repaint the
3449 // button in hover mode
3450 UpdateButtonOnScreen(part, event);
3451 m_hover_button = part;
3452 }
3453 }
3454 else
3455 {
3456 if (m_hover_button)
3457 {
3458 m_hover_button = NULL;
3459 Repaint();
3460 }
3461 else
3462 {
3463 event.Skip();
3464 }
3465 }
3466 }
3467 }
3468
3469 void wxFrameManager::OnLeaveWindow(wxMouseEvent& WXUNUSED(event))
3470 {
3471 if (m_hover_button)
3472 {
3473 m_hover_button = NULL;
3474 Repaint();
3475 }
3476 }
3477
3478 void wxFrameManager::OnChildFocus(wxChildFocusEvent& event)
3479 {
3480 // when a child pane has it's focus set, we should change the
3481 // pane's active state to reflect this. (this is only true if
3482 // active panes are allowed by the owner)
3483 if (GetFlags() & wxAUI_MGR_ALLOW_ACTIVE_PANE)
3484 {
3485 if (GetPane(event.GetWindow()).IsOk())
3486 {
3487 SetActivePane(m_panes, event.GetWindow());
3488 m_frame->Refresh();
3489 }
3490 }
3491 }
3492
3493
3494 // OnPaneButton() is an event handler that is called
3495 // when a pane button has been pressed.
3496 void wxFrameManager::OnPaneButton(wxFrameManagerEvent& evt)
3497 {
3498 wxASSERT_MSG(evt.pane, wxT("Pane Info passed to wxFrameManager::OnPaneButton must be non-null"));
3499
3500 wxPaneInfo& pane = *(evt.pane);
3501
3502 if (evt.button == wxPaneInfo::buttonClose)
3503 {
3504 // fire pane close event
3505 wxFrameManagerEvent e(wxEVT_AUI_PANECLOSE);
3506 e.SetPane(evt.pane);
3507 ProcessMgrEvent(e);
3508
3509 if (!e.GetVeto())
3510 {
3511 pane.Hide();
3512 Update();
3513 }
3514 }
3515 else if (evt.button == wxPaneInfo::buttonPin)
3516 {
3517 if ((m_flags & wxAUI_MGR_ALLOW_FLOATING) &&
3518 pane.IsFloatable())
3519 pane.Float();
3520 Update();
3521 }
3522 }
3523
3524 #endif // wxUSE_AUI