2 Tab art provider code - a tab provider provides all drawing functionality to
3 the L{AuiNotebook}. This allows the L{AuiNotebook} to have a plugable look-and-feel.
5 By default, a L{AuiNotebook} uses an instance of this class called L{AuiDefaultTabArt}
6 which provides bitmap art and a colour scheme that is adapted to the major platforms'
7 look. You can either derive from that class to alter its behaviour or write a
8 completely new tab art class. Call L{AuiNotebook.SetArtProvider} to make use this
12 __author__ = "Andrea Gavana <andrea.gavana@gmail.com>"
13 __date__ = "31 March 2009"
18 if wx.Platform == '__WXMAC__':
19 import Carbon.Appearance
21 from aui_utilities import BitmapFromBits, StepColour, IndentPressedBitmap, ChopText
22 from aui_utilities import GetBaseColour, DrawMACCloseButton, LightColour, TakeScreenShot
23 from aui_utilities import CopyAttributes
25 from aui_constants import *
28 # -- GUI helper classes and functions --
29 class AuiCommandCapture(wx.PyEvtHandler):
30 """ A class to handle the dropdown window menu. """
33 """ Default class constructor. """
35 wx.PyEvtHandler.__init__(self)
39 def GetCommandId(self):
40 """ Returns the event command identifier. """
45 def ProcessEvent(self, event):
47 Processes an event, searching event tables and calling zero or more suitable
48 event handler function(s).
50 :param `event`: the event to process.
52 :note: Normally, your application would not call this function: it is called
53 in the wxPython implementation to dispatch incoming user interface events
54 to the framework (and application).
55 However, you might need to call it if implementing new functionality (such as
56 a new control) where you define new event types, as opposed to allowing the
57 user to override functions.
59 An instance where you might actually override the L{ProcessEvent} function is where
60 you want to direct event processing to event handlers not normally noticed by
61 wxPython. For example, in the document/view architecture, documents and views
62 are potential event handlers. When an event reaches a frame, L{ProcessEvent} will
63 need to be called on the associated document and view in case event handler
64 functions are associated with these objects.
66 The normal order of event table searching is as follows:
68 1. If the object is disabled (via a call to `SetEvtHandlerEnabled`) the function
70 2. If the object is a `wx.Window`, L{ProcessEvent} is recursively called on the window's
71 `wx.Validator`. If this returns ``True``, the function exits.
72 3. wxWidgets `SearchEventTable` is called for this event handler. If this fails, the
73 base class table is tried, and so on until no more tables exist or an appropriate
74 function was found, in which case the function exits.
75 4. The search is applied down the entire chain of event handlers (usually the chain
76 has a length of one). If this succeeds, the function exits.
77 5. If the object is a `wx.Window` and the event is a `wx.CommandEvent`, L{ProcessEvent} is
78 recursively applied to the parent window's event handler. If this returns ``True``,
80 6. Finally, L{ProcessEvent} is called on the `wx.App` object.
83 if event.GetEventType() == wx.wxEVT_COMMAND_MENU_SELECTED:
84 self._last_id = event.GetId()
87 if self.GetNextHandler():
88 return self.GetNextHandler().ProcessEvent(event)
93 class AuiDefaultTabArt(object):
95 Tab art provider code - a tab provider provides all drawing functionality to
96 the L{AuiNotebook}. This allows the L{AuiNotebook} to have a plugable look-and-feel.
98 By default, a L{AuiNotebook} uses an instance of this class called L{AuiDefaultTabArt}
99 which provides bitmap art and a colour scheme that is adapted to the major platforms'
100 look. You can either derive from that class to alter its behaviour or write a
101 completely new tab art class. Call L{AuiNotebook.SetArtProvider} to make use this
106 """ Default class constructor. """
108 self._normal_font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
109 self._selected_font = wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
110 self._selected_font.SetWeight(wx.BOLD)
111 self._measuring_font = self._selected_font
113 self._fixed_tab_width = 100
114 self._tab_ctrl_height = 0
115 self._buttonRect = wx.Rect()
117 self.SetDefaultColours()
119 if wx.Platform == "__WXMAC__":
120 bmp_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DDKSHADOW)
121 self._active_close_bmp = DrawMACCloseButton(bmp_colour)
122 self._disabled_close_bmp = DrawMACCloseButton(wx.Colour(128, 128, 128))
124 self._active_close_bmp = BitmapFromBits(nb_close_bits, 16, 16, wx.BLACK)
125 self._disabled_close_bmp = BitmapFromBits(nb_close_bits, 16, 16, wx.Colour(128, 128, 128))
127 self._hover_close_bmp = self._active_close_bmp
128 self._pressed_close_bmp = self._active_close_bmp
130 self._active_left_bmp = BitmapFromBits(nb_left_bits, 16, 16, wx.BLACK)
131 self._disabled_left_bmp = BitmapFromBits(nb_left_bits, 16, 16, wx.Colour(128, 128, 128))
133 self._active_right_bmp = BitmapFromBits(nb_right_bits, 16, 16, wx.BLACK)
134 self._disabled_right_bmp = BitmapFromBits(nb_right_bits, 16, 16, wx.Colour(128, 128, 128))
136 self._active_windowlist_bmp = BitmapFromBits(nb_list_bits, 16, 16, wx.BLACK)
137 self._disabled_windowlist_bmp = BitmapFromBits(nb_list_bits, 16, 16, wx.Colour(128, 128, 128))
139 if wx.Platform == "__WXMAC__":
140 # Get proper highlight colour for focus rectangle from the
141 # current Mac theme. kThemeBrushFocusHighlight is
142 # available on Mac OS 8.5 and higher
143 if hasattr(wx, 'MacThemeColour'):
144 c = wx.MacThemeColour(Carbon.Appearance.kThemeBrushFocusHighlight)
146 brush = wx.Brush(wx.BLACK)
147 brush.MacSetTheme(Carbon.Appearance.kThemeBrushFocusHighlight)
148 c = brush.GetColour()
149 self._focusPen = wx.Pen(c, 2, wx.SOLID)
151 self._focusPen = wx.Pen(wx.BLACK, 1, wx.USER_DASH)
152 self._focusPen.SetDashes([1, 1])
153 self._focusPen.SetCap(wx.CAP_BUTT)
156 def SetBaseColour(self, base_colour):
158 Sets a new base colour.
160 :param `base_colour`: an instance of `wx.Colour`.
163 self._base_colour = base_colour
164 self._base_colour_pen = wx.Pen(self._base_colour)
165 self._base_colour_brush = wx.Brush(self._base_colour)
168 def SetDefaultColours(self, base_colour=None):
170 Sets the default colours, which are calculated from the given base colour.
172 :param `base_colour`: an instance of `wx.Colour`. If defaulted to ``None``, a colour
173 is generated accordingly to the platform and theme.
176 if base_colour is None:
177 base_colour = GetBaseColour()
179 self.SetBaseColour( base_colour )
180 self._border_colour = StepColour(base_colour, 75)
181 self._border_pen = wx.Pen(self._border_colour)
183 self._background_top_colour = StepColour(self._base_colour, 90)
184 self._background_bottom_colour = StepColour(self._base_colour, 170)
186 self._tab_top_colour = self._base_colour
187 self._tab_bottom_colour = wx.WHITE
188 self._tab_gradient_highlight_colour = wx.WHITE
190 self._tab_inactive_top_colour = self._base_colour
191 self._tab_inactive_bottom_colour = StepColour(self._tab_inactive_top_colour, 160)
193 self._tab_text_colour = lambda page: page.text_colour
194 self._tab_disabled_text_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT)
198 """ Clones the art object. """
201 art.SetNormalFont(self.GetNormalFont())
202 art.SetSelectedFont(self.GetSelectedFont())
203 art.SetMeasuringFont(self.GetMeasuringFont())
205 art = CopyAttributes(art, self)
209 def SetAGWFlags(self, agwFlags):
211 Sets the tab art flags.
213 :param `agwFlags`: a combination of the following values:
215 ==================================== ==================================
216 Flag name Description
217 ==================================== ==================================
218 ``AUI_NB_TOP`` With this style, tabs are drawn along the top of the notebook
219 ``AUI_NB_LEFT`` With this style, tabs are drawn along the left of the notebook. Not implemented yet.
220 ``AUI_NB_RIGHT`` With this style, tabs are drawn along the right of the notebook. Not implemented yet.
221 ``AUI_NB_BOTTOM`` With this style, tabs are drawn along the bottom of the notebook
222 ``AUI_NB_TAB_SPLIT`` Allows the tab control to be split by dragging a tab
223 ``AUI_NB_TAB_MOVE`` Allows a tab to be moved horizontally by dragging
224 ``AUI_NB_TAB_EXTERNAL_MOVE`` Allows a tab to be moved to another tab control
225 ``AUI_NB_TAB_FIXED_WIDTH`` With this style, all tabs have the same width
226 ``AUI_NB_SCROLL_BUTTONS`` With this style, left and right scroll buttons are displayed
227 ``AUI_NB_WINDOWLIST_BUTTON`` With this style, a drop-down list of windows is available
228 ``AUI_NB_CLOSE_BUTTON`` With this style, a close button is available on the tab bar
229 ``AUI_NB_CLOSE_ON_ACTIVE_TAB`` With this style, a close button is available on the active tab
230 ``AUI_NB_CLOSE_ON_ALL_TABS`` With this style, a close button is available on all tabs
231 ``AUI_NB_MIDDLE_CLICK_CLOSE`` Allows to close L{AuiNotebook} tabs by mouse middle button click
232 ``AUI_NB_SUB_NOTEBOOK`` This style is used by L{AuiManager} to create automatic AuiNotebooks
233 ``AUI_NB_HIDE_ON_SINGLE_TAB`` Hides the tab window if only one tab is present
234 ``AUI_NB_SMART_TABS`` Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows
235 ``AUI_NB_USE_IMAGES_DROPDOWN`` Uses images on dropdown window list menu instead of check items
236 ``AUI_NB_CLOSE_ON_TAB_LEFT`` Draws the tab close button on the left instead of on the right (a la Camino browser)
237 ``AUI_NB_TAB_FLOAT`` Allows the floating of single tabs. Known limitation: when the notebook is more or less full screen, tabs cannot be dragged far enough outside of the notebook to become floating pages
238 ``AUI_NB_DRAW_DND_TAB`` Draws an image representation of a tab while dragging (on by default)
239 ``AUI_NB_ORDER_BY_ACCESS`` Tab navigation order by last access time for the tabs
240 ``AUI_NB_NO_TAB_FOCUS`` Don't draw tab focus rectangle
241 ==================================== ==================================
245 self._agwFlags = agwFlags
248 def GetAGWFlags(self):
250 Returns the tab art flags.
252 :see: L{SetAGWFlags} for a list of possible return values.
255 return self._agwFlags
258 def SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth):
260 Sets the tab sizing information.
262 :param `tab_ctrl_size`: the size of the tab control area;
263 :param `tab_count`: the number of tabs;
264 :param `minMaxTabWidth`: a tuple containing the minimum and maximum tab widths
265 to be used when the ``AUI_NB_TAB_FIXED_WIDTH`` style is active.
268 self._fixed_tab_width = 100
269 minTabWidth, maxTabWidth = minMaxTabWidth
271 tot_width = tab_ctrl_size.x - self.GetIndentSize() - 4
272 agwFlags = self.GetAGWFlags()
274 if agwFlags & AUI_NB_CLOSE_BUTTON:
275 tot_width -= self._active_close_bmp.GetWidth()
276 if agwFlags & AUI_NB_WINDOWLIST_BUTTON:
277 tot_width -= self._active_windowlist_bmp.GetWidth()
280 self._fixed_tab_width = tot_width/tab_count
282 if self._fixed_tab_width < 100:
283 self._fixed_tab_width = 100
285 if self._fixed_tab_width > tot_width/2:
286 self._fixed_tab_width = tot_width/2
288 if self._fixed_tab_width > 220:
289 self._fixed_tab_width = 220
292 self._fixed_tab_width = max(self._fixed_tab_width, minTabWidth)
294 self._fixed_tab_width = min(self._fixed_tab_width, maxTabWidth)
296 self._tab_ctrl_height = tab_ctrl_size.y
299 def DrawBackground(self, dc, wnd, rect):
301 Draws the tab area background.
303 :param `dc`: a `wx.DC` device context;
304 :param `wnd`: a `wx.Window` instance object;
305 :param `rect`: the tab control rectangle.
308 self._buttonRect = wx.Rect()
311 agwFlags = self.GetAGWFlags()
312 if agwFlags & AUI_NB_BOTTOM:
313 r = wx.Rect(rect.x, rect.y, rect.width+2, rect.height)
315 # TODO: else if (agwFlags & AUI_NB_LEFT)
316 # TODO: else if (agwFlags & AUI_NB_RIGHT)
317 else: #for AUI_NB_TOP
318 r = wx.Rect(rect.x, rect.y, rect.width+2, rect.height-3)
320 dc.GradientFillLinear(r, self._background_top_colour, self._background_bottom_colour, wx.SOUTH)
324 dc.SetPen(self._border_pen)
328 if agwFlags & AUI_NB_BOTTOM:
329 dc.SetBrush(wx.Brush(self._background_bottom_colour))
330 dc.DrawRectangle(-1, 0, w+2, 4)
332 # TODO: else if (agwFlags & AUI_NB_LEFT)
333 # TODO: else if (agwFlags & AUI_NB_RIGHT)
335 else: # for AUI_NB_TOP
336 dc.SetBrush(self._base_colour_brush)
337 dc.DrawRectangle(-1, y-4, w+2, 4)
340 def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False):
344 :param `dc`: a `wx.DC` device context;
345 :param `wnd`: a `wx.Window` instance object;
346 :param `page`: the tab control page associated with the tab;
347 :param `in_rect`: rectangle the tab should be confined to;
348 :param `close_button_state`: the state of the close button on the tab;
349 :param `paint_control`: whether to draw the control inside a tab (if any) on a `wx.MemoryDC`.
352 # if the caption is empty, measure some temporary text
353 caption = page.caption
357 dc.SetFont(self._selected_font)
358 selected_textx, selected_texty, dummy = dc.GetMultiLineTextExtent(caption)
360 dc.SetFont(self._normal_font)
361 normal_textx, normal_texty, dummy = dc.GetMultiLineTextExtent(caption)
363 control = page.control
365 # figure out the size of the tab
366 tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap,
367 page.active, close_button_state, control)
369 tab_height = self._tab_ctrl_height - 3
370 tab_width = tab_size[0]
372 tab_y = in_rect.y + in_rect.height - tab_height
374 caption = page.caption
376 # select pen, brush and font for the tab to be drawn
380 dc.SetFont(self._selected_font)
381 textx, texty = selected_textx, selected_texty
385 dc.SetFont(self._normal_font)
386 textx, texty = normal_textx, normal_texty
389 dc.SetTextForeground(self._tab_disabled_text_colour)
390 pagebitmap = page.dis_bitmap
392 dc.SetTextForeground(self._tab_text_colour(page))
393 pagebitmap = page.bitmap
395 # create points that will make the tab outline
397 clip_width = tab_width
398 if tab_x + clip_width > in_rect.x + in_rect.width:
399 clip_width = in_rect.x + in_rect.width - tab_x
401 # since the above code above doesn't play well with WXDFB or WXCOCOA,
402 # we'll just use a rectangle for the clipping region for now --
403 dc.SetClippingRegion(tab_x, tab_y, clip_width+1, tab_height-3)
405 border_points = [wx.Point() for i in xrange(6)]
406 agwFlags = self.GetAGWFlags()
408 if agwFlags & AUI_NB_BOTTOM:
410 border_points[0] = wx.Point(tab_x, tab_y)
411 border_points[1] = wx.Point(tab_x, tab_y+tab_height-6)
412 border_points[2] = wx.Point(tab_x+2, tab_y+tab_height-4)
413 border_points[3] = wx.Point(tab_x+tab_width-2, tab_y+tab_height-4)
414 border_points[4] = wx.Point(tab_x+tab_width, tab_y+tab_height-6)
415 border_points[5] = wx.Point(tab_x+tab_width, tab_y)
417 else: #if (agwFlags & AUI_NB_TOP)
419 border_points[0] = wx.Point(tab_x, tab_y+tab_height-4)
420 border_points[1] = wx.Point(tab_x, tab_y+2)
421 border_points[2] = wx.Point(tab_x+2, tab_y)
422 border_points[3] = wx.Point(tab_x+tab_width-2, tab_y)
423 border_points[4] = wx.Point(tab_x+tab_width, tab_y+2)
424 border_points[5] = wx.Point(tab_x+tab_width, tab_y+tab_height-4)
426 # TODO: else if (agwFlags & AUI_NB_LEFT)
427 # TODO: else if (agwFlags & AUI_NB_RIGHT)
429 drawn_tab_yoff = border_points[1].y
430 drawn_tab_height = border_points[0].y - border_points[1].y
436 # draw base background colour
437 r = wx.Rect(tab_x, tab_y, tab_width, tab_height)
438 dc.SetPen(self._base_colour_pen)
439 dc.SetBrush(self._base_colour_brush)
440 dc.DrawRectangle(r.x+1, r.y+1, r.width-1, r.height-4)
442 # this white helps fill out the gradient at the top of the tab
443 dc.SetPen( wx.Pen(self._tab_gradient_highlight_colour) )
444 dc.SetBrush( wx.Brush(self._tab_gradient_highlight_colour) )
445 dc.DrawRectangle(r.x+2, r.y+1, r.width-3, r.height-4)
447 # these two points help the rounded corners appear more antialiased
448 dc.SetPen(self._base_colour_pen)
449 dc.DrawPoint(r.x+2, r.y+1)
450 dc.DrawPoint(r.x+r.width-2, r.y+1)
452 # set rectangle down a bit for gradient drawing
453 r.SetHeight(r.GetHeight()/2)
459 # draw gradient background
460 top_colour = self._tab_bottom_colour
461 bottom_colour = self._tab_top_colour
462 dc.GradientFillLinear(r, bottom_colour, top_colour, wx.NORTH)
468 r = wx.Rect(tab_x, tab_y+1, tab_width, tab_height-3)
470 # start the gradent up a bit and leave the inside border inset
471 # by a pixel for a 3D look. Only the top half of the inactive
472 # tab will have a slight gradient
479 # -- draw top gradient fill for glossy look
480 top_colour = self._tab_inactive_top_colour
481 bottom_colour = self._tab_inactive_bottom_colour
482 dc.GradientFillLinear(r, bottom_colour, top_colour, wx.NORTH)
487 # -- draw bottom fill for glossy look
488 top_colour = self._tab_inactive_bottom_colour
489 bottom_colour = self._tab_inactive_bottom_colour
490 dc.GradientFillLinear(r, top_colour, bottom_colour, wx.SOUTH)
493 dc.SetPen(self._border_pen)
494 dc.SetBrush(wx.TRANSPARENT_BRUSH)
495 dc.DrawPolygon(border_points)
497 # there are two horizontal grey lines at the bottom of the tab control,
498 # this gets rid of the top one of those lines in the tab control
501 if agwFlags & AUI_NB_BOTTOM:
502 dc.SetPen(wx.Pen(self._background_bottom_colour))
504 # TODO: else if (agwFlags & AUI_NB_LEFT)
505 # TODO: else if (agwFlags & AUI_NB_RIGHT)
506 else: # for AUI_NB_TOP
507 dc.SetPen(self._base_colour_pen)
509 dc.DrawLine(border_points[0].x+1,
514 text_offset = tab_x + 8
515 close_button_width = 0
517 if close_button_state != AUI_BUTTON_STATE_HIDDEN:
518 close_button_width = self._active_close_bmp.GetWidth()
520 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
521 text_offset += close_button_width - 5
525 if pagebitmap.IsOk():
527 bitmap_offset = tab_x + 8
528 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width:
529 bitmap_offset += close_button_width - 5
532 dc.DrawBitmap(pagebitmap,
534 drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2),
537 text_offset = bitmap_offset + pagebitmap.GetWidth()
538 text_offset += 3 # bitmap padding
542 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width:
543 text_offset = tab_x + 8
545 draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width)
547 ypos = drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1
549 offset_focus = text_offset
550 if control is not None:
551 if control.GetPosition() != wx.Point(text_offset+1, ypos):
552 control.SetPosition(wx.Point(text_offset+1, ypos))
554 if not control.IsShown():
558 bmp = TakeScreenShot(control.GetScreenRect())
559 dc.DrawBitmap(bmp, text_offset+1, ypos, True)
561 controlW, controlH = control.GetSize()
562 text_offset += controlW + 4
563 textx += controlW + 4
566 rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text)
567 dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty))
569 # draw focus rectangle
570 if (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0:
571 self.DrawFocusRectangle(dc, page, wnd, draw_text, offset_focus, bitmap_offset, drawn_tab_yoff, drawn_tab_height, rectx, recty)
573 out_button_rect = wx.Rect()
575 # draw close button if necessary
576 if close_button_state != AUI_BUTTON_STATE_HIDDEN:
578 bmp = self._disabled_close_bmp
580 if close_button_state == AUI_BUTTON_STATE_HOVER:
581 bmp = self._hover_close_bmp
582 elif close_button_state == AUI_BUTTON_STATE_PRESSED:
583 bmp = self._pressed_close_bmp
585 shift = (agwFlags & AUI_NB_BOTTOM and [1] or [0])[0]
587 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
588 rect = wx.Rect(tab_x + 4, tab_y + (tab_height - bmp.GetHeight())/2 - shift,
589 close_button_width, tab_height)
591 rect = wx.Rect(tab_x + tab_width - close_button_width - 1,
592 tab_y + (tab_height - bmp.GetHeight())/2 - shift,
593 close_button_width, tab_height)
595 rect = IndentPressedBitmap(rect, close_button_state)
596 dc.DrawBitmap(bmp, rect.x, rect.y, True)
598 out_button_rect = rect
600 out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height)
602 dc.DestroyClippingRegion()
604 return out_tab_rect, out_button_rect, x_extent
607 def SetCustomButton(self, bitmap_id, button_state, bmp):
609 Sets a custom bitmap for the close, left, right and window list
612 :param `bitmap_id`: the button identifier;
613 :param `button_state`: the button state;
614 :param `bmp`: the custom bitmap to use for the button.
617 if bitmap_id == AUI_BUTTON_CLOSE:
618 if button_state == AUI_BUTTON_STATE_NORMAL:
619 self._active_close_bmp = bmp
620 self._hover_close_bmp = self._active_close_bmp
621 self._pressed_close_bmp = self._active_close_bmp
622 self._disabled_close_bmp = self._active_close_bmp
624 elif button_state == AUI_BUTTON_STATE_HOVER:
625 self._hover_close_bmp = bmp
626 elif button_state == AUI_BUTTON_STATE_PRESSED:
627 self._pressed_close_bmp = bmp
629 self._disabled_close_bmp = bmp
631 elif bitmap_id == AUI_BUTTON_LEFT:
632 if button_state & AUI_BUTTON_STATE_DISABLED:
633 self._disabled_left_bmp = bmp
635 self._active_left_bmp = bmp
637 elif bitmap_id == AUI_BUTTON_RIGHT:
638 if button_state & AUI_BUTTON_STATE_DISABLED:
639 self._disabled_right_bmp = bmp
641 self._active_right_bmp = bmp
643 elif bitmap_id == AUI_BUTTON_WINDOWLIST:
644 if button_state & AUI_BUTTON_STATE_DISABLED:
645 self._disabled_windowlist_bmp = bmp
647 self._active_windowlist_bmp = bmp
650 def GetIndentSize(self):
651 """ Returns the tabs indent size. """
656 def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control=None):
658 Returns the tab size for the given caption, bitmap and button state.
660 :param `dc`: a `wx.DC` device context;
661 :param `wnd`: a `wx.Window` instance object;
662 :param `caption`: the tab text caption;
663 :param `bitmap`: the bitmap displayed on the tab;
664 :param `active`: whether the tab is selected or not;
665 :param `close_button_state`: the state of the close button on the tab;
666 :param `control`: a `wx.Window` instance inside a tab (or ``None``).
669 dc.SetFont(self._measuring_font)
670 measured_textx, measured_texty, dummy = dc.GetMultiLineTextExtent(caption)
672 # add padding around the text
673 tab_width = measured_textx
674 tab_height = measured_texty
676 # if the close button is showing, add space for it
677 if close_button_state != AUI_BUTTON_STATE_HIDDEN:
678 tab_width += self._active_close_bmp.GetWidth() + 3
680 # if there's a bitmap, add space for it
682 tab_width += bitmap.GetWidth()
683 tab_width += 3 # right side bitmap padding
684 tab_height = max(tab_height, bitmap.GetHeight())
690 agwFlags = self.GetAGWFlags()
691 if agwFlags & AUI_NB_TAB_FIXED_WIDTH:
692 tab_width = self._fixed_tab_width
694 if control is not None:
695 tab_width += control.GetSize().GetWidth() + 4
699 return (tab_width, tab_height), x_extent
702 def DrawButton(self, dc, wnd, in_rect, button, orientation):
704 Draws a button on the tab or on the tab area, depending on the button identifier.
706 :param `dc`: a `wx.DC` device context;
707 :param `wnd`: a `wx.Window` instance object;
708 :param `in_rect`: rectangle the tab should be confined to;
709 :param `button`: an instance of the button class;
710 :param `orientation`: the tab orientation.
713 bitmap_id, button_state = button.id, button.cur_state
715 if bitmap_id == AUI_BUTTON_CLOSE:
716 if button_state & AUI_BUTTON_STATE_DISABLED:
717 bmp = self._disabled_close_bmp
718 elif button_state & AUI_BUTTON_STATE_HOVER:
719 bmp = self._hover_close_bmp
720 elif button_state & AUI_BUTTON_STATE_PRESSED:
721 bmp = self._pressed_close_bmp
723 bmp = self._active_close_bmp
725 elif bitmap_id == AUI_BUTTON_LEFT:
726 if button_state & AUI_BUTTON_STATE_DISABLED:
727 bmp = self._disabled_left_bmp
729 bmp = self._active_left_bmp
731 elif bitmap_id == AUI_BUTTON_RIGHT:
732 if button_state & AUI_BUTTON_STATE_DISABLED:
733 bmp = self._disabled_right_bmp
735 bmp = self._active_right_bmp
737 elif bitmap_id == AUI_BUTTON_WINDOWLIST:
738 if button_state & AUI_BUTTON_STATE_DISABLED:
739 bmp = self._disabled_windowlist_bmp
741 bmp = self._active_windowlist_bmp
744 if button_state & AUI_BUTTON_STATE_DISABLED:
745 bmp = button.dis_bitmap
752 rect = wx.Rect(*in_rect)
754 if orientation == wx.LEFT:
757 rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2))
758 rect.SetWidth(bmp.GetWidth())
759 rect.SetHeight(bmp.GetHeight())
763 rect = wx.Rect(in_rect.x + in_rect.width - bmp.GetWidth(),
764 ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
765 bmp.GetWidth(), bmp.GetHeight())
767 rect = IndentPressedBitmap(rect, button_state)
768 dc.DrawBitmap(bmp, rect.x, rect.y, True)
772 if bitmap_id == AUI_BUTTON_RIGHT:
773 self._buttonRect = wx.Rect(rect.x, rect.y, 30, rect.height)
778 def DrawFocusRectangle(self, dc, page, wnd, draw_text, text_offset, bitmap_offset, drawn_tab_yoff, drawn_tab_height, textx, texty):
780 Draws the focus rectangle on a tab.
782 :param `dc`: a `wx.DC` device context;
783 :param `page`: the page associated with the tab;
784 :param `wnd`: a `wx.Window` instance object;
785 :param `draw_text`: the text that has been drawn on the tab;
786 :param `text_offset`: the text offset on the tab;
787 :param `bitmap_offset`: the bitmap offset on the tab;
788 :param `drawn_tab_yoff`: the y offset of the tab text;
789 :param `drawn_tab_height`: the height of the tab;
790 :param `textx`: the x text extent;
791 :param `texty`: the y text extent.
794 if self.GetAGWFlags() & AUI_NB_NO_TAB_FOCUS:
797 if page.active and wx.Window.FindFocus() == wnd:
799 focusRectText = wx.Rect(text_offset, (drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2)),
802 if page.bitmap.IsOk():
803 focusRectBitmap = wx.Rect(bitmap_offset, drawn_tab_yoff + (drawn_tab_height/2) - (page.bitmap.GetHeight()/2),
804 page.bitmap.GetWidth(), page.bitmap.GetHeight())
806 if page.bitmap.IsOk() and draw_text == "":
807 focusRect = wx.Rect(*focusRectBitmap)
808 elif not page.bitmap.IsOk() and draw_text != "":
809 focusRect = wx.Rect(*focusRectText)
810 elif page.bitmap.IsOk() and draw_text != "":
811 focusRect = focusRectText.Union(focusRectBitmap)
813 focusRect.Inflate(2, 2)
815 dc.SetBrush(wx.TRANSPARENT_BRUSH)
816 dc.SetPen(self._focusPen)
817 dc.DrawRoundedRectangleRect(focusRect, 2)
820 def GetBestTabCtrlSize(self, wnd, pages, required_bmp_size):
822 Returns the best tab control size.
824 :param `wnd`: a `wx.Window` instance object;
825 :param `pages`: the pages associated with the tabs;
826 :param `required_bmp_size`: the size of the bitmap on the tabs.
829 dc = wx.ClientDC(wnd)
830 dc.SetFont(self._measuring_font)
832 # sometimes a standard bitmap size needs to be enforced, especially
833 # if some tabs have bitmaps and others don't. This is important because
834 # it prevents the tab control from resizing when tabs are added.
836 measure_bmp = wx.NullBitmap
838 if required_bmp_size.IsFullySpecified():
839 measure_bmp = wx.EmptyBitmap(required_bmp_size.x,
846 if measure_bmp.IsOk():
851 # we don't use the caption text because we don't
852 # want tab heights to be different in the case
853 # of a very short piece of text on one tab and a very
854 # tall piece of text on another tab
855 s, x_ext = self.GetTabSize(dc, wnd, page.caption, bmp, True, AUI_BUTTON_STATE_HIDDEN, None)
856 max_y = max(max_y, s[1])
859 controlW, controlH = page.control.GetSize()
860 max_y = max(max_y, controlH+4)
865 def SetNormalFont(self, font):
867 Sets the normal font for drawing tab labels.
869 :param `font`: a `wx.Font` object.
872 self._normal_font = font
875 def SetSelectedFont(self, font):
877 Sets the selected tab font for drawing tab labels.
879 :param `font`: a `wx.Font` object.
882 self._selected_font = font
885 def SetMeasuringFont(self, font):
887 Sets the font for calculating text measurements.
889 :param `font`: a `wx.Font` object.
892 self._measuring_font = font
895 def GetNormalFont(self):
896 """ Returns the normal font for drawing tab labels. """
898 return self._normal_font
901 def GetSelectedFont(self):
902 """ Returns the selected tab font for drawing tab labels. """
904 return self._selected_font
907 def GetMeasuringFont(self):
908 """ Returns the font for calculating text measurements. """
910 return self._measuring_font
913 def ShowDropDown(self, wnd, pages, active_idx):
915 Shows the drop-down window menu on the tab area.
917 :param `wnd`: a `wx.Window` derived window instance;
918 :param `pages`: the pages associated with the tabs;
919 :param `active_idx`: the active tab index.
922 useImages = self.GetAGWFlags() & AUI_NB_USE_IMAGES_DROPDOWN
923 menuPopup = wx.Menu()
926 for i, page in enumerate(pages):
928 caption = page.caption
930 # if there is no caption, make it a space. This will prevent
931 # an assert in the menu code.
935 # Save longest caption width for calculating menu width with
936 width = wnd.GetTextExtent(caption)[0]
941 menuItem = wx.MenuItem(menuPopup, 1000+i, caption)
943 menuItem.SetBitmap(page.bitmap)
945 menuPopup.AppendItem(menuItem)
949 menuPopup.AppendCheckItem(1000+i, caption)
951 menuPopup.Enable(1000+i, page.enabled)
953 if active_idx != -1 and not useImages:
955 menuPopup.Check(1000+active_idx, True)
957 # find out the screen coordinate at the bottom of the tab ctrl
958 cli_rect = wnd.GetClientRect()
960 # Calculate the approximate size of the popupmenu for setting the
961 # position of the menu when its shown.
962 # Account for extra padding on left/right of text on mac menus
963 if wx.Platform in ['__WXMAC__', '__WXMSW__']:
966 # Bitmap/Checkmark width + padding
969 if self.GetAGWFlags() & AUI_NB_CLOSE_BUTTON:
972 pt = wx.Point(cli_rect.x + cli_rect.GetWidth() - longest,
973 cli_rect.y + cli_rect.height)
975 cc = AuiCommandCapture()
976 wnd.PushEventHandler(cc)
977 wnd.PopupMenu(menuPopup, pt)
978 command = cc.GetCommandId()
979 wnd.PopEventHandler(True)
982 return command - 1000
987 class AuiSimpleTabArt(object):
988 """ A simple-looking implementation of a tab art. """
991 """ Default class constructor. """
993 self._normal_font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
994 self._selected_font = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
995 self._selected_font.SetWeight(wx.BOLD)
996 self._measuring_font = self._selected_font
999 self._fixed_tab_width = 100
1001 base_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE)
1003 background_colour = base_colour
1004 normaltab_colour = base_colour
1005 selectedtab_colour = wx.WHITE
1007 self._bkbrush = wx.Brush(background_colour)
1008 self._normal_bkbrush = wx.Brush(normaltab_colour)
1009 self._normal_bkpen = wx.Pen(normaltab_colour)
1010 self._selected_bkbrush = wx.Brush(selectedtab_colour)
1011 self._selected_bkpen = wx.Pen(selectedtab_colour)
1013 self._active_close_bmp = BitmapFromBits(nb_close_bits, 16, 16, wx.BLACK)
1014 self._disabled_close_bmp = BitmapFromBits(nb_close_bits, 16, 16, wx.Colour(128, 128, 128))
1016 self._active_left_bmp = BitmapFromBits(nb_left_bits, 16, 16, wx.BLACK)
1017 self._disabled_left_bmp = BitmapFromBits(nb_left_bits, 16, 16, wx.Colour(128, 128, 128))
1019 self._active_right_bmp = BitmapFromBits(nb_right_bits, 16, 16, wx.BLACK)
1020 self._disabled_right_bmp = BitmapFromBits(nb_right_bits, 16, 16, wx.Colour(128, 128, 128))
1022 self._active_windowlist_bmp = BitmapFromBits(nb_list_bits, 16, 16, wx.BLACK)
1023 self._disabled_windowlist_bmp = BitmapFromBits(nb_list_bits, 16, 16, wx.Colour(128, 128, 128))
1027 """ Clones the art object. """
1030 art.SetNormalFont(self.GetNormalFont())
1031 art.SetSelectedFont(self.GetSelectedFont())
1032 art.SetMeasuringFont(self.GetMeasuringFont())
1034 art = CopyAttributes(art, self)
1038 def SetAGWFlags(self, agwFlags):
1040 Sets the tab art flags.
1042 :param `agwFlags`: a combination of the following values:
1044 ==================================== ==================================
1045 Flag name Description
1046 ==================================== ==================================
1047 ``AUI_NB_TOP`` With this style, tabs are drawn along the top of the notebook
1048 ``AUI_NB_LEFT`` With this style, tabs are drawn along the left of the notebook. Not implemented yet.
1049 ``AUI_NB_RIGHT`` With this style, tabs are drawn along the right of the notebook. Not implemented yet.
1050 ``AUI_NB_BOTTOM`` With this style, tabs are drawn along the bottom of the notebook
1051 ``AUI_NB_TAB_SPLIT`` Allows the tab control to be split by dragging a tab
1052 ``AUI_NB_TAB_MOVE`` Allows a tab to be moved horizontally by dragging
1053 ``AUI_NB_TAB_EXTERNAL_MOVE`` Allows a tab to be moved to another tab control
1054 ``AUI_NB_TAB_FIXED_WIDTH`` With this style, all tabs have the same width
1055 ``AUI_NB_SCROLL_BUTTONS`` With this style, left and right scroll buttons are displayed
1056 ``AUI_NB_WINDOWLIST_BUTTON`` With this style, a drop-down list of windows is available
1057 ``AUI_NB_CLOSE_BUTTON`` With this style, a close button is available on the tab bar
1058 ``AUI_NB_CLOSE_ON_ACTIVE_TAB`` With this style, a close button is available on the active tab
1059 ``AUI_NB_CLOSE_ON_ALL_TABS`` With this style, a close button is available on all tabs
1060 ``AUI_NB_MIDDLE_CLICK_CLOSE`` Allows to close L{AuiNotebook} tabs by mouse middle button click
1061 ``AUI_NB_SUB_NOTEBOOK`` This style is used by L{AuiManager} to create automatic AuiNotebooks
1062 ``AUI_NB_HIDE_ON_SINGLE_TAB`` Hides the tab window if only one tab is present
1063 ``AUI_NB_SMART_TABS`` Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows
1064 ``AUI_NB_USE_IMAGES_DROPDOWN`` Uses images on dropdown window list menu instead of check items
1065 ``AUI_NB_CLOSE_ON_TAB_LEFT`` Draws the tab close button on the left instead of on the right (a la Camino browser)
1066 ``AUI_NB_TAB_FLOAT`` Allows the floating of single tabs. Known limitation: when the notebook is more or less full screen, tabs cannot be dragged far enough outside of the notebook to become floating pages
1067 ``AUI_NB_DRAW_DND_TAB`` Draws an image representation of a tab while dragging (on by default)
1068 ``AUI_NB_ORDER_BY_ACCESS`` Tab navigation order by last access time for the tabs
1069 ``AUI_NB_NO_TAB_FOCUS`` Don't draw tab focus rectangle
1070 ==================================== ==================================
1074 self._agwFlags = agwFlags
1077 def GetAGWFlags(self):
1079 Returns the tab art flags.
1081 :see: L{SetAGWFlags} for a list of possible return values.
1084 return self._agwFlags
1087 def SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth):
1089 Sets the tab sizing information.
1091 :param `tab_ctrl_size`: the size of the tab control area;
1092 :param `tab_count`: the number of tabs;
1093 :param `minMaxTabWidth`: a tuple containing the minimum and maximum tab widths
1094 to be used when the ``AUI_NB_TAB_FIXED_WIDTH`` style is active.
1097 self._fixed_tab_width = 100
1098 minTabWidth, maxTabWidth = minMaxTabWidth
1100 tot_width = tab_ctrl_size.x - self.GetIndentSize() - 4
1102 if self._agwFlags & AUI_NB_CLOSE_BUTTON:
1103 tot_width -= self._active_close_bmp.GetWidth()
1104 if self._agwFlags & AUI_NB_WINDOWLIST_BUTTON:
1105 tot_width -= self._active_windowlist_bmp.GetWidth()
1108 self._fixed_tab_width = tot_width/tab_count
1110 if self._fixed_tab_width < 100:
1111 self._fixed_tab_width = 100
1113 if self._fixed_tab_width > tot_width/2:
1114 self._fixed_tab_width = tot_width/2
1116 if self._fixed_tab_width > 220:
1117 self._fixed_tab_width = 220
1119 if minTabWidth > -1:
1120 self._fixed_tab_width = max(self._fixed_tab_width, minTabWidth)
1121 if maxTabWidth > -1:
1122 self._fixed_tab_width = min(self._fixed_tab_width, maxTabWidth)
1124 self._tab_ctrl_height = tab_ctrl_size.y
1127 def DrawBackground(self, dc, wnd, rect):
1129 Draws the tab area background.
1131 :param `dc`: a `wx.DC` device context;
1132 :param `wnd`: a `wx.Window` instance object;
1133 :param `rect`: the tab control rectangle.
1137 dc.SetBrush(self._bkbrush)
1138 dc.SetPen(wx.TRANSPARENT_PEN)
1139 dc.DrawRectangle(-1, -1, rect.GetWidth()+2, rect.GetHeight()+2)
1142 dc.SetPen(wx.GREY_PEN)
1143 dc.DrawLine(0, rect.GetHeight()-1, rect.GetWidth(), rect.GetHeight()-1)
1146 def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False):
1150 :param `dc`: a `wx.DC` device context;
1151 :param `wnd`: a `wx.Window` instance object;
1152 :param `page`: the tab control page associated with the tab;
1153 :param `in_rect`: rectangle the tab should be confined to;
1154 :param `close_button_state`: the state of the close button on the tab;
1155 :param `paint_control`: whether to draw the control inside a tab (if any) on a `wx.MemoryDC`.
1158 # if the caption is empty, measure some temporary text
1159 caption = page.caption
1163 agwFlags = self.GetAGWFlags()
1165 dc.SetFont(self._selected_font)
1166 selected_textx, selected_texty, dummy = dc.GetMultiLineTextExtent(caption)
1168 dc.SetFont(self._normal_font)
1169 normal_textx, normal_texty, dummy = dc.GetMultiLineTextExtent(caption)
1171 control = page.control
1173 # figure out the size of the tab
1174 tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap,
1175 page.active, close_button_state, control)
1177 tab_height = tab_size[1]
1178 tab_width = tab_size[0]
1180 tab_y = in_rect.y + in_rect.height - tab_height
1182 caption = page.caption
1183 # select pen, brush and font for the tab to be drawn
1187 dc.SetPen(self._selected_bkpen)
1188 dc.SetBrush(self._selected_bkbrush)
1189 dc.SetFont(self._selected_font)
1190 textx = selected_textx
1191 texty = selected_texty
1195 dc.SetPen(self._normal_bkpen)
1196 dc.SetBrush(self._normal_bkbrush)
1197 dc.SetFont(self._normal_font)
1198 textx = normal_textx
1199 texty = normal_texty
1201 if not page.enabled:
1202 dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
1204 dc.SetTextForeground(page.text_colour)
1208 points = [wx.Point() for i in xrange(7)]
1210 points[0].y = tab_y + tab_height - 1
1211 points[1].x = tab_x + tab_height - 3
1212 points[1].y = tab_y + 2
1213 points[2].x = tab_x + tab_height + 3
1215 points[3].x = tab_x + tab_width - 2
1217 points[4].x = tab_x + tab_width
1218 points[4].y = tab_y + 2
1219 points[5].x = tab_x + tab_width
1220 points[5].y = tab_y + tab_height - 1
1221 points[6] = points[0]
1223 dc.SetClippingRect(in_rect)
1224 dc.DrawPolygon(points)
1226 dc.SetPen(wx.GREY_PEN)
1227 dc.DrawLines(points)
1229 close_button_width = 0
1231 if close_button_state != AUI_BUTTON_STATE_HIDDEN:
1233 close_button_width = self._active_close_bmp.GetWidth()
1234 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
1236 text_offset = tab_x + (tab_height/2) + close_button_width - (textx/2) - 2
1238 text_offset = tab_x + (tab_height/2) + ((tab_width+close_button_width)/2) - (textx/2) - 2
1241 text_offset = tab_x + (tab_height/2) + close_button_width - (textx/2)
1243 text_offset = tab_x + (tab_height/2) + ((tab_width-close_button_width)/2) - (textx/2)
1247 text_offset = tab_x + (tab_height/3) + (tab_width/2) - (textx/2)
1249 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
1250 text_offset = tab_x + (tab_height/3) - (textx/2) + close_button_width + 2
1252 text_offset = tab_x + (tab_height/3) - (textx/2)
1254 # set minimum text offset
1255 if text_offset < tab_x + tab_height:
1256 text_offset = tab_x + tab_height
1258 # chop text if necessary
1259 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
1260 draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x))
1262 draw_text = ChopText(dc, caption,
1263 tab_width - (text_offset-tab_x) - close_button_width)
1265 ypos = (tab_y + tab_height)/2 - (texty/2) + 1
1267 if control is not None:
1268 if control.GetPosition() != wx.Point(text_offset+1, ypos):
1269 control.SetPosition(wx.Point(text_offset+1, ypos))
1271 if not control.IsShown():
1275 bmp = TakeScreenShot(control.GetScreenRect())
1276 dc.DrawBitmap(bmp, text_offset+1, ypos, True)
1278 controlW, controlH = control.GetSize()
1279 text_offset += controlW + 4
1282 rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text)
1283 dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty))
1285 # draw focus rectangle
1286 if page.active and wx.Window.FindFocus() == wnd and (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0:
1288 focusRect = wx.Rect(text_offset, ((tab_y + tab_height)/2 - (texty/2) + 1),
1289 selected_textx, selected_texty)
1291 focusRect.Inflate(2, 2)
1293 # This should be uncommented when DrawFocusRect will become
1294 # available in wxPython
1295 # wx.RendererNative.Get().DrawFocusRect(wnd, dc, focusRect, 0)
1297 out_button_rect = wx.Rect()
1298 # draw close button if necessary
1299 if close_button_state != AUI_BUTTON_STATE_HIDDEN:
1302 bmp = self._active_close_bmp
1304 bmp = self._disabled_close_bmp
1306 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
1307 rect = wx.Rect(tab_x + tab_height - 2,
1308 tab_y + (tab_height/2) - (bmp.GetHeight()/2) + 1,
1309 close_button_width, tab_height - 1)
1311 rect = wx.Rect(tab_x + tab_width - close_button_width - 1,
1312 tab_y + (tab_height/2) - (bmp.GetHeight()/2) + 1,
1313 close_button_width, tab_height - 1)
1315 self.DrawButtons(dc, rect, bmp, wx.WHITE, close_button_state)
1316 out_button_rect = wx.Rect(*rect)
1318 out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height)
1319 dc.DestroyClippingRegion()
1321 return out_tab_rect, out_button_rect, x_extent
1324 def DrawButtons(self, dc, _rect, bmp, bkcolour, button_state):
1326 Convenience method to draw tab buttons.
1328 :param `dc`: a `wx.DC` device context;
1329 :param `_rect`: the tab rectangle;
1330 :param `bmp`: the tab bitmap;
1331 :param `bkcolour`: the tab background colour;
1332 :param `button_state`: the state of the tab button.
1335 rect = wx.Rect(*_rect)
1337 if button_state == AUI_BUTTON_STATE_PRESSED:
1341 if button_state in [AUI_BUTTON_STATE_HOVER, AUI_BUTTON_STATE_PRESSED]:
1342 dc.SetBrush(wx.Brush(StepColour(bkcolour, 120)))
1343 dc.SetPen(wx.Pen(StepColour(bkcolour, 75)))
1345 # draw the background behind the button
1346 dc.DrawRectangle(rect.x, rect.y, 15, 15)
1348 # draw the button itself
1349 dc.DrawBitmap(bmp, rect.x, rect.y, True)
1352 def GetIndentSize(self):
1353 """ Returns the tabs indent size. """
1358 def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control=None):
1360 Returns the tab size for the given caption, bitmap and button state.
1362 :param `dc`: a `wx.DC` device context;
1363 :param `wnd`: a `wx.Window` instance object;
1364 :param `caption`: the tab text caption;
1365 :param `bitmap`: the bitmap displayed on the tab;
1366 :param `active`: whether the tab is selected or not;
1367 :param `close_button_state`: the state of the close button on the tab;
1368 :param `control`: a `wx.Window` instance inside a tab (or ``None``).
1371 dc.SetFont(self._measuring_font)
1372 measured_textx, measured_texty, dummy = dc.GetMultiLineTextExtent(caption)
1374 tab_height = measured_texty + 4
1375 tab_width = measured_textx + tab_height + 5
1377 if close_button_state != AUI_BUTTON_STATE_HIDDEN:
1378 tab_width += self._active_close_bmp.GetWidth()
1380 if self._agwFlags & AUI_NB_TAB_FIXED_WIDTH:
1381 tab_width = self._fixed_tab_width
1383 if control is not None:
1384 controlW, controlH = control.GetSize()
1385 tab_width += controlW + 4
1387 x_extent = tab_width - (tab_height/2) - 1
1389 return (tab_width, tab_height), x_extent
1392 def DrawButton(self, dc, wnd, in_rect, button, orientation):
1394 Draws a button on the tab or on the tab area, depending on the button identifier.
1396 :param `dc`: a `wx.DC` device context;
1397 :param `wnd`: a `wx.Window` instance object;
1398 :param `in_rect`: rectangle the tab should be confined to;
1399 :param `button`: an instance of the button class;
1400 :param `orientation`: the tab orientation.
1403 bitmap_id, button_state = button.id, button.cur_state
1405 if bitmap_id == AUI_BUTTON_CLOSE:
1406 if button_state & AUI_BUTTON_STATE_DISABLED:
1407 bmp = self._disabled_close_bmp
1409 bmp = self._active_close_bmp
1411 elif bitmap_id == AUI_BUTTON_LEFT:
1412 if button_state & AUI_BUTTON_STATE_DISABLED:
1413 bmp = self._disabled_left_bmp
1415 bmp = self._active_left_bmp
1417 elif bitmap_id == AUI_BUTTON_RIGHT:
1418 if button_state & AUI_BUTTON_STATE_DISABLED:
1419 bmp = self._disabled_right_bmp
1421 bmp = self._active_right_bmp
1423 elif bitmap_id == AUI_BUTTON_WINDOWLIST:
1424 if button_state & AUI_BUTTON_STATE_DISABLED:
1425 bmp = self._disabled_windowlist_bmp
1427 bmp = self._active_windowlist_bmp
1430 if button_state & AUI_BUTTON_STATE_DISABLED:
1431 bmp = button.dis_bitmap
1438 rect = wx.Rect(*in_rect)
1440 if orientation == wx.LEFT:
1442 rect.SetX(in_rect.x)
1443 rect.SetY(((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2))
1444 rect.SetWidth(bmp.GetWidth())
1445 rect.SetHeight(bmp.GetHeight())
1449 rect = wx.Rect(in_rect.x + in_rect.width - bmp.GetWidth(),
1450 ((in_rect.y + in_rect.height)/2) - (bmp.GetHeight()/2),
1451 bmp.GetWidth(), bmp.GetHeight())
1453 self.DrawButtons(dc, rect, bmp, wx.WHITE, button_state)
1455 out_rect = wx.Rect(*rect)
1459 def ShowDropDown(self, wnd, pages, active_idx):
1461 Shows the drop-down window menu on the tab area.
1463 :param `wnd`: a `wx.Window` derived window instance;
1464 :param `pages`: the pages associated with the tabs;
1465 :param `active_idx`: the active tab index.
1468 menuPopup = wx.Menu()
1469 useImages = self.GetAGWFlags() & AUI_NB_USE_IMAGES_DROPDOWN
1471 for i, page in enumerate(pages):
1474 menuItem = wx.MenuItem(menuPopup, 1000+i, page.caption)
1476 menuItem.SetBitmap(page.bitmap)
1478 menuPopup.AppendItem(menuItem)
1482 menuPopup.AppendCheckItem(1000+i, page.caption)
1484 menuPopup.Enable(1000+i, page.enabled)
1486 if active_idx != -1 and not useImages:
1487 menuPopup.Check(1000+active_idx, True)
1489 # find out where to put the popup menu of window
1490 # items. Subtract 100 for now to center the menu
1491 # a bit, until a better mechanism can be implemented
1492 pt = wx.GetMousePosition()
1493 pt = wnd.ScreenToClient(pt)
1500 # find out the screen coordinate at the bottom of the tab ctrl
1501 cli_rect = wnd.GetClientRect()
1502 pt.y = cli_rect.y + cli_rect.height
1504 cc = AuiCommandCapture()
1505 wnd.PushEventHandler(cc)
1506 wnd.PopupMenu(menuPopup, pt)
1507 command = cc.GetCommandId()
1508 wnd.PopEventHandler(True)
1516 def GetBestTabCtrlSize(self, wnd, pages, required_bmp_size):
1518 Returns the best tab control size.
1520 :param `wnd`: a `wx.Window` instance object;
1521 :param `pages`: the pages associated with the tabs;
1522 :param `required_bmp_size`: the size of the bitmap on the tabs.
1525 dc = wx.ClientDC(wnd)
1526 dc.SetFont(self._measuring_font)
1527 s, x_extent = self.GetTabSize(dc, wnd, "ABCDEFGHIj", wx.NullBitmap, True,
1528 AUI_BUTTON_STATE_HIDDEN, None)
1534 controlW, controlH = page.control.GetSize()
1535 max_y = max(max_y, controlH+4)
1537 textx, texty, dummy = dc.GetMultiLineTextExtent(page.caption)
1538 max_y = max(max_y, texty)
1543 def SetNormalFont(self, font):
1545 Sets the normal font for drawing tab labels.
1547 :param `font`: a `wx.Font` object.
1550 self._normal_font = font
1553 def SetSelectedFont(self, font):
1555 Sets the selected tab font for drawing tab labels.
1557 :param `font`: a `wx.Font` object.
1560 self._selected_font = font
1563 def SetMeasuringFont(self, font):
1565 Sets the font for calculating text measurements.
1567 :param `font`: a `wx.Font` object.
1570 self._measuring_font = font
1573 def GetNormalFont(self):
1574 """ Returns the normal font for drawing tab labels. """
1576 return self._normal_font
1579 def GetSelectedFont(self):
1580 """ Returns the selected tab font for drawing tab labels. """
1582 return self._selected_font
1585 def GetMeasuringFont(self):
1586 """ Returns the font for calculating text measurements. """
1588 return self._measuring_font
1591 def SetCustomButton(self, bitmap_id, button_state, bmp):
1593 Sets a custom bitmap for the close, left, right and window list
1596 :param `bitmap_id`: the button identifier;
1597 :param `button_state`: the button state;
1598 :param `bmp`: the custom bitmap to use for the button.
1601 if bitmap_id == AUI_BUTTON_CLOSE:
1602 if button_state == AUI_BUTTON_STATE_NORMAL:
1603 self._active_close_bmp = bmp
1604 self._hover_close_bmp = self._active_close_bmp
1605 self._pressed_close_bmp = self._active_close_bmp
1606 self._disabled_close_bmp = self._active_close_bmp
1608 elif button_state == AUI_BUTTON_STATE_HOVER:
1609 self._hover_close_bmp = bmp
1610 elif button_state == AUI_BUTTON_STATE_PRESSED:
1611 self._pressed_close_bmp = bmp
1613 self._disabled_close_bmp = bmp
1615 elif bitmap_id == AUI_BUTTON_LEFT:
1616 if button_state & AUI_BUTTON_STATE_DISABLED:
1617 self._disabled_left_bmp = bmp
1619 self._active_left_bmp = bmp
1621 elif bitmap_id == AUI_BUTTON_RIGHT:
1622 if button_state & AUI_BUTTON_STATE_DISABLED:
1623 self._disabled_right_bmp = bmp
1625 self._active_right_bmp = bmp
1627 elif bitmap_id == AUI_BUTTON_WINDOWLIST:
1628 if button_state & AUI_BUTTON_STATE_DISABLED:
1629 self._disabled_windowlist_bmp = bmp
1631 self._active_windowlist_bmp = bmp
1634 class VC71TabArt(AuiDefaultTabArt):
1635 """ A class to draw tabs using the Visual Studio 2003 (VC71) style. """
1638 """ Default class constructor. """
1640 AuiDefaultTabArt.__init__(self)
1644 """ Clones the art object. """
1647 art.SetNormalFont(self.GetNormalFont())
1648 art.SetSelectedFont(self.GetSelectedFont())
1649 art.SetMeasuringFont(self.GetMeasuringFont())
1651 art = CopyAttributes(art, self)
1655 def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False):
1659 :param `dc`: a `wx.DC` device context;
1660 :param `wnd`: a `wx.Window` instance object;
1661 :param `page`: the tab control page associated with the tab;
1662 :param `in_rect`: rectangle the tab should be confined to;
1663 :param `close_button_state`: the state of the close button on the tab;
1664 :param `paint_control`: whether to draw the control inside a tab (if any) on a `wx.MemoryDC`.
1667 # Visual studio 7.1 style
1668 # This code is based on the renderer included in FlatNotebook
1670 # figure out the size of the tab
1672 control = page.control
1673 tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap, page.active,
1674 close_button_state, control)
1676 tab_height = self._tab_ctrl_height - 3
1677 tab_width = tab_size[0]
1679 tab_y = in_rect.y + in_rect.height - tab_height
1680 clip_width = tab_width
1682 if tab_x + clip_width > in_rect.x + in_rect.width - 4:
1683 clip_width = (in_rect.x + in_rect.width) - tab_x - 4
1685 dc.SetClippingRegion(tab_x, tab_y, clip_width + 1, tab_height - 3)
1686 agwFlags = self.GetAGWFlags()
1688 if agwFlags & AUI_NB_BOTTOM:
1691 dc.SetPen((page.active and [wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DHIGHLIGHT))] or \
1692 [wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DSHADOW))])[0])
1693 dc.SetBrush((page.active and [wx.Brush(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE))] or \
1694 [wx.TRANSPARENT_BRUSH])[0])
1698 tabH = tab_height - 2
1699 dc.DrawRectangle(tab_x, tab_y, tab_width, tabH)
1701 rightLineY1 = (agwFlags & AUI_NB_BOTTOM and [vertical_border_padding - 2] or \
1702 [vertical_border_padding - 1])[0]
1703 rightLineY2 = tabH + 3
1704 dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DSHADOW)))
1705 dc.DrawLine(tab_x + tab_width - 1, rightLineY1 + 1, tab_x + tab_width - 1, rightLineY2)
1707 if agwFlags & AUI_NB_BOTTOM:
1708 dc.DrawLine(tab_x + 1, rightLineY2 - 3 , tab_x + tab_width - 1, rightLineY2 - 3)
1710 dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DDKSHADOW)))
1711 dc.DrawLine(tab_x + tab_width, rightLineY1, tab_x + tab_width, rightLineY2)
1713 if agwFlags & AUI_NB_BOTTOM:
1714 dc.DrawLine(tab_x, rightLineY2 - 2, tab_x + tab_width, rightLineY2 - 2)
1718 # We dont draw a rectangle for non selected tabs, but only
1719 # vertical line on the right
1720 blackLineY1 = (agwFlags & AUI_NB_BOTTOM and [vertical_border_padding + 2] or \
1721 [vertical_border_padding + 1])[0]
1722 blackLineY2 = tab_height - 5
1723 dc.DrawLine(tab_x + tab_width, blackLineY1, tab_x + tab_width, blackLineY2)
1725 border_points = [0, 0]
1727 if agwFlags & AUI_NB_BOTTOM:
1729 border_points[0] = wx.Point(tab_x, tab_y)
1730 border_points[1] = wx.Point(tab_x, tab_y + tab_height - 6)
1732 else: # if (agwFlags & AUI_NB_TOP)
1734 border_points[0] = wx.Point(tab_x, tab_y + tab_height - 4)
1735 border_points[1] = wx.Point(tab_x, tab_y + 2)
1737 drawn_tab_yoff = border_points[1].y
1738 drawn_tab_height = border_points[0].y - border_points[1].y
1740 text_offset = tab_x + 8
1741 close_button_width = 0
1743 if close_button_state != AUI_BUTTON_STATE_HIDDEN:
1744 close_button_width = self._active_close_bmp.GetWidth()
1745 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
1746 text_offset += close_button_width - 5
1748 if not page.enabled:
1749 dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
1750 pagebitmap = page.dis_bitmap
1752 dc.SetTextForeground(page.text_colour)
1753 pagebitmap = page.bitmap
1756 if agwFlags & AUI_NB_BOTTOM:
1757 shift = (page.active and [1] or [2])[0]
1760 if pagebitmap.IsOk():
1761 bitmap_offset = tab_x + 8
1762 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width:
1763 bitmap_offset += close_button_width - 5
1766 dc.DrawBitmap(pagebitmap, bitmap_offset,
1767 drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2) + shift,
1770 text_offset = bitmap_offset + pagebitmap.GetWidth()
1771 text_offset += 3 # bitmap padding
1774 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width:
1775 text_offset = tab_x + 8
1777 # if the caption is empty, measure some temporary text
1778 caption = page.caption
1784 dc.SetFont(self._selected_font)
1785 textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
1787 dc.SetFont(self._normal_font)
1788 textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
1790 draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width)
1792 ypos = drawn_tab_yoff + (drawn_tab_height)/2 - (texty/2) - 1 + shift
1794 offset_focus = text_offset
1796 if control is not None:
1797 if control.GetPosition() != wx.Point(text_offset+1, ypos):
1798 control.SetPosition(wx.Point(text_offset+1, ypos))
1800 if not control.IsShown():
1804 bmp = TakeScreenShot(control.GetScreenRect())
1805 dc.DrawBitmap(bmp, text_offset+1, ypos, True)
1807 controlW, controlH = control.GetSize()
1808 text_offset += controlW + 4
1809 textx += controlW + 4
1812 rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text)
1813 dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty))
1815 out_button_rect = wx.Rect()
1817 # draw focus rectangle
1818 if (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0:
1819 self.DrawFocusRectangle(dc, page, wnd, draw_text, offset_focus, bitmap_offset, drawn_tab_yoff+shift,
1820 drawn_tab_height+shift, rectx, recty)
1822 # draw 'x' on tab (if enabled)
1823 if close_button_state != AUI_BUTTON_STATE_HIDDEN:
1824 close_button_width = self._active_close_bmp.GetWidth()
1826 bmp = self._disabled_close_bmp
1828 if close_button_state == AUI_BUTTON_STATE_HOVER:
1829 bmp = self._hover_close_bmp
1830 elif close_button_state == AUI_BUTTON_STATE_PRESSED:
1831 bmp = self._pressed_close_bmp
1833 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
1834 rect = wx.Rect(tab_x + 4,
1835 drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift,
1836 close_button_width, tab_height)
1838 rect = wx.Rect(tab_x + tab_width - close_button_width - 3,
1839 drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift,
1840 close_button_width, tab_height)
1842 # Indent the button if it is pressed down:
1843 rect = IndentPressedBitmap(rect, close_button_state)
1844 dc.DrawBitmap(bmp, rect.x, rect.y, True)
1846 out_button_rect = rect
1848 out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height)
1849 dc.DestroyClippingRegion()
1851 return out_tab_rect, out_button_rect, x_extent
1854 class FF2TabArt(AuiDefaultTabArt):
1855 """ A class to draw tabs using the Firefox 2 (FF2) style. """
1858 """ Default class constructor. """
1860 AuiDefaultTabArt.__init__(self)
1864 """ Clones the art object. """
1867 art.SetNormalFont(self.GetNormalFont())
1868 art.SetSelectedFont(self.GetSelectedFont())
1869 art.SetMeasuringFont(self.GetMeasuringFont())
1871 art = CopyAttributes(art, self)
1875 def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control):
1877 Returns the tab size for the given caption, bitmap and button state.
1879 :param `dc`: a `wx.DC` device context;
1880 :param `wnd`: a `wx.Window` instance object;
1881 :param `caption`: the tab text caption;
1882 :param `bitmap`: the bitmap displayed on the tab;
1883 :param `active`: whether the tab is selected or not;
1884 :param `close_button_state`: the state of the close button on the tab;
1885 :param `control`: a `wx.Window` instance inside a tab (or ``None``).
1888 tab_size, x_extent = AuiDefaultTabArt.GetTabSize(self, dc, wnd, caption, bitmap,
1889 active, close_button_state, control)
1891 tab_width, tab_height = tab_size
1893 # add some vertical padding
1896 return (tab_width, tab_height), x_extent
1899 def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False):
1903 :param `dc`: a `wx.DC` device context;
1904 :param `wnd`: a `wx.Window` instance object;
1905 :param `page`: the tab control page associated with the tab;
1906 :param `in_rect`: rectangle the tab should be confined to;
1907 :param `close_button_state`: the state of the close button on the tab;
1908 :param `paint_control`: whether to draw the control inside a tab (if any) on a `wx.MemoryDC`.
1913 control = page.control
1915 # figure out the size of the tab
1916 tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap,
1917 page.active, close_button_state, control)
1919 tab_height = self._tab_ctrl_height - 2
1920 tab_width = tab_size[0]
1922 tab_y = in_rect.y + in_rect.height - tab_height
1924 clip_width = tab_width
1925 if tab_x + clip_width > in_rect.x + in_rect.width - 4:
1926 clip_width = (in_rect.x + in_rect.width) - tab_x - 4
1928 dc.SetClippingRegion(tab_x, tab_y, clip_width + 1, tab_height - 3)
1930 tabPoints = [wx.Point() for i in xrange(7)]
1936 agwFlags = self.GetAGWFlags()
1938 tabPoints[0].x = tab_x + 3
1939 tabPoints[0].y = (agwFlags & AUI_NB_BOTTOM and [3] or [tab_height - 2])[0]
1941 tabPoints[1].x = tabPoints[0].x
1942 tabPoints[1].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - (vertical_border_padding + 2) - adjust] or \
1943 [(vertical_border_padding + 2) + adjust])[0]
1945 tabPoints[2].x = tabPoints[1].x+2
1946 tabPoints[2].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - vertical_border_padding - adjust] or \
1947 [vertical_border_padding + adjust])[0]
1949 tabPoints[3].x = tab_x + tab_width - 2
1950 tabPoints[3].y = tabPoints[2].y
1952 tabPoints[4].x = tabPoints[3].x + 2
1953 tabPoints[4].y = tabPoints[1].y
1955 tabPoints[5].x = tabPoints[4].x
1956 tabPoints[5].y = tabPoints[0].y
1958 tabPoints[6].x = tabPoints[0].x
1959 tabPoints[6].y = tabPoints[0].y
1961 rr = wx.RectPP(tabPoints[2], tabPoints[5])
1962 self.DrawTabBackground(dc, rr, page.active, (agwFlags & AUI_NB_BOTTOM) == 0)
1964 dc.SetBrush(wx.TRANSPARENT_BRUSH)
1965 dc.SetPen(wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNSHADOW)))
1967 # Draw the tab as rounded rectangle
1968 dc.DrawPolygon(tabPoints)
1971 dc.DrawLine(tabPoints[0].x + 1, tabPoints[0].y, tabPoints[5].x , tabPoints[0].y)
1973 drawn_tab_yoff = tabPoints[1].y
1974 drawn_tab_height = tabPoints[0].y - tabPoints[2].y
1976 text_offset = tab_x + 8
1977 close_button_width = 0
1978 if close_button_state != AUI_BUTTON_STATE_HIDDEN:
1979 close_button_width = self._active_close_bmp.GetWidth()
1980 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
1981 text_offset += close_button_width - 4
1983 if not page.enabled:
1984 dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
1985 pagebitmap = page.dis_bitmap
1987 dc.SetTextForeground(page.text_colour)
1988 pagebitmap = page.bitmap
1991 if agwFlags & AUI_NB_BOTTOM:
1995 if pagebitmap.IsOk():
1996 bitmap_offset = tab_x + 8
1997 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width:
1998 bitmap_offset += close_button_width - 4
2001 dc.DrawBitmap(pagebitmap, bitmap_offset,
2002 drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2) + shift,
2005 text_offset = bitmap_offset + pagebitmap.GetWidth()
2006 text_offset += 3 # bitmap padding
2010 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width:
2011 text_offset = tab_x + 8
2013 # if the caption is empty, measure some temporary text
2014 caption = page.caption
2019 dc.SetFont(self._selected_font)
2020 textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
2022 dc.SetFont(self._normal_font)
2023 textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
2025 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
2026 draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width + 1)
2028 draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width)
2030 ypos = drawn_tab_yoff + drawn_tab_height/2 - texty/2 - 1 + shift
2032 offset_focus = text_offset
2034 if control is not None:
2035 if control.GetPosition() != wx.Point(text_offset+1, ypos):
2036 control.SetPosition(wx.Point(text_offset+1, ypos))
2038 if not control.IsShown():
2042 bmp = TakeScreenShot(control.GetScreenRect())
2043 dc.DrawBitmap(bmp, text_offset+1, ypos, True)
2045 controlW, controlH = control.GetSize()
2046 text_offset += controlW + 4
2047 textx += controlW + 4
2050 rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text)
2051 dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty))
2053 # draw focus rectangle
2054 if (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0:
2055 self.DrawFocusRectangle(dc, page, wnd, draw_text, offset_focus, bitmap_offset, drawn_tab_yoff+shift,
2056 drawn_tab_height, rectx, recty)
2058 out_button_rect = wx.Rect()
2059 # draw 'x' on tab (if enabled)
2060 if close_button_state != AUI_BUTTON_STATE_HIDDEN:
2062 close_button_width = self._active_close_bmp.GetWidth()
2063 bmp = self._disabled_close_bmp
2065 if close_button_state == AUI_BUTTON_STATE_HOVER:
2066 bmp = self._hover_close_bmp
2067 elif close_button_state == AUI_BUTTON_STATE_PRESSED:
2068 bmp = self._pressed_close_bmp
2070 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
2071 rect = wx.Rect(tab_x + 5,
2072 drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift,
2073 close_button_width, tab_height)
2075 rect = wx.Rect(tab_x + tab_width - close_button_width - 3,
2076 drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift,
2077 close_button_width, tab_height)
2079 # Indent the button if it is pressed down:
2080 rect = IndentPressedBitmap(rect, close_button_state)
2081 dc.DrawBitmap(bmp, rect.x, rect.y, True)
2082 out_button_rect = rect
2084 out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height)
2085 dc.DestroyClippingRegion()
2087 return out_tab_rect, out_button_rect, x_extent
2090 def DrawTabBackground(self, dc, rect, focus, upperTabs):
2092 Draws the tab background for the Firefox 2 style.
2093 This is more consistent with L{FlatNotebook} than before.
2095 :param `dc`: a `wx.DC` device context;
2096 :param `rect`: rectangle the tab should be confined to;
2097 :param `focus`: whether the tab has focus or not;
2098 :param `upperTabs`: whether the style is ``AUI_NB_TOP`` or ``AUI_NB_BOTTOM``.
2101 # Define the rounded rectangle base on the given rect
2102 # we need an array of 9 points for it
2103 regPts = [wx.Point() for indx in xrange(9)]
2107 leftPt = wx.Point(rect.x, rect.y + (rect.height / 10)*8)
2108 rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 10)*8)
2110 leftPt = wx.Point(rect.x, rect.y + (rect.height / 10)*5)
2111 rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 10)*5)
2113 leftPt = wx.Point(rect.x, rect.y + (rect.height / 2))
2114 rightPt = wx.Point(rect.x + rect.width - 2, rect.y + (rect.height / 2))
2116 # Define the top region
2117 top = wx.RectPP(rect.GetTopLeft(), rightPt)
2118 bottom = wx.RectPP(leftPt, rect.GetBottomRight())
2120 topStartColour = wx.WHITE
2123 topStartColour = LightColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE), 50)
2125 topEndColour = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)
2126 bottomStartColour = topEndColour
2127 bottomEndColour = topEndColour
2129 # Incase we use bottom tabs, switch the colours
2132 dc.GradientFillLinear(top, topStartColour, topEndColour, wx.SOUTH)
2133 dc.GradientFillLinear(bottom, bottomStartColour, bottomEndColour, wx.SOUTH)
2135 dc.GradientFillLinear(top, topEndColour , topStartColour, wx.SOUTH)
2136 dc.GradientFillLinear(bottom, bottomStartColour, bottomEndColour, wx.SOUTH)
2140 dc.GradientFillLinear(bottom, topEndColour, bottomEndColour, wx.SOUTH)
2141 dc.GradientFillLinear(top, topStartColour, topStartColour, wx.SOUTH)
2143 dc.GradientFillLinear(bottom, bottomStartColour, bottomEndColour, wx.SOUTH)
2144 dc.GradientFillLinear(top, topEndColour, topStartColour, wx.SOUTH)
2146 dc.SetBrush(wx.TRANSPARENT_BRUSH)
2149 class VC8TabArt(AuiDefaultTabArt):
2150 """ A class to draw tabs using the Visual Studio 2005 (VC8) style. """
2153 """ Default class constructor. """
2155 AuiDefaultTabArt.__init__(self)
2159 """ Clones the art object. """
2162 art.SetNormalFont(self.GetNormalFont())
2163 art.SetSelectedFont(self.GetSelectedFont())
2164 art.SetMeasuringFont(self.GetMeasuringFont())
2166 art = CopyAttributes(art, self)
2170 def SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth):
2172 Sets the tab sizing information.
2174 :param `tab_ctrl_size`: the size of the tab control area;
2175 :param `tab_count`: the number of tabs;
2176 :param `minMaxTabWidth`: a tuple containing the minimum and maximum tab widths
2177 to be used when the ``AUI_NB_TAB_FIXED_WIDTH`` style is active.
2180 AuiDefaultTabArt.SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth)
2182 minTabWidth, maxTabWidth = minMaxTabWidth
2183 if minTabWidth > -1:
2184 self._fixed_tab_width = max(self._fixed_tab_width, minTabWidth)
2185 if maxTabWidth > -1:
2186 self._fixed_tab_width = min(self._fixed_tab_width, maxTabWidth)
2188 self._fixed_tab_width -= 5
2191 def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control=None):
2193 Returns the tab size for the given caption, bitmap and button state.
2195 :param `dc`: a `wx.DC` device context;
2196 :param `wnd`: a `wx.Window` instance object;
2197 :param `caption`: the tab text caption;
2198 :param `bitmap`: the bitmap displayed on the tab;
2199 :param `active`: whether the tab is selected or not;
2200 :param `close_button_state`: the state of the close button on the tab;
2201 :param `control`: a `wx.Window` instance inside a tab (or ``None``).
2204 tab_size, x_extent = AuiDefaultTabArt.GetTabSize(self, dc, wnd, caption, bitmap,
2205 active, close_button_state, control)
2207 tab_width, tab_height = tab_size
2213 return (tab_width, tab_height), x_extent
2216 def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False):
2220 :param `dc`: a `wx.DC` device context;
2221 :param `wnd`: a `wx.Window` instance object;
2222 :param `page`: the tab control page associated with the tab;
2223 :param `in_rect`: rectangle the tab should be confined to;
2224 :param `close_button_state`: the state of the close button on the tab;
2225 :param `paint_control`: whether to draw the control inside a tab (if any) on a `wx.MemoryDC`.
2228 # Visual Studio 8 style
2230 control = page.control
2232 # figure out the size of the tab
2233 tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap,
2234 page.active, close_button_state, control)
2236 tab_height = self._tab_ctrl_height - 1
2237 tab_width = tab_size[0]
2239 tab_y = in_rect.y + in_rect.height - tab_height
2241 clip_width = tab_width + 3
2242 if tab_x + clip_width > in_rect.x + in_rect.width - 4:
2243 clip_width = (in_rect.x + in_rect.width) - tab_x - 4
2245 tabPoints = [wx.Point() for i in xrange(8)]
2247 # If we draw the first tab or the active tab,
2248 # we draw a full tab, else we draw a truncated tab
2263 agwFlags = self.GetAGWFlags()
2264 tabPoints[0].x = (agwFlags & AUI_NB_BOTTOM and [tab_x] or [tab_x + adjust])[0]
2265 tabPoints[0].y = (agwFlags & AUI_NB_BOTTOM and [2] or [tab_height - 3])[0]
2267 tabPoints[1].x = tabPoints[0].x + tab_height - vertical_border_padding - 3 - adjust
2268 tabPoints[1].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - (vertical_border_padding+2)] or \
2269 [(vertical_border_padding+2)])[0]
2271 tabPoints[2].x = tabPoints[1].x + 4
2272 tabPoints[2].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - vertical_border_padding] or \
2273 [vertical_border_padding])[0]
2275 tabPoints[3].x = tabPoints[2].x + tab_width - tab_height + vertical_border_padding
2276 tabPoints[3].y = (agwFlags & AUI_NB_BOTTOM and [tab_height - vertical_border_padding] or \
2277 [vertical_border_padding])[0]
2279 tabPoints[4].x = tabPoints[3].x + 1
2280 tabPoints[4].y = (agwFlags & AUI_NB_BOTTOM and [tabPoints[3].y - 1] or [tabPoints[3].y + 1])[0]
2282 tabPoints[5].x = tabPoints[4].x + 1
2283 tabPoints[5].y = (agwFlags & AUI_NB_BOTTOM and [(tabPoints[4].y - 1)] or [tabPoints[4].y + 1])[0]
2285 tabPoints[6].x = tabPoints[2].x + tab_width - tab_height + 2 + vertical_border_padding
2286 tabPoints[6].y = tabPoints[0].y
2288 tabPoints[7].x = tabPoints[0].x
2289 tabPoints[7].y = tabPoints[0].y
2291 self.FillVC8GradientColour(dc, tabPoints, page.active)
2293 dc.SetBrush(wx.TRANSPARENT_BRUSH)
2295 dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_BTNSHADOW)))
2296 dc.DrawPolygon(tabPoints)
2299 # Delete the bottom line (or the upper one, incase we use wxBOTTOM)
2300 dc.SetPen(wx.WHITE_PEN)
2301 dc.DrawLine(tabPoints[0].x, tabPoints[0].y, tabPoints[6].x, tabPoints[6].y)
2303 dc.SetClippingRegion(tab_x, tab_y, clip_width + 2, tab_height - 3)
2305 drawn_tab_yoff = tabPoints[1].y
2306 drawn_tab_height = tabPoints[0].y - tabPoints[2].y
2308 text_offset = tab_x + 20
2309 close_button_width = 0
2310 if close_button_state != AUI_BUTTON_STATE_HIDDEN:
2311 close_button_width = self._active_close_bmp.GetWidth()
2312 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
2313 text_offset += close_button_width
2315 if not page.enabled:
2316 dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
2317 pagebitmap = page.dis_bitmap
2319 dc.SetTextForeground(page.text_colour)
2320 pagebitmap = page.bitmap
2323 if agwFlags & AUI_NB_BOTTOM:
2324 shift = (page.active and [1] or [2])[0]
2327 if pagebitmap.IsOk():
2328 bitmap_offset = tab_x + 20
2329 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width:
2330 bitmap_offset += close_button_width
2333 dc.DrawBitmap(pagebitmap, bitmap_offset,
2334 drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2) + shift,
2337 text_offset = bitmap_offset + pagebitmap.GetWidth()
2338 text_offset += 3 # bitmap padding
2341 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width:
2342 text_offset = tab_x + tab_height
2344 # if the caption is empty, measure some temporary text
2345 caption = page.caption
2350 dc.SetFont(self._selected_font)
2351 textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
2353 dc.SetFont(self._normal_font)
2354 textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
2356 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
2357 draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x))
2359 draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width)
2361 ypos = drawn_tab_yoff + drawn_tab_height/2 - texty/2 - 1 + shift
2363 offset_focus = text_offset
2365 if control is not None:
2366 if control.GetPosition() != wx.Point(text_offset+1, ypos):
2367 control.SetPosition(wx.Point(text_offset+1, ypos))
2369 if not control.IsShown():
2373 bmp = TakeScreenShot(control.GetScreenRect())
2374 dc.DrawBitmap(bmp, text_offset+1, ypos, True)
2376 controlW, controlH = control.GetSize()
2377 text_offset += controlW + 4
2378 textx += controlW + 4
2381 rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text)
2382 dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty))
2384 # draw focus rectangle
2385 if (agwFlags & AUI_NB_NO_TAB_FOCUS) == 0:
2386 self.DrawFocusRectangle(dc, page, wnd, draw_text, offset_focus, bitmap_offset, drawn_tab_yoff+shift,
2387 drawn_tab_height+shift, rectx, recty)
2389 out_button_rect = wx.Rect()
2390 # draw 'x' on tab (if enabled)
2391 if close_button_state != AUI_BUTTON_STATE_HIDDEN:
2393 close_button_width = self._active_close_bmp.GetWidth()
2394 bmp = self._disabled_close_bmp
2396 if close_button_state == AUI_BUTTON_STATE_HOVER:
2397 bmp = self._hover_close_bmp
2398 elif close_button_state == AUI_BUTTON_STATE_PRESSED:
2399 bmp = self._pressed_close_bmp
2402 xpos = tab_x + tab_width - close_button_width + 3
2404 xpos = tab_x + tab_width - close_button_width - 5
2406 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
2407 rect = wx.Rect(tab_x + 20,
2408 drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift,
2409 close_button_width, tab_height)
2411 rect = wx.Rect(xpos,
2412 drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + shift,
2413 close_button_width, tab_height)
2415 # Indent the button if it is pressed down:
2416 rect = IndentPressedBitmap(rect, close_button_state)
2417 dc.DrawBitmap(bmp, rect.x, rect.y, True)
2418 out_button_rect = rect
2420 out_tab_rect = wx.Rect(tab_x, tab_y, x_extent, tab_height)
2421 dc.DestroyClippingRegion()
2423 return out_tab_rect, out_button_rect, x_extent
2426 def FillVC8GradientColour(self, dc, tabPoints, active):
2428 Fills the tab with the Visual Studio 2005 gradient background.
2430 :param `dc`: a `wx.DC` device context;
2431 :param `tabPoints`: a list of `wx.Point` objects describing the tab shape;
2432 :param `active`: whether the tab is selected or not.
2435 xList = [pt.x for pt in tabPoints]
2436 yList = [pt.y for pt in tabPoints]
2438 minx, maxx = min(xList), max(xList)
2439 miny, maxy = min(yList), max(yList)
2441 rect = wx.Rect(minx, maxy, maxx-minx, miny-maxy+1)
2442 region = wx.RegionFromPoints(tabPoints)
2444 if self._buttonRect.width > 0:
2445 buttonRegion = wx.Region(*self._buttonRect)
2446 region.XorRegion(buttonRegion)
2448 dc.SetClippingRegionAsRegion(region)
2451 bottom_colour = top_colour = wx.WHITE
2453 bottom_colour = StepColour(self._base_colour, 90)
2454 top_colour = StepColour(self._base_colour, 170)
2456 dc.GradientFillLinear(rect, top_colour, bottom_colour, wx.SOUTH)
2457 dc.DestroyClippingRegion()
2460 class ChromeTabArt(AuiDefaultTabArt):
2462 A class to draw tabs using the Google Chrome browser style.
2463 It uses custom bitmap to render the tabs, so that the look and feel is as close
2464 as possible to the Chrome style.
2468 """ Default class constructor. """
2470 AuiDefaultTabArt.__init__(self)
2472 self.SetBitmaps(mirror=False)
2474 closeBmp = tab_close.GetBitmap()
2475 closeHBmp = tab_close_h.GetBitmap()
2476 closePBmp = tab_close_p.GetBitmap()
2478 self.SetCustomButton(AUI_BUTTON_CLOSE, AUI_BUTTON_STATE_NORMAL, closeBmp)
2479 self.SetCustomButton(AUI_BUTTON_CLOSE, AUI_BUTTON_STATE_HOVER, closeHBmp)
2480 self.SetCustomButton(AUI_BUTTON_CLOSE, AUI_BUTTON_STATE_PRESSED, closePBmp)
2483 def SetAGWFlags(self, agwFlags):
2485 Sets the tab art flags.
2487 :param `agwFlags`: a combination of the following values:
2489 ==================================== ==================================
2490 Flag name Description
2491 ==================================== ==================================
2492 ``AUI_NB_TOP`` With this style, tabs are drawn along the top of the notebook
2493 ``AUI_NB_LEFT`` With this style, tabs are drawn along the left of the notebook. Not implemented yet.
2494 ``AUI_NB_RIGHT`` With this style, tabs are drawn along the right of the notebook. Not implemented yet.
2495 ``AUI_NB_BOTTOM`` With this style, tabs are drawn along the bottom of the notebook
2496 ``AUI_NB_TAB_SPLIT`` Allows the tab control to be split by dragging a tab
2497 ``AUI_NB_TAB_MOVE`` Allows a tab to be moved horizontally by dragging
2498 ``AUI_NB_TAB_EXTERNAL_MOVE`` Allows a tab to be moved to another tab control
2499 ``AUI_NB_TAB_FIXED_WIDTH`` With this style, all tabs have the same width
2500 ``AUI_NB_SCROLL_BUTTONS`` With this style, left and right scroll buttons are displayed
2501 ``AUI_NB_WINDOWLIST_BUTTON`` With this style, a drop-down list of windows is available
2502 ``AUI_NB_CLOSE_BUTTON`` With this style, a close button is available on the tab bar
2503 ``AUI_NB_CLOSE_ON_ACTIVE_TAB`` With this style, a close button is available on the active tab
2504 ``AUI_NB_CLOSE_ON_ALL_TABS`` With this style, a close button is available on all tabs
2505 ``AUI_NB_MIDDLE_CLICK_CLOSE`` Allows to close L{AuiNotebook} tabs by mouse middle button click
2506 ``AUI_NB_SUB_NOTEBOOK`` This style is used by L{AuiManager} to create automatic AuiNotebooks
2507 ``AUI_NB_HIDE_ON_SINGLE_TAB`` Hides the tab window if only one tab is present
2508 ``AUI_NB_SMART_TABS`` Use Smart Tabbing, like ``Alt`` + ``Tab`` on Windows
2509 ``AUI_NB_USE_IMAGES_DROPDOWN`` Uses images on dropdown window list menu instead of check items
2510 ``AUI_NB_CLOSE_ON_TAB_LEFT`` Draws the tab close button on the left instead of on the right (a la Camino browser)
2511 ``AUI_NB_TAB_FLOAT`` Allows the floating of single tabs. Known limitation: when the notebook is more or less full screen, tabs cannot be dragged far enough outside of the notebook to become floating pages
2512 ``AUI_NB_DRAW_DND_TAB`` Draws an image representation of a tab while dragging (on by default)
2513 ``AUI_NB_ORDER_BY_ACCESS`` Tab navigation order by last access time for the tabs
2514 ``AUI_NB_NO_TAB_FOCUS`` Don't draw tab focus rectangle
2515 ==================================== ==================================
2517 :note: Overridden from L{AuiDefaultTabArt}.
2520 if agwFlags & AUI_NB_TOP:
2521 self.SetBitmaps(mirror=False)
2522 elif agwFlags & AUI_NB_BOTTOM:
2523 self.SetBitmaps(mirror=True)
2525 AuiDefaultTabArt.SetAGWFlags(self, agwFlags)
2528 def SetBitmaps(self, mirror):
2530 Assigns the tab custom bitmaps
2532 :param `mirror`: whether to vertically mirror the bitmap or not.
2535 bmps = [tab_active_left.GetBitmap(), tab_active_center.GetBitmap(),
2536 tab_active_right.GetBitmap(), tab_inactive_left.GetBitmap(),
2537 tab_inactive_center.GetBitmap(), tab_inactive_right.GetBitmap()]
2540 for indx, bmp in enumerate(bmps):
2541 img = bmp.ConvertToImage()
2542 img = img.Mirror(horizontally=False)
2543 bmps[indx] = img.ConvertToBitmap()
2545 self._leftActiveBmp = bmps[0]
2546 self._centerActiveBmp = bmps[1]
2547 self._rightActiveBmp = bmps[2]
2548 self._leftInactiveBmp = bmps[3]
2549 self._centerInactiveBmp = bmps[4]
2550 self._rightInactiveBmp = bmps[5]
2554 """ Clones the art object. """
2557 art.SetNormalFont(self.GetNormalFont())
2558 art.SetSelectedFont(self.GetSelectedFont())
2559 art.SetMeasuringFont(self.GetMeasuringFont())
2561 art = CopyAttributes(art, self)
2565 def SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth):
2567 Sets the tab sizing information.
2569 :param `tab_ctrl_size`: the size of the tab control area;
2570 :param `tab_count`: the number of tabs;
2571 :param `minMaxTabWidth`: a tuple containing the minimum and maximum tab widths
2572 to be used when the ``AUI_NB_TAB_FIXED_WIDTH`` style is active.
2575 AuiDefaultTabArt.SetSizingInfo(self, tab_ctrl_size, tab_count, minMaxTabWidth)
2577 minTabWidth, maxTabWidth = minMaxTabWidth
2578 if minTabWidth > -1:
2579 self._fixed_tab_width = max(self._fixed_tab_width, minTabWidth)
2580 if maxTabWidth > -1:
2581 self._fixed_tab_width = min(self._fixed_tab_width, maxTabWidth)
2583 self._fixed_tab_width -= 5
2586 def GetTabSize(self, dc, wnd, caption, bitmap, active, close_button_state, control=None):
2588 Returns the tab size for the given caption, bitmap and button state.
2590 :param `dc`: a `wx.DC` device context;
2591 :param `wnd`: a `wx.Window` instance object;
2592 :param `caption`: the tab text caption;
2593 :param `bitmap`: the bitmap displayed on the tab;
2594 :param `active`: whether the tab is selected or not;
2595 :param `close_button_state`: the state of the close button on the tab;
2596 :param `control`: a `wx.Window` instance inside a tab (or ``None``).
2599 tab_size, x_extent = AuiDefaultTabArt.GetTabSize(self, dc, wnd, caption, bitmap,
2600 active, close_button_state, control)
2602 tab_width, tab_height = tab_size
2605 tab_width += self._leftActiveBmp.GetWidth()
2608 tab_height = max(tab_height, self._centerActiveBmp.GetHeight())
2610 return (tab_width, tab_height), x_extent
2613 def DrawTab(self, dc, wnd, page, in_rect, close_button_state, paint_control=False):
2617 :param `dc`: a `wx.DC` device context;
2618 :param `wnd`: a `wx.Window` instance object;
2619 :param `page`: the tab control page associated with the tab;
2620 :param `in_rect`: rectangle the tab should be confined to;
2621 :param `close_button_state`: the state of the close button on the tab;
2622 :param `paint_control`: whether to draw the control inside a tab (if any) on a `wx.MemoryDC`.
2627 control = page.control
2628 # figure out the size of the tab
2629 tab_size, x_extent = self.GetTabSize(dc, wnd, page.caption, page.bitmap, page.active,
2630 close_button_state, control)
2632 agwFlags = self.GetAGWFlags()
2634 tab_height = self._tab_ctrl_height - 1
2635 tab_width = tab_size[0]
2637 tab_y = in_rect.y + in_rect.height - tab_height
2638 clip_width = tab_width
2640 if tab_x + clip_width > in_rect.x + in_rect.width - 4:
2641 clip_width = (in_rect.x + in_rect.width) - tab_x - 4
2643 dc.SetClippingRegion(tab_x, tab_y, clip_width + 1, tab_height - 3)
2647 left = self._leftActiveBmp
2648 center = self._centerActiveBmp
2649 right = self._rightActiveBmp
2651 left = self._leftInactiveBmp
2652 center = self._centerInactiveBmp
2653 right = self._rightInactiveBmp
2655 dc.DrawBitmap(left, tab_x, tab_y)
2656 leftw = left.GetWidth()
2657 centerw = center.GetWidth()
2658 rightw = right.GetWidth()
2660 available = tab_x + tab_width - rightw
2661 posx = tab_x + leftw
2664 if posx >= available:
2666 dc.DrawBitmap(center, posx, tab_y)
2669 dc.DrawBitmap(right, posx, tab_y)
2671 drawn_tab_height = center.GetHeight()
2672 text_offset = tab_x + leftw
2674 close_button_width = 0
2675 if close_button_state != AUI_BUTTON_STATE_HIDDEN:
2676 close_button_width = self._active_close_bmp.GetWidth()
2677 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
2678 text_offset += close_button_width
2680 if not page.enabled:
2681 dc.SetTextForeground(wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT))
2682 pagebitmap = page.dis_bitmap
2684 dc.SetTextForeground(page.text_colour)
2685 pagebitmap = page.bitmap
2688 if pagebitmap.IsOk():
2689 bitmap_offset = tab_x + leftw
2690 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT and close_button_width:
2691 bitmap_offset += close_button_width
2694 dc.DrawBitmap(pagebitmap, bitmap_offset,
2695 drawn_tab_yoff + (drawn_tab_height/2) - (pagebitmap.GetHeight()/2),
2698 text_offset = bitmap_offset + pagebitmap.GetWidth()
2699 text_offset += 3 # bitmap padding
2703 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT == 0 or not close_button_width:
2704 text_offset = tab_x + leftw
2706 # if the caption is empty, measure some temporary text
2707 caption = page.caption
2712 dc.SetFont(self._selected_font)
2713 textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
2715 dc.SetFont(self._normal_font)
2716 textx, texty, dummy = dc.GetMultiLineTextExtent(caption)
2718 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
2719 draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - leftw)
2721 draw_text = ChopText(dc, caption, tab_width - (text_offset-tab_x) - close_button_width - leftw)
2723 ypos = drawn_tab_yoff + drawn_tab_height/2 - texty/2 - 1
2725 if control is not None:
2726 if control.GetPosition() != wx.Point(text_offset+1, ypos):
2727 control.SetPosition(wx.Point(text_offset+1, ypos))
2729 if not control.IsShown():
2733 bmp = TakeScreenShot(control.GetScreenRect())
2734 dc.DrawBitmap(bmp, text_offset+1, ypos, True)
2736 controlW, controlH = control.GetSize()
2737 text_offset += controlW + 4
2740 rectx, recty, dummy = dc.GetMultiLineTextExtent(draw_text)
2741 dc.DrawLabel(draw_text, wx.Rect(text_offset, ypos, rectx, recty))
2743 out_button_rect = wx.Rect()
2744 # draw 'x' on tab (if enabled)
2745 if close_button_state != AUI_BUTTON_STATE_HIDDEN:
2747 close_button_width = self._active_close_bmp.GetWidth()
2748 bmp = self._disabled_close_bmp
2750 if close_button_state == AUI_BUTTON_STATE_HOVER:
2751 bmp = self._hover_close_bmp
2752 elif close_button_state == AUI_BUTTON_STATE_PRESSED:
2753 bmp = self._pressed_close_bmp
2755 if agwFlags & AUI_NB_CLOSE_ON_TAB_LEFT:
2756 rect = wx.Rect(tab_x + leftw - 2,
2757 drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + 1,
2758 close_button_width, tab_height)
2760 rect = wx.Rect(tab_x + tab_width - close_button_width - rightw + 2,
2761 drawn_tab_yoff + (drawn_tab_height / 2) - (bmp.GetHeight() / 2) + 1,
2762 close_button_width, tab_height)
2764 if agwFlags & AUI_NB_BOTTOM:
2767 # Indent the button if it is pressed down:
2768 rect = IndentPressedBitmap(rect, close_button_state)
2769 dc.DrawBitmap(bmp, rect.x, rect.y, True)
2770 out_button_rect = rect
2772 out_tab_rect = wx.Rect(tab_x, tab_y, tab_width, tab_height)
2773 dc.DestroyClippingRegion()
2775 return out_tab_rect, out_button_rect, x_extent