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