1 # --------------------------------------------------------------------------- #
2 # AUI Library wxPython IMPLEMENTATION
4 # Original C++ Code From Kirix (wxAUI). You Can Find It At:
6 # License: wxWidgets license
8 # http:#www.kirix.com/en/community/opensource/wxaui/about_wxaui.html
10 # Current wxAUI Version Tracked: wxWidgets 2.9.0 SVN HEAD
15 # Andrea Gavana, @ 23 Dec 2005
16 # Latest Revision: 10 Mar 2011, 15.00 GMT
18 # For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
21 # andrea.gavana@gmail.com
24 # Or, Obviously, To The wxPython Mailing List!!!
27 # --------------------------------------------------------------------------- #
33 framemanager is the central module of the AUI class framework.
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.
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()`.
47 Panes can be added quite easily::
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"))
57 Later on, the positions can be modified easily. The following will float an
58 existing pane in a tool window::
60 self._mgr.GetPane(text1).Float()
63 Layers, Rows and Directions, Positions
64 ======================================
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.
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
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.
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.
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`).
92 __author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
93 __date__ = "31 March 2009"
107 from aui_utilities import Clip, PaneCreateStippleBitmap, GetDockingImage, GetSlidingPoints
109 from aui_constants import *
111 # Define this as a translation function
112 _ = wx.GetTranslation
115 if wx.Platform == "__WXMSW__":
122 # wxPython version string
123 _VERSION_STRING = wx.VERSION_STRING
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()
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. """
170 # ---------------------------------------------------------------------------- #
172 class AuiDockInfo(object):
173 """ A class to store all properties of a dock. """
177 Default class constructor.
178 Used internally, do not call it in your code!
181 object.__init__(self)
183 self.dock_direction = 0
188 self.resizable = True
191 self.rect = wx.Rect()
197 Returns whether a dock is valid or not.
199 In order to be valid, a dock needs to have a non-zero `dock_direction`.
202 return self.dock_direction != 0
205 def IsHorizontal(self):
206 """ Returns whether the dock is horizontal or not. """
208 return self.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]
211 def IsVertical(self):
212 """ Returns whether the dock is vertical or not. """
214 return self.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT, AUI_DOCK_CENTER]
217 # ---------------------------------------------------------------------------- #
219 class AuiDockingGuideInfo(object):
220 """ A class which holds information about VS2005 docking guide windows. """
222 def __init__(self, other=None):
224 Default class constructor.
225 Used internally, do not call it in your code!
227 :param `other`: another instance of L{AuiDockingGuideInfo}.
233 # window representing the docking target
235 # dock direction (top, bottom, left, right, center)
236 self.dock_direction = AUI_DOCK_NONE
239 def Assign(self, other):
241 Assigns the properties of the `other` L{AuiDockingGuideInfo} to `self`.
243 :param `other`: another instance of L{AuiDockingGuideInfo}.
246 self.host = other.host
247 self.dock_direction = other.dock_direction
252 Hosts a docking guide window.
254 :param `h`: an instance of L{AuiSingleDockingGuide} or L{AuiCenterDockingGuide}.
262 """ Sets the guide window to left docking. """
264 self.dock_direction = AUI_DOCK_LEFT
269 """ Sets the guide window to right docking. """
271 self.dock_direction = AUI_DOCK_RIGHT
276 """ Sets the guide window to top docking. """
278 self.dock_direction = AUI_DOCK_TOP
283 """ Sets the guide window to bottom docking. """
285 self.dock_direction = AUI_DOCK_BOTTOM
290 """ Sets the guide window to center docking. """
292 self.dock_direction = AUI_DOCK_CENTER
297 """ Sets the guide window to centre docking. """
299 self.dock_direction = AUI_DOCK_CENTRE
303 # ---------------------------------------------------------------------------- #
305 class AuiDockUIPart(object):
306 """ A class which holds attributes for a UI part in the interface. """
320 Default class constructor.
321 Used internally, do not call it in your code!
324 self.orientation = wx.VERTICAL
326 self.rect = wx.Rect()
329 # ---------------------------------------------------------------------------- #
331 class AuiPaneButton(object):
332 """ A simple class which describes the caption pane button attributes. """
334 def __init__(self, button_id):
336 Default class constructor.
337 Used internally, do not call it in your code!
339 :param `button_id`: the pane button identifier.
342 self.button_id = button_id
345 # ---------------------------------------------------------------------------- #
347 # event declarations/classes
349 class AuiManagerEvent(wx.PyCommandEvent):
350 """ A specialized command event class for events sent by L{AuiManager}. """
352 def __init__(self, eventType, id=1):
354 Default class constructor.
356 :param `eventType`: the event kind;
357 :param `id`: the event identification number.
360 wx.PyCommandEvent.__init__(self, eventType, id)
365 self.veto_flag = False
366 self.canveto_flag = True
370 def SetManager(self, mgr):
372 Associates a L{AuiManager} to the current event.
374 :param `mgr`: an instance of L{AuiManager}.
380 def SetDC(self, pdc):
382 Associates a `wx.DC` device context to this event.
384 :param `pdc`: a `wx.DC` device context object.
390 def SetPane(self, p):
392 Associates a L{AuiPaneInfo} instance to this event.
394 :param `p`: a L{AuiPaneInfo} instance.
400 def SetButton(self, b):
402 Associates a L{AuiPaneButton} instance to this event.
404 :param `b`: a L{AuiPaneButton} instance.
410 def GetManager(self):
411 """ Returns the associated L{AuiManager} (if any). """
417 """ Returns the associated `wx.DC` device context (if any). """
423 """ Returns the associated L{AuiPaneInfo} structure (if any). """
429 """ Returns the associated L{AuiPaneButton} instance (if any). """
434 def Veto(self, veto=True):
436 Prevents the change announced by this event from happening.
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.
442 :param `veto`: ``True`` to veto the event, ``False`` otherwise.
445 self.veto_flag = veto
449 """ Returns whether the event has been vetoed or not. """
451 return self.veto_flag
454 def SetCanVeto(self, can_veto):
456 Sets whether the event can be vetoed or not.
458 :param `can_veto`: a bool flag. ``True`` if the event can be vetoed, ``False`` otherwise.
461 self.canveto_flag = can_veto
465 """ Returns whether the event can be vetoed and has been vetoed. """
467 return self.canveto_flag and self.veto_flag
470 # ---------------------------------------------------------------------------- #
472 class AuiPaneInfo(object):
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.
480 optionFloating = 2**0
482 optionLeftDockable = 2**2
483 optionRightDockable = 2**3
484 optionTopDockable = 2**4
485 optionBottomDockable = 2**5
486 optionFloatable = 2**6
488 optionResizable = 2**8
489 optionPaneBorder = 2**9
490 optionCaption = 2**10
491 optionGripper = 2**11
492 optionDestroyOnClose = 2**12
493 optionToolbar = 2**13
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
505 optionCaptionLeft = 2**25
508 buttonMaximize = 2**27
509 buttonMinimize = 2**28
512 buttonCustom1 = 2**30
513 buttonCustom2 = 2**31
514 buttonCustom3 = 2**32
516 savedHiddenState = 2**33 # used internally
517 actionPane = 2**34 # used internally
518 wasMaximized = 2**35 # used internally
519 needsRestore = 2**36 # used internally
523 """ Default class constructor. """
528 self.dock_direction = AUI_DOCK_LEFT
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
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
554 def dock_direction_get(self):
556 Getter for the `dock_direction`.
558 :see: L{dock_direction_set} for a set of valid docking directions.
561 if self.IsMaximized():
562 return AUI_DOCK_CENTER
564 return self._dock_direction
567 def dock_direction_set(self, value):
569 Setter for the `dock_direction`.
571 :param `value`: the docking direction. This cab ne one of the following bits:
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 ============================ ======= =============================================
588 self._dock_direction = value
590 dock_direction = property(dock_direction_get, dock_direction_set)
594 Returns ``True`` if the L{AuiPaneInfo} structure is valid.
596 :note: A pane structure is valid if it has an associated window.
599 return self.window != None
602 def IsMaximized(self):
603 """ Returns ``True`` if the pane is maximized. """
605 return self.HasFlag(self.optionMaximized)
608 def IsMinimized(self):
609 """ Returns ``True`` if the pane is minimized. """
611 return self.HasFlag(self.optionMinimized)
615 """ Returns ``True`` if the pane cannot be resized. """
617 return not self.HasFlag(self.optionResizable)
620 def IsResizeable(self):
621 """ Returns ``True`` if the pane can be resized. """
623 return self.HasFlag(self.optionResizable)
627 """ Returns ``True`` if the pane is currently shown. """
629 return not self.HasFlag(self.optionHidden)
632 def IsFloating(self):
633 """ Returns ``True`` if the pane is floating. """
635 return self.HasFlag(self.optionFloating)
639 """ Returns ``True`` if the pane is docked. """
641 return not self.HasFlag(self.optionFloating)
645 """ Returns ``True`` if the pane contains a toolbar. """
647 return self.HasFlag(self.optionToolbar)
650 def IsTopDockable(self):
652 Returns ``True`` if the pane can be docked at the top
653 of the managed frame.
656 return self.HasFlag(self.optionTopDockable)
659 def IsBottomDockable(self):
661 Returns ``True`` if the pane can be docked at the bottom
662 of the managed frame.
665 return self.HasFlag(self.optionBottomDockable)
668 def IsLeftDockable(self):
670 Returns ``True`` if the pane can be docked at the left
671 of the managed frame.
674 return self.HasFlag(self.optionLeftDockable)
677 def IsRightDockable(self):
679 Returns ``True`` if the pane can be docked at the right
680 of the managed frame.
683 return self.HasFlag(self.optionRightDockable)
686 def IsDockable(self):
687 """ Returns ``True`` if the pane can be docked. """
689 return self.IsTopDockable() or self.IsBottomDockable() or self.IsLeftDockable() or \
690 self.IsRightDockable() or self.IsNotebookDockable()
693 def IsFloatable(self):
695 Returns ``True`` if the pane can be undocked and displayed as a
699 return self.HasFlag(self.optionFloatable)
704 Returns ``True`` if the docked frame can be undocked or moved to
705 another dock position.
708 return self.HasFlag(self.optionMovable)
711 def IsDestroyOnClose(self):
713 Returns ``True`` if the pane should be destroyed when it is closed.
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.
720 return self.HasFlag(self.optionDestroyOnClose)
723 def IsNotebookDockable(self):
725 Returns ``True`` if a pane can be docked on top to another to create a
729 return self.HasFlag(self.optionNotebookDockable)
732 def IsTopSnappable(self):
733 """ Returns ``True`` if the pane can be snapped at the top of the managed frame. """
735 return self.HasFlag(self.optionTopSnapped)
738 def IsBottomSnappable(self):
739 """ Returns ``True`` if the pane can be snapped at the bottom of the managed frame. """
741 return self.HasFlag(self.optionBottomSnapped)
744 def IsLeftSnappable(self):
745 """ Returns ``True`` if the pane can be snapped on the left of the managed frame. """
747 return self.HasFlag(self.optionLeftSnapped)
750 def IsRightSnappable(self):
751 """ Returns ``True`` if the pane can be snapped on the right of the managed frame. """
753 return self.HasFlag(self.optionRightSnapped)
756 def IsSnappable(self):
757 """ Returns ``True`` if the pane can be snapped. """
759 return self.IsTopSnappable() or self.IsBottomSnappable() or self.IsLeftSnappable() or \
760 self.IsRightSnappable()
764 """ Returns ``True`` if the floating pane has a "fly-out" effect. """
766 return self.HasFlag(self.optionFlyOut)
769 def HasCaption(self):
770 """ Returns ``True`` if the pane displays a caption. """
772 return self.HasFlag(self.optionCaption)
775 def HasCaptionLeft(self):
776 """ Returns ``True`` if the pane displays a caption on the left (rotated by 90 degrees). """
778 return self.HasFlag(self.optionCaptionLeft)
781 def HasGripper(self):
782 """ Returns ``True`` if the pane displays a gripper. """
784 return self.HasFlag(self.optionGripper)
788 """ Returns ``True`` if the pane displays a border. """
790 return self.HasFlag(self.optionPaneBorder)
793 def HasCloseButton(self):
794 """ Returns ``True`` if the pane displays a button to close the pane. """
796 return self.HasFlag(self.buttonClose)
799 def HasMaximizeButton(self):
800 """ Returns ``True`` if the pane displays a button to maximize the pane. """
802 return self.HasFlag(self.buttonMaximize)
805 def HasMinimizeButton(self):
806 """ Returns ``True`` if the pane displays a button to minimize the pane. """
808 return self.HasFlag(self.buttonMinimize)
811 def GetMinimizeMode(self):
813 Returns the minimization style for this pane.
815 Possible return values are:
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 ============================== ========= ==============================
832 The flags can be filtered with the following masks:
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 ============================== ========= ==============================
843 return self.minimize_mode
846 def HasPinButton(self):
847 """ Returns ``True`` if the pane displays a button to float the pane. """
849 return self.HasFlag(self.buttonPin)
852 def HasGripperTop(self):
853 """ Returns ``True`` if the pane displays a gripper at the top. """
855 return self.HasFlag(self.optionGripperTop)
860 Associate a `wx.Window` derived window to this pane.
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.
866 :param `w`: a `wx.Window` derived window.
873 def Name(self, name):
875 Sets the name of the pane so it can be referenced in lookup functions.
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.
880 :param `name`: a string specifying the pane name.
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.
891 def Caption(self, caption):
893 Sets the caption of the pane.
895 :param `caption`: a string specifying the pane caption.
898 self.caption = caption
904 Sets the pane dock position to the left side of the frame.
906 :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_LEFT`` as
910 self.dock_direction = AUI_DOCK_LEFT
916 Sets the pane dock position to the right side of the frame.
918 :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_RIGHT`` as
922 self.dock_direction = AUI_DOCK_RIGHT
928 Sets the pane dock position to the top of the frame.
930 :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_TOP`` as
934 self.dock_direction = AUI_DOCK_TOP
940 Sets the pane dock position to the bottom of the frame.
942 :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_BOTTOM`` as
946 self.dock_direction = AUI_DOCK_BOTTOM
952 Sets the pane to the center position of the frame.
954 The centre pane is the space in the middle after all border panes (left, top,
955 right, bottom) are subtracted from the layout.
957 :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_CENTER`` as
961 self.dock_direction = AUI_DOCK_CENTER
967 Sets the pane to the center position of the frame.
969 The centre pane is the space in the middle after all border panes (left, top,
970 right, bottom) are subtracted from the layout.
972 :note: This is the same thing as calling L{Direction} with ``AUI_DOCK_CENTRE`` as
976 self.dock_direction = AUI_DOCK_CENTRE
980 def Direction(self, direction):
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`.
986 :param `direction`: the direction of the docked pane.
988 :see: L{dock_direction_set} for a list of valid docking directions.
991 self.dock_direction = direction
995 def Layer(self, layer):
997 Determines the layer of the docked pane.
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.
1003 :param `layer`: the layer of the docked pane.
1006 self.dock_layer = layer
1012 Determines the row of the docked pane.
1014 :param `row`: the row of the docked pane.
1021 def Position(self, pos):
1023 Determines the position of the docked pane.
1025 :param `pos`: the position of the docked pane.
1032 def MinSize(self, arg1=None, arg2=None):
1034 Sets the minimum size of the pane.
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.
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).
1043 if isinstance(arg1, wx.Size):
1044 ret = self.MinSize1(arg1)
1045 elif isinstance(arg1, types.TupleType):
1046 ret = self.MinSize1(wx.Size(*arg1))
1048 ret = self.MinSize2(arg1, arg2)
1053 def MinSize1(self, size):
1055 Sets the minimum size of the pane.
1057 :see: L{MinSize} for an explanation of input parameters.
1059 self.min_size = size
1063 def MinSize2(self, x, y):
1065 Sets the minimum size of the pane.
1067 :see: L{MinSize} for an explanation of input parameters.
1070 self.min_size = wx.Size(x, y)
1074 def MaxSize(self, arg1=None, arg2=None):
1076 Sets the maximum size of the pane.
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.
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).
1085 if isinstance(arg1, wx.Size):
1086 ret = self.MaxSize1(arg1)
1087 elif isinstance(arg1, types.TupleType):
1088 ret = self.MaxSize1(wx.Size(*arg1))
1090 ret = self.MaxSize2(arg1, arg2)
1095 def MaxSize1(self, size):
1097 Sets the maximum size of the pane.
1099 :see: L{MaxSize} for an explanation of input parameters.
1102 self.max_size = size
1106 def MaxSize2(self, x, y):
1108 Sets the maximum size of the pane.
1110 :see: L{MaxSize} for an explanation of input parameters.
1113 self.max_size.Set(x,y)
1117 def BestSize(self, arg1=None, arg2=None):
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.
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.
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).
1129 if isinstance(arg1, wx.Size):
1130 ret = self.BestSize1(arg1)
1131 elif isinstance(arg1, types.TupleType):
1132 ret = self.BestSize1(wx.Size(*arg1))
1134 ret = self.BestSize2(arg1, arg2)
1139 def BestSize1(self, size):
1141 Sets the best size of the pane.
1143 :see: L{BestSize} for an explanation of input parameters.
1146 self.best_size = size
1150 def BestSize2(self, x, y):
1152 Sets the best size of the pane.
1154 :see: L{BestSize} for an explanation of input parameters.
1157 self.best_size.Set(x,y)
1161 def FloatingPosition(self, pos):
1163 Sets the position of the floating pane.
1165 :param `pos`: a `wx.Point` or a tuple indicating the pane floating position.
1168 self.floating_pos = wx.Point(*pos)
1172 def FloatingSize(self, size):
1174 Sets the size of the floating pane.
1176 :param `size`: a `wx.Size` or a tuple indicating the pane floating size.
1179 self.floating_size = wx.Size(*size)
1184 """ Makes the pane take up the full area."""
1186 return self.SetFlag(self.optionMaximized, True)
1191 Makes the pane minimized in a L{AuiToolBar}.
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.
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.
1202 return self.SetFlag(self.optionMinimized, True)
1205 def MinimizeMode(self, mode):
1207 Sets the expected minimized mode if the MinimizeButton() is visible.
1209 The minimized pane can have a specific position in the work space:
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 ============================== ========= ==============================
1221 The caption of the minimized pane can be displayed in different modes:
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 ============================== ========= ==============================
1233 self.minimize_mode = mode
1238 """ Is the reverse of L{Maximize} and L{Minimize}."""
1240 return self.SetFlag(self.optionMaximized or self.optionMinimized, False)
1245 Forces a pane to be fixed size so that it cannot be resized.
1246 After calling L{Fixed}, L{IsFixed} will return ``True``.
1249 return self.SetFlag(self.optionResizable, False)
1252 def Resizable(self, resizable=True):
1254 Allows a pane to be resizable if `resizable` is ``True``, and forces
1255 it to be a fixed size if `resizeable` is ``False``.
1257 If `resizable` is ``False``, this is simply an antonym for L{Fixed}.
1259 :param `resizable`: whether the pane will be resizeable or not.
1262 return self.SetFlag(self.optionResizable, resizable)
1265 def Transparent(self, alpha):
1267 Makes the pane transparent when floating.
1269 :param `alpha`: an integer value between 0 and 255 for pane transparency.
1272 if alpha < 0 or alpha > 255:
1273 raise Exception("Invalid transparency value (%s)"%repr(alpha))
1275 self.transparent = alpha
1276 self.needsTransparency = True
1281 Indicates that a pane should be docked. It is the opposite of L{Float}.
1284 if self.IsNotebookPage():
1285 self.notebook_id = -1
1286 self.dock_direction = AUI_DOCK_NONE
1288 return self.SetFlag(self.optionFloating, False)
1293 Indicates that a pane should be floated. It is the opposite of L{Dock}.
1296 if self.IsNotebookPage():
1297 self.notebook_id = -1
1298 self.dock_direction = AUI_DOCK_NONE
1300 return self.SetFlag(self.optionFloating, True)
1305 Indicates that a pane should be hidden.
1307 Calling L{Show} (``False``) achieve the same effect.
1310 return self.SetFlag(self.optionHidden, True)
1313 def Show(self, show=True):
1315 Indicates that a pane should be shown.
1317 :param `show`: whether the pane should be shown or not.
1320 return self.SetFlag(self.optionHidden, not show)
1323 # By defaulting to 1000, the tab will get placed at the end
1324 def NotebookPage(self, id, tab_position=1000):
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}.
1329 :param `id`: the notebook id;
1330 :param `tab_position`: the tab number of the pane once docked in a notebook.
1333 # Remove any floating frame
1335 self.notebook_id = id
1336 self.dock_pos = tab_position
1339 self.dock_direction = AUI_DOCK_NOTEBOOK_PAGE
1344 def NotebookControl(self, id):
1346 Forces a pane to be a notebook control (L{AuiNotebook}).
1348 :param `id`: the notebook id.
1351 self.notebook_id = id
1355 if self.dock_direction == AUI_DOCK_NOTEBOOK_PAGE:
1356 self.dock_direction = AUI_DOCK_NONE
1361 def HasNotebook(self):
1362 """ Returns whether a pane has a L{AuiNotebook} or not. """
1364 return self.notebook_id >= 0
1367 def IsNotebookPage(self):
1368 """ Returns whether the pane is a notebook page in a L{AuiNotebook}. """
1370 return self.notebook_id >= 0 and self.dock_direction == AUI_DOCK_NOTEBOOK_PAGE
1373 def IsNotebookControl(self):
1374 """ Returns whether the pane is a notebook control (L{AuiNotebook}). """
1376 return not self.IsNotebookPage() and self.HasNotebook()
1379 def SetNameFromNotebookId(self):
1380 """ Sets the pane name once docked in a L{AuiNotebook} using the notebook id. """
1382 if self.notebook_id >= 0:
1383 self.name = "__notebook_%d"%self.notebook_id
1388 def CaptionVisible(self, visible=True, left=False):
1390 Indicates that a pane caption should be visible. If `visible` is ``False``, no pane
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.
1398 self.SetFlag(self.optionCaption, False)
1399 return self.SetFlag(self.optionCaptionLeft, visible)
1401 self.SetFlag(self.optionCaptionLeft, False)
1402 return self.SetFlag(self.optionCaption, visible)
1405 def PaneBorder(self, visible=True):
1407 Indicates that a border should be drawn for the pane.
1409 :param `visible`: whether the pane border should be visible or not.
1412 return self.SetFlag(self.optionPaneBorder, visible)
1415 def Gripper(self, visible=True):
1417 Indicates that a gripper should be drawn for the pane.
1419 :param `visible`: whether the gripper should be visible or not.
1422 return self.SetFlag(self.optionGripper, visible)
1425 def GripperTop(self, attop=True):
1427 Indicates that a gripper should be drawn at the top of the pane.
1429 :param `attop`: whether the gripper should be drawn at the top or not.
1432 return self.SetFlag(self.optionGripperTop, attop)
1435 def CloseButton(self, visible=True):
1437 Indicates that a close button should be drawn for the pane.
1439 :param `visible`: whether the close button should be visible or not.
1442 return self.SetFlag(self.buttonClose, visible)
1445 def MaximizeButton(self, visible=True):
1447 Indicates that a maximize button should be drawn for the pane.
1449 :param `visible`: whether the maximize button should be visible or not.
1452 return self.SetFlag(self.buttonMaximize, visible)
1455 def MinimizeButton(self, visible=True):
1457 Indicates that a minimize button should be drawn for the pane.
1459 :param `visible`: whether the minimize button should be visible or not.
1462 return self.SetFlag(self.buttonMinimize, visible)
1465 def PinButton(self, visible=True):
1467 Indicates that a pin button should be drawn for the pane.
1469 :param `visible`: whether the pin button should be visible or not.
1472 return self.SetFlag(self.buttonPin, visible)
1475 def DestroyOnClose(self, b=True):
1477 Indicates whether a pane should be destroyed when it is closed.
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.
1483 :param `b`: whether the pane should be destroyed when it is closed or not.
1486 return self.SetFlag(self.optionDestroyOnClose, b)
1489 def TopDockable(self, b=True):
1491 Indicates whether a pane can be docked at the top of the frame.
1493 :param `b`: whether the pane can be docked at the top or not.
1496 return self.SetFlag(self.optionTopDockable, b)
1499 def BottomDockable(self, b=True):
1501 Indicates whether a pane can be docked at the bottom of the frame.
1503 :param `b`: whether the pane can be docked at the bottom or not.
1506 return self.SetFlag(self.optionBottomDockable, b)
1509 def LeftDockable(self, b=True):
1511 Indicates whether a pane can be docked on the left of the frame.
1513 :param `b`: whether the pane can be docked at the left or not.
1516 return self.SetFlag(self.optionLeftDockable, b)
1519 def RightDockable(self, b=True):
1521 Indicates whether a pane can be docked on the right of the frame.
1523 :param `b`: whether the pane can be docked at the right or not.
1526 return self.SetFlag(self.optionRightDockable, b)
1529 def Floatable(self, b=True):
1531 Sets whether the user will be able to undock a pane and turn it
1532 into a floating window.
1534 :param `b`: whether the pane can be floated or not.
1537 return self.SetFlag(self.optionFloatable, b)
1540 def Movable(self, b=True):
1542 Indicates whether a pane can be moved.
1544 :param `b`: whether the pane can be moved or not.
1547 return self.SetFlag(self.optionMovable, b)
1550 def NotebookDockable(self, b=True):
1552 Indicates whether a pane can be docked in an automatic L{AuiNotebook}.
1554 :param `b`: whether the pane can be docked in a notebook or not.
1557 return self.SetFlag(self.optionNotebookDockable, b)
1560 def DockFixed(self, b=True):
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.
1566 :param `b`: whether the pane will have a resize sash or not.
1569 return self.SetFlag(self.optionDockFixed, b)
1572 def Dockable(self, b=True):
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} .
1577 :param `b`: whether the frame can be docked or not.
1580 return self.TopDockable(b).BottomDockable(b).LeftDockable(b).RightDockable(b)
1583 def TopSnappable(self, b=True):
1585 Indicates whether a pane can be snapped at the top of the main frame.
1587 :param `b`: whether the pane can be snapped at the top of the main frame or not.
1590 return self.SetFlag(self.optionTopSnapped, b)
1593 def BottomSnappable(self, b=True):
1595 Indicates whether a pane can be snapped at the bottom of the main frame.
1597 :param `b`: whether the pane can be snapped at the bottom of the main frame or not.
1600 return self.SetFlag(self.optionBottomSnapped, b)
1603 def LeftSnappable(self, b=True):
1605 Indicates whether a pane can be snapped on the left of the main frame.
1607 :param `b`: whether the pane can be snapped at the left of the main frame or not.
1610 return self.SetFlag(self.optionLeftSnapped, b)
1613 def RightSnappable(self, b=True):
1615 Indicates whether a pane can be snapped on the right of the main frame.
1617 :param `b`: whether the pane can be snapped at the right of the main frame or not.
1620 return self.SetFlag(self.optionRightSnapped, b)
1623 def Snappable(self, b=True):
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} .
1628 :param `b`: whether the pane can be snapped on the main frame or not.
1631 return self.TopSnappable(b).BottomSnappable(b).LeftSnappable(b).RightSnappable(b)
1634 def FlyOut(self, b=True):
1636 Indicates whether a pane, when floating, has a "fly-out" effect
1637 (i.e., floating panes which only show themselves when moused over).
1639 :param `b`: whether the pane can be snapped on the main frame or not.
1642 return self.SetFlag(self.optionFlyOut, b)
1645 # Copy over the members that pertain to docking position
1646 def SetDockPos(self, source):
1648 Copies the `source` pane members that pertain to docking position to `self`.
1650 :param `source`: the source pane from where to copy the attributes.
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)
1665 def DefaultPane(self):
1666 """ Specifies that the pane should adopt the default pane settings. """
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
1680 def CentrePane(self):
1682 Specifies that the pane should adopt the default center pane settings.
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.
1688 return self.CenterPane()
1691 def CenterPane(self):
1693 Specifies that the pane should adopt the default center pane settings.
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.
1700 return self.Center().PaneBorder().Resizable()
1703 def ToolbarPane(self):
1704 """ Specifies that the pane should adopt the default toolbar pane settings. """
1709 state |= (self.optionToolbar | self.optionGripper)
1710 state &= ~(self.optionResizable | self.optionCaption | self.optionCaptionLeft)
1712 if self.dock_layer == 0:
1713 self.dock_layer = 10
1720 def Icon(self, icon):
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
1726 :param icon: an icon to draw on the caption space, or ``None``.
1736 def SetFlag(self, flag, option_state):
1738 Turns the property given by `flag` on or off with the `option_state`
1741 :param `flag`: the property to set;
1742 :param `option_state`: either ``True`` or ``False``.
1754 if flag in [self.buttonClose, self.buttonMaximize, self.buttonMinimize, self.buttonPin]:
1760 def HasFlag(self, flag):
1762 Returns ``True`` if the the property specified by flag is active for the pane.
1764 :param `flag`: the property to check for activity.
1767 return (self.state & flag and [True] or [False])[0]
1770 def ResetButtons(self):
1772 Resets all the buttons and recreates them from scratch depending on the
1773 L{AuiPaneInfo} flags.
1776 floating = self.HasFlag(self.optionFloating)
1779 if not floating and self.HasMinimizeButton():
1780 button = AuiPaneButton(AUI_BUTTON_MINIMIZE)
1781 self.buttons.append(button)
1783 if not floating and self.HasMaximizeButton():
1784 button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE)
1785 self.buttons.append(button)
1787 if not floating and self.HasPinButton():
1788 button = AuiPaneButton(AUI_BUTTON_PIN)
1789 self.buttons.append(button)
1791 if self.HasCloseButton():
1792 button = AuiPaneButton(AUI_BUTTON_CLOSE)
1793 self.buttons.append(button)
1796 def CountButtons(self):
1797 """ Returns the number of visible buttons in the docked pane. """
1801 if self.HasCaption() or self.HasCaptionLeft():
1802 if isinstance(wx.GetTopLevelParent(self.window), AuiFloatingFrame):
1805 if self.HasCloseButton():
1807 if self.HasMaximizeButton():
1809 if self.HasMinimizeButton():
1811 if self.HasPinButton():
1817 def IsHorizontal(self):
1818 """ Returns ``True`` if the pane `dock_direction` is horizontal. """
1820 return self.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]
1822 def IsVertical(self):
1823 """ Returns ``True`` if the pane `dock_direction` is vertical. """
1825 return self.dock_direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT]
1828 # Null AuiPaneInfo reference
1829 NonePaneInfo = AuiPaneInfo()
1832 # ---------------------------------------------------------------------------- #
1834 class AuiDockingGuide(wx.Frame):
1835 """ Base class for L{AuiCenterDockingGuide} and L{AuiSingleDockingGuide}."""
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"):
1841 Default class constructor. Used internally, do not call it in your code!
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.
1855 wx.Frame.__init__(self, parent, id, title, pos, size, style, name=name)
1858 def HitTest(self, x, y):
1860 To be overridden by parent classes.
1862 :param `x`: the `x` mouse position;
1863 :param `y`: the `y` mouse position.
1869 def ValidateNotebookDocking(self, valid):
1871 To be overridden by parent classes.
1873 :param `valid`: whether a pane can be docked on top to another to form an automatic
1879 # ============================================================================
1881 # ============================================================================
1883 # ---------------------------------------------------------------------------
1884 # AuiDockingGuideWindow
1885 # ---------------------------------------------------------------------------
1887 class AuiDockingGuideWindow(wx.Window):
1888 """ Target class for L{AuiSingleDockingGuide} and L{AuiCenterDockingGuide}. """
1890 def __init__(self, parent, rect, direction=0, center=False, useAero=False):
1892 Default class constructor. Used internally, do not call it in your code!
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``,
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.
1903 wx.Window.__init__(self, parent, -1, rect.GetPosition(), rect.GetSize(), wx.NO_BORDER)
1905 self._direction = direction
1906 self._center = center
1908 self._useAero = useAero
1910 self._bmp_unfocus, self._bmp_focus = GetDockingImage(direction, useAero, center)
1912 self._currentImage = self._bmp_unfocus
1913 self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
1915 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
1916 self.Bind(wx.EVT_PAINT, self.OnPaint)
1919 def SetValid(self, valid):
1921 Sets the docking direction as valid or invalid.
1923 :param `valid`: whether the docking direction is allowed or not.
1930 """ Returns whether the docking direction is valid. """
1935 def OnEraseBackground(self, event):
1937 Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{AuiDockingGuideWindow}.
1939 :param `event`: a `wx.EraseEvent` to be processed.
1941 :note: This is intentionally empty to reduce flickering while drawing.
1947 def DrawBackground(self, dc):
1949 Draws the docking guide background.
1951 :param `dc`: a `wx.DC` device context object.
1954 rect = self.GetClientRect()
1956 dc.SetPen(wx.TRANSPARENT_PEN)
1957 dc.SetBrush(wx.Brush(colourTargetBackground))
1958 dc.DrawRectangleRect(rect)
1960 dc.SetPen(wx.Pen(colourTargetBorder))
1962 left = rect.GetLeft()
1964 right = rect.GetRight()
1965 bottom = rect.GetBottom()
1967 if self._direction != wx.CENTER:
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)
1978 dc.SetPen(wx.Pen(colourTargetShade))
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)
1986 def DrawDottedLine(self, dc, point, length, vertical):
1988 Draws a dotted line (not used if the docking guide images are ok).
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.
1996 for i in xrange(0, length, 2):
1997 dc.DrawPoint(point.x, point.y)
2004 def DrawIcon(self, dc):
2006 Draws the docking guide icon (not used if the docking guide images are ok).
2008 :param `dc`: a `wx.DC` device context object.
2011 rect = wx.Rect(*self.GetClientRect())
2016 dc.SetPen(wx.Pen(colourIconBorder))
2017 dc.SetBrush(wx.Brush(colourIconBackground))
2018 dc.DrawRectangleRect(rect)
2020 right1 = rect.GetRight() + 1
2021 bottom1 = rect.GetBottom() + 1
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)
2029 if self._direction == wx.TOP:
2030 rect.height -= rect.height / 2
2031 point = rect.GetBottomLeft()
2034 elif self._direction == wx.LEFT:
2035 rect.width -= rect.width / 2
2036 point = rect.GetTopRight()
2037 length = rect.height
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
2045 elif self._direction == wx.BOTTOM:
2046 rect.y += rect.height / 2
2047 rect.height -= rect.height / 2
2048 point = rect.GetTopLeft()
2051 elif self._direction == wx.CENTER:
2053 point = rect.GetTopLeft()
2056 dc.GradientFillLinear(rect, colourIconDockingPart1,
2057 colourIconDockingPart2, self._direction)
2059 dc.SetPen(wx.Pen(colourIconBorder))
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)
2067 elif self._direction in [wx.TOP, wx.BOTTOM]:
2068 self.DrawDottedLine(dc, point, length, False)
2071 self.DrawDottedLine(dc, point, length, True)
2074 def DrawArrow(self, dc):
2076 Draws the docking guide arrow icon (not used if the docking guide images are ok).
2078 :param `dc`: a `wx.DC` device context object.
2081 rect = self.GetClientRect()
2084 point.x = (rect.GetLeft() + rect.GetRight()) / 2
2085 point.y = (rect.GetTop() + rect.GetBottom()) / 2
2086 rx, ry = wx.Size(), wx.Size()
2088 if self._direction == wx.TOP:
2092 elif self._direction == wx.LEFT:
2096 elif self._direction == wx.RIGHT:
2100 elif self._direction == wx.BOTTOM:
2107 dc.SetPen(wx.Pen(colourIconArrow))
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)
2117 def OnPaint(self, event):
2119 Handles the ``wx.EVT_PAINT`` event for L{AuiDockingGuideWindow}.
2121 :param `event`: a `wx.PaintEvent` to be processed.
2124 dc = wx.AutoBufferedPaintDC(self)
2125 if self._currentImage.IsOk() and self._valid:
2126 dc.DrawBitmap(self._currentImage, 0, 0, True)
2133 Draws the whole docking guide window (not used if the docking guide images are ok).
2135 :param `dc`: a `wx.DC` device context object.
2138 self.DrawBackground(dc)
2145 def UpdateDockGuide(self, pos):
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
2151 :param `pos`: a `wx.Point` mouse position.
2154 inside = self.GetScreenRect().Contains(pos)
2157 image = self._bmp_focus
2159 image = self._bmp_unfocus
2161 if image != self._currentImage:
2162 self._currentImage = image
2167 # ---------------------------------------------------------------------------
2168 # AuiSingleDockingGuide
2169 # ---------------------------------------------------------------------------
2171 class AuiSingleDockingGuide(AuiDockingGuide):
2172 """ A docking guide window for single docking hint (not diamond-shaped HUD). """
2174 def __init__(self, parent, direction=0):
2176 Default class constructor. Used internally, do not call it in your code!
2178 :param `parent`: the L{AuiSingleDockingGuide} parent;
2179 :param `direction`: one of ``wx.TOP``, ``wx.BOTTOM``, ``wx.LEFT``, ``wx.RIGHT``.
2182 self._direction = direction
2184 style = wx.FRAME_TOOL_WINDOW | wx.STAY_ON_TOP | \
2185 wx.FRAME_NO_TASKBAR | wx.NO_BORDER
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
2192 AuiDockingGuide.__init__(self, parent, style=style, name="auiSingleDockTarget")
2196 useAero = GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_AERO_DOCKING_GUIDES
2197 useWhidbey = GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES
2199 self._useAero = useAero or useWhidbey
2203 sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
2205 sizeX, sizeY = whidbeySizeX, whidbeySizeY
2207 sizeX, sizeY = guideSizeX, guideSizeY
2209 if direction not in [wx.TOP, wx.BOTTOM]:
2210 sizeX, sizeY = sizeY, sizeX
2213 self.CreateShapesWithStyle(useWhidbey)
2215 if wx.Platform == "__WXGTK__":
2216 self.Bind(wx.EVT_WINDOW_CREATE, self.SetGuideShape)
2218 self.SetGuideShape()
2220 self.SetSize(self.region.GetBox().GetSize())
2222 self.SetSize((sizeX, sizeY))
2224 self.rect = wx.Rect(0, 0, sizeX, sizeY)
2227 useAero = (useWhidbey and [2] or [1])[0]
2231 self.target = AuiDockingGuideWindow(self, self.rect, direction, False, useAero)
2234 def CreateShapesWithStyle(self, useWhidbey):
2236 Creates the docking guide window shape based on which docking bitmaps are used.
2238 :param `useWhidbey`: if ``True``, use Whidbey-style bitmaps; if ``False``, use the
2242 sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
2244 sizeX, sizeY = whidbeySizeX, whidbeySizeY
2246 if self._direction not in [wx.TOP, wx.BOTTOM]:
2247 sizeX, sizeY = sizeY, sizeX
2249 useAero = (useWhidbey and [2] or [1])[0]
2250 bmp, dummy = GetDockingImage(self._direction, useAero, False)
2251 region = wx.RegionFromBitmap(bmp)
2253 self.region = region
2256 def AeroMove(self, pos):
2258 Moves the docking window to the new position. Overridden in children classes.
2260 :param `pos`: the new docking guide position.
2266 def SetGuideShape(self, event=None):
2268 Sets the correct shape for the docking guide window.
2270 :param `event`: on wxGTK, a `wx.WindowCreateEvent` event to process.
2273 self.SetShape(self.region)
2275 if event is not None:
2276 # Skip the event on wxGTK
2278 wx.CallAfter(wx.SafeYield, self, True)
2281 def SetShape(self, region):
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.
2288 :param `region`: the shape of the frame.
2290 :note: Overridden for wxMac.
2293 if wx.Platform == '__WXMAC__':
2294 # HACK so we don't crash when SetShape is called
2297 super(AuiSingleDockingGuide, self).SetShape(region)
2300 def SetValid(self, valid):
2302 Sets the docking direction as valid or invalid.
2304 :param `valid`: whether the docking direction is allowed or not.
2311 """ Returns whether the docking direction is valid. """
2316 def UpdateDockGuide(self, pos):
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
2322 :param `pos`: a `wx.Point` mouse position.
2325 self.target.UpdateDockGuide(pos)
2328 def HitTest(self, x, y):
2330 Checks if the mouse position is inside the target window rect.
2332 :param `x`: the `x` mouse position;
2333 :param `y`: the `y` mouse position.
2336 if self.target.GetScreenRect().Contains((x, y)):
2342 # ---------------------------------------------------------------------------
2343 # AuiCenterDockingGuide
2344 # ---------------------------------------------------------------------------
2346 class AuiCenterDockingGuide(AuiDockingGuide):
2347 """ A docking guide window for multiple docking hint (diamond-shaped HUD). """
2349 def __init__(self, parent):
2351 Default class constructor.
2352 Used internally, do not call it in your code!
2354 :param `parent`: the L{AuiCenterDockingGuide} parent.
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")
2363 self.CreateShapesWithStyle()
2364 self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
2366 if wx.Platform == "__WXGTK__":
2367 self.Bind(wx.EVT_WINDOW_CREATE, self.SetGuideShape)
2369 self.SetGuideShape()
2371 self.SetSize(self.region.GetBox().GetSize())
2373 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
2374 self.Bind(wx.EVT_PAINT, self.OnPaint)
2377 def CreateShapesWithStyle(self):
2378 """ Creates the docking guide window shape based on which docking bitmaps are used. """
2380 useAero = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_AERO_DOCKING_GUIDES) != 0
2381 useWhidbey = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES) != 0
2390 sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
2392 sizeX, sizeY = whidbeySizeX, whidbeySizeY
2394 sizeX, sizeY = guideSizeX, guideSizeY
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)
2402 if not self._useAero:
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)
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()]
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()]
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)]]
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))
2447 self._aeroBmp = aero_dock_pane.GetBitmap()
2448 region = wx.RegionFromBitmap(self._aeroBmp)
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]
2459 self._aeroBmp = whidbey_dock_pane.GetBitmap()
2460 region = wx.RegionFromBitmap(self._aeroBmp)
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]
2470 self.region = region
2473 def SetGuideShape(self, event=None):
2475 Sets the correct shape for the docking guide window.
2477 :param `event`: on wxGTK, a `wx.WindowCreateEvent` event to process.
2480 self.SetShape(self.region)
2482 if event is not None:
2483 # Skip the event on wxGTK
2485 wx.CallAfter(wx.SafeYield, self, True)
2488 def UpdateDockGuide(self, pos):
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
2494 :param `pos`: a `wx.Point` mouse position.
2497 if not self._useAero:
2498 for target in self.GetChildren():
2499 target.UpdateDockGuide(pos)
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]
2509 self._aeroBmp = self._allAeroBmps[-1]
2514 if self._aeroBmp != self._allAeroBmps[-1]:
2515 self._aeroBmp = self._allAeroBmps[-1]
2519 def HitTest(self, x, y):
2521 Checks if the mouse position is inside the target windows rect.
2523 :param `x`: the `x` mouse position;
2524 :param `y`: the `y` mouse position.
2527 if not self._useAero:
2528 if self.targetLeft.GetScreenRect().Contains((x, y)):
2530 if self.targetTop.GetScreenRect().Contains((x, y)):
2532 if self.targetRight.GetScreenRect().Contains((x, y)):
2534 if self.targetBottom.GetScreenRect().Contains((x, y)):
2536 if self.targetCenter.IsValid() and self.targetCenter.GetScreenRect().Contains((x, y)):
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]
2549 def ValidateNotebookDocking(self, valid):
2551 Sets whether a pane can be docked on top of another to create an automatic
2554 :param `valid`: whether a pane can be docked on top to another to form an automatic
2558 if not self._useAero:
2559 if self.targetCenter.IsValid() != valid:
2560 self.targetCenter.SetValid(valid)
2561 self.targetCenter.Refresh()
2563 if self._valid != valid:
2568 def AeroMove(self, pos):
2570 Moves the docking guide window to the new position.
2572 :param `pos`: the new docking guide position.
2575 if not self._useAero:
2578 useWhidbey = (GetManager(self.GetParent()).GetAGWFlags() & AUI_MGR_WHIDBEY_DOCKING_GUIDES) != 0
2581 sizeX, sizeY = whidbeySizeX, whidbeySizeY
2583 sizeX, sizeY = aeroguideSizeX, aeroguideSizeY
2585 size = self.GetSize()
2587 leftRect, topRect, rightRect, bottomRect, centerRect = self._aeroRects
2588 thePos = pos + wx.Point((size.x-sizeY)/2, (size.y-sizeX)/2)
2590 centerRect.SetPosition(thePos)
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))
2598 def OnEraseBackground(self, event):
2600 Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{AuiCenterDockingGuide}.
2602 :param `event`: `wx.EraseEvent` to be processed.
2604 :note: This is intentionally empty to reduce flickering while drawing.
2610 def OnPaint(self, event):
2612 Handles the ``wx.EVT_PAINT`` event for L{AuiCenterDockingGuide}.
2614 :param `event`: a `wx.PaintEvent` to be processed.
2617 dc = wx.AutoBufferedPaintDC(self)
2620 dc.SetBrush(wx.TRANSPARENT_BRUSH)
2621 dc.SetPen(wx.TRANSPARENT_PEN)
2623 dc.SetBrush(wx.Brush(colourTargetBackground))
2624 dc.SetPen(wx.Pen(colourTargetBorder))
2626 rect = self.GetClientRect()
2627 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
2630 dc.DrawBitmap(self._aeroBmp, 0, 0, True)
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)
2639 dc.SetPen(wx.Pen(colourTargetBorder, 2))
2640 for pts in self._triangles:
2641 dc.DrawLinePoint(pts[0], pts[1])
2644 # ----------------------------------------------------------------------------
2645 # AuiDockingHintWindow
2646 # ----------------------------------------------------------------------------
2648 class AuiDockingHintWindow(wx.Frame):
2649 """ The original wxAUI docking window hint. """
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"):
2656 Default class constructor. Used internally, do not call it in your code!
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.
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
2674 wx.Frame.__init__(self, parent, id, title, pos, size, style, name=name)
2676 self._blindMode = False
2677 self.SetBackgroundColour(colourHintBackground)
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)
2688 self.Bind(wx.EVT_SIZE, self.OnSize)
2691 def MakeVenetianBlinds(self):
2693 Creates the "venetian blind" effect if L{AuiManager} has the ``AUI_MGR_VENETIAN_BLINDS_HINT``
2698 size = self.GetClientSize()
2699 region = wx.Region(0, 0, size.x, 1)
2701 for y in xrange(size.y):
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]
2708 region.Union(0, y, size.x, 1)
2710 self.SetShape(region)
2713 def SetBlindMode(self, agwFlags):
2715 Sets whether venetian blinds or transparent hints will be shown as docking hint.
2716 This depends on the L{AuiManager} flags.
2718 :param `agwFlags`: the L{AuiManager} flags.
2721 self._blindMode = (agwFlags & AUI_MGR_VENETIAN_BLINDS_HINT) != 0
2723 if self._blindMode or not self.CanSetTransparent():
2724 self.MakeVenetianBlinds()
2725 self.SetTransparent(255)
2728 self.SetShape(wx.Region())
2729 if agwFlags & AUI_MGR_HINT_FADE == 0:
2730 self.SetTransparent(80)
2732 self.SetTransparent(0)
2735 def SetShape(self, region):
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.
2742 :param `region`: the shape of the frame (an instance of `wx.Region`).
2744 :note: Overridden for wxMac.
2747 if wx.Platform == '__WXMAC__':
2748 # HACK so we don't crash when SetShape is called
2751 super(AuiDockingHintWindow, self).SetShape(region)
2754 def Show(self, show=True):
2756 Show the hint window.
2758 :param `show`: whether to show or hide the hint docking window.
2761 super(AuiDockingHintWindow, self).Show(show)
2762 if wx.Platform == '__WXMAC__':
2763 # Need to manually do layout since its a borderless frame.
2767 def OnSize(self, event):
2769 Handles the ``wx.EVT_SIZE`` event for L{AuiDockingHintWindow}.
2771 :param `event`: a `wx.SizeEvent` to be processed.
2774 if self._blindMode or not self.CanSetTransparent():
2775 self.MakeVenetianBlinds()
2778 # ---------------------------------------------------------------------------- #
2780 # -- AuiFloatingFrame class implementation --
2782 class AuiFloatingFrame(wx.MiniFrame):
2783 """ AuiFloatingFrame is the frame class that holds floating panes. """
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):
2789 Default class constructor. Used internally, do not call it in your code!
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.
2799 if pane and pane.IsResizeable():
2800 style += wx.RESIZE_BORDER
2802 self._is_toolbar = pane.IsToolbar()
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
2816 wx.MiniFrame.__init__(self, parent, id, title, pos=pane.floating_pos,
2817 size=pane.floating_size, style=style, name="auiFloatingFrame")
2819 self._fly_timer = wx.Timer(self, wx.ID_ANY)
2820 self._check_fly_timer = wx.Timer(self, wx.ID_ANY)
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)
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)
2836 self.Bind(wx.EVT_MOVE, self.OnMove)
2839 self._send_size = True
2840 self._alpha_amount = 255
2842 self._owner_mgr = owner_mgr
2843 self._moving = False
2844 self._lastDirection = None
2845 self._transparent = 255
2847 self._last_rect = wx.Rect()
2848 self._last2_rect = wx.Rect()
2849 self._last3_rect = wx.Rect()
2851 self._mgr = AuiManager()
2852 self._mgr.SetManagedWindow(self)
2853 self._mgr.SetArtProvider(owner_mgr.GetArtProvider())
2854 self._mgr.SetAGWFlags(owner_mgr.GetAGWFlags())
2857 def CopyAttributes(self, pane):
2859 Copies all the attributes of the input `pane` into another L{AuiPaneInfo}.
2861 :param `pane`: the source L{AuiPaneInfo} from where to copy attributes.
2864 contained_pane = AuiPaneInfo()
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
2889 return contained_pane
2892 def SetPaneWindow(self, pane):
2894 Sets all the properties of a pane.
2896 :param `pane`: the L{AuiPaneInfo} to analyze.
2899 self._is_toolbar = pane.IsToolbar()
2900 self._pane_window = pane.window
2902 if isinstance(pane.window, auibar.AuiToolBar):
2903 pane.window.SetAuiManager(self._mgr)
2905 self._pane_window.Reparent(self)
2907 contained_pane = self.CopyAttributes(pane)
2909 contained_pane.Dock().Center().Show(). \
2910 CaptionVisible(False). \
2911 PaneBorder(False). \
2912 Layer(0).Row(0).Position(0)
2914 if not contained_pane.HasGripper() and not self._useNativeMiniframes:
2915 contained_pane.CaptionVisible(True)
2917 indx = self._owner_mgr._panes.index(pane)
2919 # Carry over the minimum size
2920 pane_min_size = pane.window.GetMinSize()
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):
2928 pane_min_size = pane_best_size
2929 self._pane_window.SetMinSize(pane_min_size)
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)
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)
2943 min_size = pane.window.GetMinSize()
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]
2952 self.SetMinSize((new_x, new_y))
2954 self.SetMinSize(min_size)
2956 self._mgr.AddPane(self._pane_window, contained_pane)
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)
2967 self.SetTitle(pane.caption)
2969 if pane.floating_size != wx.Size(-1, -1):
2970 self.SetSize(pane.floating_size)
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)
2981 size.x += self._owner_mgr._art.GetMetric(AUI_DOCKART_GRIPPER_SIZE)
2983 if not self._useNativeMiniframes:
2984 size.y += self._owner_mgr._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
2986 pane.floating_size = size
2988 self.SetClientSize(size)
2990 self._owner_mgr._panes[indx] = pane
2992 self._fly_step = abs(pane.floating_size.y - \
2993 (caption_size + 2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_Y)))/10
2995 self._floating_size = wx.Size(*self.GetSize())
2998 self._check_fly_timer.Start(50)
3001 def GetOwnerManager(self):
3002 """ Returns the L{AuiManager} that manages the pane. """
3004 return self._owner_mgr
3007 def OnSize(self, event):
3009 Handles the ``wx.EVT_SIZE`` event for L{AuiFloatingFrame}.
3011 :param `event`: a `wx.SizeEvent` to be processed.
3014 if self._owner_mgr and self._send_size:
3015 self._owner_mgr.OnFloatingPaneResized(self._pane_window, event.GetSize())
3018 def OnClose(self, event):
3020 Handles the ``wx.EVT_CLOSE`` event for L{AuiFloatingFrame}.
3022 :param `event`: a `wx.CloseEvent` to be processed.
3026 self._owner_mgr.OnFloatingPaneClosed(self._pane_window, event)
3028 if not event.GetVeto():
3029 self._mgr.DetachPane(self._pane_window)
3031 if isinstance(self._pane_window, auibar.AuiToolBar):
3032 self._pane_window.SetAuiManager(self._owner_mgr)
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
3041 def OnActivate(self, event):
3043 Handles the ``wx.EVT_ACTIVATE`` event for L{AuiFloatingFrame}.
3045 :param `event`: a `wx.ActivateEvent` to be processed.
3048 if self._owner_mgr and event.GetActive():
3049 self._owner_mgr.OnFloatingPaneActivated(self._pane_window)
3052 def OnMove(self, event):
3054 Handles the ``wx.EVT_MOVE`` event for L{AuiFloatingFrame}.
3056 :param `event`: a `wx.MoveEvent` to be processed.
3058 :note: This event is not processed on wxMAC or if L{AuiManager} is not using the
3059 ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
3063 self._owner_mgr.OnFloatingPaneMoved(self._pane_window, event)
3066 def OnMoveEvent(self, event):
3068 Handles the ``wx.EVT_MOVE`` and ``wx.EVT_MOVING`` events for L{AuiFloatingFrame}.
3070 :param `event`: a `wx.MoveEvent` to be processed.
3072 :note: This event is only processed on wxMAC or if L{AuiManager} is using the
3073 ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
3076 win_rect = self.GetRect()
3078 if win_rect == self._last_rect:
3081 # skip the first move event
3082 if self._last_rect.IsEmpty():
3083 self._last_rect = wx.Rect(*win_rect)
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)
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)
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)
3105 if _VERSION_STRING < "2.9":
3106 leftDown = wx.GetMouseState().LeftDown()
3108 leftDown = wx.GetMouseState().LeftIsDown()
3113 if not self._moving:
3114 self.OnMoveStart(event)
3117 if self._last3_rect.IsEmpty():
3120 self.OnMoving(event)
3123 def OnIdle(self, event):
3125 Handles the ``wx.EVT_IDLE`` event for L{AuiFloatingFrame}.
3127 :param `event`: a `wx.IdleEvent` event to be processed.
3129 :note: This event is only processed on wxMAC or if L{AuiManager} is using the
3130 ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
3134 if _VERSION_STRING < "2.9":
3135 leftDown = wx.GetMouseState().LeftDown()
3137 leftDown = wx.GetMouseState().LeftIsDown()
3140 self._moving = False
3141 self.OnMoveFinished()
3146 def OnMoveStart(self, event):
3148 The user has just started moving the floating pane.
3150 :param `event`: an instance of `wx.MouseEvent`.
3152 :note: This method is used only on wxMAC or if L{AuiManager} is using the
3153 ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
3156 # notify the owner manager that the pane has started to move
3158 if self._owner_mgr._from_move:
3160 self._owner_mgr._action_window = self._pane_window
3161 point = wx.GetMousePosition()
3162 action_offset = point - self.GetPosition()
3164 if self._is_toolbar:
3165 self._owner_mgr._toolbar_action_offset = action_offset
3166 self._owner_mgr.OnMotion_DragToolbarPane(point)
3168 self._owner_mgr._action_offset = action_offset
3169 self._owner_mgr.OnMotion_DragFloatingPane(point)
3172 def OnMoving(self, event):
3174 The user is moving the floating pane.
3176 :param `event`: an instance of `wx.MouseEvent`.
3178 :note: This method is used only on wxMAC or if L{AuiManager} is using the
3179 ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
3182 # notify the owner manager that the pane is moving
3183 self.OnMoveStart(event)
3186 def OnMoveFinished(self):
3188 The user has just finished moving the floating pane.
3190 :note: This method is used only on wxMAC or if L{AuiManager} is using the
3191 ``AUI_MGR_USE_NATIVE_MINIFRAMES`` style.
3194 # notify the owner manager that the pane has finished moving
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)
3201 self._owner_mgr.OnLeftUp_DragFloatingPane(point)
3203 self._owner_mgr.OnFloatingPaneMoved(self._pane_window, point)
3206 def OnCheckFlyTimer(self, event):
3208 Handles the ``wx.EVT_TIMER`` event for L{AuiFloatingFrame}.
3210 :param `event`: a `wx.TimerEvent` to be processed.
3212 :note: This is used solely for "fly-out" panes.
3216 pane = self._mgr.GetPane(self._pane_window)
3218 if self.IsShownOnScreen():
3222 def OnFindManager(self, event):
3224 Handles the ``EVT_AUI_FIND_MANAGER`` event for L{AuiFloatingFrame}.
3226 :param `event`: a L{AuiManagerEvent} event to be processed.
3229 event.SetManager(self._owner_mgr)
3233 """ Starts the flying in and out of a floating pane. """
3235 if self._fly_timer.IsRunning():
3238 if _VERSION_STRING < "2.9":
3239 leftDown = wx.GetMouseState().LeftDown()
3241 leftDown = wx.GetMouseState().LeftIsDown()
3246 rect = wx.Rect(*self.GetScreenRect())
3247 rect.Inflate(10, 10)
3249 if rect.Contains(wx.GetMousePosition()):
3252 self._send_size = False
3253 self._fly_timer.Start(5)
3257 self._send_size = False
3258 self._fly_timer.Start(5)
3261 def OnFlyTimer(self, event):
3263 Handles the ``wx.EVT_TIMER`` event for L{AuiFloatingFrame}.
3265 :param `event`: a `wx.TimerEvent` to be processed.
3268 current_size = self.GetClientSize()
3269 floating_size = wx.Size(*self._owner_mgr.GetPane(self._pane_window).floating_size)
3271 if floating_size.y == -1:
3272 floating_size = self._floating_size
3275 min_size = self._mgr.GetArtProvider().GetMetric(AUI_DOCKART_CAPTION_SIZE)
3277 if wx.Platform != "__WXMSW__":
3278 min_size += 2*wx.SystemSettings.GetMetric(wx.SYS_EDGE_Y)
3280 if current_size.y - self._fly_step <= min_size:
3281 self.SetClientSize((current_size.x, min_size))
3283 self._fly_timer.Stop()
3284 self._send_size = True
3286 self.SetClientSize((current_size.x, current_size.y-self._fly_step))
3289 if current_size.y + self._fly_step >= floating_size.y:
3290 self.SetClientSize((current_size.x, floating_size.y))
3292 self._fly_timer.Stop()
3293 self._send_size = True
3295 self.SetClientSize((current_size.x, current_size.y+self._fly_step))
3302 """ Actually starts the fading out of the floating pane. """
3305 self._alpha_amount -= 10
3306 if self._alpha_amount <= 0:
3307 self._alpha_amount = 255
3310 self.SetTransparent(self._alpha_amount)
3315 # -- static utility functions --
3317 def DrawResizeHint(dc, rect):
3319 Draws a resize hint while a sash is dragged.
3321 :param `rect`: a `wx.Rect` rectangle which specifies the sash dimensions.
3324 if wx.Platform == "__WXMSW__" and wx.App.GetComCtl32Version() >= 600:
3325 if wx.GetOsVersion()[1] > 5:
3327 dc.SetPen(wx.Pen("black", 2, wx.SOLID))
3328 dc.SetBrush(wx.TRANSPARENT_BRUSH)
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)
3337 stipple = PaneCreateStippleBitmap()
3338 brush = wx.BrushFromBitmap(stipple)
3340 dc.SetPen(wx.TRANSPARENT_PEN)
3342 dc.SetLogicalFunction(wx.XOR)
3343 dc.DrawRectangleRect(rect)
3346 def CopyDocksAndPanes(src_docks, src_panes):
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.
3353 :param `src_docks`: a list of L{AuiDockInfo} classes;
3354 :param `src_panes`: a list of L{AuiPaneInfo} classes.
3357 dest_docks = src_docks
3358 dest_panes = src_panes
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]
3367 return dest_docks, dest_panes
3370 def CopyDocksAndPanes2(src_docks, src_panes):
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.
3377 :param `src_docks`: a list of L{AuiDockInfo} classes;
3378 :param `src_panes`: a list of L{AuiPaneInfo} classes.
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)
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
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]
3430 dest_docks[ii] = dock
3432 return dest_docks, dest_panes
3435 def GetMaxLayer(docks, dock_direction):
3437 This is an internal function which returns
3438 the highest layer inside the specified dock.
3440 :param `docks`: a list of L{AuiDockInfo};
3441 :param `dock_direction`: the L{AuiDockInfo} docking direction to analyze.
3447 if dock.dock_direction == dock_direction and dock.dock_layer > max_layer and not dock.fixed:
3448 max_layer = dock.dock_layer
3453 def GetMaxRow(panes, dock_direction, dock_layer):
3455 This is an internal function which returns
3456 the highest layer inside the specified dock.
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.
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
3473 def DoInsertDockLayer(panes, dock_direction, dock_layer):
3475 This is an internal function that inserts a new dock
3476 layer by incrementing all existing dock layer values by one.
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.
3483 for ii in xrange(len(panes)):
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
3493 def DoInsertDockRow(panes, dock_direction, dock_layer, dock_row):
3495 This is an internal function that inserts a new dock
3496 row by incrementing all existing dock row values by one.
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.
3505 if not pane.IsFloating() and pane.dock_direction == dock_direction and \
3506 pane.dock_layer == dock_layer and pane.dock_row >= dock_row:
3512 def DoInsertPane(panes, dock_direction, dock_layer, dock_row, dock_pos):
3514 This is an internal function that inserts a new pane
3515 by incrementing all existing dock position values by one.
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.
3524 for ii in xrange(len(panes)):
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
3536 def FindDocks(docks, dock_direction, dock_layer=-1, dock_row=-1, reverse=False):
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).
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;
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))]
3553 arr = [x[-1] for x in sorted(matchDocks, reverse=reverse)]
3558 def FindOppositeDocks(docks, dock_direction):
3560 This is an internal function that returns a list of docks
3561 which is related to the opposite direction.
3563 :param `docks`: a list of L{AuiDockInfo};
3564 :param `dock_direction`: the L{AuiDockInfo} docking direction to analyze;
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)
3579 def FindPaneInDock(dock, window):
3581 This method looks up a specified window pointer inside a dock.
3582 If found, the corresponding L{AuiPaneInfo} pointer is returned, otherwise ``None``.
3584 :param `dock`: a L{AuiDockInfo} structure;
3585 :param `window`: a `wx.Window` derived window (associated to a pane).
3588 for p in dock.panes:
3589 if p.window == window:
3595 def GetToolBarDockOffsets(docks):
3597 Returns the toolbar dock offsets (top-left and bottom-right).
3599 :param `docks`: a list of L{AuiDockInfo} to analyze.
3602 top_left = wx.Size(0, 0)
3603 bottom_right = wx.Size(0, 0)
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
3612 elif dock_direction == AUI_DOCK_TOP:
3613 top_left.y += dock.rect.height
3614 bottom_right.y += dock.rect.height
3616 elif dock_direction == AUI_DOCK_RIGHT:
3617 bottom_right.x += dock.rect.width
3619 elif dock_direction == AUI_DOCK_BOTTOM:
3620 bottom_right.y += dock.rect.height
3622 return top_left, bottom_right
3625 def GetInternalFrameRect(window, docks):
3627 Returns the window rectangle excluding toolbars.
3629 :param `window`: a `wx.Window` derived window;
3630 :param `docks`: a list of L{AuiDockInfo} structures.
3633 frameRect = wx.Rect()
3635 frameRect.SetTopLeft(window.ClientToScreen(window.GetClientAreaOrigin()))
3636 frameRect.SetSize(window.GetClientSize())
3638 top_left, bottom_right = GetToolBarDockOffsets(docks)
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
3649 def CheckOutOfWindow(window, pt):
3651 Checks if a point is outside the window rectangle.
3653 :param `window`: a `wx.Window` derived window;
3654 :param `pt`: a `wx.Point` object.
3657 auiWindowMargin = 30
3658 marginRect = wx.Rect(*window.GetClientRect())
3659 marginRect.Inflate(auiWindowMargin, auiWindowMargin)
3661 return not marginRect.Contains(pt)
3664 def CheckEdgeDrop(window, docks, pt):
3666 Checks on which edge of a window the drop action has taken place.
3668 :param `window`: a `wx.Window` derived window;
3669 :param `docks`: a list of L{AuiDockInfo} structures;
3670 :param `pt`: a `wx.Point` object.
3673 screenPt = window.ClientToScreen(pt)
3674 clientSize = window.GetClientSize()
3675 frameRect = GetInternalFrameRect(window, docks)
3677 if screenPt.y >= frameRect.GetTop() and screenPt.y < frameRect.GetBottom():
3678 if pt.x < auiLayerInsertOffset and pt.x > auiLayerInsertOffset - auiLayerInsertPixels:
3681 if pt.x >= clientSize.x - auiLayerInsertOffset and \
3682 pt.x < clientSize.x - auiLayerInsertOffset + auiLayerInsertPixels:
3685 if screenPt.x >= frameRect.GetLeft() and screenPt.x < frameRect.GetRight():
3686 if pt.y < auiLayerInsertOffset and pt.y > auiLayerInsertOffset - auiLayerInsertPixels:
3689 if pt.y >= clientSize.y - auiLayerInsertOffset and \
3690 pt.y < clientSize.y - auiLayerInsertOffset + auiLayerInsertPixels:
3696 def RemovePaneFromDocks(docks, pane, exc=None):
3698 Removes a pane window from all docks
3699 with a possible exception specified by parameter `exc`.
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.
3706 for ii in xrange(len(docks)):
3710 pi = FindPaneInDock(d, pane.window)
3719 def RenumberDockRows(docks):
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.
3725 :param `docks`: a list of L{AuiDockInfo} structures.
3728 for ii in xrange(len(docks)):
3731 for jj in xrange(len(dock.panes)):
3732 dock.panes[jj].dock_row = ii
3739 def SetActivePane(panes, active_pane):
3741 Sets the active pane, as well as cycles through
3742 every other pane and makes sure that all others' active flags
3745 :param `panes`: a list of L{AuiPaneInfo} structures;
3746 :param `active_pane`: the pane to be made active (if found).
3750 pane.state &= ~AuiPaneInfo.optionActive
3753 if pane.window == active_pane and not pane.IsNotebookPage():
3754 pane.state |= AuiPaneInfo.optionActive
3760 def ShowDockingGuides(guides, show):
3762 Shows or hide the docking guide windows.
3764 :param `guides`: a list of L{AuiDockingGuideInfo} classes;
3765 :param `show`: whether to show or hide the docking guide windows.
3768 for target in guides:
3770 if show and not target.host.IsShown():
3772 target.host.Update()
3774 elif not show and target.host.IsShown():
3778 def RefreshDockingGuides(guides):
3780 Refreshes the docking guide windows.
3782 :param `guides`: a list of L{AuiDockingGuideInfo} classes;
3785 for target in guides:
3786 if target.host.IsShown():
3787 target.host.Refresh()
3790 def PaneSortFunc(p1, p2):
3792 This function is used to sort panes by dock position.
3794 :param `p1`: a L{AuiPaneInfo} instance;
3795 :param `p2`: another L{AuiPaneInfo} instance.
3798 return (p1.dock_pos < p2.dock_pos and [-1] or [1])[0]
3801 def GetNotebookRoot(panes, notebook_id):
3803 Returns the L{AuiPaneInfo} which has the specified `notebook_id`.
3805 :param `panes`: a list of L{AuiPaneInfo} instances;
3806 :param `notebook_id`: the target notebook id.
3809 for paneInfo in panes:
3810 if paneInfo.IsNotebookControl() and paneInfo.notebook_id == notebook_id:
3816 def EscapeDelimiters(s):
3818 Changes ``;`` into ``\`` and ``|`` into ``\|`` in the input string.
3820 :param `s`: the string to be analyzed.
3822 :note: This is an internal functions which is used for saving perspectives.
3825 result = s.replace(";", "\\")
3826 result = result.replace("|", "|\\")
3831 def IsDifferentDockingPosition(pane1, pane2):
3833 Returns whether `pane1` and `pane2` are in a different docking position
3834 based on pane status, docking direction, docking layer and docking row.
3836 :param `pane1`: a L{AuiPaneInfo} instance;
3837 :param `pane2`: another L{AuiPaneInfo} instance.
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
3846 # Convenience function
3847 def AuiManager_HasLiveResize(manager):
3849 Static function which returns if the input `manager` should have "live resize"
3852 :param `manager`: an instance of L{AuiManager}.
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.
3858 # With Core Graphics on Mac, it's not possible to show sash feedback,
3859 # so we'll always use live update instead.
3861 if wx.Platform == "__WXMAC__":
3864 return (manager.GetAGWFlags() & AUI_MGR_LIVE_RESIZE) == AUI_MGR_LIVE_RESIZE
3867 # Convenience function
3868 def AuiManager_UseNativeMiniframes(manager):
3870 Static function which returns if the input `manager` should use native `wx.MiniFrame` as
3873 :param `manager`: an instance of L{AuiManager}.
3875 :note: This method always returns ``True`` on wxMac as this platform doesn't have
3876 the ability to use custom drawn miniframes.
3879 # With Core Graphics on Mac, it's not possible to show sash feedback,
3880 # so we'll always use live update instead.
3882 if wx.Platform == "__WXMAC__":
3885 return (manager.GetAGWFlags() & AUI_MGR_USE_NATIVE_MINIFRAMES) == AUI_MGR_USE_NATIVE_MINIFRAMES
3888 def GetManager(window):
3890 This function will return the aui manager for a given window.
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.
3899 if not isinstance(wx.GetTopLevelParent(window), AuiFloatingFrame):
3900 if isinstance(window, auibar.AuiToolBar):
3901 return window.GetAuiManager()
3903 evt = AuiManagerEvent(wxEVT_AUI_FIND_MANAGER)
3904 evt.SetManager(None)
3905 evt.ResumePropagation(wx.EVENT_PROPAGATE_MAX)
3907 if not window.GetEventHandler().ProcessEvent(evt):
3910 return evt.GetManager()
3913 # ---------------------------------------------------------------------------- #
3915 class AuiManager(wx.EvtHandler):
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.
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()`.
3930 Panes can be added quite easily::
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"))
3940 Later on, the positions can be modified easily. The following will float an
3941 existing pane in a tool window::
3943 self._mgr.GetPane(text1).Float()
3946 **Layers, Rows and Directions, Positions:**
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.
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
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.
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.
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`).
3974 def __init__(self, managed_window=None, agwFlags=None):
3976 Default class constructor.
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:
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 ==================================== ==================================
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``
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.
4011 wx.EvtHandler.__init__(self)
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
4023 self._dock_constraint_x = 0.3
4024 self._dock_constraint_y = 0.3
4025 self._reserved = None
4032 self._notebooks = []
4034 self._masterManager = None
4035 self._currentDragItem = -1
4036 self._lastknowndocks = {}
4038 self._hint_fadetimer = wx.Timer(self, wx.ID_ANY)
4039 self._hint_fademax = 50
4040 self._last_hint = wx.Rect()
4042 self._from_move = False
4043 self._last_rect = wx.Rect()
4045 if agwFlags is None:
4046 agwFlags = AUI_MGR_DEFAULT
4048 self._agwFlags = agwFlags
4049 self._is_docked = (False, wx.RIGHT, wx.TOP, 0)
4050 self._snap_limits = (15, 15)
4052 if wx.Platform == "__WXMSW__":
4053 self._animation_step = 30.0
4055 self._animation_step = 5.0
4057 self._hint_rect = wx.Rect()
4059 self._preview_timer = wx.Timer(self, wx.ID_ANY)
4060 self._sliding_frame = None
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
4068 self.SetManagedWindow(managed_window)
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)
4084 self.Bind(wx.EVT_MOVE, self.OnMove)
4085 self.Bind(wx.EVT_SYS_COLOUR_CHANGED, self.OnSysColourChanged)
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)
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)
4098 def CreateFloatingFrame(self, parent, pane_info):
4100 Creates a floating frame for the windows.
4102 :param `parent`: the floating frame parent;
4103 :param `pane_info`: the L{AuiPaneInfo} class with all the pane's information.
4106 return AuiFloatingFrame(parent, self, pane_info)
4109 def CanDockPanel(self, p):
4111 Returns whether a pane can be docked or not.
4113 :param `p`: the L{AuiPaneInfo} class with all the pane's information.
4116 # is the pane dockable?
4117 if not p.IsDockable():
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))
4125 def GetPaneByWidget(self, window):
4127 This version of L{GetPane} looks up a pane based on a
4130 :param `window`: a `wx.Window` derived window.
4135 for p in self._panes:
4136 if p.window == window:
4142 def GetPaneByName(self, name):
4144 This version of L{GetPane} looks up a pane based on a
4147 :param `name`: the pane name.
4152 for p in self._panes:
4159 def GetPane(self, item):
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}.
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.
4170 :param `item`: either a pane name or a `wx.Window`.
4173 if isinstance(item, basestring):
4174 return self.GetPaneByName(item)
4176 return self.GetPaneByWidget(item)
4179 def GetAllPanes(self):
4180 """ Returns a reference to all the pane info structures. """
4185 def ShowPane(self, window, show):
4187 Shows or hides a pane based on the window passed as input.
4189 :param `window`: a `wx.Window` derived window;
4190 :param `show`: ``True`` to show the pane, ``False`` otherwise.
4193 p = self.GetPane(window)
4196 if p.IsNotebookPage():
4199 notebook = self._notebooks[p.notebook_id]
4200 id = notebook.GetPageIndex(p.window)
4202 notebook.SetSelection(id)
4203 self.ShowPane(notebook, True)
4214 def HitTest(self, x, y):
4216 This is an internal function which determines
4217 which UI item the specified coordinates are over.
4219 :param `x`: specifies a x position in client coordinates;
4220 :param `y`: specifies a y position in client coordinates.
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:
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:
4239 # if the point is inside the rectangle, we have a hit
4240 if item.rect.Contains((x, y)):
4246 def PaneHitTest(self, panes, pt):
4248 Similar to L{HitTest}, but it checks in which L{AuiPaneInfo} rectangle the
4249 input point belongs to.
4251 :param `panes`: a list of L{AuiPaneInfo} instances;
4252 :param `pt`: a `wx.Point` object.
4255 for paneInfo in panes:
4256 if paneInfo.IsDocked() and paneInfo.IsShown() and paneInfo.rect.Contains(pt):
4262 # SetAGWFlags() and GetAGWFlags() allow the owner to set various
4263 # options which are global to AuiManager
4265 def SetAGWFlags(self, agwFlags):
4267 This method is used to specify L{AuiManager}'s settings flags.
4269 :param `agwFlags`: specifies options which allow the frame management behavior
4270 to be modified. `agwFlags` can be one of the following style bits:
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 ==================================== ==================================
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.
4299 self._agwFlags = agwFlags
4301 if len(self._guides) > 0:
4302 self.CreateGuideWindows()
4304 if self._hint_window and agwFlags & AUI_MGR_RECTANGLE_HINT == 0:
4305 self.CreateHintWindow()
4308 def GetAGWFlags(self):
4310 Returns the current manager's flags.
4312 :see: L{SetAGWFlags} for a list of possible L{AuiManager} flags.
4315 return self._agwFlags
4318 def SetManagedWindow(self, managed_window):
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.
4324 :param `managed_window`: specifies the window which should be managed by
4328 if not managed_window:
4329 raise Exception("Specified managed window must be non-null. ")
4331 self._frame = managed_window
4332 self._frame.PushEventHandler(self)
4334 # if the owner is going to manage an MDI parent frame,
4335 # we need to add the MDI client window as the default
4338 if isinstance(self._frame, wx.MDIParentFrame):
4339 mdi_frame = self._frame
4340 client_window = mdi_frame.GetClientWindow()
4342 if not client_window:
4343 raise Exception("Client window is None!")
4345 self.AddPane(client_window, AuiPaneInfo().Name("mdiclient").
4346 CenterPane().PaneBorder(False))
4348 elif isinstance(self._frame, tabmdi.AuiMDIParentFrame):
4350 mdi_frame = self._frame
4351 client_window = mdi_frame.GetClientWindow()
4353 if not client_window:
4354 raise Exception("Client window is None!")
4356 self.AddPane(client_window, AuiPaneInfo().Name("mdiclient").
4357 CenterPane().PaneBorder(False))
4360 def GetManagedWindow(self):
4361 """ Returns the window being managed by L{AuiManager}. """
4366 def SetFrame(self, managed_window):
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.
4372 :param `managed_window`: specifies the window which should be managed by
4375 :warning: This method is now deprecated, use L{SetManagedWindow} instead.
4378 DeprecationWarning("This method is deprecated, use SetManagedWindow instead.")
4379 return self.SetManagedWindow(managed_window)
4384 Returns the window being managed by L{AuiManager}.
4386 :warning: This method is now deprecated, use L{GetManagedWindow} instead.
4389 DeprecationWarning("This method is deprecated, use GetManagedWindow instead.")
4393 def CreateGuideWindows(self):
4394 """ Creates the VS2005 HUD guide windows. """
4396 self.DestroyGuideWindows()
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)))
4410 def DestroyGuideWindows(self):
4411 """ Destroys the VS2005 HUD guide windows. """
4413 for guide in self._guides:
4415 guide.host.Destroy()
4420 def CreateHintWindow(self):
4421 """ Creates the standard wxAUI hint window. """
4423 self.DestroyHintWindow()
4425 self._hint_window = AuiDockingHintWindow(self._frame)
4426 self._hint_window.SetBlindMode(self._agwFlags)
4429 def DestroyHintWindow(self):
4430 """ Destroys the standard wxAUI hint window. """
4432 if self._hint_window:
4434 self._hint_window.Destroy()
4435 self._hint_window = None
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`
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
4450 self._frame.RemoveEventHandler(self)
4453 def GetArtProvider(self):
4454 """ Returns the current art provider being used. """
4459 def ProcessMgrEvent(self, event):
4461 Process the AUI events sent to the manager.
4463 :param `event`: the event to process, an instance of L{AuiManagerEvent}.
4466 # first, give the owner frame a chance to override
4468 if self._frame.GetEventHandler().ProcessEvent(event):
4471 self.ProcessEvent(event)
4474 def FireEvent(self, evtType, pane, canVeto=False):
4476 Fires one of the ``EVT_AUI_PANE_FLOATED``/``FLOATING``/``DOCKING``/``DOCKED``/``ACTIVATED`` event.
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.
4483 event = AuiManagerEvent(evtType)
4485 event.SetCanVeto(canVeto)
4486 self.ProcessMgrEvent(event)
4491 def CanUseModernDockArt(self):
4493 Returns whether L{ModernDockArt} can be used (Windows XP / Vista / 7 only,
4494 requires Mark Hammonds's `pywin32` package).
4500 # Get the size of a small close button (themed)
4501 hwnd = self._frame.GetHandle()
4502 hTheme = winxptheme.OpenThemeData(hwnd, "Window")
4510 def SetArtProvider(self, art_provider):
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
4516 :param `art_provider`: a AUI dock art provider.
4518 :note: The previous art provider object, if any, will be deleted by L{AuiManager}.
4521 # delete the last art provider, if any
4524 # assign the new art provider
4525 self._art = art_provider
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()
4533 def AddPane(self, window, arg1=None, arg2=None, target=None):
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.
4543 In wxPython, simply call L{AddPane}.
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)
4553 if target in self._panes:
4554 return self.AddPane4(window, arg1, target)
4556 if type(arg1) == type(1):
4562 return self.AddPane2(window, arg1, arg2)
4564 if isinstance(arg2, wx.Point):
4565 return self.AddPane3(window, arg1, arg2)
4567 return self.AddPane1(window, arg1)
4570 def AddPane1(self, window, pane_info):
4571 """ See comments on L{AddPane}. """
4573 # check if the pane has a valid window
4577 # check if the pane already exists
4578 if self.GetPane(pane_info.window).IsOk():
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
4588 # if the new pane is docked then we should undo maximize
4589 if pane_info.IsDocked():
4590 self.RestoreMaximizedPane()
4592 self._panes.append(pane_info)
4593 pinfo = self._panes[-1]
4595 # set the pane window
4596 pinfo.window = window
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))
4603 # set initial proportion (if not already set)
4604 if pinfo.dock_proportion == 0:
4605 pinfo.dock_proportion = 100000
4607 floating = isinstance(self._frame, AuiFloatingFrame)
4611 if not floating and pinfo.HasMinimizeButton():
4612 button = AuiPaneButton(AUI_BUTTON_MINIMIZE)
4613 pinfo.buttons.append(button)
4615 if not floating and pinfo.HasMaximizeButton():
4616 button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE)
4617 pinfo.buttons.append(button)
4619 if not floating and pinfo.HasPinButton():
4620 button = AuiPaneButton(AUI_BUTTON_PIN)
4621 pinfo.buttons.append(button)
4623 if pinfo.HasCloseButton():
4624 button = AuiPaneButton(AUI_BUTTON_CLOSE)
4625 pinfo.buttons.append(button)
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.
4635 pinfo.SetFlag(AuiPaneInfo.optionGripper, False)
4636 tb.SetGripperVisible(True)
4639 if pinfo.best_size == wx.Size(-1, -1):
4640 pinfo.best_size = pinfo.window.GetClientSize()
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()
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))
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
4659 self._panes[-1] = pinfo
4660 if isinstance(window, auibar.AuiToolBar):
4661 window.SetAuiManager(self)
4666 def AddPane2(self, window, direction, caption):
4667 """ See comments on L{AddPane}. """
4669 pinfo = AuiPaneInfo()
4670 pinfo.Caption(caption)
4672 if direction == wx.TOP:
4674 elif direction == wx.BOTTOM:
4676 elif direction == wx.LEFT:
4678 elif direction == wx.RIGHT:
4680 elif direction == wx.CENTER:
4683 return self.AddPane(window, pinfo)
4686 def AddPane3(self, window, pane_info, drop_pos):
4687 """ See comments on L{AddPane}. """
4689 if not self.AddPane(window, pane_info):
4692 pane = self.GetPane(window)
4693 indx = self._panes.index(pane)
4695 ret, pane = self.DoDrop(self._docks, self._panes, pane, drop_pos, wx.Point(0, 0))
4696 self._panes[indx] = pane
4701 def AddPane4(self, window, pane_info, target):
4702 """ See comments on L{AddPane}. """
4704 if not self.AddPane(window, pane_info):
4707 paneInfo = self.GetPane(window)
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)
4714 if not target.HasNotebook():
4715 self.CreateNotebookBase(self._panes, target)
4717 # Add new item to notebook
4718 paneInfo.NotebookPage(target.notebook_id)
4720 # we also want to remove our captions sometimes
4721 self.RemoveAutoNBCaption(paneInfo)
4722 self.UpdateNotebook()
4727 def InsertPane(self, window, pane_info, insert_level=AUI_INSERT_PANE):
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`.
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``.
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.
4744 raise Exception("Invalid window passed to InsertPane.")
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,
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)
4756 elif insert_level == AUI_INSERT_DOCK:
4757 self._panes = DoInsertDockLayer(self._panes, pane_info.dock_direction,
4758 pane_info.dock_layer)
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)
4765 if not existing_pane.IsOk():
4767 return self.AddPane(window, pane_info)
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)
4778 # if the new pane is docked then we should undo maximize
4779 self.RestoreMaximizedPane()
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)
4786 self._panes[indx] = existing_pane
4791 def DetachPane(self, window):
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}.
4797 :param `window`: the window to be un-managed.
4800 for p in self._panes:
4801 if p.window == window:
4803 # we have a floating frame which is being detached. We need to
4804 # reparent it to self._frame and destroy the floating frame
4807 p.window.SetSize((1, 1))
4808 if p.frame.IsShown():
4811 if self._action_window == p.frame:
4812 self._action_window = None
4814 # reparent to self._frame and destroy the pane
4815 p.window.Reparent(self._frame)
4816 p.frame.SetSizer(None)
4820 elif p.IsNotebookPage():
4821 notebook = self._notebooks[p.notebook_id]
4822 id = notebook.GetPageIndex(p.window)
4823 notebook.RemovePage(id)
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()
4830 for pi in xrange(len(self._uiparts)):
4831 part = self._uiparts[counter]
4833 self._uiparts.pop(counter)
4838 self._panes.remove(p)
4844 def ClosePane(self, pane_info):
4846 Destroys or hides the pane depending on its flags.
4848 :param `pane_info`: a L{AuiPaneInfo} instance.
4851 # if we were maximized, restore
4852 if pane_info.IsMaximized():
4853 self.RestorePane(pane_info)
4856 if self._agwFlags & AUI_MGR_ANIMATE_FRAMES:
4857 pane_info.frame.FadeOut()
4859 # first, hide the window
4860 if pane_info.window and pane_info.window.IsShown():
4861 pane_info.window.Show(False)
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)
4867 # if we have a frame, destroy it
4869 pane_info.frame.Destroy()
4870 pane_info.frame = None
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
4878 # This code just prevents an out-of bounds error.
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)
4885 notebook.RemovePage(page_idx)
4887 # now we need to either destroy or hide the pane
4889 if pane_info.IsDestroyOnClose():
4890 to_destroy = pane_info.window
4891 self.DetachPane(to_destroy)
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)
4898 pane_info.Dock().Hide()
4900 if pane_info.IsNotebookControl():
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)
4908 info.notebook_id = -1
4909 info.dock_direction = AUI_DOCK_NONE
4910 # Note: this could change our paneInfo reference ...
4911 self.ClosePane(info)
4914 to_destroy.Destroy()
4917 def MaximizePane(self, pane_info, savesizes=True):
4919 Maximizes the input pane.
4921 :param `pane_info`: a L{AuiPaneInfo} instance.
4922 :param `savesizes`: whether to save previous dock sizes.
4926 self.SavePreviousDockSizes(pane_info)
4928 for p in self._panes:
4931 p.SetFlag(p.savedHiddenState, p.HasFlag(p.optionHidden))
4933 if not p.IsToolbar() and not p.IsFloating():
4936 # hide the pane, because only the newly
4937 # maximized pane should show
4940 pane_info.previousDockPos = pane_info.dock_pos
4942 # mark ourselves maximized
4943 pane_info.Maximize()
4945 self._has_maximized = True
4947 # last, show the window
4948 if pane_info.window and not pane_info.window.IsShown():
4949 pane_info.window.Show(True)
4952 def SavePreviousDockSizes(self, pane_info):
4954 Stores the previous dock sizes, to be used in a "restore" action later.
4956 :param `pane_info`: a L{AuiPaneInfo} instance.
4959 for d in self._docks:
4962 p.previousDockSize = d.size
4963 if pane_info is not p:
4964 p.SetFlag(p.needsRestore, True)
4967 def RestorePane(self, pane_info):
4969 Restores the input pane from a previous maximized or minimized state.
4971 :param `pane_info`: a L{AuiPaneInfo} instance.
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))
4979 pane_info.SetFlag(pane_info.needsRestore, True)
4981 # mark ourselves non-maximized
4983 self._has_maximized = False
4984 self._has_minimized = False
4986 # last, show the window
4987 if pane_info.window and not pane_info.window.IsShown():
4988 pane_info.window.Show(True)
4991 def RestoreMaximizedPane(self):
4992 """ Restores the current maximized pane (if any). """
4994 # restore all the panes
4995 for p in self._panes:
5001 def ActivatePane(self, window):
5003 Activates the pane to which `window` is associated.
5005 :param `window`: a `wx.Window` derived window.
5008 if self.GetAGWFlags() & AUI_MGR_ALLOW_ACTIVE_PANE:
5010 ret, self._panes = SetActivePane(self._panes, window)
5014 window = window.GetParent()
5016 self.RefreshCaptions()
5017 self.FireEvent(wxEVT_AUI_PANE_ACTIVATED, window, canVeto=False)
5020 def CreateNotebook(self):
5022 Creates an automatic L{AuiNotebook} when a pane is docked on
5023 top of another pane.
5026 notebook = auibook.AuiNotebook(self._frame, -1, wx.Point(0, 0), wx.Size(0, 0), agwStyle=self._autoNBStyle)
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)
5036 def SetAutoNotebookTabArt(self, art):
5038 Sets the default tab art provider for automatic notebooks.
5040 :param `art`: a tab art provider.
5043 for nb in self._notebooks:
5044 nb.SetArtProvider(art.Clone())
5048 self._autoNBTabArt = art
5051 def GetAutoNotebookTabArt(self):
5052 """ Returns the default tab art provider for automatic notebooks. """
5054 return self._autoNBTabArt
5057 def SetAutoNotebookStyle(self, agwStyle):
5059 Sets the default AGW-specific window style for automatic notebooks.
5061 :param `agwStyle`: the underlying L{AuiNotebook} window style.
5062 This can be a combination of the following bits:
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 ==================================== ==================================
5092 for nb in self._notebooks:
5093 nb.SetAGWWindowStyleFlag(agwStyle)
5097 self._autoNBStyle = agwStyle
5100 def GetAutoNotebookStyle(self):
5102 Returns the default AGW-specific window style for automatic notebooks.
5104 :see: L{SetAutoNotebookStyle} method for a list of possible styles.
5107 return self._autoNBStyle
5110 def SavePaneInfo(self, pane):
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}.
5116 :param `pane`: a L{AuiPaneInfo} instance to save.
5119 result = "name=" + EscapeDelimiters(pane.name) + ";"
5120 result += "caption=" + EscapeDelimiters(pane.caption) + ";"
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
5144 def LoadPaneInfo(self, pane_part, pane):
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}.
5150 :param `pane_part`: the string to analyze;
5151 :param `pane`: the L{AuiPaneInfo} structure in which to load `pane_part`.
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")
5159 options = pane_part.split(";")
5160 for items in options:
5162 val_name, value = items.split("=")
5163 val_name = val_name.strip()
5165 if val_name == "name":
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)
5211 raise Exception("Bad perspective string")
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", ";")
5225 def SavePerspective(self):
5227 Saves the entire user interface layout into an encoded string, which can then
5228 be stored by the application (probably using `wx.Config`).
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.
5236 for pane in self._panes:
5237 result += self.SavePaneInfo(pane) + "|"
5239 for dock in self._docks:
5240 result = result + ("dock_size(%d,%d,%d)=%d|")%(dock.dock_direction,
5247 def LoadPerspective(self, layout, update=True):
5249 Loads a layout which was saved with L{SavePerspective}.
5251 If the `update` flag parameter is ``True``, L{Update} will be
5252 automatically invoked, thus realizing the saved perspective on screen.
5254 :param `layout`: a string which contains a saved AUI layout;
5255 :param `update`: whether to update immediately the window or not.
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:]
5267 if part != "layout2":
5270 # mark all panes currently managed as docked and hidden
5271 for pane in self._panes:
5274 # clear out the dock array; this will be reconstructed
5277 # replace escaped characters so we can
5278 # split up the string easily
5279 input = input.replace("\\|", "\a")
5280 input = input.replace("\\;", "\b")
5284 pane = AuiPaneInfo()
5285 index = input.find("|")
5286 pane_part = input[0:index].strip()
5287 input = input[index+1:]
5289 # if the string is empty, we're done parsing
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:]
5298 index = val_name.find("(")
5299 piece = val_name[index+1:]
5300 index = piece.find(")")
5301 piece = piece[0:index]
5303 vals = piece.split(",")
5305 layer = int(vals[1])
5309 dock = AuiDockInfo()
5310 dock.dock_direction = dir
5311 dock.dock_layer = layer
5314 self._docks.append(dock)
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", ";")
5323 pane = self.LoadPaneInfo(pane_part, pane)
5325 p = self.GetPane(pane.name)
5328 if pane.IsNotebookControl():
5329 # notebook controls - auto add...
5330 self._panes.append(pane)
5331 indx = self._panes.index(pane)
5333 # the pane window couldn't be found
5334 # in the existing layout -- skip it
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
5344 if isinstance(pane.window, auibar.AuiToolBar) and (pane.IsFloatable() or pane.IsDockable()):
5345 pane.window.SetGripperVisible(True)
5353 def GetPanePositionsAndSizes(self, dock):
5355 Returns all the panes positions and sizes in a dock.
5357 :param `dock`: a L{AuiDockInfo} instance.
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)
5368 pane_count = len(dock.panes)
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
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)
5385 if pane.HasBorder():
5386 size += pane_border_size*2
5388 if dock.IsHorizontal():
5389 if pane.HasGripper() and not pane.HasGripperTop():
5390 size += gripper_size
5392 if pane.HasCaptionLeft():
5393 size += caption_size
5395 size += pane.best_size.x
5398 if pane.HasGripper() and pane.HasGripperTop():
5399 size += gripper_size
5401 if pane.HasCaption() and not pane.HasCaptionLeft():
5402 size += caption_size
5404 size += pane.best_size.y
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
5414 for pane_i in xrange(action_pane-1, -1, -1):
5415 amount = positions[pane_i+1] - (positions[pane_i] + sizes[pane_i])
5419 positions[pane_i] -= -amount
5421 offset += sizes[pane_i]
5423 # if the dock mode is fixed, make sure none of the panes
5424 # overlap we will bump panes that overlap
5426 for pane_i in xrange(action_pane, pane_count):
5427 amount = positions[pane_i] - offset
5431 positions[pane_i] += -amount
5433 offset += sizes[pane_i]
5435 return positions, sizes
5438 def LayoutAddPane(self, cont, dock, pane, uiparts, spacer_only):
5440 Adds a pane into the existing layout (in an existing dock).
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.
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)
5455 # find out the orientation of the item (orientation for panes
5456 # is the same as the dock's orientation)
5458 if dock.IsHorizontal():
5459 orientation = wx.HORIZONTAL
5461 orientation = wx.VERTICAL
5463 # this variable will store the proportion
5464 # value that the pane will receive
5465 pane_proportion = pane.dock_proportion
5467 horz_pane_sizer = wx.BoxSizer(wx.HORIZONTAL)
5468 vert_pane_sizer = wx.BoxSizer(wx.VERTICAL)
5470 if pane.HasGripper():
5472 part = AuiDockUIPart()
5473 if pane.HasGripperTop():
5474 sizer_item = vert_pane_sizer.Add((1, gripper_size), 0, wx.EXPAND)
5476 sizer_item = horz_pane_sizer.Add((gripper_size, 1), 0, wx.EXPAND)
5478 part.type = AuiDockUIPart.typeGripper
5482 part.orientation = orientation
5483 part.cont_sizer = horz_pane_sizer
5484 part.sizer_item = sizer_item
5485 uiparts.append(part)
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
5492 caption, captionLeft = pane.HasCaption(), pane.HasCaptionLeft()
5493 button_count = len(pane.buttons)
5496 caption_sizer = wx.BoxSizer(wx.VERTICAL)
5498 # add pane buttons to the caption
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
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)
5512 sizer_item = caption_sizer.Add((caption_size, 1), 1, wx.EXPAND)
5513 vert_pane_sizer = wx.BoxSizer(wx.HORIZONTAL)
5515 # create the caption sizer
5516 part = AuiDockUIPart()
5518 part.type = AuiDockUIPart.typeCaption
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)
5531 caption_sizer = wx.BoxSizer(wx.HORIZONTAL)
5532 sizer_item = caption_sizer.Add((1, caption_size), 1, wx.EXPAND)
5534 # create the caption sizer
5535 part = AuiDockUIPart()
5537 part.type = AuiDockUIPart.typeCaption
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)
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
5554 part.button = button
5555 part.orientation = orientation
5556 part.cont_sizer = caption_sizer
5557 part.sizer_item = sizer_item
5558 uiparts.append(part)
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:
5565 caption_sizer.Add((caption_size, 3), 0, wx.EXPAND)
5567 caption_sizer.Add((3, caption_size), 0, wx.EXPAND)
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
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)
5577 sizer_item = vert_pane_sizer.Add(pane.window, 1, wx.EXPAND)
5578 vert_pane_sizer.SetItemMinSize(pane.window, (1, 1))
5580 part = AuiDockUIPart()
5581 part.type = AuiDockUIPart.typePane
5585 part.orientation = orientation
5586 part.cont_sizer = vert_pane_sizer
5587 part.sizer_item = sizer_item
5588 uiparts.append(part)
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
5594 min_size = pane.min_size
5596 if min_size == wx.Size(-1, -1):
5597 min_size = pane.best_size
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))
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)
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
5617 part.orientation = orientation
5618 part.cont_sizer = cont
5619 part.sizer_item = sizer_item
5620 uiparts.append(part)
5622 sizer_item = cont.Add(horz_pane_sizer, pane_proportion, wx.EXPAND)
5627 def LayoutAddDock(self, cont, dock, uiparts, spacer_only):
5629 Adds a dock into the existing layout.
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.
5637 sizer_item = wx.SizerItem()
5638 part = AuiDockUIPart()
5640 sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
5641 orientation = (dock.IsHorizontal() and [wx.HORIZONTAL] or [wx.VERTICAL])[0]
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]:
5647 sizer_item = cont.Add((sash_size, sash_size), 0, wx.EXPAND)
5649 part.type = AuiDockUIPart.typeDockSizer
5650 part.orientation = orientation
5654 part.cont_sizer = cont
5655 part.sizer_item = sizer_item
5656 uiparts.append(part)
5658 # create the sizer for the dock
5659 dock_sizer = wx.BoxSizer(orientation)
5661 # add each pane to the dock
5662 has_maximized_pane = False
5663 pane_count = len(dock.panes)
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)
5672 for pane_i in xrange(pane_count):
5674 pane = dock.panes[pane_i]
5675 pane_pos = pane_positions[pane_i]
5677 if pane.IsMaximized():
5678 has_maximized_pane = True
5680 amount = pane_pos - offset
5683 if dock.IsVertical():
5684 sizer_item = dock_sizer.Add((1, amount), 0, wx.EXPAND)
5686 sizer_item = dock_sizer.Add((amount, 1), 0, wx.EXPAND)
5688 part = AuiDockUIPart()
5689 part.type = AuiDockUIPart.typeBackground
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)
5699 offset = offset + amount
5701 uiparts = self.LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only)
5703 offset = offset + pane_sizes[pane_i]
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
5712 part.orientation = orientation
5713 part.cont_sizer = dock_sizer
5714 part.sizer_item = sizer_item
5715 uiparts.append(part)
5719 for pane_i in xrange(pane_count):
5721 pane = dock.panes[pane_i]
5723 if pane.IsMaximized():
5724 has_maximized_pane = True
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
5733 part.pane = dock.panes[pane_i-1]
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)
5741 uiparts = self.LayoutAddPane(dock_sizer, dock, pane, uiparts, spacer_only)
5743 if dock.dock_direction == AUI_DOCK_CENTER or has_maximized_pane:
5744 sizer_item = cont.Add(dock_sizer, 1, wx.EXPAND)
5746 sizer_item = cont.Add(dock_sizer, 0, wx.EXPAND)
5748 part = AuiDockUIPart()
5749 part.type = AuiDockUIPart.typeDock
5753 part.orientation = orientation
5754 part.cont_sizer = cont
5755 part.sizer_item = sizer_item
5756 uiparts.append(part)
5758 if dock.IsHorizontal():
5759 cont.SetItemMinSize(dock_sizer, (0, dock.size))
5761 cont.SetItemMinSize(dock_sizer, (dock.size, 0))
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]:
5767 sizer_item = cont.Add((sash_size, sash_size), 0, wx.EXPAND)
5769 part = AuiDockUIPart()
5770 part.type = AuiDockUIPart.typeDockSizer
5774 part.orientation = orientation
5775 part.cont_sizer = cont
5776 part.sizer_item = sizer_item
5777 uiparts.append(part)
5782 def LayoutAll(self, panes, docks, uiparts, spacer_only=False, oncheck=True):
5784 Layouts all the UI structures in the interface.
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.
5793 container = wx.BoxSizer(wx.VERTICAL)
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()
5799 # empty all docks out
5803 # always reset fixed docks' sizes, because
5804 # the contained windows may have been resized
5807 dock_count = len(docks)
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
5814 # don't layout hidden panes.
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)
5825 # dock was not found, so we need to create a new one
5827 d.dock_direction = p.dock_direction
5828 d.dock_layer = p.dock_layer
5829 d.dock_row = p.dock_row
5833 if p.HasFlag(p.needsRestore) and not p.HasFlag(p.wasMaximized):
5835 isHor = dock.IsHorizontal()
5836 sashSize = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
5838 # get the sizes of any docks that might
5839 # overlap with our restored dock
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 \
5846 d.dock_direction != AUI_DOCK_CENTER]
5848 frameRect = GetInternalFrameRect(self._frame, self._docks)
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)
5857 if p.HasFlag(p.wasMaximized):
5858 self.MaximizePane(p, savesizes=False)
5859 p.SetFlag(p.wasMaximized, False)
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)
5869 # remove the pane from any existing docks except this one
5870 docks = RemovePaneFromDocks(docks, p, dock)
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)
5877 # remove the pane from any existing docks
5878 docks = RemovePaneFromDocks(docks, p)
5880 # remove any empty docks
5881 docks = [dock for dock in docks if dock.panes]
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)
5891 # for newly created docks, set up their initial size
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)
5903 size = max(pane_size.x, size)
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
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
5920 for pane in dock.panes:
5921 if pane.HasCaptionLeft() and not pane.HasCaption():
5922 size = size + caption_size
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
5933 if dock.IsHorizontal():
5934 size = min(size, max_dock_y_size)
5936 size = min(size, max_dock_x_size)
5938 # absolute minimum size for a dock is 10 pixels
5944 # determine the dock's minimum size
5946 plus_caption = False
5947 plus_caption_left = False
5949 for pane in dock.panes:
5950 if pane.min_size != wx.Size(-1, -1):
5951 if pane.HasBorder():
5953 if pane.HasCaption():
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
5961 if pane.min_size.x > dock_min_size:
5962 dock_min_size = pane.min_size.x
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
5971 dock.min_size = dock_min_size
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
5978 # determine the dock's mode (fixed or proportional)
5979 # determine whether the dock has only toolbars
5980 action_pane_marked = False
5983 for pane in dock.panes:
5984 if not pane.IsFixed():
5986 if not pane.IsToolbar():
5987 dock.toolbar = False
5988 if pane.HasFlag(AuiPaneInfo.optionDockFixed):
5990 if pane.HasFlag(AuiPaneInfo.actionPane):
5991 action_pane_marked = True
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
5997 for jj in xrange(dock_pane_count):
5998 pane = dock.panes[jj]
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)
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
6015 pane.dock_pos += -amount
6017 offset += pane_sizes[jj]
6018 dock.panes[jj] = pane
6021 self._docks[ii] = dock
6023 # shrink docks if needed
6024 ## docks = self.SmartShrink(docks, AUI_DOCK_TOP)
6025 ## docks = self.SmartShrink(docks, AUI_DOCK_LEFT)
6030 # discover the maximum dock layer
6032 dock_count = len(docks)
6034 for ii in xrange(dock_count):
6035 max_layer = max(max_layer, docks[ii].dock_layer)
6040 # create a bunch of box sizers,
6041 # from the innermost level outwards.
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
6057 # create a container which will hold this layer's
6058 # docks (top, bottom, left, right)
6059 cont = wx.BoxSizer(wx.VERTICAL)
6061 # find any top docks in this layer
6062 arr = FindDocks(docks, AUI_DOCK_TOP, layer, -1)
6064 uiparts = self.LayoutAddDock(cont, row, uiparts, spacer_only)
6066 # fill out the middle layer (which consists
6067 # of left docks, content area and right docks)
6069 middle = wx.BoxSizer(wx.HORIZONTAL)
6071 # find any left docks in this layer
6072 arr = FindDocks(docks, AUI_DOCK_LEFT, layer, -1)
6074 uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only)
6076 # add content dock (or previous layer's sizer
6079 # find any center docks
6080 arr = FindDocks(docks, AUI_DOCK_CENTER, -1, -1)
6083 uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only)
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
6093 part.cont_sizer = middle
6094 part.sizer_item = sizer_item
6095 uiparts.append(part)
6097 middle.Add(old_cont, 1, wx.EXPAND)
6099 # find any right docks in this layer
6100 arr = FindDocks(docks, AUI_DOCK_RIGHT, layer, -1, reverse=True)
6102 uiparts = self.LayoutAddDock(middle, row, uiparts, spacer_only)
6104 if len(middle.GetChildren()) > 0:
6105 cont.Add(middle, 1, wx.EXPAND)
6107 # find any bottom docks in this layer
6108 arr = FindDocks(docks, AUI_DOCK_BOTTOM, layer, -1, reverse=True)
6110 uiparts = self.LayoutAddDock(cont, row, uiparts, spacer_only)
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
6122 part.cont_sizer = middle
6123 part.sizer_item = sizer_item
6124 uiparts.append(part)
6127 self._uiparts = uiparts
6130 container.Add(cont, 1, wx.EXPAND)
6135 return container, panes, docks, uiparts
6138 def SetDockSizeConstraint(self, width_pct, height_pct):
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
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.
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
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.
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))
6160 def GetDockSizeConstraint(self):
6162 Returns the current dock constraint values.
6164 :see: L{SetDockSizeConstraint}
6167 return self._dock_constraint_x, self._dock_constraint_y
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.
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.
6182 self._hover_button = None
6183 self._action_part = None
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:
6191 # because the pane is no longer in a floating, we need to
6192 # reparent it to self._frame and destroy the floating frame
6194 p.window.SetSize((1, 1))
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
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
6209 if p.frame.IsShown():
6212 if self._action_window == p.frame:
6213 self._action_window = None
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)
6221 p.frame.SetSizer(None)
6225 # Only the master manager should create/destroy notebooks...
6226 if not self._masterManager:
6227 self.UpdateNotebook()
6229 # delete old sizer first
6230 self._frame.SetSizer(None)
6232 # create a layout for all of the panes
6233 sizer = self.LayoutAll(self._panes, self._docks, self._uiparts, False)
6235 # hide or show panes as necessary,
6236 # and float panes as necessary
6238 pane_count = len(self._panes)
6240 for ii in xrange(pane_count):
6246 # we need to create a frame for this
6247 # pane, which has recently been floated
6248 frame = self.CreateFloatingFrame(self._frame, p)
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)
6259 if isinstance(bar, auibar.AuiToolBar):
6260 bar.SetGripperVisible(False)
6261 agwStyle = bar.GetAGWWindowStyleFlag()
6262 bar.SetAGWWindowStyleFlag(agwStyle & ~AUI_TB_VERTICAL)
6265 s = p.window.GetMinSize()
6267 p.FloatingSize(wx.DefaultSize)
6269 frame.SetPaneWindow(p)
6270 p.needsTransparency = True
6271 p.frame = pFrame = frame
6272 if p.IsShown() and not frame.IsShown():
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)
6283 # update whether the pane is resizable or not
6284 style = p.frame.GetWindowStyleFlag()
6286 style &= ~wx.RESIZE_BORDER
6288 style |= wx.RESIZE_BORDER
6290 p.frame.SetWindowStyleFlag(style)
6292 if pFrame.IsShown() != p.IsShown():
6293 p.needsTransparency = True
6294 pFrame.Show(p.IsShown())
6296 if pFrame.GetTitle() != p.caption:
6297 pFrame.SetTitle(p.caption)
6299 pFrame.SetIcon(wx.IconFromBitmap(p.icon))
6304 # self.SwitchToolBarOrientation(p)
6305 p.best_size = p.window.GetBestSize()
6307 if p.window and not p.IsNotebookPage() and p.window.IsShown() != p.IsShown():
6308 p.window.Show(p.IsShown())
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
6315 p.needsTransparency = False
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
6325 pane_count = len(self._panes)
6327 for p in self._panes:
6329 if p.window and p.IsShown() and p.IsDocked():
6332 old_pane_rects.append(r)
6334 # apply the new sizer
6335 self._frame.SetSizer(sizer)
6336 self._frame.SetAutoLayout(False)
6337 self.DoFrameLayout()
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):
6345 if p.window and p.IsShown() and p.IsDocked():
6346 if p.rect != old_pane_rects[ii]:
6350 if wx.Platform == "__WXMAC__":
6351 self._frame.Refresh()
6355 if not self._masterManager:
6356 e = self.FireEvent(wxEVT_AUI_PERSPECTIVE_CHANGED, None, canVeto=False)
6359 def UpdateNotebook(self):
6360 """ Updates the automatic L{AuiNotebook} in the layout (if any exists). """
6362 # Workout how many notebooks we need.
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
6371 # We are the master of our domain
6372 extra_notebook = len(self._notebooks)
6375 for i in xrange(extra_notebook, max_notebook):
6376 self.CreateNotebook()
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
6383 # Check each tab ...
6384 for page in xrange(pages):
6386 if page >= allPages:
6389 window = notebook.GetPage(pageCounter)
6390 paneInfo = self.GetPane(window)
6391 if paneInfo.IsOk() and paneInfo.notebook_id != nb:
6392 notebook.RemovePage(pageCounter)
6394 window.Reparent(self._frame)
6402 # Add notebook pages that aren't there already...
6403 for paneInfo in self._panes:
6404 if paneInfo.IsNotebookPage():
6406 title = (paneInfo.caption == "" and [paneInfo.name] or [paneInfo.caption])[0]
6408 notebook = self._notebooks[paneInfo.notebook_id]
6409 page_id = notebook.GetPageIndex(paneInfo.window)
6413 paneInfo.window.Reparent(notebook)
6414 notebook.AddPage(paneInfo.window, title, True, paneInfo.icon)
6416 # Update title and icon ...
6419 notebook.SetPageText(page_id, title)
6420 notebook.SetPageBitmap(page_id, paneInfo.icon)
6424 # Wire-up newly created notebooks
6425 elif paneInfo.IsNotebookControl() and not paneInfo.window:
6426 paneInfo.window = self._notebooks[paneInfo.notebook_id]
6428 # Delete empty notebooks, and convert notebooks with 1 page to
6430 remap_ids = [-1]*len(self._notebooks)
6433 for nb, notebook in enumerate(self._notebooks):
6434 if notebook.GetPageCount() == 1:
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():
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():
6450 self.DetachPane(notebook)
6452 notebook.RemovePage(0)
6457 raise Exception("Odd notebook docking")
6459 elif notebook.GetPageCount() == 0:
6461 self.DetachPane(notebook)
6466 # Correct page ordering. The original wxPython code
6467 # for this did not work properly, and would misplace
6468 # windows causing errors.
6470 self._notebooks[nb_idx] = notebook
6471 pages = notebook.GetPageCount()
6472 selected = notebook.GetPage(notebook.GetSelection())
6474 # Take each page out of the notebook, group it with
6475 # its current pane, and sort the list by pane.dock_pos
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)
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):
6493 self.SetAttributes(pane, attrs)
6494 notebook.AddPage(pane.window, pane.caption)
6496 notebook.SetSelection(notebook.GetPageIndex(selected), True)
6501 remap_ids[nb] = nb_idx
6505 nb_count = len(self._notebooks)
6507 if nb_count != nb_idx:
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()
6516 # Make sure buttons are correct ...
6517 for notebook in self._notebooks:
6522 pages = notebook.GetPageCount()
6523 for page in xrange(pages):
6525 win = notebook.GetPage(page)
6526 pane = self.GetPane(win)
6529 if not pane.HasCloseButton():
6531 if not pane.HasMaximizeButton():
6533 if not pane.HasMinimizeButton():
6536 notebook_pane = self.GetPane(notebook)
6537 if notebook_pane.IsOk():
6538 if notebook_pane.HasMinimizeButton() != want_min:
6540 button = AuiPaneButton(AUI_BUTTON_MINIMIZE)
6541 notebook_pane.state |= AuiPaneInfo.buttonMinimize
6542 notebook_pane.buttons.append(button)
6544 # todo: remove min/max
6546 if notebook_pane.HasMaximizeButton() != want_max:
6548 button = AuiPaneButton(AUI_BUTTON_MAXIMIZE_RESTORE)
6549 notebook_pane.state |= AuiPaneInfo.buttonMaximize
6550 notebook_pane.buttons.append(button)
6552 # todo: remove min/max
6554 if notebook_pane.HasCloseButton() != want_close:
6556 button = AuiPaneButton(AUI_BUTTON_CLOSE)
6557 notebook_pane.state |= AuiPaneInfo.buttonClose
6558 notebook_pane.buttons.append(button)
6560 # todo: remove close
6563 def SmartShrink(self, docks, direction):
6565 Used to intelligently shrink the docks' size (if needed).
6567 :param `docks`: a list of L{AuiDockInfo} instances;
6568 :param `direction`: the direction in which to shrink.
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)
6579 for dock in ourDocks:
6580 ourSize += dock.size
6582 if not dock.toolbar:
6585 shrinkSize = ourSize + oppositeSize
6587 if direction == AUI_DOCK_TOP or direction == AUI_DOCK_BOTTOM:
6588 shrinkSize -= clientSize.y
6590 shrinkSize -= clientSize.x
6596 for dock in oppositeDocks:
6597 ourDocks.append(dock)
6601 for dock in ourDocks:
6602 if dock.toolbar or not dock.resizable:
6605 dockRange = dock.size - dock.min_size
6607 if dock.min_size == 0:
6608 dockRange -= sashSize
6609 if direction == AUI_DOCK_TOP or direction == AUI_DOCK_BOTTOM:
6610 dockRange -= caption_size
6612 if dockRange >= shrinkSize:
6614 dock.size -= shrinkSize
6619 dock.size -= dockRange
6620 shrinkSize -= dockRange
6625 def UpdateDockingGuides(self, paneInfo):
6627 Updates the docking guide windows positions and appearance.
6629 :param `paneInfo`: a L{AuiPaneInfo} instance.
6632 if len(self._guides) == 0:
6633 self.CreateGuideWindows()
6635 captionSize = self._art.GetMetric(AUI_DOCKART_CAPTION_SIZE)
6636 frameRect = GetInternalFrameRect(self._frame, self._docks)
6637 mousePos = wx.GetMousePosition()
6639 for indx, guide in enumerate(self._guides):
6642 guide_size = guide.host.GetSize()
6644 raise Exception("Invalid docking host")
6646 direction = guide.dock_direction
6648 if direction == AUI_DOCK_LEFT:
6649 pt.x = frameRect.x + guide_size.x / 2 + 16
6650 pt.y = frameRect.y + frameRect.height / 2
6652 elif direction == AUI_DOCK_TOP:
6653 pt.x = frameRect.x + frameRect.width / 2
6654 pt.y = frameRect.y + guide_size.y / 2 + 16
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
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
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
6673 # guide will be centered around point 'pt'
6674 targetPosition = wx.Point(pt.x - guide_size.x / 2, pt.y - guide_size.y / 2)
6676 if guide.host.GetPosition() != targetPosition:
6677 guide.host.Move(targetPosition)
6679 guide.host.AeroMove(targetPosition)
6681 if guide.dock_direction == AUI_DOCK_CENTER:
6682 guide.host.ValidateNotebookDocking(paneInfo.IsNotebookDockable())
6684 guide.host.UpdateDockGuide(mousePos)
6686 paneInfo.window.Lower()
6689 def DoFrameLayout(self):
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.
6695 :note: This should always be called instead of calling
6696 `self._managed_window.Layout()` directly.
6699 self._frame.Layout()
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
6713 part.rect = part.sizer_item.GetRect()
6714 flag = part.sizer_item.GetFlag()
6715 border = part.sizer_item.GetBorder()
6718 part.rect.y -= border
6719 part.rect.height += border
6721 part.rect.x -= border
6722 part.rect.width += border
6723 if flag & wx.BOTTOM:
6724 part.rect.height += border
6726 part.rect.width += border
6728 if part.type == AuiDockUIPart.typeDock:
6729 part.dock.rect = part.rect
6730 if part.type == AuiDockUIPart.typePane:
6731 part.pane.rect = part.rect
6734 def GetPanePart(self, wnd):
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.
6740 :param `wnd`: the window to which the pane border belongs to.
6743 for part in self._uiparts:
6744 if part.type == AuiDockUIPart.typePaneBorder and \
6745 part.pane and part.pane.window == wnd:
6748 for part in self._uiparts:
6749 if part.type == AuiDockUIPart.typePane and \
6750 part.pane and part.pane.window == wnd:
6756 def GetDockPixelOffset(self, test):
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
6763 This value is necessary for calculating fixed-pane/toolbar offsets
6764 when they are dragged.
6766 :param `test`: a fake L{AuiPaneInfo} for testing purposes.
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)
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)
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
6789 if test.dock_direction == dock.dock_direction and \
6790 test.dock_layer == dock.dock_layer and \
6791 test.dock_row == dock.dock_row:
6793 if dock.IsVertical():
6801 def GetPartnerDock(self, dock):
6803 Returns the partner dock for the input dock.
6805 :param `dock`: a L{AuiDockInfo} instance.
6808 for layer in xrange(dock.dock_layer, -1, -1):
6812 for tmpDock in self._docks:
6814 if tmpDock.dock_layer != layer:
6817 if tmpDock.dock_direction != dock.dock_direction:
6820 if tmpDock.dock_layer < dock.dock_layer:
6822 if not bestDock or tmpDock.dock_row < bestDock.dock_row:
6825 elif tmpDock.dock_row > dock.dock_row:
6827 if not bestDock or tmpDock.dock_row > bestDock.dock_row:
6836 def GetPartnerPane(self, dock, pane):
6838 Returns the partner pane for the input pane. They both need to live
6839 in the same L{AuiDockInfo}.
6841 :param `dock`: a L{AuiDockInfo} instance;
6842 :param `pane`: a L{AuiPaneInfo} class.
6847 for i, tmpPane in enumerate(dock.panes):
6848 if tmpPane.window == pane.window:
6850 elif not tmpPane.IsFixed() and panePosition != -1:
6856 def GetTotalPixSizeAndProportion(self, dock):
6858 Returns the dimensions and proportion of the input dock.
6860 :param `dock`: the L{AuiDockInfo} structure to analyze.
6866 # determine the total proportion of all resizable panes,
6867 # and the total size of the dock minus the size of all
6869 for tmpPane in dock.panes:
6871 if tmpPane.IsFixed():
6874 totalProportion += tmpPane.dock_proportion
6876 if dock.IsHorizontal():
6877 totalPixsize += tmpPane.rect.width
6879 totalPixsize += tmpPane.rect.height
6881 ## if tmpPane.min_size.IsFullySpecified():
6883 ## if dock.IsHorizontal():
6884 ## totalPixsize -= tmpPane.min_size.x
6886 ## totalPixsize -= tmpPane.min_size.y
6888 return totalPixsize, totalProportion
6891 def GetOppositeDockTotalSize(self, docks, direction):
6893 Returns the dimensions of the dock which lives opposite of the input dock.
6895 :param `docks`: a list of L{AuiDockInfo} structures to analyze;
6896 :param `direction`: the direction in which to look for the opposite dock.
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)
6906 if direction in [AUI_DOCK_TOP, AUI_DOCK_BOTTOM]:
6909 # Get minimum size of the most inner area
6910 for tmpDock in docks:
6912 if tmpDock.dock_layer != 0:
6915 if tmpDock.dock_direction != AUI_DOCK_CENTER and tmpDock.IsVertical() != vertical:
6918 for tmpPane in tmpDock.panes:
6920 minSize = pane_border_size*2 - sash_size
6923 minSize += tmpPane.min_size.y + caption_size
6925 minSize += tmpPane.min_size.x
6927 if minSize > minSizeMax:
6928 minSizeMax = minSize
6930 result += minSizeMax
6932 # Get opposite docks
6933 oppositeDocks = FindOppositeDocks(docks, direction)
6935 # Sum size of the opposite docks and their sashes
6936 for dock in oppositeDocks:
6938 # if it's not a toolbar add the sash_size too
6939 if not dock.toolbar:
6945 def CalculateDockSizerLimits(self, dock):
6947 Calculates the minimum and maximum sizes allowed for the input dock.
6949 :param `dock`: the L{AuiDockInfo} structure to analyze.
6952 docks, panes = CopyDocksAndPanes2(self._docks, self._panes)
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)
6958 for tmpDock in docks:
6960 if tmpDock.dock_direction == dock.dock_direction and \
6961 tmpDock.dock_layer == dock.dock_layer and \
6962 tmpDock.dock_row == dock.dock_row:
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)
6972 for part in uiparts:
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
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:
6989 partnerDock = self.GetPartnerDock(dock)
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
6998 direction = dock.dock_direction
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
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
7010 elif direction == AUI_DOCK_RIGHT:
7011 minPix = dock.rect.x - partnerRange - sash_size
7012 maxPix = new_dock.rect.x - sash_size
7014 elif direction == AUI_DOCK_BOTTOM:
7015 minPix = dock.rect.y - partnerRange - sash_size
7016 maxPix = new_dock.rect.y - sash_size
7018 return minPix, maxPix
7020 direction = new_dock.dock_direction
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
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
7030 elif direction == AUI_DOCK_RIGHT:
7031 minPix = opposite_size
7032 maxPix = new_dock.rect.x - sash_size
7034 elif direction == AUI_DOCK_BOTTOM:
7035 minPix = opposite_size
7036 maxPix = new_dock.rect.y - sash_size
7038 return minPix, maxPix
7041 def CalculatePaneSizerLimits(self, dock, pane):
7043 Calculates the minimum and maximum sizes allowed for the input pane.
7045 :param `dock`: the L{AuiDockInfo} structure to which `pane` belongs to;
7046 :param `pane`: a L{AuiPaneInfo} class for which calculation are requested.
7050 if dock.IsHorizontal():
7051 minPix = maxPix = pane.rect.x + 1 + pane.rect.width
7053 minPix = maxPix = pane.rect.y + 1 + pane.rect.height
7055 return minPix, maxPix
7057 totalPixsize, totalProportion = self.GetTotalPixSizeAndProportion(dock)
7058 partnerPane = self.GetPartnerPane(dock, pane)
7060 if dock.IsHorizontal():
7062 minPix = pane.rect.x + 1
7063 maxPix = pane.rect.x + 1 + pane.rect.width
7065 if pane.min_size.IsFullySpecified():
7066 minPix += pane.min_size.x
7071 maxPix += partnerPane.rect.width
7073 if partnerPane.min_size.IsFullySpecified():
7074 maxPix -= partnerPane.min_size.x - 1
7081 minPix = pane.rect.y + 1
7082 maxPix = pane.rect.y + 1 + pane.rect.height
7084 if pane.min_size.IsFullySpecified():
7085 minPix += pane.min_size.y
7090 maxPix += partnerPane.rect.height
7092 if partnerPane.min_size.IsFullySpecified():
7093 maxPix -= partnerPane.min_size.y - 1
7098 return minPix, maxPix
7101 def CheckMovableSizer(self, part):
7103 Checks if a UI part can be actually resized.
7105 :param `part`: a UI part.
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():
7117 # panes that may not be resized should be ignored here
7118 minPix, maxPix = self.CalculatePaneSizerLimits(part.dock, part.pane)
7120 if minPix == maxPix:
7126 def PaneFromTabEvent(self, event):
7128 Returns a L{AuiPaneInfo} from a L{AuiNotebookEvent} event.
7130 :param `event`: a L{AuiNotebookEvent} event.
7133 obj = event.GetEventObject()
7135 if obj and isinstance(obj, auibook.AuiTabCtrl):
7137 page_idx = obj.GetActivePage()
7140 page = obj.GetPage(page_idx)
7141 window = page.window
7143 return self.GetPane(window)
7145 elif obj and isinstance(obj, auibook.AuiNotebook):
7147 page_idx = event.GetSelection()
7150 window = obj.GetPage(page_idx)
7152 return self.GetPane(window)
7157 def OnTabBeginDrag(self, event):
7159 Handles the ``EVT_AUINOTEBOOK_BEGIN_DRAG`` event.
7161 :param `event`: a L{AuiNotebookEvent} event to be processed.
7164 if self._masterManager:
7165 self._masterManager.OnTabBeginDrag(event)
7168 paneInfo = self.PaneFromTabEvent(event)
7173 self._action = actionDragFloatingPane
7174 mouse = wx.GetMousePosition()
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)
7181 paneInfo.floating_pos = mouse - self._action_offset
7182 paneInfo.dock_pos = AUI_DOCK_NONE
7183 paneInfo.notebook_id = -1
7185 tab = event.GetEventObject()
7187 if tab.HasCapture():
7191 if paneInfo.IsMaximized():
7192 self.RestorePane(paneInfo)
7196 self._action_window = paneInfo.window
7198 self._frame.CaptureMouse()
7199 event.SetDispatched(True)
7207 def OnTabPageClose(self, event):
7209 Handles the ``EVT_AUINOTEBOOK_PAGE_CLOSE`` event.
7211 :param `event`: a L{AuiNotebookEvent} event to be processed.
7214 if self._masterManager:
7215 self._masterManager.OnTabPageClose(event)
7219 p = self.PaneFromTabEvent(event)
7222 # veto it because we will call "RemovePage" ourselves
7225 # Now ask the app if they really want to close...
7226 # fire pane close event
7227 e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE)
7230 self.ProcessMgrEvent(e)
7241 def OnTabSelected(self, event):
7243 Handles the ``EVT_AUINOTEBOOK_PAGE_CHANGED`` event.
7245 :param `event`: a L{AuiNotebookEvent} event to be processed.
7248 if self._masterManager:
7249 self._masterManager.OnTabSelected(event)
7252 obj = event.GetEventObject()
7254 if obj and isinstance(obj, auibook.AuiNotebook):
7257 page = notebook.GetPage(event.GetSelection())
7258 paneInfo = self.GetPane(page)
7261 notebookRoot = GetNotebookRoot(self._panes, paneInfo.notebook_id)
7264 notebookRoot.Caption(paneInfo.caption)
7265 self.RefreshCaptions()
7270 def GetNotebooks(self):
7271 """ Returns all the automatic L{AuiNotebook} in the L{AuiManager}. """
7273 if self._masterManager:
7274 return self._masterManager.GetNotebooks()
7276 return self._notebooks
7279 def SetMasterManager(self, manager):
7281 Sets the master manager for an automatic L{AuiNotebook}.
7283 :param `manager`: an instance of L{AuiManager}.
7286 self._masterManager = manager
7289 def ProcessDockResult(self, target, new_pos):
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``.
7295 :param `target`: the L{AuiPaneInfo} instance to be docked;
7296 :param `new_pos`: the new docking position if the docking operation is allowed.
7300 direction = new_pos.dock_direction
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()
7314 if target.IsToolbar():
7315 self.SwitchToolBarOrientation(target)
7317 return allowed, target
7320 def SwitchToolBarOrientation(self, pane):
7322 Switches the toolbar orientation from vertical to horizontal and vice-versa.
7323 This is especially useful for vertical docked toolbars once they float.
7325 :param `pane`: an instance of L{AuiPaneInfo}, which may have a L{AuiToolBar}
7326 window associated with it.
7329 if not isinstance(pane.window, auibar.AuiToolBar):
7332 if pane.IsFloating():
7335 toolBar = pane.window
7336 direction = pane.dock_direction
7337 vertical = direction in [AUI_DOCK_LEFT, AUI_DOCK_RIGHT]
7339 agwStyle = toolBar.GetAGWWindowStyleFlag()
7340 new_agwStyle = agwStyle
7343 new_agwStyle |= AUI_TB_VERTICAL
7345 new_agwStyle &= ~(AUI_TB_VERTICAL)
7347 if agwStyle != new_agwStyle:
7348 toolBar.SetAGWWindowStyleFlag(new_agwStyle)
7349 if not toolBar.GetGripperVisible():
7350 toolBar.SetGripperVisible(True)
7352 s = pane.window.GetMinSize()
7355 if new_agwStyle != agwStyle:
7361 def DoDrop(self, docks, panes, target, pt, offset=wx.Point(0, 0)):
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.
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`.
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)
7380 return self.DoDropNonFloatingPane(docks, panes, target, pt)
7383 def CopyTarget(self, target):
7385 Copies all the attributes of the input `target` into another L{AuiPaneInfo}.
7387 :param `target`: the source L{AuiPaneInfo} from where to copy attributes.
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
7417 def DoDropToolbar(self, docks, panes, target, pt, offset):
7419 Handles the situation in which the dropped pane contains a toolbar.
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`.
7428 drop = self.CopyTarget(target)
7430 # The result should always be shown
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():
7438 return self.ProcessDockResult(target, drop)
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)
7445 safeRect.Inflate(50, 100)
7447 # Check to see if the toolbar has been dragged to edge of the frame
7448 dropDir = CheckEdgeDrop(self._frame, docks, pt)
7452 if dropDir == wx.LEFT:
7453 drop.Dock().Left().Layer(auiToolBarLayer).Row(0). \
7454 Position(pt.y - self.GetDockPixelOffset(drop) - offset.y)
7456 elif dropDir == wx.RIGHT:
7457 drop.Dock().Right().Layer(auiToolBarLayer).Row(0). \
7458 Position(pt.y - self.GetDockPixelOffset(drop) - offset.y)
7460 elif dropDir == wx.TOP:
7461 drop.Dock().Top().Layer(auiToolBarLayer).Row(0). \
7462 Position(pt.x - self.GetDockPixelOffset(drop) - offset.x)
7464 elif dropDir == wx.BOTTOM:
7465 drop.Dock().Bottom().Layer(auiToolBarLayer).Row(0). \
7466 Position(pt.x - self.GetDockPixelOffset(drop) - offset.x)
7468 if not target.IsFloating() and safeRect.Contains(pt) and \
7469 target.dock_direction != drop.dock_direction:
7470 return False, target
7472 return self.ProcessDockResult(target, drop)
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
7478 # Ok, can't drop on edge - check internals ...
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)
7485 if not part or not part.dock:
7486 return False, target
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:
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():
7500 return self.ProcessDockResult(target, drop)
7502 # calculate the offset from where the dock begins
7503 # to the point where the user dropped the pane
7505 if dock.IsHorizontal():
7506 dockDropOffset = pt.x - dock.rect.x - offset.x
7508 dockDropOffset = pt.y - dock.rect.y - offset.y
7510 drop.Dock().Direction(dock.dock_direction).Layer(dock.dock_layer). \
7511 Row(dock.dock_row).Position(dockDropOffset)
7513 if (pt.y <= dock.rect.GetTop() + 2 and dock.IsHorizontal()) or \
7514 (pt.x <= dock.rect.GetLeft() + 2 and dock.IsVertical()):
7516 if dock.dock_direction in [AUI_DOCK_TOP, AUI_DOCK_LEFT]:
7518 panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row)
7522 panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row+1)
7523 drop.dock_row = dock.dock_row + 1
7525 if (pt.y >= dock.rect.GetBottom() - 2 and dock.IsHorizontal()) or \
7526 (pt.x >= dock.rect.GetRight() - 2 and dock.IsVertical()):
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
7534 panes = DoInsertDockRow(panes, dock.dock_direction, dock.dock_layer, dock.dock_row)
7537 if not target.IsFloating() and safeRect.Contains(pt) and \
7538 target.dock_direction != drop.dock_direction:
7539 return False, target
7541 return self.ProcessDockResult(target, drop)
7544 def DoDropFloatingPane(self, docks, panes, target, pt):
7546 Handles the situation in which the dropped pane contains a normal window.
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.
7554 screenPt = self._frame.ClientToScreen(pt)
7555 paneInfo = self.PaneHitTest(panes, pt)
7557 if paneInfo.IsMaximized():
7558 return False, target
7560 if paneInfo.window is None:
7561 return False, target
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]
7568 # do hit testing on the guide
7569 dir = guide.host.HitTest(screenPt.x, screenPt.y)
7571 if dir == -1: # point was outside of the dock guide
7574 if dir == wx.ALL: # target is a single dock guide
7575 return self.DoDropLayer(docks, target, guide.dock_direction)
7577 elif dir == wx.CENTER:
7579 if not target.IsNotebookDockable():
7581 if not paneInfo.IsNotebookDockable() and not paneInfo.IsNotebookControl():
7584 if not paneInfo.HasNotebook():
7586 # Add a new notebook pane with the original as a tab...
7587 self.CreateNotebookBase(panes, paneInfo)
7589 # Add new item to notebook
7590 target.NotebookPage(paneInfo.notebook_id)
7597 insert_dir = paneInfo.dock_direction
7598 insert_layer = paneInfo.dock_layer
7599 insert_row = paneInfo.dock_row
7600 insert_pos = paneInfo.dock_pos
7602 if insert_dir == AUI_DOCK_CENTER:
7606 insert_dir = AUI_DOCK_LEFT
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
7614 if insert_dir == AUI_DOCK_LEFT:
7616 drop_pane = (dir == wx.UP or dir == wx.DOWN)
7617 drop_row = (dir == wx.LEFT or dir == wx.RIGHT)
7620 elif dir == wx.DOWN:
7623 elif insert_dir == AUI_DOCK_RIGHT:
7625 drop_pane = (dir == wx.UP or dir == wx.DOWN)
7626 drop_row = (dir == wx.LEFT or dir == wx.RIGHT)
7629 elif dir == wx.DOWN:
7632 elif insert_dir == AUI_DOCK_TOP:
7634 drop_pane = (dir == wx.LEFT or dir == wx.RIGHT)
7635 drop_row = (dir == wx.UP or dir == wx.DOWN)
7638 elif dir == wx.RIGHT:
7641 elif insert_dir == AUI_DOCK_BOTTOM:
7643 drop_pane = (dir == wx.LEFT or dir == wx.RIGHT)
7644 drop_row = (dir == wx.UP or dir == wx.DOWN)
7647 elif dir == wx.RIGHT:
7650 if paneInfo.dock_direction == AUI_DOCK_CENTER:
7651 insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1
7654 return self.DoDropPane(panes, target, insert_dir, insert_layer, insert_row, insert_pos)
7657 return self.DoDropRow(panes, target, insert_dir, insert_layer, insert_row)
7661 return False, target
7664 def DoDropNonFloatingPane(self, docks, panes, target, pt):
7666 Handles the situation in which the dropped pane is not floating.
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.
7674 screenPt = self._frame.ClientToScreen(pt)
7675 clientSize = self._frame.GetClientSize()
7676 frameRect = GetInternalFrameRect(self._frame, self._docks)
7678 drop = self.CopyTarget(target)
7680 # The result should always be shown
7683 part = self.HitTest(pt.x, pt.y)
7686 return False, target
7688 if part.type == AuiDockUIPart.typeDockSizer:
7690 if len(part.dock.panes) != 1:
7691 return False, target
7693 part = self.GetPanePart(part.dock.panes[0].window)
7695 return False, target
7698 return False, target
7700 part = self.GetPanePart(part.pane.window)
7702 return False, target
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
7709 direction = part.pane.dock_direction
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
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
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
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
7729 elif direction == AUI_DOCK_CENTER:
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
7736 if new_row_pixels_x > (part.rect.width*20)/100:
7737 new_row_pixels_x = (part.rect.width*20)/100
7739 if new_row_pixels_y > (part.rect.height*20)/100:
7740 new_row_pixels_y = (part.rect.height*20)/100
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
7747 insert_dock_row = True
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
7759 return False, target
7761 insert_row = GetMaxRow(panes, insert_dir, insert_layer) + 1
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)
7769 return self.ProcessDockResult(target, drop)
7771 # determine the mouse offset and the pane size, both in the
7772 # direction of the dock itself, and perpendicular to the dock
7774 if part.orientation == wx.VERTICAL:
7776 offset = pt.y - part.rect.y
7777 size = part.rect.GetHeight()
7781 offset = pt.x - part.rect.x
7782 size = part.rect.GetWidth()
7784 drop_position = part.pane.dock_pos
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:
7790 drop_position = part.pane.dock_pos
7791 panes = DoInsertPane(panes,
7792 part.pane.dock_direction,
7793 part.pane.dock_layer,
7797 # if we are in the bottom/right part of the pane,
7798 # insert the pane before the pane being hovered over
7801 drop_position = part.pane.dock_pos+1
7802 panes = DoInsertPane(panes,
7803 part.pane.dock_direction,
7804 part.pane.dock_layer,
7806 part.pane.dock_pos+1)
7810 Direction(part.dock.dock_direction). \
7811 Layer(part.dock.dock_layer).Row(part.dock.dock_row). \
7812 Position(drop_position)
7814 return self.ProcessDockResult(target, drop)
7817 def DoDropLayer(self, docks, target, dock_direction):
7819 Handles the situation in which `target` is a single dock guide.
7821 :param `docks`: a list of L{AuiDockInfo} classes;
7822 :param `target`: the target pane;
7823 :param `dock_direction`: the docking direction.
7826 drop = self.CopyTarget(target)
7828 if dock_direction == AUI_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
7834 elif dock_direction == AUI_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
7840 elif dock_direction == AUI_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
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
7853 return False, target
7856 drop.Dock().Layer(drop_new_layer)
7857 return self.ProcessDockResult(target, drop)
7860 def DoDropPane(self, panes, target, dock_direction, dock_layer, dock_row, dock_pos):
7862 Drop a pane in the interface.
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.
7872 drop = self.CopyTarget(target)
7873 panes = DoInsertPane(panes, dock_direction, dock_layer, dock_row, dock_pos)
7875 drop.Dock().Direction(dock_direction).Layer(dock_layer).Row(dock_row).Position(dock_pos)
7876 return self.ProcessDockResult(target, drop)
7879 def DoDropRow(self, panes, target, dock_direction, dock_layer, dock_row):
7881 Insert a row in the interface before dropping.
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.
7890 drop = self.CopyTarget(target)
7891 panes = DoInsertDockRow(panes, dock_direction, dock_layer, dock_row)
7893 drop.Dock().Direction(dock_direction).Layer(dock_layer).Row(dock_row).Position(0)
7894 return self.ProcessDockResult(target, drop)
7897 def ShowHint(self, rect):
7899 Shows the AUI hint window.
7901 :param `rect`: the hint rect calculated in advance.
7904 if rect == self._last_hint:
7907 if self._agwFlags & AUI_MGR_RECTANGLE_HINT and wx.Platform != "__WXMAC__":
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()
7915 screendc = wx.ScreenDC()
7916 clip = wx.Region(1, 1, 10000, 10000)
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():
7922 rect2 = wx.Rect(*pane.frame.GetRect())
7923 if wx.Platform == "__WXGTK__":
7924 # wxGTK returns the client size, not the whole frame size
7929 clip.SubtractRect(rect2)
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)
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)
7949 if not self._hint_window:
7950 self.CreateHintWindow()
7952 if self._hint_window:
7953 self._hint_window.SetRect(rect)
7954 self._hint_window.Show()
7956 self._hint_fadeamt = self._hint_fademax
7958 if self._agwFlags & AUI_MGR_HINT_FADE:
7959 self._hint_fadeamt = 0
7960 self._hint_window.SetTransparent(self._hint_fadeamt)
7962 if self._action == actionDragFloatingPane and self._action_window:
7963 self._action_window.SetFocus()
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)
7969 self._last_hint = wx.Rect(*rect)
7973 """ Hides a transparent window hint if there is one. """
7975 # hides a transparent window hint if there is one
7976 if self._hint_window:
7977 self._hint_window.Hide()
7979 self._hint_fadetimer.Stop()
7980 self._last_hint = wx.Rect()
7983 def IsPaneButtonVisible(self, part):
7985 Returns whether a pane button in the pane caption is visible.
7987 :param `part`: the UI part to analyze.
7990 captionRect = wx.Rect()
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
7998 return captionRect.ContainsRect(part.rect)
8001 def DrawPaneButton(self, dc, part, pt):
8003 Draws a pane button in the caption (convenience function).
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.
8010 if not self.IsPaneButtonVisible(part):
8013 state = AUI_BUTTON_STATE_NORMAL
8015 if part.rect.Contains(pt):
8017 if _VERSION_STRING < "2.9":
8018 leftDown = wx.GetMouseState().LeftDown()
8020 leftDown = wx.GetMouseState().LeftIsDown()
8023 state = AUI_BUTTON_STATE_PRESSED
8025 state = AUI_BUTTON_STATE_HOVER
8027 self._art.DrawPaneButton(dc, self._frame, part.button.button_id,
8028 state, part.rect, part.pane)
8031 def RefreshButton(self, part):
8033 Refreshes a pane button in the caption.
8035 :param `part`: the UI part to analyze.
8038 rect = wx.Rect(*part.rect)
8040 self._frame.Refresh(True, rect)
8041 self._frame.Update()
8044 def RefreshCaptions(self):
8045 """ Refreshes all pane captions. """
8047 for part in self._uiparts:
8048 if part.type == AuiDockUIPart.typeCaption:
8049 self._frame.Refresh(True, part.rect)
8050 self._frame.Update()
8053 def CalculateHintRect(self, pane_window, pt, offset):
8055 Calculates the drop hint rectangle.
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.
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.
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
8074 pane = self.GetPane(pane_window)
8076 attrs = self.GetAttributes(pane)
8077 hint = AuiPaneInfo()
8078 hint = self.SetAttributes(hint, attrs)
8080 if hint.name != "__HINT__":
8081 self._oldname = hint.name
8083 hint.name = "__HINT__"
8084 hint.PaneBorder(True)
8088 hint.name = self._oldname
8091 docks, panes = CopyDocksAndPanes2(self._docks, self._panes)
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])
8101 # find out where the new pane would be
8102 allow, hint = self.DoDrop(docks, panes, hint, pt, offset)
8109 sizer, panes, docks, uiparts = self.LayoutAll(panes, docks, [], True, False)
8111 client_size = self._frame.GetClientSize()
8112 sizer.SetDimension(0, 0, client_size.x, client_size.y)
8117 # For a notebook page, actually look for the noteboot itself.
8118 if hint.IsNotebookPage():
8119 id = hint.notebook_id
8121 if pane.IsNotebookControl() and pane.notebook_id==id:
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()))
8132 # check for floating frame ...
8135 if p.name == sought and p.IsFloating():
8136 return wx.RectPS(p.floating_pos, p.floating_size)
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()
8150 def DrawHintRect(self, pane_window, pt, offset):
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.
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.
8163 rect = self.CalculateHintRect(pane_window, pt, offset)
8167 self._hint_rect = wx.Rect()
8170 self._hint_rect = wx.Rect(*rect)
8173 def GetPartSizerRect(self, uiparts):
8175 Returns the rectangle surrounding the specified UI parts.
8177 :param `uiparts`: UI parts.
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()))
8190 def GetAttributes(self, pane):
8192 Returns all the attributes of a L{AuiPaneInfo}.
8194 :param `pane`: a L{AuiPaneInfo} instance.
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])
8208 def SetAttributes(self, pane, attrs):
8210 Sets all the attributes contained in `attrs` to a L{AuiPaneInfo}.
8212 :param `pane`: a L{AuiPaneInfo} instance;
8213 :param `attrs`: a list of attributes.
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]
8242 def OnFloatingPaneResized(self, wnd, size):
8244 Handles the resizing of a floating pane.
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.
8250 # try to find the pane
8251 pane = self.GetPane(wnd)
8253 raise Exception("Pane window not found")
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)
8264 def OnFloatingPaneClosed(self, wnd, event):
8266 Handles the close event of a floating pane.
8268 :param `wnd`: a `wx.Window` derived window, managed by the pane;
8269 :param `event`: a `wx.CloseEvent` to be processed.
8272 # try to find the pane
8273 pane = self.GetPane(wnd)
8275 raise Exception("Pane window not found")
8277 # fire pane close event
8278 e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE)
8280 e.SetCanVeto(event.CanVeto())
8281 self.ProcessMgrEvent(e)
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)
8291 check = self.GetPane(wnd)
8293 self.ClosePane(pane)
8296 def OnFloatingPaneActivated(self, wnd):
8298 Handles the activation event of a floating pane.
8300 :param `wnd`: a `wx.Window` derived window, managed by the pane.
8303 pane = self.GetPane(wnd)
8305 raise Exception("Pane window not found")
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)
8313 def OnFloatingPaneMoved(self, wnd, eventOrPt):
8315 Handles the move event of a floating pane.
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`.
8321 pane = self.GetPane(wnd)
8323 raise Exception("Pane window not found")
8325 if not pane.IsSnappable():
8328 if isinstance(eventOrPt, wx.Point):
8329 pane_pos = wx.Point(*eventOrPt)
8331 pane_pos = eventOrPt.GetPosition()
8333 pane_size = pane.floating_size
8335 self.SnapPane(pane, pane_pos, pane_size, False)
8338 def SnapPane(self, pane, pane_pos, pane_size, toSnap=False):
8340 Snaps a floating pane to one of the main frame sides.
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
8352 managed_window = self.GetManagedWindow()
8353 wnd_pos = managed_window.GetPosition()
8354 wnd_size = managed_window.GetSize()
8355 snapX, snapY = self._snap_limits
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)
8384 self.RepositionPane(pane, wnd_pos, wnd_size)
8387 def RepositionPane(self, pane, wnd_pos, wnd_size):
8389 Repositions a pane after the main frame has been moved/resized.
8391 :param `pane`: a L{AuiPaneInfo} instance;
8392 :param `wnd_pos`: the main frame position;
8393 :param `wnd_size`: the main frame size.
8396 pane_pos = pane.floating_pos
8397 pane_size = pane.floating_size
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)
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
8417 def OnGripperClicked(self, pane_window, start, offset):
8419 Handles the mouse click on the pane gripper.
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.
8426 # try to find the pane
8427 paneInfo = self.GetPane(pane_window)
8429 if not paneInfo.IsOk():
8430 raise Exception("Pane window not found")
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)
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)
8445 self._frame.CaptureMouse()
8447 if paneInfo.IsDocked():
8448 self._action = actionClickCaption
8450 if paneInfo.IsToolbar():
8451 self._action = actionDragToolbarPane
8453 self._action = actionDragFloatingPane
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)
8462 if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
8463 paneInfo.frame.SetTransparent(150)
8465 if paneInfo.IsToolbar():
8466 self._frame.SetCursor(wx.StockCursor(wx.CURSOR_SIZING))
8469 def OnRender(self, event):
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.
8475 :param `event`: an instance of L{AuiManagerEvent}.
8478 # if the frame is about to be deleted, don't bother
8479 if not self._frame or self._frame.IsBeingDeleted():
8482 if not self._frame.GetSizer():
8485 mouse = wx.GetMouseState()
8486 mousePos = wx.Point(mouse.GetX(), mouse.GetY())
8487 point = self._frame.ScreenToClient(mousePos)
8492 for part in self._uiparts:
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()):
8504 if ptype in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
8505 art.DrawSash(dc, self._frame, part.orientation, part.rect)
8507 elif ptype == AuiDockUIPart.typeBackground:
8508 art.DrawBackground(dc, self._frame, part.orientation, part.rect)
8510 elif ptype == AuiDockUIPart.typeCaption:
8511 art.DrawCaption(dc, self._frame, part.pane.caption, part.rect, part.pane)
8513 elif ptype == AuiDockUIPart.typeGripper:
8514 art.DrawGripper(dc, self._frame, part.rect, part.pane)
8516 elif ptype == AuiDockUIPart.typePaneBorder:
8517 art.DrawBorder(dc, self._frame, part.rect, part.pane)
8519 elif ptype == AuiDockUIPart.typePaneButton:
8520 self.DrawPaneButton(dc, part, point)
8523 def Repaint(self, dc=None):
8525 Repaints the entire frame decorations (sashes, borders, buttons and so on).
8526 It renders the entire user interface.
8528 :param `dc`: if not ``None``, an instance of `wx.PaintDC`.
8531 w, h = self._frame.GetClientSize()
8533 # Figure out which dc to use; if one
8534 # has been specified, use it, otherwise
8537 client_dc = wx.ClientDC(self._frame)
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)
8546 # Render all the items
8550 def Render(self, dc):
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.
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
8560 :param `dc`: a `wx.DC` device context object.
8563 e = AuiManagerEvent(wxEVT_AUI_RENDER)
8566 self.ProcessMgrEvent(e)
8569 def OnCaptionDoubleClicked(self, pane_window):
8571 Handles the mouse double click on the pane caption.
8573 :param `pane_window`: a `wx.Window` derived window, managed by the pane.
8576 # try to find the pane
8577 paneInfo = self.GetPane(pane_window)
8578 if not paneInfo.IsOk():
8579 raise Exception("Pane window not found")
8581 if not paneInfo.IsFloatable() or not paneInfo.IsDockable() or \
8582 self._agwFlags & AUI_MGR_ALLOW_FLOATING == 0:
8585 indx = self._panes.index(paneInfo)
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)
8597 e = self.FireEvent(wxEVT_AUI_PANE_DOCKING, paneInfo, canVeto=True)
8600 ShowDockingGuides(self._guides, False)
8603 win_rect = paneInfo.frame.GetRect()
8605 if paneInfo.IsToolbar():
8606 paneInfo = self.SwitchToolBarOrientation(paneInfo)
8608 e = self.FireEvent(wxEVT_AUI_PANE_DOCKED, paneInfo, canVeto=False)
8612 e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, paneInfo, canVeto=True)
8617 if paneInfo.IsMaximized():
8618 self.RestorePane(paneInfo)
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
8626 e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, paneInfo, canVeto=False)
8628 self._panes[indx] = paneInfo
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)
8637 def OnPaint(self, event):
8639 Handles the ``wx.EVT_PAINT`` event for L{AuiManager}.
8641 :param `event`: an instance of `wx.PaintEvent` to be processed.
8644 dc = wx.PaintDC(self._frame)
8648 def OnEraseBackground(self, event):
8650 Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{AuiManager}.
8652 :param `event`: `wx.EraseEvent` to be processed.
8654 :note: This is intentionally empty (excluding wxMAC) to reduce
8655 flickering while drawing.
8658 if wx.Platform == "__WXMAC__":
8662 def OnSize(self, event):
8664 Handles the ``wx.EVT_SIZE`` event for L{AuiManager}.
8666 :param `event`: a `wx.SizeEvent` to be processed.
8670 if isinstance(self._frame, AuiFloatingFrame) and self._frame.IsShownOnScreen():
8676 self.DoFrameLayout()
8677 if wx.Platform == "__WXMAC__":
8678 self._frame.Refresh()
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
8693 # For the snap to screen...
8697 def OnFindManager(self, event):
8699 Handles the ``EVT_AUI_FIND_MANAGER`` event for L{AuiManager}.
8701 :param `event`: a L{AuiManagerEvent} event to be processed.
8704 # Initialize to None
8705 event.SetManager(None)
8710 # See it this window wants to overwrite
8711 self._frame.ProcessEvent(event)
8713 # if no, it must be us
8714 if not event.GetManager():
8715 event.SetManager(self)
8718 def OnSetCursor(self, event):
8720 Handles the ``wx.EVT_SET_CURSOR`` event for L{AuiManager}.
8722 :param `event`: a `wx.SetCursorEvent` to be processed.
8726 part = self.HitTest(event.GetX(), event.GetY())
8727 cursor = wx.NullCursor
8730 if part.type in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
8732 if not self.CheckMovableSizer(part):
8735 if part.orientation == wx.VERTICAL:
8736 cursor = wx.StockCursor(wx.CURSOR_SIZEWE)
8738 cursor = wx.StockCursor(wx.CURSOR_SIZENS)
8740 elif part.type == AuiDockUIPart.typeGripper:
8741 cursor = wx.StockCursor(wx.CURSOR_SIZING)
8743 event.SetCursor(cursor)
8746 def UpdateButtonOnScreen(self, button_ui_part, event):
8748 Updates/redraws the UI part containing a pane button.
8750 :param `button_ui_part`: the UI part the button belongs to;
8751 :param `event`: a `wx.MouseEvent` to be processed.
8754 hit_test = self.HitTest(*event.GetPosition())
8756 if not hit_test or not button_ui_part:
8759 state = AUI_BUTTON_STATE_NORMAL
8761 if hit_test == button_ui_part:
8762 if event.LeftDown():
8763 state = AUI_BUTTON_STATE_PRESSED
8765 state = AUI_BUTTON_STATE_HOVER
8767 if event.LeftDown():
8768 state = AUI_BUTTON_STATE_HOVER
8770 # now repaint the button with hover state
8771 cdc = wx.ClientDC(self._frame)
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)
8780 self._art.DrawPaneButton(cdc, self._frame,
8781 button_ui_part.button.button_id,
8783 button_ui_part.rect, hit_test.pane)
8786 def OnLeftDown(self, event):
8788 Handles the ``wx.EVT_LEFT_DOWN`` event for L{AuiManager}.
8790 :param `event`: a `wx.MouseEvent` to be processed.
8793 part = self.HitTest(*event.GetPosition())
8799 self._currentDragItem = -1
8801 if part.type in [AuiDockUIPart.typeDockSizer, AuiDockUIPart.typePaneSizer]:
8803 if not self.CheckMovableSizer(part):
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)
8814 # draw the resize hint
8815 rect = wx.RectPS(self._frame.ClientToScreen(part.rect.GetPosition()),
8816 part.rect.GetSize())
8818 self._action_rect = wx.Rect(*rect)
8820 if not AuiManager_HasLiveResize(self):
8821 if wx.Platform == "__WXMAC__":
8822 dc = wx.ClientDC(self._frame)
8826 DrawResizeHint(dc, rect)
8828 self._frame.CaptureMouse()
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()
8838 self.RefreshButton(part)
8840 elif part.type in [AuiDockUIPart.typeCaption, AuiDockUIPart.typeGripper]:
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)
8850 offset = wx.Point(event.GetX() - part.rect.x, event.GetY() - part.rect.y)
8851 rootManager.OnGripperClicked(part.pane.window, event.GetPosition(), offset)
8853 if wx.Platform != "__WXMAC__":
8857 def OnLeftDClick(self, event):
8859 Handles the ``wx.EVT_LEFT_DCLICK`` event for L{AuiManager}.
8861 :param `event`: a `wx.MouseEvent` to be processed.
8864 part = self.HitTest(event.GetX(), event.GetY())
8866 if part and part.type == AuiDockUIPart.typeCaption:
8867 if isinstance(part.pane.window.GetParent(), AuiFloatingFrame):
8868 rootManager = GetManager(part.pane.window)
8872 rootManager.OnCaptionDoubleClicked(part.pane.window)
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():
8879 win = child.GetSizer().GetContainingWindow()
8880 if isinstance(win, auibook.AuiNotebook):
8881 win.UnsplitDClick(part, sash_size, event.GetPosition())
8887 def DoEndResizeAction(self, event):
8889 Ends a resize action, or for live update, resizes the sash.
8891 :param `event`: a `wx.MouseEvent` to be processed.
8894 clientPt = event.GetPosition()
8895 screenPt = self._frame.ClientToScreen(clientPt)
8897 return self.RestrictResize(clientPt, screenPt, createDC=False)
8900 def RestrictResize(self, clientPt, screenPt, createDC):
8901 """ Common method between L{DoEndResizeAction} and L{OnLeftUp_Resize}. """
8903 dock = self._action_part.dock
8904 pane = self._action_part.pane
8907 if wx.Platform == "__WXMAC__":
8908 dc = wx.ClientDC(self._frame)
8912 DrawResizeHint(dc, self._action_rect)
8913 self._action_rect = wx.Rect()
8915 newPos = clientPt - self._action_offset
8917 if self._action_part.type == AuiDockUIPart.typeDockSizer:
8918 minPix, maxPix = self.CalculateDockSizerLimits(dock)
8920 if not self._action_part.pane:
8922 minPix, maxPix = self.CalculatePaneSizerLimits(dock, pane)
8924 if self._action_part.orientation == wx.HORIZONTAL:
8925 newPos.y = Clip(newPos.y, minPix, maxPix)
8927 newPos.x = Clip(newPos.x, minPix, maxPix)
8929 if self._action_part.type == AuiDockUIPart.typeDockSizer:
8931 partnerDock = self.GetPartnerDock(dock)
8932 sash_size = self._art.GetMetric(AUI_DOCKART_SASH_SIZE)
8934 direction = dock.dock_direction
8936 if direction == AUI_DOCK_LEFT:
8937 new_dock_size = newPos.x - dock.rect.x
8939 elif direction == AUI_DOCK_TOP:
8940 new_dock_size = newPos.y - dock.rect.y
8942 elif direction == AUI_DOCK_RIGHT:
8943 new_dock_size = dock.rect.x + dock.rect.width - newPos.x - sash_size
8945 elif direction == AUI_DOCK_BOTTOM:
8946 new_dock_size = dock.rect.y + dock.rect.height - newPos.y - sash_size
8948 deltaDockSize = new_dock_size - dock.size
8951 if deltaDockSize > partnerDock.size - sash_size:
8952 deltaDockSize = partnerDock.size - sash_size
8954 partnerDock.size -= deltaDockSize
8956 dock.size += deltaDockSize
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
8968 oldPixsize = pane.rect.height
8969 newPixsize = oldPixsize + newPos.y - self._action_part.rect.y
8971 totalPixsize, totalProportion = self.GetTotalPixSizeAndProportion(dock)
8972 partnerPane = self.GetPartnerPane(dock, pane)
8974 # prevent division by zero
8975 if totalPixsize <= 0 or totalProportion <= 0 or not partnerPane:
8978 # adjust for the surplus
8979 while (oldPixsize > 0 and totalPixsize > 10 and \
8980 oldPixsize*totalProportion/totalPixsize < pane.dock_proportion):
8984 # calculate the new proportion of the pane
8986 newProportion = newPixsize*totalProportion/totalPixsize
8987 newProportion = Clip(newProportion, 1, totalProportion)
8988 deltaProp = newProportion - pane.dock_proportion
8990 if partnerPane.dock_proportion - deltaProp < 1:
8991 deltaProp = partnerPane.dock_proportion - 1
8992 newProportion = pane.dock_proportion + deltaProp
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
9004 def OnLeftUp(self, event):
9006 Handles the ``wx.EVT_LEFT_UP`` event for L{AuiManager}.
9008 :param `event`: a `wx.MouseEvent` to be processed.
9011 if self._action == actionResize:
9012 ## self._frame.Freeze()
9013 self.OnLeftUp_Resize(event)
9014 ## self._frame.Thaw()
9016 elif self._action == actionClickButton:
9017 self.OnLeftUp_ClickButton(event)
9019 elif self._action == actionDragFloatingPane:
9020 self.OnLeftUp_DragFloatingPane(event)
9022 elif self._action == actionDragToolbarPane:
9023 self.OnLeftUp_DragToolbarPane(event)
9028 if self._frame.HasCapture():
9029 self._frame.ReleaseMouse()
9031 self._action = actionNone
9034 def OnMotion(self, event):
9036 Handles the ``wx.EVT_MOTION`` event for L{AuiManager}.
9038 :param `event`: a `wx.MouseEvent` to be processed.
9041 if self._action == actionResize:
9042 self.OnMotion_Resize(event)
9044 elif self._action == actionClickCaption:
9045 self.OnMotion_ClickCaption(event)
9047 elif self._action == actionDragFloatingPane:
9048 self.OnMotion_DragFloatingPane(event)
9050 elif self._action == actionDragToolbarPane:
9051 self.OnMotion_DragToolbarPane(event)
9054 self.OnMotion_Other(event)
9057 def OnLeaveWindow(self, event):
9059 Handles the ``wx.EVT_LEAVE_WINDOW`` event for L{AuiManager}.
9061 :param `event`: a `wx.MouseEvent` to be processed.
9064 if self._hover_button:
9065 self.RefreshButton(self._hover_button)
9066 self._hover_button = None
9069 def OnCaptureLost(self, event):
9071 Handles the ``wx.EVT_MOUSE_CAPTURE_LOST`` event for L{AuiManager}.
9073 :param `event`: a `wx.MouseCaptureLostEvent` to be processed.
9076 # cancel the operation in progress, if any
9077 if self._action != actionNone:
9078 self._action = actionNone
9082 def OnHintFadeTimer(self, event):
9084 Handles the ``wx.EVT_TIMER`` event for L{AuiManager}.
9086 :param `event`: a `wx.TimerEvent` to be processed.
9089 if not self._hint_window or self._hint_fadeamt >= self._hint_fademax:
9090 self._hint_fadetimer.Stop()
9093 self._hint_fadeamt += 4
9094 self._hint_window.SetTransparent(self._hint_fadeamt)
9097 def OnMove(self, event):
9099 Handles the ``wx.EVT_MOVE`` event for L{AuiManager}.
9101 :param `event`: a `wx.MoveEvent` to be processed.
9104 if event is not None:
9107 if isinstance(self._frame, AuiFloatingFrame) and self._frame.IsShownOnScreen():
9110 docked, hAlign, vAlign, monitor = self._is_docked
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)
9120 def OnSysColourChanged(self, event):
9122 Handles the ``wx.EVT_SYS_COLOUR_CHANGED`` event for L{AuiManager}.
9124 :param `event`: a `wx.SysColourChangedEvent` to be processed.
9127 # This event is probably triggered by a theme change
9128 # so we have to re-init the art provider.
9134 self._frame.Refresh()
9137 def OnChildFocus(self, event):
9139 Handles the ``wx.EVT_CHILD_FOCUS`` event for L{AuiManager}.
9141 :param `event`: a `wx.ChildFocusEvent` to be processed.
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)
9148 window = event.GetWindow()
9149 if isinstance(window, wx.Dialog):
9150 # Ignore EVT_CHILD_FOCUS events originating from dialogs not
9153 elif isinstance(window.GetParent(), AuiFloatingFrame):
9154 rootManager = GetManager(window)
9159 rootManager.ActivatePane(window)
9164 def OnMotion_ClickCaption(self, event):
9166 Sub-handler for the L{OnMotion} event.
9168 :param `event`: a `wx.MouseEvent` to be processed.
9171 clientPt = event.GetPosition()
9172 screenPt = self._frame.ClientToScreen(clientPt)
9174 drag_x_threshold = wx.SystemSettings.GetMetric(wx.SYS_DRAG_X)
9175 drag_y_threshold = wx.SystemSettings.GetMetric(wx.SYS_DRAG_Y)
9177 if not self._action_pane:
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):
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
9191 elif self._action_pane.IsFloatable() and self._agwFlags & AUI_MGR_ALLOW_FLOATING:
9193 e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, self._action_pane, canVeto=True)
9197 self._action = actionDragFloatingPane
9199 # set initial float position
9200 self._action_pane.floating_pos = screenPt - self._action_offset
9203 if self._action_pane.IsMaximized():
9204 self.RestorePane(self._action_pane)
9206 self._action_pane.Hide()
9207 self._action_pane.Float()
9208 if wx.Platform == "__WXGTK__":
9209 self._action_pane.Show()
9211 e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, self._action_pane, canVeto=False)
9213 if not self._action_pane.frame:
9216 self._action_window = self._action_pane.window
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
9223 if self._agwFlags & AUI_MGR_USE_NATIVE_MINIFRAMES:
9224 originPt = windowPt + wx.Point(3, 3)
9226 self._action_offset += originPt - windowPt
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
9239 self.OnMotion_DragFloatingPane(event)
9240 if wx.Platform != "__WXGTK__":
9241 self._action_pane.Show()
9246 def OnMotion_Resize(self, event):
9248 Sub-handler for the L{OnMotion} event.
9250 :param `event`: a `wx.MouseEvent` to be processed.
9253 if AuiManager_HasLiveResize(self):
9254 if self._currentDragItem != -1:
9255 self._action_part = self._uiparts[self._currentDragItem]
9257 self._currentDragItem = self._uiparts.index(self._action_part)
9259 if self._frame.HasCapture():
9260 self._frame.ReleaseMouse()
9262 self.DoEndResizeAction(event)
9263 self._frame.CaptureMouse()
9266 if not self._action_part or not self._action_part.dock or not self._action_part.orientation:
9269 clientPt = event.GetPosition()
9270 screenPt = self._frame.ClientToScreen(clientPt)
9272 dock = self._action_part.dock
9273 pos = self._action_part.rect.GetPosition()
9275 if self._action_part.type == AuiDockUIPart.typeDockSizer:
9276 minPix, maxPix = self.CalculateDockSizerLimits(dock)
9278 if not self._action_part.pane:
9281 pane = self._action_part.pane
9282 minPix, maxPix = self.CalculatePaneSizerLimits(dock, pane)
9284 if self._action_part.orientation == wx.HORIZONTAL:
9285 pos.y = Clip(clientPt.y - self._action_offset.y, minPix, maxPix)
9287 pos.x = Clip(clientPt.x - self._action_offset.x, minPix, maxPix)
9289 hintrect = wx.RectPS(self._frame.ClientToScreen(pos), self._action_part.rect.GetSize())
9291 if hintrect != self._action_rect:
9293 if wx.Platform == "__WXMAC__":
9294 dc = wx.ClientDC(self._frame)
9298 DrawResizeHint(dc, self._action_rect)
9299 DrawResizeHint(dc, hintrect)
9300 self._action_rect = wx.Rect(*hintrect)
9303 def OnLeftUp_Resize(self, event):
9305 Sub-handler for the L{OnLeftUp} event.
9307 :param `event`: a `wx.MouseEvent` to be processed.
9310 if self._currentDragItem != -1 and AuiManager_HasLiveResize(self):
9311 self._action_part = self._uiparts[self._currentDragItem]
9313 if self._frame.HasCapture():
9314 self._frame.ReleaseMouse()
9316 self.DoEndResizeAction(event)
9317 self._currentDragItem = -1
9320 if not self._action_part or not self._action_part.dock:
9323 clientPt = event.GetPosition()
9324 screenPt = self._frame.ClientToScreen(clientPt)
9326 return self.RestrictResize(clientPt, screenPt, createDC=True)
9329 def OnLeftUp_ClickButton(self, event):
9331 Sub-handler for the L{OnLeftUp} event.
9333 :param `event`: a `wx.MouseEvent` to be processed.
9336 self._hover_button = None
9338 if self._action_part:
9339 self.RefreshButton(self._action_part)
9341 # make sure we're still over the item that was originally clicked
9342 if self._action_part == self.HitTest(*event.GetPosition()):
9344 # fire button-click event
9345 e = AuiManagerEvent(wxEVT_AUI_PANE_BUTTON)
9347 e.SetPane(self._action_part.pane)
9348 e.SetButton(self._action_part.button.button_id)
9349 self.ProcessMgrEvent(e)
9352 def CheckPaneMove(self, pane):
9354 Checks if a pane has moved by a visible amount.
9356 :param `pane`: an instance of L{AuiPaneInfo}.
9359 win_rect = pane.frame.GetRect()
9360 win_rect.x, win_rect.y = pane.floating_pos
9362 if win_rect == self._last_rect:
9365 # skip the first move event
9366 if self._last_rect.IsEmpty():
9367 self._last_rect = wx.Rect(*win_rect)
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)
9380 def OnMotion_DragFloatingPane(self, eventOrPt):
9382 Sub-handler for the L{OnMotion} event.
9384 :param `event`: a `wx.MouseEvent` to be processed.
9388 if isinstance(eventOrPt, wx.Point):
9389 clientPt = self._frame.ScreenToClient(eventOrPt)
9390 screenPt = wx.Point(*eventOrPt)
9393 clientPt = eventOrPt.GetPosition()
9394 screenPt = self._frame.ClientToScreen(clientPt)
9396 framePos = wx.Point()
9398 # try to find the pane
9399 pane = self.GetPane(self._action_window)
9401 raise Exception("Pane window not found")
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
9408 framePos = pane.floating_pos
9410 # Move the pane window
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):
9416 # HACK: Terrible hack on wxMSW (!)
9417 pane.frame.SetTransparent(254)
9419 self._from_move = True
9420 pane.frame.Move(pane.floating_pos)
9421 self._from_move = False
9423 if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
9424 pane.frame.SetTransparent(150)
9426 # calculate the offset from the upper left-hand corner
9427 # of the frame to the mouse pointer
9428 action_offset = screenPt - framePos
9430 # is the pane dockable?
9431 if not self.CanDockPanel(pane):
9433 ShowDockingGuides(self._guides, False)
9436 for paneInfo in self._panes:
9438 if not paneInfo.IsDocked() or not paneInfo.IsShown():
9440 if paneInfo.IsToolbar() or paneInfo.IsNotebookControl():
9442 if paneInfo.IsMaximized():
9445 if paneInfo.IsNotebookPage():
9447 notebookRoot = GetNotebookRoot(self._panes, paneInfo.notebook_id)
9449 if not notebookRoot or not notebookRoot.IsDocked():
9452 rc = paneInfo.window.GetScreenRect()
9453 if rc.Contains(screenPt):
9454 if rc.height < 20 or rc.width < 20:
9457 self.UpdateDockingGuides(paneInfo)
9458 ShowDockingGuides(self._guides, True)
9461 self.DrawHintRect(pane.window, clientPt, action_offset)
9464 def OnLeftUp_DragFloatingPane(self, eventOrPt):
9466 Sub-handler for the L{OnLeftUp} event.
9468 :param `event`: a `wx.MouseEvent` to be processed.
9471 if isinstance(eventOrPt, wx.Point):
9472 clientPt = self._frame.ScreenToClient(eventOrPt)
9473 screenPt = wx.Point(*eventOrPt)
9475 clientPt = eventOrPt.GetPosition()
9476 screenPt = self._frame.ClientToScreen(clientPt)
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")
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
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)
9499 e = self.FireEvent(wxEVT_AUI_PANE_DOCKING, paneInfo, canVeto=True)
9502 ShowDockingGuides(self._guides, False)
9505 e = self.FireEvent(wxEVT_AUI_PANE_DOCKED, paneInfo, canVeto=False)
9507 if self._agwFlags & AUI_MGR_SMOOTH_DOCKING:
9508 self.SmoothDock(paneInfo)
9510 self._panes[indx] = paneInfo
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
9520 elif self._has_maximized:
9521 self.RestoreMaximizedPane()
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)
9533 ShowDockingGuides(self._guides, False)
9536 def OnMotion_DragToolbarPane(self, eventOrPt):
9538 Sub-handler for the L{OnMotion} event.
9540 :param `event`: a `wx.MouseEvent` to be processed.
9544 if isinstance(eventOrPt, wx.Point):
9545 clientPt = self._frame.ScreenToClient(eventOrPt)
9546 screenPt = wx.Point(*eventOrPt)
9549 clientPt = eventOrPt.GetPosition()
9550 screenPt = self._frame.ClientToScreen(clientPt)
9552 pane = self.GetPane(self._action_window)
9554 raise Exception("Pane window not found")
9556 pane.state |= AuiPaneInfo.actionPane
9557 indx = self._panes.index(pane)
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)
9566 # update floating position
9567 if pane.IsFloating():
9568 pane.floating_pos = screenPt - self._toolbar_action_offset
9570 # move the pane window
9572 if wx.Platform == "__WXMSW__" and (self._agwFlags & AUI_MGR_TRANSPARENT_DRAG) == 0: # and not self.CheckPaneMove(pane):
9574 # HACK: Terrible hack on wxMSW (!)
9575 pane.frame.SetTransparent(254)
9577 self._from_move = True
9578 pane.frame.Move(pane.floating_pos)
9579 self._from_move = False
9581 if self._agwFlags & AUI_MGR_TRANSPARENT_DRAG:
9582 pane.frame.SetTransparent(150)
9584 self._panes[indx] = pane
9585 if ret and wasFloating != pane.IsFloating() or (ret and not wasFloating):
9586 wx.CallAfter(self.Update)
9588 # when release the button out of the window.
9589 # TODO: a better fix is needed.
9591 if _VERSION_STRING < "2.9":
9592 leftDown = wx.GetMouseState().LeftDown()
9594 leftDown = wx.GetMouseState().LeftIsDown()
9597 self._action = actionNone
9598 self.OnLeftUp_DragToolbarPane(eventOrPt)
9601 def OnMotion_Other(self, event):
9603 Sub-handler for the L{OnMotion} event.
9605 :param `event`: a `wx.MouseEvent` to be processed.
9608 part = self.HitTest(*event.GetPosition())
9610 if part and part.type == AuiDockUIPart.typePaneButton \
9611 and self.IsPaneButtonVisible(part):
9612 if part != self._hover_button:
9614 if self._hover_button:
9615 self.RefreshButton(self._hover_button)
9617 self._hover_button = part
9618 self.RefreshButton(part)
9622 if self._hover_button:
9623 self.RefreshButton(self._hover_button)
9627 self._hover_button = None
9630 def OnLeftUp_DragToolbarPane(self, eventOrPt):
9632 Sub-handler for the L{OnLeftUp} event.
9634 :param `event`: a `wx.MouseEvent` to be processed.
9638 if isinstance(eventOrPt, wx.Point):
9639 clientPt = self._frame.ScreenToClient(eventOrPt)
9640 screenPt = wx.Point(*eventOrPt)
9643 clientPt = eventOrPt.GetPosition()
9644 screenPt = self._frame.ClientToScreen(clientPt)
9646 # try to find the pane
9647 pane = self.GetPane(self._action_window)
9649 raise Exception("Pane window not found")
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
9657 # save the new positions
9658 docks = FindDocks(self._docks, pane.dock_direction, pane.dock_layer, pane.dock_row)
9661 pane_positions, pane_sizes = self.GetPanePositionsAndSizes(dock)
9663 for i in xrange(len(dock.panes)):
9664 dock.panes[i].dock_pos = pane_positions[i]
9666 pane.state &= ~AuiPaneInfo.actionPane
9670 def OnPaneButton(self, event):
9672 Handles the ``EVT_AUI_PANE_BUTTON`` event for L{AuiManager}.
9674 :param `event`: a L{AuiManagerEvent} event to be processed.
9678 raise Exception("Pane Info passed to AuiManager.OnPaneButton must be non-null")
9682 if event.button == AUI_BUTTON_CLOSE:
9684 if isinstance(pane.window.GetParent(), AuiFloatingFrame):
9685 rootManager = GetManager(pane.window)
9689 if rootManager != self:
9693 # fire pane close event
9694 e = AuiManagerEvent(wxEVT_AUI_PANE_CLOSE)
9696 e.SetPane(event.pane)
9697 self.ProcessMgrEvent(e)
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)
9705 check = self.GetPane(pane.window)
9707 self.ClosePane(pane)
9711 # mn this performs the minimizing of a pane
9712 elif event.button == AUI_BUTTON_MINIMIZE:
9713 e = AuiManagerEvent(wxEVT_AUI_PANE_MINIMIZE)
9715 e.SetPane(event.pane)
9716 self.ProcessMgrEvent(e)
9719 self.MinimizePane(pane)
9721 elif event.button == AUI_BUTTON_MAXIMIZE_RESTORE and not pane.IsMaximized():
9723 # fire pane close event
9724 e = AuiManagerEvent(wxEVT_AUI_PANE_MAXIMIZE)
9726 e.SetPane(event.pane)
9727 self.ProcessMgrEvent(e)
9731 self.MaximizePane(pane)
9734 elif event.button == AUI_BUTTON_MAXIMIZE_RESTORE and pane.IsMaximized():
9736 # fire pane close event
9737 e = AuiManagerEvent(wxEVT_AUI_PANE_RESTORE)
9739 e.SetPane(event.pane)
9740 self.ProcessMgrEvent(e)
9744 self.RestorePane(pane)
9747 elif event.button == AUI_BUTTON_PIN:
9749 if self._agwFlags & AUI_MGR_ALLOW_FLOATING and pane.IsFloatable():
9750 e = self.FireEvent(wxEVT_AUI_PANE_FLOATING, pane, canVeto=True)
9755 e = self.FireEvent(wxEVT_AUI_PANE_FLOATED, pane, canVeto=False)
9760 def MinimizePane(self, paneInfo):
9762 Minimizes a pane in a newly and automatically created L{AuiToolBar}.
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.
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.
9772 :param `paneInfo`: a L{AuiPaneInfo} instance for the pane to be minimized.
9775 if not paneInfo.IsToolbar():
9777 if paneInfo.IsMinimized():
9778 # We are already minimized
9781 # Basically the idea is this.
9783 # 1) create a toolbar, with a restore button
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)
9788 # 3) Hide the minimizing pane
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
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
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
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
9812 dockDirection = AUI_DOCK_BOTTOM
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
9825 # Create a new toolbar
9826 # give it the same name as the minimized pane with _min appended
9828 win_rect = paneInfo.window.GetScreenRect()
9830 minimize_toolbar = auibar.AuiToolBar(self.GetManagedWindow(), agwStyle=tbStyle)
9831 minimize_toolbar.Hide()
9832 minimize_toolbar.SetToolBitmapSize(wx.Size(16, 16))
9834 if paneInfo.icon and paneInfo.icon.IsOk():
9835 restore_bitmap = paneInfo.icon
9837 restore_bitmap = self._art._restore_bitmap
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"
9844 if paneInfo.IsMaximized():
9845 paneInfo.SetFlag(paneInfo.wasMaximized, True)
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())
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())
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())
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())
9871 arr = FindDocks(self._docks, paneInfo.dock_direction, paneInfo.dock_layer, paneInfo.dock_row)
9875 paneInfo.previousDockSize = dock.size
9877 paneInfo.previousDockPos = paneInfo.dock_pos
9879 # mark ourselves minimized
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)
9887 minimize_toolbar.Show()
9889 if self._agwFlags & AUI_MGR_ANIMATE_FRAMES:
9890 self.AnimateDocking(win_rect, minimize_toolbar.GetScreenRect())
9893 def OnRestoreMinimizedPane(self, event):
9895 Handles the ``EVT_AUI_PANE_MIN_RESTORE`` event for L{AuiManager}.
9897 :param `event`: an instance of L{AuiManagerEvent} to be processed.
9900 self.RestoreMinimizedPane(event.pane)
9903 def OnPaneDocked(self, event):
9905 Handles the ``EVT_AUI_PANE_DOCKED`` event for L{AuiManager}.
9907 :param `event`: an instance of L{AuiManagerEvent} to be processed.
9911 self.RemoveAutoNBCaption(event.GetPane())
9914 def CreateNotebookBase(self, panes, paneInfo):
9916 Creates an auto-notebook base from a pane, and then add that pane as a page.
9918 :param `panes`: Set of panes to append new notebook base pane to
9919 :param `paneInfo`: L{AuiPaneInfo} instance to convert to new notebook.
9922 # Create base notebook pane ...
9923 nbid = len(self._notebooks)
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)
9932 # add original pane as tab ...
9933 paneInfo.NotebookPage(nbid)
9935 def RemoveAutoNBCaption(self, pane):
9937 Removes the caption on newly created automatic notebooks.
9939 :param `pane`: an instance of L{AuiPaneInfo} (the target notebook).
9942 if self._agwFlags & AUI_MGR_AUTONB_NO_CAPTION == 0:
9945 def RemoveCaption():
9946 """ Sub-function used to remove the pane caption on automatic notebooks. """
9948 if pane.HasNotebook():
9949 notebook = self._notebooks[pane.notebook_id]
9950 self.GetPane(notebook).CaptionVisible(False).PaneBorder(False)
9953 # it seems the notebook isnt created by this stage, so remove
9954 # the caption a moment later
9955 wx.CallAfter(RemoveCaption)
9959 def RestoreMinimizedPane(self, paneInfo):
9961 Restores a previously minimized pane.
9963 :param `paneInfo`: a L{AuiPaneInfo} instance for the pane to be restored.
9966 panename = paneInfo.name
9967 panename = panename[0:-4]
9968 pane = self.GetPane(panename)
9970 pane.SetFlag(pane.needsRestore, True)
9973 panename = paneInfo.name
9974 pane = self.GetPane(panename)
9975 paneInfo = self.GetPane(panename + "_min")
9976 if not paneInfo.IsOk():
9981 if not pane.IsMinimized():
9985 if pane.HasFlag(pane.wasMaximized):
9987 self.SavePreviousDockSizes(pane)
9990 self.ShowPane(pane.window, 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)
10002 def AnimateDocking(self, win_rect, pane_rect):
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.
10007 :param `win_rect`: the original pane screen rectangle;
10008 :param `pane_rect`: the newly created toolbar/pane screen rectangle.
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.
10014 if wx.Platform == "__WXMAC__":
10015 # No wx.ScreenDC on the Mac...
10017 if wx.Platform == "__WXMSW__" and wx.GetOsVersion()[1] > 5:
10018 # No easy way to handle this on Vista...
10021 xstart, ystart = win_rect.x, win_rect.y
10022 xend, yend = pane_rect.x, pane_rect.y
10024 step = self.GetAnimationStep()
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
10032 dc.SetLogicalFunction(wx.INVERT)
10033 dc.SetBrush(wx.TRANSPARENT_BRUSH)
10034 dc.SetPen(wx.LIGHT_GREY_PEN)
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)
10043 dc.DrawRoundedRectangleRect(new_rect, 3)
10046 def SmoothDock(self, paneInfo):
10048 This method implements a smooth docking effect for floating panes, similar to
10049 what the PyQT library does with its floating windows.
10051 :param `paneInfo`: an instance of L{AuiPaneInfo}.
10053 :note: The smooth docking effect can only be used if you set the ``AUI_MGR_SMOOTH_DOCKING``
10054 style to L{AuiManager}.
10057 if paneInfo.IsToolbar():
10060 if not paneInfo.frame or self._hint_rect.IsEmpty():
10063 hint_rect = self._hint_rect
10064 win_rect = paneInfo.frame.GetScreenRect()
10066 xstart, ystart = win_rect.x, win_rect.y
10067 xend, yend = hint_rect.x, hint_rect.y
10069 step = self.GetAnimationStep()/3
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
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)
10084 def SetSnapLimits(self, x, y):
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}).
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.
10094 :param `x`: the minimum horizontal distance below which the snap occurs;
10095 :param `y`: the minimum vertical distance below which the snap occurs.
10098 self._snap_limits = (x, y)
10104 Snaps the main frame to specified position on the screen.
10106 :see: L{SnapToScreen}
10109 snap, hAlign, vAlign, monitor = self._is_docked
10113 managed_window = self.GetManagedWindow()
10114 snap_pos = self.GetSnapPosition()
10115 wnd_pos = managed_window.GetPosition()
10116 snapX, snapY = self._snap_limits
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)
10122 def SnapToScreen(self, snap=True, monitor=0, hAlign=wx.RIGHT, vAlign=wx.TOP):
10124 Snaps the main frame to specified position on the screen.
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.
10133 self._is_docked = (False, wx.RIGHT, wx.TOP, 0)
10136 displayCount = wx.Display.GetCount()
10137 if monitor > displayCount:
10138 raise Exception("Invalid monitor selected: you only have %d monitors"%displayCount)
10140 self._is_docked = (True, hAlign, vAlign, monitor)
10141 self.GetManagedWindow().SetPosition(self.GetSnapPosition())
10144 def GetSnapPosition(self):
10145 """ Returns the main frame snapping position. """
10147 snap, hAlign, vAlign, monitor = self._is_docked
10149 display = wx.Display(monitor)
10150 area = display.GetClientArea()
10151 size = self.GetManagedWindow().GetSize()
10154 if hAlign == wx.LEFT:
10156 elif hAlign == wx.CENTER:
10157 pos.x = area.x + (area.width - size.x)/2
10159 pos.x = area.x + area.width - size.x
10161 if vAlign == wx.TOP:
10163 elif vAlign == wx.CENTER:
10164 pos.y = area.y + (area.height - size.y)/2
10166 pos.y = area.y + area.height - size.y
10171 def GetAnimationStep(self):
10172 """ Returns the animation step speed (a float) to use in L{AnimateDocking}. """
10174 return self._animation_step
10177 def SetAnimationStep(self, step):
10179 Sets the animation step speed (a float) to use in L{AnimateDocking}.
10181 :param `step`: a floating point value for the animation speed.
10184 self._animation_step = float(step)
10187 def RequestUserAttention(self, pane_window):
10189 Requests the user attention by intermittently highlighting the pane caption.
10191 :param `pane_window`: a `wx.Window` derived window, managed by the pane.
10194 # try to find the pane
10195 paneInfo = self.GetPane(pane_window)
10196 if not paneInfo.IsOk():
10197 raise Exception("Pane window not found")
10199 dc = wx.ClientDC(self._frame)
10201 # if the frame is about to be deleted, don't bother
10202 if not self._frame or self._frame.IsBeingDeleted():
10205 if not self._frame.GetSizer():
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)
10215 def StartPreviewTimer(self, toolbar):
10217 Starts a timer for sliding in and out a minimized pane.
10219 :param `toolbar`: the L{AuiToolBar} containing the minimized pane tool.
10222 toolbar_pane = self.GetPane(toolbar)
10223 toolbar_name = toolbar_pane.name
10225 pane_name = toolbar_name[0:-4]
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
10232 self._preview_timer.Start(1000, wx.TIMER_ONE_SHOT)
10235 def StopPreviewTimer(self):
10236 """ Stops a timer for sliding in and out a minimized pane. """
10238 if self._preview_timer.IsRunning():
10239 self._preview_timer.Stop()
10242 self._sliding_pane = None
10245 def SlideIn(self, event):
10247 Handles the ``wx.EVT_TIMER`` event for L{AuiManager}.
10249 :param `event`: a `wx.TimerEvent` to be processed.
10251 :note: This is used solely for sliding in and out minimized panes.
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))
10261 self._sliding_frame.Show()
10263 size = window.GetBestSize()
10265 startX, startY, stopX, stopY = GetSlidingPoints(self._sliding_rect, size, self._sliding_direction)
10270 for i in xrange(0, stopX, step):
10272 self._sliding_frame.SetDimensions(startX, startY, window_size, stopY)
10273 self._sliding_frame.Refresh()
10274 self._sliding_frame.Update()
10277 self._sliding_frame.SetDimensions(startX, startY, stopX, stopY)
10278 self._sliding_frame.Refresh()
10279 self._sliding_frame.Update()
10282 def SlideOut(self):
10284 Slides out a preview of a minimized pane.
10286 :note: This is used solely for sliding in and out minimized panes.
10289 if not self._sliding_frame:
10292 window = self._sliding_frame.GetChildren()[0]
10293 size = window.GetBestSize()
10295 startX, startY, stopX, stopY = GetSlidingPoints(self._sliding_rect, size, self._sliding_direction)
10300 for i in xrange(stopX, 0, -step):
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()
10309 self._sliding_frame.SetDimensions(startX, startY, 0, stopY)
10312 window.Reparent(self._frame)
10314 self._sliding_frame.Hide()
10315 self._sliding_frame.Destroy()
10316 self._sliding_frame = None
10317 self._sliding_pane = None
10320 class AuiManager_DCP(AuiManager):
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.
10327 def __init__(self, *args, **keys):
10329 AuiManager.__init__(self, *args, **keys)
10330 self.hasDummyPane = False
10333 def _createDummyPane(self):
10334 """ Creates a Dummy Center Pane (**DCP**). """
10336 if self.hasDummyPane:
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)
10345 def _destroyDummyPane(self):
10346 """ Destroys the Dummy Center Pane (**DCP**). """
10348 if not self.hasDummyPane:
10351 self.hasDummyPane = False
10352 self.ClosePane(self.GetPane('dummyCenterPane'))
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.
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.
10367 AuiManager.Update(self)
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())
10374 if self.hasDummyPane:
10375 # there's our dummy pane and also another center pane, therefor let's remove our dummy
10377 self._destroyDummyPane()
10381 # if we get here, there's no center pane, create our dummy
10382 if not self.hasDummyPane:
10383 self._createDummyPane()