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