...
[iramuteq] / aui / auibar.py
1 """
2 auibar contains an implementation of L{AuiToolBar}, which is a completely owner-drawn
3 toolbar perfectly integrated with the AUI layout system. This allows drag and drop of
4 toolbars, docking/floating behaviour and the possibility to define "overflow" items
5 in the toolbar itself.
6
7 The default theme that is used is L{AuiDefaultToolBarArt}, which provides a modern,
8 glossy look and feel. The theme can be changed by calling L{AuiToolBar.SetArtProvider}.
9 """
10
11 __author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
12 __date__ = "31 March 2009"
13
14
15 import wx
16 import types
17
18 from aui_utilities import BitmapFromBits, StepColour, GetLabelSize
19 from aui_utilities import GetBaseColour, MakeDisabledBitmap
20
21 import framemanager
22 from aui_constants import *
23
24 # wxPython version string
25 _VERSION_STRING = wx.VERSION_STRING
26
27 # AuiToolBar events
28 wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN = wx.NewEventType()
29 wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK = wx.NewEventType()
30 wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK = wx.NewEventType()
31 wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK = wx.NewEventType()
32 wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG = wx.NewEventType()
33
34 EVT_AUITOOLBAR_TOOL_DROPDOWN = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, 1)
35 """ A dropdown `AuiToolBarItem` is being shown. """
36 EVT_AUITOOLBAR_OVERFLOW_CLICK = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK, 1)
37 """ The user left-clicked on the overflow button in `AuiToolBar`. """
38 EVT_AUITOOLBAR_RIGHT_CLICK = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK, 1)
39 """ Fires an event when the user right-clicks on a `AuiToolBarItem`. """
40 EVT_AUITOOLBAR_MIDDLE_CLICK = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK, 1)
41 """ Fires an event when the user middle-clicks on a `AuiToolBarItem`. """
42 EVT_AUITOOLBAR_BEGIN_DRAG = wx.PyEventBinder(wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG, 1)
43 """ A drag operation involving a toolbar item has started. """
44
45 # ----------------------------------------------------------------------
46
47 class CommandToolBarEvent(wx.PyCommandEvent):
48     """ A specialized command event class for events sent by L{AuiToolBar}. """
49     
50     def __init__(self, command_type, win_id):
51         """
52         Default class constructor.
53
54         :param `command_type`: the event kind or an instance of `wx.PyCommandEvent`.
55         :param `win_id`: the window identification number.
56         """
57         
58         if type(command_type) == types.IntType:    
59             wx.PyCommandEvent.__init__(self, command_type, win_id)
60         else:
61             wx.PyCommandEvent.__init__(self, command_type.GetEventType(), command_type.GetId())
62             
63         self.is_dropdown_clicked = False
64         self.click_pt = wx.Point(-1, -1)
65         self.rect = wx.Rect(-1, -1, 0, 0)
66         self.tool_id = -1
67
68
69     def IsDropDownClicked(self):
70         """ Returns whether the drop down menu has been clicked. """
71
72         return self.is_dropdown_clicked
73     
74
75     def SetDropDownClicked(self, c):
76         """
77         Sets whether the drop down menu has been clicked.
78
79         :param `c`: ``True`` to set the drop down as clicked, ``False`` otherwise.
80         """
81
82         self.is_dropdown_clicked = c    
83
84
85     def GetClickPoint(self):
86         """ Returns the point where the user clicked with the mouse. """
87
88         return self.click_pt
89
90     
91     def SetClickPoint(self, p):
92         """
93         Sets the clicking point.
94
95         :param `p`: a `wx.Point` object.
96         """
97         
98         self.click_pt = p    
99
100
101     def GetItemRect(self):
102         """ Returns the L{AuiToolBarItem} rectangle. """
103
104         return self.rect
105
106     
107     def SetItemRect(self, r):
108         """
109         Sets the L{AuiToolBarItem} rectangle.
110
111         :param `r`: an instance of `wx.Rect`.
112         """
113
114         self.rect = r    
115
116
117     def GetToolId(self):
118         """ Returns the L{AuiToolBarItem} identifier. """
119
120         return self.tool_id
121
122     
123     def SetToolId(self, id):
124         """
125         Sets the L{AuiToolBarItem} identifier.
126
127         :param `id`: the toolbar item identifier.
128         """
129
130         self.tool_id = id   
131
132
133 # ----------------------------------------------------------------------
134
135 class AuiToolBarEvent(CommandToolBarEvent):
136     """ A specialized command event class for events sent by L{AuiToolBar}. """
137     
138     def __init__(self, command_type=None, win_id=0):
139         """
140         Default class constructor.
141
142         :param `command_type`: the event kind or an instance of `wx.PyCommandEvent`.
143         :param `win_id`: the window identification number.
144         """
145
146         CommandToolBarEvent.__init__(self, command_type, win_id)
147
148         if type(command_type) == types.IntType:
149             self.notify = wx.NotifyEvent(command_type, win_id)
150         else:
151             self.notify = wx.NotifyEvent(command_type.GetEventType(), command_type.GetId())
152
153         
154     def GetNotifyEvent(self):
155         """ Returns the actual `wx.NotifyEvent`. """
156         
157         return self.notify
158
159
160     def IsAllowed(self):
161         """ Returns whether the event is allowed or not. """
162
163         return self.notify.IsAllowed()
164
165
166     def Veto(self):
167         """
168         Prevents the change announced by this event from happening.
169
170         It is in general a good idea to notify the user about the reasons for
171         vetoing the change because otherwise the applications behaviour (which
172         just refuses to do what the user wants) might be quite surprising.
173         """
174
175         self.notify.Veto()
176
177
178     def Allow(self):
179         """
180         This is the opposite of L{Veto}: it explicitly allows the event to be
181         processed. For most events it is not necessary to call this method as the
182         events are allowed anyhow but some are forbidden by default (this will
183         be mentioned in the corresponding event description).
184         """
185
186         self.notify.Allow()
187
188
189 # ----------------------------------------------------------------------
190
191 class ToolbarCommandCapture(wx.PyEvtHandler):
192     """ A class to handle the dropdown window menu. """
193     
194     def __init__(self):
195         """ Default class constructor. """
196         
197         wx.PyEvtHandler.__init__(self)
198         self._last_id = 0
199
200
201     def GetCommandId(self):
202         """ Returns the event command identifier. """
203         
204         return self._last_id 
205
206
207     def ProcessEvent(self, event):
208         """
209         Processes an event, searching event tables and calling zero or more suitable
210         event handler function(s).
211
212         :param `event`: the event to process.
213
214         :note: Normally, your application would not call this function: it is called
215          in the wxPython implementation to dispatch incoming user interface events
216          to the framework (and application).
217          However, you might need to call it if implementing new functionality (such as
218          a new control) where you define new event types, as opposed to allowing the
219          user to override functions.
220
221          An instance where you might actually override the L{ProcessEvent} function is where
222          you want to direct event processing to event handlers not normally noticed by
223          wxPython. For example, in the document/view architecture, documents and views
224          are potential event handlers. When an event reaches a frame, L{ProcessEvent} will
225          need to be called on the associated document and view in case event handler
226          functions are associated with these objects. 
227
228          The normal order of event table searching is as follows:
229
230          1. If the object is disabled (via a call to `SetEvtHandlerEnabled`) the function
231             skips to step (6).
232          2. If the object is a `wx.Window`, L{ProcessEvent} is recursively called on the window's 
233             `wx.Validator`. If this returns ``True``, the function exits.
234          3. wxWidgets `SearchEventTable` is called for this event handler. If this fails, the
235             base class table is tried, and so on until no more tables exist or an appropriate
236             function was found, in which case the function exits.
237          4. The search is applied down the entire chain of event handlers (usually the chain
238             has a length of one). If this succeeds, the function exits.
239          5. If the object is a `wx.Window` and the event is a `wx.CommandEvent`, L{ProcessEvent} is
240             recursively applied to the parent window's event handler. If this returns ``True``,
241             the function exits.
242          6. Finally, L{ProcessEvent} is called on the `wx.App` object.
243         """
244         
245         if event.GetEventType() == wx.wxEVT_COMMAND_MENU_SELECTED:
246             self._last_id = event.GetId()
247             return True
248         
249         if self.GetNextHandler():
250             return self.GetNextHandler().ProcessEvent(event)
251
252         return False
253
254
255 # ----------------------------------------------------------------------
256
257 class AuiToolBarItem(object):
258     """
259     AuiToolBarItem is a toolbar element.
260     
261     It has a unique id (except for the separators which always have id = -1), the
262     style (telling whether it is a normal button, separator or a control), the
263     state (toggled or not, enabled or not) and short and long help strings. The
264     default implementations use the short help string for the tooltip text which
265     is popped up when the mouse pointer enters the tool and the long help string
266     for the applications status bar.
267     """
268
269     def __init__(self, item=None):
270         """
271         Default class constructor.
272
273         :param `item`: another instance of L{AuiToolBarItem}.
274         """
275
276         if item:
277             self.Assign(item)
278             return
279         
280         self.window = None
281         self.clockwisebmp = wx.NullBitmap
282         self.counterclockwisebmp = wx.NullBitmap
283         self.clockwisedisbmp = wx.NullBitmap
284         self.counterclockwisedisbmp = wx.NullBitmap
285         self.sizer_item = None
286         self.spacer_pixels = 0
287         self.id = 0
288         self.kind = ITEM_NORMAL
289         self.state = 0   # normal, enabled
290         self.proportion = 0
291         self.active = True
292         self.dropdown = True
293         self.sticky = True
294         self.user_data = 0
295
296         self.label = ""
297         self.bitmap = wx.NullBitmap
298         self.disabled_bitmap = wx.NullBitmap
299         self.hover_bitmap = wx.NullBitmap
300         self.short_help = ""
301         self.long_help = ""
302         self.min_size = wx.Size(-1, -1)
303         self.alignment = wx.ALIGN_CENTER
304         self.orientation = AUI_TBTOOL_HORIZONTAL
305         
306
307     def Assign(self, c):
308         """
309         Assigns the properties of the L{AuiToolBarItem} `c` to `self`.
310
311         :param `c`: another instance of L{AuiToolBarItem}.
312         """
313
314         self.window = c.window
315         self.label = c.label
316         self.bitmap = c.bitmap
317         self.disabled_bitmap = c.disabled_bitmap
318         self.hover_bitmap = c.hover_bitmap
319         self.short_help = c.short_help
320         self.long_help = c.long_help
321         self.sizer_item = c.sizer_item
322         self.min_size = c.min_size
323         self.spacer_pixels = c.spacer_pixels
324         self.id = c.id
325         self.kind = c.kind
326         self.state = c.state
327         self.proportion = c.proportion
328         self.active = c.active
329         self.dropdown = c.dropdown
330         self.sticky = c.sticky
331         self.user_data = c.user_data
332         self.alignment = c.alignment
333         self.orientation = c.orientation
334
335
336     def SetWindow(self, w):
337         """
338         Assigns a window to the toolbar item.
339
340         :param `w`: an instance of `wx.Window`.
341         """
342
343         self.window = w
344
345         
346     def GetWindow(self):
347         """ Returns window associated to the toolbar item. """
348
349         return self.window        
350
351
352     def SetId(self, new_id):
353         """
354         Sets the toolbar item identifier.
355
356         :param `new_id`: the new tool id.
357         """
358
359         self.id = new_id
360
361         
362     def GetId(self):
363         """ Returns the toolbar item identifier. """
364
365         return self.id 
366
367
368     def SetKind(self, new_kind):
369         """
370         Sets the L{AuiToolBarItem} kind.
371
372         :param `new_kind`: can be one of the following items:
373
374          ========================  =============================
375          Item Kind                 Description
376          ========================  =============================
377          ``ITEM_CONTROL``          The item in the `AuiToolBar` is a control
378          ``ITEM_LABEL``            The item in the `AuiToolBar` is a text label
379          ``ITEM_SPACER``           The item in the `AuiToolBar` is a spacer
380          ``ITEM_SEPARATOR``        The item in the `AuiToolBar` is a separator
381          ``ITEM_CHECK``            The item in the `AuiToolBar` is a toolbar check item
382          ``ITEM_NORMAL``           The item in the `AuiToolBar` is a standard toolbar item
383          ``ITEM_RADIO``            The item in the `AuiToolBar` is a toolbar radio item
384          ========================  =============================
385         """
386
387         self.kind = new_kind
388
389
390     def GetKind(self):
391         """ Returns the toolbar item kind. See L{SetKind} for more details. """
392
393         return self.kind
394         
395
396     def SetState(self, new_state):
397         """
398         Sets the toolbar item state.
399
400         :param `new_state`: can be one of the following states:
401
402          ============================================  ======================================
403          Button State Constant                         Description     
404          ============================================  ======================================
405          ``AUI_BUTTON_STATE_NORMAL``                   Normal button state
406          ``AUI_BUTTON_STATE_HOVER``                    Hovered button state
407          ``AUI_BUTTON_STATE_PRESSED``                  Pressed button state
408          ``AUI_BUTTON_STATE_DISABLED``                 Disabled button state
409          ``AUI_BUTTON_STATE_HIDDEN``                   Hidden button state
410          ``AUI_BUTTON_STATE_CHECKED``                  Checked button state
411          ============================================  ======================================
412     
413         """
414
415         self.state = new_state
416
417         
418     def GetState(self):
419         """
420         Returns the toolbar item state. See L{SetState} for more details.
421
422         :see: L{SetState}
423         """
424         
425         return self.state 
426
427
428     def SetSizerItem(self, s):
429         """
430         Associates a sizer item to this toolbar item.
431
432         :param `s`: an instance of `wx.SizerItem`.
433         """
434
435         self.sizer_item = s
436
437         
438     def GetSizerItem(self):
439         """ Returns the associated sizer item. """
440
441         return self.sizer_item 
442
443
444     def SetLabel(self, s):
445         """
446         Sets the toolbar item label.
447
448         :param `s`: a string specifying the toolbar item label.
449         """
450
451         self.label = s
452
453         
454     def GetLabel(self):
455         """ Returns the toolbar item label. """
456
457         return self.label 
458
459
460     def SetBitmap(self, bmp):
461         """
462         Sets the toolbar item bitmap.
463
464         :param `bmp`: an instance of `wx.Bitmap`.
465         """
466         
467         self.bitmap = bmp
468
469         
470     def GetBitmap(self):
471         """ Returns the toolbar item bitmap. """
472
473         return self.GetRotatedBitmap(False)
474
475
476     def SetDisabledBitmap(self, bmp):
477         """
478         Sets the toolbar item disabled bitmap.
479
480         :param `bmp`: an instance of `wx.Bitmap`.
481         """
482         
483         self.disabled_bitmap = bmp
484
485         
486     def GetDisabledBitmap(self):
487         """ Returns the toolbar item disabled bitmap. """
488         
489         return self.GetRotatedBitmap(True)
490
491
492     def SetHoverBitmap(self, bmp):
493         """
494         Sets the toolbar item hover bitmap.
495
496         :param `bmp`: an instance of `wx.Bitmap`.
497         """
498         
499         self.hover_bitmap = bmp
500
501
502     def SetOrientation(self, a):
503         """
504         Sets the toolbar tool orientation.
505
506         :param `a`: one of ``AUI_TBTOOL_HORIZONTAL``, ``AUI_TBTOOL_VERT_CLOCKWISE`` or
507          ``AUI_TBTOOL_VERT_COUNTERCLOCKWISE``.
508         """
509
510         self.orientation = a
511
512
513     def GetOrientation(self):
514         """ Returns the toolbar tool orientation. """
515
516         return self.orientation
517     
518         
519     def GetHoverBitmap(self):
520         """ Returns the toolbar item hover bitmap. """
521         
522         return self.hover_bitmap 
523
524
525     def GetRotatedBitmap(self, disabled):
526         """
527         Returns the correct bitmap depending on the tool orientation.
528
529         :param `disabled`: whether to return the disabled bitmap or not.
530         """
531         
532         bitmap_to_rotate = (disabled and [self.disabled_bitmap] or [self.bitmap])[0]
533         if not bitmap_to_rotate.IsOk() or self.orientation == AUI_TBTOOL_HORIZONTAL:
534             return bitmap_to_rotate
535
536         rotated_bitmap = wx.NullBitmap
537         clockwise = True
538         if self.orientation == AUI_TBTOOL_VERT_CLOCKWISE:
539             rotated_bitmap = (disabled and [self.clockwisedisbmp] or [self.clockwisebmp])[0]
540
541         elif self.orientation == AUI_TBTOOL_VERT_COUNTERCLOCKWISE:
542             rotated_bitmap = (disabled and [self.counterclockwisedisbmp] or [self.counterclockwisebmp])[0]
543             clockwise = False
544
545         if not rotated_bitmap.IsOk():
546             rotated_bitmap = wx.BitmapFromImage(bitmap_to_rotate.ConvertToImage().Rotate90(clockwise))
547
548         return rotated_bitmap
549
550
551     def SetShortHelp(self, s):
552         """
553         Sets the short help string for the L{AuiToolBarItem}, to be displayed in a
554         `wx.ToolTip` when the mouse hover over the toolbar item.
555
556         :param `s`: the tool short help string.
557         """
558
559         self.short_help = s
560
561         
562     def GetShortHelp(self):
563         """ Returns the short help string for the L{AuiToolBarItem}. """
564
565         return self.short_help 
566
567
568     def SetLongHelp(self, s):
569         """
570         Sets the long help string for the toolbar item. This string is shown in the
571         statusbar (if any) of the parent frame when the mouse pointer is inside the
572         tool.
573
574         :param `s`: the tool long help string.
575         """
576
577         self.long_help = s
578
579         
580     def GetLongHelp(self):
581         """ Returns the long help string for the L{AuiToolBarItem}. """
582
583         return self.long_help 
584
585
586     def SetMinSize(self, s):
587         """
588         Sets the toolbar item minimum size.
589
590         :param `s`: an instance of `wx.Size`.
591         """
592
593         self.min_size = wx.Size(*s)
594
595         
596     def GetMinSize(self):
597         """ Returns the toolbar item minimum size. """
598
599         return self.min_size 
600
601
602     def SetSpacerPixels(self, s):
603         """
604         Sets the number of pixels for a toolbar item with kind = ``ITEM_SEPARATOR``.
605
606         :param `s`: number of pixels.
607         """
608
609         self.spacer_pixels = s
610
611         
612     def GetSpacerPixels(self):
613         """ Returns the number of pixels for a toolbar item with kind = ``ITEM_SEPARATOR``. """
614
615         return self.spacer_pixels 
616
617
618     def SetProportion(self, p):
619         """
620         Sets the L{AuiToolBarItem} proportion in the toolbar.
621
622         :param `p`: the item proportion.
623         """
624
625         self.proportion = p
626
627         
628     def GetProportion(self):
629         """ Returns the L{AuiToolBarItem} proportion in the toolbar. """
630
631         return self.proportion 
632
633
634     def SetActive(self, b):
635         """
636         Activates/deactivates the toolbar item.
637
638         :param `b`: ``True`` to activate the item, ``False`` to deactivate it.
639         """
640
641         self.active = b
642
643         
644     def IsActive(self):
645         """ Returns whether the toolbar item is active or not. """
646
647         return self.active
648     
649
650     def SetHasDropDown(self, b):
651         """
652         Sets whether the toolbar item has an associated dropdown menu.
653
654         :param `b`: ``True`` to set a dropdown menu, ``False`` otherwise.
655         """
656
657         self.dropdown = b
658
659         
660     def HasDropDown(self):
661         """ Returns whether the toolbar item has an associated dropdown menu or not. """
662
663         return self.dropdown 
664
665
666     def SetSticky(self, b):
667         """
668         Sets whether the toolbar item is sticky (permanent highlight after mouse enter)
669         or not.
670
671         :param `b`: ``True`` to set the item as sticky, ``False`` otherwise.
672         """
673
674         self.sticky = b
675
676         
677     def IsSticky(self):
678         """ Returns whether the toolbar item has a sticky behaviour or not. """
679
680         return self.sticky 
681
682
683     def SetUserData(self, l):
684         """
685         Associates some kind of user data to the toolbar item.
686         
687         :param `l`: a Python object.
688
689         :note: The user data can be any Python object.
690         """
691
692         self.user_data = l
693
694         
695     def GetUserData(self):
696         """ Returns the associated user data. """
697
698         return self.user_data
699     
700
701     def SetAlignment(self, l):
702         """
703         Sets the toolbar item alignment.
704
705         :param `l`: the item alignment, which can be one of the available `wx.Sizer`
706          alignments.
707         """
708
709         self.alignment = l
710
711         
712     def GetAlignment(self):
713         """ Returns the toolbar item alignment. """
714
715         return self.alignment        
716
717
718 # ----------------------------------------------------------------------
719
720 class AuiDefaultToolBarArt(object):
721     """
722     Toolbar art provider code - a tab provider provides all drawing functionality to
723     the L{AuiToolBar}. This allows the L{AuiToolBar} to have a plugable look-and-feel.
724
725     By default, a L{AuiToolBar} uses an instance of this class called L{AuiDefaultToolBarArt}
726     which provides bitmap art and a colour scheme that is adapted to the major platforms'
727     look. You can either derive from that class to alter its behaviour or write a
728     completely new tab art class. Call L{AuiToolBar.SetArtProvider} to make use this
729     new tab art.
730     """
731
732     def __init__(self):
733         """ Default class constructor. """
734         
735         self._base_colour = GetBaseColour()
736
737         self._agwFlags = 0
738         self._text_orientation = AUI_TBTOOL_TEXT_BOTTOM
739         self._highlight_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT)
740
741         self._separator_size = 7
742         self._orientation = AUI_TBTOOL_HORIZONTAL
743         self._gripper_size = 7
744         self._overflow_size = 16
745
746         darker1_colour = StepColour(self._base_colour, 85)
747         darker2_colour = StepColour(self._base_colour, 75)
748         darker3_colour = StepColour(self._base_colour, 60)
749         darker4_colour = StepColour(self._base_colour, 50)
750         darker5_colour = StepColour(self._base_colour, 40)
751
752         self._gripper_pen1 = wx.Pen(darker5_colour)
753         self._gripper_pen2 = wx.Pen(darker3_colour)
754         self._gripper_pen3 = wx.WHITE_PEN
755
756         button_dropdown_bits = "\xe0\xf1\xfb"
757         overflow_bits = "\x80\xff\x80\xc1\xe3\xf7"
758
759         self._button_dropdown_bmp = BitmapFromBits(button_dropdown_bits, 5, 3, wx.BLACK)
760         self._disabled_button_dropdown_bmp = BitmapFromBits(button_dropdown_bits, 5, 3,
761                                                             wx.Colour(128, 128, 128))
762         self._overflow_bmp = BitmapFromBits(overflow_bits, 7, 6, wx.BLACK)
763         self._disabled_overflow_bmp = BitmapFromBits(overflow_bits, 7, 6, wx.Colour(128, 128, 128))
764
765         self._font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
766
767
768     def Clone(self):
769         """ Clones the L{AuiToolBar} art. """
770
771         return AuiDefaultToolBarArt()
772
773
774     def SetAGWFlags(self, agwFlags):
775         """
776         Sets the toolbar art flags.
777
778         :param `agwFlags`: a combination of the following values:
779
780          ==================================== ==================================
781          Flag name                            Description
782          ==================================== ==================================
783          ``AUI_TB_TEXT``                      Shows the text in the toolbar buttons; by default only icons are shown
784          ``AUI_TB_NO_TOOLTIPS``               Don't show tooltips on `AuiToolBar` items
785          ``AUI_TB_NO_AUTORESIZE``             Do not auto-resize the `AuiToolBar`
786          ``AUI_TB_GRIPPER``                   Shows a gripper on the `AuiToolBar`
787          ``AUI_TB_OVERFLOW``                  The `AuiToolBar` can contain overflow items
788          ``AUI_TB_VERTICAL``                  The `AuiToolBar` is vertical
789          ``AUI_TB_HORZ_LAYOUT``               Shows the text and the icons alongside, not vertically stacked. This style must be used with ``AUI_TB_TEXT``
790          ``AUI_TB_PLAIN_BACKGROUND``          Don't draw a gradient background on the toolbar
791          ``AUI_TB_HORZ_TEXT``                 Combination of ``AUI_TB_HORZ_LAYOUT`` and ``AUI_TB_TEXT``
792          ==================================== ==================================
793         
794         """
795         
796         self._agwFlags = agwFlags
797
798
799     def GetAGWFlags(self):
800         """
801         Returns the L{AuiDefaultToolBarArt} flags. See L{SetAGWFlags} for more
802         details.
803
804         :see: L{SetAGWFlags}
805         """
806
807         return self._agwFlags
808
809
810     def SetFont(self, font):
811         """
812         Sets the L{AuiDefaultToolBarArt} font.
813
814         :param `font`: a `wx.Font` object.
815         """
816
817         self._font = font
818
819
820     def SetTextOrientation(self, orientation):
821         """
822         Sets the text orientation.
823
824         :param `orientation`: can be one of the following constants:
825
826          ==================================== ==================================
827          Orientation Switches                 Description
828          ==================================== ==================================
829          ``AUI_TBTOOL_TEXT_LEFT``             Text in `AuiToolBar` items is aligned left
830          ``AUI_TBTOOL_TEXT_RIGHT``            Text in `AuiToolBar` items is aligned right
831          ``AUI_TBTOOL_TEXT_TOP``              Text in `AuiToolBar` items is aligned top
832          ``AUI_TBTOOL_TEXT_BOTTOM``           Text in `AuiToolBar` items is aligned bottom
833          ==================================== ==================================
834         
835         """
836
837         self._text_orientation = orientation
838
839
840     def GetFont(self):
841         """ Returns the L{AuiDefaultToolBarArt} font. """
842
843         return self._font
844
845
846     def GetTextOrientation(self):
847         """
848         Returns the L{AuiDefaultToolBarArt} text orientation. See
849         L{SetTextOrientation} for more details.
850
851         :see: L{SetTextOrientation}
852         """
853
854         return self._text_orientation
855
856
857     def SetOrientation(self, orientation):
858         """
859         Sets the toolbar tool orientation.
860
861         :param `orientation`: one of ``AUI_TBTOOL_HORIZONTAL``, ``AUI_TBTOOL_VERT_CLOCKWISE`` or
862          ``AUI_TBTOOL_VERT_COUNTERCLOCKWISE``.
863         """
864
865         self._orientation = orientation
866
867
868     def GetOrientation(self):
869         """ Returns the toolbar orientation. """
870
871         return self._orientation        
872
873
874     def DrawBackground(self, dc, wnd, _rect, horizontal=True):
875         """
876         Draws a toolbar background with a gradient shading.
877
878         :param `dc`: a `wx.DC` device context;
879         :param `wnd`: a `wx.Window` derived window;
880         :param `_rect`: the L{AuiToolBar} rectangle;
881         :param `horizontal`: ``True`` if the toolbar is horizontal, ``False`` if it is vertical.
882         """
883
884         rect = wx.Rect(*_rect)
885
886         start_colour = StepColour(self._base_colour, 180)
887         end_colour = StepColour(self._base_colour, 85)
888         reflex_colour = StepColour(self._base_colour, 95)
889         
890         dc.GradientFillLinear(rect, start_colour, end_colour,
891                               (horizontal and [wx.SOUTH] or [wx.EAST])[0])
892
893         left = rect.GetLeft()
894         right = rect.GetRight()
895         top = rect.GetTop()
896         bottom = rect.GetBottom()
897
898         dc.SetPen(wx.Pen(reflex_colour))
899         if horizontal:
900             dc.DrawLine(left, bottom, right+1, bottom)
901         else:
902             dc.DrawLine(right, top, right, bottom+1)
903             
904
905     def DrawPlainBackground(self, dc, wnd, _rect):
906         """
907         Draws a toolbar background with a plain colour.
908
909         This method contrasts with the default behaviour of the L{AuiToolBar} that
910         draws a background gradient and this break the window design when putting
911         it within a control that has margin between the borders and the toolbar
912         (example: put L{AuiToolBar} within a `wx.StaticBoxSizer` that has a plain background).
913       
914         :param `dc`: a `wx.DC` device context;
915         :param `wnd`: a `wx.Window` derived window;
916         :param `_rect`: the L{AuiToolBar} rectangle.
917         """
918         
919         rect = wx.Rect(*_rect)
920         rect.height += 1
921
922         dc.SetBrush(wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE)))
923         dc.DrawRectangle(rect.x - 1, rect.y - 1, rect.width + 2, rect.height + 1)
924
925
926     def DrawLabel(self, dc, wnd, item, rect):
927         """
928         Draws a toolbar item label.
929         
930         :param `dc`: a `wx.DC` device context;
931         :param `wnd`: a `wx.Window` derived window;
932         :param `item`: an instance of L{AuiToolBarItem};
933         :param `rect`: the L{AuiToolBarItem} rectangle.
934         """
935         
936         dc.SetFont(self._font)
937         dc.SetTextForeground(wx.BLACK)
938         orient = item.GetOrientation()
939
940         horizontal = orient == AUI_TBTOOL_HORIZONTAL
941         # we only care about the text height here since the text
942         # will get cropped based on the width of the item
943         label_size = GetLabelSize(dc, item.GetLabel(), not horizontal)
944         text_width = label_size.GetWidth()
945         text_height = label_size.GetHeight()
946
947         if orient == AUI_TBTOOL_HORIZONTAL:
948             text_x = rect.x
949             text_y = rect.y + (rect.height-text_height)/2
950             dc.DrawText(item.GetLabel(), text_x, text_y)
951
952         elif orient == AUI_TBTOOL_VERT_CLOCKWISE:
953             text_x = rect.x + (rect.width+text_width)/2
954             text_y = rect.y
955             dc.DrawRotatedText(item.GetLabel(), text_x, text_y, 270)
956
957         elif AUI_TBTOOL_VERT_COUNTERCLOCKWISE:
958             text_x = rect.x + (rect.width-text_width)/2
959             text_y = rect.y + text_height
960             dc.DrawRotatedText(item.GetLabel(), text_x, text_y, 90)
961
962
963     def DrawButton(self, dc, wnd, item, rect):
964         """
965         Draws a toolbar item button.
966         
967         :param `dc`: a `wx.DC` device context;
968         :param `wnd`: a `wx.Window` derived window;
969         :param `item`: an instance of L{AuiToolBarItem};
970         :param `rect`: the L{AuiToolBarItem} rectangle.
971         """
972
973         bmp_rect, text_rect = self.GetToolsPosition(dc, item, rect)
974         
975         if not item.GetState() & AUI_BUTTON_STATE_DISABLED:
976         
977             if item.GetState() & AUI_BUTTON_STATE_PRESSED:
978             
979                 dc.SetPen(wx.Pen(self._highlight_colour))
980                 dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 150)))
981                 dc.DrawRectangleRect(rect)
982             
983             elif item.GetState() & AUI_BUTTON_STATE_HOVER or item.IsSticky():
984             
985                 dc.SetPen(wx.Pen(self._highlight_colour))
986                 dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 170)))
987
988                 # draw an even lighter background for checked item hovers (since
989                 # the hover background is the same colour as the check background)
990                 if item.GetState() & AUI_BUTTON_STATE_CHECKED:
991                     dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 180)))
992
993                 dc.DrawRectangleRect(rect)
994             
995             elif item.GetState() & AUI_BUTTON_STATE_CHECKED:
996             
997                 # it's important to put this code in an else statment after the
998                 # hover, otherwise hovers won't draw properly for checked items
999                 dc.SetPen(wx.Pen(self._highlight_colour))
1000                 dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 170)))
1001                 dc.DrawRectangleRect(rect)
1002             
1003         if item.GetState() & AUI_BUTTON_STATE_DISABLED:
1004             bmp = item.GetDisabledBitmap()
1005         else:
1006             bmp = item.GetBitmap()
1007
1008         if bmp.IsOk():
1009             dc.DrawBitmap(bmp, bmp_rect.x, bmp_rect.y, True)
1010
1011         # set the item's text colour based on if it is disabled
1012         dc.SetTextForeground(wx.BLACK)
1013         if item.GetState() & AUI_BUTTON_STATE_DISABLED:
1014             dc.SetTextForeground(DISABLED_TEXT_COLOUR)
1015
1016         if self._agwFlags & AUI_TB_TEXT and item.GetLabel() != "":
1017             self.DrawLabel(dc, wnd, item, text_rect)
1018         
1019
1020     def DrawDropDownButton(self, dc, wnd, item, rect):
1021         """
1022         Draws a toolbar dropdown button.
1023         
1024         :param `dc`: a `wx.DC` device context;
1025         :param `wnd`: a `wx.Window` derived window;
1026         :param `item`: an instance of L{AuiToolBarItem};
1027         :param `rect`: the L{AuiToolBarItem} rectangle.
1028         """
1029         
1030         dropbmp_x = dropbmp_y = 0
1031
1032         button_rect = wx.Rect(rect.x, rect.y, rect.width-BUTTON_DROPDOWN_WIDTH, rect.height)
1033         dropdown_rect = wx.Rect(rect.x+rect.width-BUTTON_DROPDOWN_WIDTH-1, rect.y, BUTTON_DROPDOWN_WIDTH+1, rect.height)
1034
1035         horizontal = item.GetOrientation() == AUI_TBTOOL_HORIZONTAL
1036         
1037         if horizontal:
1038             button_rect = wx.Rect(rect.x, rect.y, rect.width-BUTTON_DROPDOWN_WIDTH, rect.height)
1039             dropdown_rect = wx.Rect(rect.x+rect.width-BUTTON_DROPDOWN_WIDTH-1, rect.y, BUTTON_DROPDOWN_WIDTH+1, rect.height)
1040         else:
1041             button_rect = wx.Rect(rect.x, rect.y, rect.width, rect.height-BUTTON_DROPDOWN_WIDTH)
1042             dropdown_rect = wx.Rect(rect.x, rect.y+rect.height-BUTTON_DROPDOWN_WIDTH-1, rect.width, BUTTON_DROPDOWN_WIDTH+1)
1043
1044         dropbmp_width = self._button_dropdown_bmp.GetWidth()
1045         dropbmp_height = self._button_dropdown_bmp.GetHeight()
1046         if not horizontal:
1047             tmp = dropbmp_width
1048             dropbmp_width = dropbmp_height
1049             dropbmp_height = tmp
1050
1051         dropbmp_x = dropdown_rect.x + (dropdown_rect.width/2) - dropbmp_width/2
1052         dropbmp_y = dropdown_rect.y + (dropdown_rect.height/2) - dropbmp_height/2
1053
1054         bmp_rect, text_rect = self.GetToolsPosition(dc, item, button_rect)
1055         
1056         if item.GetState() & AUI_BUTTON_STATE_PRESSED:
1057         
1058             dc.SetPen(wx.Pen(self._highlight_colour))
1059             dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 140)))
1060             dc.DrawRectangleRect(button_rect)
1061             dc.DrawRectangleRect(dropdown_rect)
1062         
1063         elif item.GetState() & AUI_BUTTON_STATE_HOVER or item.IsSticky():
1064         
1065             dc.SetPen(wx.Pen(self._highlight_colour))
1066             dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 170)))
1067             dc.DrawRectangleRect(button_rect)
1068             dc.DrawRectangleRect(dropdown_rect)
1069
1070         elif item.GetState() & AUI_BUTTON_STATE_CHECKED:
1071             # it's important to put this code in an else statment after the 
1072             # hover, otherwise hovers won't draw properly for checked items 
1073             dc.SetPen(wx.Pen(self._highlight_colour))
1074             dc.SetBrush(wx.Brush(StepColour(self._highlight_colour, 170)))
1075             dc.DrawRectangle(button_rect)
1076             dc.DrawRectangle(dropdown_rect)
1077             
1078         if item.GetState() & AUI_BUTTON_STATE_DISABLED:
1079         
1080             bmp = item.GetDisabledBitmap()
1081             dropbmp = self._disabled_button_dropdown_bmp
1082         
1083         else:
1084         
1085             bmp = item.GetBitmap()
1086             dropbmp = self._button_dropdown_bmp
1087         
1088         if not bmp.IsOk():
1089             return
1090
1091         dc.DrawBitmap(bmp, bmp_rect.x, bmp_rect.y, True)
1092         if horizontal:
1093             dc.DrawBitmap(dropbmp, dropbmp_x, dropbmp_y, True)
1094         else:
1095             dc.DrawBitmap(wx.BitmapFromImage(dropbmp.ConvertToImage().Rotate90(item.GetOrientation() == AUI_TBTOOL_VERT_CLOCKWISE)),
1096                           dropbmp_x, dropbmp_y, True)
1097             
1098         # set the item's text colour based on if it is disabled
1099         dc.SetTextForeground(wx.BLACK)
1100         if item.GetState() & AUI_BUTTON_STATE_DISABLED:
1101             dc.SetTextForeground(DISABLED_TEXT_COLOUR)
1102
1103         if self._agwFlags & AUI_TB_TEXT and item.GetLabel() != "":  
1104             self.DrawLabel(dc, wnd, item, text_rect)
1105         
1106
1107     def DrawControlLabel(self, dc, wnd, item, rect):
1108         """
1109         Draws a label for a toolbar control.
1110         
1111         :param `dc`: a `wx.DC` device context;
1112         :param `wnd`: a `wx.Window` derived window;
1113         :param `item`: an instance of L{AuiToolBarItem};
1114         :param `rect`: the L{AuiToolBarItem} rectangle.
1115         """
1116
1117         label_size = GetLabelSize(dc, item.GetLabel(), item.GetOrientation() != AUI_TBTOOL_HORIZONTAL)
1118         text_height = label_size.GetHeight()
1119         text_width = label_size.GetWidth()
1120
1121         dc.SetFont(self._font)
1122
1123         if self._agwFlags & AUI_TB_TEXT:
1124         
1125             tx, text_height = dc.GetTextExtent("ABCDHgj")        
1126
1127         text_width, ty = dc.GetTextExtent(item.GetLabel())
1128
1129         # don't draw the label if it is wider than the item width
1130         if text_width > rect.width:
1131             return
1132
1133         # set the label's text colour
1134         dc.SetTextForeground(wx.BLACK)
1135
1136         text_x = rect.x + (rect.width/2) - (text_width/2) + 1
1137         text_y = rect.y + rect.height - text_height - 1
1138
1139         if self._agwFlags & AUI_TB_TEXT and item.GetLabel() != "": 
1140             dc.DrawText(item.GetLabel(), text_x, text_y)
1141     
1142
1143     def GetLabelSize(self, dc, wnd, item):
1144         """
1145         Returns the label size for a toolbar item.
1146         
1147         :param `dc`: a `wx.DC` device context;
1148         :param `wnd`: a `wx.Window` derived window;
1149         :param `item`: an instance of L{AuiToolBarItem}.
1150         """
1151
1152         dc.SetFont(self._font)
1153         label_size = GetLabelSize(dc, item.GetLabel(), self._orientation != AUI_TBTOOL_HORIZONTAL)
1154
1155         return wx.Size(item.GetMinSize().GetWidth(), label_size.GetHeight())
1156
1157
1158     def GetToolSize(self, dc, wnd, item):
1159         """
1160         Returns the toolbar item size.
1161         
1162         :param `dc`: a `wx.DC` device context;
1163         :param `wnd`: a `wx.Window` derived window;
1164         :param `item`: an instance of L{AuiToolBarItem}.
1165         """
1166         
1167         if not item.GetBitmap().IsOk() and not self._agwFlags & AUI_TB_TEXT:
1168             return wx.Size(16, 16)
1169
1170         width = item.GetBitmap().GetWidth()
1171         height = item.GetBitmap().GetHeight()
1172
1173         if self._agwFlags & AUI_TB_TEXT:
1174         
1175             dc.SetFont(self._font)
1176             label_size = GetLabelSize(dc, item.GetLabel(), self.GetOrientation() != AUI_TBTOOL_HORIZONTAL)
1177             padding = 6
1178             
1179             if self._text_orientation == AUI_TBTOOL_TEXT_BOTTOM:
1180             
1181                 if self.GetOrientation() != AUI_TBTOOL_HORIZONTAL:
1182                     height += 3   # space between top border and bitmap
1183                     height += 3   # space between bitmap and text
1184                     padding = 0
1185
1186                 height += label_size.GetHeight()
1187             
1188                 if item.GetLabel() != "":
1189                     width = max(width, label_size.GetWidth()+padding)
1190                 
1191             elif self._text_orientation == AUI_TBTOOL_TEXT_RIGHT and item.GetLabel() != "":
1192             
1193                 if self.GetOrientation() == AUI_TBTOOL_HORIZONTAL:
1194                     
1195                     width += 3  # space between left border and bitmap
1196                     width += 3  # space between bitmap and text
1197                     padding = 0
1198
1199                 width += label_size.GetWidth()
1200                 height = max(height, label_size.GetHeight()+padding)
1201                 
1202         # if the tool has a dropdown button, add it to the width
1203         if item.HasDropDown():
1204             if item.GetOrientation() == AUI_TBTOOL_HORIZONTAL:
1205                 width += BUTTON_DROPDOWN_WIDTH+4
1206             else:
1207                 height += BUTTON_DROPDOWN_WIDTH+4
1208
1209         return wx.Size(width, height)
1210
1211
1212     def DrawSeparator(self, dc, wnd, _rect):
1213         """
1214         Draws a toolbar separator.
1215         
1216         :param `dc`: a `wx.DC` device context;
1217         :param `wnd`: a `wx.Window` derived window;
1218         :param `_rect`: the L{AuiToolBarItem} rectangle.
1219         """
1220         
1221         horizontal = True
1222         if self._agwFlags & AUI_TB_VERTICAL:
1223             horizontal = False
1224
1225         rect = wx.Rect(*_rect)
1226
1227         if horizontal:
1228         
1229             rect.x += (rect.width/2)
1230             rect.width = 1
1231             new_height = (rect.height*3)/4
1232             rect.y += (rect.height/2) - (new_height/2)
1233             rect.height = new_height
1234         
1235         else:
1236         
1237             rect.y += (rect.height/2)
1238             rect.height = 1
1239             new_width = (rect.width*3)/4
1240             rect.x += (rect.width/2) - (new_width/2)
1241             rect.width = new_width
1242         
1243         start_colour = StepColour(self._base_colour, 80)
1244         end_colour = StepColour(self._base_colour, 80)
1245         dc.GradientFillLinear(rect, start_colour, end_colour, (horizontal and [wx.SOUTH] or [wx.EAST])[0])
1246
1247
1248     def DrawGripper(self, dc, wnd, rect):
1249         """
1250         Draws the toolbar gripper.
1251         
1252         :param `dc`: a `wx.DC` device context;
1253         :param `wnd`: a `wx.Window` derived window;
1254         :param `rect`: the L{AuiToolBar} rectangle.
1255         """
1256         
1257         i = 0
1258         while 1:
1259         
1260             if self._agwFlags & AUI_TB_VERTICAL:
1261             
1262                 x = rect.x + (i*4) + 4
1263                 y = rect.y + 3
1264                 if x > rect.GetWidth() - 4:
1265                     break
1266             
1267             else:
1268             
1269                 x = rect.x + 3
1270                 y = rect.y + (i*4) + 4
1271                 if y > rect.GetHeight() - 4:
1272                     break
1273             
1274             dc.SetPen(self._gripper_pen1)
1275             dc.DrawPoint(x, y)
1276             dc.SetPen(self._gripper_pen2)
1277             dc.DrawPoint(x, y+1)
1278             dc.DrawPoint(x+1, y)
1279             dc.SetPen(self._gripper_pen3)
1280             dc.DrawPoint(x+2, y+1)
1281             dc.DrawPoint(x+2, y+2)
1282             dc.DrawPoint(x+1, y+2)
1283
1284             i += 1
1285
1286
1287     def DrawOverflowButton(self, dc, wnd, rect, state):
1288         """
1289         Draws the overflow button for the L{AuiToolBar}.
1290         
1291         :param `dc`: a `wx.DC` device context;
1292         :param `wnd`: a `wx.Window` derived window;
1293         :param `rect`: the L{AuiToolBar} rectangle;
1294         :param `state`: the overflow button state.
1295         """
1296         
1297         if state & AUI_BUTTON_STATE_HOVER or  state & AUI_BUTTON_STATE_PRESSED:
1298         
1299             cli_rect = wnd.GetClientRect()
1300             light_gray_bg = StepColour(self._highlight_colour, 170)
1301
1302             if self._agwFlags & AUI_TB_VERTICAL:
1303             
1304                 dc.SetPen(wx.Pen(self._highlight_colour))
1305                 dc.DrawLine(rect.x, rect.y, rect.x+rect.width, rect.y)
1306                 dc.SetPen(wx.Pen(light_gray_bg))
1307                 dc.SetBrush(wx.Brush(light_gray_bg))
1308                 dc.DrawRectangle(rect.x, rect.y+1, rect.width, rect.height)
1309             
1310             else:
1311             
1312                 dc.SetPen(wx.Pen(self._highlight_colour))
1313                 dc.DrawLine(rect.x, rect.y, rect.x, rect.y+rect.height)
1314                 dc.SetPen(wx.Pen(light_gray_bg))
1315                 dc.SetBrush(wx.Brush(light_gray_bg))
1316                 dc.DrawRectangle(rect.x+1, rect.y, rect.width, rect.height)
1317             
1318         x = rect.x + 1 + (rect.width-self._overflow_bmp.GetWidth())/2
1319         y = rect.y + 1 + (rect.height-self._overflow_bmp.GetHeight())/2
1320         dc.DrawBitmap(self._overflow_bmp, x, y, True)
1321
1322
1323     def GetElementSize(self, element_id):
1324         """
1325         Returns the size of a UI element in the L{AuiToolBar}.
1326
1327         :param `element_id`: can be one of the following:
1328
1329          ==================================== ==================================
1330          Element Identifier                   Description
1331          ==================================== ==================================
1332          ``AUI_TBART_SEPARATOR_SIZE``         Separator size in `AuiToolBar`
1333          ``AUI_TBART_GRIPPER_SIZE``           Gripper size in `AuiToolBar`
1334          ``AUI_TBART_OVERFLOW_SIZE``          Overflow button size in `AuiToolBar`
1335          ==================================== ==================================        
1336         """
1337         
1338         if element_id == AUI_TBART_SEPARATOR_SIZE:
1339             return self._separator_size
1340         elif element_id == AUI_TBART_GRIPPER_SIZE:
1341             return self._gripper_size
1342         elif element_id == AUI_TBART_OVERFLOW_SIZE:
1343             return self._overflow_size
1344
1345         return 0
1346
1347
1348     def SetElementSize(self, element_id, size):
1349         """
1350         Sets the size of a UI element in the L{AuiToolBar}.
1351
1352         :param `element_id`: can be one of the following:
1353
1354          ==================================== ==================================
1355          Element Identifier                   Description
1356          ==================================== ==================================
1357          ``AUI_TBART_SEPARATOR_SIZE``         Separator size in `AuiToolBar`
1358          ``AUI_TBART_GRIPPER_SIZE``           Gripper size in `AuiToolBar`
1359          ``AUI_TBART_OVERFLOW_SIZE``          Overflow button size in `AuiToolBar`
1360          ==================================== ==================================
1361
1362         :param `size`: the new size of the UI element.        
1363         """
1364         
1365         if element_id == AUI_TBART_SEPARATOR_SIZE:
1366             self._separator_size = size
1367         elif element_id == AUI_TBART_GRIPPER_SIZE:
1368             self._gripper_size = size
1369         elif element_id == AUI_TBART_OVERFLOW_SIZE:
1370             self._overflow_size = size
1371
1372
1373     def ShowDropDown(self, wnd, items):
1374         """
1375         Shows the drop down window menu for overflow items.
1376
1377         :param `wnd`: an instance of `wx.Window`;
1378         :param `items`: the overflow toolbar items (a Python list).
1379         """
1380
1381         menuPopup = wx.Menu()
1382         items_added = 0
1383
1384         for item in items:
1385
1386             if item.GetKind() not in [ITEM_SEPARATOR, ITEM_SPACER, ITEM_CONTROL]:
1387             
1388                 text = item.GetShortHelp()
1389                 if text == "":
1390                     text = item.GetLabel()
1391                 if text == "":
1392                     text = " "
1393
1394                 kind = item.GetKind()
1395                 m = wx.MenuItem(menuPopup, item.GetId(), text, item.GetShortHelp(), kind)
1396                 orientation = item.GetOrientation()
1397                 item.SetOrientation(AUI_TBTOOL_HORIZONTAL)
1398                 
1399                 if kind not in [ITEM_CHECK, ITEM_RADIO]:
1400                     m.SetBitmap(item.GetBitmap())
1401
1402                 item.SetOrientation(orientation)                    
1403                     
1404                 menuPopup.AppendItem(m)
1405                 if kind in [ITEM_CHECK, ITEM_RADIO]:            
1406                     state = (item.state & AUI_BUTTON_STATE_CHECKED and [True] or [False])[0]
1407                     m.Check(state)
1408
1409                 items_added += 1
1410             
1411             else:
1412             
1413                 if items_added > 0 and item.GetKind() == ITEM_SEPARATOR:
1414                     menuPopup.AppendSeparator()
1415             
1416         # find out where to put the popup menu of window items
1417         pt = wx.GetMousePosition()
1418         pt = wnd.ScreenToClient(pt)
1419
1420         # find out the screen coordinate at the bottom of the tab ctrl
1421         cli_rect = wnd.GetClientRect()
1422         pt.y = cli_rect.y + cli_rect.height
1423
1424         cc = ToolbarCommandCapture()
1425         wnd.PushEventHandler(cc)
1426
1427         # Adjustments to get slightly better menu placement
1428         if wx.Platform == "__WXMAC__":
1429             pt.y += 5
1430             pt.x -= 5
1431
1432         wnd.PopupMenu(menuPopup, pt)
1433         command = cc.GetCommandId()
1434         wnd.PopEventHandler(True)
1435
1436         return command
1437
1438
1439     def GetToolsPosition(self, dc, item, rect):
1440         """
1441         Returns the bitmap and text rectangles for a toolbar item.
1442         
1443         :param `dc`: a `wx.DC` device context;
1444         :param `item`: an instance of L{AuiToolBarItem};
1445         :param `rect`: the tool rect.
1446         """
1447         
1448         text_width = text_height = 0
1449         horizontal = self._orientation == AUI_TBTOOL_HORIZONTAL
1450         text_bottom = self._text_orientation == AUI_TBTOOL_TEXT_BOTTOM
1451         text_right = self._text_orientation == AUI_TBTOOL_TEXT_RIGHT
1452         bmp_width = item.GetBitmap().GetWidth()
1453         bmp_height = item.GetBitmap().GetHeight()
1454      
1455         if self._agwFlags & AUI_TB_TEXT:        
1456             dc.SetFont(self._font)
1457             label_size = GetLabelSize(dc, item.GetLabel(), not horizontal)
1458             text_height = label_size.GetHeight()
1459             text_width = label_size.GetWidth()
1460         
1461         bmp_x = bmp_y = text_x = text_y = 0
1462
1463         if horizontal and text_bottom:
1464             bmp_x = rect.x + (rect.width/2) - (bmp_width/2)
1465             bmp_y = rect.y + 3
1466             text_x = rect.x + (rect.width/2) - (text_width/2)
1467             text_y = rect.y + ((bmp_y - rect.y) * 2) + bmp_height
1468         
1469         elif horizontal and text_right:
1470             bmp_x = rect.x + 3
1471             bmp_y = rect.y + (rect.height/2) - (bmp_height / 2)
1472             text_x = rect.x + ((bmp_x - rect.x) * 2) + bmp_width
1473             text_y = rect.y + (rect.height/2) - (text_height/2)
1474         
1475         elif not horizontal and text_bottom:
1476             bmp_x = rect.x + (rect.width / 2) - (bmp_width / 2)
1477             bmp_y = rect.y + 3
1478             text_x = rect.x + (rect.width / 2) - (text_width / 2)
1479             text_y = rect.y + ((bmp_y - rect.y) * 2) + bmp_height
1480         
1481         bmp_rect = wx.Rect(bmp_x, bmp_y, bmp_width, bmp_height)
1482         text_rect = wx.Rect(text_x, text_y, text_width, text_height)
1483
1484         return bmp_rect, text_rect
1485
1486     
1487 class AuiToolBar(wx.PyControl):
1488     """
1489     AuiToolBar is a completely owner-drawn toolbar perfectly integrated with the
1490     AUI layout system. This allows drag and drop of toolbars, docking/floating
1491     behaviour and the possibility to define "overflow" items in the toolbar itself.
1492
1493     The default theme that is used is L{AuiDefaultToolBarArt}, which provides a modern,
1494     glossy look and feel. The theme can be changed by calling L{AuiToolBar.SetArtProvider}.
1495     """
1496
1497     def __init__(self, parent, id=wx.ID_ANY, pos=wx.DefaultPosition,
1498                  size=wx.DefaultSize, style=0, agwStyle=AUI_TB_DEFAULT_STYLE):
1499         """
1500         Default class constructor.
1501
1502         :param `parent`: the L{AuiToolBar} parent;
1503         :param `id`: an identifier for the control: a value of -1 is taken to mean a default;
1504         :param `pos`: the control position. A value of (-1, -1) indicates a default position,
1505          chosen by either the windowing system or wxPython, depending on platform;
1506         :param `size`: the control size. A value of (-1, -1) indicates a default size,
1507          chosen by either the windowing system or wxPython, depending on platform;
1508         :param `style`: the control window style;
1509         :param `agwStyle`: the AGW-specific window style. This can be a combination of the
1510          following bits:
1511         
1512          ==================================== ==================================
1513          Flag name                            Description
1514          ==================================== ==================================
1515          ``AUI_TB_TEXT``                      Shows the text in the toolbar buttons; by default only icons are shown
1516          ``AUI_TB_NO_TOOLTIPS``               Don't show tooltips on `AuiToolBar` items
1517          ``AUI_TB_NO_AUTORESIZE``             Do not auto-resize the `AuiToolBar`
1518          ``AUI_TB_GRIPPER``                   Shows a gripper on the `AuiToolBar`
1519          ``AUI_TB_OVERFLOW``                  The `AuiToolBar` can contain overflow items
1520          ``AUI_TB_VERTICAL``                  The `AuiToolBar` is vertical
1521          ``AUI_TB_HORZ_LAYOUT``               Shows the text and the icons alongside, not vertically stacked. This style must be used with ``AUI_TB_TEXT``
1522          ``AUI_TB_PLAIN_BACKGROUND``          Don't draw a gradient background on the toolbar
1523          ``AUI_TB_HORZ_TEXT``                 Combination of ``AUI_TB_HORZ_LAYOUT`` and ``AUI_TB_TEXT``
1524          ==================================== ==================================
1525
1526          The default value for `agwStyle` is: ``AUI_TB_DEFAULT_STYLE`` = 0
1527
1528         """
1529         
1530         wx.PyControl.__init__(self, parent, id, pos, size, style|wx.BORDER_NONE)
1531
1532         self._sizer = wx.BoxSizer(wx.HORIZONTAL)
1533         self.SetSizer(self._sizer)
1534         self._button_width = -1
1535         self._button_height = -1
1536         self._sizer_element_count = 0
1537         self._action_pos = wx.Point(-1, -1)
1538         self._action_item = None
1539         self._tip_item = None
1540         self._art = AuiDefaultToolBarArt()
1541         self._tool_packing = 2
1542         self._tool_border_padding = 3
1543         self._tool_text_orientation = AUI_TBTOOL_TEXT_BOTTOM
1544         self._tool_orientation = AUI_TBTOOL_HORIZONTAL
1545         self._tool_alignment = wx.EXPAND
1546         self._gripper_sizer_item = None
1547         self._overflow_sizer_item = None
1548         self._dragging = False
1549
1550         self._agwStyle = self._originalStyle = agwStyle
1551
1552         self._gripper_visible = (self._agwStyle & AUI_TB_GRIPPER and [True] or [False])[0]
1553         self._overflow_visible = (self._agwStyle & AUI_TB_OVERFLOW and [True] or [False])[0]
1554         self._overflow_state = 0
1555         self._custom_overflow_prepend = []
1556         self._custom_overflow_append = []
1557
1558         self._items = []
1559         
1560         self.SetMargins(5, 5, 2, 2)
1561         self.SetFont(wx.NORMAL_FONT)
1562         self._art.SetAGWFlags(self._agwStyle)
1563         self.SetExtraStyle(wx.WS_EX_PROCESS_IDLE)
1564         
1565         if agwStyle & AUI_TB_HORZ_LAYOUT:
1566             self.SetToolTextOrientation(AUI_TBTOOL_TEXT_RIGHT)
1567         elif agwStyle & AUI_TB_VERTICAL:
1568             if agwStyle & AUI_TB_CLOCKWISE:
1569                 self.SetToolOrientation(AUI_TBTOOL_VERT_CLOCKWISE)
1570             elif agwStyle & AUI_TB_COUNTERCLOCKWISE:
1571                 self.SetToolOrientation(AUI_TBTOOL_VERT_COUNTERCLOCKWISE)
1572  
1573         self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
1574         
1575         self.Bind(wx.EVT_SIZE, self.OnSize)
1576         self.Bind(wx.EVT_IDLE, self.OnIdle)
1577         self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground)
1578         self.Bind(wx.EVT_PAINT, self.OnPaint)
1579         self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown)
1580         self.Bind(wx.EVT_LEFT_DCLICK, self.OnLeftDown)
1581         self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp)
1582         self.Bind(wx.EVT_RIGHT_DOWN, self.OnRightDown)
1583         self.Bind(wx.EVT_RIGHT_DCLICK, self.OnRightDown)
1584         self.Bind(wx.EVT_RIGHT_UP, self.OnRightUp)
1585         self.Bind(wx.EVT_MIDDLE_DOWN, self.OnMiddleDown)
1586         self.Bind(wx.EVT_MIDDLE_DCLICK, self.OnMiddleDown)
1587         self.Bind(wx.EVT_MIDDLE_UP, self.OnMiddleUp)
1588         self.Bind(wx.EVT_MOTION, self.OnMotion)
1589         self.Bind(wx.EVT_LEAVE_WINDOW, self.OnLeaveWindow)
1590         self.Bind(wx.EVT_SET_CURSOR, self.OnSetCursor)
1591
1592
1593     def SetWindowStyleFlag(self, style):
1594         """
1595         Sets the style of the window.
1596         
1597         :param `style`: the new window style. 
1598
1599         :note: Please note that some styles cannot be changed after the window
1600          creation and that `Refresh` might need to be be called after changing the
1601          others for the change to take place immediately.
1602
1603         :note: Overridden from `wx.PyControl`.
1604         """
1605
1606         wx.PyControl.SetWindowStyleFlag(self, style|wx.BORDER_NONE)
1607         
1608
1609     def SetAGWWindowStyleFlag(self, agwStyle):
1610         """
1611         Sets the AGW-specific style of the window.
1612         
1613         :param `agwStyle`: the new window style. This can be a combination of the
1614          following bits:
1615         
1616          ==================================== ==================================
1617          Flag name                            Description
1618          ==================================== ==================================
1619          ``AUI_TB_TEXT``                      Shows the text in the toolbar buttons; by default only icons are shown
1620          ``AUI_TB_NO_TOOLTIPS``               Don't show tooltips on `AuiToolBar` items
1621          ``AUI_TB_NO_AUTORESIZE``             Do not auto-resize the `AuiToolBar`
1622          ``AUI_TB_GRIPPER``                   Shows a gripper on the `AuiToolBar`
1623          ``AUI_TB_OVERFLOW``                  The `AuiToolBar` can contain overflow items
1624          ``AUI_TB_VERTICAL``                  The `AuiToolBar` is vertical
1625          ``AUI_TB_HORZ_LAYOUT``               Shows the text and the icons alongside, not vertically stacked. This style must be used with ``AUI_TB_TEXT``
1626          ``AUI_TB_PLAIN_BACKGROUND``          Don't draw a gradient background on the toolbar
1627          ``AUI_TB_HORZ_TEXT``                 Combination of ``AUI_TB_HORZ_LAYOUT`` and ``AUI_TB_TEXT``
1628          ==================================== ==================================
1629
1630         :note: Please note that some styles cannot be changed after the window
1631          creation and that `Refresh` might need to be be called after changing the
1632          others for the change to take place immediately.
1633         """
1634         
1635         self._agwStyle = self._originalStyle = agwStyle
1636
1637         if self._art:
1638             self._art.SetAGWFlags(self._agwStyle)
1639         
1640         if agwStyle & AUI_TB_GRIPPER:
1641             self._gripper_visible = True
1642         else:
1643             self._gripper_visible = False
1644
1645         if agwStyle & AUI_TB_OVERFLOW:
1646             self._overflow_visible = True
1647         else:
1648             self._overflow_visible = False
1649
1650         if agwStyle & AUI_TB_HORZ_LAYOUT:
1651             self.SetToolTextOrientation(AUI_TBTOOL_TEXT_RIGHT)
1652         else:
1653             self.SetToolTextOrientation(AUI_TBTOOL_TEXT_BOTTOM)
1654
1655         if agwStyle & AUI_TB_VERTICAL:
1656             if agwStyle & AUI_TB_CLOCKWISE:
1657                 self.SetToolOrientation(AUI_TBTOOL_VERT_CLOCKWISE)
1658             elif agwStyle & AUI_TB_COUNTERCLOCKWISE:
1659                 self.SetToolOrientation(AUI_TBTOOL_VERT_COUNTERCLOCKWISE)
1660
1661                 
1662     def GetAGWWindowStyleFlag(self):
1663         """
1664         Returns the AGW-specific window style flag.
1665
1666         :see: L{SetAGWWindowStyleFlag} for an explanation of various AGW-specific style.
1667         """
1668
1669         return self._agwStyle
1670     
1671
1672     def SetArtProvider(self, art):
1673         """
1674         Instructs L{AuiToolBar} to use art provider specified by parameter `art`
1675         for all drawing calls. This allows plugable look-and-feel features. 
1676
1677         :param `art`: an art provider.
1678
1679         :note: The previous art provider object, if any, will be deleted by L{AuiToolBar}.
1680         """
1681         
1682         del self._art
1683         self._art = art
1684
1685         if self._art:
1686             self._art.SetAGWFlags(self._agwStyle)
1687             self._art.SetTextOrientation(self._tool_text_orientation)
1688             self._art.SetOrientation(self._tool_orientation)
1689         
1690
1691     def GetArtProvider(self):
1692         """ Returns the current art provider being used. """
1693
1694         return self._art
1695
1696
1697     def AddSimpleTool(self, tool_id, label, bitmap, short_help_string="", kind=ITEM_NORMAL):
1698         """
1699         Adds a tool to the toolbar. This is the simplest method you can use to
1700         ass an item to the L{AuiToolBar}.
1701
1702         :param `tool_id`: an integer by which the tool may be identified in subsequent operations;
1703         :param `label`: the toolbar tool label;
1704         :param `bitmap`: the primary tool bitmap;
1705         :param `short_help_string`: this string is used for the tools tooltip;
1706         :param `kind`: the item kind. Can be one of the following:
1707
1708          ========================  =============================
1709          Item Kind                 Description
1710          ========================  =============================
1711          ``ITEM_CONTROL``          The item in the `AuiToolBar` is a control
1712          ``ITEM_LABEL``            The item in the `AuiToolBar` is a text label
1713          ``ITEM_SPACER``           The item in the `AuiToolBar` is a spacer
1714          ``ITEM_SEPARATOR``        The item in the `AuiToolBar` is a separator
1715          ``ITEM_CHECK``            The item in the `AuiToolBar` is a toolbar check item
1716          ``ITEM_NORMAL``           The item in the `AuiToolBar` is a standard toolbar item
1717          ``ITEM_RADIO``            The item in the `AuiToolBar` is a toolbar radio item
1718          ========================  =============================
1719         """
1720         
1721         return self.AddTool(tool_id, label, bitmap, wx.NullBitmap, kind, short_help_string, "", None)
1722
1723
1724     def AddToggleTool(self, tool_id, bitmap, disabled_bitmap, toggle=False, client_data=None, short_help_string="", long_help_string=""):
1725         """
1726         Adds a toggle tool to the toolbar. 
1727
1728         :param `tool_id`: an integer by which the tool may be identified in subsequent operations;
1729         :param `bitmap`: the primary tool bitmap;
1730         :param `disabled_bitmap`: the bitmap to use when the tool is disabled. If it is equal to
1731          `wx.NullBitmap`, the disabled bitmap is automatically generated by greing the normal one;
1732         :param `client_data`: whatever Python object to associate with the toolbar item;
1733         :param `short_help_string`: this string is used for the tools tooltip;
1734         :param `long_help_string`: this string is shown in the statusbar (if any) of the parent
1735          frame when the mouse pointer is inside the tool.
1736         """
1737
1738         kind = (toggle and [ITEM_CHECK] or [ITEM_NORMAL])[0]
1739         return self.AddTool(tool_id, "", bitmap, disabled_bitmap, kind, short_help_string, long_help_string, client_data)
1740
1741
1742     def AddTool(self, tool_id, label, bitmap, disabled_bitmap, kind, short_help_string, long_help_string, client_data):
1743         """
1744         Adds a tool to the toolbar. This is the full feature version of L{AddTool}.
1745
1746         :param `tool_id`: an integer by which the tool may be identified in subsequent operations;
1747         :param `label`: the toolbar tool label;
1748         :param `bitmap`: the primary tool bitmap;
1749         :param `disabled_bitmap`: the bitmap to use when the tool is disabled. If it is equal to
1750          `wx.NullBitmap`, the disabled bitmap is automatically generated by greing the normal one;
1751         :param `kind`: the item kind. Can be one of the following:
1752
1753          ========================  =============================
1754          Item Kind                 Description
1755          ========================  =============================
1756          ``ITEM_CONTROL``          The item in the `AuiToolBar` is a control
1757          ``ITEM_LABEL``            The item in the `AuiToolBar` is a text label
1758          ``ITEM_SPACER``           The item in the `AuiToolBar` is a spacer
1759          ``ITEM_SEPARATOR``        The item in the `AuiToolBar` is a separator
1760          ``ITEM_CHECK``            The item in the `AuiToolBar` is a toolbar check item
1761          ``ITEM_NORMAL``           The item in the `AuiToolBar` is a standard toolbar item
1762          ``ITEM_RADIO``            The item in the `AuiToolBar` is a toolbar radio item
1763          ========================  =============================
1764
1765         :param `short_help_string`: this string is used for the tools tooltip;
1766         :param `long_help_string`: this string is shown in the statusbar (if any) of the parent
1767          frame when the mouse pointer is inside the tool.
1768         :param `client_data`: whatever Python object to associate with the toolbar item.
1769         """
1770         
1771         item = AuiToolBarItem()
1772         item.window = None
1773         item.label = label
1774         item.bitmap = bitmap
1775         item.disabled_bitmap = disabled_bitmap
1776         item.short_help = short_help_string
1777         item.long_help = long_help_string
1778         item.active = True
1779         item.dropdown = False
1780         item.spacer_pixels = 0
1781
1782         if tool_id == wx.ID_ANY:
1783             tool_id = wx.NewId()
1784             
1785         item.id = tool_id
1786         item.state = 0
1787         item.proportion = 0
1788         item.kind = kind
1789         item.sizer_item = None
1790         item.min_size = wx.Size(-1, -1)
1791         item.user_data = 0
1792         item.sticky = False
1793         item.orientation = self._tool_orientation
1794
1795         if not item.disabled_bitmap.IsOk():
1796             # no disabled bitmap specified, we need to make one
1797             if item.bitmap.IsOk():
1798                 item.disabled_bitmap = MakeDisabledBitmap(item.bitmap)
1799         
1800         self._items.append(item)
1801         return self._items[-1]
1802
1803
1804     def AddCheckTool(self, tool_id, label, bitmap, disabled_bitmap, short_help_string="", long_help_string="", client_data=None):
1805         """
1806         Adds a new check (or toggle) tool to the L{AuiToolBar}.
1807         
1808         :see: L{AddTool}.
1809         """
1810
1811         return self.AddTool(tool_id, label, bitmap, disabled_bitmap, ITEM_CHECK, short_help_string, long_help_string, client_data) 
1812
1813
1814     def AddRadioTool(self, tool_id, label, bitmap, disabled_bitmap, short_help_string="", long_help_string="", client_data=None):
1815         """
1816         Adds a new radio tool to the toolbar.
1817
1818         Consecutive radio tools form a radio group such that exactly one button
1819         in the group is pressed at any moment, in other words whenever a button
1820         in the group is pressed the previously pressed button is automatically
1821         released. You should avoid having the radio groups of only one element
1822         as it would be impossible for the user to use such button.
1823
1824         :note: By default, the first button in the radio group is initially pressed,
1825          the others are not.
1826
1827         :see: L{AddTool}.
1828         """
1829
1830         return self.AddTool(tool_id, label, bitmap, disabled_bitmap, ITEM_RADIO, short_help_string, long_help_string, client_data)
1831
1832     
1833     def AddControl(self, control, label=""):
1834         """
1835         Adds any control to the toolbar, typically e.g. a combobox.
1836
1837         :param `control`: the control to be added;
1838         :param `label`: the label which appears if the control goes into the
1839          overflow items in the toolbar.
1840         """
1841
1842         item = AuiToolBarItem()
1843         item.window = control
1844         item.label = label
1845         item.bitmap = wx.NullBitmap
1846         item.disabled_bitmap = wx.NullBitmap
1847         item.active = True
1848         item.dropdown = False
1849         item.spacer_pixels = 0
1850         item.id = control.GetId()
1851         item.state = 0
1852         item.proportion = 0
1853         item.kind = ITEM_CONTROL
1854         item.sizer_item = None
1855         item.min_size = control.GetEffectiveMinSize()
1856         item.user_data = 0
1857         item.sticky = False
1858         item.orientation = self._tool_orientation
1859
1860         self._items.append(item)
1861         return self._items[-1]
1862
1863
1864     def AddLabel(self, tool_id, label="", width=0):
1865         """
1866         Adds a label tool to the L{AuiToolBar}.
1867
1868         :param `tool_id`: an integer by which the tool may be identified in subsequent operations;
1869         :param `label`: the toolbar tool label;
1870         :param `width`: the tool width.
1871         """
1872
1873         min_size = wx.Size(-1, -1)
1874         
1875         if width != -1:
1876             min_size.x = width
1877
1878         item = AuiToolBarItem()
1879         item.window = None
1880         item.label = label
1881         item.bitmap = wx.NullBitmap
1882         item.disabled_bitmap = wx.NullBitmap
1883         item.active = True
1884         item.dropdown = False
1885         item.spacer_pixels = 0
1886
1887         if tool_id == wx.ID_ANY:
1888             tool_id = wx.NewId()
1889         
1890         item.id = tool_id
1891         item.state = 0
1892         item.proportion = 0
1893         item.kind = ITEM_LABEL
1894         item.sizer_item = None
1895         item.min_size = min_size
1896         item.user_data = 0
1897         item.sticky = False
1898         item.orientation = self._tool_orientation
1899
1900         self._items.append(item)
1901         return self._items[-1]
1902
1903
1904     def AddSeparator(self):
1905         """ Adds a separator for spacing groups of tools. """
1906         
1907         item = AuiToolBarItem()
1908         item.window = None
1909         item.label = ""
1910         item.bitmap = wx.NullBitmap
1911         item.disabled_bitmap = wx.NullBitmap
1912         item.active = True
1913         item.dropdown = False
1914         item.id = -1
1915         item.state = 0
1916         item.proportion = 0
1917         item.kind = ITEM_SEPARATOR
1918         item.sizer_item = None
1919         item.min_size = wx.Size(-1, -1)
1920         item.user_data = 0
1921         item.sticky = False
1922         item.orientation = self._tool_orientation
1923
1924         self._items.append(item)
1925         return self._items[-1]
1926
1927
1928     def AddSpacer(self, pixels):
1929         """
1930         Adds a spacer for spacing groups of tools.
1931
1932         :param `pixels`: the width of the spacer.
1933         """
1934
1935         item = AuiToolBarItem()
1936         item.window = None
1937         item.label = ""
1938         item.bitmap = wx.NullBitmap
1939         item.disabled_bitmap = wx.NullBitmap
1940         item.active = True
1941         item.dropdown = False
1942         item.spacer_pixels = pixels
1943         item.id = -1
1944         item.state = 0
1945         item.proportion = 0
1946         item.kind = ITEM_SPACER
1947         item.sizer_item = None
1948         item.min_size = wx.Size(-1, -1)
1949         item.user_data = 0
1950         item.sticky = False
1951         item.orientation = self._tool_orientation
1952
1953         self._items.append(item)
1954         return self._items[-1]
1955
1956
1957     def AddStretchSpacer(self, proportion=1):
1958         """
1959         Adds a stretchable spacer for spacing groups of tools.
1960
1961         :param `proportion`: the stretchable spacer proportion.
1962         """
1963         
1964         item = AuiToolBarItem()
1965         item.window = None
1966         item.label = ""
1967         item.bitmap = wx.NullBitmap
1968         item.disabled_bitmap = wx.NullBitmap
1969         item.active = True
1970         item.dropdown = False
1971         item.spacer_pixels = 0
1972         item.id = -1
1973         item.state = 0
1974         item.proportion = proportion
1975         item.kind = ITEM_SPACER
1976         item.sizer_item = None
1977         item.min_size = wx.Size(-1, -1)
1978         item.user_data = 0
1979         item.sticky = False
1980         item.orientation = self._tool_orientation
1981
1982         self._items.append(item)
1983         return self._items[-1]
1984
1985
1986     def Clear(self):
1987         """ Deletes all the tools in the L{AuiToolBar}. """
1988
1989         self._items = []
1990         self._sizer_element_count = 0
1991
1992
1993     def ClearTools(self):
1994         """ Deletes all the tools in the L{AuiToolBar}. """
1995
1996         self.Clear()
1997         
1998
1999     def DeleteTool(self, tool_id):
2000         """
2001         Removes the specified tool from the toolbar and deletes it.
2002
2003         :param `tool_id`: the L{AuiToolBarItem} identifier.
2004
2005         :returns: ``True`` if the tool was deleted, ``False`` otherwise.
2006         
2007         :note: Note that it is unnecessary to call L{Realize} for the change to
2008          take place, it will happen immediately.
2009         """
2010
2011         idx = self.GetToolIndex(tool_id)
2012         
2013         if idx >= 0 and idx < len(self._items):
2014             self._items.pop(idx)
2015             self.Realize()
2016             return True
2017         
2018         return False
2019
2020
2021     def DeleteToolByPos(self, pos):
2022         """
2023         This function behaves like L{DeleteTool} but it deletes the tool at the
2024         specified position and not the one with the given id.
2025
2026         :param `pos`: the tool position.
2027
2028         :see: L{DeleteTool}        
2029         """
2030         
2031         if pos >= 0 and pos < len(self._items):
2032             
2033             self._items.pop(pos)
2034             self.Realize()
2035             return True
2036
2037         return False
2038
2039
2040     def FindControl(self, id):
2041         """
2042         Returns a pointer to the control identified by `id` or ``None`` if no corresponding
2043         control is found.
2044
2045         :param `id`: the control identifier.        
2046         """
2047         
2048         wnd = self.FindWindow(id)
2049         return wnd
2050
2051
2052     def FindTool(self, tool_id):
2053         """
2054         Finds a tool for the given tool id.
2055
2056         :param `tool_id`: the L{AuiToolBarItem} identifier.
2057         """
2058         
2059         for item in self._items:
2060             if item.id == tool_id:
2061                 return item
2062     
2063         return None
2064
2065
2066     def FindToolForPosition(self, x, y):
2067         """
2068         Finds a tool for the given mouse position.
2069
2070         :param `x`: mouse `x` position;
2071         :param `y`: mouse `y` position.
2072
2073         :returns: a pointer to a L{AuiToolBarItem} if a tool is found, or ``None`` otherwise.
2074         """
2075
2076         for i, item in enumerate(self._items):
2077             if not item.sizer_item:
2078                 continue
2079
2080             rect = item.sizer_item.GetRect()
2081             if rect.Contains((x,y)):
2082             
2083                 # if the item doesn't fit on the toolbar, return None
2084                 if not self.GetToolFitsByIndex(i):
2085                     return None
2086
2087                 return item
2088             
2089         return None
2090
2091
2092     def FindToolForPositionWithPacking(self, x, y):
2093         """
2094         Finds a tool for the given mouse position, taking into account also the
2095         tool packing.
2096
2097         :param `x`: mouse `x` position;
2098         :param `y`: mouse `y` position.
2099
2100         :returns: a pointer to a L{AuiToolBarItem} if a tool is found, or ``None`` otherwise.
2101         """
2102         
2103         count = len(self._items)
2104         
2105         for i, item in enumerate(self._items):
2106             if not item.sizer_item:
2107                 continue
2108
2109             rect = item.sizer_item.GetRect()
2110
2111             # apply tool packing
2112             if i+1 < count:
2113                 rect.width += self._tool_packing
2114
2115             if rect.Contains((x,y)):
2116             
2117                 # if the item doesn't fit on the toolbar, return None
2118                 if not self.GetToolFitsByIndex(i):
2119                     return None
2120
2121                 return item
2122
2123         return None
2124
2125
2126     def FindToolByIndex(self, pos):
2127         """
2128         Finds a tool for the given tool position in the L{AuiToolBar}.
2129
2130         :param `pos`: the tool position in the toolbar.
2131
2132         :returns: a pointer to a L{AuiToolBarItem} if a tool is found, or ``None`` otherwise.        
2133         """
2134         
2135         if pos < 0 or pos >= len(self._items):
2136             return None
2137
2138         return self._items[pos]
2139
2140
2141     def SetToolBitmapSize(self, size):
2142         """
2143         Sets the default size of each tool bitmap. The default bitmap size is
2144         16 by 15 pixels.
2145
2146         :param `size`: the size of the bitmaps in the toolbar.
2147
2148         :note: This should be called to tell the toolbar what the tool bitmap
2149          size is. Call it before you add tools.
2150
2151         :note: Note that this is the size of the bitmap you pass to L{AddTool},
2152          and not the eventual size of the tool button.
2153
2154         :todo: Add `wx.ToolBar` compatibility, actually implementing this method.
2155         """
2156
2157         # TODO: wx.ToolBar compatibility
2158         pass
2159
2160
2161     def GetToolBitmapSize(self):
2162         """
2163         Returns the size of bitmap that the toolbar expects to have. The default
2164         bitmap size is 16 by 15 pixels.
2165
2166         :note: Note that this is the size of the bitmap you pass to L{AddTool},
2167          and not the eventual size of the tool button.
2168
2169         :todo: Add `wx.ToolBar` compatibility, actually implementing this method.
2170         """
2171         
2172         # TODO: wx.ToolBar compatibility
2173         return wx.Size(16, 15)
2174
2175
2176     def SetToolProportion(self, tool_id, proportion):
2177         """
2178         Sets the tool proportion in the toolbar.
2179
2180         :param `tool_id`: the L{AuiToolBarItem} identifier;
2181         :param `proportion`: the tool proportion in the toolbar.
2182         """
2183
2184         item = self.FindTool(tool_id)
2185         if not item:
2186             return
2187
2188         item.proportion = proportion
2189
2190
2191     def GetToolProportion(self, tool_id):
2192         """
2193         Returns the tool proportion in the toolbar.
2194
2195         :param `tool_id`: the L{AuiToolBarItem} identifier.
2196         """
2197
2198         item = self.FindTool(tool_id)
2199         if not item:
2200             return
2201
2202         return item.proportion
2203
2204
2205     def SetToolSeparation(self, separation):
2206         """
2207         Sets the separator size for the toolbar.
2208
2209         :param `separation`: the separator size in pixels.
2210         """
2211
2212         if self._art:
2213             self._art.SetElementSize(AUI_TBART_SEPARATOR_SIZE, separation)
2214
2215
2216     def GetToolSeparation(self):
2217         """ Returns the separator size for the toolbar, in pixels. """
2218         
2219         if self._art:
2220             return self._art.GetElementSize(AUI_TBART_SEPARATOR_SIZE)
2221
2222         return 5
2223
2224
2225     def SetToolDropDown(self, tool_id, dropdown):
2226         """
2227         Assigns a drop down window menu to the toolbar item.
2228
2229         :param `tool_id`: the L{AuiToolBarItem} identifier;
2230         :param `dropdown`: whether to assign a drop down menu or not.
2231         """
2232
2233         item = self.FindTool(tool_id)
2234         if not item:
2235             return
2236
2237         item.dropdown = dropdown
2238
2239
2240     def GetToolDropDown(self, tool_id):
2241         """
2242         Returns whether the toolbar item identified by `tool_id` has an associated
2243         drop down window menu or not.
2244
2245         :param `tool_id`: the L{AuiToolBarItem} identifier.
2246         """
2247
2248         item = self.FindTool(tool_id)
2249         if not item:
2250             return
2251
2252         return item.dropdown
2253
2254
2255     def SetToolSticky(self, tool_id, sticky):
2256         """
2257         Sets the toolbar item as sticky or non-sticky.
2258
2259         :param `tool_id`: the L{AuiToolBarItem} identifier;
2260         :param `sticky`: whether the tool should be sticky or not.
2261         """
2262
2263         # ignore separators
2264         if tool_id == -1:
2265             return
2266
2267         item = self.FindTool(tool_id)
2268         if not item:
2269             return
2270
2271         if item.sticky == sticky:
2272             return
2273
2274         item.sticky = sticky
2275
2276         self.Refresh(False)
2277         self.Update()
2278
2279
2280     def GetToolSticky(self, tool_id):
2281         """
2282         Returns whether the toolbar item identified by `tool_id` has a sticky
2283         behaviour or not.
2284
2285         :param `tool_id`: the L{AuiToolBarItem} identifier.
2286         """
2287
2288         item = self.FindTool(tool_id)
2289         if not item:
2290             return
2291
2292         return item.sticky
2293
2294
2295     def SetToolBorderPadding(self, padding):
2296         """
2297         Sets the padding between the tool border and the label.
2298
2299         :param `padding`: the padding in pixels.
2300         """
2301
2302         self._tool_border_padding = padding
2303
2304
2305     def GetToolBorderPadding(self):
2306         """ Returns the padding between the tool border and the label, in pixels. """
2307
2308         return self._tool_border_padding
2309
2310
2311     def SetToolTextOrientation(self, orientation):
2312         """
2313         Sets the label orientation for the toolbar items.
2314
2315         :param `orientation`: the L{AuiToolBarItem} label orientation.
2316         """
2317
2318         self._tool_text_orientation = orientation
2319
2320         if self._art:
2321             self._art.SetTextOrientation(orientation)
2322     
2323
2324     def GetToolTextOrientation(self):
2325         """ Returns the label orientation for the toolbar items. """
2326
2327         return self._tool_text_orientation
2328
2329
2330     def SetToolOrientation(self, orientation):
2331         """
2332         Sets the tool orientation for the toolbar items.
2333
2334         :param `orientation`: the L{AuiToolBarItem} orientation.
2335         """
2336
2337         self._tool_orientation = orientation
2338         if self._art:
2339             self._art.SetOrientation(orientation)
2340
2341
2342     def GetToolOrientation(self):
2343         """ Returns the orientation for the toolbar items. """
2344
2345         return self._tool_orientation        
2346
2347
2348     def SetToolPacking(self, packing):
2349         """
2350         Sets the value used for spacing tools. The default value is 1 pixel.
2351
2352         :param `packing`: the value for packing.
2353         """
2354
2355         self._tool_packing = packing
2356
2357
2358     def GetToolPacking(self):
2359         """ Returns the value used for spacing tools. The default value is 1 pixel. """
2360
2361         return self._tool_packing
2362
2363
2364     def SetOrientation(self, orientation):
2365         """
2366         Sets the toolbar orientation.
2367
2368         :param `orientation`: either ``wx.VERTICAL`` or ``wx.HORIZONTAL``.
2369
2370         :note: This can be temporarily overridden by L{AuiManager} when floating and
2371          docking a L{AuiToolBar}.
2372         """
2373
2374         pass
2375     
2376
2377     def SetMargins(self, left=-1, right=-1, top=-1, bottom=-1):
2378         """
2379         Set the values to be used as margins for the toolbar.
2380
2381         :param `left`: the left toolbar margin;
2382         :param `right`: the right toolbar margin;
2383         :param `top`: the top toolbar margin;
2384         :param `bottom`: the bottom toolbar margin.
2385         """
2386
2387         if left != -1:
2388             self._left_padding = left
2389         if right != -1:
2390             self._right_padding = right
2391         if top != -1:
2392             self._top_padding = top
2393         if bottom != -1:
2394             self._bottom_padding = bottom
2395
2396
2397     def SetMarginsSize(self, size):
2398         """
2399         Set the values to be used as margins for the toolbar.
2400
2401         :param `size`: the margin size (an instance of `wx.Size`).
2402         """
2403         
2404         self.SetMargins(size.x, size.x, size.y, size.y)
2405
2406
2407     def SetMarginsXY(self, x, y):
2408         """
2409         Set the values to be used as margins for the toolbar.
2410         
2411         :param `x`: left margin, right margin and inter-tool separation value;
2412         :param `y`: top margin, bottom margin and inter-tool separation value.
2413         """
2414         
2415         self.SetMargins(x, x, y, y)        
2416
2417             
2418     def GetGripperVisible(self):
2419         """ Returns whether the toolbar gripper is visible or not. """
2420
2421         return self._gripper_visible
2422
2423
2424     def SetGripperVisible(self, visible):
2425         """
2426         Sets whether the toolbar gripper is visible or not.
2427
2428         :param `visible`: ``True`` for a visible gripper, ``False`` otherwise.
2429         """
2430
2431         self._gripper_visible = visible
2432         if visible:
2433             self._agwStyle |= AUI_TB_GRIPPER
2434         else:
2435             self._agwStyle &= ~AUI_TB_GRIPPER
2436             
2437         self.Realize()
2438         self.Refresh(False)
2439
2440
2441     def GetOverflowVisible(self):
2442         """ Returns whether the overflow button is visible or not. """
2443
2444         return self._overflow_visible
2445
2446
2447     def SetOverflowVisible(self, visible):
2448         """
2449         Sets whether the overflow button is visible or not.
2450
2451         :param `visible`: ``True`` for a visible overflow button, ``False`` otherwise.
2452         """
2453
2454         self._overflow_visible = visible
2455         if visible:
2456             self._agwStyle |= AUI_TB_OVERFLOW
2457         else:
2458             self._agwStyle &= ~AUI_TB_OVERFLOW
2459
2460         self.Refresh(False)
2461
2462
2463     def SetFont(self, font):
2464         """
2465         Sets the L{AuiToolBar} font.
2466
2467         :param `font`: a `wx.Font` object.
2468
2469         :note: Overridden from `wx.PyControl`.
2470         """        
2471
2472         res = wx.PyControl.SetFont(self, font)
2473
2474         if self._art:
2475             self._art.SetFont(font)
2476     
2477         return res
2478
2479
2480     def SetHoverItem(self, pitem):
2481         """
2482         Sets a toolbar item to be currently hovered by the mouse.
2483
2484         :param `pitem`: an instance of L{AuiToolBarItem}.
2485         """
2486
2487         former_hover = None
2488
2489         for item in self._items:
2490         
2491             if item.state & AUI_BUTTON_STATE_HOVER:
2492                 former_hover = item
2493                 
2494             item.state &= ~AUI_BUTTON_STATE_HOVER
2495
2496         if pitem:
2497             pitem.state |= AUI_BUTTON_STATE_HOVER
2498         
2499         if former_hover != pitem:
2500             self.Refresh(False)
2501             self.Update()
2502         
2503
2504     def SetPressedItem(self, pitem):
2505         """
2506         Sets a toolbar item to be currently in a "pressed" state.
2507
2508         :param `pitem`: an instance of L{AuiToolBarItem}.
2509         """
2510
2511         former_item = None
2512
2513         for item in self._items:
2514         
2515             if item.state & AUI_BUTTON_STATE_PRESSED:
2516                 former_item = item
2517                 
2518             item.state &= ~AUI_BUTTON_STATE_PRESSED
2519         
2520         if pitem:
2521             pitem.state &= ~AUI_BUTTON_STATE_HOVER
2522             pitem.state |= AUI_BUTTON_STATE_PRESSED
2523         
2524         if former_item != pitem:
2525             self.Refresh(False)
2526             self.Update()
2527     
2528
2529     def RefreshOverflowState(self):
2530         """ Refreshes the overflow button. """
2531
2532         if not self._overflow_sizer_item:
2533             self._overflow_state = 0
2534             return
2535         
2536         overflow_state = 0
2537         overflow_rect = self.GetOverflowRect()
2538
2539         # find out the mouse's current position
2540         pt = wx.GetMousePosition()
2541         pt = self.ScreenToClient(pt)
2542
2543         # find out if the mouse cursor is inside the dropdown rectangle
2544         if overflow_rect.Contains((pt.x, pt.y)):
2545
2546             if _VERSION_STRING < "2.9":
2547                 leftDown = wx.GetMouseState().LeftDown()
2548             else:
2549                 leftDown = wx.GetMouseState().LeftIsDown()
2550         
2551             if leftDown:
2552                 overflow_state = AUI_BUTTON_STATE_PRESSED
2553             else:
2554                 overflow_state = AUI_BUTTON_STATE_HOVER
2555         
2556         if overflow_state != self._overflow_state:
2557             self._overflow_state = overflow_state
2558             self.Refresh(False)
2559             self.Update()
2560         
2561         self._overflow_state = overflow_state
2562
2563
2564     def ToggleTool(self, tool_id, state):
2565         """
2566         Toggles a tool on or off. This does not cause any event to get emitted.
2567
2568         :param `tool_id`: tool in question.
2569         :param `state`: if ``True``, toggles the tool on, otherwise toggles it off.
2570
2571         :note: This only applies to a tool that has been specified as a toggle tool.
2572         """
2573         
2574         tool = self.FindTool(tool_id)
2575
2576         if tool:
2577             if tool.kind not in [ITEM_CHECK, ITEM_RADIO]:
2578                 return
2579
2580             if tool.kind == ITEM_RADIO:
2581                 idx = self.GetToolIndex(tool_id)
2582                 if idx >= 0 and idx < len(self._items):
2583                     for i in xrange(idx, len(self._items)):
2584                         tool = self.FindToolByIndex(i)
2585                         if tool.kind != ITEM_RADIO:
2586                             break
2587                         tool.state &= ~AUI_BUTTON_STATE_CHECKED
2588
2589                     for i in xrange(idx, -1, -1):
2590                         tool = self.FindToolByIndex(i)
2591                         if tool.kind != ITEM_RADIO:
2592                             break
2593                         tool.state &= ~AUI_BUTTON_STATE_CHECKED 
2594
2595                     tool = self.FindTool(tool_id)
2596                     tool.state |= AUI_BUTTON_STATE_CHECKED
2597             else:
2598                 if state == True:
2599                     tool.state |= AUI_BUTTON_STATE_CHECKED
2600                 else:
2601                     tool.state &= ~AUI_BUTTON_STATE_CHECKED 
2602
2603
2604     def GetToolToggled(self, tool_id):
2605         """
2606         Returns whether a tool is toggled or not.
2607
2608         :param `tool_id`: the toolbar item identifier.
2609
2610         :note: This only applies to a tool that has been specified as a toggle tool.
2611         """        
2612
2613         tool = self.FindTool(tool_id)
2614
2615         if tool:
2616             if tool.kind not in [ITEM_CHECK, ITEM_RADIO]:
2617                 return False
2618
2619             return (tool.state & AUI_BUTTON_STATE_CHECKED and [True] or [False])[0]
2620         
2621         return False
2622
2623
2624     def EnableTool(self, tool_id, state):
2625         """
2626         Enables or disables the tool.
2627
2628         :param `tool_id`: identifier for the tool to enable or disable.
2629         :param `state`: if ``True``, enables the tool, otherwise disables it.
2630         """
2631
2632         tool = self.FindTool(tool_id)
2633
2634         if tool:
2635         
2636             if state == True:
2637                 tool.state &= ~AUI_BUTTON_STATE_DISABLED
2638             else:
2639                 tool.state |= AUI_BUTTON_STATE_DISABLED
2640         
2641
2642     def GetToolEnabled(self, tool_id):
2643         """
2644         Returns whether the tool identified by `tool_id` is enabled or not.
2645
2646         :param `tool_id`: the tool identifier.
2647         """
2648
2649         tool = self.FindTool(tool_id)
2650
2651         if tool:
2652             return (tool.state & AUI_BUTTON_STATE_DISABLED and [False] or [True])[0]
2653
2654         return False
2655
2656
2657     def GetToolLabel(self, tool_id):
2658         """
2659         Returns the tool label for the tool identified by `tool_id`.
2660
2661         :param `tool_id`: the tool identifier.
2662         """
2663
2664         tool = self.FindTool(tool_id)
2665         if not tool:
2666             return ""
2667         
2668         return tool.label
2669
2670
2671     def SetToolLabel(self, tool_id, label):
2672         """
2673         Sets the tool label for the tool identified by `tool_id`.
2674
2675         :param `tool_id`: the tool identifier;
2676         :param `label`: the new toolbar item label.
2677         """
2678         
2679         tool = self.FindTool(tool_id)
2680         if tool:    
2681             tool.label = label
2682     
2683
2684     def GetToolBitmap(self, tool_id):
2685         """
2686         Returns the tool bitmap for the tool identified by `tool_id`.
2687
2688         :param `tool_id`: the tool identifier.
2689         """
2690         
2691         tool = self.FindTool(tool_id)
2692         if not tool:
2693             return wx.NullBitmap
2694
2695         return tool.bitmap
2696
2697
2698     def SetToolBitmap(self, tool_id, bitmap):
2699         """
2700         Sets the tool bitmap for the tool identified by `tool_id`.
2701
2702         :param `tool_id`: the tool identifier;
2703         :param `bitmap`: the new bitmap for the toolbar item (an instance of `wx.Bitmap`).
2704         """
2705         
2706         tool = self.FindTool(tool_id)
2707         if tool:
2708             tool.bitmap = bitmap
2709
2710
2711     def SetToolNormalBitmap(self, tool_id, bitmap):
2712         """
2713         Sets the tool bitmap for the tool identified by `tool_id`.
2714
2715         :param `tool_id`: the tool identifier;
2716         :param `bitmap`: the new bitmap for the toolbar item (an instance of `wx.Bitmap`).
2717         """
2718         
2719         self.SetToolBitmap(tool_id, bitmap)
2720
2721
2722     def SetToolDisabledBitmap(self, tool_id, bitmap):
2723         """
2724         Sets the tool disabled bitmap for the tool identified by `tool_id`.
2725
2726         :param `tool_id`: the tool identifier;
2727         :param `bitmap`: the new disabled bitmap for the toolbar item (an instance of `wx.Bitmap`).
2728         """
2729         
2730         tool = self.FindTool(tool_id)
2731         if tool:
2732             tool.disabled_bitmap = bitmap
2733
2734
2735     def GetToolShortHelp(self, tool_id):
2736         """
2737         Returns the short help for the given tool.
2738
2739         :param `tool_id`: the tool identifier.
2740         """
2741
2742         tool = self.FindTool(tool_id)
2743         if not tool:
2744             return ""
2745
2746         return tool.short_help
2747
2748
2749     def SetToolShortHelp(self, tool_id, help_string):
2750         """
2751         Sets the short help for the given tool.
2752
2753         :param `tool_id`: the tool identifier;
2754         :param `help_string`: the string for the short help.
2755         """
2756         
2757         tool = self.FindTool(tool_id)
2758         if tool:
2759             tool.short_help = help_string
2760
2761
2762     def GetToolLongHelp(self, tool_id):
2763         """
2764         Returns the long help for the given tool.
2765
2766         :param `tool_id`: the tool identifier.
2767         """
2768
2769         tool = self.FindTool(tool_id)
2770         if not tool:
2771             return ""
2772
2773         return tool.long_help
2774
2775
2776     def SetToolAlignment(self, alignment=wx.EXPAND):
2777         """
2778         This sets the alignment for all of the tools within the
2779         toolbar (only has an effect when the toolbar is expanded).
2780
2781         :param `alignment`: `wx.Sizer` alignment value
2782          (``wx.ALIGN_CENTER_HORIZONTAL`` or ``wx.ALIGN_CENTER_VERTICAL``).
2783         """
2784
2785         self._tool_alignment = alignment
2786
2787
2788
2789     def SetToolLongHelp(self, tool_id, help_string):
2790         """
2791         Sets the long help for the given tool.
2792
2793         :param `tool_id`: the tool identifier;
2794         :param `help_string`: the string for the long help.
2795         """
2796         
2797         tool = self.FindTool(tool_id)
2798         if tool:
2799             tool.long_help = help_string
2800     
2801
2802     def SetCustomOverflowItems(self, prepend, append):
2803         """
2804         Sets the two lists `prepend` and `append` as custom overflow items.
2805
2806         :param `prepend`: a list of L{AuiToolBarItem} to be prepended;
2807         :param `append`: a list of L{AuiToolBarItem} to be appended.
2808         """
2809
2810         self._custom_overflow_prepend = prepend
2811         self._custom_overflow_append = append
2812
2813
2814     def GetToolCount(self):
2815         """ Returns the number of tools in the L{AuiToolBar}. """
2816
2817         return len(self._items)
2818
2819
2820     def GetToolIndex(self, tool_id):
2821         """
2822         Returns the position of the tool in the toolbar given its identifier.
2823
2824         :param `tool_id`: the toolbar item identifier.
2825         """
2826
2827         # this will prevent us from returning the index of the
2828         # first separator in the toolbar since its id is equal to -1
2829         if tool_id == -1:
2830             return wx.NOT_FOUND
2831
2832         for i, item in enumerate(self._items):
2833             if item.id == tool_id:
2834                 return i
2835         
2836         return wx.NOT_FOUND
2837
2838
2839     def GetToolPos(self, tool_id):
2840         """
2841         Returns the position of the tool in the toolbar given its identifier.
2842
2843         :param `tool_id`: the toolbar item identifier.
2844         """
2845         
2846         return self.GetToolIndex(tool_id)
2847                                 
2848
2849     def GetToolFitsByIndex(self, tool_id):
2850         """
2851         Returns whether the tool identified by `tool_id` fits into the toolbar or not.
2852
2853         :param `tool_id`: the toolbar item identifier.
2854         """
2855         
2856         if tool_id < 0 or tool_id >= len(self._items):
2857             return False
2858
2859         if not self._items[tool_id].sizer_item:
2860             return False
2861
2862         cli_w, cli_h = self.GetClientSize()
2863         rect = self._items[tool_id].sizer_item.GetRect()
2864
2865         if self._agwStyle & AUI_TB_VERTICAL:
2866             # take the dropdown size into account
2867             if self._overflow_visible:
2868                 cli_h -= self._overflow_sizer_item.GetSize().y
2869
2870             if rect.y+rect.height < cli_h:
2871                 return True
2872         
2873         else:
2874         
2875             # take the dropdown size into account
2876             if self._overflow_visible:
2877                 cli_w -= self._overflow_sizer_item.GetSize().x
2878
2879             if rect.x+rect.width < cli_w:
2880                 return True
2881         
2882         return False
2883
2884
2885     def GetToolFits(self, tool_id):
2886         """
2887         Returns whether the tool identified by `tool_id` fits into the toolbar or not.
2888
2889         :param `tool_id`: the toolbar item identifier.
2890         """
2891         
2892         return self.GetToolFitsByIndex(self.GetToolIndex(tool_id))
2893
2894
2895     def GetToolRect(self, tool_id):
2896         """
2897         Returns the toolbar item rectangle
2898
2899         :param `tool_id`: the toolbar item identifier.
2900         """
2901
2902         tool = self.FindTool(tool_id)
2903         if tool and tool.sizer_item:
2904             return tool.sizer_item.GetRect()
2905
2906         return wx.Rect()
2907
2908
2909     def GetToolBarFits(self):
2910         """ Returns whether the L{AuiToolBar} size fits in a specified size. """
2911
2912         if len(self._items) == 0:
2913             # empty toolbar always 'fits'
2914             return True
2915         
2916         # entire toolbar content fits if the last tool fits
2917         return self.GetToolFitsByIndex(len(self._items) - 1)
2918
2919
2920     def Realize(self):
2921         """ Realizes the toolbar. This function should be called after you have added tools. """
2922
2923         dc = wx.ClientDC(self)
2924         
2925         if not dc.IsOk():
2926             return False
2927
2928         horizontal = True
2929         if self._agwStyle & AUI_TB_VERTICAL:
2930             horizontal = False
2931
2932         # create the new sizer to add toolbar elements to
2933         sizer = wx.BoxSizer((horizontal and [wx.HORIZONTAL] or [wx.VERTICAL])[0])
2934
2935         # add gripper area
2936         separator_size = self._art.GetElementSize(AUI_TBART_SEPARATOR_SIZE)
2937         gripper_size = self._art.GetElementSize(AUI_TBART_GRIPPER_SIZE)
2938         
2939         if gripper_size > 0 and self._gripper_visible:        
2940             if horizontal:
2941                 self._gripper_sizer_item = sizer.Add((gripper_size, 1), 0, wx.EXPAND)
2942             else:
2943                 self._gripper_sizer_item = sizer.Add((1, gripper_size), 0, wx.EXPAND)
2944         else:
2945             self._gripper_sizer_item = None
2946         
2947         # add "left" padding
2948         if self._left_padding > 0:
2949             if horizontal:
2950                 sizer.Add((self._left_padding, 1))
2951             else:
2952                 sizer.Add((1, self._left_padding))
2953         
2954         count = len(self._items)
2955         for i, item in enumerate(self._items):
2956         
2957             sizer_item = None
2958             kind = item.kind
2959
2960             if kind == ITEM_LABEL:
2961                 
2962                 size = self._art.GetLabelSize(dc, self, item)
2963                 sizer_item = sizer.Add((size.x + (self._tool_border_padding*2),
2964                                         size.y + (self._tool_border_padding*2)),
2965                                        item.proportion,
2966                                        item.alignment)
2967                 if i+1 < count:
2968                     sizer.AddSpacer(self._tool_packing)
2969                 
2970
2971             elif kind in [ITEM_CHECK, ITEM_NORMAL, ITEM_RADIO]:
2972                 
2973                 size = self._art.GetToolSize(dc, self, item)
2974                 sizer_item = sizer.Add((size.x + (self._tool_border_padding*2),
2975                                         size.y + (self._tool_border_padding*2)),
2976                                        0,
2977                                        item.alignment)
2978                 # add tool packing
2979                 if i+1 < count:
2980                     sizer.AddSpacer(self._tool_packing)
2981
2982             elif kind == ITEM_SEPARATOR:
2983                 
2984                 if horizontal:
2985                     sizer_item = sizer.Add((separator_size, 1), 0, wx.EXPAND)
2986                 else:
2987                     sizer_item = sizer.Add((1, separator_size), 0, wx.EXPAND)
2988
2989                 # add tool packing
2990                 if i+1 < count:
2991                     sizer.AddSpacer(self._tool_packing)
2992
2993             elif kind == ITEM_SPACER:
2994                 
2995                 if item.proportion > 0:
2996                     sizer_item = sizer.AddStretchSpacer(item.proportion)
2997                 else:
2998                     sizer_item = sizer.Add((item.spacer_pixels, 1))
2999                     
3000             elif kind == ITEM_CONTROL:
3001                 
3002                 vert_sizer = wx.BoxSizer(wx.VERTICAL)
3003                 vert_sizer.AddStretchSpacer(1)
3004                 ctrl_sizer_item = vert_sizer.Add(item.window, 0, wx.EXPAND)
3005                 vert_sizer.AddStretchSpacer(1)
3006                 
3007                 if self._agwStyle & AUI_TB_TEXT and \
3008                     self._tool_text_orientation == AUI_TBTOOL_TEXT_BOTTOM and \
3009                     item.GetLabel() != "":
3010                 
3011                     s = self.GetLabelSize(item.GetLabel())
3012                     vert_sizer.Add((1, s.y))
3013
3014                 sizer_item = sizer.Add(vert_sizer, item.proportion, wx.EXPAND)
3015                 min_size = item.min_size
3016
3017                 # proportional items will disappear from the toolbar if
3018                 # their min width is not set to something really small
3019                 if item.proportion != 0:
3020                     min_size.x = 1
3021                 
3022                 if min_size.IsFullySpecified():
3023                     sizer.SetItemMinSize(vert_sizer, min_size)
3024                     vert_sizer.SetItemMinSize(item.window, min_size)
3025                 
3026                 # add tool packing
3027                 if i+1 < count:
3028                     sizer.AddSpacer(self._tool_packing)
3029                 
3030             item.sizer_item = sizer_item
3031         
3032
3033         # add "right" padding
3034         if self._right_padding > 0:
3035             if horizontal:
3036                 sizer.Add((self._right_padding, 1))
3037             else:
3038                 sizer.Add((1, self._right_padding))
3039         
3040         # add drop down area
3041         self._overflow_sizer_item = None
3042
3043         if self._agwStyle & AUI_TB_OVERFLOW:
3044         
3045             overflow_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE)
3046             if overflow_size > 0 and self._overflow_visible:
3047             
3048                 if horizontal:
3049                     self._overflow_sizer_item = sizer.Add((overflow_size, 1), 0, wx.EXPAND)
3050                 else:
3051                     self._overflow_sizer_item = sizer.Add((1, overflow_size), 0, wx.EXPAND)
3052             
3053             else:
3054             
3055                 self._overflow_sizer_item = None
3056             
3057         # the outside sizer helps us apply the "top" and "bottom" padding
3058         outside_sizer = wx.BoxSizer((horizontal and [wx.VERTICAL] or [wx.HORIZONTAL])[0])
3059
3060         # add "top" padding
3061         if self._top_padding > 0:
3062         
3063             if horizontal:
3064                 outside_sizer.Add((1, self._top_padding))
3065             else:
3066                 outside_sizer.Add((self._top_padding, 1))
3067         
3068         # add the sizer that contains all of the toolbar elements
3069         outside_sizer.Add(sizer, 1, self._tool_alignment)
3070
3071         # add "bottom" padding
3072         if self._bottom_padding > 0:
3073         
3074             if horizontal:
3075                 outside_sizer.Add((1, self._bottom_padding))
3076             else:
3077                 outside_sizer.Add((self._bottom_padding, 1))
3078
3079         del self._sizer # remove old sizer
3080         self._sizer = outside_sizer
3081         self.SetSizer(outside_sizer)
3082
3083         # calculate the rock-bottom minimum size
3084         for item in self._items:
3085         
3086             if item.sizer_item and item.proportion > 0 and item.min_size.IsFullySpecified():
3087                 item.sizer_item.SetMinSize((0, 0))
3088         
3089         self._absolute_min_size = self._sizer.GetMinSize()
3090
3091         # reset the min sizes to what they were
3092         for item in self._items:
3093         
3094             if item.sizer_item and item.proportion > 0 and item.min_size.IsFullySpecified():
3095                 item.sizer_item.SetMinSize(item.min_size)
3096         
3097         # set control size
3098         size = self._sizer.GetMinSize()
3099         self.SetMinSize(size)
3100         self._minWidth = size.x
3101         self._minHeight = size.y
3102
3103         if self._agwStyle & AUI_TB_NO_AUTORESIZE == 0:
3104         
3105             cur_size = self.GetClientSize()
3106             new_size = self.GetMinSize()
3107
3108             if new_size != cur_size:
3109             
3110                 self.SetClientSize(new_size)
3111             
3112             else:
3113             
3114                 self._sizer.SetDimension(0, 0, cur_size.x, cur_size.y)
3115             
3116         else:
3117         
3118             cur_size = self.GetClientSize()
3119             self._sizer.SetDimension(0, 0, cur_size.x, cur_size.y)
3120                     
3121         self.Refresh(False)
3122         return True
3123
3124
3125     def GetOverflowState(self):
3126         """ Returns the state of the overflow button. """
3127
3128         return self._overflow_state
3129
3130
3131     def GetOverflowRect(self):
3132         """ Returns the rectangle of the overflow button. """
3133
3134         cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize())
3135         overflow_rect = wx.Rect(*self._overflow_sizer_item.GetRect())
3136         overflow_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE)
3137
3138         if self._agwStyle & AUI_TB_VERTICAL:
3139         
3140             overflow_rect.y = cli_rect.height - overflow_size
3141             overflow_rect.x = 0
3142             overflow_rect.width = cli_rect.width
3143             overflow_rect.height = overflow_size
3144         
3145         else:
3146         
3147             overflow_rect.x = cli_rect.width - overflow_size
3148             overflow_rect.y = 0
3149             overflow_rect.width = overflow_size
3150             overflow_rect.height = cli_rect.height
3151         
3152         return overflow_rect
3153
3154
3155     def GetLabelSize(self, label):
3156         """
3157         Returns the standard size of a toolbar item.
3158
3159         :param `label`: a test label.
3160         """
3161
3162         dc = wx.ClientDC(self)
3163         dc.SetFont(self._font)
3164
3165         return GetLabelSize(dc, label, self._tool_orientation != AUI_TBTOOL_HORIZONTAL)
3166
3167
3168     def GetAuiManager(self):
3169         """ Returns the L{AuiManager} which manages the toolbar. """
3170
3171         try:
3172             return self._auiManager
3173         except AttributeError:
3174             return False
3175
3176
3177     def SetAuiManager(self, auiManager):
3178         """ Sets the L{AuiManager} which manages the toolbar. """
3179         
3180         self._auiManager = auiManager        
3181
3182         
3183     def DoIdleUpdate(self):
3184         """ Updates the toolbar during idle times. """
3185
3186         handler = self.GetEventHandler()
3187         if not handler:
3188             return
3189         
3190         need_refresh = False
3191
3192         for item in self._items:
3193                 
3194             if item.id == -1:
3195                 continue
3196
3197             evt = wx.UpdateUIEvent(item.id)
3198             evt.SetEventObject(self)
3199
3200             if handler.ProcessEvent(evt):
3201             
3202                 if evt.GetSetEnabled():
3203                 
3204                     if item.window:
3205                         is_enabled = item.window.IsEnabled()
3206                     else:
3207                         is_enabled = (item.state & AUI_BUTTON_STATE_DISABLED and [False] or [True])[0]
3208
3209                     new_enabled = evt.GetEnabled()
3210                     if new_enabled != is_enabled:
3211                     
3212                         if item.window:
3213                             item.window.Enable(new_enabled)
3214                         else:
3215                             if new_enabled:
3216                                 item.state &= ~AUI_BUTTON_STATE_DISABLED
3217                             else:
3218                                 item.state |= AUI_BUTTON_STATE_DISABLED
3219                         
3220                         need_refresh = True
3221                     
3222                 if evt.GetSetChecked():
3223                 
3224                     # make sure we aren't checking an item that can't be
3225                     if item.kind != ITEM_CHECK and item.kind != ITEM_RADIO:
3226                         continue
3227
3228                     is_checked = (item.state & AUI_BUTTON_STATE_CHECKED and [True] or [False])[0]
3229                     new_checked = evt.GetChecked()
3230
3231                     if new_checked != is_checked:
3232                     
3233                         if new_checked:
3234                             item.state |= AUI_BUTTON_STATE_CHECKED
3235                         else:
3236                             item.state &= ~AUI_BUTTON_STATE_CHECKED
3237
3238                         need_refresh = True
3239                     
3240         if need_refresh:
3241             self.Refresh(False)
3242
3243         
3244     def OnSize(self, event):
3245         """
3246         Handles the ``wx.EVT_SIZE`` event for L{AuiToolBar}.
3247
3248         :param `event`: a `wx.SizeEvent` event to be processed.        
3249         """
3250         
3251         x, y = self.GetClientSize()
3252         realize = False
3253
3254         if x > y:
3255             self.SetOrientation(wx.HORIZONTAL)
3256         else:
3257             self.SetOrientation(wx.VERTICAL)
3258
3259         if (x >= y and self._absolute_min_size.x > x) or (y > x and self._absolute_min_size.y > y):
3260         
3261             # hide all flexible items
3262             for item in self._items:
3263                 if item.sizer_item and item.proportion > 0 and item.sizer_item.IsShown():
3264                     item.sizer_item.Show(False)
3265                     item.sizer_item.SetProportion(0)
3266
3267             if self._originalStyle & AUI_TB_OVERFLOW:
3268                 if not self.GetOverflowVisible():
3269                     self.SetOverflowVisible(True)
3270                     realize = True
3271                        
3272         else:
3273
3274             if self._originalStyle & AUI_TB_OVERFLOW and not self._custom_overflow_append and \
3275                not self._custom_overflow_prepend:
3276                 if self.GetOverflowVisible():
3277                     self.SetOverflowVisible(False)
3278                     realize = True
3279
3280             # show all flexible items
3281             for item in self._items:
3282                 if item.sizer_item and item.proportion > 0 and not item.sizer_item.IsShown():
3283                     item.sizer_item.Show(True)
3284                     item.sizer_item.SetProportion(item.proportion)
3285                 
3286         self._sizer.SetDimension(0, 0, x, y)
3287
3288         if realize:
3289             self.Realize()
3290         else:
3291             self.Refresh(False)
3292             
3293         self.Update()
3294
3295         
3296     def DoSetSize(self, x, y, width, height, sizeFlags=wx.SIZE_AUTO):
3297         """        
3298         Sets the position and size of the window in pixels. The `sizeFlags`
3299         parameter indicates the interpretation of the other params if they are
3300         equal to -1.
3301
3302         :param `x`: the window `x` position;
3303         :param `y`: the window `y` position;
3304         :param `width`: the window width;
3305         :param `height`: the window height;
3306         :param `sizeFlags`: may have one of this bit set:
3307    
3308          ===================================  ======================================
3309          Size Flags                           Description
3310          ===================================  ======================================
3311          ``wx.SIZE_AUTO``                     A -1 indicates that a class-specific default should be used.
3312          ``wx.SIZE_AUTO_WIDTH``               A -1 indicates that a class-specific default should be used for the width.
3313          ``wx.SIZE_AUTO_HEIGHT``              A -1 indicates that a class-specific default should be used for the height.
3314          ``wx.SIZE_USE_EXISTING``             Existing dimensions should be used if -1 values are supplied.
3315          ``wx.SIZE_ALLOW_MINUS_ONE``          Allow dimensions of -1 and less to be interpreted as real dimensions, not default values.
3316          ``wx.SIZE_FORCE``                    Normally, if the position and the size of the window are already the same as the parameters of this function, nothing is done. but with this flag a window resize may be forced even in this case (supported in wx 2.6.2 and later and only implemented for MSW and ignored elsewhere currently) 
3317          ===================================  ======================================
3318
3319         :note: Overridden from `wx.PyControl`.
3320         """
3321         
3322         parent_size = self.GetParent().GetClientSize()
3323         if x + width > parent_size.x:
3324             width = max(0, parent_size.x - x)
3325         if y + height > parent_size.y:
3326             height = max(0, parent_size.y - y)
3327
3328         wx.PyControl.DoSetSize(self, x, y, width, height, sizeFlags)
3329
3330
3331     def OnIdle(self, event):
3332         """
3333         Handles the ``wx.EVT_IDLE`` event for L{AuiToolBar}.
3334
3335         :param `event`: a `wx.IdleEvent` event to be processed.        
3336         """
3337         
3338         self.DoIdleUpdate()
3339         event.Skip()
3340
3341
3342     def DoGetBestSize(self):
3343         """
3344         Gets the size which best suits the window: for a control, it would be the
3345         minimal size which doesn't truncate the control, for a panel - the same
3346         size as it would have after a call to `Fit()`.
3347         
3348         :note: Overridden from `wx.PyControl`.
3349         """
3350
3351         return self._absolute_min_size
3352     
3353
3354     def OnPaint(self, event):
3355         """
3356         Handles the ``wx.EVT_PAINT`` event for L{AuiToolBar}.
3357
3358         :param `event`: a `wx.PaintEvent` event to be processed.        
3359         """
3360
3361         dc = wx.AutoBufferedPaintDC(self)
3362         cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize())
3363
3364         horizontal = True
3365         if self._agwStyle & AUI_TB_VERTICAL:
3366             horizontal = False
3367
3368         if self._agwStyle & AUI_TB_PLAIN_BACKGROUND:
3369             self._art.DrawPlainBackground(dc, self, cli_rect)
3370         else:
3371             self._art.DrawBackground(dc, self, cli_rect, horizontal)
3372
3373         gripper_size = self._art.GetElementSize(AUI_TBART_GRIPPER_SIZE)
3374         dropdown_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE)
3375
3376         # paint the gripper
3377         if gripper_size > 0 and self._gripper_sizer_item:
3378             gripper_rect = wx.Rect(*self._gripper_sizer_item.GetRect())
3379             if horizontal:
3380                 gripper_rect.width = gripper_size
3381             else:
3382                 gripper_rect.height = gripper_size
3383                 
3384             self._art.DrawGripper(dc, self, gripper_rect)
3385         
3386         # calculated how far we can draw items
3387         if horizontal:
3388             last_extent = cli_rect.width
3389         else:
3390             last_extent = cli_rect.height
3391             
3392         if self._overflow_visible:
3393             last_extent -= dropdown_size
3394
3395         # paint each individual tool
3396         for item in self._items:
3397
3398             if not item.sizer_item:
3399                 continue
3400
3401             item_rect = wx.Rect(*item.sizer_item.GetRect())
3402
3403             if (horizontal and item_rect.x + item_rect.width >= last_extent) or \
3404                (not horizontal and item_rect.y + item_rect.height >= last_extent):
3405
3406                 break
3407             
3408             if item.kind == ITEM_SEPARATOR:
3409                 # draw a separator
3410                 self._art.DrawSeparator(dc, self, item_rect)
3411             
3412             elif item.kind == ITEM_LABEL:
3413                 # draw a text label only
3414                 self._art.DrawLabel(dc, self, item, item_rect)
3415             
3416             elif item.kind == ITEM_NORMAL:
3417                 # draw a regular button or dropdown button
3418                 if not item.dropdown:
3419                     self._art.DrawButton(dc, self, item, item_rect)
3420                 else:
3421                     self._art.DrawDropDownButton(dc, self, item, item_rect)
3422             
3423             elif item.kind == ITEM_CHECK:
3424                 # draw a regular toggle button or a dropdown one
3425                 if not item.dropdown:
3426                     self._art.DrawButton(dc, self, item, item_rect)
3427                 else:
3428                     self._art.DrawDropDownButton(dc, self, item, item_rect)
3429
3430             elif item.kind == ITEM_RADIO:
3431                 # draw a toggle button
3432                 self._art.DrawButton(dc, self, item, item_rect)
3433             
3434             elif item.kind == ITEM_CONTROL:
3435                 # draw the control's label
3436                 self._art.DrawControlLabel(dc, self, item, item_rect)
3437             
3438             # fire a signal to see if the item wants to be custom-rendered
3439             self.OnCustomRender(dc, item, item_rect)
3440         
3441         # paint the overflow button
3442         if dropdown_size > 0 and self._overflow_sizer_item:
3443             dropdown_rect = self.GetOverflowRect()
3444             self._art.DrawOverflowButton(dc, self, dropdown_rect, self._overflow_state)
3445
3446         
3447     def OnEraseBackground(self, event):
3448         """
3449         Handles the ``wx.EVT_ERASE_BACKGROUND`` event for L{AuiToolBar}.
3450
3451         :param `event`: a `wx.EraseEvent` event to be processed.
3452
3453         :note: This is intentionally empty, to reduce flicker.
3454         """
3455
3456         pass
3457     
3458
3459     def OnLeftDown(self, event):
3460         """
3461         Handles the ``wx.EVT_LEFT_DOWN`` event for L{AuiToolBar}.
3462
3463         :param `event`: a `wx.MouseEvent` event to be processed.        
3464         """
3465         
3466         cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize())
3467         self.StopPreviewTimer()
3468
3469         if self._gripper_sizer_item:
3470         
3471             gripper_rect = wx.Rect(*self._gripper_sizer_item.GetRect())
3472             if gripper_rect.Contains(event.GetPosition()):
3473             
3474                 # find aui manager
3475                 manager = self.GetAuiManager()
3476                 if not manager:
3477                     return
3478
3479                 x_drag_offset = event.GetX() - gripper_rect.GetX()
3480                 y_drag_offset = event.GetY() - gripper_rect.GetY()
3481
3482                 clientPt = wx.Point(*event.GetPosition())
3483                 screenPt = self.ClientToScreen(clientPt)
3484                 managedWindow = manager.GetManagedWindow()
3485                 managerClientPt = managedWindow.ScreenToClient(screenPt)
3486
3487                 # gripper was clicked
3488                 manager.OnGripperClicked(self, managerClientPt, wx.Point(x_drag_offset, y_drag_offset))            
3489                 return
3490
3491         if self._overflow_sizer_item:
3492             overflow_rect = self.GetOverflowRect()
3493
3494             if self._art and self._overflow_visible and overflow_rect.Contains(event.GetPosition()):
3495             
3496                 e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_OVERFLOW_CLICK, -1)
3497                 e.SetEventObject(self)
3498                 e.SetToolId(-1)
3499                 e.SetClickPoint(event.GetPosition())
3500                 processed = self.ProcessEvent(e)
3501
3502                 if processed:
3503                     self.DoIdleUpdate()
3504                 else:                
3505                     overflow_items = []
3506
3507                     # add custom overflow prepend items, if any
3508                     count = len(self._custom_overflow_prepend)
3509                     for i in xrange(count):
3510                         overflow_items.append(self._custom_overflow_prepend[i])
3511
3512                     # only show items that don't fit in the dropdown
3513                     count = len(self._items)
3514                     for i in xrange(count):
3515                     
3516                         if not self.GetToolFitsByIndex(i):
3517                             overflow_items.append(self._items[i])
3518                     
3519                     # add custom overflow append items, if any
3520                     count = len(self._custom_overflow_append)
3521                     for i in xrange(count):
3522                         overflow_items.append(self._custom_overflow_append[i])
3523
3524                     res = self._art.ShowDropDown(self, overflow_items)
3525                     self._overflow_state = 0
3526                     self.Refresh(False)
3527                     if res != -1:
3528                         e = wx.CommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, res)
3529                         e.SetEventObject(self)
3530                         if not self.GetParent().ProcessEvent(e):
3531                             tool = self.FindTool(res)
3532                             if tool:
3533                                 state = (tool.state & AUI_BUTTON_STATE_CHECKED and [True] or [False])[0]
3534                                 self.ToggleTool(res, not state)
3535                     
3536                 return
3537             
3538         self._dragging = False
3539         self._action_pos = wx.Point(*event.GetPosition())
3540         self._action_item = self.FindToolForPosition(*event.GetPosition())
3541
3542         if self._action_item:
3543         
3544             if self._action_item.state & AUI_BUTTON_STATE_DISABLED:
3545             
3546                 self._action_pos = wx.Point(-1, -1)
3547                 self._action_item = None
3548                 return
3549             
3550             self.SetPressedItem(self._action_item)
3551
3552             # fire the tool dropdown event
3553             e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, self._action_item.id)
3554             e.SetEventObject(self)
3555             e.SetToolId(self._action_item.id)
3556             e.SetDropDownClicked(False)
3557
3558             mouse_x, mouse_y = event.GetX(), event.GetY()
3559             rect = wx.Rect(*self._action_item.sizer_item.GetRect())
3560
3561             if self._action_item.dropdown:
3562                 if (self._action_item.orientation == AUI_TBTOOL_HORIZONTAL and \
3563                     mouse_x >= (rect.x+rect.width-BUTTON_DROPDOWN_WIDTH-1) and \
3564                     mouse_x < (rect.x+rect.width)) or \
3565                     (self._action_item.orientation != AUI_TBTOOL_HORIZONTAL and \
3566                      mouse_y >= (rect.y+rect.height-BUTTON_DROPDOWN_WIDTH-1) and \
3567                      mouse_y < (rect.y+rect.height)):
3568                     
3569                     e.SetDropDownClicked(True)            
3570             
3571             e.SetClickPoint(event.GetPosition())
3572             e.SetItemRect(rect)
3573             self.ProcessEvent(e)
3574             self.DoIdleUpdate()
3575         
3576
3577     def OnLeftUp(self, event):
3578         """
3579         Handles the ``wx.EVT_LEFT_UP`` event for L{AuiToolBar}.
3580
3581         :param `event`: a `wx.MouseEvent` event to be processed.        
3582         """
3583         
3584         self.SetPressedItem(None)
3585
3586         hit_item = self.FindToolForPosition(*event.GetPosition())
3587         
3588         if hit_item and not hit_item.state & AUI_BUTTON_STATE_DISABLED:
3589             self.SetHoverItem(hit_item)
3590
3591         if self._dragging:
3592             # reset drag and drop member variables
3593             self._dragging = False
3594             self._action_pos = wx.Point(-1, -1)
3595             self._action_item = None
3596         
3597         else:
3598
3599             if self._action_item and hit_item == self._action_item:
3600                 self.SetToolTipString("")
3601
3602                 if hit_item.kind in [ITEM_CHECK, ITEM_RADIO]:
3603                     toggle = not (self._action_item.state & AUI_BUTTON_STATE_CHECKED)
3604                     self.ToggleTool(self._action_item.id, toggle)
3605
3606                     # repaint immediately
3607                     self.Refresh(False)
3608                     self.Update()
3609                     
3610                     e = wx.CommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, self._action_item.id)
3611                     e.SetEventObject(self)
3612                     e.SetInt(toggle)
3613                     self._action_pos = wx.Point(-1, -1)
3614                     self._action_item = None
3615                     
3616                     self.ProcessEvent(e)
3617                     self.DoIdleUpdate()
3618                     
3619                 else:
3620
3621                     if self._action_item.id == ID_RESTORE_FRAME:
3622                         # find aui manager
3623                         manager = self.GetAuiManager()
3624
3625                         if not manager:
3626                             return
3627
3628                         pane = manager.GetPane(self)
3629                         e = framemanager.AuiManagerEvent(framemanager.wxEVT_AUI_PANE_MIN_RESTORE)
3630
3631                         e.SetManager(manager)
3632                         e.SetPane(pane)
3633
3634                         manager.ProcessEvent(e)
3635                         self.DoIdleUpdate()
3636
3637                     else:
3638
3639                         e = wx.CommandEvent(wx.wxEVT_COMMAND_MENU_SELECTED, self._action_item.id)
3640                         e.SetEventObject(self)
3641                         self.ProcessEvent(e)
3642                         self.DoIdleUpdate()
3643                 
3644         # reset drag and drop member variables
3645         self._dragging = False
3646         self._action_pos = wx.Point(-1, -1)
3647         self._action_item = None
3648
3649
3650     def OnRightDown(self, event):
3651         """
3652         Handles the ``wx.EVT_RIGHT_DOWN`` event for L{AuiToolBar}.
3653
3654         :param `event`: a `wx.MouseEvent` event to be processed.        
3655         """
3656         
3657         cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize())
3658
3659         if self._gripper_sizer_item:
3660             gripper_rect = self._gripper_sizer_item.GetRect()
3661             if gripper_rect.Contains(event.GetPosition()):
3662                 return
3663         
3664         if self._overflow_sizer_item:
3665         
3666             dropdown_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE)
3667             if dropdown_size > 0 and event.GetX() > cli_rect.width - dropdown_size and \
3668                event.GetY() >= 0 and event.GetY() < cli_rect.height and self._art:
3669                 return
3670             
3671         self._action_pos = wx.Point(*event.GetPosition())
3672         self._action_item = self.FindToolForPosition(*event.GetPosition())
3673
3674         if self._action_item:
3675             if self._action_item.state & AUI_BUTTON_STATE_DISABLED:
3676             
3677                 self._action_pos = wx.Point(-1, -1)
3678                 self._action_item = None
3679                 return
3680
3681
3682     def OnRightUp(self, event):
3683         """
3684         Handles the ``wx.EVT_RIGHT_UP`` event for L{AuiToolBar}.
3685
3686         :param `event`: a `wx.MouseEvent` event to be processed.        
3687         """
3688         
3689         hit_item = self.FindToolForPosition(*event.GetPosition())
3690
3691         if self._action_item and hit_item == self._action_item:
3692             
3693             e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK, self._action_item.id)
3694             e.SetEventObject(self)
3695             e.SetToolId(self._action_item.id)
3696             e.SetClickPoint(self._action_pos)
3697             self.ProcessEvent(e)
3698             self.DoIdleUpdate()
3699             
3700         else:
3701         
3702             # right-clicked on the invalid area of the toolbar
3703             e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_RIGHT_CLICK, -1)
3704             e.SetEventObject(self)
3705             e.SetToolId(-1)
3706             e.SetClickPoint(self._action_pos)
3707             self.ProcessEvent(e)
3708             self.DoIdleUpdate()
3709         
3710         # reset member variables
3711         self._action_pos = wx.Point(-1, -1)
3712         self._action_item = None
3713
3714
3715     def OnMiddleDown(self, event):
3716         """
3717         Handles the ``wx.EVT_MIDDLE_DOWN`` event for L{AuiToolBar}.
3718
3719         :param `event`: a `wx.MouseEvent` event to be processed.        
3720         """
3721         
3722         cli_rect = wx.RectPS(wx.Point(0, 0), self.GetClientSize())
3723
3724         if self._gripper_sizer_item:
3725         
3726             gripper_rect = self._gripper_sizer_item.GetRect()
3727             if gripper_rect.Contains(event.GetPosition()):
3728                 return
3729         
3730         if self._overflow_sizer_item:
3731         
3732             dropdown_size = self._art.GetElementSize(AUI_TBART_OVERFLOW_SIZE)
3733             if dropdown_size > 0 and event.GetX() > cli_rect.width - dropdown_size and \
3734                event.GetY() >= 0 and event.GetY() < cli_rect.height and self._art:            
3735                 return
3736             
3737         self._action_pos = wx.Point(*event.GetPosition())
3738         self._action_item = self.FindToolForPosition(*event.GetPosition())
3739
3740         if self._action_item:
3741             if self._action_item.state & AUI_BUTTON_STATE_DISABLED:
3742             
3743                 self._action_pos = wx.Point(-1, -1)
3744                 self._action_item = None
3745                 return
3746
3747
3748     def OnMiddleUp(self, event):
3749         """
3750         Handles the ``wx.EVT_MIDDLE_UP`` event for L{AuiToolBar}.
3751
3752         :param `event`: a `wx.MouseEvent` event to be processed.        
3753         """
3754         
3755         hit_item = self.FindToolForPosition(*event.GetPosition())
3756
3757         if self._action_item and hit_item == self._action_item:        
3758             if hit_item.kind == ITEM_NORMAL:
3759             
3760                 e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_MIDDLE_CLICK, self._action_item.id)
3761                 e.SetEventObject(self)
3762                 e.SetToolId(self._action_item.id)
3763                 e.SetClickPoint(self._action_pos)
3764                 self.ProcessEvent(e)
3765                 self.DoIdleUpdate()
3766             
3767         # reset member variables
3768         self._action_pos = wx.Point(-1, -1)
3769         self._action_item = None
3770
3771
3772     def OnMotion(self, event):
3773         """
3774         Handles the ``wx.EVT_MOTION`` event for L{AuiToolBar}.
3775
3776         :param `event`: a `wx.MouseEvent` event to be processed.        
3777         """
3778         
3779         # start a drag event
3780         if not self._dragging and self._action_item != None and self._action_pos != wx.Point(-1, -1) and \
3781            abs(event.GetX() - self._action_pos.x) + abs(event.GetY() - self._action_pos.y) > 5:
3782         
3783             self.SetToolTipString("")
3784             self._dragging = True
3785
3786             e = AuiToolBarEvent(wxEVT_COMMAND_AUITOOLBAR_BEGIN_DRAG, self.GetId())
3787             e.SetEventObject(self)
3788             e.SetToolId(self._action_item.id)
3789             self.ProcessEvent(e)
3790             self.DoIdleUpdate()
3791             return
3792         
3793         hit_item = self.FindToolForPosition(*event.GetPosition())
3794         
3795         if hit_item:        
3796             if not hit_item.state & AUI_BUTTON_STATE_DISABLED:
3797                 self.SetHoverItem(hit_item)
3798             else:
3799                 self.SetHoverItem(None)
3800         
3801         else:        
3802             # no hit item, remove any hit item
3803             self.SetHoverItem(hit_item)
3804         
3805         # figure out tooltips
3806         packing_hit_item = self.FindToolForPositionWithPacking(*event.GetPosition())
3807         
3808         if packing_hit_item:
3809         
3810             if packing_hit_item != self._tip_item:
3811                 self._tip_item = packing_hit_item
3812
3813                 if packing_hit_item.short_help != "":
3814                     self.StartPreviewTimer()
3815                     self.SetToolTipString(packing_hit_item.short_help)
3816                 else:
3817                     self.SetToolTipString("")
3818                     self.StopPreviewTimer()
3819             
3820         else:
3821         
3822             self.SetToolTipString("")
3823             self._tip_item = None
3824             self.StopPreviewTimer()
3825         
3826         # if we've pressed down an item and we're hovering
3827         # over it, make sure it's state is set to pressed
3828         if self._action_item:
3829         
3830             if self._action_item == hit_item:
3831                 self.SetPressedItem(self._action_item)
3832             else:
3833                 self.SetPressedItem(None)
3834         
3835         # figure out the dropdown button state (are we hovering or pressing it?)
3836         self.RefreshOverflowState()
3837
3838
3839     def OnLeaveWindow(self, event):
3840         """
3841         Handles the ``wx.EVT_LEAVE_WINDOW`` event for L{AuiToolBar}.
3842
3843         :param `event`: a `wx.MouseEvent` event to be processed.        
3844         """
3845
3846         self.RefreshOverflowState()
3847         self.SetHoverItem(None)
3848         self.SetPressedItem(None)
3849
3850         self._tip_item = None
3851         self.StopPreviewTimer()
3852
3853
3854     def OnSetCursor(self, event):
3855         """
3856         Handles the ``wx.EVT_SET_CURSOR`` event for L{AuiToolBar}.
3857
3858         :param `event`: a `wx.SetCursorEvent` event to be processed.        
3859         """
3860         
3861         cursor = wx.NullCursor
3862
3863         if self._gripper_sizer_item:
3864         
3865             gripper_rect = self._gripper_sizer_item.GetRect()
3866             if gripper_rect.Contains((event.GetX(), event.GetY())):
3867                 cursor = wx.StockCursor(wx.CURSOR_SIZING)
3868             
3869         event.SetCursor(cursor)
3870
3871
3872     def OnCustomRender(self, dc, item, rect):
3873         """
3874         Handles custom render for single L{AuiToolBar} items.
3875         
3876         :param `dc`: a `wx.DC` device context;
3877         :param `item`: an instance of L{AuiToolBarItem};
3878         :param `rect`: the toolbar item rect.
3879
3880         :note: This method must be overridden to provide custom rendering of items.
3881         """
3882         
3883         pass
3884
3885
3886     def IsPaneMinimized(self):
3887         """ Returns whether this L{AuiToolBar} contains a minimized pane tool. """
3888         
3889         manager = self.GetAuiManager()
3890         if not manager:
3891             return False
3892         
3893         if manager.GetAGWFlags() & AUI_MGR_PREVIEW_MINIMIZED_PANES == 0:
3894             # No previews here
3895             return False
3896
3897         self_name = manager.GetPane(self).name
3898         
3899         if not self_name.endswith("_min"):
3900             # Wrong tool name
3901             return False
3902
3903         return self_name[0:-4]
3904     
3905         
3906     def StartPreviewTimer(self):
3907         """ Starts a timer in L{AuiManager} to slide-in/slide-out the minimized pane. """
3908
3909         self_name = self.IsPaneMinimized()
3910         if not self_name:
3911             return
3912
3913         manager = self.GetAuiManager()        
3914         manager.StartPreviewTimer(self)
3915
3916
3917     def StopPreviewTimer(self):
3918         """ Stops a timer in L{AuiManager} to slide-in/slide-out the minimized pane. """
3919
3920         self_name = self.IsPaneMinimized()
3921         if not self_name:
3922             return
3923
3924         manager = self.GetAuiManager()        
3925         manager.StopPreviewTimer()
3926