...
[iramuteq] / agw / aui / framemanager.py
1 # --------------------------------------------------------------------------- #
2 # AUI Library wxPython IMPLEMENTATION
3 #
4 # Original C++ Code From Kirix (wxAUI). You Can Find It At:
5 #
6 #    License: wxWidgets license
7 #
8 # http:#www.kirix.com/en/community/opensource/wxaui/about_wxaui.html
9 #
10 # Current wxAUI Version Tracked: wxWidgets 2.9.0 SVN HEAD
11 #
12 #
13 # Python Code By:
14 #
15 # Andrea Gavana, @ 23 Dec 2005
16 # Latest Revision: 10 Mar 2011, 15.00 GMT
17 #
18 # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
19 # Write To Me At:
20 #
21 # andrea.gavana@gmail.com
22 # gavana@kpo.kz
23 #
24 # Or, Obviously, To The wxPython Mailing List!!!
25 #
26 # End Of Comments
27 # --------------------------------------------------------------------------- #
28
29 """
30 Description
31 ===========
32
33 framemanager is the central module of the AUI class framework.
34
35 L{AuiManager} manages the panes associated with it for a particular `wx.Frame`, using
36 a pane's L{AuiPaneInfo} information to determine each pane's docking and floating
37 behavior. AuiManager uses wxPython' sizer mechanism to plan the layout of each frame.
38 It uses a replaceable dock art class to do all drawing, so all drawing is localized
39 in one area, and may be customized depending on an application's specific needs.
40
41 AuiManager works as follows: the programmer adds panes to the class, or makes
42 changes to existing pane properties (dock position, floating state, show state, etc...).
43 To apply these changes, AuiManager's L{AuiManager.Update} function is called. This batch
44 processing can be used to avoid flicker, by modifying more than one pane at a time,
45 and then "committing" all of the changes at once by calling `Update()`.
46
47 Panes can be added quite easily::
48
49     text1 = wx.TextCtrl(self, -1)
50     text2 = wx.TextCtrl(self, -1)
51     self._mgr.AddPane(text1, AuiPaneInfo().Left().Caption("Pane Number One"))
52     self._mgr.AddPane(text2, AuiPaneInfo().Bottom().Caption("Pane Number Two"))
53
54     self._mgr.Update()
55
56
57 Later on, the positions can be modified easily. The following will float an
58 existing pane in a tool window::
59
60     self._mgr.GetPane(text1).Float()
61
62
63 Layers, Rows and Directions, Positions
64 ======================================
65
66 Inside AUI, the docking layout is figured out by checking several pane parameters.
67 Four of these are important for determining where a pane will end up.
68
69 **Direction** - Each docked pane has a direction, `Top`, `Bottom`, `Left`, `Right`, or `Center`.
70 This is fairly self-explanatory. The pane will be placed in the location specified
71 by this variable.
72
73 **Position** - More than one pane can be placed inside of a "dock". Imagine two panes
74 being docked on the left side of a window. One pane can be placed over another.
75 In proportionally managed docks, the pane position indicates it's sequential position,
76 starting with zero. So, in our scenario with two panes docked on the left side, the
77 top pane in the dock would have position 0, and the second one would occupy position 1. 
78
79 **Row** - A row can allow for two docks to be placed next to each other. One of the most
80 common places for this to happen is in the toolbar. Multiple toolbar rows are allowed,
81 the first row being in row 0, and the second in row 1. Rows can also be used on
82 vertically docked panes. 
83
84 **Layer** - A layer is akin to an onion. Layer 0 is the very center of the managed pane.
85 Thus, if a pane is in layer 0, it will be closest to the center window (also sometimes
86 known as the "content window"). Increasing layers "swallow up" all layers of a lower
87 value. This can look very similar to multiple rows, but is different because all panes
88 in a lower level yield to panes in higher levels. The best way to understand layers
89 is by running the AUI sample (`AUI.py`).
90 """
91
92 __author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
93 __date__ = "31 March 2009"
94
95
96 import wx
97 import time
98 import types
99 import warnings
100
101 import auibar
102 import auibook
103 import tabmdi
104 import dockart
105 import tabart
106
107 from aui_utilities import Clip, PaneCreateStippleBitmap, GetDockingImage, GetSlidingPoints
108
109 from aui_constants import *
110
111 # Define this as a translation function
112 _ = wx.GetTranslation
113
114 _winxptheme = False
115 if wx.Platform == "__WXMSW__":
116     try:
117         import winxptheme
118         _winxptheme = True
119     except ImportError:
120         pass
121
122 # wxPython version string
123 _VERSION_STRING = wx.VERSION_STRING
124
125 # AUI Events
126 wxEVT_AUI_PANE_BUTTON = wx.NewEventType()
127 wxEVT_AUI_PANE_CLOSE = wx.NewEventType()
128 wxEVT_AUI_PANE_MAXIMIZE = wx.NewEventType()
129 wxEVT_AUI_PANE_RESTORE = wx.NewEventType()
130 wxEVT_AUI_RENDER = wx.NewEventType()
131 wxEVT_AUI_FIND_MANAGER = wx.NewEventType()
132 wxEVT_AUI_PANE_MINIMIZE = wx.NewEventType()
133 wxEVT_AUI_PANE_MIN_RESTORE = wx.NewEventType()
134 wxEVT_AUI_PANE_FLOATING = wx.NewEventType()
135 wxEVT_AUI_PANE_FLOATED = wx.NewEventType()
136 wxEVT_AUI_PANE_DOCKING = wx.NewEventType()
137 wxEVT_AUI_PANE_DOCKED = wx.NewEventType()
138 wxEVT_AUI_PANE_ACTIVATED = wx.NewEventType()
139 wxEVT_AUI_PERSPECTIVE_CHANGED = wx.NewEventType()
140
141 EVT_AUI_PANE_BUTTON = wx.PyEventBinder(wxEVT_AUI_PANE_BUTTON, 0)
142 """ Fires an event when the user left-clicks on a pane button. """
143 EVT_AUI_PANE_CLOSE = wx.PyEventBinder(wxEVT_AUI_PANE_CLOSE, 0)
144 """ A pane in `AuiManager` has been closed. """
145 EVT_AUI_PANE_MAXIMIZE = wx.PyEventBinder(wxEVT_AUI_PANE_MAXIMIZE, 0)
146 """ A pane in `AuiManager` has been maximized. """
147 EVT_AUI_PANE_RESTORE = wx.PyEventBinder(wxEVT_AUI_PANE_RESTORE, 0)
148 """ A pane in `AuiManager` has been restored from a maximized state. """
149 EVT_AUI_RENDER = wx.PyEventBinder(wxEVT_AUI_RENDER, 0)
150 """ Fires an event every time the AUI frame is being repainted. """
151 EVT_AUI_FIND_MANAGER = wx.PyEventBinder(wxEVT_AUI_FIND_MANAGER, 0)
152 """ Used to find which AUI manager is controlling a certain pane. """
153 EVT_AUI_PANE_MINIMIZE = wx.PyEventBinder(wxEVT_AUI_PANE_MINIMIZE, 0)
154 """ A pane in `AuiManager` has been minimized. """
155 EVT_AUI_PANE_MIN_RESTORE = wx.PyEventBinder(wxEVT_AUI_PANE_MIN_RESTORE, 0)
156 """ A pane in `AuiManager` has been restored from a minimized state. """
157 EVT_AUI_PANE_FLOATING = wx.PyEventBinder(wxEVT_AUI_PANE_FLOATING, 0)
158 """ A pane in `AuiManager` is about to be floated. """
159 EVT_AUI_PANE_FLOATED = wx.PyEventBinder(wxEVT_AUI_PANE_FLOATED, 0)
160 """ A pane in `AuiManager` has been floated. """
161 EVT_AUI_PANE_DOCKING = wx.PyEventBinder(wxEVT_AUI_PANE_DOCKING, 0)
162 """ A pane in `AuiManager` is about to be docked. """
163 EVT_AUI_PANE_DOCKED = wx.PyEventBinder(wxEVT_AUI_PANE_DOCKED, 0)
164 """ A pane in `AuiManager` has been docked. """
165 EVT_AUI_PANE_ACTIVATED = wx.PyEventBinder(wxEVT_AUI_PANE_ACTIVATED, 0)
166 """ A pane in `AuiManager` has been activated. """
167 EVT_AUI_PERSPECTIVE_CHANGED = wx.PyEventBinder(wxEVT_AUI_PERSPECTIVE_CHANGED, 0)
168 """ The layout in `AuiManager` has been changed. """
169
170 # ---------------------------------------------------------------------------- #
171
172 class AuiDockInfo(object):
173     """ A class to store all properties of a dock. """
174
175     def __init__(self):
176         """
177         Default class constructor.
178         Used internally, do not call it in your code!
179         """
180
181         object.__init__(self)
182         
183         self.dock_direction = 0
184         self.dock_layer = 0
185         self.dock_row = 0
186         self.size = 0
187         self.min_size = 0
188         self.resizable = True
189         self.fixed = False
190         self.toolbar = False
191         self.rect = wx.Rect()
192         self.panes = []
193
194
195     def IsOk(self):
196         """
197         Returns whether a dock is valid or not.
198
199         In order to be valid, a dock needs to have a non-zero `dock_direction`.
200         """
201
202         return self.dock_direction != 0
203
204     
205     def IsHorizontal(self):
206         """ Returns whether the dock is horizontal or not. """
207
208         return self.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]
209
210
211     def IsVertical(self):
212         """ Returns whether the dock is vertical or not. """
213
214         return self.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT, AUI_DOCK_CENTER]
215     
216
217 # ---------------------------------------------------------------------------- #
218
219 class AuiDockingGuideInfo(object):
220     """ A class which holds information about VS2005 docking guide windows. """
221
222     def __init__(self, other=None):
223         """
224         Default class constructor.
225         Used internally, do not call it in your code!
226
227         :param `other`: another instance of L{AuiDockingGuideInfo}.
228         """
229
230         if other:
231             self.Assign(other)
232         else:
233             # window representing the docking target
234             self.host = None
235             # dock direction (top, bottom, left, right, center)
236             self.dock_direction = AUI_DOCK_NONE
237
238
239     def Assign(self, other):
240         """
241         Assigns the properties of the `other` L{AuiDockingGuideInfo} to `self`.
242
243         :param `other`: another instance of L{AuiDockingGuideInfo}.
244         """
245
246         self.host = other.host
247         self.dock_direction = other.dock_direction
248
249
250     def Host(self, h):
251         """
252         Hosts a docking guide window.
253
254         :param `h`: an instance of L{AuiSingleDockingGuide} or L{AuiCenterDockingGuide}.
255         """
256
257         self.host = h
258         return self
259     
260
261     def Left(self):
262         """ Sets the guide window to left docking. """
263
264         self.dock_direction = AUI_DOCK_LEFT
265         return self
266
267     
268     def Right(self):
269         """ Sets the guide window to right docking. """
270
271         self.dock_direction = AUI_DOCK_RIGHT
272         return self 
273
274
275     def Top(self):
276         """ Sets the guide window to top docking. """
277
278         self.dock_direction = AUI_DOCK_TOP
279         return self 
280
281
282     def Bottom(self):
283         """ Sets the guide window to bottom docking. """
284
285         self.dock_direction = AUI_DOCK_BOTTOM
286         return self 
287
288
289     def Center(self):
290         """ Sets the guide window to center docking. """
291
292         self.dock_direction = AUI_DOCK_CENTER
293         return self 
294
295
296     def Centre(self):
297         """ Sets the guide window to centre docking. """
298         
299         self.dock_direction = AUI_DOCK_CENTRE
300         return self
301
302
303 # ---------------------------------------------------------------------------- #
304
305 class AuiDockUIPart(object):
306     """ A class which holds attributes for a UI part in the interface. """
307     
308     typeCaption = 0
309     typeGripper = 1
310     typeDock = 2
311     typeDockSizer = 3
312     typePane = 4
313     typePaneSizer = 5
314     typeBackground = 6
315     typePaneBorder = 7
316     typePaneButton = 8
317
318     def __init__(self):
319         """
320         Default class constructor.
321         Used internally, do not call it in your code!
322         """
323         
324         self.orientation = wx.VERTICAL
325         self.type = 0
326         self.rect = wx.Rect()
327
328
329 # ---------------------------------------------------------------------------- #
330
331 class AuiPaneButton(object):
332     """ A simple class which describes the caption pane button attributes. """
333
334     def __init__(self, button_id):
335         """
336         Default class constructor.
337         Used internally, do not call it in your code!
338
339         :param `button_id`: the pane button identifier.
340         """
341
342         self.button_id = button_id
343
344
345 # ---------------------------------------------------------------------------- #
346
347 # event declarations/classes
348
349 class AuiManagerEvent(wx.PyCommandEvent):
350     """ A specialized command event class for events sent by L{AuiManager}. """
351
352     def __init__(self, eventType, id=1):
353         """
354         Default class constructor.
355
356         :param `eventType`: the event kind;
357         :param `id`: the event identification number.
358         """
359
360         wx.PyCommandEvent.__init__(self, eventType, id)
361
362         self.manager = None
363         self.pane = None
364         self.button = 0
365         self.veto_flag = False
366         self.canveto_flag = True
367         self.dc = None
368
369
370     def SetManager(self, mgr):
371         """
372         Associates a L{AuiManager} to the current event.
373
374         :param `mgr`: an instance of L{AuiManager}.
375         """
376
377         self.manager = mgr
378
379
380     def SetDC(self, pdc):
381         """
382         Associates a `wx.DC` device context to this event.
383
384         :param `pdc`: a `wx.DC` device context object. 
385         """
386
387         self.dc = pdc
388
389
390     def SetPane(self, p):
391         """
392         Associates a L{AuiPaneInfo} instance to this event.
393
394         :param `p`: a L{AuiPaneInfo} instance.
395         """
396         
397         self.pane = p
398
399         
400     def SetButton(self, b):
401         """
402         Associates a L{AuiPaneButton} instance to this event.
403
404         :param `b`: a L{AuiPaneButton} instance.
405         """
406         
407         self.button = b
408
409         
410     def GetManager(self):
411         """ Returns the associated L{AuiManager} (if any). """
412
413         return self.manager
414
415
416     def GetDC(self):
417         """ Returns the associated `wx.DC` device context (if any). """
418
419         return self.dc
420     
421
422     def GetPane(self):
423         """ Returns the associated L{AuiPaneInfo} structure (if any). """
424         
425         return self.pane
426
427
428     def GetButton(self):
429         """ Returns the associated L{AuiPaneButton} instance (if any). """
430
431         return self.button
432
433
434     def Veto(self, veto=True):
435         """
436         Prevents the change announced by this event from happening.
437
438         It is in general a good idea to notify the user about the reasons for
439         vetoing the change because otherwise the applications behaviour (which
440         just refuses to do what the user wants) might be quite surprising.
441
442         :param `veto`: ``True`` to veto the event, ``False`` otherwise.
443         """
444
445         self.veto_flag = veto
446
447         
448     def GetVeto(self):
449         """ Returns whether the event has been vetoed or not. """
450
451         return self.veto_flag
452
453     
454     def SetCanVeto(self, can_veto):
455         """
456         Sets whether the event can be vetoed or not.
457
458         :param `can_veto`: a bool flag. ``True`` if the event can be vetoed, ``False`` otherwise.
459         """
460
461         self.canveto_flag = can_veto
462
463         
464     def CanVeto(self):
465         """ Returns whether the event can be vetoed and has been vetoed. """
466
467         return  self.canveto_flag and self.veto_flag
468
469
470 # ---------------------------------------------------------------------------- #
471
472 class AuiPaneInfo(object):
473     """
474     AuiPaneInfo specifies all the parameters for a pane. These parameters specify where
475     the pane is on the screen, whether it is docked or floating, or hidden. In addition,
476     these parameters specify the pane's docked position, floating position, preferred
477     size, minimum size, caption text among many other parameters.
478     """
479     
480     optionFloating         = 2**0
481     optionHidden           = 2**1
482     optionLeftDockable     = 2**2
483     optionRightDockable    = 2**3
484     optionTopDockable      = 2**4
485     optionBottomDockable   = 2**5
486     optionFloatable        = 2**6
487     optionMovable          = 2**7
488     optionResizable        = 2**8
489     optionPaneBorder       = 2**9
490     optionCaption          = 2**10
491     optionGripper          = 2**11
492     optionDestroyOnClose   = 2**12
493     optionToolbar          = 2**13
494     optionActive           = 2**14
495     optionGripperTop       = 2**15
496     optionMaximized        = 2**16
497     optionDockFixed        = 2**17
498     optionNotebookDockable = 2**18
499     optionMinimized        = 2**19
500     optionLeftSnapped      = 2**20
501     optionRightSnapped     = 2**21
502     optionTopSnapped       = 2**22
503     optionBottomSnapped    = 2**23
504     optionFlyOut           = 2**24
505     optionCaptionLeft      = 2**25
506
507     buttonClose            = 2**26
508     buttonMaximize         = 2**27
509     buttonMinimize         = 2**28
510     buttonPin              = 2**29
511     
512     buttonCustom1          = 2**30
513     buttonCustom2          = 2**31
514     buttonCustom3          = 2**32
515
516     savedHiddenState       = 2**33    # used internally
517     actionPane             = 2**34    # used internally
518     wasMaximized           = 2**35    # used internally
519     needsRestore           = 2**36    # used internally
520
521
522     def __init__(self):
523         """ Default class constructor. """
524         
525         self.window = None
526         self.frame = None
527         self.state = 0
528         self.dock_direction = AUI_DOCK_LEFT
529         self.dock_layer = 0
530         self.dock_row = 0
531         self.dock_pos = 0
532         self.minimize_mode = AUI_MINIMIZE_POS_SMART
533         self.floating_pos = wx.Point(-1, -1)
534         self.floating_size = wx.Size(-1, -1)
535         self.best_size = wx.Size(-1, -1)
536         self.min_size = wx.Size(-1, -1)
537         self.max_size = wx.Size(-1, -1)
538         self.dock_proportion = 0
539         self.caption = ""
540         self.buttons = []
541         self.name = ""
542         self.icon = wx.NullIcon
543         self.rect = wx.Rect()
544         self.notebook_id = -1
545         self.transparent = 255
546         self.needsTransparency = False
547         self.previousDockPos = None
548         self.previousDockSize = 0
549         self.snapped = 0
550         
551         self.DefaultPane()
552         
553     
554     def dock_direction_get(self):
555         """
556         Getter for the `dock_direction`.
557
558         :see: L{dock_direction_set} for a set of valid docking directions.
559         """
560         
561         if self.IsMaximized():
562             return AUI_DOCK_CENTER
563         else:
564             return self._dock_direction
565
566
567     def dock_direction_set(self, value):
568         """
569         Setter for the `dock_direction`.
570
571         :param `value`: the docking direction. This cab ne one of the following bits:
572
573         ============================ ======= =============================================
574         Dock Flag                     Value  Description
575         ============================ ======= =============================================
576         ``AUI_DOCK_NONE``                  0 No docking direction.
577         ``AUI_DOCK_TOP``                   1 Top docking direction.
578         ``AUI_DOCK_RIGHT``                 2 Right docking direction.
579         ``AUI_DOCK_BOTTOM``                3 Bottom docking direction.
580         ``AUI_DOCK_LEFT``                  4 Left docking direction.
581         ``AUI_DOCK_CENTER``                5 Center docking direction.
582         ``AUI_DOCK_CENTRE``                5 Centre docking direction.
583         ``AUI_DOCK_NOTEBOOK_PAGE``         6 Automatic AuiNotebooks docking style.
584         ============================ ======= =============================================
585         
586         """
587         
588         self._dock_direction = value
589         
590     dock_direction = property(dock_direction_get, dock_direction_set)
591
592     def IsOk(self):
593         """
594         Returns ``True`` if the L{AuiPaneInfo} structure is valid.
595
596         :note: A pane structure is valid if it has an associated window.
597         """
598         
599         return self.window != None
600
601
602     def IsMaximized(self):
603         """ Returns ``True`` if the pane is maximized. """
604         
605         return self.HasFlag(self.optionMaximized)
606
607
608     def IsMinimized(self):
609         """ Returns ``True`` if the pane is minimized. """
610
611         return self.HasFlag(self.optionMinimized)
612
613
614     def IsFixed(self):
615         """ Returns ``True`` if the pane cannot be resized. """
616         
617         return not self.HasFlag(self.optionResizable)
618
619     
620     def IsResizeable(self):
621         """ Returns ``True`` if the pane can be resized. """
622         
623         return self.HasFlag(self.optionResizable)
624
625     
626     def IsShown(self):
627         """ Returns ``True`` if the pane is currently shown. """
628         
629         return not self.HasFlag(self.optionHidden)
630
631     
632     def IsFloating(self):
633         """ Returns ``True`` if the pane is floating. """
634
635         return self.HasFlag(self.optionFloating)
636
637     
638     def IsDocked(self):
639         """ Returns ``True`` if the pane is docked. """
640         
641         return not self.HasFlag(self.optionFloating)
642
643     
644     def IsToolbar(self):
645         """ Returns ``True`` if the pane contains a toolbar. """
646
647         return self.HasFlag(self.optionToolbar)
648
649     
650     def IsTopDockable(self):
651         """
652         Returns ``True`` if the pane can be docked at the top
653         of the managed frame.
654         """
655         
656         return self.HasFlag(self.optionTopDockable)
657
658     
659     def IsBottomDockable(self):
660         """
661         Returns ``True`` if the pane can be docked at the bottom
662         of the managed frame.
663         """
664         
665         return self.HasFlag(self.optionBottomDockable)
666
667     
668     def IsLeftDockable(self):
669         """
670         Returns ``True`` if the pane can be docked at the left
671         of the managed frame.
672         """
673         
674         return self.HasFlag(self.optionLeftDockable) 
675
676
677     def IsRightDockable(self):
678         """
679         Returns ``True`` if the pane can be docked at the right
680         of the managed frame.
681         """
682         
683         return self.HasFlag(self.optionRightDockable)
684
685
686     def IsDockable(self):
687         """ Returns ``True`` if the pane can be docked. """
688         
689         return self.IsTopDockable() or self.IsBottomDockable() or self.IsLeftDockable() or \
690                self.IsRightDockable() or self.IsNotebookDockable()
691     
692     
693     def IsFloatable(self):
694         """
695         Returns ``True`` if the pane can be undocked and displayed as a
696         floating window.
697         """
698
699         return self.HasFlag(self.optionFloatable)
700
701     
702     def IsMovable(self):
703         """
704         Returns ``True`` if the docked frame can be undocked or moved to
705         another dock position.
706         """
707         
708         return self.HasFlag(self.optionMovable)
709
710
711     def IsDestroyOnClose(self):
712         """
713         Returns ``True`` if the pane should be destroyed when it is closed.
714         
715         Normally a pane is simply hidden when the close button is clicked. Calling L{DestroyOnClose}
716         with a ``True`` input parameter will cause the window to be destroyed when the user clicks
717         the pane's close button.
718         """
719         
720         return self.HasFlag(self.optionDestroyOnClose)
721     
722
723     def IsNotebookDockable(self):
724         """
725         Returns ``True`` if a pane can be docked on top to another to create a
726         L{AuiNotebook}.
727         """
728
729         return self.HasFlag(self.optionNotebookDockable)
730     
731
732     def IsTopSnappable(self):
733         """ Returns ``True`` if the pane can be snapped at the top of the managed frame. """
734         
735         return self.HasFlag(self.optionTopSnapped)
736
737     
738     def IsBottomSnappable(self):
739         """ Returns ``True`` if the pane can be snapped at the bottom of the managed frame. """
740         
741         return self.HasFlag(self.optionBottomSnapped)
742
743     
744     def IsLeftSnappable(self):
745         """ Returns ``True`` if the pane can be snapped on the left of the managed frame. """
746         
747         return self.HasFlag(self.optionLeftSnapped) 
748
749
750     def IsRightSnappable(self):
751         """ Returns ``True`` if the pane can be snapped on the right of the managed frame. """
752         
753         return self.HasFlag(self.optionRightSnapped)
754
755
756     def IsSnappable(self):
757         """ Returns ``True`` if the pane can be snapped. """
758         
759         return self.IsTopSnappable() or self.IsBottomSnappable() or self.IsLeftSnappable() or \
760                self.IsRightSnappable()
761
762
763     def IsFlyOut(self):
764         """ Returns ``True`` if the floating pane has a "fly-out" effect. """
765
766         return self.HasFlag(self.optionFlyOut)        
767             
768
769     def HasCaption(self):
770         """ Returns ``True`` if the pane displays a caption. """
771         
772         return self.HasFlag(self.optionCaption)
773
774     
775     def HasCaptionLeft(self):
776         """ Returns ``True`` if the pane displays a caption on the left (rotated by 90 degrees). """
777         
778         return self.HasFlag(self.optionCaptionLeft)
779
780
781     def HasGripper(self):
782         """ Returns ``True`` if the pane displays a gripper. """
783         
784         return self.HasFlag(self.optionGripper) 
785
786
787     def HasBorder(self):
788         """ Returns ``True`` if the pane displays a border. """
789         
790         return self.HasFlag(self.optionPaneBorder)
791
792     
793     def HasCloseButton(self):
794         """ Returns ``True`` if the pane displays a button to close the pane. """
795
796         return self.HasFlag(self.buttonClose) 
797
798
799     def HasMaximizeButton(self):
800         """ Returns ``True`` if the pane displays a button to maximize the pane. """
801         
802         return self.HasFlag(self.buttonMaximize)
803
804     
805     def HasMinimizeButton(self):
806         """ Returns ``True`` if the pane displays a button to minimize the pane. """
807         
808         return self.HasFlag(self.buttonMinimize) 
809
810
811     def GetMinimizeMode(self):
812         """
813         Returns the minimization style for this pane.
814
815         Possible return values are:
816
817         ============================== ========= ==============================
818         Minimize Mode Flag             Hex Value Description
819         ============================== ========= ==============================
820         ``AUI_MINIMIZE_POS_SMART``          0x01 Minimizes the pane on the closest tool bar
821         ``AUI_MINIMIZE_POS_TOP``            0x02 Minimizes the pane on the top tool bar
822         ``AUI_MINIMIZE_POS_LEFT``           0x03 Minimizes the pane on its left tool bar
823         ``AUI_MINIMIZE_POS_RIGHT``          0x04 Minimizes the pane on its right tool bar
824         ``AUI_MINIMIZE_POS_BOTTOM``         0x05 Minimizes the pane on its bottom tool bar
825         ``AUI_MINIMIZE_POS_MASK``           0x07 Mask to filter the position flags
826         ``AUI_MINIMIZE_CAPT_HIDE``           0x0 Hides the caption of the minimized pane
827         ``AUI_MINIMIZE_CAPT_SMART``         0x08 Displays the caption in the best rotation (horizontal or clockwise)
828         ``AUI_MINIMIZE_CAPT_HORZ``          0x10 Displays the caption horizontally
829         ``AUI_MINIMIZE_CAPT_MASK``          0x18 Mask to filter the caption flags
830         ============================== ========= ==============================
831
832         The flags can be filtered with the following masks:
833
834         ============================== ========= ==============================
835         Minimize Mask Flag             Hex Value Description
836         ============================== ========= ==============================        
837         ``AUI_MINIMIZE_POS_MASK``           0x07 Filters the position flags
838         ``AUI_MINIMIZE_CAPT_MASK``          0x18 Filters the caption flags
839         ============================== ========= ==============================
840
841         """
842         
843         return self.minimize_mode
844     
845
846     def HasPinButton(self):
847         """ Returns ``True`` if the pane displays a button to float the pane. """
848         
849         return self.HasFlag(self.buttonPin) 
850
851
852     def HasGripperTop(self):
853         """ Returns ``True`` if the pane displays a gripper at the top. """
854
855         return self.HasFlag(self.optionGripperTop)
856
857
858     def Window(self, w):
859         """
860         Associate a `wx.Window` derived window to this pane.
861
862         This normally does not need to be specified, as the window pointer is
863         automatically assigned to the L{AuiPaneInfo} structure as soon as it is
864         added to the manager.
865
866         :param `w`: a `wx.Window` derived window.
867         """
868
869         self.window = w
870         return self
871
872     
873     def Name(self, name):
874         """
875         Sets the name of the pane so it can be referenced in lookup functions.
876
877         If a name is not specified by the user, a random name is assigned to the pane
878         when it is added to the manager.
879
880         :param `name`: a string specifying the pane name.
881
882         :warning: If you are using L{AuiManager.SavePerspective} and L{AuiManager.LoadPerspective}, you will have
883          to specify a name for your pane using L{Name}, as randomly generated names can
884          not be properly restored.
885         """
886
887         self.name = name
888         return self
889
890     
891     def Caption(self, caption):
892         """
893         Sets the caption of the pane.
894
895         :param `caption`: a string specifying the pane caption.
896         """
897         
898         self.caption = caption
899         return self
900
901     
902     def Left(self):
903         """ 
904         Sets the pane dock position to the left side of the frame.
905
906         :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_LEFT`` as
907          parameter.
908         """
909         
910         self.dock_direction = AUI_DOCK_LEFT
911         return self
912
913     
914     def Right(self):
915         """
916         Sets the pane dock position to the right side of the frame.
917
918         :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_RIGHT`` as
919          parameter.
920         """
921         
922         self.dock_direction = AUI_DOCK_RIGHT
923         return self
924
925     
926     def Top(self):
927         """
928         Sets the pane dock position to the top of the frame.
929
930         :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_TOP`` as
931          parameter.
932         """
933
934         self.dock_direction = AUI_DOCK_TOP
935         return self
936
937     
938     def Bottom(self):
939         """
940         Sets the pane dock position to the bottom of the frame.
941
942         :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_BOTTOM`` as
943          parameter.
944         """
945
946         self.dock_direction = AUI_DOCK_BOTTOM
947         return self
948
949     
950     def Center(self):
951         """
952         Sets the pane to the center position of the frame.
953
954         The centre pane is the space in the middle after all border panes (left, top,
955         right, bottom) are subtracted from the layout.
956
957         :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_CENTER`` as
958          parameter.
959         """
960         
961         self.dock_direction = AUI_DOCK_CENTER
962         return self
963
964         
965     def Centre(self):
966         """
967         Sets the pane to the center position of the frame.
968
969         The centre pane is the space in the middle after all border panes (left, top,
970         right, bottom) are subtracted from the layout.
971
972         :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_CENTRE`` as
973          parameter.
974         """
975         
976         self.dock_direction = AUI_DOCK_CENTRE
977         return self
978
979     
980     def Direction(self, direction):
981         """
982         Determines the direction of the docked pane. It is functionally the
983         same as calling L{Left}, L{Right}, L{Top} or L{Bottom}, except that docking direction
984         may be specified programmatically via the parameter `direction`.
985
986         :param `direction`: the direction of the docked pane.
987
988         :see: L{dock_direction_set} for a list of valid docking directions.        
989         """
990         
991         self.dock_direction = direction
992         return self
993
994     
995     def Layer(self, layer):
996         """
997         Determines the layer of the docked pane.
998
999         The dock layer is similar to an onion, the inner-most layer being layer 0. Each
1000         shell moving in the outward direction has a higher layer number. This allows for
1001         more complex docking layout formation.
1002
1003         :param `layer`: the layer of the docked pane.
1004         """
1005         
1006         self.dock_layer = layer
1007         return self
1008
1009     
1010     def Row(self, row):
1011         """
1012         Determines the row of the docked pane.
1013
1014         :param `row`: the row of the docked pane.
1015         """
1016         
1017         self.dock_row = row
1018         return self
1019
1020     
1021     def Position(self, pos):
1022         """
1023         Determines the position of the docked pane.
1024
1025         :param `pos`: the position of the docked pane.
1026         """
1027
1028         self.dock_pos = pos
1029         return self
1030
1031
1032     def MinSize(self, arg1=None, arg2=None):
1033         """
1034         Sets the minimum size of the pane.
1035
1036         This method is split in 2 versions depending on the input type. If `arg1` is
1037         a `wx.Size` object, then L{MinSize1} is called. Otherwise, L{MinSize2} is called.
1038
1039         :param `arg1`: a `wx.Size` object, a (x, y) tuple or or a `x` coordinate.
1040         :param `arg2`: a `y` coordinate (only if `arg1` is a `x` coordinate, otherwise unused).
1041         """
1042         
1043         if isinstance(arg1, wx.Size):
1044             ret = self.MinSize1(arg1)
1045         elif isinstance(arg1, types.TupleType):
1046             ret = self.MinSize1(wx.Size(*arg1))
1047         else:
1048             ret = self.MinSize2(arg1, arg2)
1049
1050         return ret
1051
1052     
1053     def MinSize1(self, size):
1054         """
1055         Sets the minimum size of the pane.
1056
1057         :see: L{MinSize} for an explanation of input parameters.
1058         """
1059         self.min_size = size
1060         return self
1061
1062
1063     def MinSize2(self, x, y):
1064         """
1065         Sets the minimum size of the pane.
1066
1067         :see: L{MinSize} for an explanation of input parameters.
1068         """
1069
1070         self.min_size = wx.Size(x, y)
1071         return self
1072
1073
1074     def MaxSize(self, arg1=None, arg2=None):
1075         """
1076         Sets the maximum size of the pane.
1077
1078         This method is split in 2 versions depending on the input type. If `arg1` is
1079         a `wx.Size` object, then L{MaxSize1} is called. Otherwise, L{MaxSize2} is called.
1080
1081         :param `arg1`: a `wx.Size` object, a (x, y) tuple or a `x` coordinate.
1082         :param `arg2`: a `y` coordinate (only if `arg1` is a `x` coordinate, otherwise unused).
1083         """
1084         
1085         if isinstance(arg1, wx.Size):
1086             ret = self.MaxSize1(arg1)
1087         elif isinstance(arg1, types.TupleType):
1088             ret = self.MaxSize1(wx.Size(*arg1))
1089         else:
1090             ret = self.MaxSize2(arg1, arg2)
1091
1092         return ret
1093     
1094     
1095     def MaxSize1(self, size):
1096         """
1097         Sets the maximum size of the pane.
1098
1099         :see: L{MaxSize} for an explanation of input parameters.
1100         """
1101
1102         self.max_size = size
1103         return self
1104
1105
1106     def MaxSize2(self, x, y):
1107         """
1108         Sets the maximum size of the pane.
1109
1110         :see: L{MaxSize} for an explanation of input parameters.
1111         """
1112
1113         self.max_size.Set(x,y)
1114         return self
1115
1116
1117     def BestSize(self, arg1=None, arg2=None):
1118         """
1119         Sets the ideal size for the pane. The docking manager will attempt to use
1120         this size as much as possible when docking or floating the pane.
1121
1122         This method is split in 2 versions depending on the input type. If `arg1` is
1123         a `wx.Size` object, then L{BestSize1} is called. Otherwise, L{BestSize2} is called.
1124
1125         :param `arg1`: a `wx.Size` object, a (x, y) tuple or a `x` coordinate.
1126         :param `arg2`: a `y` coordinate (only if `arg1` is a `x` coordinate, otherwise unused).
1127         """
1128         
1129         if isinstance(arg1, wx.Size):
1130             ret = self.BestSize1(arg1)
1131         elif isinstance(arg1, types.TupleType):
1132             ret = self.BestSize1(wx.Size(*arg1))
1133         else:
1134             ret = self.BestSize2(arg1, arg2)
1135
1136         return ret
1137     
1138             
1139     def BestSize1(self, size):
1140         """
1141         Sets the best size of the pane.
1142
1143         :see: L{BestSize} for an explanation of input parameters.
1144         """
1145
1146         self.best_size = size
1147         return self
1148
1149     
1150     def BestSize2(self, x, y):
1151         """
1152         Sets the best size of the pane.
1153
1154         :see: L{BestSize} for an explanation of input parameters.
1155         """
1156
1157         self.best_size.Set(x,y)
1158         return self
1159     
1160     
1161     def FloatingPosition(self, pos):
1162         """
1163         Sets the position of the floating pane.
1164
1165         :param `pos`: a `wx.Point` or a tuple indicating the pane floating position.
1166         """
1167         
1168         self.floating_pos = wx.Point(*pos)
1169         return self
1170
1171     
1172     def FloatingSize(self, size):
1173         """
1174         Sets the size of the floating pane.
1175
1176         :param `size`: a `wx.Size` or a tuple indicating the pane floating size.
1177         """
1178         
1179         self.floating_size = wx.Size(*size)
1180         return self
1181
1182
1183     def Maximize(self):
1184         """ Makes the pane take up the full area."""
1185
1186         return self.SetFlag(self.optionMaximized, True)
1187
1188
1189     def Minimize(self):
1190         """
1191         Makes the pane minimized in a L{AuiToolBar}.
1192
1193         Clicking on the minimize button causes a new L{AuiToolBar} to be created
1194         and added to the frame manager, (currently the implementation is such that
1195         panes at West will have a toolbar at the right, panes at South will have
1196         toolbars at the bottom etc...) and the pane is hidden in the manager.
1197         
1198         Clicking on the restore button on the newly created toolbar will result in the
1199         toolbar being removed and the original pane being restored.
1200         """
1201         
1202         return self.SetFlag(self.optionMinimized, True)
1203
1204
1205     def MinimizeMode(self, mode):
1206         """
1207         Sets the expected minimized mode if the MinimizeButton() is visible.
1208
1209         The minimized pane can have a specific position in the work space:
1210
1211         ============================== ========= ==============================
1212         Minimize Mode Flag             Hex Value Description
1213         ============================== ========= ==============================
1214         ``AUI_MINIMIZE_POS_SMART``          0x01 Minimizes the pane on the closest tool bar
1215         ``AUI_MINIMIZE_POS_TOP``            0x02 Minimizes the pane on the top tool bar
1216         ``AUI_MINIMIZE_POS_LEFT``           0x03 Minimizes the pane on its left tool bar
1217         ``AUI_MINIMIZE_POS_RIGHT``          0x04 Minimizes the pane on its right tool bar
1218         ``AUI_MINIMIZE_POS_BOTTOM``         0x05 Minimizes the pane on its bottom tool bar
1219         ============================== ========= ==============================
1220
1221         The caption of the minimized pane can be displayed in different modes:
1222
1223         ============================== ========= ==============================
1224         Caption Mode Flag              Hex Value Description
1225         ============================== ========= ==============================
1226         ``AUI_MINIMIZE_CAPT_HIDE``           0x0 Hides the caption of the minimized pane
1227         ``AUI_MINIMIZE_CAPT_SMART``         0x08 Displays the caption in the best rotation (horizontal in the top and in the bottom tool bar or clockwise in the right and in the left tool bar)
1228         ``AUI_MINIMIZE_CAPT_HORZ``          0x10 Displays the caption horizontally
1229         ============================== ========= ==============================
1230         
1231         """
1232         
1233         self.minimize_mode = mode
1234         return self
1235     
1236
1237     def Restore(self):
1238         """ Is the reverse of L{Maximize} and L{Minimize}."""
1239         
1240         return self.SetFlag(self.optionMaximized or self.optionMinimized, False)
1241
1242     
1243     def Fixed(self):
1244         """
1245         Forces a pane to be fixed size so that it cannot be resized.
1246         After calling L{Fixed}, L{IsFixed} will return ``True``.
1247         """
1248         
1249         return self.SetFlag(self.optionResizable, False)
1250
1251     
1252     def Resizable(self, resizable=True):
1253         """
1254         Allows a pane to be resizable if `resizable` is ``True``, and forces
1255         it to be a fixed size if `resizeable` is ``False``.
1256
1257         If `resizable` is ``False``, this is simply an antonym for L{Fixed}.
1258
1259         :param `resizable`: whether the pane will be resizeable or not.
1260         """
1261         
1262         return self.SetFlag(self.optionResizable, resizable)
1263
1264
1265     def Transparent(self, alpha):
1266         """
1267         Makes the pane transparent when floating.
1268
1269         :param `alpha`: an integer value between 0 and 255 for pane transparency.
1270         """
1271
1272         if alpha < 0 or alpha > 255:
1273             raise Exception("Invalid transparency value (%s)"%repr(alpha))
1274                             
1275         self.transparent = alpha
1276         self.needsTransparency = True
1277
1278     
1279     def Dock(self):
1280         """
1281         Indicates that a pane should be docked. It is the opposite of L{Float}.
1282         """
1283
1284         if self.IsNotebookPage():
1285             self.notebook_id = -1
1286             self.dock_direction = AUI_DOCK_NONE
1287         
1288         return self.SetFlag(self.optionFloating, False)
1289
1290     
1291     def Float(self):
1292         """
1293         Indicates that a pane should be floated. It is the opposite of L{Dock}.
1294         """
1295
1296         if self.IsNotebookPage():
1297             self.notebook_id = -1
1298             self.dock_direction = AUI_DOCK_NONE
1299
1300         return self.SetFlag(self.optionFloating, True)
1301
1302     
1303     def Hide(self):
1304         """
1305         Indicates that a pane should be hidden.
1306
1307         Calling L{Show} (``False``) achieve the same effect.
1308         """
1309         
1310         return self.SetFlag(self.optionHidden, True)
1311
1312     
1313     def Show(self, show=True):
1314         """
1315         Indicates that a pane should be shown.
1316
1317         :param `show`: whether the pane should be shown or not.
1318         """
1319         
1320         return self.SetFlag(self.optionHidden, not show)
1321     
1322
1323     # By defaulting to 1000, the tab will get placed at the end
1324     def NotebookPage(self, id, tab_position=1000):
1325         """
1326         Forces a pane to be a notebook page, so that the pane can be
1327         docked on top to another to create a L{AuiNotebook}.
1328
1329         :param `id`: the notebook id;
1330         :param `tab_position`: the tab number of the pane once docked in a notebook.
1331         """
1332         
1333         # Remove any floating frame
1334         self.Dock()
1335         self.notebook_id = id
1336         self.dock_pos = tab_position
1337         self.dock_row = 0
1338         self.dock_layer = 0
1339         self.dock_direction = AUI_DOCK_NOTEBOOK_PAGE
1340
1341         return self
1342
1343
1344     def NotebookControl(self, id):
1345         """
1346         Forces a pane to be a notebook control (L{AuiNotebook}).
1347
1348         :param `id`: the notebook id.
1349         """
1350
1351         self.notebook_id = id
1352         self.window = None
1353         self.buttons = []
1354         
1355         if self.dock_direction == AUI_DOCK_NOTEBOOK_PAGE:
1356             self.dock_direction = AUI_DOCK_NONE
1357             
1358         return self
1359     
1360
1361     def HasNotebook(self):
1362         """ Returns whether a pane has a L{AuiNotebook} or not. """
1363
1364         return self.notebook_id >= 0
1365
1366
1367     def IsNotebookPage(self):
1368         """ Returns whether the pane is a notebook page in a L{AuiNotebook}. """
1369
1370         return self.notebook_id >= 0 and self.dock_direction == AUI_DOCK_NOTEBOOK_PAGE
1371
1372
1373     def IsNotebookControl(self):
1374         """ Returns whether the pane is a notebook control (L{AuiNotebook}). """
1375
1376         return not self.IsNotebookPage() and self.HasNotebook()
1377
1378
1379     def SetNameFromNotebookId(self):
1380         """ Sets the pane name once docked in a L{AuiNotebook} using the notebook id. """
1381
1382         if self.notebook_id >= 0:
1383             self.name = "__notebook_%d"%self.notebook_id
1384             
1385         return self
1386
1387
1388     def CaptionVisible(self, visible=True, left=False):
1389         """
1390         Indicates that a pane caption should be visible. If `visible` is ``False``, no pane
1391         caption is drawn.
1392
1393         :param `visible`: whether the caption should be visible or not;
1394         :param `left`: whether the caption should be drawn on the left (rotated by 90 degrees) or not.
1395         """
1396
1397         if left:
1398             self.SetFlag(self.optionCaption, False)
1399             return self.SetFlag(self.optionCaptionLeft, visible)
1400
1401         self.SetFlag(self.optionCaptionLeft, False)
1402         return self.SetFlag(self.optionCaption, visible)
1403
1404     
1405     def PaneBorder(self, visible=True):
1406         """
1407         Indicates that a border should be drawn for the pane.
1408
1409         :param `visible`: whether the pane border should be visible or not.
1410         """
1411         
1412         return self.SetFlag(self.optionPaneBorder, visible)
1413
1414     
1415     def Gripper(self, visible=True):
1416         """
1417         Indicates that a gripper should be drawn for the pane.
1418
1419         :param `visible`: whether the gripper should be visible or not.
1420         """
1421         
1422         return self.SetFlag(self.optionGripper, visible)
1423
1424
1425     def GripperTop(self, attop=True):
1426         """
1427         Indicates that a gripper should be drawn at the top of the pane.
1428
1429         :param `attop`: whether the gripper should be drawn at the top or not.
1430         """
1431         
1432         return self.SetFlag(self.optionGripperTop, attop)
1433
1434     
1435     def CloseButton(self, visible=True):
1436         """
1437         Indicates that a close button should be drawn for the pane.
1438
1439         :param `visible`: whether the close button should be visible or not.
1440         """
1441         
1442         return self.SetFlag(self.buttonClose, visible)
1443
1444     
1445     def MaximizeButton(self, visible=True):
1446         """
1447         Indicates that a maximize button should be drawn for the pane.
1448
1449         :param `visible`: whether the maximize button should be visible or not.
1450         """
1451         
1452         return self.SetFlag(self.buttonMaximize, visible)
1453
1454     
1455     def MinimizeButton(self, visible=True):
1456         """
1457         Indicates that a minimize button should be drawn for the pane.
1458
1459         :param `visible`: whether the minimize button should be visible or not.
1460         """
1461
1462         return self.SetFlag(self.buttonMinimize, visible)
1463
1464     
1465     def PinButton(self, visible=True):
1466         """
1467         Indicates that a pin button should be drawn for the pane.
1468
1469         :param `visible`: whether the pin button should be visible or not.
1470         """
1471         
1472         return self.SetFlag(self.buttonPin, visible)
1473
1474     
1475     def DestroyOnClose(self, b=True):
1476         """
1477         Indicates whether a pane should be destroyed when it is closed.
1478
1479         Normally a pane is simply hidden when the close button is clicked. Setting
1480         `b` to ``True`` will cause the window to be destroyed when the user clicks
1481         the pane's close button.
1482
1483         :param `b`: whether the pane should be destroyed when it is closed or not.
1484         """
1485         
1486         return self.SetFlag(self.optionDestroyOnClose, b)
1487
1488     
1489     def TopDockable(self, b=True):
1490         """
1491         Indicates whether a pane can be docked at the top of the frame.
1492
1493         :param `b`: whether the pane can be docked at the top or not.
1494         """
1495         
1496         return self.SetFlag(self.optionTopDockable, b)
1497
1498     
1499     def BottomDockable(self, b=True):
1500         """
1501         Indicates whether a pane can be docked at the bottom of the frame.
1502
1503         :param `b`: whether the pane can be docked at the bottom or not.
1504         """
1505         
1506         return self.SetFlag(self.optionBottomDockable, b)
1507
1508     
1509     def LeftDockable(self, b=True):
1510         """
1511         Indicates whether a pane can be docked on the left of the frame.
1512
1513         :param `b`: whether the pane can be docked at the left or not.
1514         """
1515
1516         return self.SetFlag(self.optionLeftDockable, b)
1517
1518     
1519     def RightDockable(self, b=True):
1520         """
1521         Indicates whether a pane can be docked on the right of the frame.
1522
1523         :param `b`: whether the pane can be docked at the right or not.
1524         """
1525         
1526         return self.SetFlag(self.optionRightDockable, b)
1527
1528     
1529     def Floatable(self, b=True):
1530         """
1531         Sets whether the user will be able to undock a pane and turn it
1532         into a floating window.
1533
1534         :param `b`: whether the pane can be floated or not.
1535         """
1536         
1537         return self.SetFlag(self.optionFloatable, b)
1538
1539     
1540     def Movable(self, b=True):
1541         """
1542         Indicates whether a pane can be moved.
1543
1544         :param `b`: whether the pane can be moved or not.
1545         """
1546         
1547         return self.SetFlag(self.optionMovable, b)
1548
1549
1550     def NotebookDockable(self, b=True):
1551         """
1552         Indicates whether a pane can be docked in an automatic L{AuiNotebook}.
1553
1554         :param `b`: whether the pane can be docked in a notebook or not.
1555         """
1556         
1557         return self.SetFlag(self.optionNotebookDockable, b)
1558                                   
1559
1560     def DockFixed(self, b=True):
1561         """
1562         Causes the containing dock to have no resize sash. This is useful
1563         for creating panes that span the entire width or height of a dock, but should
1564         not be resizable in the other direction.
1565
1566         :param `b`: whether the pane will have a resize sash or not.
1567         """
1568
1569         return self.SetFlag(self.optionDockFixed, b)
1570
1571                                    
1572     def Dockable(self, b=True):
1573         """
1574         Specifies whether a frame can be docked or not. It is the same as specifying
1575         L{TopDockable} . L{BottomDockable} . L{LeftDockable} . L{RightDockable} .
1576
1577         :param `b`: whether the frame can be docked or not.
1578         """
1579
1580         return self.TopDockable(b).BottomDockable(b).LeftDockable(b).RightDockable(b)
1581     
1582
1583     def TopSnappable(self, b=True):
1584         """
1585         Indicates whether a pane can be snapped at the top of the main frame.
1586
1587         :param `b`: whether the pane can be snapped at the top of the main frame or not.
1588         """
1589         
1590         return self.SetFlag(self.optionTopSnapped, b)
1591
1592     
1593     def BottomSnappable(self, b=True):
1594         """
1595         Indicates whether a pane can be snapped at the bottom of the main frame.
1596
1597         :param `b`: whether the pane can be snapped at the bottom of the main frame or not.
1598         """
1599         
1600         return self.SetFlag(self.optionBottomSnapped, b)
1601
1602     
1603     def LeftSnappable(self, b=True):
1604         """
1605         Indicates whether a pane can be snapped on the left of the main frame.
1606
1607         :param `b`: whether the pane can be snapped at the left of the main frame or not.
1608         """
1609
1610         return self.SetFlag(self.optionLeftSnapped, b)
1611
1612     
1613     def RightSnappable(self, b=True):
1614         """
1615         Indicates whether a pane can be snapped on the right of the main frame.
1616
1617         :param `b`: whether the pane can be snapped at the right of the main frame or not.
1618         """
1619         
1620         return self.SetFlag(self.optionRightSnapped, b)
1621
1622
1623     def Snappable(self, b=True):
1624         """
1625         Indicates whether a pane can be snapped on the main frame. This is
1626         equivalent as calling L{TopSnappable} . L{BottomSnappable} . L{LeftSnappable} . L{RightSnappable} .
1627
1628         :param `b`: whether the pane can be snapped on the main frame or not.
1629         """
1630     
1631         return self.TopSnappable(b).BottomSnappable(b).LeftSnappable(b).RightSnappable(b)
1632
1633
1634     def FlyOut(self, b=True):
1635         """
1636         Indicates whether a pane, when floating, has a "fly-out" effect
1637         (i.e., floating panes which only show themselves when moused over).
1638
1639         :param `b`: whether the pane can be snapped on the main frame or not.
1640         """
1641
1642         return self.SetFlag(self.optionFlyOut, b)
1643     
1644     
1645     # Copy over the members that pertain to docking position
1646     def SetDockPos(self, source):
1647         """
1648         Copies the `source` pane members that pertain to docking position to `self`.
1649
1650         :param `source`: the source pane from where to copy the attributes.
1651         """
1652         
1653         self.dock_direction = source.dock_direction
1654         self.dock_layer = source.dock_layer
1655         self.dock_row = source.dock_row
1656         self.dock_pos = source.dock_pos
1657         self.dock_proportion = source.dock_proportion
1658         self.floating_pos = wx.Point(*source.floating_pos)
1659         self.floating_size = wx.Size(*source.floating_size)
1660         self.rect = wx.Rect(*source.rect)
1661         
1662         return self
1663
1664
1665     def DefaultPane(self):
1666         """ Specifies that the pane should adopt the default pane settings. """
1667         
1668         state = self.state    
1669         state |= self.optionTopDockable | self.optionBottomDockable | \
1670                  self.optionLeftDockable | self.optionRightDockable | \
1671                  self.optionNotebookDockable | \
1672                  self.optionFloatable | self.optionMovable | self.optionResizable | \
1673                  self.optionCaption | self.optionPaneBorder | self.buttonClose
1674
1675         self.state = state
1676         
1677         return self
1678     
1679     
1680     def CentrePane(self):
1681         """
1682         Specifies that the pane should adopt the default center pane settings.
1683
1684         Centre panes usually do not have caption bars. This function provides an easy way of
1685         preparing a pane to be displayed in the center dock position.
1686         """
1687         
1688         return self.CenterPane()
1689
1690     
1691     def CenterPane(self):
1692         """
1693         Specifies that the pane should adopt the default center pane settings.
1694
1695         Centre panes usually do not have caption bars. This function provides an easy way of
1696         preparing a pane to be displayed in the center dock position.
1697         """
1698         
1699         self.state = 0
1700         return self.Center().PaneBorder().Resizable()
1701     
1702      
1703     def ToolbarPane(self):
1704         """ Specifies that the pane should adopt the default toolbar pane settings. """
1705         
1706         self.DefaultPane()
1707         state = self.state
1708         
1709         state |= (self.optionToolbar | self.optionGripper)
1710         state &= ~(self.optionResizable | self.optionCaption | self.optionCaptionLeft)
1711         
1712         if self.dock_layer == 0:
1713             self.dock_layer = 10
1714
1715         self.state = state
1716         
1717         return self
1718
1719
1720     def Icon(self, icon):
1721         """
1722         Specifies whether an icon is drawn on the left of the caption text when
1723         the pane is docked. If `icon` is ``None`` or `wx.NullIcon`, no icon is drawn on
1724         the caption space.
1725
1726         :param icon: an icon to draw on the caption space, or ``None``.
1727         """
1728
1729         if icon is None:
1730             icon = wx.NullIcon
1731             
1732         self.icon = icon
1733         return self        
1734     
1735
1736     def SetFlag(self, flag, option_state):
1737         """
1738         Turns the property given by `flag` on or off with the `option_state`
1739         parameter.
1740
1741         :param `flag`: the property to set;
1742         :param `option_state`: either ``True`` or ``False``.
1743         """
1744         
1745         state = self.state
1746         
1747         if option_state:
1748             state |= flag
1749         else:
1750             state &= ~flag
1751
1752         self.state = state
1753
1754         if flag in [self.buttonClose, self.buttonMaximize, self.buttonMinimize, self.buttonPin]:
1755             self.ResetButtons()
1756             
1757         return self
1758     
1759     
1760     def HasFlag(self, flag):
1761         """
1762         Returns ``True`` if the the property specified by flag is active for the pane.
1763
1764         :param `flag`: the property to check for activity.
1765         """
1766         
1767         return (self.state & flag and [True] or [False])[0]
1768
1769
1770     def ResetButtons(self):
1771         """
1772         Resets all the buttons and recreates them from scratch depending on the
1773         L{AuiPaneInfo} flags.
1774         """
1775
1776         floating = self.HasFlag(self.optionFloating)
1777         self.buttons = []
1778
1779         if not floating and self.HasMinimizeButton():
1780             button = AuiPaneButton(AUI_BUTTON_MINIMIZE)
1781             self.buttons.append(button)
1782     
1783         if not floating and self.HasMaximizeButton():
1784             button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE)
1785             self.buttons.append(button)
1786
1787         if not floating and self.HasPinButton():
1788             button = AuiPaneButton(AUI_BUTTON_PIN)
1789             self.buttons.append(button)
1790
1791         if self.HasCloseButton():
1792             button = AuiPaneButton(AUI_BUTTON_CLOSE)
1793             self.buttons.append(button)
1794         
1795
1796     def CountButtons(self):
1797         """ Returns the number of visible buttons in the docked pane. """
1798
1799         n = 0
1800         
1801         if self.HasCaption() or self.HasCaptionLeft():
1802             if isinstance(wx.GetTopLevelParent(self.window), AuiFloatingFrame):
1803                 return 1
1804             
1805             if self.HasCloseButton():
1806                 n += 1
1807             if self.HasMaximizeButton():
1808                 n += 1
1809             if self.HasMinimizeButton():
1810                 n += 1
1811             if self.HasPinButton():
1812                 n += 1
1813
1814         return n
1815     
1816
1817     def IsHorizontal(self):
1818         """ Returns ``True`` if the pane `dock_direction` is horizontal. """
1819
1820         return self.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]
1821
1822     def IsVertical(self):
1823         """ Returns ``True`` if the pane `dock_direction` is vertical. """
1824
1825         return self.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT]
1826
1827
1828 # Null AuiPaneInfo reference
1829 NonePaneInfo = AuiPaneInfo()
1830
1831
1832 # ---------------------------------------------------------------------------- #
1833
1834 class AuiDockingGuide(wx.Frame):
1835     """ Base class for L{AuiCenterDockingGuide} and L{AuiSingleDockingGuide}."""
1836
1837     def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
1838                  size=wx.DefaultSize, style=wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP |
1839                  wx.FRAME_NO_TASKBAR | wx.NO_BORDER, name="AuiDockingGuide"):
1840         """
1841         Default class constructor. Used internally, do not call it in your code!
1842
1843         :param `parent`: the L{AuiDockingGuide} parent;
1844         :param `id`: the window identifier. It may take a value of -1 to indicate a default value.
1845         :param `title`: the caption to be displayed on the frame's title bar.
1846         :param `pos`: the window position. A value of (-1, -1) indicates a default position,
1847          chosen by either the windowing system or wxPython, depending on platform.
1848         :param `size`: the window size. A value of (-1, -1) indicates a default size, chosen by
1849          either the windowing system or wxPython, depending on platform.
1850         :param `style`: the window style. 
1851         :param `name`: the name of the window. This parameter is used to associate a name with the
1852          item, allowing the application user to set Motif resource values for individual windows.
1853         """
1854
1855         wx.Frame.__init__(self, parent, id, title, pos, size, style, name=name)
1856
1857
1858     def HitTest(self, x, y):
1859         """
1860         To be overridden by parent classes.
1861
1862         :param `x`: the `x` mouse position;
1863         :param `y`: the `y` mouse position.
1864         """
1865
1866         return 0
1867
1868     
1869     def ValidateNotebookDocking(self, valid):
1870         """
1871         To be overridden by parent classes.
1872
1873         :param `valid`: whether a pane can be docked on top to another to form an automatic
1874          L{AuiNotebook}.
1875         """
1876         
1877         return 0
1878
1879 # ============================================================================
1880 # implementation
1881 # ============================================================================
1882
1883 # ---------------------------------------------------------------------------
1884 # AuiDockingGuideWindow
1885 # ---------------------------------------------------------------------------
1886
1887 class AuiDockingGuideWindow(wx.Window):
1888     """ Target class for L{AuiSingleDockingGuide} and L{AuiCenterDockingGuide}. """
1889
1890     def __init__(self, parent, rect, direction=0, center=False, useAero=False):
1891         """
1892         Default class constructor. Used internally, do not call it in your code!
1893
1894         :param `parent`: the L{AuiDockingGuideWindow} parent;
1895         :param `rect`: the window rect;
1896         :param `direction`: one of ``wx.TOP``, ``wx.BOTTOM``, ``wx.LEFT``, ``wx.RIGHT``,
1897          ``wx.CENTER``;
1898         :param `center`: whether the calling class is a L{AuiCenterDockingGuide};
1899         :param `useAero`: whether to use the new Aero-style bitmaps or Whidbey-style bitmaps
1900          for the docking guide.
1901         """
1902
1903         wx.Window.__init__(self, parent, -1, rect.GetPosition(), rect.GetSize(), wx.NO_BORDER)
1904
1905         self._direction = direction
1906         self._center = center
1907         self._valid = True
1908         self._useAero = useAero
1909         
1910         self._bmp_unfocus, self._bmp_focus = GetDockingImage(direction, useAero, center)
1911         
1912         self._currentImage = self._bmp_unfocus
1913         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
1914         
1915         self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
1916         self.Bind(wx.EVT_PAINT, self.OnPaint)
1917
1918
1919     def SetValid(self, valid):
1920         """
1921         Sets the docking direction as valid or invalid.
1922
1923         :param `valid`: whether the docking direction is allowed or not.
1924         """
1925
1926         self._valid = valid
1927
1928
1929     def IsValid(self):
1930         """ Returns whether the docking direction is valid. """
1931         
1932         return self._valid
1933
1934
1935     def OnEraseBackground(self, event):
1936         """
1937         Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{AuiDockingGuideWindow}.
1938
1939         :param `event`: a `wx.EraseEvent` to be processed.
1940
1941         :note: This is intentionally empty to reduce flickering while drawing.
1942         """
1943
1944         pass
1945
1946
1947     def DrawBackground(self, dc):
1948         """
1949         Draws the docking guide background.
1950
1951         :param `dc`: a `wx.DC` device context object.
1952         """
1953
1954         rect = self.GetClientRect()
1955
1956         dc.SetPen(wx.TRANSPARENT_PEN)
1957         dc.SetBrush(wx.Brush(colourTargetBackground))
1958         dc.DrawRectangleRect(rect)
1959
1960         dc.SetPen(wx.Pen(colourTargetBorder))
1961
1962         left = rect.GetLeft()
1963         top = rect.GetTop()
1964         right = rect.GetRight()
1965         bottom = rect.GetBottom()
1966
1967         if self._direction != wx.CENTER:
1968         
1969             if not self._center or self._direction != wx.BOTTOM:
1970                 dc.DrawLine(left, top, right+1, top)
1971             if not self._center or self._direction != wx.RIGHT:
1972                 dc.DrawLine(left, top, left, bottom+1)
1973             if not self._center or self._direction != wx.LEFT:
1974                 dc.DrawLine(right, top, right, bottom+1)
1975             if not self._center or self._direction != wx.TOP:
1976                 dc.DrawLine(left, bottom, right+1, bottom)
1977
1978             dc.SetPen(wx.Pen(colourTargetShade))
1979
1980             if self._direction != wx.RIGHT:
1981                 dc.DrawLine(left + 1, top + 1, left + 1, bottom)
1982             if self._direction != wx.BOTTOM:
1983                 dc.DrawLine(left + 1, top + 1, right, top + 1)
1984
1985         
1986     def DrawDottedLine(self, dc, point, length, vertical):
1987         """
1988         Draws a dotted line (not used if the docking guide images are ok).
1989
1990         :param `dc`: a `wx.DC` device context object;
1991         :param `point`: a `wx.Point` where to start drawing the dotted line;
1992         :param `length`: the length of the dotted line;
1993         :param `vertical`: whether it is a vertical docking guide window or not.
1994         """
1995
1996         for i in xrange(0, length, 2):
1997             dc.DrawPoint(point.x, point.y)
1998             if vertical:
1999                 point.y += 2
2000             else:
2001                 point.x += 2
2002         
2003
2004     def DrawIcon(self, dc):
2005         """
2006         Draws the docking guide icon (not used if the docking guide images are ok).
2007
2008         :param `dc`: a `wx.DC` device context object.
2009         """
2010
2011         rect = wx.Rect(*self.GetClientRect())
2012         point = wx.Point()
2013         length = 0
2014
2015         rect.Deflate(4, 4)
2016         dc.SetPen(wx.Pen(colourIconBorder))
2017         dc.SetBrush(wx.Brush(colourIconBackground))
2018         dc.DrawRectangleRect(rect)
2019
2020         right1 = rect.GetRight() + 1
2021         bottom1 = rect.GetBottom() + 1
2022
2023         dc.SetPen(wx.Pen(colourIconShadow))
2024         dc.DrawLine(rect.x + 1, bottom1, right1 + 1, bottom1)
2025         dc.DrawLine(right1, rect.y + 1, right1, bottom1 + 1)
2026
2027         rect.Deflate(1, 1)
2028
2029         if self._direction == wx.TOP:
2030             rect.height -= rect.height / 2
2031             point = rect.GetBottomLeft()
2032             length = rect.width
2033
2034         elif self._direction == wx.LEFT:
2035             rect.width -= rect.width / 2
2036             point = rect.GetTopRight()
2037             length = rect.height
2038
2039         elif self._direction == wx.RIGHT:
2040             rect.x += rect.width / 2
2041             rect.width -= rect.width / 2
2042             point = rect.GetTopLeft()
2043             length = rect.height
2044
2045         elif self._direction == wx.BOTTOM:
2046             rect.y += rect.height / 2
2047             rect.height -= rect.height / 2
2048             point = rect.GetTopLeft()
2049             length = rect.width
2050
2051         elif self._direction == wx.CENTER:
2052             rect.Deflate(1, 1)
2053             point = rect.GetTopLeft()
2054             length = rect.width
2055
2056         dc.GradientFillLinear(rect, colourIconDockingPart1,
2057                               colourIconDockingPart2, self._direction)
2058
2059         dc.SetPen(wx.Pen(colourIconBorder))
2060
2061         if self._direction == wx.CENTER:        
2062             self.DrawDottedLine(dc, rect.GetTopLeft(), rect.width, False)
2063             self.DrawDottedLine(dc, rect.GetTopLeft(), rect.height, True)
2064             self.DrawDottedLine(dc, rect.GetBottomLeft(), rect.width, False)
2065             self.DrawDottedLine(dc, rect.GetTopRight(), rect.height, True)
2066         
2067         elif self._direction in [wx.TOP, wx.BOTTOM]:
2068             self.DrawDottedLine(dc, point, length, False)
2069         
2070         else:
2071             self.DrawDottedLine(dc, point, length, True)
2072         
2073
2074     def DrawArrow(self, dc):
2075         """
2076         Draws the docking guide arrow icon (not used if the docking guide images are ok).
2077
2078         :param `dc`: a `wx.DC` device context object.
2079         """
2080
2081         rect = self.GetClientRect()
2082         point = wx.Point()
2083
2084         point.x = (rect.GetLeft() + rect.GetRight()) / 2
2085         point.y = (rect.GetTop() + rect.GetBottom()) / 2
2086         rx, ry = wx.Size(), wx.Size()
2087         
2088         if self._direction == wx.TOP:
2089             rx = wx.Size(1, 0)
2090             ry = wx.Size(0, 1)
2091
2092         elif self._direction == wx.LEFT:
2093             rx = wx.Size(0, -1)
2094             ry = wx.Size(1, 0)
2095
2096         elif self._direction == wx.RIGHT:
2097             rx = wx.Size(0, 1)
2098             ry = wx.Size(-1, 0)
2099
2100         elif self._direction == wx.BOTTOM:
2101             rx = wx.Size(-1, 0)
2102             ry = wx.Size(0, -1)        
2103
2104         point.x += ry.x*3
2105         point.y += ry.y*3
2106
2107         dc.SetPen(wx.Pen(colourIconArrow))
2108
2109         for i in xrange(4):
2110             pt1 = wx.Point(point.x - rx.x*i, point.y - rx.y*i)
2111             pt2 = wx.Point(point.x + rx.x*(i+1), point.y + rx.y*(i+1))
2112             dc.DrawLinePoint(pt1, pt2)
2113             point.x += ry.x
2114             point.y += ry.y
2115
2116     
2117     def OnPaint(self, event):
2118         """
2119         Handles the ``wx.EVT_PAINT`` event for L{AuiDockingGuideWindow}.
2120
2121         :param `event`: a `wx.PaintEvent` to be processed.
2122         """
2123
2124         dc = wx.AutoBufferedPaintDC(self)
2125         if self._currentImage.IsOk() and self._valid:
2126             dc.DrawBitmap(self._currentImage, 0, 0, True)
2127         else:
2128             self.Draw(dc)
2129
2130
2131     def Draw(self, dc):
2132         """
2133         Draws the whole docking guide window (not used if the docking guide images are ok).
2134
2135         :param `dc`: a `wx.DC` device context object.
2136         """
2137
2138         self.DrawBackground(dc)
2139
2140         if self._valid:
2141             self.DrawIcon(dc)
2142             self.DrawArrow(dc)
2143
2144
2145     def UpdateDockGuide(self, pos):
2146         """
2147         Updates the docking guide images depending on the mouse position, using focused
2148         images if the mouse is inside the docking guide or unfocused images if it is
2149         outside.
2150
2151         :param `pos`: a `wx.Point` mouse position.
2152         """
2153
2154         inside = self.GetScreenRect().Contains(pos)
2155         
2156         if inside:
2157             image = self._bmp_focus
2158         else:
2159             image = self._bmp_unfocus
2160
2161         if image != self._currentImage:
2162             self._currentImage = image
2163             self.Refresh()
2164             self.Update()
2165
2166
2167 # ---------------------------------------------------------------------------
2168 # AuiSingleDockingGuide
2169 # ---------------------------------------------------------------------------
2170
2171 class AuiSingleDockingGuide(AuiDockingGuide):
2172     """ A docking guide window for single docking hint (not diamond-shaped HUD). """
2173     
2174     def __init__(self, parent, direction=0):
2175         """
2176         Default class constructor. Used internally, do not call it in your code!
2177
2178         :param `parent`: the L{AuiSingleDockingGuide} parent;
2179         :param `direction`: one of ``wx.TOP``, ``wx.BOTTOM``, ``wx.LEFT``, ``wx.RIGHT``.
2180         """
2181
2182         self._direction = direction
2183
2184         style = wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP | \
2185                 wx.FRAME_NO_TASKBAR | wx.NO_BORDER
2186
2187         # Use of FRAME_SHAPED on wxMac causes the frame to be visible
2188         # breaking the docking hints.
2189         if wx.Platform != '__WXMAC__':
2190             style |= wx.FRAME_SHAPED
2191
2192         AuiDockingGuide.__init__(self, parent, style=style, name="auiSingleDockTarget")
2193         
2194         self.Hide()
2195
2196         useAero = GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_AERO_DOCKING_GUIDES
2197         useWhidbey = GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES
2198         
2199         self._useAero = useAero or useWhidbey
2200         self._valid = True
2201         
2202         if useAero:
2203             sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
2204         elif useWhidbey:
2205             sizeX, sizeY = whidbeySizeX, whidbeySizeY
2206         else:
2207             sizeX, sizeY = guideSizeX, guideSizeY
2208
2209         if direction not in [wx.TOP, wx.BOTTOM]:
2210             sizeX, sizeY = sizeY, sizeX
2211
2212         if self._useAero:
2213             self.CreateShapesWithStyle(useWhidbey)
2214             
2215             if wx.Platform == "__WXGTK__":
2216                 self.Bind(wx.EVT_WINDOW_CREATE, self.SetGuideShape)
2217             else:
2218                 self.SetGuideShape()
2219             
2220             self.SetSize(self.region.GetBox().GetSize())
2221         else:
2222             self.SetSize((sizeX, sizeY))
2223             
2224         self.rect = wx.Rect(0, 0, sizeX, sizeY)
2225
2226         if self._useAero:
2227             useAero = (useWhidbey and [2] or [1])[0]
2228         else:
2229             useAero = 0
2230             
2231         self.target = AuiDockingGuideWindow(self, self.rect, direction, False, useAero)
2232
2233
2234     def CreateShapesWithStyle(self, useWhidbey):
2235         """
2236         Creates the docking guide window shape based on which docking bitmaps are used.
2237
2238         :param `useWhidbey`: if ``True``, use Whidbey-style bitmaps; if ``False``, use the
2239          Aero-style bitmaps.
2240          """
2241
2242         sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
2243         if useWhidbey:
2244             sizeX, sizeY = whidbeySizeX, whidbeySizeY
2245
2246         if self._direction not in [wx.TOP, wx.BOTTOM]:
2247             sizeX, sizeY = sizeY, sizeX
2248
2249         useAero = (useWhidbey and [2] or [1])[0]      
2250         bmp, dummy = GetDockingImage(self._direction, useAero, False)
2251         region = wx.RegionFromBitmap(bmp)
2252             
2253         self.region = region
2254         
2255
2256     def AeroMove(self, pos):
2257         """
2258         Moves the docking window to the new position. Overridden in children classes.
2259
2260         :param `pos`: the new docking guide position.
2261         """
2262
2263         pass
2264     
2265
2266     def SetGuideShape(self, event=None):
2267         """
2268         Sets the correct shape for the docking guide window.
2269
2270         :param `event`: on wxGTK, a `wx.WindowCreateEvent` event to process.
2271         """
2272
2273         self.SetShape(self.region)        
2274                 
2275         if event is not None:
2276             # Skip the event on wxGTK
2277             event.Skip()
2278             wx.CallAfter(wx.SafeYield, self, True)
2279
2280
2281     def SetShape(self, region):
2282         """
2283         If the platform supports it, sets the shape of the window to that depicted by `region`.
2284         The system will not display or respond to any mouse event for the pixels that lie
2285         outside of the region. To reset the window to the normal rectangular shape simply call
2286         L{SetShape} again with an empty region. 
2287
2288         :param `region`: the shape of the frame.
2289
2290         :note: Overridden for wxMac.        
2291         """
2292         
2293         if wx.Platform == '__WXMAC__':
2294             # HACK so we don't crash when SetShape is called
2295             return
2296         else:
2297             super(AuiSingleDockingGuide, self).SetShape(region)
2298
2299
2300     def SetValid(self, valid):
2301         """
2302         Sets the docking direction as valid or invalid.
2303
2304         :param `valid`: whether the docking direction is allowed or not.
2305         """
2306
2307         self._valid = valid
2308
2309
2310     def IsValid(self):
2311         """ Returns whether the docking direction is valid. """
2312         
2313         return self._valid
2314
2315
2316     def UpdateDockGuide(self, pos):
2317         """
2318         Updates the docking guide images depending on the mouse position, using focused
2319         images if the mouse is inside the docking guide or unfocused images if it is
2320         outside.
2321
2322         :param `pos`: a `wx.Point` mouse position.
2323         """
2324
2325         self.target.UpdateDockGuide(pos)
2326
2327         
2328     def HitTest(self, x, y):
2329         """
2330         Checks if the mouse position is inside the target window rect.
2331
2332         :param `x`: the `x` mouse position;
2333         :param `y`: the `y` mouse position.
2334         """
2335
2336         if self.target.GetScreenRect().Contains((x, y)):
2337             return wx.ALL
2338
2339         return -1
2340
2341
2342 # ---------------------------------------------------------------------------
2343 # AuiCenterDockingGuide
2344 # ---------------------------------------------------------------------------
2345
2346 class AuiCenterDockingGuide(AuiDockingGuide):
2347     """ A docking guide window for multiple docking hint (diamond-shaped HUD). """
2348     
2349     def __init__(self, parent):
2350         """
2351         Default class constructor.
2352         Used internally, do not call it in your code!
2353
2354         :param `parent`: the L{AuiCenterDockingGuide} parent.
2355         """
2356
2357         AuiDockingGuide.__init__(self, parent, style=wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP |
2358                                  wx.FRAME_NO_TASKBAR | wx.NO_BORDER | wx.FRAME_SHAPED,
2359                                  name="auiCenterDockTarget")
2360
2361         self.Hide()
2362
2363         self.CreateShapesWithStyle()
2364         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
2365         
2366         if wx.Platform == "__WXGTK__":
2367             self.Bind(wx.EVT_WINDOW_CREATE, self.SetGuideShape)
2368         else:
2369             self.SetGuideShape()
2370             
2371         self.SetSize(self.region.GetBox().GetSize())
2372
2373         self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
2374         self.Bind(wx.EVT_PAINT, self.OnPaint)
2375
2376
2377     def CreateShapesWithStyle(self):
2378         """ Creates the docking guide window shape based on which docking bitmaps are used. """
2379
2380         useAero = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_AERO_DOCKING_GUIDES) != 0
2381         useWhidbey = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES) != 0
2382
2383         self._useAero = 0
2384         if useAero:
2385             self._useAero = 1
2386         elif useWhidbey:
2387             self._useAero = 2
2388         
2389         if useAero:
2390             sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
2391         elif useWhidbey:
2392             sizeX, sizeY = whidbeySizeX, whidbeySizeY          
2393         else:
2394             sizeX, sizeY = guideSizeX, guideSizeY
2395
2396         rectLeft = wx.Rect(0, sizeY, sizeY, sizeX)
2397         rectTop = wx.Rect(sizeY, 0, sizeX, sizeY)
2398         rectRight = wx.Rect(sizeY+sizeX, sizeY, sizeY, sizeX)
2399         rectBottom = wx.Rect(sizeY, sizeX + sizeY, sizeX, sizeY)
2400         rectCenter = wx.Rect(sizeY, sizeY, sizeX, sizeX)
2401             
2402         if not self._useAero:
2403
2404             self.targetLeft = AuiDockingGuideWindow(self, rectLeft, wx.LEFT, True, useAero)
2405             self.targetTop = AuiDockingGuideWindow(self, rectTop, wx.TOP, True, useAero)
2406             self.targetRight = AuiDockingGuideWindow(self, rectRight, wx.RIGHT, True, useAero)
2407             self.targetBottom = AuiDockingGuideWindow(self, rectBottom, wx.BOTTOM, True, useAero)
2408             self.targetCenter = AuiDockingGuideWindow(self, rectCenter, wx.CENTER, True, useAero)
2409
2410             
2411             # top-left diamond
2412             tld = [wx.Point(rectTop.x, rectTop.y+rectTop.height-8),
2413                    wx.Point(rectLeft.x+rectLeft.width-8, rectLeft.y),
2414                    rectTop.GetBottomLeft()]
2415             # bottom-left diamond
2416             bld = [wx.Point(rectLeft.x+rectLeft.width-8, rectLeft.y+rectLeft.height),
2417                    wx.Point(rectBottom.x, rectBottom.y+8),
2418                    rectBottom.GetTopLeft()]
2419             # top-right diamond
2420             trd = [wx.Point(rectTop.x+rectTop.width, rectTop.y+rectTop.height-8),
2421                    wx.Point(rectRight.x+8, rectRight.y),
2422                    rectRight.GetTopLeft()]        
2423             # bottom-right diamond
2424             brd = [wx.Point(rectRight.x+8, rectRight.y+rectRight.height),
2425                    wx.Point(rectBottom.x+rectBottom.width, rectBottom.y+8),
2426                    rectBottom.GetTopRight()]
2427
2428             self._triangles = [tld[0:2], bld[0:2],
2429                                [wx.Point(rectTop.x+rectTop.width-1, rectTop.y+rectTop.height-8),
2430                                 wx.Point(rectRight.x+7, rectRight.y)],
2431                                [wx.Point(rectRight.x+7, rectRight.y+rectRight.height),
2432                                 wx.Point(rectBottom.x+rectBottom.width-1, rectBottom.y+8)]]
2433             
2434             region = wx.Region()
2435             region.UnionRect(rectLeft)
2436             region.UnionRect(rectTop)
2437             region.UnionRect(rectRight)
2438             region.UnionRect(rectBottom)
2439             region.UnionRect(rectCenter)
2440             region.UnionRegion(wx.RegionFromPoints(tld))
2441             region.UnionRegion(wx.RegionFromPoints(bld))
2442             region.UnionRegion(wx.RegionFromPoints(trd))
2443             region.UnionRegion(wx.RegionFromPoints(brd))
2444
2445         elif useAero:
2446
2447             self._aeroBmp = aero_dock_pane.GetBitmap()
2448             region = wx.RegionFromBitmap(self._aeroBmp)
2449
2450             self._allAeroBmps = [aero_dock_pane_left.GetBitmap(), aero_dock_pane_top.GetBitmap(),
2451                                  aero_dock_pane_right.GetBitmap(), aero_dock_pane_bottom.GetBitmap(),
2452                                  aero_dock_pane_center.GetBitmap(), aero_dock_pane.GetBitmap()]
2453             self._deniedBitmap = aero_denied.GetBitmap()
2454             self._aeroRects = [rectLeft, rectTop, rectRight, rectBottom, rectCenter]
2455             self._valid = True
2456
2457         elif useWhidbey:
2458
2459             self._aeroBmp = whidbey_dock_pane.GetBitmap()
2460             region = wx.RegionFromBitmap(self._aeroBmp)
2461
2462             self._allAeroBmps = [whidbey_dock_pane_left.GetBitmap(), whidbey_dock_pane_top.GetBitmap(),
2463                                  whidbey_dock_pane_right.GetBitmap(), whidbey_dock_pane_bottom.GetBitmap(),
2464                                  whidbey_dock_pane_center.GetBitmap(), whidbey_dock_pane.GetBitmap()]
2465             self._deniedBitmap = whidbey_denied.GetBitmap()
2466             self._aeroRects = [rectLeft, rectTop, rectRight, rectBottom, rectCenter]
2467             self._valid = True
2468             
2469             
2470         self.region = region
2471         
2472
2473     def SetGuideShape(self, event=None):
2474         """
2475         Sets the correct shape for the docking guide window.
2476
2477         :param `event`: on wxGTK, a `wx.WindowCreateEvent` event to process.
2478         """
2479
2480         self.SetShape(self.region)        
2481
2482         if event is not None:
2483             # Skip the event on wxGTK
2484             event.Skip()
2485             wx.CallAfter(wx.SafeYield, self, True)
2486
2487             
2488     def UpdateDockGuide(self, pos):
2489         """
2490         Updates the docking guides images depending on the mouse position, using focused
2491         images if the mouse is inside the docking guide or unfocused images if it is
2492         outside.
2493
2494         :param `pos`: a `wx.Point` mouse position.
2495         """
2496
2497         if not self._useAero:
2498             for target in self.GetChildren():
2499                 target.UpdateDockGuide(pos)
2500         else:
2501             lenRects = len(self._aeroRects)
2502             for indx, rect in enumerate(self._aeroRects):
2503                 if rect.Contains(pos):
2504                     if self._allAeroBmps[indx] != self._aeroBmp:
2505                         if indx < lenRects - 1 or (indx == lenRects - 1 and self._valid):
2506                             self._aeroBmp = self._allAeroBmps[indx]
2507                             self.Refresh()
2508                         else:
2509                             self._aeroBmp = self._allAeroBmps[-1]
2510                             self.Refresh()
2511                             
2512                     return
2513
2514             if self._aeroBmp != self._allAeroBmps[-1]:
2515                 self._aeroBmp = self._allAeroBmps[-1]
2516                 self.Refresh()
2517
2518
2519     def HitTest(self, x, y):
2520         """
2521         Checks if the mouse position is inside the target windows rect.
2522
2523         :param `x`: the `x` mouse position;
2524         :param `y`: the `y` mouse position.
2525         """
2526
2527         if not self._useAero:
2528             if self.targetLeft.GetScreenRect().Contains((x, y)):
2529                 return wx.LEFT
2530             if self.targetTop.GetScreenRect().Contains((x, y)):
2531                 return wx.UP
2532             if self.targetRight.GetScreenRect().Contains((x, y)):
2533                 return wx.RIGHT
2534             if self.targetBottom.GetScreenRect().Contains((x, y)):
2535                 return wx.DOWN
2536             if self.targetCenter.IsValid() and self.targetCenter.GetScreenRect().Contains((x, y)):
2537                 return wx.CENTER
2538         else:
2539             constants = [wx.LEFT, wx.UP, wx.RIGHT, wx.DOWN, wx.CENTER]
2540             lenRects = len(self._aeroRects)
2541             for indx, rect in enumerate(self._aeroRects):
2542                 if rect.Contains((x, y)):
2543                     if indx < lenRects or (indx == lenRects-1 and self._valid):
2544                         return constants[indx]
2545
2546         return -1
2547
2548
2549     def ValidateNotebookDocking(self, valid):
2550         """
2551         Sets whether a pane can be docked on top of another to create an automatic
2552         L{AuiNotebook}.
2553
2554         :param `valid`: whether a pane can be docked on top to another to form an automatic
2555          L{AuiNotebook}.
2556         """
2557
2558         if not self._useAero:
2559             if self.targetCenter.IsValid() != valid:        
2560                 self.targetCenter.SetValid(valid)
2561                 self.targetCenter.Refresh()
2562         else:
2563             if self._valid != valid:
2564                 self._valid = valid
2565                 self.Refresh()
2566     
2567
2568     def AeroMove(self, pos):
2569         """
2570         Moves the docking guide window to the new position.
2571
2572         :param `pos`: the new docking guide position.
2573         """
2574
2575         if not self._useAero:
2576             return
2577
2578         useWhidbey = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES) != 0
2579
2580         if useWhidbey:
2581             sizeX, sizeY = whidbeySizeX, whidbeySizeY            
2582         else:
2583             sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
2584             
2585         size = self.GetSize()
2586         
2587         leftRect, topRect, rightRect, bottomRect, centerRect = self._aeroRects
2588         thePos = pos + wx.Point((size.x-sizeY)/2, (size.y-sizeX)/2)
2589         
2590         centerRect.SetPosition(thePos)
2591
2592         leftRect.SetPosition(thePos + wx.Point(-sizeY, 0))
2593         topRect.SetPosition(thePos + wx.Point(0, -sizeY))
2594         rightRect.SetPosition(thePos + wx.Point(sizeX, 0))
2595         bottomRect.SetPosition(thePos + wx.Point(0, sizeX))
2596         
2597         
2598     def OnEraseBackground(self, event):
2599         """
2600         Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{AuiCenterDockingGuide}.
2601
2602         :param `event`: `wx.EraseEvent` to be processed.
2603
2604         :note: This is intentionally empty to reduce flickering while drawing.
2605         """
2606         
2607         pass
2608
2609
2610     def OnPaint(self, event):
2611         """
2612         Handles the ``wx.EVT_PAINT`` event for L{AuiCenterDockingGuide}.
2613
2614         :param `event`: a `wx.PaintEvent` to be processed.
2615         """
2616
2617         dc = wx.AutoBufferedPaintDC(self)
2618
2619         if self._useAero:
2620             dc.SetBrush(wx.TRANSPARENT_BRUSH)
2621             dc.SetPen(wx.TRANSPARENT_PEN)
2622         else:
2623             dc.SetBrush(wx.Brush(colourTargetBackground))
2624             dc.SetPen(wx.Pen(colourTargetBorder))
2625
2626         rect = self.GetClientRect()
2627         dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
2628
2629         if self._useAero:
2630             dc.DrawBitmap(self._aeroBmp, 0, 0, True)
2631             if not self._valid:
2632                 diff = (self._useAero == 2 and [1] or [0])[0]
2633                 bmpX, bmpY = self._deniedBitmap.GetWidth(), self._deniedBitmap.GetHeight()
2634                 xPos, yPos = (rect.x + (rect.width)/2 - bmpX/2), (rect.y + (rect.height)/2 - bmpY/2)
2635                 dc.DrawBitmap(self._deniedBitmap, xPos+1, yPos+diff, True)
2636                 
2637             return
2638         
2639         dc.SetPen(wx.Pen(colourTargetBorder, 2))
2640         for pts in self._triangles:
2641             dc.DrawLinePoint(pts[0], pts[1])
2642             
2643
2644 # ----------------------------------------------------------------------------
2645 # AuiDockingHintWindow
2646 # ----------------------------------------------------------------------------
2647
2648 class AuiDockingHintWindow(wx.Frame):
2649     """ The original wxAUI docking window hint. """
2650
2651     def __init__(self, parent, id=wx.ID_ANY, title="", pos=wx.DefaultPosition,
2652                  size=wx.Size(1, 1), style=wx.FRAME_TOOL_WINDOW | wx.FRAME_FLOAT_ON_PARENT |
2653                  wx.FRAME_NO_TASKBAR | wx.NO_BORDER | wx.FRAME_SHAPED,
2654                  name="auiHintWindow"):
2655         """
2656         Default class constructor. Used internally, do not call it in your code!
2657
2658         :param `parent`: the L{AuiDockingGuide} parent;
2659         :param `id`: the window identifier. It may take a value of -1 to indicate a default value.
2660         :param `title`: the caption to be displayed on the frame's title bar;
2661         :param `pos`: the window position. A value of (-1, -1) indicates a default position,
2662          chosen by either the windowing system or wxPython, depending on platform;
2663         :param `size`: the window size. A value of (-1, -1) indicates a default size, chosen by
2664          either the windowing system or wxPython, depending on platform;
2665         :param `style`: the window style;
2666         :param `name`: the name of the window. This parameter is used to associate a name with the
2667          item, allowing the application user to set Motif resource values for individual windows.
2668         """
2669         if wx.Platform == '__WXMAC__' and style & wx.FRAME_SHAPED:
2670             # Having the shaped frame causes the frame to not be visible
2671             # with the transparent style hints.
2672             style -= wx.FRAME_SHAPED
2673
2674         wx.Frame.__init__(self, parent, id, title, pos, size, style, name=name)
2675         
2676         self._blindMode = False
2677         self.SetBackgroundColour(colourHintBackground)
2678         
2679         # Can't set background colour on a frame on wxMac
2680         # so add a panel to set the colour on.
2681         if wx.Platform == '__WXMAC__':
2682             sizer = wx.BoxSizer(wx.HORIZONTAL)
2683             self.panel = wx.Panel(self)
2684             sizer.Add(self.panel, 1, wx.EXPAND)
2685             self.SetSizer(sizer)
2686             self.panel.SetBackgroundColour(colourHintBackground)
2687
2688         self.Bind(wx.EVT_SIZE, self.OnSize)
2689         
2690
2691     def MakeVenetianBlinds(self):
2692         """
2693         Creates the "venetian blind" effect if L{AuiManager} has the ``AUI_MGR_VENETIAN_BLINDS_HINT``
2694         flag set.
2695         """
2696
2697         amount = 128
2698         size = self.GetClientSize()
2699         region = wx.Region(0, 0, size.x, 1)
2700
2701         for y in xrange(size.y):
2702
2703             # Reverse the order of the bottom 4 bits
2704             j = (y & 8 and [1] or [0])[0] | (y & 4 and [2] or [0])[0] | \
2705                 (y & 2 and [4] or [0])[0] | (y & 1 and [8] or [0])[0]
2706             
2707             if 16*j+8 < amount:
2708                 region.Union(0, y, size.x, 1)
2709                         
2710         self.SetShape(region)
2711
2712
2713     def SetBlindMode(self, agwFlags):
2714         """
2715         Sets whether venetian blinds or transparent hints will be shown as docking hint.
2716         This depends on the L{AuiManager} flags.
2717
2718         :param `agwFlags`: the L{AuiManager} flags.
2719         """
2720
2721         self._blindMode = (agwFlags & AUI_MGR_VENETIAN_BLINDS_HINT) != 0
2722
2723         if self._blindMode or not self.CanSetTransparent():
2724             self.MakeVenetianBlinds()
2725             self.SetTransparent(255)
2726         
2727         else:
2728             self.SetShape(wx.Region())
2729             if agwFlags & AUI_MGR_HINT_FADE == 0:                
2730                 self.SetTransparent(80)
2731             else:
2732                 self.SetTransparent(0)
2733
2734
2735     def SetShape(self, region):
2736         """
2737         If the platform supports it, sets the shape of the window to that depicted by `region`.
2738         The system will not display or respond to any mouse event for the pixels that lie
2739         outside of the region. To reset the window to the normal rectangular shape simply call
2740         L{SetShape} again with an empty region. 
2741
2742         :param `region`: the shape of the frame (an instance of `wx.Region`).
2743
2744         :note: Overridden for wxMac.        
2745         """
2746         
2747         if wx.Platform == '__WXMAC__':
2748             # HACK so we don't crash when SetShape is called
2749             return
2750         else:
2751             super(AuiDockingHintWindow, self).SetShape(region)
2752
2753
2754     def Show(self, show=True):
2755         """
2756         Show the hint window.
2757
2758         :param `show`: whether to show or hide the hint docking window.
2759         """
2760         
2761         super(AuiDockingHintWindow, self).Show(show)
2762         if wx.Platform == '__WXMAC__':
2763             # Need to manually do layout since its a borderless frame.
2764             self.Layout()
2765
2766
2767     def OnSize(self, event):
2768         """
2769         Handles the ``wx.EVT_SIZE`` event for L{AuiDockingHintWindow}.
2770
2771         :param `event`: a `wx.SizeEvent` to be processed.
2772         """
2773
2774         if self._blindMode or not self.CanSetTransparent():
2775             self.MakeVenetianBlinds()
2776
2777
2778 # ---------------------------------------------------------------------------- #
2779
2780 # -- AuiFloatingFrame class implementation --            
2781
2782 class AuiFloatingFrame(wx.MiniFrame):
2783     """ AuiFloatingFrame is the frame class that holds floating panes. """
2784
2785     def __init__(self, parent, owner_mgr, pane=None, id=wx.ID_ANY, title="",
2786                  style=wx.FRAME_TOOL_WINDOW | wx.FRAME_FLOAT_ON_PARENT |
2787                  wx.FRAME_NO_TASKBAR | wx.CLIP_CHILDREN):
2788         """
2789         Default class constructor. Used internally, do not call it in your code!
2790
2791         :param `parent`: the L{AuiFloatingFrame} parent;
2792         :param `owner_mgr`: the L{AuiManager} that manages the floating pane;
2793         :param `pane`: the L{AuiPaneInfo} pane that is about to float;
2794         :param `id`: the window identifier. It may take a value of -1 to indicate a default value.
2795         :param `title`: the caption to be displayed on the frame's title bar.
2796         :param `style`: the window style.
2797         """
2798             
2799         if pane and pane.IsResizeable():
2800             style += wx.RESIZE_BORDER
2801         if pane:
2802             self._is_toolbar = pane.IsToolbar()
2803
2804         self._useNativeMiniframes = False
2805         if AuiManager_UseNativeMiniframes(owner_mgr):
2806             # On wxMac we always use native miniframes
2807             self._useNativeMiniframes = True
2808             style += wx.CAPTION + wx.SYSTEM_MENU
2809             if pane.HasCloseButton():
2810                 style += wx.CLOSE_BOX
2811             if pane.HasMaximizeButton():
2812                 style += wx.MAXIMIZE_BOX
2813             if pane.HasMinimizeButton():
2814                 style += wx.MINIMIZE_BOX
2815             
2816         wx.MiniFrame.__init__(self, parent, id, title, pos=pane.floating_pos,
2817                               size=pane.floating_size, style=style, name="auiFloatingFrame")
2818
2819         self._fly_timer = wx.Timer(self, wx.ID_ANY)
2820         self._check_fly_timer = wx.Timer(self, wx.ID_ANY)
2821         
2822         self.Bind(wx.EVT_CLOSE, self.OnClose)
2823         self.Bind(wx.EVT_SIZE, self.OnSize)
2824         self.Bind(wx.EVT_ACTIVATE, self.OnActivate)
2825         self.Bind(wx.EVT_TIMER, self.OnCheckFlyTimer, self._check_fly_timer)
2826         self.Bind(wx.EVT_TIMER, self.OnFlyTimer, self._fly_timer)
2827         self.Bind(EVT_AUI_FIND_MANAGER, self.OnFindManager)
2828
2829         if self._useNativeMiniframes:
2830             self.Bind(wx.EVT_MOVE, self.OnMoveEvent)
2831             self.Bind(wx.EVT_MOVING, self.OnMoveEvent)
2832             self.Bind(wx.EVT_IDLE, self.OnIdle)
2833             self._useNativeMiniframes = True
2834             self.SetExtraStyle(wx.WS_EX_PROCESS_IDLE)
2835         else:
2836             self.Bind(wx.EVT_MOVE, self.OnMove)
2837
2838         self._fly = False
2839         self._send_size = True
2840         self._alpha_amount = 255
2841         
2842         self._owner_mgr = owner_mgr
2843         self._moving = False
2844         self._lastDirection = None
2845         self._transparent = 255
2846
2847         self._last_rect = wx.Rect()
2848         self._last2_rect = wx.Rect()
2849         self._last3_rect = wx.Rect()
2850
2851         self._mgr = AuiManager()
2852         self._mgr.SetManagedWindow(self)
2853         self._mgr.SetArtProvider(owner_mgr.GetArtProvider())
2854         self._mgr.SetAGWFlags(owner_mgr.GetAGWFlags())
2855
2856
2857     def CopyAttributes(self, pane):
2858         """
2859         Copies all the attributes of the input `pane` into another L{AuiPaneInfo}.
2860
2861         :param `pane`: the source L{AuiPaneInfo} from where to copy attributes.
2862         """
2863
2864         contained_pane = AuiPaneInfo()
2865
2866         contained_pane.name = pane.name
2867         contained_pane.caption = pane.caption
2868         contained_pane.window = pane.window
2869         contained_pane.frame = pane.frame
2870         contained_pane.state = pane.state
2871         contained_pane.dock_direction = pane.dock_direction
2872         contained_pane.dock_layer = pane.dock_layer
2873         contained_pane.dock_row = pane.dock_row
2874         contained_pane.dock_pos = pane.dock_pos
2875         contained_pane.best_size = wx.Size(*pane.best_size)
2876         contained_pane.min_size = wx.Size(*pane.min_size)
2877         contained_pane.max_size = wx.Size(*pane.max_size)
2878         contained_pane.floating_pos = wx.Point(*pane.floating_pos)
2879         contained_pane.floating_size = wx.Size(*pane.floating_size)
2880         contained_pane.dock_proportion = pane.dock_proportion
2881         contained_pane.buttons = pane.buttons
2882         contained_pane.rect = wx.Rect(*pane.rect)
2883         contained_pane.icon = pane.icon
2884         contained_pane.notebook_id = pane.notebook_id
2885         contained_pane.transparent = pane.transparent
2886         contained_pane.snapped = pane.snapped
2887         contained_pane.minimize_mode = pane.minimize_mode
2888
2889         return contained_pane
2890     
2891
2892     def SetPaneWindow(self, pane):
2893         """
2894         Sets all the properties of a pane.
2895
2896         :param `pane`: the L{AuiPaneInfo} to analyze.
2897         """
2898
2899         self._is_toolbar = pane.IsToolbar()
2900         self._pane_window = pane.window
2901
2902         if isinstance(pane.window, auibar.AuiToolBar):
2903             pane.window.SetAuiManager(self._mgr)
2904         
2905         self._pane_window.Reparent(self)
2906         
2907         contained_pane = self.CopyAttributes(pane)
2908         
2909         contained_pane.Dock().Center().Show(). \
2910                        CaptionVisible(False). \
2911                        PaneBorder(False). \
2912                        Layer(0).Row(0).Position(0)
2913
2914         if not contained_pane.HasGripper() and not self._useNativeMiniframes:
2915             contained_pane.CaptionVisible(True)
2916
2917         indx = self._owner_mgr._panes.index(pane)
2918
2919         # Carry over the minimum size
2920         pane_min_size = pane.window.GetMinSize()
2921
2922         # if the best size is smaller than the min size
2923         # then set the min size to the best size as well
2924         pane_best_size = contained_pane.best_size
2925         if pane_best_size.IsFullySpecified() and (pane_best_size.x < pane_min_size.x or \
2926                                                   pane_best_size.y < pane_min_size.y):
2927
2928             pane_min_size = pane_best_size
2929             self._pane_window.SetMinSize(pane_min_size)
2930     
2931         # if the frame window's max size is greater than the min size
2932         # then set the max size to the min size as well
2933         cur_max_size = self.GetMaxSize()
2934         if cur_max_size.IsFullySpecified() and  (cur_max_size.x < pane_min_size.x or \
2935                                                  cur_max_size.y < pane_min_size.y):
2936             self.SetMaxSize(pane_min_size)
2937
2938         art_provider = self._mgr.GetArtProvider()
2939         caption_size = art_provider.GetMetric(AUI_DOCKART_CAPTION_SIZE)
2940         button_size = art_provider.GetMetric(AUI_DOCKART_PANE_BUTTON_SIZE) + \
2941                       4*art_provider.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
2942
2943         min_size = pane.window.GetMinSize()
2944
2945         if min_size.y < caption_size or min_size.x < button_size:
2946             new_x, new_y = min_size.x, min_size.y
2947             if min_size.y < caption_size:
2948                 new_y = (pane.IsResizeable() and [2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_Y)+caption_size] or [1])[0]
2949             if min_size.x < button_size:
2950                 new_x = (pane.IsResizeable() and [2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_X)+button_size] or [1])[0]
2951                 
2952             self.SetMinSize((new_x, new_y))
2953         else:
2954             self.SetMinSize(min_size)
2955
2956         self._mgr.AddPane(self._pane_window, contained_pane)
2957         self._mgr.Update()           
2958
2959         if pane.min_size.IsFullySpecified():
2960             # because SetSizeHints() calls Fit() too (which sets the window
2961             # size to its minimum allowed), we keep the size before calling
2962             # SetSizeHints() and reset it afterwards...
2963             tmp = self.GetSize()
2964             self.GetSizer().SetSizeHints(self)
2965             self.SetSize(tmp)
2966         
2967         self.SetTitle(pane.caption)
2968
2969         if pane.floating_size != wx.Size(-1, -1):
2970             self.SetSize(pane.floating_size)
2971         else:
2972             size = pane.best_size
2973             if size == wx.Size(-1, -1):
2974                 size = pane.min_size
2975             if size == wx.Size(-1, -1):
2976                 size = self._pane_window.GetSize()
2977             if self._owner_mgr and pane.HasGripper():
2978                 if pane.HasGripperTop():
2979                     size.y += self._owner_mgr._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE)
2980                 else:
2981                     size.x += self._owner_mgr._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE)
2982
2983             if not self._useNativeMiniframes:
2984                 size.y += self._owner_mgr._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
2985                 
2986             pane.floating_size = size
2987             
2988             self.SetClientSize(size)
2989
2990         self._owner_mgr._panes[indx] = pane
2991
2992         self._fly_step = abs(pane.floating_size.y - \
2993                              (caption_size + 2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_Y)))/10
2994
2995         self._floating_size = wx.Size(*self.GetSize())
2996
2997         if pane.IsFlyOut():
2998             self._check_fly_timer.Start(50)
2999
3000         
3001     def GetOwnerManager(self):
3002         """ Returns the L{AuiManager} that manages the pane. """
3003
3004         return self._owner_mgr
3005
3006
3007     def OnSize(self, event):
3008         """
3009         Handles the ``wx.EVT_SIZE`` event for L{AuiFloatingFrame}.
3010
3011         :param `event`: a `wx.SizeEvent` to be processed.
3012         """
3013
3014         if self._owner_mgr and self._send_size:
3015             self._owner_mgr.OnFloatingPaneResized(self._pane_window, event.GetSize())
3016
3017     
3018     def OnClose(self, event):
3019         """
3020         Handles the ``wx.EVT_CLOSE`` event for L{AuiFloatingFrame}.
3021
3022         :param `event`: a `wx.CloseEvent` to be processed.
3023         """
3024
3025         if self._owner_mgr:
3026             self._owner_mgr.OnFloatingPaneClosed(self._pane_window, event)
3027
3028         if not event.GetVeto():
3029             self._mgr.DetachPane(self._pane_window)
3030
3031             if isinstance(self._pane_window, auibar.AuiToolBar):
3032                 self._pane_window.SetAuiManager(self._owner_mgr)
3033
3034             # if we do not do this, then we can crash...
3035             if self._owner_mgr and self._owner_mgr._action_window == self:
3036                 self._owner_mgr._action_window = None
3037
3038             self.Destroy()
3039     
3040
3041     def OnActivate(self, event):
3042         """
3043         Handles the ``wx.EVT_ACTIVATE`` event for L{AuiFloatingFrame}.
3044
3045         :param `event`: a `wx.ActivateEvent` to be processed.
3046         """
3047
3048         if self._owner_mgr and event.GetActive():
3049             self._owner_mgr.OnFloatingPaneActivated(self._pane_window)
3050
3051
3052     def OnMove(self, event):
3053         """
3054         Handles the ``wx.EVT_MOVE`` event for L{AuiFloatingFrame}.
3055
3056         :param `event`: a `wx.MoveEvent` to be processed.
3057
3058         :note: This event is not processed on wxMAC or if L{AuiManager} is not using the
3059          ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
3060         """
3061
3062         if self._owner_mgr:
3063             self._owner_mgr.OnFloatingPaneMoved(self._pane_window, event)
3064                 
3065
3066     def OnMoveEvent(self, event):
3067         """
3068         Handles the ``wx.EVT_MOVE`` and ``wx.EVT_MOVING`` events for L{AuiFloatingFrame}.
3069
3070         :param `event`: a `wx.MoveEvent` to be processed.
3071
3072         :note: This event is only processed on wxMAC or if L{AuiManager} is using the
3073          ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
3074         """
3075
3076         win_rect = self.GetRect()
3077
3078         if win_rect == self._last_rect:
3079             return
3080
3081         # skip the first move event
3082         if self._last_rect.IsEmpty():        
3083             self._last_rect = wx.Rect(*win_rect)
3084             return
3085         
3086         # skip if moving too fast to avoid massive redraws and
3087         # jumping hint windows
3088         if abs(win_rect.x - self._last_rect.x) > 3 or abs(win_rect.y - self._last_rect.y) > 3:
3089             self._last3_rect = wx.Rect(*self._last2_rect)
3090             self._last2_rect = wx.Rect(*self._last_rect)
3091             self._last_rect = wx.Rect(*win_rect)
3092             return
3093
3094         # prevent frame redocking during resize
3095         if self._last_rect.GetSize() != win_rect.GetSize():
3096             self._last3_rect = wx.Rect(*self._last2_rect)
3097             self._last2_rect = wx.Rect(*self._last_rect)
3098             self._last_rect = wx.Rect(*win_rect)
3099             return
3100
3101         self._last3_rect = wx.Rect(*self._last2_rect)
3102         self._last2_rect = wx.Rect(*self._last_rect)
3103         self._last_rect = wx.Rect(*win_rect)
3104
3105         if _VERSION_STRING < "2.9":
3106             leftDown = wx.GetMouseState().LeftDown()
3107         else:
3108             leftDown = wx.GetMouseState().LeftIsDown()
3109
3110         if not leftDown:
3111             return
3112
3113         if not self._moving:        
3114             self.OnMoveStart(event)
3115             self._moving = True
3116
3117         if self._last3_rect.IsEmpty():
3118             return
3119
3120         self.OnMoving(event)
3121
3122
3123     def OnIdle(self, event):
3124         """
3125         Handles the ``wx.EVT_IDLE`` event for L{AuiFloatingFrame}.
3126
3127         :param `event`: a `wx.IdleEvent` event to be processed.
3128
3129         :note: This event is only processed on wxMAC or if L{AuiManager} is using the
3130          ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.        
3131         """
3132
3133         if self._moving:        
3134             if _VERSION_STRING < "2.9":
3135                 leftDown = wx.GetMouseState().LeftDown()
3136             else:
3137                 leftDown = wx.GetMouseState().LeftIsDown()
3138
3139             if not leftDown:
3140                 self._moving = False
3141                 self.OnMoveFinished()
3142             else:            
3143                 event.RequestMore()
3144
3145         
3146     def OnMoveStart(self, event):
3147         """
3148         The user has just started moving the floating pane.
3149
3150         :param `event`: an instance of `wx.MouseEvent`.
3151     
3152         :note: This method is used only on wxMAC or if L{AuiManager} is using the
3153          ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
3154         """
3155
3156         # notify the owner manager that the pane has started to move
3157         if self._owner_mgr:
3158             if self._owner_mgr._from_move:
3159                 return
3160             self._owner_mgr._action_window = self._pane_window
3161             point = wx.GetMousePosition()
3162             action_offset = point - self.GetPosition()
3163
3164             if self._is_toolbar:
3165                 self._owner_mgr._toolbar_action_offset = action_offset
3166                 self._owner_mgr.OnMotion_DragToolbarPane(point)
3167             else:
3168                 self._owner_mgr._action_offset = action_offset
3169                 self._owner_mgr.OnMotion_DragFloatingPane(point)
3170
3171     
3172     def OnMoving(self, event):
3173         """
3174         The user is moving the floating pane.
3175
3176         :param `event`: an instance of `wx.MouseEvent`.
3177         
3178         :note: This method is used only on wxMAC or if L{AuiManager} is using the
3179          ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
3180         """
3181
3182         # notify the owner manager that the pane is moving
3183         self.OnMoveStart(event)
3184         
3185
3186     def OnMoveFinished(self):
3187         """
3188         The user has just finished moving the floating pane.
3189
3190         :note: This method is used only on wxMAC or if L{AuiManager} is using the
3191          ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
3192         """
3193
3194         # notify the owner manager that the pane has finished moving
3195         if self._owner_mgr:
3196             self._owner_mgr._action_window = self._pane_window
3197             point = wx.GetMousePosition()
3198             if self._is_toolbar:
3199                 self._owner_mgr.OnLeftUp_DragToolbarPane(point)
3200             else:
3201                 self._owner_mgr.OnLeftUp_DragFloatingPane(point)
3202
3203             self._owner_mgr.OnFloatingPaneMoved(self._pane_window, point)
3204     
3205
3206     def OnCheckFlyTimer(self, event):
3207         """
3208         Handles the ``wx.EVT_TIMER`` event for L{AuiFloatingFrame}.
3209
3210         :param `event`: a `wx.TimerEvent` to be processed.
3211
3212         :note: This is used solely for "fly-out" panes.        
3213         """
3214         
3215         if self._owner_mgr:
3216             pane = self._mgr.GetPane(self._pane_window)
3217             if pane.IsFlyOut():
3218                 if self.IsShownOnScreen():
3219                     self.FlyOut()
3220                         
3221
3222     def OnFindManager(self, event):
3223         """
3224         Handles the ``EVT_AUI_FIND_MANAGER`` event for L{AuiFloatingFrame}.
3225
3226         :param `event`: a L{AuiManagerEvent} event to be processed.
3227         """
3228         
3229         event.SetManager(self._owner_mgr)
3230
3231
3232     def FlyOut(self):
3233         """ Starts the flying in and out of a floating pane. """
3234
3235         if self._fly_timer.IsRunning():
3236             return
3237
3238         if _VERSION_STRING < "2.9":
3239             leftDown = wx.GetMouseState().LeftDown()
3240         else:
3241             leftDown = wx.GetMouseState().LeftIsDown()
3242
3243         if leftDown:
3244             return
3245         
3246         rect = wx.Rect(*self.GetScreenRect())
3247         rect.Inflate(10, 10)
3248
3249         if rect.Contains(wx.GetMousePosition()):
3250             if not self._fly:
3251                 return
3252             self._send_size = False
3253             self._fly_timer.Start(5)
3254         else:
3255             if self._fly:
3256                 return
3257             self._send_size = False
3258             self._fly_timer.Start(5)
3259
3260
3261     def OnFlyTimer(self, event):            
3262         """
3263         Handles the ``wx.EVT_TIMER`` event for L{AuiFloatingFrame}.
3264
3265         :param `event`: a `wx.TimerEvent` to be processed.
3266         """
3267
3268         current_size = self.GetClientSize()
3269         floating_size = wx.Size(*self._owner_mgr.GetPane(self._pane_window).floating_size)
3270
3271         if floating_size.y == -1:
3272             floating_size = self._floating_size
3273         
3274         if not self._fly:
3275             min_size = self._mgr.GetArtProvider().GetMetric(AUI_DOCKART_CAPTION_SIZE)
3276
3277             if wx.Platform != "__WXMSW__":
3278                 min_size += 2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_Y)
3279
3280             if current_size.y - self._fly_step <= min_size:
3281                 self.SetClientSize((current_size.x, min_size))
3282                 self._fly = True
3283                 self._fly_timer.Stop()
3284                 self._send_size = True
3285             else:
3286                 self.SetClientSize((current_size.x, current_size.y-self._fly_step))
3287
3288         else:
3289             if current_size.y + self._fly_step >= floating_size.y:
3290                 self.SetClientSize((current_size.x, floating_size.y))
3291                 self._fly = False
3292                 self._fly_timer.Stop()
3293                 self._send_size = True
3294             else:
3295                 self.SetClientSize((current_size.x, current_size.y+self._fly_step))
3296
3297         self.Update()
3298         self.Refresh()
3299
3300
3301     def FadeOut(self):
3302         """ Actually starts the fading out of the floating pane. """
3303
3304         while 1:
3305             self._alpha_amount -= 10
3306             if self._alpha_amount <= 0:
3307                 self._alpha_amount = 255
3308                 return
3309
3310             self.SetTransparent(self._alpha_amount)
3311             wx.SafeYield()
3312             wx.MilliSleep(15)
3313
3314     
3315 # -- static utility functions --
3316
3317 def DrawResizeHint(dc, rect):
3318     """
3319     Draws a resize hint while a sash is dragged.
3320
3321     :param `rect`: a `wx.Rect` rectangle which specifies the sash dimensions.
3322     """
3323         
3324     if wx.Platform == "__WXMSW__" and wx.App.GetComCtl32Version() >= 600:
3325         if wx.GetOsVersion()[1] > 5:
3326             # Windows Vista
3327             dc.SetPen(wx.Pen("black", 2, wx.SOLID))
3328             dc.SetBrush(wx.TRANSPARENT_BRUSH)
3329         else:
3330             # Draw the nice XP style splitter
3331             dc.SetPen(wx.TRANSPARENT_PEN)
3332             dc.SetBrush(wx.BLACK_BRUSH)
3333         dc.SetLogicalFunction(wx.INVERT)
3334         dc.DrawRectangleRect(rect)
3335         dc.SetLogicalFunction(wx.COPY)
3336     else:
3337         stipple = PaneCreateStippleBitmap()
3338         brush = wx.BrushFromBitmap(stipple)
3339         dc.SetBrush(brush)
3340         dc.SetPen(wx.TRANSPARENT_PEN)
3341
3342         dc.SetLogicalFunction(wx.XOR)
3343         dc.DrawRectangleRect(rect)    
3344
3345
3346 def CopyDocksAndPanes(src_docks, src_panes):
3347     """
3348     This utility function creates shallow copies of
3349     the dock and pane info. L{AuiDockInfo} usually contain pointers
3350     to L{AuiPaneInfo} classes, thus this function is necessary to reliably
3351     reconstruct that relationship in the new dock info and pane info arrays.
3352
3353     :param `src_docks`: a list of L{AuiDockInfo} classes;
3354     :param `src_panes`: a list of L{AuiPaneInfo} classes.
3355     """
3356     
3357     dest_docks = src_docks
3358     dest_panes = src_panes
3359
3360     for ii in xrange(len(dest_docks)):
3361         dock = dest_docks[ii]
3362         for jj in xrange(len(dock.panes)):
3363             for kk in xrange(len(src_panes)):
3364                 if dock.panes[jj] == src_panes[kk]:
3365                     dock.panes[jj] = dest_panes[kk]
3366
3367     return dest_docks, dest_panes
3368
3369
3370 def CopyDocksAndPanes2(src_docks, src_panes):
3371     """
3372     This utility function creates full copies of
3373     the dock and pane info. L{AuiDockInfo} usually contain pointers
3374     to L{AuiPaneInfo} classes, thus this function is necessary to reliably
3375     reconstruct that relationship in the new dock info and pane info arrays.
3376
3377     :param `src_docks`: a list of L{AuiDockInfo} classes;
3378     :param `src_panes`: a list of L{AuiPaneInfo} classes.
3379     """
3380     
3381     dest_docks = []
3382
3383     for ii in xrange(len(src_docks)):
3384         dest_docks.append(AuiDockInfo())
3385         dest_docks[ii].dock_direction = src_docks[ii].dock_direction
3386         dest_docks[ii].dock_layer = src_docks[ii].dock_layer
3387         dest_docks[ii].dock_row = src_docks[ii].dock_row
3388         dest_docks[ii].size = src_docks[ii].size
3389         dest_docks[ii].min_size = src_docks[ii].min_size
3390         dest_docks[ii].resizable = src_docks[ii].resizable
3391         dest_docks[ii].fixed = src_docks[ii].fixed
3392         dest_docks[ii].toolbar = src_docks[ii].toolbar
3393         dest_docks[ii].panes = src_docks[ii].panes
3394         dest_docks[ii].rect = wx.Rect(*src_docks[ii].rect)
3395
3396     dest_panes = []
3397
3398     for ii in xrange(len(src_panes)):
3399         dest_panes.append(AuiPaneInfo())
3400         dest_panes[ii].name = src_panes[ii].name
3401         dest_panes[ii].caption = src_panes[ii].caption
3402         dest_panes[ii].window = src_panes[ii].window
3403         dest_panes[ii].frame = src_panes[ii].frame
3404         dest_panes[ii].state = src_panes[ii].state
3405         dest_panes[ii].dock_direction = src_panes[ii].dock_direction
3406         dest_panes[ii].dock_layer = src_panes[ii].dock_layer
3407         dest_panes[ii].dock_row = src_panes[ii].dock_row
3408         dest_panes[ii].dock_pos = src_panes[ii].dock_pos
3409         dest_panes[ii].best_size = wx.Size(*src_panes[ii].best_size)
3410         dest_panes[ii].min_size = wx.Size(*src_panes[ii].min_size)
3411         dest_panes[ii].max_size = wx.Size(*src_panes[ii].max_size)
3412         dest_panes[ii].floating_pos = wx.Point(*src_panes[ii].floating_pos)
3413         dest_panes[ii].floating_size = wx.Size(*src_panes[ii].floating_size)
3414         dest_panes[ii].dock_proportion = src_panes[ii].dock_proportion
3415         dest_panes[ii].buttons = src_panes[ii].buttons
3416         dest_panes[ii].rect = wx.Rect(*src_panes[ii].rect)
3417         dest_panes[ii].icon = src_panes[ii].icon
3418         dest_panes[ii].notebook_id = src_panes[ii].notebook_id
3419         dest_panes[ii].transparent = src_panes[ii].transparent
3420         dest_panes[ii].snapped = src_panes[ii].snapped
3421         dest_panes[ii].minimize_mode = src_panes[ii].minimize_mode
3422
3423     for ii in xrange(len(dest_docks)):
3424         dock = dest_docks[ii]
3425         for jj in xrange(len(dock.panes)):
3426             for kk in xrange(len(src_panes)):
3427                 if dock.panes[jj] == src_panes[kk]:
3428                     dock.panes[jj] = dest_panes[kk]
3429
3430         dest_docks[ii] = dock
3431         
3432     return dest_docks, dest_panes
3433
3434
3435 def GetMaxLayer(docks, dock_direction):
3436     """
3437     This is an internal function which returns
3438     the highest layer inside the specified dock.
3439
3440     :param `docks`: a list of L{AuiDockInfo};
3441     :param `dock_direction`: the L{AuiDockInfo} docking direction to analyze.
3442     """
3443     
3444     max_layer = 0
3445
3446     for dock in docks:
3447         if dock.dock_direction == dock_direction and dock.dock_layer > max_layer and not dock.fixed:
3448             max_layer = dock.dock_layer
3449     
3450     return max_layer
3451
3452
3453 def GetMaxRow(panes, dock_direction, dock_layer):
3454     """
3455     This is an internal function which returns
3456     the highest layer inside the specified dock.
3457
3458     :param `panes`: a list of L{AuiPaneInfo};
3459     :param `dock_direction`: the L{AuiPaneInfo} docking direction to analyze;
3460     :param `dock_layer`: the L{AuiPaneInfo} layer to analyze.
3461     """
3462     
3463     max_row = 0
3464
3465     for pane in panes:
3466         if pane.dock_direction == dock_direction and pane.dock_layer == dock_layer and \
3467            pane.dock_row > max_row:
3468             max_row = pane.dock_row
3469     
3470     return max_row
3471
3472
3473 def DoInsertDockLayer(panes, dock_direction, dock_layer):
3474     """
3475     This is an internal function that inserts a new dock
3476     layer by incrementing all existing dock layer values by one.
3477     
3478     :param `panes`: a list of L{AuiPaneInfo};
3479     :param `dock_direction`: the L{AuiPaneInfo} docking direction to analyze;
3480     :param `dock_layer`: the L{AuiPaneInfo} layer to analyze.
3481     """
3482     
3483     for ii in xrange(len(panes)):
3484         pane = panes[ii]
3485         if not pane.IsFloating() and pane.dock_direction == dock_direction and pane.dock_layer >= dock_layer:
3486             pane.dock_layer = pane.dock_layer + 1
3487
3488         panes[ii] = pane
3489
3490     return panes
3491
3492
3493 def DoInsertDockRow(panes, dock_direction, dock_layer, dock_row):
3494     """
3495     This is an internal function that inserts a new dock
3496     row by incrementing all existing dock row values by one.
3497     
3498     :param `panes`: a list of L{AuiPaneInfo};
3499     :param `dock_direction`: the L{AuiPaneInfo} docking direction to analyze;
3500     :param `dock_layer`: the L{AuiPaneInfo} layer to analyze;
3501     :param `dock_row`: the L{AuiPaneInfo} row to analyze.
3502     """
3503     
3504     for pane in panes:
3505         if not pane.IsFloating() and pane.dock_direction == dock_direction and \
3506            pane.dock_layer == dock_layer and pane.dock_row >= dock_row:
3507             pane.dock_row += 1
3508
3509     return panes
3510
3511     
3512 def DoInsertPane(panes, dock_direction, dock_layer, dock_row, dock_pos):
3513     """
3514     This is an internal function that inserts a new pane
3515     by incrementing all existing dock position values by one.
3516     
3517     :param `panes`: a list of L{AuiPaneInfo};
3518     :param `dock_direction`: the L{AuiPaneInfo} docking direction to analyze;
3519     :param `dock_layer`: the L{AuiPaneInfo} layer to analyze;
3520     :param `dock_row`: the L{AuiPaneInfo} row to analyze;
3521     :param `dock_pos`: the L{AuiPaneInfo} row to analyze.
3522     """
3523
3524     for ii in xrange(len(panes)):
3525         pane = panes[ii]
3526         if not pane.IsFloating() and pane.dock_direction == dock_direction and \
3527            pane.dock_layer == dock_layer and  pane.dock_row == dock_row and \
3528            pane.dock_pos >= dock_pos:
3529             pane.dock_pos = pane.dock_pos + 1
3530
3531         panes[ii] = pane
3532
3533     return panes
3534
3535
3536 def FindDocks(docks, dock_direction, dock_layer=-1, dock_row=-1, reverse=False):
3537     """
3538     This is an internal function that returns a list of docks which meet
3539     the specified conditions in the parameters and returns a sorted array
3540     (sorted by layer and then row).
3541     
3542     :param `docks`: a list of L{AuiDockInfo};
3543     :param `dock_direction`: the L{AuiDockInfo} docking direction to analyze;
3544     :param `dock_layer`: the L{AuiDockInfo} layer to analyze;
3545     :param `dock_row`: the L{AuiDockInfo} row to analyze;
3546     """
3547     
3548     matchDocks = [(d.dock_layer, d.dock_row, d.dock_direction, d) for d in docks if \
3549                   (dock_direction == -1 or dock_direction == d.dock_direction) and \
3550                   ((dock_layer == -1 or dock_layer == d.dock_layer) and \
3551                   (dock_row == -1 or dock_row == d.dock_row))]
3552     
3553     arr = [x[-1] for x in sorted(matchDocks, reverse=reverse)]
3554     
3555     return arr
3556
3557
3558 def FindOppositeDocks(docks, dock_direction):
3559     """
3560     This is an internal function that returns a list of docks
3561     which is related to the opposite direction.
3562
3563     :param `docks`: a list of L{AuiDockInfo};
3564     :param `dock_direction`: the L{AuiDockInfo} docking direction to analyze;
3565     """
3566
3567     if dock_direction == AUI_DOCK_LEFT:
3568         arr = FindDocks(docks, AUI_DOCK_RIGHT, -1, -1)
3569     elif dock_direction == AUI_DOCK_TOP:
3570         arr = FindDocks(docks, AUI_DOCK_BOTTOM, -1, -1)
3571     elif dock_direction == AUI_DOCK_RIGHT:
3572         arr = FindDocks(docks, AUI_DOCK_LEFT, -1, -1)
3573     elif dock_direction == AUI_DOCK_BOTTOM:
3574         arr = FindDocks(docks, AUI_DOCK_TOP, -1, -1)
3575
3576     return arr    
3577
3578
3579 def FindPaneInDock(dock, window):
3580     """
3581     This method looks up a specified window pointer inside a dock.
3582     If found, the corresponding L{AuiPaneInfo} pointer is returned, otherwise ``None``.
3583
3584     :param `dock`: a L{AuiDockInfo} structure;
3585     :param `window`: a `wx.Window` derived window (associated to a pane).
3586     """
3587
3588     for p in dock.panes:
3589         if p.window == window:
3590             return p
3591     
3592     return None
3593
3594
3595 def GetToolBarDockOffsets(docks):
3596     """
3597     Returns the toolbar dock offsets (top-left and bottom-right).
3598
3599     :param `docks`: a list of L{AuiDockInfo} to analyze.
3600     """
3601
3602     top_left = wx.Size(0, 0)
3603     bottom_right = wx.Size(0, 0)
3604
3605     for dock in docks:
3606         if dock.toolbar:
3607             dock_direction = dock.dock_direction
3608             if dock_direction == AUI_DOCK_LEFT:
3609                 top_left.x += dock.rect.width
3610                 bottom_right.x += dock.rect.width
3611
3612             elif dock_direction == AUI_DOCK_TOP:
3613                 top_left.y += dock.rect.height
3614                 bottom_right.y += dock.rect.height
3615
3616             elif dock_direction == AUI_DOCK_RIGHT:
3617                 bottom_right.x += dock.rect.width
3618             
3619             elif dock_direction == AUI_DOCK_BOTTOM:
3620                 bottom_right.y += dock.rect.height
3621
3622     return top_left, bottom_right        
3623     
3624
3625 def GetInternalFrameRect(window, docks):
3626     """
3627     Returns the window rectangle excluding toolbars.
3628
3629     :param `window`: a `wx.Window` derived window;
3630     :param `docks`: a list of L{AuiDockInfo} structures.
3631     """
3632
3633     frameRect = wx.Rect()
3634
3635     frameRect.SetTopLeft(window.ClientToScreen(window.GetClientAreaOrigin()))
3636     frameRect.SetSize(window.GetClientSize())
3637
3638     top_left, bottom_right = GetToolBarDockOffsets(docks)
3639
3640     # make adjustments for toolbars
3641     frameRect.x += top_left.x
3642     frameRect.y += top_left.y
3643     frameRect.width -= bottom_right.x
3644     frameRect.height -= bottom_right.y
3645
3646     return frameRect
3647
3648
3649 def CheckOutOfWindow(window, pt):
3650     """
3651     Checks if a point is outside the window rectangle.
3652     
3653     :param `window`: a `wx.Window` derived window;
3654     :param `pt`: a `wx.Point` object.
3655     """
3656
3657     auiWindowMargin = 30
3658     marginRect = wx.Rect(*window.GetClientRect())
3659     marginRect.Inflate(auiWindowMargin, auiWindowMargin)
3660
3661     return not marginRect.Contains(pt)
3662
3663
3664 def CheckEdgeDrop(window, docks, pt):
3665     """
3666     Checks on which edge of a window the drop action has taken place.
3667
3668     :param `window`: a `wx.Window` derived window;
3669     :param `docks`: a list of L{AuiDockInfo} structures;
3670     :param `pt`: a `wx.Point` object.
3671     """
3672
3673     screenPt = window.ClientToScreen(pt)
3674     clientSize = window.GetClientSize()
3675     frameRect = GetInternalFrameRect(window, docks)
3676
3677     if screenPt.y >= frameRect.GetTop() and screenPt.y < frameRect.GetBottom():
3678         if pt.x < auiLayerInsertOffset and pt.x > auiLayerInsertOffset - auiLayerInsertPixels:
3679             return wx.LEFT
3680         
3681         if pt.x >= clientSize.x - auiLayerInsertOffset and \
3682            pt.x < clientSize.x - auiLayerInsertOffset + auiLayerInsertPixels:
3683             return wx.RIGHT
3684         
3685     if screenPt.x >= frameRect.GetLeft() and screenPt.x < frameRect.GetRight():
3686         if pt.y < auiLayerInsertOffset and pt.y > auiLayerInsertOffset - auiLayerInsertPixels:
3687             return wx.TOP
3688         
3689         if pt.y >= clientSize.y - auiLayerInsertOffset and \
3690            pt.y < clientSize.y - auiLayerInsertOffset + auiLayerInsertPixels:
3691             return wx.BOTTOM
3692
3693     return -1
3694
3695
3696 def RemovePaneFromDocks(docks, pane, exc=None):
3697     """
3698     Removes a pane window from all docks
3699     with a possible exception specified by parameter `exc`.
3700
3701     :param `docks`: a list of L{AuiDockInfo} structures;
3702     :param `pane`: the L{AuiPaneInfo} pane to be removed;
3703     :param `exc`: the possible pane exception.
3704     """
3705     
3706     for ii in xrange(len(docks)):
3707         d = docks[ii]
3708         if d == exc:
3709             continue
3710         pi = FindPaneInDock(d, pane.window)
3711         if pi:
3712             d.panes.remove(pi)
3713
3714         docks[ii] = d            
3715
3716     return docks
3717
3718
3719 def RenumberDockRows(docks):
3720     """
3721     Takes a dock and assigns sequential numbers
3722     to existing rows.  Basically it takes out the gaps so if a
3723     dock has rows with numbers 0, 2, 5, they will become 0, 1, 2.
3724
3725     :param `docks`: a list of L{AuiDockInfo} structures.    
3726     """
3727     
3728     for ii in xrange(len(docks)):
3729         dock = docks[ii]
3730         dock.dock_row = ii
3731         for jj in xrange(len(dock.panes)):
3732             dock.panes[jj].dock_row = ii
3733
3734         docks[ii] = dock
3735         
3736     return docks
3737
3738
3739 def SetActivePane(panes, active_pane):
3740     """
3741     Sets the active pane, as well as cycles through
3742     every other pane and makes sure that all others' active flags
3743     are turned off.
3744
3745     :param `panes`: a list of L{AuiPaneInfo} structures;
3746     :param `active_pane`: the pane to be made active (if found).
3747     """
3748
3749     for pane in panes:
3750         pane.state &= ~AuiPaneInfo.optionActive
3751
3752     for pane in panes:
3753         if pane.window == active_pane and not pane.IsNotebookPage():
3754             pane.state |= AuiPaneInfo.optionActive
3755             return True, panes
3756             
3757     return False, panes
3758         
3759
3760 def ShowDockingGuides(guides, show):
3761     """
3762     Shows or hide the docking guide windows.
3763
3764     :param `guides`: a list of L{AuiDockingGuideInfo} classes;
3765     :param `show`: whether to show or hide the docking guide windows.
3766     """
3767
3768     for target in guides:
3769         
3770         if show and not target.host.IsShown():
3771             target.host.Show()
3772             target.host.Update()
3773         
3774         elif not show and target.host.IsShown():        
3775             target.host.Hide()
3776         
3777
3778 def RefreshDockingGuides(guides):
3779     """
3780     Refreshes the docking guide windows.
3781
3782     :param `guides`: a list of L{AuiDockingGuideInfo} classes;
3783     """
3784     
3785     for target in guides:
3786         if target.host.IsShown():
3787             target.host.Refresh()
3788         
3789     
3790 def PaneSortFunc(p1, p2):
3791     """
3792     This function is used to sort panes by dock position.
3793
3794     :param `p1`: a L{AuiPaneInfo} instance;
3795     :param `p2`: another L{AuiPaneInfo} instance.    
3796     """
3797     
3798     return (p1.dock_pos < p2.dock_pos and [-1] or [1])[0]
3799
3800
3801 def GetNotebookRoot(panes, notebook_id):
3802     """
3803     Returns the L{AuiPaneInfo} which has the specified `notebook_id`.
3804
3805     :param `panes`: a list of L{AuiPaneInfo} instances;
3806     :param `notebook_id`: the target notebook id.
3807     """    
3808
3809     for paneInfo in panes:
3810         if paneInfo.IsNotebookControl() and paneInfo.notebook_id == notebook_id:
3811             return paneInfo
3812         
3813     return None
3814
3815
3816 def EscapeDelimiters(s):
3817     """
3818     Changes ``;`` into ``\`` and ``|`` into ``\|`` in the input string.  
3819
3820     :param `s`: the string to be analyzed.
3821
3822     :note: This is an internal functions which is used for saving perspectives.    
3823     """
3824     
3825     result = s.replace(";", "\\")
3826     result = result.replace("|", "|\\")
3827     
3828     return result
3829
3830
3831 def IsDifferentDockingPosition(pane1, pane2):
3832     """
3833     Returns whether `pane1` and `pane2` are in a different docking position
3834     based on pane status, docking direction, docking layer and docking row.
3835
3836     :param `pane1`: a L{AuiPaneInfo} instance;
3837     :param `pane2`: another L{AuiPaneInfo} instance.
3838     """
3839
3840     return pane1.IsFloating() != pane2.IsFloating() or \
3841            pane1.dock_direction != pane2.dock_direction or \
3842            pane1.dock_layer != pane2.dock_layer or \
3843            pane1.dock_row != pane2.dock_row
3844
3845
3846 # Convenience function
3847 def AuiManager_HasLiveResize(manager):
3848     """
3849     Static function which returns if the input `manager` should have "live resize"
3850     behaviour.
3851
3852     :param `manager`: an instance of L{AuiManager}.
3853
3854     :note: This method always returns ``True`` on wxMac as this platform doesn't have
3855      the ability to use `wx.ScreenDC` to draw sashes.
3856     """
3857
3858     # With Core Graphics on Mac, it's not possible to show sash feedback,
3859     # so we'll always use live update instead.
3860     
3861     if wx.Platform == "__WXMAC__":
3862         return True
3863     else:
3864         return (manager.GetAGWFlags() & AUI_MGR_LIVE_RESIZE) == AUI_MGR_LIVE_RESIZE
3865
3866
3867 # Convenience function
3868 def AuiManager_UseNativeMiniframes(manager):
3869     """
3870     Static function which returns if the input `manager` should use native `wx.MiniFrame` as
3871     floating panes.
3872
3873     :param `manager`: an instance of L{AuiManager}.
3874
3875     :note: This method always returns ``True`` on wxMac as this platform doesn't have
3876      the ability to use custom drawn miniframes.
3877     """
3878
3879     # With Core Graphics on Mac, it's not possible to show sash feedback,
3880     # so we'll always use live update instead.
3881     
3882     if wx.Platform == "__WXMAC__":
3883         return True
3884     else:
3885         return (manager.GetAGWFlags() & AUI_MGR_USE_NATIVE_MINIFRAMES) == AUI_MGR_USE_NATIVE_MINIFRAMES
3886
3887
3888 def GetManager(window):
3889     """
3890     This function will return the aui manager for a given window.
3891     
3892     :param `window`: this parameter should be any child window or grand-child
3893      window (and so on) of the frame/window managed by L{AuiManager}. The window
3894      does not need to be managed by the manager itself, nor does it even need
3895      to be a child or sub-child of a managed window. It must however be inside
3896      the window hierarchy underneath the managed window.
3897     """
3898     
3899     if not isinstance(wx.GetTopLevelParent(window), AuiFloatingFrame):
3900         if isinstance(window, auibar.AuiToolBar):
3901             return window.GetAuiManager()
3902     
3903     evt = AuiManagerEvent(wxEVT_AUI_FIND_MANAGER)
3904     evt.SetManager(None)
3905     evt.ResumePropagation(wx.EVENT_PROPAGATE_MAX)
3906
3907     if not window.GetEventHandler().ProcessEvent(evt):
3908         return None
3909
3910     return evt.GetManager()
3911
3912
3913 # ---------------------------------------------------------------------------- #
3914
3915 class AuiManager(wx.EvtHandler):
3916     """
3917     AuiManager manages the panes associated with it for a particular `wx.Frame`,
3918     using a pane's L{AuiPaneInfo} information to determine each pane's docking and
3919     floating behavior. L{AuiManager} uses wxPython's sizer mechanism to plan the
3920     layout of each frame. It uses a replaceable dock art class to do all drawing,
3921     so all drawing is localized in one area, and may be customized depending on an
3922     applications' specific needs.
3923
3924     L{AuiManager} works as follows: the programmer adds panes to the class, or makes
3925     changes to existing pane properties (dock position, floating state, show state, etc...).
3926     To apply these changes, the L{AuiManager.Update} function is called. This batch
3927     processing can be used to avoid flicker, by modifying more than one pane at a time,
3928     and then "committing" all of the changes at once by calling `Update()`.
3929
3930     Panes can be added quite easily::
3931
3932         text1 = wx.TextCtrl(self, -1)
3933         text2 = wx.TextCtrl(self, -1)
3934         self._mgr.AddPane(text1, AuiPaneInfo().Left().Caption("Pane Number One"))
3935         self._mgr.AddPane(text2, AuiPaneInfo().Bottom().Caption("Pane Number Two"))
3936
3937         self._mgr.Update()
3938
3939
3940     Later on, the positions can be modified easily. The following will float an
3941     existing pane in a tool window::
3942
3943         self._mgr.GetPane(text1).Float()
3944
3945
3946     **Layers, Rows and Directions, Positions:**
3947     
3948     Inside AUI, the docking layout is figured out by checking several pane parameters.
3949     Four of these are important for determining where a pane will end up.
3950
3951     **Direction** - Each docked pane has a direction, `Top`, `Bottom`, `Left`, `Right`, or `Center`.
3952     This is fairly self-explanatory. The pane will be placed in the location specified
3953     by this variable.
3954
3955     **Position** - More than one pane can be placed inside of a "dock". Imagine two panes
3956     being docked on the left side of a window. One pane can be placed over another.
3957     In proportionally managed docks, the pane position indicates it's sequential position,
3958     starting with zero. So, in our scenario with two panes docked on the left side, the
3959     top pane in the dock would have position 0, and the second one would occupy position 1. 
3960
3961     **Row** - A row can allow for two docks to be placed next to each other. One of the most
3962     common places for this to happen is in the toolbar. Multiple toolbar rows are allowed,
3963     the first row being in row 0, and the second in row 1. Rows can also be used on
3964     vertically docked panes. 
3965
3966     **Layer** - A layer is akin to an onion. Layer 0 is the very center of the managed pane.
3967     Thus, if a pane is in layer 0, it will be closest to the center window (also sometimes
3968     known as the "content window"). Increasing layers "swallow up" all layers of a lower
3969     value. This can look very similar to multiple rows, but is different because all panes
3970     in a lower level yield to panes in higher levels. The best way to understand layers
3971     is by running the AUI sample (`AUI.py`).
3972     """
3973
3974     def __init__(self, managed_window=None, agwFlags=None):
3975         """
3976         Default class constructor.
3977         
3978         :param `managed_window`: specifies the window which should be managed;
3979         :param `agwFlags`: specifies options which allow the frame management behavior to be
3980          modified. `agwFlags` can be a combination of the following style bits:
3981
3982          ==================================== ==================================
3983          Flag name                            Description
3984          ==================================== ==================================
3985          ``AUI_MGR_ALLOW_FLOATING``           Allow floating of panes
3986          ``AUI_MGR_ALLOW_ACTIVE_PANE``        If a pane becomes active, "highlight" it in the interface
3987          ``AUI_MGR_TRANSPARENT_DRAG``         If the platform supports it, set transparency on a floating pane while it is dragged by the user
3988          ``AUI_MGR_TRANSPARENT_HINT``         If the platform supports it, show a transparent hint window when the user is about to dock a floating pane
3989          ``AUI_MGR_VENETIAN_BLINDS_HINT``     Show a "venetian blind" effect when the user is about to dock a floating pane
3990          ``AUI_MGR_RECTANGLE_HINT``           Show a rectangle hint effect when the user is about to dock a floating pane
3991          ``AUI_MGR_HINT_FADE``                If the platform supports it, the hint window will fade in and out
3992          ``AUI_MGR_NO_VENETIAN_BLINDS_FADE``  Disables the "venetian blind" fade in and out
3993          ``AUI_MGR_LIVE_RESIZE``              Live resize when the user drag a sash
3994          ``AUI_MGR_ANIMATE_FRAMES``           Fade-out floating panes when they are closed (all platforms which support frames transparency) and show a moving rectangle when they are docked (Windows < Vista and GTK only)
3995          ``AUI_MGR_AERO_DOCKING_GUIDES``      Use the new Aero-style bitmaps as docking guides
3996          ``AUI_MGR_PREVIEW_MINIMIZED_PANES``  Slide in and out minimized panes to preview them
3997          ``AUI_MGR_WHIDBEY_DOCKING_GUIDES``   Use the new Whidbey-style bitmaps as docking guides
3998          ``AUI_MGR_SMOOTH_DOCKING``           Performs a "smooth" docking of panes (a la PyQT)
3999          ``AUI_MGR_USE_NATIVE_MINIFRAMES``    Use miniframes with native caption bar as floating panes instead or custom drawn caption bars (forced on wxMac)
4000          ``AUI_MGR_AUTONB_NO_CAPTION``        Panes that merge into an automatic notebook will not have the pane caption visible
4001          ==================================== ==================================
4002
4003          Default value for `agwFlags` is:
4004          ``AUI_MGR_DEFAULT`` = ``AUI_MGR_ALLOW_FLOATING`` | ``AUI_MGR_TRANSPARENT_HINT`` | ``AUI_MGR_HINT_FADE`` | ``AUI_MGR_NO_VENETIAN_BLINDS_FADE``
4005
4006          :note: If using the ``AUI_MGR_USE_NATIVE_MINIFRAMES``, double-clicking on a
4007           floating pane caption will not re-dock the pane, but simply maximize it (if
4008           L{AuiPaneInfo.MaximizeButton} has been set to ``True``) or do nothing.
4009         """
4010
4011         wx.EvtHandler.__init__(self)
4012         
4013         self._action = actionNone
4014         self._action_window = None
4015         self._hover_button = None
4016         self._art = dockart.AuiDefaultDockArt()
4017         self._hint_window = None
4018         self._active_pane = None
4019         self._has_maximized = False
4020         self._has_minimized = False
4021
4022         self._frame = None
4023         self._dock_constraint_x = 0.3
4024         self._dock_constraint_y = 0.3
4025         self._reserved = None
4026     
4027         self._panes = []
4028         self._docks = []
4029         self._uiparts = []
4030         
4031         self._guides = []
4032         self._notebooks = []
4033
4034         self._masterManager = None
4035         self._currentDragItem = -1
4036         self._lastknowndocks = {}
4037
4038         self._hint_fadetimer = wx.Timer(self, wx.ID_ANY)
4039         self._hint_fademax = 50
4040         self._last_hint = wx.Rect()
4041
4042         self._from_move = False
4043         self._last_rect = wx.Rect()
4044         
4045         if agwFlags is None:
4046             agwFlags = AUI_MGR_DEFAULT
4047             
4048         self._agwFlags = agwFlags
4049         self._is_docked = (False, wx.RIGHT, wx.TOP, 0)
4050         self._snap_limits = (15, 15)
4051
4052         if wx.Platform == "__WXMSW__":
4053             self._animation_step = 30.0
4054         else:
4055             self._animation_step = 5.0
4056
4057         self._hint_rect = wx.Rect()
4058
4059         self._preview_timer = wx.Timer(self, wx.ID_ANY)
4060         self._sliding_frame = None
4061
4062         self._autoNBTabArt = tabart.AuiDefaultTabArt()
4063         self._autoNBStyle = AUI_NB_DEFAULT_STYLE | AUI_NB_BOTTOM | \
4064                             AUI_NB_SUB_NOTEBOOK | AUI_NB_TAB_EXTERNAL_MOVE
4065         self._autoNBStyle -= AUI_NB_DRAW_DND_TAB
4066
4067         if managed_window:
4068             self.SetManagedWindow(managed_window)
4069
4070         self.Bind(wx.EVT_PAINT, self.OnPaint)
4071         self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
4072         self.Bind(wx.EVT_SIZE, self.OnSize)
4073         self.Bind(wx.EVT_SET_CURSOR, self.OnSetCursor)
4074         self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
4075         self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDClick)
4076         self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
4077         self.Bind(wx.EVT_MOTION, self.OnMotion)
4078         self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
4079         self.Bind(wx.EVT_CHILD_FOCUS, self.OnChildFocus)
4080         self.Bind(wx.EVT_MOUSE_CAPTURE_LOST, self.OnCaptureLost)
4081         self.Bind(wx.EVT_TIMER, self.OnHintFadeTimer, self._hint_fadetimer)
4082         self.Bind(wx.EVT_TIMER, self.SlideIn, self._preview_timer)
4083
4084         self.Bind(wx.EVT_MOVE, self.OnMove)
4085         self.Bind(wx.EVT_SYS_COLOUR_CHANGED, self.OnSysColourChanged)
4086         
4087         self.Bind(EVT_AUI_PANE_BUTTON, self.OnPaneButton)
4088         self.Bind(EVT_AUI_RENDER, self.OnRender)
4089         self.Bind(EVT_AUI_FIND_MANAGER, self.OnFindManager)
4090         self.Bind(EVT_AUI_PANE_MIN_RESTORE, self.OnRestoreMinimizedPane)
4091         self.Bind(EVT_AUI_PANE_DOCKED, self.OnPaneDocked)
4092
4093         self.Bind(auibook.EVT_AUINOTEBOOK_BEGIN_DRAG, self.OnTabBeginDrag)
4094         self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CLOSE, self.OnTabPageClose)
4095         self.Bind(auibook.EVT_AUINOTEBOOK_PAGE_CHANGED, self.OnTabSelected)
4096         
4097
4098     def CreateFloatingFrame(self, parent, pane_info):
4099         """
4100         Creates a floating frame for the windows.
4101
4102         :param `parent`: the floating frame parent;
4103         :param `pane_info`: the L{AuiPaneInfo} class with all the pane's information.
4104         """
4105
4106         return AuiFloatingFrame(parent, self, pane_info)
4107
4108
4109     def CanDockPanel(self, p):
4110         """
4111         Returns whether a pane can be docked or not.
4112
4113         :param `p`: the L{AuiPaneInfo} class with all the pane's information.
4114         """        
4115
4116         # is the pane dockable?
4117         if not p.IsDockable():
4118             return False
4119
4120         # if a key modifier is pressed while dragging the frame,
4121         # don't dock the window
4122         return not (wx.GetKeyState(wx.WXK_CONTROL) or wx.GetKeyState(wx.WXK_ALT))
4123
4124
4125     def GetPaneByWidget(self, window):
4126         """
4127         This version of L{GetPane} looks up a pane based on a
4128         'pane window'.
4129
4130         :param `window`: a `wx.Window` derived window.
4131
4132         :see: L{GetPane}
4133         """
4134
4135         for p in self._panes:
4136             if p.window == window:
4137                 return p
4138
4139         return NonePaneInfo
4140
4141
4142     def GetPaneByName(self, name):
4143         """
4144         This version of L{GetPane} looks up a pane based on a
4145         'pane name'.
4146
4147         :param `name`: the pane name.
4148
4149         :see: L{GetPane}        
4150         """
4151         
4152         for p in self._panes:
4153             if p.name == name:
4154                 return p
4155         
4156         return NonePaneInfo
4157
4158
4159     def GetPane(self, item):
4160         """
4161         Looks up a L{AuiPaneInfo} structure based
4162         on the supplied window pointer. Upon failure, L{GetPane}
4163         returns an empty L{AuiPaneInfo}, a condition which can be checked
4164         by calling L{AuiPaneInfo.IsOk}.
4165
4166         The pane info's structure may then be modified. Once a pane's
4167         info is modified, L{Update} must be called to
4168         realize the changes in the UI.
4169
4170         :param `item`: either a pane name or a `wx.Window`.        
4171         """
4172
4173         if isinstance(item, basestring):
4174             return self.GetPaneByName(item)
4175         else:
4176             return self.GetPaneByWidget(item)
4177
4178
4179     def GetAllPanes(self):
4180         """ Returns a reference to all the pane info structures. """
4181         
4182         return self._panes
4183
4184
4185     def ShowPane(self, window, show):
4186         """
4187         Shows or hides a pane based on the window passed as input.
4188
4189         :param `window`: a `wx.Window` derived window;
4190         :param `show`: ``True`` to show the pane, ``False`` otherwise.
4191         """
4192
4193         p = self.GetPane(window)
4194         
4195         if p.IsOk():
4196             if p.IsNotebookPage():
4197                 if show:
4198                 
4199                     notebook = self._notebooks[p.notebook_id]
4200                     id = notebook.GetPageIndex(p.window)
4201                     if id >= 0:
4202                         notebook.SetSelection(id)
4203                     self.ShowPane(notebook, True)
4204                 
4205             else:
4206                 p.Show(show)
4207                 
4208             if p.frame:
4209                 p.frame.Raise()
4210                 
4211             self.Update()
4212
4213             
4214     def HitTest(self, x, y):
4215         """
4216         This is an internal function which determines
4217         which UI item the specified coordinates are over.
4218         
4219         :param `x`: specifies a x position in client coordinates;
4220         :param `y`: specifies a y position in client coordinates.
4221         """
4222
4223         result = None
4224
4225         for item in self._uiparts:
4226             # we are not interested in typeDock, because this space 
4227             # isn't used to draw anything, just for measurements
4228             # besides, the entire dock area is covered with other
4229             # rectangles, which we are interested in.
4230             if item.type == AuiDockUIPart.typeDock:
4231                 continue
4232
4233             # if we already have a hit on a more specific item, we are not
4234             # interested in a pane hit.  If, however, we don't already have
4235             # a hit, returning a pane hit is necessary for some operations
4236             if item.type in [AuiDockUIPart.typePane, AuiDockUIPart.typePaneBorder] and result:
4237                 continue
4238         
4239             # if the point is inside the rectangle, we have a hit
4240             if item.rect.Contains((x, y)):
4241                 result = item
4242         
4243         return result
4244
4245
4246     def PaneHitTest(self, panes, pt):
4247         """
4248         Similar to L{HitTest}, but it checks in which L{AuiPaneInfo} rectangle the
4249         input point belongs to.
4250
4251         :param `panes`: a list of L{AuiPaneInfo} instances;
4252         :param `pt`: a `wx.Point` object.
4253         """
4254
4255         for paneInfo in panes:
4256             if paneInfo.IsDocked() and paneInfo.IsShown() and paneInfo.rect.Contains(pt):
4257                 return paneInfo
4258
4259         return NonePaneInfo
4260
4261
4262     # SetAGWFlags() and GetAGWFlags() allow the owner to set various
4263     # options which are global to AuiManager
4264
4265     def SetAGWFlags(self, agwFlags):
4266         """
4267         This method is used to specify L{AuiManager}'s settings flags.
4268
4269         :param `agwFlags`: specifies options which allow the frame management behavior
4270          to be modified. `agwFlags` can be one of the following style bits:
4271
4272          ==================================== ==================================
4273          Flag name                            Description
4274          ==================================== ==================================
4275          ``AUI_MGR_ALLOW_FLOATING``           Allow floating of panes
4276          ``AUI_MGR_ALLOW_ACTIVE_PANE``        If a pane becomes active, "highlight" it in the interface
4277          ``AUI_MGR_TRANSPARENT_DRAG``         If the platform supports it, set transparency on a floating pane while it is dragged by the user
4278          ``AUI_MGR_TRANSPARENT_HINT``         If the platform supports it, show a transparent hint window when the user is about to dock a floating pane
4279          ``AUI_MGR_VENETIAN_BLINDS_HINT``     Show a "venetian blind" effect when the user is about to dock a floating pane
4280          ``AUI_MGR_RECTANGLE_HINT``           Show a rectangle hint effect when the user is about to dock a floating pane
4281          ``AUI_MGR_HINT_FADE``                If the platform supports it, the hint window will fade in and out
4282          ``AUI_MGR_NO_VENETIAN_BLINDS_FADE``  Disables the "venetian blind" fade in and out
4283          ``AUI_MGR_LIVE_RESIZE``              Live resize when the user drag a sash
4284          ``AUI_MGR_ANIMATE_FRAMES``           Fade-out floating panes when they are closed (all platforms which support frames transparency) and show a moving rectangle when they are docked (Windows < Vista and GTK only)
4285          ``AUI_MGR_AERO_DOCKING_GUIDES``      Use the new Aero-style bitmaps as docking guides
4286          ``AUI_MGR_PREVIEW_MINIMIZED_PANES``  Slide in and out minimized panes to preview them
4287          ``AUI_MGR_WHIDBEY_DOCKING_GUIDES``   Use the new Whidbey-style bitmaps as docking guides        
4288          ``AUI_MGR_SMOOTH_DOCKING``           Performs a "smooth" docking of panes (a la PyQT)
4289          ``AUI_MGR_USE_NATIVE_MINIFRAMES``    Use miniframes with native caption bar as floating panes instead or custom drawn caption bars (forced on wxMac)
4290          ``AUI_MGR_AUTONB_NO_CAPTION``        Panes that merge into an automatic notebook will not have the pane caption visible
4291          ==================================== ==================================
4292
4293          :note: If using the ``AUI_MGR_USE_NATIVE_MINIFRAMES``, double-clicking on a
4294           floating pane caption will not re-dock the pane, but simply maximize it (if
4295           L{AuiPaneInfo.MaximizeButton} has been set to ``True``) or do nothing.
4296         
4297         """
4298         
4299         self._agwFlags = agwFlags
4300
4301         if len(self._guides) > 0:
4302             self.CreateGuideWindows()
4303
4304         if self._hint_window and agwFlags & AUI_MGR_RECTANGLE_HINT == 0:
4305             self.CreateHintWindow()
4306
4307
4308     def GetAGWFlags(self):
4309         """
4310         Returns the current manager's flags.
4311
4312         :see: L{SetAGWFlags} for a list of possible L{AuiManager} flags.
4313         """
4314         
4315         return self._agwFlags
4316         
4317
4318     def SetManagedWindow(self, managed_window):
4319         """
4320         Called to specify the frame or window which is to be managed by L{AuiManager}.
4321         Frame management is not restricted to just frames. Child windows or custom
4322         controls are also allowed.
4323
4324         :param `managed_window`: specifies the window which should be managed by
4325          the AUI manager.
4326         """
4327
4328         if not managed_window:
4329             raise Exception("Specified managed window must be non-null. ")
4330         
4331         self._frame = managed_window
4332         self._frame.PushEventHandler(self)
4333
4334         # if the owner is going to manage an MDI parent frame,
4335         # we need to add the MDI client window as the default
4336         # center pane
4337
4338         if isinstance(self._frame, wx.MDIParentFrame):
4339             mdi_frame = self._frame
4340             client_window = mdi_frame.GetClientWindow()
4341
4342             if not client_window:
4343                 raise Exception("Client window is None!")
4344
4345             self.AddPane(client_window, AuiPaneInfo().Name("mdiclient").
4346                          CenterPane().PaneBorder(False))
4347
4348         elif isinstance(self._frame, tabmdi.AuiMDIParentFrame):
4349
4350             mdi_frame = self._frame
4351             client_window = mdi_frame.GetClientWindow()
4352
4353             if not client_window:
4354                 raise Exception("Client window is None!")
4355
4356             self.AddPane(client_window, AuiPaneInfo().Name("mdiclient").
4357                          CenterPane().PaneBorder(False))
4358
4359
4360     def GetManagedWindow(self):
4361         """ Returns the window being managed by L{AuiManager}. """
4362         
4363         return self._frame
4364
4365
4366     def SetFrame(self, managed_window):
4367         """
4368         Called to specify the frame or window which is to be managed by L{AuiManager}.
4369         Frame management is not restricted to just frames. Child windows or custom
4370         controls are also allowed.
4371
4372         :param `managed_window`: specifies the window which should be managed by
4373          the AUI manager.
4374
4375         :warning: This method is now deprecated, use L{SetManagedWindow} instead.
4376         """
4377
4378         DeprecationWarning("This method is deprecated, use SetManagedWindow instead.")
4379         return self.SetManagedWindow(managed_window)
4380     
4381         
4382     def GetFrame(self):
4383         """
4384         Returns the window being managed by L{AuiManager}.
4385
4386         :warning: This method is now deprecated, use L{GetManagedWindow} instead.
4387         """
4388
4389         DeprecationWarning("This method is deprecated, use GetManagedWindow instead.")        
4390         return self._frame
4391
4392
4393     def CreateGuideWindows(self):
4394         """ Creates the VS2005 HUD guide windows. """
4395
4396         self.DestroyGuideWindows()
4397
4398         self._guides.append(AuiDockingGuideInfo().Left().
4399                             Host(AuiSingleDockingGuide(self._frame, wx.LEFT)))
4400         self._guides.append(AuiDockingGuideInfo().Top().
4401                             Host(AuiSingleDockingGuide(self._frame, wx.TOP)))
4402         self._guides.append(AuiDockingGuideInfo().Right().
4403                             Host(AuiSingleDockingGuide(self._frame, wx.RIGHT)))
4404         self._guides.append(AuiDockingGuideInfo().Bottom().
4405                             Host(AuiSingleDockingGuide(self._frame, wx.BOTTOM)))
4406         self._guides.append(AuiDockingGuideInfo().Centre().
4407                             Host(AuiCenterDockingGuide(self._frame)))
4408
4409
4410     def DestroyGuideWindows(self):
4411         """ Destroys the VS2005 HUD guide windows. """
4412
4413         for guide in self._guides:
4414             if guide.host:
4415                 guide.host.Destroy()
4416         
4417         self._guides = []
4418     
4419
4420     def CreateHintWindow(self):
4421         """ Creates the standard wxAUI hint window. """
4422
4423         self.DestroyHintWindow()
4424
4425         self._hint_window = AuiDockingHintWindow(self._frame)
4426         self._hint_window.SetBlindMode(self._agwFlags)
4427
4428
4429     def DestroyHintWindow(self):
4430         """ Destroys the standard wxAUI hint window. """
4431
4432         if self._hint_window:
4433
4434             self._hint_window.Destroy()
4435             self._hint_window = None
4436
4437
4438     def UnInit(self):
4439         """
4440         Uninitializes the framework and should be called before a managed frame or
4441         window is destroyed. L{UnInit} is usually called in the managed `wx.Frame`/`wx.Window`
4442         destructor.
4443
4444         It is necessary to call this function before the managed frame or window is
4445         destroyed, otherwise the manager cannot remove its custom event handlers
4446         from a window.
4447         """
4448
4449         if self._frame:
4450             self._frame.RemoveEventHandler(self)
4451
4452
4453     def GetArtProvider(self):
4454         """ Returns the current art provider being used. """
4455         
4456         return self._art
4457
4458
4459     def ProcessMgrEvent(self, event):
4460         """
4461         Process the AUI events sent to the manager.
4462
4463         :param `event`: the event to process, an instance of L{AuiManagerEvent}.
4464         """
4465
4466         # first, give the owner frame a chance to override
4467         if self._frame:
4468             if self._frame.GetEventHandler().ProcessEvent(event):
4469                 return
4470         
4471         self.ProcessEvent(event)
4472
4473
4474     def FireEvent(self, evtType, pane, canVeto=False):
4475         """
4476         Fires one of the ``EVT_AUI_PANE_FLOATED``/``FLOATING``/``DOCKING``/``DOCKED``/``ACTIVATED`` event. 
4477
4478         :param `evtType`: one of the aforementioned events;
4479         :param `pane`: the L{AuiPaneInfo} instance associated to this event;
4480         :param `canVeto`: whether the event can be vetoed or not.
4481         """        
4482
4483         event = AuiManagerEvent(evtType)
4484         event.SetPane(pane)
4485         event.SetCanVeto(canVeto)
4486         self.ProcessMgrEvent(event)
4487
4488         return event
4489
4490     
4491     def CanUseModernDockArt(self):
4492         """
4493         Returns whether L{ModernDockArt} can be used (Windows XP / Vista / 7 only,
4494         requires Mark Hammonds's `pywin32` package).
4495         """
4496
4497         if not _winxptheme:
4498             return False
4499
4500         # Get the size of a small close button (themed)
4501         hwnd = self._frame.GetHandle()
4502         hTheme = winxptheme.OpenThemeData(hwnd, "Window")
4503
4504         if not hTheme:
4505             return False
4506
4507         return True
4508             
4509     
4510     def SetArtProvider(self, art_provider):
4511         """
4512         Instructs L{AuiManager} to use art provider specified by the parameter
4513         `art_provider` for all drawing calls. This allows plugable look-and-feel
4514         features.
4515
4516         :param `art_provider`: a AUI dock art provider.
4517
4518         :note: The previous art provider object, if any, will be deleted by L{AuiManager}.
4519         """
4520
4521         # delete the last art provider, if any
4522         del self._art
4523         
4524         # assign the new art provider
4525         self._art = art_provider
4526
4527         for pane in self.GetAllPanes():
4528             if pane.IsFloating() and pane.frame:                
4529                 pane.frame._mgr.SetArtProvider(art_provider)
4530                 pane.frame._mgr.Update()
4531
4532
4533     def AddPane(self, window, arg1=None, arg2=None, target=None):
4534         """
4535         Tells the frame manager to start managing a child window. There
4536         are four versions of this function. The first verison allows the full spectrum
4537         of pane parameter possibilities (L{AddPane1}). The second version is used for
4538         simpler user interfaces which do not require as much configuration (L{AddPane2}).
4539         The L{AddPane3} version allows a drop position to be specified, which will determine
4540         where the pane will be added. The L{AddPane4} version allows to turn the target
4541         L{AuiPaneInfo} pane into a notebook and the added pane into a page.
4542
4543         In wxPython, simply call L{AddPane}.
4544
4545         :param `window`: the child window to manage;
4546         :param `arg1`: a L{AuiPaneInfo} or an integer value (direction);
4547         :param `arg2`: a L{AuiPaneInfo} or a `wx.Point` (drop position);
4548         :param `target`: a L{AuiPaneInfo} to be turned into a notebook
4549          and new pane added to it as a page. (additionally, target can be any pane in 
4550          an existing notebook)
4551          """
4552  
4553         if target in self._panes:
4554             return self.AddPane4(window, arg1, target)
4555
4556         if type(arg1) == type(1):
4557             # This Is Addpane2
4558             if arg1 is None:
4559                 arg1 = wx.LEFT
4560             if arg2 is None:
4561                 arg2 = ""
4562             return self.AddPane2(window, arg1, arg2)
4563         else:
4564             if isinstance(arg2, wx.Point):
4565                 return self.AddPane3(window, arg1, arg2)
4566             else:
4567                 return self.AddPane1(window, arg1)
4568         
4569
4570     def AddPane1(self, window, pane_info):
4571         """ See comments on L{AddPane}. """
4572
4573         # check if the pane has a valid window
4574         if not window:
4575             return False
4576
4577         # check if the pane already exists
4578         if self.GetPane(pane_info.window).IsOk():
4579             return False
4580
4581         # check if the pane name already exists, this could reveal a
4582         # bug in the library user's application
4583         already_exists = False
4584         if pane_info.name != "" and self.GetPane(pane_info.name).IsOk():
4585             warnings.warn("A pane with the name '%s' already exists in the manager!"%pane_info.name)
4586             already_exists = True
4587
4588         # if the new pane is docked then we should undo maximize
4589         if pane_info.IsDocked():
4590             self.RestoreMaximizedPane()
4591
4592         self._panes.append(pane_info)
4593         pinfo = self._panes[-1]
4594
4595         # set the pane window
4596         pinfo.window = window
4597
4598         # if the pane's name identifier is blank, create a random string
4599         if pinfo.name == "" or already_exists:
4600             pinfo.name = ("%s%08x%08x%08x")%(pinfo.window.GetName(), time.time(),
4601                                              time.clock(), len(self._panes))
4602
4603         # set initial proportion (if not already set)
4604         if pinfo.dock_proportion == 0:
4605             pinfo.dock_proportion = 100000
4606
4607         floating = isinstance(self._frame, AuiFloatingFrame)
4608
4609         pinfo.buttons = []
4610
4611         if not floating and pinfo.HasMinimizeButton():
4612             button = AuiPaneButton(AUI_BUTTON_MINIMIZE)
4613             pinfo.buttons.append(button)
4614     
4615         if not floating and pinfo.HasMaximizeButton():
4616             button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE)
4617             pinfo.buttons.append(button)
4618
4619         if not floating and pinfo.HasPinButton():
4620             button = AuiPaneButton(AUI_BUTTON_PIN)
4621             pinfo.buttons.append(button)
4622
4623         if pinfo.HasCloseButton():
4624             button = AuiPaneButton(AUI_BUTTON_CLOSE)
4625             pinfo.buttons.append(button)
4626
4627         if pinfo.HasGripper():
4628             if isinstance(pinfo.window, auibar.AuiToolBar):
4629                 # prevent duplicate gripper -- both AuiManager and AuiToolBar
4630                 # have a gripper control.  The toolbar's built-in gripper
4631                 # meshes better with the look and feel of the control than ours,
4632                 # so turn AuiManager's gripper off, and the toolbar's on.
4633
4634                 tb = pinfo.window
4635                 pinfo.SetFlag(AuiPaneInfo.optionGripper, False)
4636                 tb.SetGripperVisible(True)
4637
4638         if pinfo.window:
4639             if pinfo.best_size == wx.Size(-1, -1):
4640                 pinfo.best_size = pinfo.window.GetClientSize()
4641
4642             if isinstance(pinfo.window, wx.ToolBar):
4643                 # GetClientSize() doesn't get the best size for
4644                 # a toolbar under some newer versions of wxWidgets,
4645                 # so use GetBestSize()
4646                 pinfo.best_size = pinfo.window.GetBestSize()
4647
4648                 # this is needed for Win2000 to correctly fill toolbar backround
4649                 # it should probably be repeated once system colour change happens
4650                 if wx.Platform == "__WXMSW__" and pinfo.window.UseBgCol():
4651                     pinfo.window.SetBackgroundColour(self.GetArtProvider().GetColour(AUI_DOCKART_BACKGROUND_COLOUR))
4652                 
4653             if pinfo.min_size != wx.Size(-1, -1):
4654                 if pinfo.best_size.x < pinfo.min_size.x:
4655                     pinfo.best_size.x = pinfo.min_size.x
4656                 if pinfo.best_size.y < pinfo.min_size.y:
4657                     pinfo.best_size.y = pinfo.min_size.y
4658
4659         self._panes[-1] = pinfo
4660         if isinstance(window, auibar.AuiToolBar):
4661             window.SetAuiManager(self)
4662
4663         return True
4664
4665
4666     def AddPane2(self, window, direction, caption):
4667         """ See comments on L{AddPane}. """
4668         
4669         pinfo = AuiPaneInfo()
4670         pinfo.Caption(caption)
4671         
4672         if direction == wx.TOP:
4673             pinfo.Top()
4674         elif direction == wx.BOTTOM:
4675             pinfo.Bottom()
4676         elif direction == wx.LEFT:
4677             pinfo.Left()
4678         elif direction == wx.RIGHT:
4679             pinfo.Right()
4680         elif direction == wx.CENTER:
4681             pinfo.CenterPane()
4682         
4683         return self.AddPane(window, pinfo)
4684
4685
4686     def AddPane3(self, window, pane_info, drop_pos):
4687         """ See comments on L{AddPane}. """
4688         
4689         if not self.AddPane(window, pane_info):
4690             return False
4691
4692         pane = self.GetPane(window)
4693         indx = self._panes.index(pane)
4694
4695         ret, pane = self.DoDrop(self._docks, self._panes, pane, drop_pos, wx.Point(0, 0))
4696         self._panes[indx] = pane
4697
4698         return True
4699
4700
4701     def AddPane4(self, window, pane_info, target):
4702         """ See comments on L{AddPane}. """
4703         
4704         if not self.AddPane(window, pane_info):
4705             return False
4706                
4707         paneInfo = self.GetPane(window)
4708         
4709         if not paneInfo.IsNotebookDockable():
4710             return self.AddPane1(window, pane_info)
4711         if not target.IsNotebookDockable() and not target.IsNotebookControl():
4712             return self.AddPane1(window, pane_info)
4713
4714         if not target.HasNotebook():
4715             self.CreateNotebookBase(self._panes, target)
4716         
4717         # Add new item to notebook
4718         paneInfo.NotebookPage(target.notebook_id)
4719
4720         # we also want to remove our captions sometimes
4721         self.RemoveAutoNBCaption(paneInfo)
4722         self.UpdateNotebook()
4723         
4724         return True
4725
4726
4727     def InsertPane(self, window, pane_info, insert_level=AUI_INSERT_PANE):
4728         """
4729         This method is used to insert either a previously unmanaged pane window
4730         into the frame manager, or to insert a currently managed pane somewhere else.
4731         L{InsertPane} will push all panes, rows, or docks aside and insert the window
4732         into the position specified by `pane_info`.
4733
4734         Because `pane_info` can specify either a pane, dock row, or dock layer, the
4735         `insert_level` parameter is used to disambiguate this. The parameter `insert_level`
4736         can take a value of ``AUI_INSERT_PANE``, ``AUI_INSERT_ROW`` or ``AUI_INSERT_DOCK``.
4737
4738         :param `window`: the window to be inserted and managed;
4739         :param `pane_info`: the insert location for the new window;
4740         :param `insert_level`: the insertion level of the new pane.
4741         """
4742
4743         if not window:
4744             raise Exception("Invalid window passed to InsertPane.")
4745                             
4746         # shift the panes around, depending on the insert level
4747         if insert_level == AUI_INSERT_PANE:
4748             self._panes = DoInsertPane(self._panes, pane_info.dock_direction,
4749                                        pane_info.dock_layer, pane_info.dock_row,
4750                                        pane_info.dock_pos)
4751
4752         elif insert_level == AUI_INSERT_ROW:
4753             self._panes = DoInsertDockRow(self._panes, pane_info.dock_direction,
4754                                           pane_info.dock_layer, pane_info.dock_row)
4755
4756         elif insert_level == AUI_INSERT_DOCK:
4757             self._panes = DoInsertDockLayer(self._panes, pane_info.dock_direction,
4758                                             pane_info.dock_layer)
4759         
4760         # if the window already exists, we are basically just moving/inserting the
4761         # existing window.  If it doesn't exist, we need to add it and insert it
4762         existing_pane = self.GetPane(window)
4763         indx = self._panes.index(existing_pane)
4764         
4765         if not existing_pane.IsOk():
4766         
4767             return self.AddPane(window, pane_info)
4768         
4769         else:
4770         
4771             if pane_info.IsFloating():
4772                 existing_pane.Float()
4773                 if pane_info.floating_pos != wx.Point(-1, -1):
4774                     existing_pane.FloatingPosition(pane_info.floating_pos)
4775                 if pane_info.floating_size != wx.Size(-1, -1):
4776                     existing_pane.FloatingSize(pane_info.floating_size)
4777             else:
4778                 # if the new pane is docked then we should undo maximize
4779                 self.RestoreMaximizedPane()
4780
4781                 existing_pane.Direction(pane_info.dock_direction)
4782                 existing_pane.Layer(pane_info.dock_layer)
4783                 existing_pane.Row(pane_info.dock_row)
4784                 existing_pane.Position(pane_info.dock_pos)
4785
4786             self._panes[indx] = existing_pane                
4787             
4788         return True
4789
4790     
4791     def DetachPane(self, window):
4792         """
4793         Tells the L{AuiManager} to stop managing the pane specified
4794         by `window`. The window, if in a floated frame, is reparented to the frame
4795         managed by L{AuiManager}.
4796
4797         :param `window`: the window to be un-managed.
4798         """
4799         
4800         for p in self._panes:
4801             if p.window == window:
4802                 if p.frame:
4803                     # we have a floating frame which is being detached. We need to
4804                     # reparent it to self._frame and destroy the floating frame
4805
4806                     # reduce flicker
4807                     p.window.SetSize((1, 1))
4808                     if p.frame.IsShown():
4809                         p.frame.Show(False)
4810
4811                     if self._action_window == p.frame:
4812                         self._action_window = None
4813                         
4814                     # reparent to self._frame and destroy the pane
4815                     p.window.Reparent(self._frame)
4816                     p.frame.SetSizer(None)
4817                     p.frame.Destroy()
4818                     p.frame = None
4819
4820                 elif p.IsNotebookPage():
4821                     notebook = self._notebooks[p.notebook_id]
4822                     id = notebook.GetPageIndex(p.window)
4823                     notebook.RemovePage(id)
4824                 
4825                 # make sure there are no references to this pane in our uiparts,
4826                 # just in case the caller doesn't call Update() immediately after
4827                 # the DetachPane() call.  This prevets obscure crashes which would
4828                 # happen at window repaint if the caller forgets to call Update()
4829                 counter = 0
4830                 for pi in xrange(len(self._uiparts)):
4831                     part = self._uiparts[counter]
4832                     if part.pane == p:
4833                         self._uiparts.pop(counter)
4834                         counter -= 1
4835
4836                     counter += 1
4837             
4838                 self._panes.remove(p)
4839                 return True
4840         
4841         return False
4842
4843
4844     def ClosePane(self, pane_info):
4845         """
4846         Destroys or hides the pane depending on its flags.
4847
4848         :param `pane_info`: a L{AuiPaneInfo} instance.
4849         """
4850
4851         # if we were maximized, restore
4852         if pane_info.IsMaximized():
4853             self.RestorePane(pane_info)
4854
4855         if pane_info.frame:
4856             if self._agwFlags & AUI_MGR_ANIMATE_FRAMES:
4857                 pane_info.frame.FadeOut()
4858
4859         # first, hide the window
4860         if pane_info.window and pane_info.window.IsShown():
4861             pane_info.window.Show(False)
4862
4863         # make sure that we are the parent of this window
4864         if pane_info.window and pane_info.window.GetParent() != self._frame:
4865             pane_info.window.Reparent(self._frame)
4866
4867         # if we have a frame, destroy it
4868         if pane_info.frame:
4869             pane_info.frame.Destroy()
4870             pane_info.frame = None
4871             
4872         elif pane_info.IsNotebookPage():
4873             # if we are a notebook page, remove ourselves...
4874             # the  code would index out of bounds 
4875             # if the last page of a sub-notebook was closed
4876             # because the notebook would be deleted, before this
4877             # code is executed.
4878             # This code just prevents an out-of bounds error.
4879             if self._notebooks:
4880                 nid = pane_info.notebook_id
4881                 if nid >= 0 and nid < len(self._notebooks):
4882                     notebook = self._notebooks[nid]
4883                     page_idx = notebook.GetPageIndex(pane_info.window)
4884                     if page_idx >= 0:
4885                         notebook.RemovePage(page_idx)
4886                                 
4887         # now we need to either destroy or hide the pane
4888         to_destroy = 0
4889         if pane_info.IsDestroyOnClose():
4890             to_destroy = pane_info.window
4891             self.DetachPane(to_destroy)
4892         else:
4893             if isinstance(pane_info.window, auibar.AuiToolBar) and pane_info.IsFloating():
4894                 tb = pane_info.window
4895                 if pane_info.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT]:
4896                     tb.SetAGWWindowStyleFlag(tb.GetAGWWindowStyleFlag() | AUI_TB_VERTICAL)
4897                 
4898             pane_info.Dock().Hide()
4899
4900         if pane_info.IsNotebookControl():
4901
4902             notebook = self._notebooks[pane_info.notebook_id]
4903             while notebook.GetPageCount():
4904                 window = notebook.GetPage(0)
4905                 notebook.RemovePage(0)
4906                 info = self.GetPane(window)
4907                 if info.IsOk():
4908                     info.notebook_id = -1
4909                     info.dock_direction = AUI_DOCK_NONE
4910                     # Note: this could change our paneInfo reference ...
4911                     self.ClosePane(info)
4912
4913         if to_destroy:
4914             to_destroy.Destroy()
4915
4916
4917     def MaximizePane(self, pane_info, savesizes=True):
4918         """
4919         Maximizes the input pane.
4920
4921         :param `pane_info`: a L{AuiPaneInfo} instance.
4922         :param `savesizes`: whether to save previous dock sizes.
4923         """
4924
4925         if savesizes:
4926             self.SavePreviousDockSizes(pane_info)
4927                 
4928         for p in self._panes:
4929             
4930             # save hidden state
4931             p.SetFlag(p.savedHiddenState, p.HasFlag(p.optionHidden))
4932
4933             if not p.IsToolbar() and not p.IsFloating():
4934                 p.Restore()
4935         
4936                 # hide the pane, because only the newly
4937                 # maximized pane should show
4938                 p.Hide()
4939
4940         pane_info.previousDockPos = pane_info.dock_pos
4941
4942         # mark ourselves maximized
4943         pane_info.Maximize()
4944         pane_info.Show()
4945         self._has_maximized = True
4946
4947         # last, show the window
4948         if pane_info.window and not pane_info.window.IsShown():
4949             pane_info.window.Show(True)
4950
4951             
4952     def SavePreviousDockSizes(self, pane_info):
4953         """
4954         Stores the previous dock sizes, to be used in a "restore" action later.
4955
4956         :param `pane_info`: a L{AuiPaneInfo} instance.
4957         """
4958
4959         for d in self._docks:
4960             if not d.toolbar:
4961                 for p in d.panes:
4962                     p.previousDockSize = d.size
4963                     if pane_info is not p:
4964                         p.SetFlag(p.needsRestore, True)
4965
4966         
4967     def RestorePane(self, pane_info):
4968         """
4969         Restores the input pane from a previous maximized or minimized state.
4970
4971         :param `pane_info`: a L{AuiPaneInfo} instance.
4972         """
4973         
4974         # restore all the panes
4975         for p in self._panes:
4976             if not p.IsToolbar():
4977                 p.SetFlag(p.optionHidden, p.HasFlag(p.savedHiddenState))
4978
4979         pane_info.SetFlag(pane_info.needsRestore, True)
4980
4981         # mark ourselves non-maximized
4982         pane_info.Restore()
4983         self._has_maximized = False
4984         self._has_minimized = False
4985
4986         # last, show the window
4987         if pane_info.window and not pane_info.window.IsShown():
4988             pane_info.window.Show(True)
4989
4990
4991     def RestoreMaximizedPane(self):
4992         """ Restores the current maximized pane (if any). """
4993         
4994         # restore all the panes
4995         for p in self._panes:
4996             if p.IsMaximized():
4997                 self.RestorePane(p)
4998                 break
4999
5000
5001     def ActivatePane(self, window):
5002         """
5003         Activates the pane to which `window` is associated.
5004
5005         :param `window`: a `wx.Window` derived window.
5006         """
5007
5008         if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
5009             while window:
5010                 ret, self._panes = SetActivePane(self._panes, window)
5011                 if ret:
5012                     break
5013
5014                 window = window.GetParent()
5015
5016             self.RefreshCaptions()
5017             self.FireEvent(wxEVT_AUI_PANE_ACTIVATED, window, canVeto=False)
5018             
5019
5020     def CreateNotebook(self):
5021         """
5022         Creates an automatic L{AuiNotebook} when a pane is docked on
5023         top of another pane.
5024         """
5025
5026         notebook = auibook.AuiNotebook(self._frame, -1, wx.Point(0, 0), wx.Size(0, 0), agwStyle=self._autoNBStyle)
5027
5028         # This is so we can get the tab-drag event.
5029         notebook.GetAuiManager().SetMasterManager(self)
5030         notebook.SetArtProvider(self._autoNBTabArt.Clone())
5031         self._notebooks.append(notebook)
5032
5033         return notebook
5034
5035
5036     def SetAutoNotebookTabArt(self, art):
5037         """
5038         Sets the default tab art provider for automatic notebooks.
5039
5040         :param `art`: a tab art provider.
5041         """
5042
5043         for nb in self._notebooks:
5044             nb.SetArtProvider(art.Clone())
5045             nb.Refresh()
5046             nb.Update()
5047
5048         self._autoNBTabArt = art
5049
5050
5051     def GetAutoNotebookTabArt(self):
5052         """ Returns the default tab art provider for automatic notebooks. """
5053
5054         return self._autoNBTabArt        
5055         
5056
5057     def SetAutoNotebookStyle(self, agwStyle):
5058         """
5059         Sets the default AGW-specific window style for automatic notebooks.
5060
5061         :param `agwStyle`: the underlying L{AuiNotebook} window style.
5062          This can be a combination of the following bits:
5063         
5064          ==================================== ==================================
5065          Flag name                            Description
5066          ==================================== ==================================
5067          ``AUI_NB_TOP``                       With this style, tabs are drawn along the top of the notebook
5068          ``AUI_NB_LEFT``                      With this style, tabs are drawn along the left of the notebook. Not implemented yet.
5069          ``AUI_NB_RIGHT``                     With this style, tabs are drawn along the right of the notebook. Not implemented yet.
5070          ``AUI_NB_BOTTOM``                    With this style, tabs are drawn along the bottom of the notebook
5071          ``AUI_NB_TAB_SPLIT``                 Allows the tab control to be split by dragging a tab
5072          ``AUI_NB_TAB_MOVE``                  Allows a tab to be moved horizontally by dragging
5073          ``AUI_NB_TAB_EXTERNAL_MOVE``         Allows a tab to be moved to another tab control
5074          ``AUI_NB_TAB_FIXED_WIDTH``           With this style, all tabs have the same width
5075          ``AUI_NB_SCROLL_BUTTONS``            With this style, left and right scroll buttons are displayed
5076          ``AUI_NB_WINDOWLIST_BUTTON``         With this style, a drop-down list of windows is available
5077          ``AUI_NB_CLOSE_BUTTON``              With this style, a close button is available on the tab bar
5078          ``AUI_NB_CLOSE_ON_ACTIVE_TAB``       With this style, a close button is available on the active tab
5079          ``AUI_NB_CLOSE_ON_ALL_TABS``         With this style, a close button is available on all tabs
5080          ``AUI_NB_MIDDLE_CLICK_CLOSE``        Allows to close L{AuiNotebook} tabs by mouse middle button click
5081          ``AUI_NB_SUB_NOTEBOOK``              This style is used by {AuiManager} to create automatic AuiNotebooks
5082          ``AUI_NB_HIDE_ON_SINGLE_TAB``        Hides the tab window if only one tab is present
5083          ``AUI_NB_SMART_TABS``                Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows
5084          ``AUI_NB_USE_IMAGES_DROPDOWN``       Uses images on dropdown window list menu instead of check items
5085          ``AUI_NB_CLOSE_ON_TAB_LEFT``         Draws the tab close button on the left instead of on the right (a la Camino browser)
5086          ``AUI_NB_TAB_FLOAT``                 Allows the floating of single tabs. Known limitation: when the notebook is more or less full screen, tabs cannot be dragged far enough outside of the notebook to become floating pages
5087          ``AUI_NB_DRAW_DND_TAB``              Draws an image representation of a tab while dragging (on by default)
5088          ==================================== ==================================
5089
5090         """
5091
5092         for nb in self._notebooks:
5093             nb.SetAGWWindowStyleFlag(agwStyle)
5094             nb.Refresh()
5095             nb.Update()
5096
5097         self._autoNBStyle = agwStyle
5098
5099
5100     def GetAutoNotebookStyle(self):
5101         """
5102         Returns the default AGW-specific window style for automatic notebooks.
5103
5104         :see: L{SetAutoNotebookStyle} method for a list of possible styles.
5105         """
5106
5107         return self._autoNBStyle
5108
5109
5110     def SavePaneInfo(self, pane):
5111         """
5112         This method is similar to L{SavePerspective}, with the exception
5113         that it only saves information about a single pane. It is used in
5114         combination with L{LoadPaneInfo}.
5115
5116         :param `pane`: a L{AuiPaneInfo} instance to save.        
5117         """
5118
5119         result = "name=" + EscapeDelimiters(pane.name) + ";"
5120         result += "caption=" + EscapeDelimiters(pane.caption) + ";"
5121
5122         result += "state=%u;"%pane.state
5123         result += "dir=%d;"%pane.dock_direction
5124         result += "layer=%d;"%pane.dock_layer
5125         result += "row=%d;"%pane.dock_row
5126         result += "pos=%d;"%pane.dock_pos
5127         result += "prop=%d;"%pane.dock_proportion
5128         result += "bestw=%d;"%pane.best_size.x
5129         result += "besth=%d;"%pane.best_size.y
5130         result += "minw=%d;"%pane.min_size.x
5131         result += "minh=%d;"%pane.min_size.y
5132         result += "maxw=%d;"%pane.max_size.x
5133         result += "maxh=%d;"%pane.max_size.y
5134         result += "floatx=%d;"%pane.floating_pos.x
5135         result += "floaty=%d;"%pane.floating_pos.y
5136         result += "floatw=%d;"%pane.floating_size.x
5137         result += "floath=%d;"%pane.floating_size.y
5138         result += "notebookid=%d;"%pane.notebook_id
5139         result += "transparent=%d"%pane.transparent
5140
5141         return result
5142
5143
5144     def LoadPaneInfo(self, pane_part, pane):
5145         """
5146         This method is similar to to L{LoadPerspective}, with the exception that
5147         it only loads information about a single pane. It is used in combination
5148         with L{SavePaneInfo}.
5149
5150         :param `pane_part`: the string to analyze;
5151         :param `pane`: the L{AuiPaneInfo} structure in which to load `pane_part`.
5152         """
5153
5154         # replace escaped characters so we can
5155         # split up the string easily
5156         pane_part = pane_part.replace("\\|", "\a")
5157         pane_part = pane_part.replace("\\;", "\b")
5158
5159         options = pane_part.split(";")
5160         for items in options:
5161
5162             val_name, value = items.split("=")
5163             val_name = val_name.strip()
5164
5165             if val_name == "name":
5166                 pane.name = value
5167             elif val_name == "caption":
5168                 pane.caption = value
5169             elif val_name == "state":
5170                 pane.state = int(value)
5171             elif val_name == "dir":
5172                 pane.dock_direction = int(value)
5173             elif val_name == "layer":
5174                 pane.dock_layer = int(value)
5175             elif val_name == "row":
5176                 pane.dock_row = int(value)
5177             elif val_name == "pos":
5178                 pane.dock_pos = int(value)
5179             elif val_name == "prop":
5180                 pane.dock_proportion = int(value)
5181             elif val_name == "bestw":
5182                 pane.best_size.x = int(value)
5183             elif val_name == "besth":
5184                 pane.best_size.y = int(value)
5185                 pane.best_size = wx.Size(pane.best_size.x, pane.best_size.y)
5186             elif val_name == "minw":
5187                 pane.min_size.x = int(value)
5188             elif val_name == "minh":
5189                 pane.min_size.y = int(value)
5190                 pane.min_size = wx.Size(pane.min_size.x, pane.min_size.y)
5191             elif val_name == "maxw":
5192                 pane.max_size.x = int(value)
5193             elif val_name == "maxh":
5194                 pane.max_size.y = int(value)
5195                 pane.max_size = wx.Size(pane.max_size.x, pane.max_size.y)
5196             elif val_name == "floatx":
5197                 pane.floating_pos.x = int(value)
5198             elif val_name == "floaty":
5199                 pane.floating_pos.y = int(value)
5200                 pane.floating_pos = wx.Point(pane.floating_pos.x, pane.floating_pos.y)
5201             elif val_name == "floatw":
5202                 pane.floating_size.x = int(value)
5203             elif val_name == "floath":
5204                 pane.floating_size.y = int(value)
5205                 pane.floating_size = wx.Size(pane.floating_size.x, pane.floating_size.y)
5206             elif val_name == "notebookid":
5207                 pane.notebook_id = int(value)
5208             elif val_name == "transparent":
5209                 pane.transparent = int(value)
5210             else:
5211                 raise Exception("Bad perspective string")
5212
5213         # replace escaped characters so we can
5214         # split up the string easily
5215         pane.name = pane.name.replace("\a", "|")
5216         pane.name = pane.name.replace("\b", ";")
5217         pane.caption = pane.caption.replace("\a", "|")
5218         pane.caption = pane.caption.replace("\b", ";")
5219         pane_part = pane_part.replace("\a", "|")
5220         pane_part = pane_part.replace("\b", ";")
5221
5222         return pane
5223     
5224
5225     def SavePerspective(self):
5226         """
5227         Saves the entire user interface layout into an encoded string, which can then
5228         be stored by the application (probably using `wx.Config`).
5229
5230         When a perspective is restored using L{LoadPerspective}, the entire user
5231         interface will return to the state it was when the perspective was saved.
5232         """
5233
5234         result = "layout2|"
5235
5236         for pane in self._panes:
5237             result += self.SavePaneInfo(pane) + "|"
5238         
5239         for dock in self._docks:
5240             result = result + ("dock_size(%d,%d,%d)=%d|")%(dock.dock_direction,
5241                                                            dock.dock_layer,
5242                                                            dock.dock_row,
5243                                                            dock.size)
5244         return result
5245
5246
5247     def LoadPerspective(self, layout, update=True):
5248         """
5249         Loads a layout which was saved with L{SavePerspective}.
5250         
5251         If the `update` flag parameter is ``True``, L{Update} will be
5252         automatically invoked, thus realizing the saved perspective on screen.
5253
5254         :param `layout`: a string which contains a saved AUI layout;
5255         :param `update`: whether to update immediately the window or not.
5256         """
5257
5258         input = layout
5259
5260         # check layout string version
5261         #    'layout1' = wxAUI 0.9.0 - wxAUI 0.9.2
5262         #    'layout2' = wxAUI 0.9.2 (wxWidgets 2.8)
5263         index = input.find("|")
5264         part = input[0:index].strip()
5265         input = input[index+1:]
5266         
5267         if part != "layout2":
5268             return False
5269
5270         # mark all panes currently managed as docked and hidden
5271         for pane in self._panes:
5272             pane.Dock().Hide()
5273
5274         # clear out the dock array; this will be reconstructed
5275         self._docks = []
5276
5277         # replace escaped characters so we can
5278         # split up the string easily
5279         input = input.replace("\\|", "\a")
5280         input = input.replace("\\;", "\b")
5281
5282         while 1:
5283
5284             pane = AuiPaneInfo()
5285             index = input.find("|")
5286             pane_part = input[0:index].strip()
5287             input = input[index+1:]
5288
5289             # if the string is empty, we're done parsing
5290             if pane_part == "":
5291                 break
5292
5293             if pane_part[0:9] == "dock_size":
5294                 index = pane_part.find("=")
5295                 val_name = pane_part[0:index]
5296                 value = pane_part[index+1:]
5297
5298                 index = val_name.find("(")
5299                 piece = val_name[index+1:]
5300                 index = piece.find(")")
5301                 piece = piece[0:index]
5302
5303                 vals = piece.split(",")
5304                 dir = int(vals[0])
5305                 layer = int(vals[1])
5306                 row = int(vals[2])
5307                 size = int(value)
5308                 
5309                 dock = AuiDockInfo()
5310                 dock.dock_direction = dir
5311                 dock.dock_layer = layer
5312                 dock.dock_row = row
5313                 dock.size = size
5314                 self._docks.append(dock)
5315                 
5316                 continue
5317
5318             # Undo our escaping as LoadPaneInfo needs to take an unescaped
5319             # name so it can be called by external callers
5320             pane_part = pane_part.replace("\a", "|")
5321             pane_part = pane_part.replace("\b", ";")
5322
5323             pane = self.LoadPaneInfo(pane_part, pane)
5324
5325             p = self.GetPane(pane.name)
5326                 
5327             if not p.IsOk():
5328                 if pane.IsNotebookControl():
5329                     # notebook controls - auto add...
5330                     self._panes.append(pane)
5331                     indx = self._panes.index(pane)
5332                 else:
5333                     # the pane window couldn't be found
5334                     # in the existing layout -- skip it
5335                     continue
5336
5337             else:
5338                 indx = self._panes.index(p)
5339             pane.window = p.window
5340             pane.frame = p.frame
5341             pane.buttons = p.buttons
5342             self._panes[indx] = pane
5343
5344             if isinstance(pane.window, auibar.AuiToolBar) and (pane.IsFloatable() or pane.IsDockable()):
5345                 pane.window.SetGripperVisible(True)
5346             
5347         if update:
5348             self.Update()
5349
5350         return True
5351
5352
5353     def GetPanePositionsAndSizes(self, dock):
5354         """
5355         Returns all the panes positions and sizes in a dock.
5356
5357         :param `dock`: a L{AuiDockInfo} instance.
5358         """
5359         
5360         caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
5361         pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
5362         gripper_size = self._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE)
5363
5364         positions = []
5365         sizes = []
5366
5367         action_pane = -1
5368         pane_count = len(dock.panes)
5369
5370         # find the pane marked as our action pane
5371         for pane_i in xrange(pane_count):
5372             pane = dock.panes[pane_i]
5373             if pane.HasFlag(AuiPaneInfo.actionPane):
5374                 if action_pane != -1:
5375                     raise Exception("Too many action panes!")
5376                 action_pane = pane_i
5377             
5378         # set up each panes default position, and
5379         # determine the size (width or height, depending
5380         # on the dock's orientation) of each pane
5381         for pane in dock.panes:
5382             positions.append(pane.dock_pos)
5383             size = 0
5384             
5385             if pane.HasBorder():
5386                 size += pane_border_size*2
5387                     
5388             if dock.IsHorizontal():
5389                 if pane.HasGripper() and not pane.HasGripperTop():
5390                     size += gripper_size
5391
5392                 if pane.HasCaptionLeft():
5393                     size += caption_size
5394                     
5395                 size += pane.best_size.x
5396                  
5397             else:
5398                 if pane.HasGripper() and pane.HasGripperTop():
5399                     size += gripper_size
5400
5401                 if pane.HasCaption() and not pane.HasCaptionLeft():
5402                     size += caption_size
5403                     
5404                 size += pane.best_size.y
5405        
5406             sizes.append(size)
5407
5408         # if there is no action pane, just return the default
5409         # positions (as specified in pane.pane_pos)
5410         if action_pane == -1:
5411             return positions, sizes
5412
5413         offset = 0
5414         for pane_i in xrange(action_pane-1, -1, -1):
5415             amount = positions[pane_i+1] - (positions[pane_i] + sizes[pane_i])
5416             if amount >= 0:
5417                 offset += amount
5418             else:
5419                 positions[pane_i] -= -amount
5420
5421             offset += sizes[pane_i]
5422         
5423         # if the dock mode is fixed, make sure none of the panes
5424         # overlap we will bump panes that overlap
5425         offset = 0
5426         for pane_i in xrange(action_pane, pane_count):
5427             amount = positions[pane_i] - offset
5428             if amount >= 0:
5429                 offset += amount
5430             else:
5431                 positions[pane_i] += -amount
5432
5433             offset += sizes[pane_i]
5434
5435         return positions, sizes
5436     
5437
5438     def LayoutAddPane(self, cont, dock, pane, uiparts, spacer_only):
5439         """
5440         Adds a pane into the existing layout (in an existing dock).
5441
5442         :param `cont`: a `wx.Sizer` object;
5443         :param `dock`: the L{AuiDockInfo} structure in which to add the pane;
5444         :param `pane`: the L{AuiPaneInfo} instance to add to the dock;
5445         :param `uiparts`: a list of UI parts in the interface;
5446         :param `spacer_only`: whether to add a simple spacer or a real window.
5447         """
5448         
5449         sizer_item = wx.SizerItem()
5450         caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
5451         gripper_size = self._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE)
5452         pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
5453         pane_button_size = self._art.GetMetric(AUI_DOCKART_PANE_BUTTON_SIZE)
5454
5455         # find out the orientation of the item (orientation for panes
5456         # is the same as the dock's orientation)
5457
5458         if dock.IsHorizontal():
5459             orientation = wx.HORIZONTAL
5460         else:
5461             orientation = wx.VERTICAL
5462
5463         # this variable will store the proportion
5464         # value that the pane will receive
5465         pane_proportion = pane.dock_proportion
5466
5467         horz_pane_sizer = wx.BoxSizer(wx.HORIZONTAL)
5468         vert_pane_sizer = wx.BoxSizer(wx.VERTICAL)
5469
5470         if pane.HasGripper():
5471             
5472             part = AuiDockUIPart()
5473             if pane.HasGripperTop():
5474                 sizer_item = vert_pane_sizer.Add((1, gripper_size), 0, wx.EXPAND)
5475             else:
5476                 sizer_item = horz_pane_sizer.Add((gripper_size, 1), 0, wx.EXPAND)
5477
5478             part.type = AuiDockUIPart.typeGripper
5479             part.dock = dock
5480             part.pane = pane
5481             part.button = None
5482             part.orientation = orientation
5483             part.cont_sizer = horz_pane_sizer
5484             part.sizer_item = sizer_item
5485             uiparts.append(part)
5486
5487         button_count = len(pane.buttons)
5488         button_width_total = button_count*pane_button_size
5489         if button_count >= 1:
5490             button_width_total += 3
5491
5492         caption, captionLeft = pane.HasCaption(), pane.HasCaptionLeft()
5493         button_count = len(pane.buttons)
5494
5495         if captionLeft:
5496             caption_sizer = wx.BoxSizer(wx.VERTICAL)
5497
5498             # add pane buttons to the caption
5499             dummy_parts = []
5500             for btn_id in xrange(len(pane.buttons)-1, -1, -1):
5501                 sizer_item = caption_sizer.Add((caption_size, pane_button_size), 0, wx.EXPAND)
5502                 part = AuiDockUIPart()
5503                 part.type = AuiDockUIPart.typePaneButton
5504                 part.dock = dock
5505                 part.pane = pane
5506                 part.button = pane.buttons[btn_id]
5507                 part.orientation = orientation
5508                 part.cont_sizer = caption_sizer
5509                 part.sizer_item = sizer_item
5510                 dummy_parts.append(part)
5511             
5512             sizer_item = caption_sizer.Add((caption_size, 1), 1, wx.EXPAND)
5513             vert_pane_sizer = wx.BoxSizer(wx.HORIZONTAL)
5514
5515             # create the caption sizer
5516             part = AuiDockUIPart()
5517
5518             part.type = AuiDockUIPart.typeCaption
5519             part.dock = dock
5520             part.pane = pane
5521             part.button = None
5522             part.orientation = orientation
5523             part.cont_sizer = vert_pane_sizer
5524             part.sizer_item = sizer_item
5525             caption_part_idx = len(uiparts)
5526             uiparts.append(part)
5527             uiparts.extend(dummy_parts)
5528
5529         elif caption:
5530
5531             caption_sizer = wx.BoxSizer(wx.HORIZONTAL)
5532             sizer_item = caption_sizer.Add((1, caption_size), 1, wx.EXPAND)
5533
5534             # create the caption sizer
5535             part = AuiDockUIPart()
5536
5537             part.type = AuiDockUIPart.typeCaption
5538             part.dock = dock
5539             part.pane = pane
5540             part.button = None
5541             part.orientation = orientation
5542             part.cont_sizer = vert_pane_sizer
5543             part.sizer_item = sizer_item
5544             caption_part_idx = len(uiparts)
5545             uiparts.append(part)
5546
5547             # add pane buttons to the caption
5548             for button in pane.buttons:
5549                 sizer_item = caption_sizer.Add((pane_button_size, caption_size), 0, wx.EXPAND)                        
5550                 part = AuiDockUIPart()
5551                 part.type = AuiDockUIPart.typePaneButton
5552                 part.dock = dock
5553                 part.pane = pane
5554                 part.button = button
5555                 part.orientation = orientation
5556                 part.cont_sizer = caption_sizer
5557                 part.sizer_item = sizer_item
5558                 uiparts.append(part)
5559
5560         if caption or captionLeft:
5561             # if we have buttons, add a little space to the right
5562             # of them to ease visual crowding
5563             if button_count >= 1:
5564                 if captionLeft:
5565                     caption_sizer.Add((caption_size, 3), 0, wx.EXPAND)
5566                 else:
5567                     caption_sizer.Add((3, caption_size), 0, wx.EXPAND)
5568
5569             # add the caption sizer
5570             sizer_item = vert_pane_sizer.Add(caption_sizer, 0, wx.EXPAND)
5571             uiparts[caption_part_idx].sizer_item = sizer_item
5572                     
5573         # add the pane window itself
5574         if spacer_only or not pane.window:
5575             sizer_item = vert_pane_sizer.Add((1, 1), 1, wx.EXPAND)
5576         else:
5577             sizer_item = vert_pane_sizer.Add(pane.window, 1, wx.EXPAND)
5578             vert_pane_sizer.SetItemMinSize(pane.window, (1, 1))
5579
5580         part = AuiDockUIPart()        
5581         part.type = AuiDockUIPart.typePane
5582         part.dock = dock
5583         part.pane = pane
5584         part.button = None
5585         part.orientation = orientation
5586         part.cont_sizer = vert_pane_sizer
5587         part.sizer_item = sizer_item
5588         uiparts.append(part)
5589
5590         # determine if the pane should have a minimum size if the pane is
5591         # non-resizable (fixed) then we must set a minimum size. Alternatively,
5592         # if the pane.min_size is set, we must use that value as well
5593         
5594         min_size = pane.min_size
5595         if pane.IsFixed():
5596             if min_size == wx.Size(-1, -1):
5597                 min_size = pane.best_size
5598                 pane_proportion = 0
5599
5600         if min_size != wx.Size(-1, -1):
5601             vert_pane_sizer.SetItemMinSize(len(vert_pane_sizer.GetChildren())-1, (min_size.x, min_size.y))
5602         
5603         # add the vertical/horizontal sizer (caption, pane window) to the
5604         # horizontal sizer (gripper, vertical sizer)
5605         horz_pane_sizer.Add(vert_pane_sizer, 1, wx.EXPAND)
5606
5607         # finally, add the pane sizer to the dock sizer
5608         if pane.HasBorder():
5609             # allowing space for the pane's border
5610             sizer_item = cont.Add(horz_pane_sizer, pane_proportion,
5611                                   wx.EXPAND | wx.ALL, pane_border_size)
5612             part = AuiDockUIPart()
5613             part.type = AuiDockUIPart.typePaneBorder
5614             part.dock = dock
5615             part.pane = pane
5616             part.button = None
5617             part.orientation = orientation
5618             part.cont_sizer = cont
5619             part.sizer_item = sizer_item
5620             uiparts.append(part)
5621         else:
5622             sizer_item = cont.Add(horz_pane_sizer, pane_proportion, wx.EXPAND)
5623         
5624         return uiparts
5625         
5626         
5627     def LayoutAddDock(self, cont, dock, uiparts, spacer_only):
5628         """
5629         Adds a dock into the existing layout.
5630
5631         :param `cont`: a `wx.Sizer` object;
5632         :param `dock`: the L{AuiDockInfo} structure to add to the layout;
5633         :param `uiparts`: a list of UI parts in the interface;
5634         :param `spacer_only`: whether to add a simple spacer or a real window.
5635         """
5636         
5637         sizer_item = wx.SizerItem()
5638         part = AuiDockUIPart()
5639
5640         sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
5641         orientation = (dock.IsHorizontal() and [wx.HORIZONTAL] or [wx.VERTICAL])[0]
5642
5643         # resizable bottom and right docks have a sash before them
5644         if not self._has_maximized and not dock.fixed and \
5645            dock.dock_direction in [AUI_DOCK_BOTTOM, AUI_DOCK_RIGHT]:
5646         
5647             sizer_item = cont.Add((sash_size, sash_size), 0, wx.EXPAND)
5648
5649             part.type = AuiDockUIPart.typeDockSizer
5650             part.orientation = orientation
5651             part.dock = dock
5652             part.pane = None
5653             part.button = None
5654             part.cont_sizer = cont
5655             part.sizer_item = sizer_item
5656             uiparts.append(part)
5657         
5658         # create the sizer for the dock
5659         dock_sizer = wx.BoxSizer(orientation)
5660
5661         # add each pane to the dock
5662         has_maximized_pane = False
5663         pane_count = len(dock.panes)
5664
5665         if dock.fixed:
5666         
5667             # figure out the real pane positions we will
5668             # use, without modifying the each pane's pane_pos member
5669             pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock)
5670
5671             offset = 0
5672             for pane_i in xrange(pane_count):
5673             
5674                 pane = dock.panes[pane_i]
5675                 pane_pos = pane_positions[pane_i]
5676
5677                 if pane.IsMaximized():
5678                     has_maximized_pane = True
5679
5680                 amount = pane_pos - offset
5681                 if amount > 0:
5682                 
5683                     if dock.IsVertical():
5684                         sizer_item = dock_sizer.Add((1, amount), 0, wx.EXPAND)
5685                     else:
5686                         sizer_item = dock_sizer.Add((amount, 1), 0, wx.EXPAND)
5687
5688                     part = AuiDockUIPart()
5689                     part.type = AuiDockUIPart.typeBackground
5690                     part.dock = dock
5691                     part.pane = None
5692                     part.button = None
5693                     part.orientation = (orientation==wx.HORIZONTAL and \
5694                                         [wx.VERTICAL] or [wx.HORIZONTAL])[0]
5695                     part.cont_sizer = dock_sizer
5696                     part.sizer_item = sizer_item
5697                     uiparts.append(part)
5698
5699                     offset = offset + amount
5700                 
5701                 uiparts = self.LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only)
5702
5703                 offset = offset + pane_sizes[pane_i]
5704             
5705             # at the end add a very small stretchable background area
5706             sizer_item = dock_sizer.Add((0, 0), 1, wx.EXPAND)
5707             part = AuiDockUIPart()
5708             part.type = AuiDockUIPart.typeBackground
5709             part.dock = dock
5710             part.pane = None
5711             part.button = None
5712             part.orientation = orientation
5713             part.cont_sizer = dock_sizer
5714             part.sizer_item = sizer_item
5715             uiparts.append(part)
5716         
5717         else:
5718         
5719             for pane_i in xrange(pane_count):
5720             
5721                 pane = dock.panes[pane_i]
5722
5723                 if pane.IsMaximized():
5724                     has_maximized_pane = True
5725
5726                 # if this is not the first pane being added,
5727                 # we need to add a pane sizer
5728                 if not self._has_maximized and pane_i > 0:
5729                     sizer_item = dock_sizer.Add((sash_size, sash_size), 0, wx.EXPAND)
5730                     part = AuiDockUIPart()
5731                     part.type = AuiDockUIPart.typePaneSizer
5732                     part.dock = dock
5733                     part.pane = dock.panes[pane_i-1]
5734                     part.button = None
5735                     part.orientation = (orientation==wx.HORIZONTAL and \
5736                                         [wx.VERTICAL] or [wx.HORIZONTAL])[0]
5737                     part.cont_sizer = dock_sizer
5738                     part.sizer_item = sizer_item
5739                     uiparts.append(part)
5740                 
5741                 uiparts = self.LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only)
5742             
5743         if dock.dock_direction == AUI_DOCK_CENTER or has_maximized_pane:
5744             sizer_item = cont.Add(dock_sizer, 1, wx.EXPAND)
5745         else:
5746             sizer_item = cont.Add(dock_sizer, 0, wx.EXPAND)
5747
5748         part = AuiDockUIPart()
5749         part.type = AuiDockUIPart.typeDock
5750         part.dock = dock
5751         part.pane = None
5752         part.button = None
5753         part.orientation = orientation
5754         part.cont_sizer = cont
5755         part.sizer_item = sizer_item
5756         uiparts.append(part)
5757
5758         if dock.IsHorizontal():
5759             cont.SetItemMinSize(dock_sizer, (0, dock.size))
5760         else:
5761             cont.SetItemMinSize(dock_sizer, (dock.size, 0))
5762
5763         #  top and left docks have a sash after them
5764         if not self._has_maximized and not dock.fixed and \
5765            dock.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_LEFT]:
5766         
5767             sizer_item = cont.Add((sash_size, sash_size), 0, wx.EXPAND)
5768
5769             part = AuiDockUIPart()
5770             part.type = AuiDockUIPart.typeDockSizer
5771             part.dock = dock
5772             part.pane = None
5773             part.button = None
5774             part.orientation = orientation
5775             part.cont_sizer = cont
5776             part.sizer_item = sizer_item
5777             uiparts.append(part)
5778         
5779         return uiparts
5780     
5781
5782     def LayoutAll(self, panes, docks, uiparts, spacer_only=False, oncheck=True):
5783         """
5784         Layouts all the UI structures in the interface.
5785
5786         :param `panes`: a list of L{AuiPaneInfo} instances;
5787         :param `docks`: a list of L{AuiDockInfo} classes;
5788         :param `uiparts`: a list of UI parts in the interface;
5789         :param `spacer_only`: whether to add a simple spacer or a real window;
5790         :param `oncheck`: whether to store the results in a class member or not.
5791         """
5792         
5793         container = wx.BoxSizer(wx.VERTICAL)
5794
5795         pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
5796         caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
5797         cli_size = self._frame.GetClientSize()
5798         
5799         # empty all docks out
5800         for dock in docks:
5801             dock.panes = []
5802             if dock.fixed:
5803                 # always reset fixed docks' sizes, because
5804                 # the contained windows may have been resized
5805                 dock.size = 0
5806             
5807         dock_count = len(docks)
5808         
5809         # iterate through all known panes, filing each
5810         # of them into the appropriate dock. If the
5811         # pane does not exist in the dock, add it
5812         for p in panes:
5813
5814             # don't layout hidden panes.
5815             if p.IsShown():
5816                 
5817                 # find any docks with the same dock direction, dock layer, and
5818                 # dock row as the pane we are working on
5819                 arr = FindDocks(docks, p.dock_direction, p.dock_layer, p.dock_row)
5820
5821                 if arr:
5822                     dock = arr[0]
5823
5824                 else:
5825                     # dock was not found, so we need to create a new one
5826                     d = AuiDockInfo()
5827                     d.dock_direction = p.dock_direction
5828                     d.dock_layer = p.dock_layer
5829                     d.dock_row = p.dock_row
5830                     docks.append(d)
5831                     dock = docks[-1]
5832
5833                     if p.HasFlag(p.needsRestore) and not p.HasFlag(p.wasMaximized):
5834                    
5835                         isHor = dock.IsHorizontal()
5836                         sashSize = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
5837
5838                         # get the sizes of any docks that might 
5839                         # overlap with our restored dock
5840
5841                         # make list of widths or heights from the size in the dock rects
5842                         sizes = [d.rect[2:][isHor] for \
5843                                  d in docks if d.IsOk() and \
5844                                  (d.IsHorizontal() == isHor) and \
5845                                  not d.toolbar and \
5846                                  d.dock_direction != AUI_DOCK_CENTER]
5847                         
5848                         frameRect = GetInternalFrameRect(self._frame, self._docks)
5849
5850                         # set max size allowing for sashes and absolute minimum
5851                         maxsize = frameRect[2:][isHor] - sum(sizes) - (len(sizes)*10) - (sashSize*len(sizes))
5852                         dock.size = min(p.previousDockSize,maxsize)
5853
5854                     else:
5855                         dock.size = 0
5856
5857                 if p.HasFlag(p.wasMaximized):
5858                     self.MaximizePane(p, savesizes=False)
5859                     p.SetFlag(p.wasMaximized, False)
5860
5861                 if p.HasFlag(p.needsRestore):
5862                     if p.previousDockPos is not None:
5863                         DoInsertPane(dock.panes, dock.dock_direction, dock.dock_layer, dock.dock_row, p.previousDockPos)
5864                         p.dock_pos = p.previousDockPos
5865                         p.previousDockPos = None
5866                     p.SetFlag(p.needsRestore, False)
5867
5868                 if p.IsDocked():
5869                     # remove the pane from any existing docks except this one
5870                     docks = RemovePaneFromDocks(docks, p, dock)
5871
5872                     # pane needs to be added to the dock,
5873                     # if it doesn't already exist 
5874                     if not FindPaneInDock(dock, p.window):
5875                         dock.panes.append(p)
5876                 else:
5877                     # remove the pane from any existing docks
5878                     docks = RemovePaneFromDocks(docks, p)
5879                 
5880         # remove any empty docks
5881         docks = [dock for dock in docks if dock.panes]
5882
5883         dock_count = len(docks)
5884         # configure the docks further
5885         for ii, dock in enumerate(docks):
5886             # sort the dock pane array by the pane's
5887             # dock position (dock_pos), in ascending order
5888             dock.panes.sort(PaneSortFunc)
5889             dock_pane_count = len(dock.panes)
5890             
5891             # for newly created docks, set up their initial size
5892             if dock.size == 0:
5893                 size = 0
5894                 for pane in dock.panes:
5895                     pane_size = pane.best_size
5896                     if pane_size == wx.Size(-1, -1):
5897                         pane_size = pane.min_size
5898                     if pane_size == wx.Size(-1, -1) and pane.window:
5899                         pane_size = pane.window.GetSize()
5900                     if dock.IsHorizontal():
5901                         size = max(pane_size.y, size)
5902                     else:
5903                         size = max(pane_size.x, size)
5904                 
5905                 # add space for the border (two times), but only
5906                 # if at least one pane inside the dock has a pane border
5907                 for pane in dock.panes:
5908                     if pane.HasBorder():
5909                         size = size + pane_border_size*2
5910                         break
5911                     
5912                 # if pane is on the top or bottom, add the caption height,
5913                 # but only if at least one pane inside the dock has a caption
5914                 if dock.IsHorizontal():
5915                     for pane in dock.panes:
5916                         if pane.HasCaption() and not pane.HasCaptionLeft():
5917                             size = size + caption_size
5918                             break
5919                 else:
5920                     for pane in dock.panes:
5921                         if pane.HasCaptionLeft() and not pane.HasCaption():
5922                             size = size + caption_size
5923                             break
5924                     
5925                 # new dock's size may not be more than the dock constraint
5926                 # parameter specifies.  See SetDockSizeConstraint()
5927                 max_dock_x_size = int(self._dock_constraint_x*float(cli_size.x))
5928                 max_dock_y_size = int(self._dock_constraint_y*float(cli_size.y))
5929                 if cli_size <= wx.Size(20, 20):
5930                     max_dock_x_size = 10000
5931                     max_dock_y_size = 10000
5932
5933                 if dock.IsHorizontal():
5934                     size = min(size, max_dock_y_size)
5935                 else:
5936                     size = min(size, max_dock_x_size)
5937
5938                 # absolute minimum size for a dock is 10 pixels
5939                 if size < 10:
5940                     size = 10
5941
5942                 dock.size = size
5943
5944             # determine the dock's minimum size
5945             plus_border = False
5946             plus_caption = False
5947             plus_caption_left = False
5948             dock_min_size = 0
5949             for pane in dock.panes:
5950                 if pane.min_size != wx.Size(-1, -1):
5951                     if pane.HasBorder():
5952                         plus_border = True
5953                     if pane.HasCaption():
5954                         plus_caption = True
5955                     if pane.HasCaptionLeft():
5956                         plus_caption_left = True
5957                     if dock.IsHorizontal():
5958                         if pane.min_size.y > dock_min_size:
5959                             dock_min_size = pane.min_size.y
5960                     else:
5961                         if pane.min_size.x > dock_min_size:
5962                             dock_min_size = pane.min_size.x
5963                     
5964             if plus_border:
5965                 dock_min_size += pane_border_size*2
5966             if plus_caption and dock.IsHorizontal():
5967                 dock_min_size += caption_size
5968             if plus_caption_left and dock.IsVertical():
5969                 dock_min_size += caption_size
5970                
5971             dock.min_size = dock_min_size
5972             
5973             # if the pane's current size is less than it's
5974             # minimum, increase the dock's size to it's minimum
5975             if dock.size < dock.min_size:
5976                 dock.size = dock.min_size
5977
5978             # determine the dock's mode (fixed or proportional)
5979             # determine whether the dock has only toolbars
5980             action_pane_marked = False
5981             dock.fixed = True
5982             dock.toolbar = True
5983             for pane in dock.panes:
5984                 if not pane.IsFixed():
5985                     dock.fixed = False
5986                 if not pane.IsToolbar():
5987                     dock.toolbar = False
5988                 if pane.HasFlag(AuiPaneInfo.optionDockFixed):
5989                     dock.fixed = True
5990                 if pane.HasFlag(AuiPaneInfo.actionPane):
5991                     action_pane_marked = True
5992
5993             # if the dock mode is proportional and not fixed-pixel,
5994             # reassign the dock_pos to the sequential 0, 1, 2, 3
5995             # e.g. remove gaps like 1, 2, 30, 500
5996             if not dock.fixed:
5997                 for jj in xrange(dock_pane_count):
5998                     pane = dock.panes[jj]
5999                     pane.dock_pos = jj
6000                 
6001             # if the dock mode is fixed, and none of the panes
6002             # are being moved right now, make sure the panes
6003             # do not overlap each other.  If they do, we will
6004             # adjust the panes' positions
6005             if dock.fixed and not action_pane_marked:
6006                 pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock)
6007                 offset = 0
6008                 for jj in xrange(dock_pane_count):
6009                     pane = dock.panes[jj]
6010                     pane.dock_pos = pane_positions[jj]
6011                     amount = pane.dock_pos - offset
6012                     if amount >= 0:
6013                         offset += amount
6014                     else:
6015                         pane.dock_pos += -amount
6016
6017                     offset += pane_sizes[jj]
6018                     dock.panes[jj] = pane
6019
6020             if oncheck:
6021                 self._docks[ii] = dock                    
6022
6023         # shrink docks if needed 
6024 ##        docks = self.SmartShrink(docks, AUI_DOCK_TOP)
6025 ##        docks = self.SmartShrink(docks, AUI_DOCK_LEFT)
6026
6027         if oncheck:
6028             self._docks = docks
6029             
6030         # discover the maximum dock layer
6031         max_layer = 0
6032         dock_count = len(docks)
6033         
6034         for ii in xrange(dock_count):
6035             max_layer = max(max_layer, docks[ii].dock_layer)
6036
6037         # clear out uiparts
6038         uiparts = []
6039
6040         # create a bunch of box sizers,
6041         # from the innermost level outwards.
6042         cont = None
6043         middle = None
6044
6045         if oncheck:
6046             docks = self._docks
6047         
6048         for layer in xrange(max_layer+1):
6049             # find any docks in this layer
6050             arr = FindDocks(docks, -1, layer, -1)
6051             # if there aren't any, skip to the next layer
6052             if not arr:
6053                 continue
6054
6055             old_cont = cont
6056
6057             # create a container which will hold this layer's
6058             # docks (top, bottom, left, right)
6059             cont = wx.BoxSizer(wx.VERTICAL)
6060
6061             # find any top docks in this layer
6062             arr = FindDocks(docks, AUI_DOCK_TOP, layer, -1)
6063             for row in arr:
6064                 uiparts = self.LayoutAddDock(cont, row, uiparts, spacer_only)
6065             
6066             # fill out the middle layer (which consists
6067             # of left docks, content area and right docks)
6068             
6069             middle = wx.BoxSizer(wx.HORIZONTAL)
6070
6071             # find any left docks in this layer
6072             arr = FindDocks(docks, AUI_DOCK_LEFT, layer, -1)
6073             for row in arr:
6074                 uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only)
6075             
6076             # add content dock (or previous layer's sizer
6077             # to the middle
6078             if not old_cont:
6079                 # find any center docks
6080                 arr = FindDocks(docks, AUI_DOCK_CENTER, -1, -1)
6081                 if arr:
6082                     for row in arr:
6083                        uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only)
6084                        
6085                 elif not self._has_maximized:
6086                     # there are no center docks, add a background area
6087                     sizer_item = middle.Add((1, 1), 1, wx.EXPAND)
6088                     part = AuiDockUIPart()
6089                     part.type = AuiDockUIPart.typeBackground
6090                     part.pane = None
6091                     part.dock = None
6092                     part.button = None
6093                     part.cont_sizer = middle
6094                     part.sizer_item = sizer_item
6095                     uiparts.append(part)
6096             else:
6097                 middle.Add(old_cont, 1, wx.EXPAND)
6098             
6099             # find any right docks in this layer
6100             arr = FindDocks(docks, AUI_DOCK_RIGHT, layer, -1, reverse=True)
6101             for row in arr:
6102                 uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only)
6103                     
6104             if len(middle.GetChildren()) > 0:
6105                 cont.Add(middle, 1, wx.EXPAND)
6106
6107             # find any bottom docks in this layer
6108             arr = FindDocks(docks, AUI_DOCK_BOTTOM, layer, -1, reverse=True)
6109             for row in arr:
6110                     uiparts = self.LayoutAddDock(cont, row, uiparts, spacer_only)
6111
6112         if not cont:
6113             # no sizer available, because there are no docks,
6114             # therefore we will create a simple background area
6115             cont = wx.BoxSizer(wx.VERTICAL)
6116             sizer_item = cont.Add((1, 1), 1, wx.EXPAND)
6117             part = AuiDockUIPart()
6118             part.type = AuiDockUIPart.typeBackground
6119             part.pane = None
6120             part.dock = None
6121             part.button = None
6122             part.cont_sizer = middle
6123             part.sizer_item = sizer_item
6124             uiparts.append(part)
6125
6126         if oncheck:
6127             self._uiparts = uiparts
6128             self._docks = docks
6129
6130         container.Add(cont, 1, wx.EXPAND)
6131
6132         if oncheck:
6133             return container
6134         else:
6135             return container, panes, docks, uiparts
6136
6137
6138     def SetDockSizeConstraint(self, width_pct, height_pct):
6139         """
6140         When a user creates a new dock by dragging a window into a docked position,
6141         often times the large size of the window will create a dock that is unwieldly
6142         large.
6143
6144         L{AuiManager} by default limits the size of any new dock to 1/3 of the window
6145         size. For horizontal docks, this would be 1/3 of the window height. For vertical
6146         docks, 1/3 of the width. Calling this function will adjust this constraint value.
6147
6148         The numbers must be between 0.0 and 1.0. For instance, calling L{SetDockSizeConstraint}
6149         with (0.5, 0.5) will cause new docks to be limited to half of the size of the entire
6150         managed window.
6151
6152         :param `width_pct`: a float number representing the x dock size constraint;
6153         :param `width_pct`: a float number representing the y dock size constraint.
6154         """
6155
6156         self._dock_constraint_x = max(0.0, min(1.0, width_pct))
6157         self._dock_constraint_y = max(0.0, min(1.0, height_pct))
6158
6159
6160     def GetDockSizeConstraint(self):
6161         """
6162         Returns the current dock constraint values.
6163
6164         :see: L{SetDockSizeConstraint}
6165         """
6166
6167         return self._dock_constraint_x, self._dock_constraint_y
6168
6169
6170     def Update(self):
6171         """
6172         This method is called after any number of changes are made to any of the
6173         managed panes. L{Update} must be invoked after L{AddPane} or L{InsertPane} are
6174         called in order to "realize" or "commit" the changes.
6175
6176         In addition, any number of changes may be made to L{AuiPaneInfo} structures
6177         (retrieved with L{GetPane}), but to realize the changes, L{Update}
6178         must be called. This construction allows pane flicker to be avoided by updating
6179         the whole layout at one time.
6180         """
6181
6182         self._hover_button = None
6183         self._action_part = None
6184         
6185         # destroy floating panes which have been
6186         # redocked or are becoming non-floating
6187         for p in self._panes:
6188             if p.IsFloating() or not p.frame:
6189                 continue
6190             
6191             # because the pane is no longer in a floating, we need to
6192             # reparent it to self._frame and destroy the floating frame
6193             # reduce flicker
6194             p.window.SetSize((1, 1))
6195
6196             # the following block is a workaround for bug #1531361
6197             # (see wxWidgets sourceforge page).  On wxGTK (only), when
6198             # a frame is shown/hidden, a move event unfortunately
6199             # also gets fired.  Because we may be dragging around
6200             # a pane, we need to cancel that action here to prevent
6201             # a spurious crash.
6202             if self._action_window == p.frame:
6203                 if self._frame.HasCapture():
6204                     self._frame.ReleaseMouse()
6205                 self._action = actionNone
6206                 self._action_window = None
6207
6208             # hide the frame
6209             if p.frame.IsShown():
6210                 p.frame.Show(False)
6211
6212             if self._action_window == p.frame:
6213                 self._action_window = None
6214         
6215             # reparent to self._frame and destroy the pane
6216             p.window.Reparent(self._frame)
6217             if isinstance(p.window, auibar.AuiToolBar):
6218                 p.window.SetAuiManager(self)
6219
6220             if p.frame:
6221                 p.frame.SetSizer(None)
6222                 p.frame.Destroy()
6223             p.frame = None
6224
6225         # Only the master manager should create/destroy notebooks...
6226         if not self._masterManager:
6227             self.UpdateNotebook()
6228         
6229         # delete old sizer first
6230         self._frame.SetSizer(None)
6231
6232         # create a layout for all of the panes
6233         sizer = self.LayoutAll(self._panes, self._docks, self._uiparts, False)
6234
6235         # hide or show panes as necessary,
6236         # and float panes as necessary
6237         
6238         pane_count = len(self._panes)
6239         
6240         for ii in xrange(pane_count):
6241             p = self._panes[ii]
6242             pFrame = p.frame
6243
6244             if p.IsFloating():
6245                 if pFrame is None:
6246                     # we need to create a frame for this
6247                     # pane, which has recently been floated
6248                     frame = self.CreateFloatingFrame(self._frame, p)
6249
6250                     # on MSW and Mac, if the owner desires transparent dragging, and
6251                     # the dragging is happening right now, then the floating
6252                     # window should have this style by default
6253                     if self._action in [actionDragFloatingPane, actionDragToolbarPane] and \
6254                        self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
6255                         frame.SetTransparent(150)
6256
6257                     if p.IsToolbar():
6258                         bar = p.window
6259                         if isinstance(bar, auibar.AuiToolBar):
6260                             bar.SetGripperVisible(False)
6261                             agwStyle = bar.GetAGWWindowStyleFlag()
6262                             bar.SetAGWWindowStyleFlag(agwStyle & ~AUI_TB_VERTICAL)
6263                             bar.Realize()
6264
6265                         s = p.window.GetMinSize()
6266                         p.BestSize(s)
6267                         p.FloatingSize(wx.DefaultSize)
6268
6269                     frame.SetPaneWindow(p)
6270                     p.needsTransparency = True
6271                     p.frame = pFrame = frame
6272                     if p.IsShown() and not frame.IsShown():
6273                         frame.Show()
6274                         frame.Update()
6275                 else:
6276
6277                     # frame already exists, make sure it's position
6278                     # and size reflect the information in AuiPaneInfo
6279                     if pFrame.GetPosition() != p.floating_pos or pFrame.GetSize() != p.floating_size:
6280                         pFrame.SetDimensions(p.floating_pos.x, p.floating_pos.y,
6281                                              p.floating_size.x, p.floating_size.y, wx.SIZE_USE_EXISTING)
6282
6283                     # update whether the pane is resizable or not
6284                     style = p.frame.GetWindowStyleFlag()
6285                     if p.IsFixed():
6286                         style &= ~wx.RESIZE_BORDER
6287                     else:
6288                         style |= wx.RESIZE_BORDER
6289
6290                     p.frame.SetWindowStyleFlag(style)
6291
6292                     if pFrame.IsShown() != p.IsShown():
6293                         p.needsTransparency = True
6294                         pFrame.Show(p.IsShown())
6295
6296                 if pFrame.GetTitle() != p.caption:
6297                     pFrame.SetTitle(p.caption)
6298                 if p.icon.IsOk():
6299                     pFrame.SetIcon(wx.IconFromBitmap(p.icon))
6300                     
6301             else:
6302
6303                 if p.IsToolbar():
6304 #                    self.SwitchToolBarOrientation(p)
6305                     p.best_size = p.window.GetBestSize()
6306
6307                 if p.window and not p.IsNotebookPage() and p.window.IsShown() != p.IsShown():
6308                     p.window.Show(p.IsShown())
6309
6310             if pFrame and p.needsTransparency:
6311                 if pFrame.IsShown() and pFrame._transparent != p.transparent:
6312                     pFrame.SetTransparent(p.transparent)
6313                     pFrame._transparent = p.transparent
6314                     
6315                 p.needsTransparency = False
6316
6317             # if "active panes" are no longer allowed, clear
6318             # any optionActive values from the pane states
6319             if self._agwFlags & AUI_MGR_ALLOW_ACTIVE_PANE == 0:
6320                 p.state &= ~AuiPaneInfo.optionActive
6321
6322             self._panes[ii] = p
6323
6324         old_pane_rects = []
6325         pane_count = len(self._panes)
6326         
6327         for p in self._panes:
6328             r = wx.Rect()
6329             if p.window and p.IsShown() and p.IsDocked():
6330                 r = p.rect
6331
6332             old_pane_rects.append(r)    
6333             
6334         # apply the new sizer
6335         self._frame.SetSizer(sizer)
6336         self._frame.SetAutoLayout(False)
6337         self.DoFrameLayout()
6338         
6339         # now that the frame layout is done, we need to check
6340         # the new pane rectangles against the old rectangles that
6341         # we saved a few lines above here.  If the rectangles have
6342         # changed, the corresponding panes must also be updated
6343         for ii in xrange(pane_count):
6344             p = self._panes[ii]
6345             if p.window and p.IsShown() and p.IsDocked():
6346                 if p.rect != old_pane_rects[ii]:
6347                     p.window.Refresh()
6348                     p.window.Update()
6349
6350         if wx.Platform == "__WXMAC__":
6351             self._frame.Refresh()
6352         else:
6353             self.Repaint()
6354
6355         if not self._masterManager:
6356             e = self.FireEvent(wxEVT_AUI_PERSPECTIVE_CHANGED, None, canVeto=False)    
6357
6358
6359     def UpdateNotebook(self):
6360         """ Updates the automatic L{AuiNotebook} in the layout (if any exists). """
6361
6362         # Workout how many notebooks we need.
6363         max_notebook = -1
6364
6365         # destroy floating panes which have been
6366         # redocked or are becoming non-floating
6367         for paneInfo in self._panes:
6368             if max_notebook < paneInfo.notebook_id:
6369                 max_notebook = paneInfo.notebook_id
6370         
6371         # We are the master of our domain
6372         extra_notebook = len(self._notebooks)
6373         max_notebook += 1
6374         
6375         for i in xrange(extra_notebook, max_notebook):
6376             self.CreateNotebook()
6377
6378         # Remove pages from notebooks that no-longer belong there ...
6379         for nb, notebook in enumerate(self._notebooks):
6380             pages = notebook.GetPageCount()
6381             pageCounter, allPages = 0, pages
6382
6383             # Check each tab ...
6384             for page in xrange(pages):
6385
6386                 if page >= allPages:
6387                     break
6388                 
6389                 window = notebook.GetPage(pageCounter)
6390                 paneInfo = self.GetPane(window)
6391                 if paneInfo.IsOk() and paneInfo.notebook_id != nb:
6392                     notebook.RemovePage(pageCounter)
6393                     window.Hide()
6394                     window.Reparent(self._frame)
6395                     pageCounter -= 1
6396                     allPages -= 1
6397
6398                 pageCounter += 1
6399
6400             notebook.DoSizing()
6401
6402         # Add notebook pages that aren't there already...
6403         for paneInfo in self._panes:
6404             if paneInfo.IsNotebookPage():
6405             
6406                 title = (paneInfo.caption == "" and [paneInfo.name] or [paneInfo.caption])[0]
6407
6408                 notebook = self._notebooks[paneInfo.notebook_id]
6409                 page_id = notebook.GetPageIndex(paneInfo.window)
6410
6411                 if page_id < 0:
6412                 
6413                     paneInfo.window.Reparent(notebook)
6414                     notebook.AddPage(paneInfo.window, title, True, paneInfo.icon)
6415                 
6416                 # Update title and icon ...
6417                 else:
6418                 
6419                     notebook.SetPageText(page_id, title)
6420                     notebook.SetPageBitmap(page_id, paneInfo.icon)
6421
6422                 notebook.DoSizing()
6423                 
6424             # Wire-up newly created notebooks
6425             elif paneInfo.IsNotebookControl() and not paneInfo.window:
6426                 paneInfo.window = self._notebooks[paneInfo.notebook_id]
6427             
6428         # Delete empty notebooks, and convert notebooks with 1 page to
6429         # normal panes...
6430         remap_ids = [-1]*len(self._notebooks)
6431         nb_idx = 0
6432
6433         for nb, notebook in enumerate(self._notebooks): 
6434             if notebook.GetPageCount() == 1:
6435             
6436                 # Convert notebook page to pane...
6437                 window = notebook.GetPage(0)
6438                 child_pane = self.GetPane(window)
6439                 notebook_pane = self.GetPane(notebook)
6440                 if child_pane.IsOk() and notebook_pane.IsOk():
6441                 
6442                     child_pane.SetDockPos(notebook_pane)
6443                     child_pane.window.Hide()
6444                     child_pane.window.Reparent(self._frame)
6445                     child_pane.frame = None
6446                     child_pane.notebook_id = -1
6447                     if notebook_pane.IsFloating():
6448                         child_pane.Float()
6449
6450                     self.DetachPane(notebook)
6451
6452                     notebook.RemovePage(0)
6453                     notebook.Destroy()
6454                 
6455                 else:
6456                 
6457                     raise Exception("Odd notebook docking")
6458                 
6459             elif notebook.GetPageCount() == 0:
6460             
6461                 self.DetachPane(notebook)
6462                 notebook.Destroy()
6463             
6464             else:
6465             
6466                 # Correct page ordering. The original wxPython code
6467                 # for this did not work properly, and would misplace 
6468                 # windows causing errors.
6469                 notebook.Freeze()
6470                 self._notebooks[nb_idx] = notebook
6471                 pages = notebook.GetPageCount()
6472                 selected = notebook.GetPage(notebook.GetSelection())
6473
6474                 # Take each page out of the notebook, group it with
6475                 # its current pane, and sort the list by pane.dock_pos
6476                 # order
6477                 pages_and_panes = []
6478                 for idx in reversed(range(pages)):
6479                     page = notebook.GetPage(idx)
6480                     pane = self.GetPane(page)
6481                     pages_and_panes.append((page, pane))
6482                     notebook.RemovePage(idx)
6483                 sorted_pnp = sorted(pages_and_panes, key=lambda tup: tup[1].dock_pos)
6484
6485                 # Grab the attributes from the panes which are ordered
6486                 # correctly, and copy those attributes to the original
6487                 # panes. (This avoids having to change the ordering
6488                 # of self._panes) Then, add the page back into the notebook
6489                 sorted_attributes = [self.GetAttributes(tup[1])
6490                                      for tup in sorted_pnp]
6491                 for attrs, tup in zip(sorted_attributes, pages_and_panes):
6492                     pane = tup[1]
6493                     self.SetAttributes(pane, attrs)
6494                     notebook.AddPage(pane.window, pane.caption)
6495
6496                 notebook.SetSelection(notebook.GetPageIndex(selected), True)
6497                 notebook.DoSizing()
6498                 notebook.Thaw()
6499
6500                 # It's a keeper.
6501                 remap_ids[nb] = nb_idx
6502                 nb_idx += 1
6503
6504         # Apply remap...
6505         nb_count = len(self._notebooks)
6506         
6507         if nb_count != nb_idx:
6508         
6509             self._notebooks = self._notebooks[0:nb_idx]
6510             for p in self._panes:
6511                 if p.notebook_id >= 0:                
6512                     p.notebook_id = remap_ids[p.notebook_id]
6513                     if p.IsNotebookControl():
6514                         p.SetNameFromNotebookId()
6515                 
6516         # Make sure buttons are correct ...
6517         for notebook in self._notebooks:
6518             want_max = True
6519             want_min = True
6520             want_close = True
6521
6522             pages = notebook.GetPageCount()
6523             for page in xrange(pages):
6524             
6525                 win = notebook.GetPage(page)
6526                 pane = self.GetPane(win)
6527                 if pane.IsOk():
6528                 
6529                     if not pane.HasCloseButton():
6530                         want_close = False
6531                     if not pane.HasMaximizeButton():
6532                         want_max = False
6533                     if not pane.HasMinimizeButton():
6534                         want_min = False
6535                 
6536             notebook_pane = self.GetPane(notebook)
6537             if notebook_pane.IsOk():
6538                 if notebook_pane.HasMinimizeButton() != want_min:
6539                     if want_min:
6540                         button = AuiPaneButton(AUI_BUTTON_MINIMIZE)
6541                         notebook_pane.state |= AuiPaneInfo.buttonMinimize
6542                         notebook_pane.buttons.append(button)
6543
6544                     # todo: remove min/max
6545             
6546                 if notebook_pane.HasMaximizeButton() != want_max:
6547                     if want_max:
6548                         button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE)
6549                         notebook_pane.state |= AuiPaneInfo.buttonMaximize
6550                         notebook_pane.buttons.append(button)
6551                     
6552                     # todo: remove min/max
6553                 
6554                 if notebook_pane.HasCloseButton() != want_close:
6555                     if want_close:
6556                         button = AuiPaneButton(AUI_BUTTON_CLOSE)
6557                         notebook_pane.state |= AuiPaneInfo.buttonClose
6558                         notebook_pane.buttons.append(button)
6559                     
6560                     # todo: remove close
6561
6562
6563     def SmartShrink(self, docks, direction):
6564         """
6565         Used to intelligently shrink the docks' size (if needed).
6566
6567         :param `docks`: a list of L{AuiDockInfo} instances;
6568         :param `direction`: the direction in which to shrink.
6569         """
6570
6571         sashSize = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
6572         caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
6573         clientSize = self._frame.GetClientSize()
6574         ourDocks = FindDocks(docks, direction, -1, -1)
6575         oppositeDocks = FindOppositeDocks(docks, direction)
6576         oppositeSize = self.GetOppositeDockTotalSize(docks, direction)
6577         ourSize = 0
6578
6579         for dock in ourDocks:
6580             ourSize += dock.size
6581
6582             if not dock.toolbar:
6583                 ourSize += sashSize
6584         
6585         shrinkSize = ourSize + oppositeSize
6586
6587         if direction == AUI_DOCK_TOP or direction == AUI_DOCK_BOTTOM:
6588             shrinkSize -= clientSize.y
6589         else:
6590             shrinkSize -= clientSize.x
6591
6592         if shrinkSize <= 0:
6593             return docks
6594
6595         # Combine arrays
6596         for dock in oppositeDocks:
6597             ourDocks.append(dock)
6598             
6599         oppositeDocks = []
6600
6601         for dock in ourDocks:
6602             if dock.toolbar or not dock.resizable:
6603                 continue
6604
6605             dockRange = dock.size - dock.min_size
6606
6607             if dock.min_size == 0:
6608                 dockRange -= sashSize
6609                 if direction == AUI_DOCK_TOP or direction == AUI_DOCK_BOTTOM:
6610                     dockRange -= caption_size
6611             
6612             if dockRange >= shrinkSize:
6613             
6614                 dock.size -= shrinkSize
6615                 return docks
6616             
6617             else:
6618             
6619                 dock.size -= dockRange
6620                 shrinkSize -= dockRange
6621             
6622         return docks
6623     
6624
6625     def UpdateDockingGuides(self, paneInfo):
6626         """
6627         Updates the docking guide windows positions and appearance.
6628
6629         :param `paneInfo`: a L{AuiPaneInfo} instance.
6630         """
6631
6632         if len(self._guides) == 0:
6633             self.CreateGuideWindows()
6634
6635         captionSize = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
6636         frameRect = GetInternalFrameRect(self._frame, self._docks)
6637         mousePos = wx.GetMousePosition()
6638
6639         for indx, guide in enumerate(self._guides):
6640         
6641             pt = wx.Point()
6642             guide_size = guide.host.GetSize()
6643             if not guide.host:
6644                 raise Exception("Invalid docking host")
6645
6646             direction = guide.dock_direction
6647
6648             if direction == AUI_DOCK_LEFT:
6649                 pt.x = frameRect.x + guide_size.x / 2 + 16
6650                 pt.y = frameRect.y + frameRect.height / 2
6651
6652             elif direction == AUI_DOCK_TOP:
6653                 pt.x = frameRect.x + frameRect.width / 2
6654                 pt.y = frameRect.y + guide_size.y / 2 + 16
6655
6656             elif direction == AUI_DOCK_RIGHT:
6657                 pt.x = frameRect.x + frameRect.width - guide_size.x / 2 - 16
6658                 pt.y = frameRect.y + frameRect.height / 2
6659
6660             elif direction == AUI_DOCK_BOTTOM:
6661                 pt.x = frameRect.x + frameRect.width / 2
6662                 pt.y = frameRect.y + frameRect.height - guide_size.y / 2 - 16
6663
6664             elif direction == AUI_DOCK_CENTER:
6665                 rc = paneInfo.window.GetScreenRect()
6666                 pt.x = rc.x + rc.width / 2
6667                 pt.y = rc.y + rc.height / 2
6668                 if paneInfo.HasCaption():
6669                     pt.y -= captionSize / 2
6670                 elif paneInfo.HasCaptionLeft():
6671                     pt.x -= captionSize / 2
6672
6673             # guide will be centered around point 'pt'
6674             targetPosition = wx.Point(pt.x - guide_size.x / 2, pt.y - guide_size.y / 2)
6675
6676             if guide.host.GetPosition() != targetPosition:
6677                 guide.host.Move(targetPosition)
6678                 
6679             guide.host.AeroMove(targetPosition)
6680
6681             if guide.dock_direction == AUI_DOCK_CENTER:
6682                 guide.host.ValidateNotebookDocking(paneInfo.IsNotebookDockable())
6683
6684             guide.host.UpdateDockGuide(mousePos)
6685         
6686         paneInfo.window.Lower()
6687
6688                         
6689     def DoFrameLayout(self):
6690         """
6691         This is an internal function which invokes `wx.Sizer.Layout`
6692         on the frame's main sizer, then measures all the various UI items
6693         and updates their internal rectangles.
6694
6695         :note: This should always be called instead of calling
6696          `self._managed_window.Layout()` directly.
6697         """
6698
6699         self._frame.Layout()
6700         
6701         for part in self._uiparts:            
6702             # get the rectangle of the UI part
6703             # originally, this code looked like this:
6704             #    part.rect = wx.Rect(part.sizer_item.GetPosition(),
6705             #                       part.sizer_item.GetSize())
6706             # this worked quite well, with one exception: the mdi
6707             # client window had a "deferred" size variable 
6708             # that returned the wrong size.  It looks like
6709             # a bug in wx, because the former size of the window
6710             # was being returned.  So, we will retrieve the part's
6711             # rectangle via other means
6712
6713             part.rect = part.sizer_item.GetRect()
6714             flag = part.sizer_item.GetFlag()
6715             border = part.sizer_item.GetBorder()
6716             
6717             if flag & wx.TOP:
6718                 part.rect.y -= border
6719                 part.rect.height += border
6720             if flag & wx.LEFT:
6721                 part.rect.x -= border
6722                 part.rect.width += border
6723             if flag & wx.BOTTOM:
6724                 part.rect.height += border
6725             if flag & wx.RIGHT:
6726                 part.rect.width += border
6727
6728             if part.type == AuiDockUIPart.typeDock:
6729                 part.dock.rect = part.rect
6730             if part.type == AuiDockUIPart.typePane:
6731                 part.pane.rect = part.rect
6732
6733
6734     def GetPanePart(self, wnd):
6735         """
6736         Looks up the pane border UI part of the
6737         pane specified. This allows the caller to get the exact rectangle
6738         of the pane in question, including decorations like caption and border.
6739
6740         :param `wnd`: the window to which the pane border belongs to.        
6741         """
6742
6743         for part in self._uiparts:
6744             if part.type == AuiDockUIPart.typePaneBorder and \
6745                part.pane and part.pane.window == wnd:
6746                 return part
6747
6748         for part in self._uiparts:
6749             if part.type == AuiDockUIPart.typePane and \
6750                part.pane and part.pane.window == wnd:
6751                 return part
6752     
6753         return None
6754
6755
6756     def GetDockPixelOffset(self, test):
6757         """
6758         This is an internal function which returns
6759         a dock's offset in pixels from the left side of the window
6760         (for horizontal docks) or from the top of the window (for
6761         vertical docks).
6762
6763         This value is necessary for calculating fixed-pane/toolbar offsets
6764         when they are dragged.
6765
6766         :param `test`: a fake L{AuiPaneInfo} for testing purposes.
6767         """
6768
6769         # the only way to accurately calculate the dock's
6770         # offset is to actually run a theoretical layout
6771         docks, panes = CopyDocksAndPanes2(self._docks, self._panes)
6772         panes.append(test)
6773
6774         sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False)
6775         client_size = self._frame.GetClientSize()
6776         sizer.SetDimension(0, 0, client_size.x, client_size.y)
6777         sizer.Layout()
6778
6779         for part in uiparts:
6780             pos = part.sizer_item.GetPosition()
6781             size = part.sizer_item.GetSize()
6782             part.rect = wx.RectPS(pos, size)
6783             if part.type == AuiDockUIPart.typeDock:
6784                 part.dock.rect = part.rect
6785
6786         sizer.Destroy()
6787
6788         for dock in docks:
6789             if test.dock_direction == dock.dock_direction and \
6790                test.dock_layer == dock.dock_layer and  \
6791                test.dock_row == dock.dock_row:
6792             
6793                 if dock.IsVertical():
6794                     return dock.rect.y
6795                 else:
6796                     return dock.rect.x
6797             
6798         return 0
6799     
6800
6801     def GetPartnerDock(self, dock):
6802         """
6803         Returns the partner dock for the input dock.
6804
6805         :param `dock`: a L{AuiDockInfo} instance.
6806         """
6807
6808         for layer in xrange(dock.dock_layer, -1, -1):
6809         
6810             bestDock = None
6811
6812             for tmpDock in self._docks:
6813             
6814                 if tmpDock.dock_layer != layer:
6815                     continue
6816                 
6817                 if tmpDock.dock_direction != dock.dock_direction:
6818                     continue
6819
6820                 if tmpDock.dock_layer < dock.dock_layer:
6821                 
6822                     if not bestDock or tmpDock.dock_row < bestDock.dock_row:
6823                         bestDock = tmpDock
6824                 
6825                 elif tmpDock.dock_row > dock.dock_row:
6826                 
6827                     if not bestDock or tmpDock.dock_row > bestDock.dock_row:
6828                         bestDock = tmpDock
6829                 
6830             if bestDock:
6831                 return bestDock
6832         
6833         return None
6834
6835
6836     def GetPartnerPane(self, dock, pane):
6837         """
6838         Returns the partner pane for the input pane. They both need to live
6839         in the same L{AuiDockInfo}.
6840
6841         :param `dock`: a L{AuiDockInfo} instance;
6842         :param `pane`: a L{AuiPaneInfo} class.
6843         """
6844         
6845         panePosition = -1
6846
6847         for i, tmpPane in enumerate(dock.panes):        
6848             if tmpPane.window == pane.window:
6849                 panePosition = i
6850             elif not tmpPane.IsFixed() and panePosition != -1:
6851                 return tmpPane
6852         
6853         return None
6854
6855
6856     def GetTotalPixSizeAndProportion(self, dock):
6857         """
6858         Returns the dimensions and proportion of the input dock.
6859
6860         :param `dock`: the L{AuiDockInfo} structure to analyze.
6861         """
6862
6863         totalPixsize = 0
6864         totalProportion = 0
6865
6866         # determine the total proportion of all resizable panes,
6867         # and the total size of the dock minus the size of all
6868         # the fixed panes
6869         for tmpPane in dock.panes:
6870         
6871             if tmpPane.IsFixed():
6872                 continue
6873
6874             totalProportion += tmpPane.dock_proportion
6875
6876             if dock.IsHorizontal():
6877                 totalPixsize += tmpPane.rect.width
6878             else:
6879                 totalPixsize += tmpPane.rect.height
6880
6881 ##            if tmpPane.min_size.IsFullySpecified():
6882 ##            
6883 ##                if dock.IsHorizontal():
6884 ##                    totalPixsize -= tmpPane.min_size.x
6885 ##                else:
6886 ##                    totalPixsize -= tmpPane.min_size.y
6887             
6888         return totalPixsize, totalProportion
6889
6890
6891     def GetOppositeDockTotalSize(self, docks, direction):
6892         """
6893         Returns the dimensions of the dock which lives opposite of the input dock.
6894
6895         :param `docks`: a list of L{AuiDockInfo} structures to analyze;
6896         :param `direction`: the direction in which to look for the opposite dock.
6897         """
6898         
6899         sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
6900         caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
6901         pane_border_size = self._art.GetMetric(AUI_DOCKART_PANE_BORDER_SIZE)
6902         minSizeMax = 0
6903         result = sash_size
6904         vertical = False
6905
6906         if direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]:
6907             vertical = True
6908
6909         # Get minimum size of the most inner area
6910         for tmpDock in docks:
6911         
6912             if tmpDock.dock_layer != 0:
6913                 continue
6914
6915             if tmpDock.dock_direction != AUI_DOCK_CENTER and tmpDock.IsVertical() != vertical:
6916                 continue
6917
6918             for tmpPane in tmpDock.panes:
6919             
6920                 minSize = pane_border_size*2 - sash_size
6921
6922                 if vertical:
6923                     minSize += tmpPane.min_size.y + caption_size
6924                 else:
6925                     minSize += tmpPane.min_size.x
6926
6927                 if minSize > minSizeMax:
6928                     minSizeMax = minSize
6929             
6930         result += minSizeMax
6931
6932         # Get opposite docks
6933         oppositeDocks = FindOppositeDocks(docks, direction)
6934
6935         # Sum size of the opposite docks and their sashes
6936         for dock in oppositeDocks:
6937             result += dock.size
6938             # if it's not a toolbar add the sash_size too
6939             if not dock.toolbar:
6940                 result += sash_size
6941         
6942         return result
6943
6944
6945     def CalculateDockSizerLimits(self, dock):
6946         """
6947         Calculates the minimum and maximum sizes allowed for the input dock.
6948
6949         :param `dock`: the L{AuiDockInfo} structure to analyze.
6950         """
6951
6952         docks, panes = CopyDocksAndPanes2(self._docks, self._panes)
6953
6954         sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
6955         caption_size = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
6956         opposite_size = self.GetOppositeDockTotalSize(docks, dock.dock_direction)
6957
6958         for tmpDock in docks:
6959         
6960             if tmpDock.dock_direction == dock.dock_direction and \
6961                tmpDock.dock_layer == dock.dock_layer and \
6962                tmpDock.dock_row == dock.dock_row:
6963         
6964                 tmpDock.size = 1
6965                 break
6966         
6967         sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False)
6968         client_size = self._frame.GetClientSize()
6969         sizer.SetDimension(0, 0, client_size.x, client_size.y)
6970         sizer.Layout()
6971
6972         for part in uiparts:
6973         
6974             part.rect = wx.RectPS(part.sizer_item.GetPosition(), part.sizer_item.GetSize())
6975             if part.type == AuiDockUIPart.typeDock:
6976                 part.dock.rect = part.rect
6977         
6978         sizer.Destroy()
6979         new_dock = None
6980
6981         for tmpDock in docks:
6982             if tmpDock.dock_direction == dock.dock_direction and \
6983                tmpDock.dock_layer == dock.dock_layer and \
6984                tmpDock.dock_row == dock.dock_row:
6985             
6986                 new_dock = tmpDock
6987                 break
6988             
6989         partnerDock = self.GetPartnerDock(dock)
6990
6991         if partnerDock:
6992             partnerRange = partnerDock.size - partnerDock.min_size
6993             if partnerDock.min_size == 0:
6994                 partnerRange -= sash_size
6995                 if dock.IsHorizontal():
6996                     partnerRange -= caption_size
6997             
6998             direction = dock.dock_direction
6999             
7000             if direction == AUI_DOCK_LEFT:
7001                 minPix = new_dock.rect.x + new_dock.rect.width
7002                 maxPix = dock.rect.x + dock.rect.width
7003                 maxPix += partnerRange
7004
7005             elif direction == AUI_DOCK_TOP:
7006                 minPix = new_dock.rect.y + new_dock.rect.height
7007                 maxPix = dock.rect.y + dock.rect.height
7008                 maxPix += partnerRange
7009
7010             elif direction == AUI_DOCK_RIGHT:
7011                 minPix = dock.rect.x - partnerRange - sash_size
7012                 maxPix = new_dock.rect.x - sash_size
7013
7014             elif direction == AUI_DOCK_BOTTOM:
7015                 minPix = dock.rect.y - partnerRange - sash_size
7016                 maxPix = new_dock.rect.y - sash_size
7017
7018             return minPix, maxPix
7019         
7020         direction = new_dock.dock_direction
7021         
7022         if direction == AUI_DOCK_LEFT:
7023             minPix = new_dock.rect.x + new_dock.rect.width
7024             maxPix = client_size.x - opposite_size - sash_size
7025
7026         elif direction == AUI_DOCK_TOP:
7027             minPix = new_dock.rect.y + new_dock.rect.height
7028             maxPix = client_size.y - opposite_size - sash_size
7029
7030         elif direction == AUI_DOCK_RIGHT:
7031             minPix = opposite_size
7032             maxPix = new_dock.rect.x - sash_size
7033
7034         elif direction == AUI_DOCK_BOTTOM:
7035             minPix = opposite_size
7036             maxPix = new_dock.rect.y - sash_size
7037
7038         return minPix, maxPix
7039
7040
7041     def CalculatePaneSizerLimits(self, dock, pane):
7042         """
7043         Calculates the minimum and maximum sizes allowed for the input pane.
7044
7045         :param `dock`: the L{AuiDockInfo} structure to which `pane` belongs to;
7046         :param `pane`: a L{AuiPaneInfo} class for which calculation are requested.
7047         """
7048         
7049         if pane.IsFixed():
7050             if dock.IsHorizontal():
7051                 minPix = maxPix = pane.rect.x + 1 + pane.rect.width
7052             else:
7053                 minPix = maxPix = pane.rect.y + 1 + pane.rect.height
7054
7055             return minPix, maxPix
7056         
7057         totalPixsize, totalProportion = self.GetTotalPixSizeAndProportion(dock)
7058         partnerPane = self.GetPartnerPane(dock, pane)
7059
7060         if dock.IsHorizontal():
7061         
7062             minPix = pane.rect.x + 1
7063             maxPix = pane.rect.x + 1 + pane.rect.width
7064
7065             if pane.min_size.IsFullySpecified():
7066                 minPix += pane.min_size.x
7067             else:
7068                 minPix += 1
7069
7070             if partnerPane:
7071                 maxPix += partnerPane.rect.width
7072
7073                 if partnerPane.min_size.IsFullySpecified():
7074                     maxPix -= partnerPane.min_size.x - 1
7075             
7076             else:
7077                 minPix = maxPix
7078         
7079         else:
7080         
7081             minPix = pane.rect.y + 1
7082             maxPix = pane.rect.y + 1 + pane.rect.height
7083
7084             if pane.min_size.IsFullySpecified():
7085                 minPix += pane.min_size.y
7086             else:
7087                 minPix += 1
7088
7089             if partnerPane:            
7090                 maxPix += partnerPane.rect.height
7091
7092                 if partnerPane.min_size.IsFullySpecified():
7093                     maxPix -= partnerPane.min_size.y - 1
7094             
7095             else:            
7096                 minPix = maxPix
7097             
7098         return minPix, maxPix
7099
7100
7101     def CheckMovableSizer(self, part):
7102         """
7103         Checks if a UI part can be actually resized.
7104
7105         :param `part`: a UI part.
7106         """
7107
7108         # a dock may not be resized if it has a single
7109         # pane which is not resizable
7110         if part.type == AuiDockUIPart.typeDockSizer and part.dock and \
7111            len(part.dock.panes) == 1 and part.dock.panes[0].IsFixed():
7112         
7113             return False
7114         
7115         if part.pane:
7116         
7117             # panes that may not be resized should be ignored here
7118             minPix, maxPix = self.CalculatePaneSizerLimits(part.dock, part.pane)
7119
7120             if minPix == maxPix:
7121                 return False
7122         
7123         return True
7124
7125
7126     def PaneFromTabEvent(self, event):
7127         """
7128         Returns a L{AuiPaneInfo} from a L{AuiNotebookEvent} event.
7129
7130         :param `event`: a L{AuiNotebookEvent} event.
7131         """
7132
7133         obj = event.GetEventObject()
7134
7135         if obj and isinstance(obj, auibook.AuiTabCtrl):
7136         
7137             page_idx = obj.GetActivePage()
7138
7139             if page_idx >= 0:
7140                 page = obj.GetPage(page_idx)
7141                 window = page.window
7142                 if window:
7143                     return self.GetPane(window)
7144             
7145         elif obj and isinstance(obj, auibook.AuiNotebook):
7146         
7147             page_idx = event.GetSelection()
7148             
7149             if page_idx >= 0:
7150                 window = obj.GetPage(page_idx)
7151                 if window:
7152                     return self.GetPane(window)
7153             
7154         return NonePaneInfo
7155
7156
7157     def OnTabBeginDrag(self, event):
7158         """
7159         Handles the ``EVT_AUINOTEBOOK_BEGIN_DRAG`` event.
7160
7161         :param `event`: a L{AuiNotebookEvent} event to be processed.
7162         """
7163
7164         if self._masterManager:
7165             self._masterManager.OnTabBeginDrag(event)
7166         
7167         else:
7168             paneInfo = self.PaneFromTabEvent(event)
7169             
7170             if paneInfo.IsOk():
7171             
7172                 # It's one of ours!
7173                 self._action = actionDragFloatingPane
7174                 mouse = wx.GetMousePosition()
7175
7176                 # set initial float position - may have to think about this
7177                 # offset a bit more later ...
7178                 self._action_offset = wx.Point(20, 10)
7179                 self._toolbar_action_offset = wx.Point(20, 10)
7180                 
7181                 paneInfo.floating_pos = mouse - self._action_offset
7182                 paneInfo.dock_pos = AUI_DOCK_NONE
7183                 paneInfo.notebook_id = -1
7184
7185                 tab = event.GetEventObject()
7186
7187                 if tab.HasCapture():
7188                     tab.ReleaseMouse()
7189
7190                 # float the window
7191                 if paneInfo.IsMaximized():
7192                     self.RestorePane(paneInfo)
7193                 paneInfo.Float()
7194                 self.Update()
7195
7196                 self._action_window = paneInfo.window
7197                     
7198                 self._frame.CaptureMouse()
7199                 event.SetDispatched(True)
7200             
7201             else:
7202             
7203                 # not our window
7204                 event.Skip()
7205             
7206
7207     def OnTabPageClose(self, event):
7208         """
7209         Handles the ``EVT_AUINOTEBOOK_PAGE_CLOSE`` event.
7210
7211         :param `event`: a L{AuiNotebookEvent} event to be processed.
7212         """
7213
7214         if self._masterManager:
7215             self._masterManager.OnTabPageClose(event)
7216         
7217         else:
7218         
7219             p = self.PaneFromTabEvent(event)
7220             if p.IsOk():
7221             
7222                 # veto it because we will call "RemovePage" ourselves
7223                 event.Veto()
7224
7225                 # Now ask the app if they really want to close...
7226                 # fire pane close event
7227                 e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE)
7228                 e.SetPane(p)
7229                 e.SetCanVeto(True)
7230                 self.ProcessMgrEvent(e)
7231
7232                 if e.GetVeto():
7233                     return
7234
7235                 self.ClosePane(p)
7236                 self.Update()
7237             else:
7238                 event.Skip()
7239             
7240
7241     def OnTabSelected(self, event):
7242         """
7243         Handles the ``EVT_AUINOTEBOOK_PAGE_CHANGED`` event.
7244
7245         :param `event`: a L{AuiNotebookEvent} event to be processed.
7246         """
7247         
7248         if self._masterManager:
7249             self._masterManager.OnTabSelected(event)
7250             return
7251         
7252         obj = event.GetEventObject()
7253
7254         if obj and isinstance(obj, auibook.AuiNotebook):
7255         
7256             notebook = obj
7257             page = notebook.GetPage(event.GetSelection())
7258             paneInfo = self.GetPane(page)
7259
7260             if paneInfo.IsOk():
7261                 notebookRoot = GetNotebookRoot(self._panes, paneInfo.notebook_id)
7262                 if notebookRoot:
7263                 
7264                     notebookRoot.Caption(paneInfo.caption)
7265                     self.RefreshCaptions()
7266                 
7267         event.Skip()
7268
7269
7270     def GetNotebooks(self):
7271         """ Returns all the automatic L{AuiNotebook} in the L{AuiManager}. """
7272
7273         if self._masterManager:
7274             return self._masterManager.GetNotebooks()
7275         
7276         return self._notebooks
7277
7278
7279     def SetMasterManager(self, manager):
7280         """
7281         Sets the master manager for an automatic L{AuiNotebook}.
7282
7283         :param `manager`: an instance of L{AuiManager}.
7284         """
7285
7286         self._masterManager = manager
7287
7288         
7289     def ProcessDockResult(self, target, new_pos):
7290         """
7291         This is a utility function used by L{DoDrop} - it checks
7292         if a dock operation is allowed, the new dock position is copied into
7293         the target info. If the operation was allowed, the function returns ``True``.
7294
7295         :param `target`: the L{AuiPaneInfo} instance to be docked;
7296         :param `new_pos`: the new docking position if the docking operation is allowed.
7297         """
7298
7299         allowed = False
7300         direction = new_pos.dock_direction
7301         
7302         if direction == AUI_DOCK_TOP:
7303             allowed = target.IsTopDockable()
7304         elif direction == AUI_DOCK_BOTTOM:
7305             allowed = target.IsBottomDockable()
7306         elif direction == AUI_DOCK_LEFT:
7307             allowed = target.IsLeftDockable()
7308         elif direction == AUI_DOCK_RIGHT:
7309             allowed = target.IsRightDockable()
7310
7311         if allowed:
7312             target = new_pos
7313
7314             if target.IsToolbar():
7315                 self.SwitchToolBarOrientation(target)
7316
7317         return allowed, target
7318
7319
7320     def SwitchToolBarOrientation(self, pane):
7321         """
7322         Switches the toolbar orientation from vertical to horizontal and vice-versa.
7323         This is especially useful for vertical docked toolbars once they float.
7324
7325         :param `pane`: an instance of L{AuiPaneInfo}, which may have a L{AuiToolBar}
7326          window associated with it.
7327         """
7328
7329         if not isinstance(pane.window, auibar.AuiToolBar):
7330             return pane
7331         
7332         if pane.IsFloating():
7333             return pane
7334
7335         toolBar = pane.window
7336         direction = pane.dock_direction
7337         vertical = direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT]
7338
7339         agwStyle = toolBar.GetAGWWindowStyleFlag()
7340         new_agwStyle = agwStyle
7341
7342         if vertical:
7343             new_agwStyle |= AUI_TB_VERTICAL
7344         else:
7345             new_agwStyle &= ~(AUI_TB_VERTICAL)
7346
7347         if agwStyle != new_agwStyle:
7348             toolBar.SetAGWWindowStyleFlag(new_agwStyle)
7349         if not toolBar.GetGripperVisible():
7350             toolBar.SetGripperVisible(True)
7351
7352         s = pane.window.GetMinSize()
7353         pane.BestSize(s)
7354
7355         if new_agwStyle != agwStyle:
7356             toolBar.Realize()
7357         
7358         return pane
7359
7360
7361     def DoDrop(self, docks, panes, target, pt, offset=wx.Point(0, 0)):
7362         """
7363         This is an important function. It basically takes a mouse position,
7364         and determines where the panes new position would be. If the pane is to be
7365         dropped, it performs the drop operation using the specified dock and pane
7366         arrays. By specifying copy dock and pane arrays when calling, a "what-if"
7367         scenario can be performed, giving precise coordinates for drop hints.
7368
7369         :param `docks`: a list of L{AuiDockInfo} classes;
7370         :param `panes`: a list of L{AuiPaneInfo} instances;
7371         :param `pt`: a mouse position to check for a drop operation;
7372         :param `offset`: a possible offset from the input point `pt`.
7373         """
7374
7375         if target.IsToolbar():
7376             return self.DoDropToolbar(docks, panes, target, pt, offset)
7377         elif target.IsFloating():
7378             return self.DoDropFloatingPane(docks, panes, target, pt)
7379         else:
7380             return self.DoDropNonFloatingPane(docks, panes, target, pt)
7381     
7382
7383     def CopyTarget(self, target):
7384         """
7385         Copies all the attributes of the input `target` into another L{AuiPaneInfo}.
7386
7387         :param `target`: the source L{AuiPaneInfo} from where to copy attributes.
7388         """
7389
7390         drop = AuiPaneInfo()
7391         drop.name = target.name
7392         drop.caption = target.caption
7393         drop.window = target.window
7394         drop.frame = target.frame
7395         drop.state = target.state
7396         drop.dock_direction = target.dock_direction
7397         drop.dock_layer = target.dock_layer
7398         drop.dock_row = target.dock_row
7399         drop.dock_pos = target.dock_pos
7400         drop.best_size = wx.Size(*target.best_size)
7401         drop.min_size = wx.Size(*target.min_size)
7402         drop.max_size = wx.Size(*target.max_size)
7403         drop.floating_pos = wx.Point(*target.floating_pos)
7404         drop.floating_size = wx.Size(*target.floating_size)
7405         drop.dock_proportion = target.dock_proportion
7406         drop.buttons = target.buttons
7407         drop.rect = wx.Rect(*target.rect)
7408         drop.icon = target.icon
7409         drop.notebook_id = target.notebook_id
7410         drop.transparent = target.transparent
7411         drop.snapped = target.snapped
7412         drop.minimize_mode = target.minimize_mode
7413
7414         return drop        
7415
7416
7417     def DoDropToolbar(self, docks, panes, target, pt, offset):
7418         """
7419         Handles the situation in which the dropped pane contains a toolbar.
7420
7421         :param `docks`: a list of L{AuiDockInfo} classes;
7422         :param `panes`: a list of L{AuiPaneInfo} instances;
7423         :param `target`: the target pane containing the toolbar;
7424         :param `pt`: a mouse position to check for a drop operation;
7425         :param `offset`: a possible offset from the input point `pt`.        
7426         """
7427         
7428         drop = self.CopyTarget(target)
7429
7430         # The result should always be shown
7431         drop.Show()
7432
7433         # Check to see if the toolbar has been dragged out of the window
7434         if CheckOutOfWindow(self._frame, pt):
7435             if self._agwFlags & AUI_MGR_ALLOW_FLOATING and drop.IsFloatable():
7436                 drop.Float()
7437
7438             return self.ProcessDockResult(target, drop)
7439
7440         # Allow directional change when the cursor leaves this rect
7441         safeRect = wx.Rect(*target.rect)
7442         if target.IsHorizontal():
7443             safeRect.Inflate(100, 50)
7444         else:
7445             safeRect.Inflate(50, 100)
7446         
7447         # Check to see if the toolbar has been dragged to edge of the frame
7448         dropDir = CheckEdgeDrop(self._frame, docks, pt)
7449
7450         if dropDir != -1:
7451         
7452             if dropDir == wx.LEFT:
7453                 drop.Dock().Left().Layer(auiToolBarLayer).Row(0). \
7454                     Position(pt.y - self.GetDockPixelOffset(drop) - offset.y)
7455
7456             elif dropDir == wx.RIGHT:
7457                 drop.Dock().Right().Layer(auiToolBarLayer).Row(0). \
7458                     Position(pt.y - self.GetDockPixelOffset(drop) - offset.y)
7459
7460             elif dropDir == wx.TOP:
7461                 drop.Dock().Top().Layer(auiToolBarLayer).Row(0). \
7462                     Position(pt.x - self.GetDockPixelOffset(drop) - offset.x)
7463
7464             elif dropDir == wx.BOTTOM:
7465                 drop.Dock().Bottom().Layer(auiToolBarLayer).Row(0). \
7466                     Position(pt.x - self.GetDockPixelOffset(drop) - offset.x)
7467
7468             if not target.IsFloating() and safeRect.Contains(pt) and \
7469                target.dock_direction != drop.dock_direction:
7470                 return False, target
7471         
7472             return self.ProcessDockResult(target, drop)
7473     
7474         # If the windows is floating and out of the client area, do nothing
7475         if drop.IsFloating() and not self._frame.GetClientRect().Contains(pt):
7476             return False, target
7477     
7478         # Ok, can't drop on edge - check internals ...
7479
7480         clientSize = self._frame.GetClientSize()
7481         x = Clip(pt.x, 0, clientSize.x - 1)
7482         y = Clip(pt.y, 0, clientSize.y - 1)
7483         part = self.HitTest(x, y)
7484
7485         if not part or not part.dock:
7486             return False, target
7487         
7488         dock = part.dock
7489         
7490         # toolbars may only be moved in and to fixed-pane docks,
7491         # otherwise we will try to float the pane.  Also, the pane
7492         # should float if being dragged over center pane windows
7493         if not dock.fixed or dock.dock_direction == AUI_DOCK_CENTER:
7494         
7495             if (self._agwFlags & AUI_MGR_ALLOW_FLOATING and drop.IsFloatable()) or \
7496                dock.dock_direction not in [AUI_DOCK_CENTER, AUI_DOCK_NONE]:
7497                 if drop.IsFloatable():
7498                     drop.Float()
7499             
7500             return self.ProcessDockResult(target, drop)
7501         
7502         # calculate the offset from where the dock begins
7503         # to the point where the user dropped the pane
7504         dockDropOffset = 0
7505         if dock.IsHorizontal():
7506             dockDropOffset = pt.x - dock.rect.x - offset.x
7507         else:
7508             dockDropOffset = pt.y - dock.rect.y - offset.y
7509         
7510         drop.Dock().Direction(dock.dock_direction).Layer(dock.dock_layer). \
7511             Row(dock.dock_row).Position(dockDropOffset)
7512
7513         if (pt.y <= dock.rect.GetTop() + 2 and dock.IsHorizontal()) or \
7514            (pt.x <= dock.rect.GetLeft() + 2 and dock.IsVertical()):
7515         
7516             if dock.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_LEFT]:
7517                 row = drop.dock_row
7518                 panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row)
7519                 drop.dock_row = row
7520             
7521             else:
7522                 panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row+1)
7523                 drop.dock_row = dock.dock_row + 1
7524             
7525         if (pt.y >= dock.rect.GetBottom() - 2 and dock.IsHorizontal()) or \
7526            (pt.x >= dock.rect.GetRight() - 2 and dock.IsVertical()):
7527         
7528             if dock.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_LEFT]:
7529                 panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row+1)
7530                 drop.dock_row = dock.dock_row+1
7531             
7532             else:
7533                 row = drop.dock_row
7534                 panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row)
7535                 drop.dock_row = row
7536
7537         if not target.IsFloating() and safeRect.Contains(pt) and \
7538            target.dock_direction != drop.dock_direction:
7539             return False, target
7540     
7541         return self.ProcessDockResult(target, drop)
7542
7543
7544     def DoDropFloatingPane(self, docks, panes, target, pt):
7545         """
7546         Handles the situation in which the dropped pane contains a normal window.
7547
7548         :param `docks`: a list of L{AuiDockInfo} classes;
7549         :param `panes`: a list of L{AuiPaneInfo} instances;
7550         :param `target`: the target pane containing the window;
7551         :param `pt`: a mouse position to check for a drop operation.
7552         """
7553         
7554         screenPt = self._frame.ClientToScreen(pt)
7555         paneInfo = self.PaneHitTest(panes, pt)
7556
7557         if paneInfo.IsMaximized():
7558             return False, target
7559
7560         if paneInfo.window is None:
7561             return False, target
7562
7563         # search the dock guides.
7564         # reverse order to handle the center first.
7565         for i in xrange(len(self._guides)-1, -1, -1):
7566             guide = self._guides[i]
7567
7568             # do hit testing on the guide
7569             dir = guide.host.HitTest(screenPt.x, screenPt.y)
7570
7571             if dir == -1:  # point was outside of the dock guide
7572                 continue
7573
7574             if dir == wx.ALL:   # target is a single dock guide
7575                 return self.DoDropLayer(docks, target, guide.dock_direction)
7576             
7577             elif dir == wx.CENTER:
7578
7579                 if not target.IsNotebookDockable():
7580                     continue
7581                 if not paneInfo.IsNotebookDockable() and not paneInfo.IsNotebookControl():
7582                     continue
7583
7584                 if not paneInfo.HasNotebook():
7585                 
7586                     # Add a new notebook pane with the original as a tab...
7587                     self.CreateNotebookBase(panes, paneInfo)
7588                 
7589                 # Add new item to notebook
7590                 target.NotebookPage(paneInfo.notebook_id)
7591             
7592             else:
7593             
7594                 drop_pane = False
7595                 drop_row = False
7596
7597                 insert_dir = paneInfo.dock_direction
7598                 insert_layer = paneInfo.dock_layer
7599                 insert_row = paneInfo.dock_row
7600                 insert_pos = paneInfo.dock_pos
7601
7602                 if insert_dir == AUI_DOCK_CENTER:
7603                 
7604                     insert_layer = 0
7605                     if dir == wx.LEFT:
7606                         insert_dir = AUI_DOCK_LEFT
7607                     elif dir == wx.UP:
7608                         insert_dir = AUI_DOCK_TOP
7609                     elif dir == wx.RIGHT:
7610                         insert_dir = AUI_DOCK_RIGHT
7611                     elif dir == wx.DOWN:
7612                         insert_dir = AUI_DOCK_BOTTOM
7613                 
7614                 if insert_dir == AUI_DOCK_LEFT:
7615                 
7616                     drop_pane = (dir == wx.UP   or dir == wx.DOWN)
7617                     drop_row  = (dir == wx.LEFT or dir == wx.RIGHT)
7618                     if dir == wx.RIGHT:
7619                         insert_row += 1
7620                     elif dir == wx.DOWN:
7621                         insert_pos += 1
7622                 
7623                 elif insert_dir == AUI_DOCK_RIGHT:
7624                 
7625                     drop_pane = (dir == wx.UP   or dir == wx.DOWN)
7626                     drop_row  = (dir == wx.LEFT or dir == wx.RIGHT)
7627                     if dir == wx.LEFT:
7628                         insert_row += 1
7629                     elif dir == wx.DOWN:
7630                         insert_pos += 1
7631                 
7632                 elif insert_dir == AUI_DOCK_TOP:
7633                 
7634                     drop_pane = (dir == wx.LEFT or dir == wx.RIGHT)
7635                     drop_row  = (dir == wx.UP   or dir == wx.DOWN)
7636                     if dir == wx.DOWN:
7637                         insert_row += 1
7638                     elif dir == wx.RIGHT:
7639                         insert_pos += 1
7640                 
7641                 elif insert_dir == AUI_DOCK_BOTTOM:
7642                 
7643                     drop_pane = (dir == wx.LEFT or dir == wx.RIGHT)
7644                     drop_row  = (dir == wx.UP   or dir == wx.DOWN)
7645                     if dir == wx.UP:
7646                         insert_row += 1
7647                     elif dir == wx.RIGHT:
7648                         insert_pos += 1
7649                 
7650                 if paneInfo.dock_direction == AUI_DOCK_CENTER:
7651                     insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1
7652
7653                 if drop_pane:
7654                     return self.DoDropPane(panes, target, insert_dir, insert_layer, insert_row, insert_pos)
7655
7656                 if drop_row:
7657                     return self.DoDropRow(panes, target, insert_dir, insert_layer, insert_row)
7658             
7659             return True, target
7660         
7661         return False, target
7662
7663
7664     def DoDropNonFloatingPane(self, docks, panes, target, pt):
7665         """
7666         Handles the situation in which the dropped pane is not floating.
7667
7668         :param `docks`: a list of L{AuiDockInfo} classes;
7669         :param `panes`: a list of L{AuiPaneInfo} instances;
7670         :param `target`: the target pane containing the toolbar;
7671         :param `pt`: a mouse position to check for a drop operation.
7672         """
7673         
7674         screenPt = self._frame.ClientToScreen(pt)
7675         clientSize = self._frame.GetClientSize()
7676         frameRect = GetInternalFrameRect(self._frame, self._docks)
7677
7678         drop = self.CopyTarget(target)
7679
7680         # The result should always be shown
7681         drop.Show()
7682
7683         part = self.HitTest(pt.x, pt.y)
7684
7685         if not part:
7686             return False, target
7687
7688         if part.type == AuiDockUIPart.typeDockSizer:
7689         
7690             if len(part.dock.panes) != 1:
7691                 return False, target
7692             
7693             part = self.GetPanePart(part.dock.panes[0].window)
7694             if not part:
7695                 return False, target
7696         
7697         if not part.pane:
7698             return False, target
7699
7700         part = self.GetPanePart(part.pane.window)
7701         if not part:
7702             return False, target
7703
7704         insert_dock_row = False
7705         insert_row = part.pane.dock_row
7706         insert_dir = part.pane.dock_direction
7707         insert_layer = part.pane.dock_layer
7708
7709         direction = part.pane.dock_direction
7710         
7711         if direction == AUI_DOCK_TOP:
7712             if pt.y >= part.rect.y and pt.y < part.rect.y+auiInsertRowPixels:
7713                 insert_dock_row = True
7714
7715         elif direction == AUI_DOCK_BOTTOM:
7716             if pt.y > part.rect.y+part.rect.height-auiInsertRowPixels and \
7717                pt.y <= part.rect.y + part.rect.height:
7718                 insert_dock_row = True
7719
7720         elif direction == AUI_DOCK_LEFT:
7721             if pt.x >= part.rect.x and pt.x < part.rect.x+auiInsertRowPixels:
7722                 insert_dock_row = True
7723
7724         elif direction == AUI_DOCK_RIGHT:
7725             if pt.x > part.rect.x+part.rect.width-auiInsertRowPixels and \
7726                pt.x <= part.rect.x+part.rect.width:
7727                 insert_dock_row = True
7728
7729         elif direction == AUI_DOCK_CENTER:
7730             
7731                 # "new row pixels" will be set to the default, but
7732                 # must never exceed 20% of the window size
7733                 new_row_pixels_x = auiNewRowPixels
7734                 new_row_pixels_y = auiNewRowPixels
7735
7736                 if new_row_pixels_x > (part.rect.width*20)/100:
7737                     new_row_pixels_x = (part.rect.width*20)/100
7738
7739                 if new_row_pixels_y > (part.rect.height*20)/100:
7740                     new_row_pixels_y = (part.rect.height*20)/100
7741
7742                 # determine if the mouse pointer is in a location that
7743                 # will cause a new row to be inserted.  The hot spot positions
7744                 # are along the borders of the center pane
7745
7746                 insert_layer = 0
7747                 insert_dock_row = True
7748                 pr = part.rect
7749                 
7750                 if pt.x >= pr.x and pt.x < pr.x + new_row_pixels_x:
7751                     insert_dir = AUI_DOCK_LEFT
7752                 elif pt.y >= pr.y and pt.y < pr.y + new_row_pixels_y:
7753                     insert_dir = AUI_DOCK_TOP
7754                 elif pt.x >= pr.x + pr.width - new_row_pixels_x and pt.x < pr.x + pr.width:
7755                     insert_dir = AUI_DOCK_RIGHT
7756                 elif pt.y >= pr.y+ pr.height - new_row_pixels_y and pt.y < pr.y + pr.height:
7757                     insert_dir = AUI_DOCK_BOTTOM
7758                 else:
7759                     return False, target
7760
7761                 insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1
7762             
7763         if insert_dock_row:
7764         
7765             panes = DoInsertDockRow(panes, insert_dir, insert_layer, insert_row)
7766             drop.Dock().Direction(insert_dir).Layer(insert_layer). \
7767                 Row(insert_row).Position(0)
7768                 
7769             return self.ProcessDockResult(target, drop)
7770
7771         # determine the mouse offset and the pane size, both in the
7772         # direction of the dock itself, and perpendicular to the dock
7773
7774         if part.orientation == wx.VERTICAL:
7775         
7776             offset = pt.y - part.rect.y
7777             size = part.rect.GetHeight()
7778         
7779         else:
7780         
7781             offset = pt.x - part.rect.x
7782             size = part.rect.GetWidth()
7783         
7784         drop_position = part.pane.dock_pos
7785
7786         # if we are in the top/left part of the pane,
7787         # insert the pane before the pane being hovered over
7788         if offset <= size/2:
7789         
7790             drop_position = part.pane.dock_pos
7791             panes = DoInsertPane(panes,
7792                                  part.pane.dock_direction,
7793                                  part.pane.dock_layer,
7794                                  part.pane.dock_row,
7795                                  part.pane.dock_pos)
7796
7797         # if we are in the bottom/right part of the pane,
7798         # insert the pane before the pane being hovered over
7799         if offset > size/2:
7800         
7801             drop_position = part.pane.dock_pos+1
7802             panes = DoInsertPane(panes,
7803                                  part.pane.dock_direction,
7804                                  part.pane.dock_layer,
7805                                  part.pane.dock_row,
7806                                  part.pane.dock_pos+1)
7807         
7808
7809         drop.Dock(). \
7810                      Direction(part.dock.dock_direction). \
7811                      Layer(part.dock.dock_layer).Row(part.dock.dock_row). \
7812                      Position(drop_position)
7813         
7814         return self.ProcessDockResult(target, drop)
7815
7816
7817     def DoDropLayer(self, docks, target, dock_direction):
7818         """
7819         Handles the situation in which `target` is a single dock guide.
7820
7821         :param `docks`: a list of L{AuiDockInfo} classes;
7822         :param `target`: the target pane;
7823         :param `dock_direction`: the docking direction.
7824         """
7825
7826         drop = self.CopyTarget(target)
7827         
7828         if dock_direction == AUI_DOCK_LEFT:
7829             drop.Dock().Left()
7830             drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_LEFT),
7831                                      GetMaxLayer(docks, AUI_DOCK_BOTTOM)),
7832                                  GetMaxLayer(docks, AUI_DOCK_TOP)) + 1
7833
7834         elif dock_direction == AUI_DOCK_TOP:
7835             drop.Dock().Top()
7836             drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_TOP),
7837                                      GetMaxLayer(docks, AUI_DOCK_LEFT)),
7838                                  GetMaxLayer(docks, AUI_DOCK_RIGHT)) + 1
7839
7840         elif dock_direction == AUI_DOCK_RIGHT:
7841             drop.Dock().Right()
7842             drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_RIGHT),
7843                                      GetMaxLayer(docks, AUI_DOCK_TOP)),
7844                                  GetMaxLayer(docks, AUI_DOCK_BOTTOM)) + 1
7845
7846         elif dock_direction == AUI_DOCK_BOTTOM:
7847             drop.Dock().Bottom()
7848             drop_new_layer = max(max(GetMaxLayer(docks, AUI_DOCK_BOTTOM),
7849                                      GetMaxLayer(docks, AUI_DOCK_LEFT)),
7850                                  GetMaxLayer(docks, AUI_DOCK_RIGHT)) + 1
7851
7852         else:
7853             return False, target
7854         
7855
7856         drop.Dock().Layer(drop_new_layer)
7857         return self.ProcessDockResult(target, drop)
7858
7859
7860     def DoDropPane(self, panes, target, dock_direction, dock_layer, dock_row, dock_pos):
7861         """
7862         Drop a pane in the interface.
7863
7864         :param `panes`: a list of L{AuiPaneInfo} classes;
7865         :param `target`: the target pane;
7866         :param `dock_direction`: the docking direction;
7867         :param `dock_layer`: the docking layer;
7868         :param `dock_row`: the docking row;
7869         :param `dock_pos`: the docking position.
7870         """
7871         
7872         drop = self.CopyTarget(target)
7873         panes = DoInsertPane(panes, dock_direction, dock_layer, dock_row, dock_pos)
7874
7875         drop.Dock().Direction(dock_direction).Layer(dock_layer).Row(dock_row).Position(dock_pos)
7876         return self.ProcessDockResult(target, drop)
7877
7878
7879     def DoDropRow(self, panes, target, dock_direction, dock_layer, dock_row):
7880         """
7881         Insert a row in the interface before dropping.
7882
7883         :param `panes`: a list of L{AuiPaneInfo} classes;
7884         :param `target`: the target pane;
7885         :param `dock_direction`: the docking direction;
7886         :param `dock_layer`: the docking layer;
7887         :param `dock_row`: the docking row.
7888         """
7889         
7890         drop = self.CopyTarget(target)
7891         panes = DoInsertDockRow(panes, dock_direction, dock_layer, dock_row)
7892
7893         drop.Dock().Direction(dock_direction).Layer(dock_layer).Row(dock_row).Position(0)
7894         return self.ProcessDockResult(target, drop)
7895
7896
7897     def ShowHint(self, rect):
7898         """
7899         Shows the AUI hint window.
7900
7901         :param `rect`: the hint rect calculated in advance.
7902         """
7903
7904         if rect == self._last_hint:
7905             return
7906
7907         if self._agwFlags & AUI_MGR_RECTANGLE_HINT and wx.Platform != "__WXMAC__":
7908
7909             if self._last_hint != rect:
7910                 # remove the last hint rectangle
7911                 self._last_hint = wx.Rect(*rect)
7912                 self._frame.Refresh()
7913                 self._frame.Update()
7914             
7915             screendc = wx.ScreenDC()
7916             clip = wx.Region(1, 1, 10000, 10000)
7917
7918             # clip all floating windows, so we don't draw over them
7919             for pane in self._panes:            
7920                 if pane.IsFloating() and pane.frame.IsShown():
7921                 
7922                     rect2 = wx.Rect(*pane.frame.GetRect())
7923                     if wx.Platform == "__WXGTK__":
7924                         # wxGTK returns the client size, not the whole frame size
7925                         rect2.width += 15
7926                         rect2.height += 35
7927                         rect2.Inflate(5, 5)
7928
7929                     clip.SubtractRect(rect2)
7930                 
7931             # As we can only hide the hint by redrawing the managed window, we
7932             # need to clip the region to the managed window too or we get
7933             # nasty redrawn problems.
7934             clip.IntersectRect(self._frame.GetRect())
7935             screendc.SetClippingRegionAsRegion(clip)
7936
7937             stipple = PaneCreateStippleBitmap()
7938             brush = wx.BrushFromBitmap(stipple)
7939             screendc.SetBrush(brush)
7940             screendc.SetPen(wx.TRANSPARENT_PEN)
7941             screendc.DrawRectangle(rect.x, rect.y, 5, rect.height)
7942             screendc.DrawRectangle(rect.x+5, rect.y, rect.width-10, 5)
7943             screendc.DrawRectangle(rect.x+rect.width-5, rect.y, 5, rect.height)
7944             screendc.DrawRectangle(rect.x+5, rect.y+rect.height-5, rect.width-10, 5)
7945             RefreshDockingGuides(self._guides)
7946
7947             return
7948             
7949         if not self._hint_window:
7950             self.CreateHintWindow()
7951
7952         if self._hint_window:
7953             self._hint_window.SetRect(rect)
7954             self._hint_window.Show()
7955
7956         self._hint_fadeamt = self._hint_fademax
7957
7958         if self._agwFlags & AUI_MGR_HINT_FADE:
7959             self._hint_fadeamt = 0
7960             self._hint_window.SetTransparent(self._hint_fadeamt)
7961
7962         if self._action == actionDragFloatingPane and self._action_window:
7963             self._action_window.SetFocus()
7964
7965         if self._hint_fadeamt != self._hint_fademax: #  Only fade if we need to
7966             # start fade in timer
7967             self._hint_fadetimer.Start(5)
7968
7969         self._last_hint = wx.Rect(*rect)
7970         
7971
7972     def HideHint(self):
7973         """ Hides a transparent window hint if there is one. """
7974
7975         # hides a transparent window hint if there is one
7976         if self._hint_window:
7977             self._hint_window.Hide()
7978
7979         self._hint_fadetimer.Stop()
7980         self._last_hint = wx.Rect()
7981         
7982
7983     def IsPaneButtonVisible(self, part):
7984         """
7985         Returns whether a pane button in the pane caption is visible.
7986
7987         :param `part`: the UI part to analyze.
7988         """
7989
7990         captionRect = wx.Rect()
7991
7992         for temp_part in self._uiparts:
7993             if temp_part.pane == part.pane and \
7994                temp_part.type == AuiDockUIPart.typeCaption:
7995                 captionRect = temp_part.rect
7996                 break
7997
7998         return captionRect.ContainsRect(part.rect)
7999
8000
8001     def DrawPaneButton(self, dc, part, pt):
8002         """
8003         Draws a pane button in the caption (convenience function).
8004
8005         :param `dc`: a `wx.DC` device context object;
8006         :param `part`: the UI part to analyze;
8007         :param `pt`: a `wx.Point` object, specifying the mouse location.
8008         """
8009
8010         if not self.IsPaneButtonVisible(part):
8011             return
8012
8013         state = AUI_BUTTON_STATE_NORMAL
8014
8015         if part.rect.Contains(pt):
8016
8017             if _VERSION_STRING < "2.9":
8018                 leftDown = wx.GetMouseState().LeftDown()
8019             else:
8020                 leftDown = wx.GetMouseState().LeftIsDown()
8021
8022             if leftDown:
8023                 state = AUI_BUTTON_STATE_PRESSED
8024             else:
8025                 state = AUI_BUTTON_STATE_HOVER
8026
8027         self._art.DrawPaneButton(dc, self._frame, part.button.button_id,
8028                                  state, part.rect, part.pane)
8029
8030     
8031     def RefreshButton(self, part):
8032         """
8033         Refreshes a pane button in the caption.
8034
8035         :param `part`: the UI part to analyze.
8036         """
8037         
8038         rect = wx.Rect(*part.rect)
8039         rect.Inflate(2, 2)
8040         self._frame.Refresh(True, rect)
8041         self._frame.Update()
8042
8043
8044     def RefreshCaptions(self):
8045         """ Refreshes all pane captions. """
8046
8047         for part in self._uiparts:
8048             if part.type == AuiDockUIPart.typeCaption:
8049                 self._frame.Refresh(True, part.rect)
8050                 self._frame.Update()
8051
8052
8053     def CalculateHintRect(self, pane_window, pt, offset):
8054         """
8055         Calculates the drop hint rectangle.
8056
8057         The method first calls L{DoDrop} to determine the exact position the pane would
8058         be at were if dropped. If the pane would indeed become docked at the
8059         specified drop point, the the rectangle hint will be returned in
8060         screen coordinates. Otherwise, an empty rectangle is returned.
8061
8062         :param `pane_window`: it is the window pointer of the pane being dragged;
8063         :param `pt`: is the mouse position, in client coordinates;
8064         :param `offset`: describes the offset that the mouse is from the upper-left
8065          corner of the item being dragged.
8066         """
8067         
8068         # we need to paint a hint rectangle to find out the exact hint rectangle,
8069         # we will create a new temporary layout and then measure the resulting
8070         # rectangle we will create a copy of the docking structures (self._docks)
8071         # so that we don't modify the real thing on screen
8072
8073         rect = wx.Rect()
8074         pane = self.GetPane(pane_window)
8075         
8076         attrs = self.GetAttributes(pane)
8077         hint = AuiPaneInfo()
8078         hint = self.SetAttributes(hint, attrs)
8079         
8080         if hint.name != "__HINT__":
8081             self._oldname = hint.name
8082             
8083         hint.name = "__HINT__"
8084         hint.PaneBorder(True)
8085         hint.Show()
8086
8087         if not hint.IsOk():
8088             hint.name = self._oldname
8089             return rect
8090
8091         docks, panes = CopyDocksAndPanes2(self._docks, self._panes)
8092
8093         # remove any pane already there which bears the same window
8094         # this happens when you are moving a pane around in a dock
8095         for ii in xrange(len(panes)):
8096             if panes[ii].window == pane_window:
8097                 docks = RemovePaneFromDocks(docks, panes[ii])
8098                 panes.pop(ii)
8099                 break
8100
8101         # find out where the new pane would be
8102         allow, hint = self.DoDrop(docks, panes, hint, pt, offset)
8103
8104         if not allow:
8105             return rect
8106         
8107         panes.append(hint)
8108
8109         sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False)
8110         
8111         client_size = self._frame.GetClientSize()
8112         sizer.SetDimension(0, 0, client_size.x, client_size.y)
8113         sizer.Layout()
8114
8115         sought = "__HINT__"
8116         
8117         # For a notebook page, actually look for the noteboot itself.
8118         if hint.IsNotebookPage():
8119             id = hint.notebook_id
8120             for pane in panes:
8121                 if pane.IsNotebookControl() and pane.notebook_id==id:
8122                     sought = pane.name
8123                     break
8124
8125         for part in uiparts:
8126             if part.pane and part.pane.name == sought:    
8127                 rect.Union(wx.RectPS(part.sizer_item.GetPosition(),
8128                                      part.sizer_item.GetSize()))
8129
8130         sizer.Destroy()
8131
8132         # check for floating frame ...
8133         if rect.IsEmpty():
8134             for p in panes:
8135                 if p.name == sought and p.IsFloating():
8136                     return wx.RectPS(p.floating_pos, p.floating_size)
8137     
8138         if rect.IsEmpty():
8139             return rect
8140
8141         # actually show the hint rectangle on the screen
8142         rect.x, rect.y = self._frame.ClientToScreen((rect.x, rect.y))
8143         if self._frame.GetLayoutDirection() == wx.Layout_RightToLeft:
8144             # Mirror rectangle in RTL mode
8145             rect.x -= rect.GetWidth()
8146
8147         return rect
8148
8149
8150     def DrawHintRect(self, pane_window, pt, offset):
8151         """
8152         Calculates the hint rectangle by calling
8153         L{CalculateHintRect}. If there is a rectangle, it shows it
8154         by calling L{ShowHint}, otherwise it hides any hint
8155         rectangle currently shown.
8156
8157         :param `pane_window`: it is the window pointer of the pane being dragged;
8158         :param `pt`: is the mouse position, in client coordinates;
8159         :param `offset`: describes the offset that the mouse is from the upper-left
8160          corner of the item being dragged.
8161         """
8162
8163         rect = self.CalculateHintRect(pane_window, pt, offset)
8164
8165         if rect.IsEmpty():
8166             self.HideHint()
8167             self._hint_rect = wx.Rect()
8168         else:
8169             self.ShowHint(rect)
8170             self._hint_rect = wx.Rect(*rect)
8171
8172
8173     def GetPartSizerRect(self, uiparts):
8174         """
8175         Returns the rectangle surrounding the specified UI parts.
8176
8177         :param `uiparts`: UI parts.
8178         """
8179
8180         rect = wx.Rect()
8181
8182         for part in self._uiparts:
8183             if part.pane and part.pane.name == "__HINT__":
8184                 rect.Union(wx.RectPS(part.sizer_item.GetPosition(),
8185                                      part.sizer_item.GetSize()))
8186
8187         return rect
8188
8189
8190     def GetAttributes(self, pane):
8191         """
8192         Returns all the attributes of a L{AuiPaneInfo}.
8193
8194         :param `pane`: a L{AuiPaneInfo} instance.
8195         """
8196
8197         attrs = []
8198         attrs.extend([pane.window, pane.frame, pane.state, pane.dock_direction,
8199                       pane.dock_layer, pane.dock_pos, pane.dock_row, pane.dock_proportion,
8200                       pane.floating_pos, pane.floating_size, pane.best_size,
8201                       pane.min_size, pane.max_size, pane.caption, pane.name,
8202                       pane.buttons, pane.rect, pane.icon, pane.notebook_id,
8203                       pane.transparent, pane.snapped, pane.minimize_mode])
8204
8205         return attrs
8206     
8207
8208     def SetAttributes(self, pane, attrs):
8209         """
8210         Sets all the attributes contained in `attrs` to a L{AuiPaneInfo}.
8211
8212         :param `pane`: a L{AuiPaneInfo} instance;
8213         :param `attrs`: a list of attributes.
8214         """
8215         
8216         pane.window = attrs[0]
8217         pane.frame = attrs[1]
8218         pane.state = attrs[2]
8219         pane.dock_direction = attrs[3]
8220         pane.dock_layer = attrs[4]
8221         pane.dock_pos = attrs[5]
8222         pane.dock_row = attrs[6]
8223         pane.dock_proportion = attrs[7]
8224         pane.floating_pos = attrs[8]
8225         pane.floating_size = attrs[9]
8226         pane.best_size = attrs[10]
8227         pane.min_size = attrs[11]
8228         pane.max_size = attrs[12]
8229         pane.caption = attrs[13]
8230         pane.name = attrs[14]
8231         pane.buttons = attrs[15]
8232         pane.rect = attrs[16]
8233         pane.icon = attrs[17]
8234         pane.notebook_id = attrs[18]
8235         pane.transparent = attrs[19]
8236         pane.snapped = attrs[20]
8237         pane.minimize_mode = attrs[21]
8238
8239         return pane
8240
8241      
8242     def OnFloatingPaneResized(self, wnd, size):
8243         """
8244         Handles the resizing of a floating pane.
8245
8246         :param `wnd`: a `wx.Window` derived window, managed by the pane;
8247         :param `size`: a `wx.Size` object, specifying the new pane floating size.
8248         """
8249
8250         # try to find the pane
8251         pane = self.GetPane(wnd)
8252         if not pane.IsOk():
8253             raise Exception("Pane window not found")
8254
8255         if pane.frame:
8256             indx = self._panes.index(pane)
8257             pane.floating_pos = pane.frame.GetPosition()
8258             pane.floating_size = size
8259             self._panes[indx] = pane
8260             if pane.IsSnappable():
8261                 self.SnapPane(pane, pane.floating_pos, pane.floating_size, True)
8262             
8263
8264     def OnFloatingPaneClosed(self, wnd, event):
8265         """
8266         Handles the close event of a floating pane.
8267
8268         :param `wnd`: a `wx.Window` derived window, managed by the pane;
8269         :param `event`: a `wx.CloseEvent` to be processed.
8270         """
8271         
8272         # try to find the pane
8273         pane = self.GetPane(wnd)
8274         if not pane.IsOk():
8275             raise Exception("Pane window not found")
8276
8277         # fire pane close event
8278         e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE)
8279         e.SetPane(pane)
8280         e.SetCanVeto(event.CanVeto())
8281         self.ProcessMgrEvent(e)
8282
8283         if e.GetVeto():
8284             event.Veto()
8285             return
8286         else:
8287             # close the pane, but check that it
8288             # still exists in our pane array first
8289             # (the event handler above might have removed it)
8290
8291             check = self.GetPane(wnd)
8292             if check.IsOk():
8293                 self.ClosePane(pane)
8294         
8295
8296     def OnFloatingPaneActivated(self, wnd):
8297         """
8298         Handles the activation event of a floating pane.
8299
8300         :param `wnd`: a `wx.Window` derived window, managed by the pane.
8301         """
8302         
8303         pane = self.GetPane(wnd)
8304         if not pane.IsOk():
8305             raise Exception("Pane window not found")
8306
8307         if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
8308             ret, self._panes = SetActivePane(self._panes, wnd)
8309             self.RefreshCaptions()
8310             self.FireEvent(wxEVT_AUI_PANE_ACTIVATED, wnd, canVeto=False)
8311
8312
8313     def OnFloatingPaneMoved(self, wnd, eventOrPt):
8314         """
8315         Handles the move event of a floating pane.
8316
8317         :param `wnd`: a `wx.Window` derived window, managed by the pane;
8318         :param `eventOrPt`: a `wx.MoveEvent` to be processed or an instance of `wx.Point`.
8319         """
8320         
8321         pane = self.GetPane(wnd)
8322         if not pane.IsOk():
8323             raise Exception("Pane window not found")
8324
8325         if not pane.IsSnappable():
8326             return
8327
8328         if isinstance(eventOrPt, wx.Point):
8329             pane_pos = wx.Point(*eventOrPt)
8330         else:
8331             pane_pos = eventOrPt.GetPosition()
8332
8333         pane_size = pane.floating_size
8334
8335         self.SnapPane(pane, pane_pos, pane_size, False)
8336
8337
8338     def SnapPane(self, pane, pane_pos, pane_size, toSnap=False):
8339         """
8340         Snaps a floating pane to one of the main frame sides.
8341
8342         :param `pane`: a L{AuiPaneInfo} instance;
8343         :param `pane_pos`: the new pane floating position;
8344         :param `pane_size`: the new pane floating size;
8345         :param `toSnap`: a bool variable to check if L{SnapPane} was called from
8346          a move event.
8347         """
8348
8349         if self._from_move:
8350             return
8351         
8352         managed_window = self.GetManagedWindow()
8353         wnd_pos = managed_window.GetPosition()
8354         wnd_size = managed_window.GetSize()
8355         snapX, snapY = self._snap_limits
8356
8357         if not toSnap:
8358             pane.snapped = 0
8359             if pane.IsLeftSnappable():
8360                 # Check if we can snap to the left
8361                 diff = wnd_pos.x - (pane_pos.x + pane_size.x)
8362                 if -snapX <= diff <= snapX:
8363                     pane.snapped = wx.LEFT
8364                     pane.floating_pos = wx.Point(wnd_pos.x-pane_size.x, pane_pos.y)
8365             elif pane.IsTopSnappable():
8366                 # Check if we can snap to the top
8367                 diff = wnd_pos.y - (pane_pos.y + pane_size.y)
8368                 if -snapY <= diff <= snapY:
8369                     pane.snapped = wx.TOP
8370                     pane.floating_pos = wx.Point(pane_pos.x, wnd_pos.y-pane_size.y)
8371             elif pane.IsRightSnappable():
8372                 # Check if we can snap to the right
8373                 diff = pane_pos.x - (wnd_pos.x + wnd_size.x)
8374                 if -snapX <= diff <= snapX:
8375                     pane.snapped = wx.RIGHT
8376                     pane.floating_pos = wx.Point(wnd_pos.x + wnd_size.x, pane_pos.y)
8377             elif pane.IsBottomSnappable():
8378                 # Check if we can snap to the bottom
8379                 diff = pane_pos.y - (wnd_pos.y + wnd_size.y)
8380                 if -snapY <= diff <= snapY:
8381                     pane.snapped = wx.BOTTOM
8382                     pane.floating_pos = wx.Point(pane_pos.x, wnd_pos.y + wnd_size.y)
8383
8384         self.RepositionPane(pane, wnd_pos, wnd_size)
8385
8386
8387     def RepositionPane(self, pane, wnd_pos, wnd_size):
8388         """
8389         Repositions a pane after the main frame has been moved/resized.
8390         
8391         :param `pane`: a L{AuiPaneInfo} instance;
8392         :param `wnd_pos`: the main frame position;
8393         :param `wnd_size`: the main frame size.
8394         """
8395
8396         pane_pos = pane.floating_pos
8397         pane_size = pane.floating_size
8398
8399         snap = pane.snapped
8400         if snap == wx.LEFT:
8401             floating_pos = wx.Point(wnd_pos.x - pane_size.x, pane_pos.y)
8402         elif snap == wx.TOP:
8403             floating_pos = wx.Point(pane_pos.x, wnd_pos.y - pane_size.y)
8404         elif snap == wx.RIGHT:
8405             floating_pos = wx.Point(wnd_pos.x + wnd_size.x, pane_pos.y)
8406         elif snap == wx.BOTTOM:
8407             floating_pos = wx.Point(pane_pos.x, wnd_pos.y + wnd_size.y)
8408
8409         if snap:
8410             if pane_pos != floating_pos:
8411                 pane.floating_pos = floating_pos
8412                 self._from_move = True
8413                 pane.frame.SetPosition(pane.floating_pos)
8414                 self._from_move = False
8415
8416             
8417     def OnGripperClicked(self, pane_window, start, offset):
8418         """
8419         Handles the mouse click on the pane gripper.
8420
8421         :param `pane_window`: a `wx.Window` derived window, managed by the pane;
8422         :param `start`: a `wx.Point` object, specifying the clicking position;
8423         :param `offset`: an offset point from the `start` position.
8424         """
8425
8426         # try to find the pane
8427         paneInfo = self.GetPane(pane_window)
8428
8429         if not paneInfo.IsOk():
8430             raise Exception("Pane window not found")
8431
8432         if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
8433             # set the caption as active
8434             ret, self._panes = SetActivePane(self._panes, pane_window)
8435             self.RefreshCaptions()
8436             self.FireEvent(wxEVT_AUI_PANE_ACTIVATED, pane_window, canVeto=False)
8437         
8438         self._action_part = None
8439         self._action_pane = paneInfo
8440         self._action_window = pane_window
8441         self._action_start = start
8442         self._action_offset = offset
8443         self._toolbar_action_offset = wx.Point(*self._action_offset)
8444         
8445         self._frame.CaptureMouse()
8446
8447         if paneInfo.IsDocked():
8448             self._action = actionClickCaption
8449         else:
8450             if paneInfo.IsToolbar():
8451                 self._action = actionDragToolbarPane
8452             else:
8453                 self._action = actionDragFloatingPane
8454
8455             if paneInfo.frame:
8456             
8457                 windowPt = paneInfo.frame.GetRect().GetTopLeft()
8458                 originPt = paneInfo.frame.ClientToScreen(wx.Point())
8459                 self._action_offset += originPt - windowPt
8460                 self._toolbar_action_offset = wx.Point(*self._action_offset)
8461
8462                 if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
8463                     paneInfo.frame.SetTransparent(150)
8464             
8465             if paneInfo.IsToolbar():
8466                 self._frame.SetCursor(wx.StockCursor(wx.CURSOR_SIZING))
8467         
8468
8469     def OnRender(self, event):        
8470         """
8471         Draws all of the pane captions, sashes,
8472         backgrounds, captions, grippers, pane borders and buttons.
8473         It renders the entire user interface. It binds the ``EVT_AUI_RENDER`` event.
8474
8475         :param `event`: an instance of L{AuiManagerEvent}.
8476         """
8477
8478         # if the frame is about to be deleted, don't bother
8479         if not self._frame or self._frame.IsBeingDeleted():
8480             return
8481         
8482         if not self._frame.GetSizer():
8483             return
8484
8485         mouse = wx.GetMouseState()
8486         mousePos = wx.Point(mouse.GetX(), mouse.GetY())
8487         point = self._frame.ScreenToClient(mousePos)
8488         art = self._art
8489
8490         dc = event.GetDC()
8491         
8492         for part in self._uiparts:
8493         
8494             # don't draw hidden pane items or items that aren't windows
8495             if part.sizer_item and ((not part.sizer_item.IsWindow() and \
8496                                      not part.sizer_item.IsSpacer() and \
8497                                      not part.sizer_item.IsSizer()) or \
8498                                     not part.sizer_item.IsShown()):
8499             
8500                 continue
8501             
8502             ptype = part.type
8503                     
8504             if ptype in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
8505                 art.DrawSash(dc, self._frame, part.orientation, part.rect)
8506
8507             elif ptype == AuiDockUIPart.typeBackground:
8508                 art.DrawBackground(dc, self._frame, part.orientation, part.rect)
8509
8510             elif ptype == AuiDockUIPart.typeCaption:
8511                 art.DrawCaption(dc, self._frame, part.pane.caption, part.rect, part.pane)
8512
8513             elif ptype == AuiDockUIPart.typeGripper:
8514                 art.DrawGripper(dc, self._frame, part.rect, part.pane)
8515
8516             elif ptype == AuiDockUIPart.typePaneBorder:
8517                 art.DrawBorder(dc, self._frame, part.rect, part.pane)
8518
8519             elif ptype == AuiDockUIPart.typePaneButton:                
8520                 self.DrawPaneButton(dc, part, point)
8521
8522
8523     def Repaint(self, dc=None):
8524         """
8525         Repaints the entire frame decorations (sashes, borders, buttons and so on).
8526         It renders the entire user interface.
8527
8528         :param `dc`: if not ``None``, an instance of `wx.PaintDC`.
8529         """
8530         
8531         w, h = self._frame.GetClientSize()
8532
8533         # Figure out which dc to use; if one
8534         # has been specified, use it, otherwise
8535         # make a client dc
8536         if dc is None:
8537             client_dc = wx.ClientDC(self._frame)
8538             dc = client_dc
8539
8540         # If the frame has a toolbar, the client area
8541         # origin will not be (0, 0).
8542         pt = self._frame.GetClientAreaOrigin()
8543         if pt.x != 0 or pt.y != 0:
8544             dc.SetDeviceOrigin(pt.x, pt.y)
8545
8546         # Render all the items
8547         self.Render(dc)
8548
8549                 
8550     def Render(self, dc):
8551         """
8552         Fires a render event, which is normally handled by
8553         L{OnRender}. This allows the render function to
8554         be overridden via the render event.
8555
8556         This can be useful for painting custom graphics in the main window.
8557         Default behavior can be invoked in the overridden function by calling
8558         L{OnRender}.
8559
8560         :param `dc`: a `wx.DC` device context object.        
8561         """
8562
8563         e = AuiManagerEvent(wxEVT_AUI_RENDER)
8564         e.SetManager(self)
8565         e.SetDC(dc)
8566         self.ProcessMgrEvent(e)
8567
8568
8569     def OnCaptionDoubleClicked(self, pane_window):
8570         """
8571         Handles the mouse double click on the pane caption.
8572
8573         :param `pane_window`: a `wx.Window` derived window, managed by the pane.
8574         """
8575
8576         # try to find the pane
8577         paneInfo = self.GetPane(pane_window)
8578         if not paneInfo.IsOk():
8579             raise Exception("Pane window not found")
8580
8581         if not paneInfo.IsFloatable() or not paneInfo.IsDockable() or \
8582            self._agwFlags & AUI_MGR_ALLOW_FLOATING == 0:
8583             return
8584
8585         indx = self._panes.index(paneInfo)
8586         win_rect = None
8587         
8588         if paneInfo.IsFloating():
8589             if paneInfo.name.startswith("__floating__"):
8590                 # It's a floating tab from a AuiNotebook
8591                 notebook = paneInfo.window.__aui_notebook__
8592                 notebook.ReDockPage(paneInfo)
8593                 self.Update()
8594                 return
8595             else:
8596
8597                 e = self.FireEvent(wxEVT_AUI_PANE_DOCKING, paneInfo, canVeto=True)
8598                 if e.GetVeto():
8599                     self.HideHint()
8600                     ShowDockingGuides(self._guides, False)
8601                     return
8602                 
8603                 win_rect = paneInfo.frame.GetRect()
8604                 paneInfo.Dock()
8605                 if paneInfo.IsToolbar():
8606                     paneInfo = self.SwitchToolBarOrientation(paneInfo)
8607
8608                 e = self.FireEvent(wxEVT_AUI_PANE_DOCKED, paneInfo, canVeto=False)
8609
8610         else:
8611
8612             e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, paneInfo, canVeto=True)
8613             if e.GetVeto():
8614                 return
8615
8616             # float the window
8617             if paneInfo.IsMaximized():
8618                 self.RestorePane(paneInfo)
8619             
8620             if paneInfo.floating_pos == wx.Point(-1, -1):
8621                 captionSize = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
8622                 paneInfo.floating_pos = pane_window.GetScreenPosition()
8623                 paneInfo.floating_pos.y -= captionSize
8624
8625             paneInfo.Float()
8626             e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, paneInfo, canVeto=False)
8627
8628         self._panes[indx] = paneInfo
8629         self.Update()
8630
8631         if win_rect and self._agwFlags & AUI_MGR_ANIMATE_FRAMES:
8632             paneInfo = self.GetPane(pane_window)
8633             pane_rect = paneInfo.window.GetScreenRect()
8634             self.AnimateDocking(win_rect, pane_rect)
8635
8636
8637     def OnPaint(self, event):
8638         """
8639         Handles the ``wx.EVT_PAINT`` event for L{AuiManager}.
8640
8641         :param `event`: an instance of `wx.PaintEvent` to be processed.
8642         """
8643         
8644         dc = wx.PaintDC(self._frame)
8645         self.Repaint(dc)
8646                 
8647
8648     def OnEraseBackground(self, event):
8649         """
8650         Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{AuiManager}.
8651
8652         :param `event`: `wx.EraseEvent` to be processed.
8653
8654         :note: This is intentionally empty (excluding wxMAC) to reduce
8655          flickering while drawing.
8656         """
8657         
8658         if wx.Platform == "__WXMAC__":
8659             event.Skip()
8660
8661
8662     def OnSize(self, event):
8663         """
8664         Handles the ``wx.EVT_SIZE`` event for L{AuiManager}.
8665
8666         :param `event`: a `wx.SizeEvent` to be processed.
8667         """
8668         
8669         skipped = False
8670         if isinstance(self._frame, AuiFloatingFrame) and self._frame.IsShownOnScreen():
8671             skipped = True
8672             event.Skip()
8673
8674         if self._frame:
8675                 
8676             self.DoFrameLayout()
8677             if wx.Platform == "__WXMAC__":
8678                 self._frame.Refresh()
8679             else:
8680                 self.Repaint()
8681             
8682             if isinstance(self._frame, wx.MDIParentFrame) or isinstance(self._frame, tabmdi.AuiMDIClientWindow) \
8683                or isinstance(self._frame, tabmdi.AuiMDIParentFrame):
8684                 # for MDI parent frames, this event must not
8685                 # be "skipped".  In other words, the parent frame
8686                 # must not be allowed to resize the client window
8687                 # after we are finished processing sizing changes
8688                 return
8689
8690         if not skipped:
8691             event.Skip()
8692
8693         # For the snap to screen...
8694         self.OnMove(None)
8695         
8696
8697     def OnFindManager(self, event):
8698         """
8699         Handles the ``EVT_AUI_FIND_MANAGER`` event for L{AuiManager}.
8700
8701         :param `event`: a L{AuiManagerEvent} event to be processed.
8702         """
8703         
8704         # Initialize to None
8705         event.SetManager(None)
8706         
8707         if not self._frame:
8708             return
8709         
8710         # See it this window wants to overwrite
8711         self._frame.ProcessEvent(event)
8712
8713         # if no, it must be us
8714         if not event.GetManager():
8715            event.SetManager(self)
8716        
8717
8718     def OnSetCursor(self, event):
8719         """
8720         Handles the ``wx.EVT_SET_CURSOR`` event for L{AuiManager}.
8721
8722         :param `event`: a `wx.SetCursorEvent` to be processed.
8723         """
8724         
8725         # determine cursor
8726         part = self.HitTest(event.GetX(), event.GetY())
8727         cursor = wx.NullCursor
8728
8729         if part:
8730             if part.type in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
8731
8732                 if not self.CheckMovableSizer(part):
8733                     return
8734                 
8735                 if part.orientation == wx.VERTICAL:
8736                     cursor = wx.StockCursor(wx.CURSOR_SIZEWE)
8737                 else:
8738                     cursor = wx.StockCursor(wx.CURSOR_SIZENS)
8739             
8740             elif part.type == AuiDockUIPart.typeGripper:
8741                 cursor = wx.StockCursor(wx.CURSOR_SIZING)
8742
8743         event.SetCursor(cursor)
8744
8745
8746     def UpdateButtonOnScreen(self, button_ui_part, event):
8747         """
8748         Updates/redraws the UI part containing a pane button.
8749
8750         :param `button_ui_part`: the UI part the button belongs to;
8751         :param `event`: a `wx.MouseEvent` to be processed.
8752         """
8753
8754         hit_test = self.HitTest(*event.GetPosition())
8755
8756         if not hit_test or not button_ui_part:
8757             return
8758     
8759         state = AUI_BUTTON_STATE_NORMAL
8760         
8761         if hit_test == button_ui_part:
8762             if event.LeftDown():
8763                 state = AUI_BUTTON_STATE_PRESSED
8764             else:
8765                 state = AUI_BUTTON_STATE_HOVER
8766         else:
8767             if event.LeftDown():
8768                 state = AUI_BUTTON_STATE_HOVER
8769         
8770         # now repaint the button with hover state
8771         cdc = wx.ClientDC(self._frame)
8772
8773         # if the frame has a toolbar, the client area
8774         # origin will not be (0,0).
8775         pt = self._frame.GetClientAreaOrigin()
8776         if pt.x != 0 or pt.y != 0:
8777             cdc.SetDeviceOrigin(pt.x, pt.y)
8778
8779         if hit_test.pane:        
8780             self._art.DrawPaneButton(cdc, self._frame,
8781                       button_ui_part.button.button_id,
8782                       state,
8783                       button_ui_part.rect, hit_test.pane)
8784
8785
8786     def OnLeftDown(self, event):
8787         """
8788         Handles the ``wx.EVT_LEFT_DOWN`` event for L{AuiManager}.
8789
8790         :param `event`: a `wx.MouseEvent` to be processed.
8791         """
8792         
8793         part = self.HitTest(*event.GetPosition())
8794
8795         if not part:
8796             event.Skip()
8797             return
8798         
8799         self._currentDragItem = -1
8800         
8801         if part.type in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
8802         
8803             if not self.CheckMovableSizer(part):
8804                 return
8805
8806             self._action = actionResize
8807             self._action_part = part
8808             self._action_pane = None
8809             self._action_rect = wx.Rect()
8810             self._action_start = wx.Point(event.GetX(), event.GetY())
8811             self._action_offset = wx.Point(event.GetX() - part.rect.x,
8812                                            event.GetY() - part.rect.y)
8813
8814             # draw the resize hint
8815             rect = wx.RectPS(self._frame.ClientToScreen(part.rect.GetPosition()),
8816                              part.rect.GetSize())
8817
8818             self._action_rect = wx.Rect(*rect)
8819
8820             if not AuiManager_HasLiveResize(self):
8821                 if wx.Platform == "__WXMAC__":
8822                     dc = wx.ClientDC(self._frame)
8823                 else:
8824                     dc = wx.ScreenDC()
8825                     
8826                 DrawResizeHint(dc, rect)
8827
8828             self._frame.CaptureMouse()
8829         
8830         elif part.type == AuiDockUIPart.typePaneButton:
8831             if self.IsPaneButtonVisible(part):
8832                 self._action = actionClickButton
8833                 self._action_part = part
8834                 self._action_pane = None
8835                 self._action_start = wx.Point(*event.GetPosition())
8836                 self._frame.CaptureMouse()
8837
8838                 self.RefreshButton(part)
8839         
8840         elif part.type in [AuiDockUIPart.typeCaption, AuiDockUIPart.typeGripper]:
8841
8842             # if we are managing a AuiFloatingFrame window, then
8843             # we are an embedded AuiManager inside the AuiFloatingFrame.
8844             # We want to initiate a toolbar drag in our owner manager
8845             if isinstance(part.pane.window.GetParent(), AuiFloatingFrame):
8846                 rootManager = GetManager(part.pane.window)
8847             else:
8848                 rootManager = self
8849
8850             offset = wx.Point(event.GetX() - part.rect.x, event.GetY() - part.rect.y)
8851             rootManager.OnGripperClicked(part.pane.window, event.GetPosition(), offset)
8852         
8853         if wx.Platform != "__WXMAC__":
8854             event.Skip()
8855
8856
8857     def OnLeftDClick(self, event):
8858         """
8859         Handles the ``wx.EVT_LEFT_DCLICK`` event for L{AuiManager}.
8860
8861         :param `event`: a `wx.MouseEvent` to be processed.
8862         """
8863         
8864         part = self.HitTest(event.GetX(), event.GetY())
8865
8866         if part and part.type == AuiDockUIPart.typeCaption:
8867             if isinstance(part.pane.window.GetParent(), AuiFloatingFrame):
8868                 rootManager = GetManager(part.pane.window)
8869             else:
8870                 rootManager = self
8871                 
8872             rootManager.OnCaptionDoubleClicked(part.pane.window)
8873             
8874         elif part and part.type in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
8875             # Handles double click on AuiNotebook sashes to unsplit
8876             sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
8877             for child in part.cont_sizer.GetChildren():
8878                 if child.IsSizer():
8879                     win = child.GetSizer().GetContainingWindow()
8880                     if isinstance(win, auibook.AuiNotebook):
8881                         win.UnsplitDClick(part, sash_size, event.GetPosition())
8882                         break
8883                 
8884         event.Skip()
8885
8886
8887     def DoEndResizeAction(self, event):
8888         """
8889         Ends a resize action, or for live update, resizes the sash.
8890
8891         :param `event`: a `wx.MouseEvent` to be processed.
8892         """
8893
8894         clientPt = event.GetPosition()
8895         screenPt = self._frame.ClientToScreen(clientPt)
8896
8897         return self.RestrictResize(clientPt, screenPt, createDC=False)
8898
8899
8900     def RestrictResize(self, clientPt, screenPt, createDC):
8901         """ Common method between L{DoEndResizeAction} and L{OnLeftUp_Resize}. """
8902
8903         dock = self._action_part.dock
8904         pane = self._action_part.pane
8905
8906         if createDC:
8907             if wx.Platform == "__WXMAC__":
8908                 dc = wx.ClientDC(self._frame)
8909             else:
8910                 dc = wx.ScreenDC()
8911
8912             DrawResizeHint(dc, self._action_rect)
8913             self._action_rect = wx.Rect()
8914         
8915         newPos = clientPt - self._action_offset
8916
8917         if self._action_part.type == AuiDockUIPart.typeDockSizer:
8918             minPix, maxPix = self.CalculateDockSizerLimits(dock)
8919         else:
8920             if not self._action_part.pane:
8921                 return
8922             minPix, maxPix = self.CalculatePaneSizerLimits(dock, pane)
8923
8924         if self._action_part.orientation == wx.HORIZONTAL:
8925             newPos.y = Clip(newPos.y, minPix, maxPix)
8926         else:
8927             newPos.x = Clip(newPos.x, minPix, maxPix)
8928
8929         if self._action_part.type == AuiDockUIPart.typeDockSizer:
8930         
8931             partnerDock = self.GetPartnerDock(dock)
8932             sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
8933             new_dock_size = 0
8934             direction = dock.dock_direction
8935
8936             if direction == AUI_DOCK_LEFT:
8937                 new_dock_size = newPos.x - dock.rect.x
8938
8939             elif direction == AUI_DOCK_TOP:
8940                 new_dock_size = newPos.y - dock.rect.y
8941
8942             elif direction == AUI_DOCK_RIGHT:
8943                 new_dock_size = dock.rect.x + dock.rect.width - newPos.x - sash_size
8944
8945             elif direction == AUI_DOCK_BOTTOM:
8946                 new_dock_size = dock.rect.y + dock.rect.height - newPos.y - sash_size
8947
8948             deltaDockSize = new_dock_size - dock.size
8949
8950             if partnerDock:
8951                 if deltaDockSize > partnerDock.size - sash_size:
8952                     deltaDockSize = partnerDock.size - sash_size
8953
8954                 partnerDock.size -= deltaDockSize
8955             
8956             dock.size += deltaDockSize
8957             self.Update()
8958         
8959         else:
8960         
8961             # determine the new pixel size that the user wants
8962             # this will help us recalculate the pane's proportion
8963             if dock.IsHorizontal():
8964                 oldPixsize = pane.rect.width
8965                 newPixsize = oldPixsize + newPos.x - self._action_part.rect.x
8966                     
8967             else:            
8968                 oldPixsize = pane.rect.height
8969                 newPixsize = oldPixsize + newPos.y - self._action_part.rect.y
8970                                 
8971             totalPixsize, totalProportion = self.GetTotalPixSizeAndProportion(dock)
8972             partnerPane = self.GetPartnerPane(dock, pane)
8973
8974             # prevent division by zero
8975             if totalPixsize <= 0 or totalProportion <= 0 or not partnerPane:
8976                 return
8977
8978             # adjust for the surplus
8979             while (oldPixsize > 0 and totalPixsize > 10 and \
8980                   oldPixsize*totalProportion/totalPixsize < pane.dock_proportion):
8981             
8982                 totalPixsize -= 1
8983
8984             # calculate the new proportion of the pane
8985             
8986             newProportion = newPixsize*totalProportion/totalPixsize
8987             newProportion = Clip(newProportion, 1, totalProportion)
8988             deltaProp = newProportion - pane.dock_proportion
8989
8990             if partnerPane.dock_proportion - deltaProp < 1:
8991                 deltaProp = partnerPane.dock_proportion - 1
8992                 newProportion = pane.dock_proportion + deltaProp
8993             
8994             # borrow the space from our neighbor pane to the
8995             # right or bottom (depending on orientation)
8996             partnerPane.dock_proportion -= deltaProp
8997             pane.dock_proportion = newProportion
8998
8999             self.Update()
9000         
9001         return True
9002     
9003
9004     def OnLeftUp(self, event):
9005         """
9006         Handles the ``wx.EVT_LEFT_UP`` event for L{AuiManager}.
9007
9008         :param `event`: a `wx.MouseEvent` to be processed.
9009         """
9010
9011         if self._action == actionResize:
9012 ##            self._frame.Freeze()
9013             self.OnLeftUp_Resize(event)
9014 ##            self._frame.Thaw()
9015         
9016         elif self._action == actionClickButton:
9017             self.OnLeftUp_ClickButton(event)
9018         
9019         elif self._action == actionDragFloatingPane:
9020             self.OnLeftUp_DragFloatingPane(event)
9021         
9022         elif self._action == actionDragToolbarPane:
9023             self.OnLeftUp_DragToolbarPane(event)
9024             
9025         else:
9026             event.Skip()        
9027
9028         if self._frame.HasCapture():
9029             self._frame.ReleaseMouse()
9030             
9031         self._action = actionNone
9032
9033
9034     def OnMotion(self, event):
9035         """
9036         Handles the ``wx.EVT_MOTION`` event for L{AuiManager}.
9037
9038         :param `event`: a `wx.MouseEvent` to be processed.
9039         """
9040
9041         if self._action == actionResize:
9042             self.OnMotion_Resize(event)
9043         
9044         elif self._action == actionClickCaption:
9045             self.OnMotion_ClickCaption(event)
9046         
9047         elif self._action == actionDragFloatingPane:
9048             self.OnMotion_DragFloatingPane(event)
9049         
9050         elif self._action == actionDragToolbarPane:
9051             self.OnMotion_DragToolbarPane(event)
9052         
9053         else:
9054             self.OnMotion_Other(event)
9055                         
9056     
9057     def OnLeaveWindow(self, event):
9058         """
9059         Handles the ``wx.EVT_LEAVE_WINDOW`` event for L{AuiManager}.
9060
9061         :param `event`: a `wx.MouseEvent` to be processed.
9062         """
9063
9064         if self._hover_button:
9065             self.RefreshButton(self._hover_button)
9066             self._hover_button = None
9067
9068
9069     def OnCaptureLost(self, event):
9070         """
9071         Handles the ``wx.EVT_MOUSE_CAPTURE_LOST`` event for L{AuiManager}.
9072
9073         :param `event`: a `wx.MouseCaptureLostEvent` to be processed.
9074         """
9075         
9076         # cancel the operation in progress, if any
9077         if self._action != actionNone:
9078             self._action = actionNone
9079             self.HideHint()
9080
9081
9082     def OnHintFadeTimer(self, event):
9083         """
9084         Handles the ``wx.EVT_TIMER`` event for L{AuiManager}.
9085
9086         :param `event`: a `wx.TimerEvent` to be processed.
9087         """
9088
9089         if not self._hint_window or self._hint_fadeamt >= self._hint_fademax:
9090             self._hint_fadetimer.Stop()
9091             return
9092
9093         self._hint_fadeamt += 4
9094         self._hint_window.SetTransparent(self._hint_fadeamt)
9095
9096
9097     def OnMove(self, event):
9098         """
9099         Handles the ``wx.EVT_MOVE`` event for L{AuiManager}.
9100
9101         :param `event`: a `wx.MoveEvent` to be processed.
9102         """
9103
9104         if event is not None:
9105             event.Skip()
9106
9107         if isinstance(self._frame, AuiFloatingFrame) and self._frame.IsShownOnScreen():
9108             return
9109
9110         docked, hAlign, vAlign, monitor = self._is_docked
9111         if docked:
9112             self.Snap()
9113
9114         for pane in self._panes:
9115             if pane.IsSnappable():
9116                 if pane.IsFloating() and pane.IsShown():
9117                     self.SnapPane(pane, pane.floating_pos, pane.floating_size, True)
9118         
9119
9120     def OnSysColourChanged(self, event):
9121         """
9122         Handles the ``wx.EVT_SYS_COLOUR_CHANGED`` event for L{AuiManager}.
9123
9124         :param `event`: a `wx.SysColourChangedEvent` to be processed.
9125         """
9126         
9127         # This event is probably triggered by a theme change 
9128         # so we have to re-init the art provider.
9129         if self._art:
9130             self._art.Init()
9131
9132         if self._frame:
9133             self.Update()
9134             self._frame.Refresh()
9135             
9136
9137     def OnChildFocus(self, event):
9138         """
9139         Handles the ``wx.EVT_CHILD_FOCUS`` event for L{AuiManager}.
9140
9141         :param `event`: a `wx.ChildFocusEvent` to be processed.
9142         """
9143
9144         # when a child pane has it's focus set, we should change the 
9145         # pane's active state to reflect this. (this is only true if 
9146         # active panes are allowed by the owner)
9147
9148         window = event.GetWindow()
9149         if isinstance(window, wx.Dialog):
9150             # Ignore EVT_CHILD_FOCUS events originating from dialogs not
9151             # managed by AUI
9152             rootManager = None
9153         elif isinstance(window.GetParent(), AuiFloatingFrame):
9154             rootManager = GetManager(window)
9155         else:
9156             rootManager = self
9157                 
9158         if rootManager:
9159             rootManager.ActivatePane(window)
9160             
9161         event.Skip()
9162
9163
9164     def OnMotion_ClickCaption(self, event):
9165         """
9166         Sub-handler for the L{OnMotion} event.
9167
9168         :param `event`: a `wx.MouseEvent` to be processed.
9169         """
9170         
9171         clientPt = event.GetPosition()
9172         screenPt = self._frame.ClientToScreen(clientPt)
9173
9174         drag_x_threshold = wx.SystemSettings.GetMetric(wx.SYS_DRAG_X)
9175         drag_y_threshold = wx.SystemSettings.GetMetric(wx.SYS_DRAG_Y)
9176
9177         if not self._action_pane:
9178             return
9179
9180         # we need to check if the mouse is now being dragged
9181         if not (abs(clientPt.x - self._action_start.x) > drag_x_threshold or \
9182                 abs(clientPt.y - self._action_start.y) > drag_y_threshold):
9183         
9184             return
9185         
9186         # dragged -- we need to change the mouse action to 'drag'
9187         if self._action_pane.IsToolbar():
9188             self._action = actionDragToolbarPane
9189             self._action_window = self._action_pane.window
9190         
9191         elif self._action_pane.IsFloatable() and self._agwFlags & AUI_MGR_ALLOW_FLOATING:
9192
9193             e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, self._action_pane, canVeto=True)
9194             if e.GetVeto():
9195                 return
9196             
9197             self._action = actionDragFloatingPane
9198
9199             # set initial float position
9200             self._action_pane.floating_pos = screenPt - self._action_offset
9201
9202             # float the window
9203             if self._action_pane.IsMaximized():
9204                 self.RestorePane(self._action_pane)
9205                 
9206             self._action_pane.Hide()
9207             self._action_pane.Float()
9208             if wx.Platform == "__WXGTK__":
9209                 self._action_pane.Show()
9210
9211             e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, self._action_pane, canVeto=False)
9212
9213             if not self._action_pane.frame:
9214                 self.Update()
9215
9216             self._action_window = self._action_pane.window
9217
9218             # adjust action offset for window frame
9219             windowPt = self._action_pane.frame.GetRect().GetTopLeft()
9220             originPt = self._action_pane.frame.ClientToScreen(wx.Point())
9221             self._toolbar_action_offset = originPt - windowPt
9222             
9223             if self._agwFlags & AUI_MGR_USE_NATIVE_MINIFRAMES:
9224                 originPt = windowPt + wx.Point(3, 3)
9225                 
9226             self._action_offset += originPt - windowPt
9227
9228             # action offset is used here to make it feel "natural" to the user
9229             # to drag a docked pane and suddenly have it become a floating frame.
9230             # Sometimes, however, the offset where the user clicked on the docked
9231             # caption is bigger than the width of the floating frame itself, so
9232             # in that case we need to set the action offset to a sensible value
9233             frame_size = self._action_pane.frame.GetSize()
9234             if self._action_offset.x > frame_size.x * 2 / 3:
9235                 self._action_offset.x = frame_size.x / 2
9236             if self._action_offset.y > frame_size.y * 2 / 3:
9237                 self._action_offset.y = frame_size.y / 2
9238
9239             self.OnMotion_DragFloatingPane(event)
9240             if wx.Platform != "__WXGTK__":
9241                 self._action_pane.Show()
9242                 
9243             self.Update()
9244
9245
9246     def OnMotion_Resize(self, event):
9247         """
9248         Sub-handler for the L{OnMotion} event.
9249
9250         :param `event`: a `wx.MouseEvent` to be processed.
9251         """
9252
9253         if AuiManager_HasLiveResize(self):
9254             if self._currentDragItem != -1:
9255                 self._action_part = self._uiparts[self._currentDragItem]
9256             else:
9257                 self._currentDragItem = self._uiparts.index(self._action_part)
9258
9259             if self._frame.HasCapture():
9260                 self._frame.ReleaseMouse()
9261                 
9262             self.DoEndResizeAction(event)
9263             self._frame.CaptureMouse()
9264             return
9265
9266         if not self._action_part or not self._action_part.dock or not self._action_part.orientation:
9267             return
9268
9269         clientPt = event.GetPosition()
9270         screenPt = self._frame.ClientToScreen(clientPt)
9271                     
9272         dock = self._action_part.dock
9273         pos = self._action_part.rect.GetPosition()
9274
9275         if self._action_part.type == AuiDockUIPart.typeDockSizer:
9276             minPix, maxPix = self.CalculateDockSizerLimits(dock)
9277         else:
9278             if not self._action_part.pane:
9279                 return
9280             
9281             pane = self._action_part.pane
9282             minPix, maxPix = self.CalculatePaneSizerLimits(dock, pane)
9283
9284         if self._action_part.orientation == wx.HORIZONTAL:
9285             pos.y = Clip(clientPt.y - self._action_offset.y, minPix, maxPix)
9286         else:
9287             pos.x = Clip(clientPt.x - self._action_offset.x, minPix, maxPix)
9288
9289         hintrect = wx.RectPS(self._frame.ClientToScreen(pos), self._action_part.rect.GetSize())
9290
9291         if hintrect != self._action_rect:
9292         
9293             if wx.Platform == "__WXMAC__":
9294                 dc = wx.ClientDC(self._frame)
9295             else:
9296                 dc = wx.ScreenDC()
9297
9298             DrawResizeHint(dc, self._action_rect)
9299             DrawResizeHint(dc, hintrect)
9300             self._action_rect = wx.Rect(*hintrect)
9301                 
9302
9303     def OnLeftUp_Resize(self, event):
9304         """
9305         Sub-handler for the L{OnLeftUp} event.
9306
9307         :param `event`: a `wx.MouseEvent` to be processed.
9308         """
9309         
9310         if self._currentDragItem != -1 and AuiManager_HasLiveResize(self):
9311             self._action_part = self._uiparts[self._currentDragItem]
9312
9313             if self._frame.HasCapture():
9314                 self._frame.ReleaseMouse()
9315                 
9316             self.DoEndResizeAction(event)
9317             self._currentDragItem = -1
9318             return
9319             
9320         if not self._action_part or not self._action_part.dock:
9321             return
9322
9323         clientPt = event.GetPosition()
9324         screenPt = self._frame.ClientToScreen(clientPt)
9325
9326         return self.RestrictResize(clientPt, screenPt, createDC=True)
9327         
9328
9329     def OnLeftUp_ClickButton(self, event):
9330         """
9331         Sub-handler for the L{OnLeftUp} event.
9332
9333         :param `event`: a `wx.MouseEvent` to be processed.
9334         """
9335         
9336         self._hover_button = None
9337
9338         if self._action_part:
9339             self.RefreshButton(self._action_part)
9340
9341             # make sure we're still over the item that was originally clicked
9342             if self._action_part == self.HitTest(*event.GetPosition()):
9343             
9344                 # fire button-click event
9345                 e = AuiManagerEvent(wxEVT_AUI_PANE_BUTTON)
9346                 e.SetManager(self)
9347                 e.SetPane(self._action_part.pane)
9348                 e.SetButton(self._action_part.button.button_id)
9349                 self.ProcessMgrEvent(e)
9350         
9351
9352     def CheckPaneMove(self, pane):
9353         """
9354         Checks if a pane has moved by a visible amount.
9355
9356         :param `pane`: an instance of L{AuiPaneInfo}.
9357         """
9358
9359         win_rect = pane.frame.GetRect()
9360         win_rect.x, win_rect.y = pane.floating_pos
9361         
9362         if win_rect == self._last_rect:
9363             return False
9364
9365         # skip the first move event
9366         if self._last_rect.IsEmpty():
9367             self._last_rect = wx.Rect(*win_rect)
9368             return False
9369
9370         # skip if moving too fast to avoid massive redraws and
9371         # jumping hint windows
9372         if abs(win_rect.x - self._last_rect.x) > 10 or \
9373            abs(win_rect.y - self._last_rect.y) > 10:
9374             self._last_rect = wx.Rect(*win_rect)
9375             return False
9376
9377         return True        
9378         
9379
9380     def OnMotion_DragFloatingPane(self, eventOrPt):
9381         """
9382         Sub-handler for the L{OnMotion} event.
9383
9384         :param `event`: a `wx.MouseEvent` to be processed.
9385         """
9386
9387         isPoint = False
9388         if isinstance(eventOrPt, wx.Point):
9389             clientPt = self._frame.ScreenToClient(eventOrPt)
9390             screenPt = wx.Point(*eventOrPt)
9391             isPoint = True
9392         else:
9393             clientPt = eventOrPt.GetPosition()
9394             screenPt = self._frame.ClientToScreen(clientPt)
9395         
9396         framePos = wx.Point()
9397         
9398         # try to find the pane
9399         pane = self.GetPane(self._action_window)
9400         if not pane.IsOk():
9401             raise Exception("Pane window not found")
9402
9403         # update floating position
9404         if pane.IsFloating():
9405             diff = pane.floating_pos - (screenPt - self._action_offset)
9406             pane.floating_pos = screenPt - self._action_offset
9407
9408         framePos = pane.floating_pos
9409
9410         # Move the pane window
9411         if pane.frame:
9412
9413             if diff.x != 0 or diff.y != 0:
9414                 if wx.Platform == "__WXMSW__" and (self._agwFlags & AUI_MGR_TRANSPARENT_DRAG) == 0: # and not self.CheckPaneMove(pane):
9415                     # return
9416                     # HACK: Terrible hack on wxMSW (!)
9417                     pane.frame.SetTransparent(254)
9418                             
9419                 self._from_move = True
9420                 pane.frame.Move(pane.floating_pos)
9421                 self._from_move = False
9422
9423             if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
9424                 pane.frame.SetTransparent(150)
9425
9426         # calculate the offset from the upper left-hand corner
9427         # of the frame to the mouse pointer
9428         action_offset = screenPt - framePos
9429
9430         # is the pane dockable?
9431         if not self.CanDockPanel(pane):
9432             self.HideHint()
9433             ShowDockingGuides(self._guides, False)
9434             return
9435         
9436         for paneInfo in self._panes:
9437         
9438             if not paneInfo.IsDocked() or not paneInfo.IsShown():
9439                 continue
9440             if paneInfo.IsToolbar() or paneInfo.IsNotebookControl():
9441                 continue
9442             if paneInfo.IsMaximized():
9443                 continue
9444
9445             if paneInfo.IsNotebookPage():
9446             
9447                 notebookRoot = GetNotebookRoot(self._panes, paneInfo.notebook_id)
9448
9449                 if not notebookRoot or not notebookRoot.IsDocked():
9450                     continue
9451             
9452             rc = paneInfo.window.GetScreenRect()
9453             if rc.Contains(screenPt):
9454                 if rc.height < 20 or rc.width < 20:
9455                     return
9456                 
9457                 self.UpdateDockingGuides(paneInfo)
9458                 ShowDockingGuides(self._guides, True)
9459                 break
9460
9461         self.DrawHintRect(pane.window, clientPt, action_offset)
9462
9463
9464     def OnLeftUp_DragFloatingPane(self, eventOrPt):
9465         """
9466         Sub-handler for the L{OnLeftUp} event.
9467
9468         :param `event`: a `wx.MouseEvent` to be processed.
9469         """
9470
9471         if isinstance(eventOrPt, wx.Point):
9472             clientPt = self._frame.ScreenToClient(eventOrPt)
9473             screenPt = wx.Point(*eventOrPt)
9474         else:
9475             clientPt = eventOrPt.GetPosition()
9476             screenPt = self._frame.ClientToScreen(clientPt)
9477
9478         # try to find the pane
9479         paneInfo = self.GetPane(self._action_window)
9480         if not paneInfo.IsOk():
9481             raise Exception("Pane window not found")
9482
9483         ret = False
9484         
9485         if paneInfo.frame:
9486         
9487             # calculate the offset from the upper left-hand corner
9488             # of the frame to the mouse pointer
9489             framePos = paneInfo.frame.GetPosition()
9490             action_offset = screenPt - framePos
9491
9492             # is the pane dockable?
9493             if self.CanDockPanel(paneInfo):
9494                 # do the drop calculation
9495                 indx = self._panes.index(paneInfo)
9496                 ret, paneInfo = self.DoDrop(self._docks, self._panes, paneInfo, clientPt, action_offset)
9497
9498                 if ret:
9499                     e = self.FireEvent(wxEVT_AUI_PANE_DOCKING, paneInfo, canVeto=True)
9500                     if e.GetVeto():
9501                         self.HideHint()
9502                         ShowDockingGuides(self._guides, False)
9503                         return
9504
9505                     e = self.FireEvent(wxEVT_AUI_PANE_DOCKED, paneInfo, canVeto=False)
9506
9507                     if self._agwFlags & AUI_MGR_SMOOTH_DOCKING:
9508                         self.SmoothDock(paneInfo)
9509
9510                 self._panes[indx] = paneInfo
9511             
9512         # if the pane is still floating, update it's floating
9513         # position (that we store)
9514         if paneInfo.IsFloating():
9515             paneInfo.floating_pos = paneInfo.frame.GetPosition()
9516             if paneInfo.frame._transparent != paneInfo.transparent or self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
9517                 paneInfo.frame.SetTransparent(paneInfo.transparent)
9518                 paneInfo.frame._transparent = paneInfo.transparent
9519         
9520         elif self._has_maximized:
9521             self.RestoreMaximizedPane()
9522         
9523         # reorder for dropping to a new notebook
9524         # (caution: this code breaks the reference!)
9525         tempPaneInfo = self.CopyTarget(paneInfo)
9526         self._panes.remove(paneInfo)
9527         self._panes.append(tempPaneInfo)
9528
9529         if ret:
9530             self.Update()
9531
9532         self.HideHint()
9533         ShowDockingGuides(self._guides, False)
9534
9535
9536     def OnMotion_DragToolbarPane(self, eventOrPt):
9537         """
9538         Sub-handler for the L{OnMotion} event.
9539
9540         :param `event`: a `wx.MouseEvent` to be processed.
9541         """
9542         
9543         isPoint = False
9544         if isinstance(eventOrPt, wx.Point):
9545             clientPt = self._frame.ScreenToClient(eventOrPt)
9546             screenPt = wx.Point(*eventOrPt)
9547             isPoint = True
9548         else:
9549             clientPt = eventOrPt.GetPosition()
9550             screenPt = self._frame.ClientToScreen(clientPt)
9551
9552         pane = self.GetPane(self._action_window)
9553         if not pane.IsOk():
9554             raise Exception("Pane window not found")
9555
9556         pane.state |= AuiPaneInfo.actionPane
9557         indx = self._panes.index(pane)
9558
9559         ret = False
9560         wasFloating = pane.IsFloating()
9561         # is the pane dockable?
9562         if self.CanDockPanel(pane):
9563             # do the drop calculation
9564             ret, pane = self.DoDrop(self._docks, self._panes, pane, clientPt, self._action_offset)
9565         
9566         # update floating position
9567         if pane.IsFloating():
9568             pane.floating_pos = screenPt - self._toolbar_action_offset
9569
9570         # move the pane window
9571         if pane.frame:
9572             if wx.Platform == "__WXMSW__" and (self._agwFlags & AUI_MGR_TRANSPARENT_DRAG) == 0: # and not self.CheckPaneMove(pane):
9573                 # return
9574                 # HACK: Terrible hack on wxMSW (!)
9575                 pane.frame.SetTransparent(254)
9576
9577             self._from_move = True
9578             pane.frame.Move(pane.floating_pos)
9579             self._from_move = False
9580                 
9581             if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
9582                 pane.frame.SetTransparent(150)
9583
9584         self._panes[indx] = pane
9585         if ret and wasFloating != pane.IsFloating() or (ret and not wasFloating):
9586             wx.CallAfter(self.Update)
9587
9588         # when release the button out of the window.
9589         # TODO: a better fix is needed.
9590
9591         if _VERSION_STRING < "2.9":
9592             leftDown = wx.GetMouseState().LeftDown()
9593         else:
9594             leftDown = wx.GetMouseState().LeftIsDown()
9595         
9596         if not leftDown:
9597             self._action = actionNone
9598             self.OnLeftUp_DragToolbarPane(eventOrPt)
9599
9600
9601     def OnMotion_Other(self, event):
9602         """
9603         Sub-handler for the L{OnMotion} event.
9604
9605         :param `event`: a `wx.MouseEvent` to be processed.
9606         """
9607         
9608         part = self.HitTest(*event.GetPosition())
9609
9610         if part and part.type == AuiDockUIPart.typePaneButton \
9611            and self.IsPaneButtonVisible(part):
9612             if part != self._hover_button:
9613             
9614                 if self._hover_button:
9615                     self.RefreshButton(self._hover_button)
9616
9617                 self._hover_button = part
9618                 self.RefreshButton(part)
9619             
9620         else:
9621         
9622             if self._hover_button:
9623                 self.RefreshButton(self._hover_button)
9624             else:
9625                 event.Skip()
9626
9627             self._hover_button = None
9628         
9629         
9630     def OnLeftUp_DragToolbarPane(self, eventOrPt):
9631         """
9632         Sub-handler for the L{OnLeftUp} event.
9633
9634         :param `event`: a `wx.MouseEvent` to be processed.
9635         """
9636         
9637         isPoint = False
9638         if isinstance(eventOrPt, wx.Point):
9639             clientPt = self._frame.ScreenToClient(eventOrPt)
9640             screenPt = wx.Point(*eventOrPt)
9641             isPoint = True
9642         else:
9643             clientPt = eventOrPt.GetPosition()
9644             screenPt = self._frame.ClientToScreen(clientPt)
9645
9646         # try to find the pane
9647         pane = self.GetPane(self._action_window)
9648         if not pane.IsOk():
9649             raise Exception("Pane window not found")
9650
9651         if pane.IsFloating():
9652             pane.floating_pos = pane.frame.GetPosition()
9653             if pane.frame._transparent != pane.transparent or self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
9654                 pane.frame.SetTransparent(pane.transparent)
9655                 pane.frame._transparent = pane.transparent
9656         
9657         # save the new positions
9658         docks = FindDocks(self._docks, pane.dock_direction, pane.dock_layer, pane.dock_row)
9659         if len(docks) == 1:
9660             dock = docks[0]
9661             pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock)
9662
9663             for i in xrange(len(dock.panes)):
9664                 dock.panes[i].dock_pos = pane_positions[i]
9665         
9666         pane.state &= ~AuiPaneInfo.actionPane
9667         self.Update()
9668
9669
9670     def OnPaneButton(self, event):
9671         """
9672         Handles the ``EVT_AUI_PANE_BUTTON`` event for L{AuiManager}.
9673
9674         :param `event`: a L{AuiManagerEvent} event to be processed.
9675         """
9676
9677         if not event.pane:
9678             raise Exception("Pane Info passed to AuiManager.OnPaneButton must be non-null")
9679
9680         pane = event.pane
9681
9682         if event.button == AUI_BUTTON_CLOSE:
9683
9684             if isinstance(pane.window.GetParent(), AuiFloatingFrame):
9685                 rootManager = GetManager(pane.window)
9686             else:
9687                 rootManager = self
9688             
9689             if rootManager != self:
9690                 self._frame.Close()
9691                 return
9692
9693             # fire pane close event
9694             e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE)
9695             e.SetManager(self)
9696             e.SetPane(event.pane)
9697             self.ProcessMgrEvent(e)
9698
9699             if not e.GetVeto():
9700             
9701                 # close the pane, but check that it
9702                 # still exists in our pane array first
9703                 # (the event handler above might have removed it)
9704
9705                 check = self.GetPane(pane.window)
9706                 if check.IsOk():                
9707                     self.ClosePane(pane)
9708                 
9709                 self.Update()
9710
9711         # mn this performs the minimizing of a pane
9712         elif event.button == AUI_BUTTON_MINIMIZE:
9713             e = AuiManagerEvent(wxEVT_AUI_PANE_MINIMIZE)
9714             e.SetManager(self)
9715             e.SetPane(event.pane)
9716             self.ProcessMgrEvent(e)
9717
9718             if not e.GetVeto():
9719                 self.MinimizePane(pane)
9720     
9721         elif event.button == AUI_BUTTON_MAXIMIZE_RESTORE and not pane.IsMaximized():
9722         
9723             # fire pane close event
9724             e = AuiManagerEvent(wxEVT_AUI_PANE_MAXIMIZE)
9725             e.SetManager(self)
9726             e.SetPane(event.pane)
9727             self.ProcessMgrEvent(e)
9728
9729             if not e.GetVeto():
9730             
9731                 self.MaximizePane(pane)
9732                 self.Update()
9733             
9734         elif event.button == AUI_BUTTON_MAXIMIZE_RESTORE and pane.IsMaximized():
9735         
9736             # fire pane close event
9737             e = AuiManagerEvent(wxEVT_AUI_PANE_RESTORE)
9738             e.SetManager(self)
9739             e.SetPane(event.pane)
9740             self.ProcessMgrEvent(e)
9741
9742             if not e.GetVeto():
9743             
9744                 self.RestorePane(pane)
9745                 self.Update()
9746             
9747         elif event.button == AUI_BUTTON_PIN:
9748         
9749             if self._agwFlags & AUI_MGR_ALLOW_FLOATING and pane.IsFloatable():
9750                 e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, pane, canVeto=True)
9751                 if e.GetVeto():
9752                     return
9753
9754                 pane.Float()
9755                 e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, pane, canVeto=False)
9756
9757             self.Update()
9758
9759
9760     def MinimizePane(self, paneInfo):
9761         """
9762         Minimizes a pane in a newly and automatically created L{AuiToolBar}.
9763
9764         Clicking on the minimize button causes a new L{AuiToolBar} to be created
9765         and added to the frame manager (currently the implementation is such that
9766         panes at West will have a toolbar at the right, panes at South will have
9767         toolbars at the bottom etc...) and the pane is hidden in the manager.
9768         
9769         Clicking on the restore button on the newly created toolbar will result in the
9770         toolbar being removed and the original pane being restored.
9771
9772         :param `paneInfo`: a L{AuiPaneInfo} instance for the pane to be minimized.
9773         """
9774         
9775         if not paneInfo.IsToolbar():
9776
9777             if paneInfo.IsMinimized():
9778                 # We are already minimized
9779                 return
9780             
9781             # Basically the idea is this.
9782             #
9783             # 1) create a toolbar, with a restore button 
9784             #
9785             # 2) place the new toolbar in the toolbar area representative of the location of the pane 
9786             #  (NORTH/SOUTH/EAST/WEST, central area always to the right)
9787             #
9788             # 3) Hide the minimizing pane 
9789
9790
9791             # personalize the toolbar style
9792             tbStyle = AUI_TB_DEFAULT_STYLE
9793             posMask = paneInfo.minimize_mode & AUI_MINIMIZE_POS_MASK
9794             captMask = paneInfo.minimize_mode & AUI_MINIMIZE_CAPT_MASK
9795             dockDirection = paneInfo.dock_direction
9796             if captMask != 0:
9797                 tbStyle |= AUI_TB_TEXT
9798             if posMask == AUI_MINIMIZE_POS_SMART:
9799                 if paneInfo.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]:
9800                     tbStyle |= AUI_TB_HORZ_LAYOUT
9801
9802                 elif paneInfo.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT, AUI_DOCK_CENTER]:
9803                     tbStyle |= AUI_TB_VERTICAL
9804                     if captMask == AUI_MINIMIZE_CAPT_SMART:
9805                         tbStyle |= AUI_TB_CLOCKWISE
9806                     
9807             elif posMask in [AUI_MINIMIZE_POS_TOP, AUI_MINIMIZE_POS_BOTTOM]:
9808                 tbStyle |= AUI_TB_HORZ_LAYOUT
9809                 if posMask == AUI_MINIMIZE_POS_TOP:
9810                     dockDirection = AUI_DOCK_TOP
9811                 else:
9812                     dockDirection = AUI_DOCK_BOTTOM
9813
9814             else:
9815                 tbStyle |= AUI_TB_VERTICAL
9816                 if captMask == AUI_MINIMIZE_CAPT_SMART:
9817                     tbStyle |= AUI_TB_CLOCKWISE
9818                 if posMask == AUI_MINIMIZE_POS_LEFT:
9819                     dockDirection = AUI_DOCK_LEFT
9820                 elif posMask == AUI_MINIMIZE_POS_RIGHT:
9821                     dockDirection = AUI_DOCK_RIGHT
9822                 elif posMask == AUI_MINIMIZE_POS_BOTTOM:
9823                     dockDirection = AUI_DOCK_BOTTOM
9824
9825             # Create a new toolbar
9826             # give it the same name as the minimized pane with _min appended
9827
9828             win_rect = paneInfo.window.GetScreenRect()
9829             
9830             minimize_toolbar = auibar.AuiToolBar(self.GetManagedWindow(), agwStyle=tbStyle)
9831             minimize_toolbar.Hide()
9832             minimize_toolbar.SetToolBitmapSize(wx.Size(16, 16))
9833
9834             if paneInfo.icon and paneInfo.icon.IsOk():
9835                 restore_bitmap = paneInfo.icon
9836             else:
9837                 restore_bitmap = self._art._restore_bitmap
9838                 
9839             minimize_toolbar.AddSimpleTool(ID_RESTORE_FRAME, paneInfo.caption, restore_bitmap, "Restore " + paneInfo.caption)
9840             minimize_toolbar.SetAuiManager(self)
9841             minimize_toolbar.Realize()
9842             toolpanelname = paneInfo.name + "_min"
9843
9844             if paneInfo.IsMaximized():
9845                 paneInfo.SetFlag(paneInfo.wasMaximized, True)
9846
9847             if dockDirection == AUI_DOCK_TOP:
9848                 self.AddPane(minimize_toolbar, AuiPaneInfo(). \
9849                     Name(toolpanelname).Caption(paneInfo.caption). \
9850                     ToolbarPane().Top().BottomDockable(False). \
9851                     LeftDockable(False).RightDockable(False).DestroyOnClose())
9852                 
9853             elif dockDirection == AUI_DOCK_BOTTOM:
9854                 self.AddPane(minimize_toolbar, AuiPaneInfo(). \
9855                     Name(toolpanelname).Caption(paneInfo.caption). \
9856                     ToolbarPane().Bottom().TopDockable(False). \
9857                     LeftDockable(False).RightDockable(False).DestroyOnClose())
9858                 
9859             elif dockDirection == AUI_DOCK_LEFT:
9860                 self.AddPane(minimize_toolbar, AuiPaneInfo(). \
9861                     Name(toolpanelname).Caption(paneInfo.caption). \
9862                     ToolbarPane().Left().TopDockable(False). \
9863                     BottomDockable(False).RightDockable(False).DestroyOnClose())
9864
9865             elif dockDirection in [AUI_DOCK_RIGHT, AUI_DOCK_CENTER]:
9866                 self.AddPane(minimize_toolbar, AuiPaneInfo(). \
9867                     Name(toolpanelname).Caption(paneInfo.caption). \
9868                     ToolbarPane().Right().TopDockable(False). \
9869                     LeftDockable(False).BottomDockable(False).DestroyOnClose())
9870
9871             arr = FindDocks(self._docks, paneInfo.dock_direction, paneInfo.dock_layer, paneInfo.dock_row)
9872
9873             if arr:
9874                 dock = arr[0]
9875                 paneInfo.previousDockSize = dock.size
9876
9877             paneInfo.previousDockPos = paneInfo.dock_pos
9878             
9879             # mark ourselves minimized
9880             paneInfo.Minimize()
9881             paneInfo.Show(False)
9882             self._has_minimized = True
9883             # last, hide the window
9884             if paneInfo.window and paneInfo.window.IsShown():
9885                 paneInfo.window.Show(False)
9886
9887             minimize_toolbar.Show()
9888             self.Update()
9889             if self._agwFlags & AUI_MGR_ANIMATE_FRAMES:
9890                 self.AnimateDocking(win_rect, minimize_toolbar.GetScreenRect())
9891
9892
9893     def OnRestoreMinimizedPane(self, event):
9894         """
9895         Handles the ``EVT_AUI_PANE_MIN_RESTORE`` event for L{AuiManager}.
9896
9897         :param `event`: an instance of L{AuiManagerEvent} to be processed.
9898         """
9899
9900         self.RestoreMinimizedPane(event.pane)
9901
9902
9903     def OnPaneDocked(self, event):
9904         """
9905         Handles the ``EVT_AUI_PANE_DOCKED`` event for L{AuiManager}.
9906
9907         :param `event`: an instance of L{AuiManagerEvent} to be processed.
9908         """
9909
9910         event.Skip()
9911         self.RemoveAutoNBCaption(event.GetPane())        
9912     
9913
9914     def CreateNotebookBase(self, panes, paneInfo):
9915         """
9916         Creates an auto-notebook base from a pane, and then add that pane as a page.
9917
9918         :param `panes`: Set of panes to append new notebook base pane to
9919         :param `paneInfo`: L{AuiPaneInfo} instance to convert to new notebook.
9920         """
9921
9922         # Create base notebook pane ...
9923         nbid = len(self._notebooks)
9924
9925         baseInfo = AuiPaneInfo()
9926         baseInfo.SetDockPos(paneInfo).NotebookControl(nbid). \
9927             CloseButton(False).SetNameFromNotebookId(). \
9928             NotebookDockable(False).Floatable(paneInfo.IsFloatable())
9929         baseInfo.best_size = paneInfo.best_size
9930         panes.append(baseInfo)
9931
9932         # add original pane as tab ...
9933         paneInfo.NotebookPage(nbid)
9934
9935     def RemoveAutoNBCaption(self, pane):
9936         """
9937         Removes the caption on newly created automatic notebooks.
9938
9939         :param `pane`: an instance of L{AuiPaneInfo} (the target notebook).
9940         """
9941
9942         if self._agwFlags & AUI_MGR_AUTONB_NO_CAPTION == 0:
9943             return False
9944
9945         def RemoveCaption():
9946             """ Sub-function used to remove the pane caption on automatic notebooks. """
9947             
9948             if pane.HasNotebook(): 
9949                 notebook = self._notebooks[pane.notebook_id] 
9950                 self.GetPane(notebook).CaptionVisible(False).PaneBorder(False)                
9951                 self.Update() 
9952
9953         # it seems the notebook isnt created by this stage, so remove 
9954         # the caption a moment later 
9955         wx.CallAfter(RemoveCaption)
9956         return True
9957         
9958         
9959     def RestoreMinimizedPane(self, paneInfo):
9960         """
9961         Restores a previously minimized pane.
9962
9963         :param `paneInfo`: a L{AuiPaneInfo} instance for the pane to be restored.
9964         """
9965
9966         panename = paneInfo.name
9967         panename = panename[0:-4]
9968         pane = self.GetPane(panename)
9969
9970         pane.SetFlag(pane.needsRestore, True)
9971
9972         if not pane.IsOk():
9973             panename = paneInfo.name
9974             pane = self.GetPane(panename)
9975             paneInfo = self.GetPane(panename + "_min")
9976             if not paneInfo.IsOk():
9977                 # Already minimized
9978                 return
9979         
9980         if pane.IsOk():
9981             if not pane.IsMinimized():
9982                 return
9983             
9984
9985             if pane.HasFlag(pane.wasMaximized):
9986
9987                 self.SavePreviousDockSizes(pane)
9988                 
9989
9990             self.ShowPane(pane.window, True)
9991             pane.Show(True)
9992             self._has_minimized = False
9993             pane.SetFlag(pane.optionMinimized, False)
9994             paneInfo.window.Show(False)
9995             self.DetachPane(paneInfo.window)
9996             paneInfo.Show(False)
9997             paneInfo.Hide()
9998
9999             self.Update()
10000
10001
10002     def AnimateDocking(self, win_rect, pane_rect):
10003         """
10004         Animates the minimization/docking of a pane a la Eclipse, using a `wx.ScreenDC`
10005         to draw a "moving docking rectangle" on the screen.
10006
10007         :param `win_rect`: the original pane screen rectangle;
10008         :param `pane_rect`: the newly created toolbar/pane screen rectangle.
10009
10010         :note: This functionality is not available on wxMAC as this platform doesn't have
10011          the ability to use `wx.ScreenDC` to draw on-screen and on Windows > Vista.
10012         """
10013
10014         if wx.Platform == "__WXMAC__":
10015             # No wx.ScreenDC on the Mac...
10016             return
10017         if wx.Platform == "__WXMSW__" and wx.GetOsVersion()[1] > 5:
10018             # No easy way to handle this on Vista...
10019             return
10020
10021         xstart, ystart = win_rect.x, win_rect.y
10022         xend, yend = pane_rect.x, pane_rect.y
10023
10024         step = self.GetAnimationStep()
10025         
10026         wstep = int(abs(win_rect.width - pane_rect.width)/step)
10027         hstep = int(abs(win_rect.height - pane_rect.height)/step)
10028         xstep = int(win_rect.x - pane_rect.x)/step
10029         ystep = int(win_rect.y - pane_rect.y)/step
10030         
10031         dc = wx.ScreenDC()
10032         dc.SetLogicalFunction(wx.INVERT)
10033         dc.SetBrush(wx.TRANSPARENT_BRUSH)
10034         dc.SetPen(wx.LIGHT_GREY_PEN)
10035         
10036         for i in xrange(int(step)):
10037             width, height = win_rect.width - i*wstep, win_rect.height - i*hstep
10038             x, y = xstart - i*xstep, ystart - i*ystep
10039             new_rect = wx.Rect(x, y, width, height)
10040             dc.DrawRoundedRectangleRect(new_rect, 3)
10041             wx.SafeYield()
10042             wx.MilliSleep(10)
10043             dc.DrawRoundedRectangleRect(new_rect, 3)
10044             
10045
10046     def SmoothDock(self, paneInfo):
10047         """
10048         This method implements a smooth docking effect for floating panes, similar to
10049         what the PyQT library does with its floating windows.
10050
10051         :param `paneInfo`: an instance of L{AuiPaneInfo}.
10052
10053         :note: The smooth docking effect can only be used if you set the ``AUI_MGR_SMOOTH_DOCKING``
10054          style to L{AuiManager}.
10055         """
10056
10057         if paneInfo.IsToolbar():
10058             return
10059
10060         if not paneInfo.frame or self._hint_rect.IsEmpty():
10061             return
10062
10063         hint_rect = self._hint_rect
10064         win_rect = paneInfo.frame.GetScreenRect()
10065
10066         xstart, ystart = win_rect.x, win_rect.y
10067         xend, yend = hint_rect.x, hint_rect.y
10068
10069         step = self.GetAnimationStep()/3
10070
10071         wstep = int((win_rect.width - hint_rect.width)/step)
10072         hstep = int((win_rect.height - hint_rect.height)/step)
10073         xstep = int((win_rect.x - hint_rect.x))/step
10074         ystep = int((win_rect.y - hint_rect.y))/step
10075
10076         for i in xrange(int(step)):
10077             width, height = win_rect.width - i*wstep, win_rect.height - i*hstep
10078             x, y = xstart - i*xstep, ystart - i*ystep
10079             new_rect = wx.Rect(x, y, width, height)
10080             paneInfo.frame.SetRect(new_rect)
10081             wx.MilliSleep(10)            
10082         
10083             
10084     def SetSnapLimits(self, x, y):
10085         """
10086         Modifies the snap limits used when snapping the `managed_window` to the screen
10087         (using L{SnapToScreen}) or when snapping the floating panes to one side of the
10088         `managed_window` (using L{SnapPane}).
10089
10090         To change the limit after which the `managed_window` or the floating panes are
10091         automatically stickled to the screen border (or to the `managed_window` side),
10092         set these two variables. Default values are 15 pixels.
10093     
10094         :param `x`: the minimum horizontal distance below which the snap occurs;
10095         :param `y`: the minimum vertical distance below which the snap occurs.
10096         """
10097
10098         self._snap_limits = (x, y)
10099         self.Snap()
10100
10101
10102     def Snap(self):
10103         """
10104         Snaps the main frame to specified position on the screen.
10105
10106         :see: L{SnapToScreen}
10107         """
10108         
10109         snap, hAlign, vAlign, monitor = self._is_docked
10110         if not snap:
10111             return
10112
10113         managed_window = self.GetManagedWindow()
10114         snap_pos = self.GetSnapPosition()
10115         wnd_pos = managed_window.GetPosition()
10116         snapX, snapY = self._snap_limits
10117         
10118         if abs(snap_pos.x - wnd_pos.x) < snapX and abs(snap_pos.y - wnd_pos.y) < snapY:
10119             managed_window.SetPosition(snap_pos)
10120         
10121
10122     def SnapToScreen(self, snap=True, monitor=0, hAlign=wx.RIGHT, vAlign=wx.TOP):
10123         """
10124         Snaps the main frame to specified position on the screen.
10125
10126         :param `snap`: whether to snap the main frame or not;
10127         :param `monitor`: the monitor display in which snapping the window;
10128         :param `hAlign`: the horizontal alignment of the snapping position;
10129         :param `vAlign`: the vertical alignment of the snapping position.
10130         """
10131         
10132         if not snap:
10133             self._is_docked = (False, wx.RIGHT, wx.TOP, 0)
10134             return
10135
10136         displayCount = wx.Display.GetCount()
10137         if monitor > displayCount:
10138             raise Exception("Invalid monitor selected: you only have %d monitors"%displayCount)
10139
10140         self._is_docked = (True, hAlign, vAlign, monitor)
10141         self.GetManagedWindow().SetPosition(self.GetSnapPosition())
10142         
10143
10144     def GetSnapPosition(self):
10145         """ Returns the main frame snapping position. """
10146
10147         snap, hAlign, vAlign, monitor = self._is_docked
10148         
10149         display = wx.Display(monitor)
10150         area = display.GetClientArea()
10151         size = self.GetManagedWindow().GetSize()
10152         
10153         pos = wx.Point()
10154         if hAlign == wx.LEFT:
10155             pos.x = area.x
10156         elif hAlign == wx.CENTER:
10157             pos.x = area.x + (area.width - size.x)/2
10158         else:
10159             pos.x = area.x + area.width - size.x
10160
10161         if vAlign == wx.TOP:
10162             pos.y = area.y
10163         elif vAlign == wx.CENTER:
10164             pos.y = area.y + (area.height - size.y)/2
10165         else:
10166             pos.y = area.y + area.height - size.y
10167
10168         return pos            
10169
10170
10171     def GetAnimationStep(self):
10172         """ Returns the animation step speed (a float) to use in L{AnimateDocking}. """
10173
10174         return self._animation_step
10175
10176
10177     def SetAnimationStep(self, step):
10178         """
10179         Sets the animation step speed (a float) to use in L{AnimateDocking}.
10180
10181         :param `step`: a floating point value for the animation speed.
10182         """
10183
10184         self._animation_step = float(step)        
10185
10186         
10187     def RequestUserAttention(self, pane_window):
10188         """
10189         Requests the user attention by intermittently highlighting the pane caption.
10190
10191         :param `pane_window`: a `wx.Window` derived window, managed by the pane.
10192         """
10193                 
10194         # try to find the pane
10195         paneInfo = self.GetPane(pane_window)
10196         if not paneInfo.IsOk():
10197             raise Exception("Pane window not found")
10198
10199         dc = wx.ClientDC(self._frame)
10200
10201         # if the frame is about to be deleted, don't bother
10202         if not self._frame or self._frame.IsBeingDeleted():
10203             return
10204         
10205         if not self._frame.GetSizer():
10206             return
10207
10208         for part in self._uiparts:
10209             if part.pane == paneInfo:
10210                 self._art.RequestUserAttention(dc, self._frame, part.pane.caption, part.rect, part.pane)
10211                 self._frame.RefreshRect(part.rect, True)
10212                 break
10213
10214
10215     def StartPreviewTimer(self, toolbar):
10216         """
10217         Starts a timer for sliding in and out a minimized pane.
10218
10219         :param `toolbar`: the L{AuiToolBar} containing the minimized pane tool.
10220         """
10221
10222         toolbar_pane = self.GetPane(toolbar)
10223         toolbar_name = toolbar_pane.name
10224         
10225         pane_name = toolbar_name[0:-4]
10226         
10227         self._sliding_pane = self.GetPane(pane_name)
10228         self._sliding_rect = toolbar.GetScreenRect()
10229         self._sliding_direction = toolbar_pane.dock_direction
10230         self._sliding_frame = None
10231         
10232         self._preview_timer.Start(1000, wx.TIMER_ONE_SHOT)
10233
10234
10235     def StopPreviewTimer(self):
10236         """ Stops a timer for sliding in and out a minimized pane. """
10237
10238         if self._preview_timer.IsRunning():
10239             self._preview_timer.Stop()
10240
10241         self.SlideOut()
10242         self._sliding_pane = None
10243
10244
10245     def SlideIn(self, event):
10246         """
10247         Handles the ``wx.EVT_TIMER`` event for L{AuiManager}.
10248
10249         :param `event`: a `wx.TimerEvent` to be processed.
10250
10251         :note: This is used solely for sliding in and out minimized panes.
10252         """
10253
10254         window = self._sliding_pane.window
10255         self._sliding_frame = wx.MiniFrame(None, -1, title=_("Pane Preview"),
10256                                            style=wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP |
10257                                            wx.FRAME_NO_TASKBAR | wx.CAPTION)
10258         window.Reparent(self._sliding_frame)
10259         self._sliding_frame.SetSize((0, 0))
10260         window.Show()
10261         self._sliding_frame.Show()
10262         
10263         size = window.GetBestSize()
10264
10265         startX, startY, stopX, stopY = GetSlidingPoints(self._sliding_rect, size, self._sliding_direction)
10266         
10267         step = stopX/10
10268         window_size = 0
10269         
10270         for i in xrange(0, stopX, step):
10271             window_size = i
10272             self._sliding_frame.SetDimensions(startX, startY, window_size, stopY)
10273             self._sliding_frame.Refresh()
10274             self._sliding_frame.Update()
10275             wx.MilliSleep(10)
10276
10277         self._sliding_frame.SetDimensions(startX, startY, stopX, stopY)
10278         self._sliding_frame.Refresh()
10279         self._sliding_frame.Update()
10280         
10281
10282     def SlideOut(self):
10283         """
10284         Slides out a preview of a minimized pane.
10285
10286         :note: This is used solely for sliding in and out minimized panes.
10287         """
10288
10289         if not self._sliding_frame:
10290             return
10291
10292         window = self._sliding_frame.GetChildren()[0]
10293         size = window.GetBestSize()
10294         
10295         startX, startY, stopX, stopY = GetSlidingPoints(self._sliding_rect, size, self._sliding_direction)
10296
10297         step = stopX/10
10298         window_size = 0
10299         
10300         for i in xrange(stopX, 0, -step):
10301             window_size = i
10302             self._sliding_frame.SetDimensions(startX, startY, window_size, stopY)
10303             self._sliding_frame.Refresh()
10304             self._sliding_frame.Update()
10305             self._frame.RefreshRect(wx.Rect(startX+window_size, startY, step, stopY))
10306             self._frame.Update()
10307             wx.MilliSleep(10)
10308
10309         self._sliding_frame.SetDimensions(startX, startY, 0, stopY)
10310
10311         window.Hide()
10312         window.Reparent(self._frame)
10313
10314         self._sliding_frame.Hide()
10315         self._sliding_frame.Destroy()
10316         self._sliding_frame = None
10317         self._sliding_pane = None
10318         
10319
10320 class AuiManager_DCP(AuiManager):
10321     """
10322     A class similar to L{AuiManager} but with a Dummy Center Pane (**DCP**).
10323     The code for this class is still flickery due to the call to `wx.CallAfter`
10324     and the double-update call.
10325     """
10326     
10327     def __init__(self, *args, **keys):
10328
10329         AuiManager.__init__(self, *args, **keys)
10330         self.hasDummyPane = False
10331         
10332
10333     def _createDummyPane(self):
10334         """ Creates a Dummy Center Pane (**DCP**). """
10335
10336         if self.hasDummyPane:
10337             return
10338
10339         self.hasDummyPane = True
10340         dummy = wx.Panel(self.GetManagedWindow())
10341         info = AuiPaneInfo().CenterPane().NotebookDockable(True).Name('dummyCenterPane').DestroyOnClose(True)
10342         self.AddPane(dummy, info)
10343
10344
10345     def _destroyDummyPane(self):
10346         """ Destroys the Dummy Center Pane (**DCP**). """
10347
10348         if not self.hasDummyPane:
10349             return
10350         
10351         self.hasDummyPane = False
10352         self.ClosePane(self.GetPane('dummyCenterPane'))
10353
10354         
10355     def Update(self):
10356         """
10357         This method is called after any number of changes are made to any of the
10358         managed panes. L{Update} must be invoked after L{AuiManager.AddPane} or L{AuiManager.InsertPane} are
10359         called in order to "realize" or "commit" the changes.
10360
10361         In addition, any number of changes may be made to L{AuiPaneInfo} structures
10362         (retrieved with L{AuiManager.GetPane}), but to realize the changes, L{Update}
10363         must be called. This construction allows pane flicker to be avoided by updating
10364         the whole layout at one time.
10365         """
10366         
10367         AuiManager.Update(self)
10368
10369         # check if there's already a center pane (except our dummy pane)
10370         dummyCenterPane = self.GetPane('dummyCenterPane')
10371         haveCenterPane = any((pane != dummyCenterPane) and (pane.dock_direction == AUI_DOCK_CENTER) and
10372                              not pane.IsFloating() and pane.IsShown() for pane in self.GetAllPanes())
10373         if haveCenterPane:
10374             if self.hasDummyPane:
10375                 # there's our dummy pane and also another center pane, therefor let's remove our dummy
10376                 def do():
10377                     self._destroyDummyPane()
10378                     self.Update()
10379                 wx.CallAfter(do)
10380         else:
10381             # if we get here, there's no center pane, create our dummy
10382             if not self.hasDummyPane:
10383                 self._createDummyPane()
10384
10385