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