1# -*- coding: utf-8 -*- 2#---------------------------------------------------------------------------- 3# Name: art_aui.py 4# Purpose: 5# 6# Author: Andrea Gavana <andrea.gavana@gmail.com> 7# 8# Created: 9# Version: 10# Date: 11# Licence: wxWindows license 12# Tags: phoenix-port, unittest, documented, py3-port 13#---------------------------------------------------------------------------- 14""" 15`art_aui` is responsible for drawing all the components of the ribbon 16interface using an AUI-compatible appearance. 17 18 19Description 20=========== 21 22This allows a ribbon bar to have a pluggable look-and-feel, while retaining the same 23underlying behaviour. As a single art provider is used for all ribbon components, a 24ribbon bar usually has a consistent (though unique) appearance. 25 26By default, a :class:`~wx.lib.agw.ribbon.bar.RibbonBar` uses an instance of a class called 27:class:`~wx.lib.agw.ribbon.art_default.RibbonDefaultArtProvider`, 28which resolves to :class:`~wx.lib.agw.ribbon.art_aui.RibbonAUIArtProvider`, 29:class:`~wx.lib.agw.ribbon.art_msw.RibbonMSWArtProvider`, or 30:class:`~wx.lib.agw.ribbon.art_osx.RibbonOSXArtProvider` - whichever is most appropriate 31to the current platform. These art providers are all 32slightly configurable with regard to colours and fonts, but for larger modifications, 33you can derive from one of these classes, or write a completely new art provider class. 34 35Call :meth:`RibbonBar.SetArtProvider() <lib.agw.ribbon.bar.RibbonBar.SetArtProvider>` to change the art provider being used. 36 37 38See Also 39======== 40 41:class:`~wx.lib.agw.ribbon.bar.RibbonBar` 42""" 43 44import wx 45 46from math import cos 47from math import pi as M_PI 48 49from .art_msw import RibbonMSWArtProvider 50from .art_internal import RibbonHSLColour, RibbonShiftLuminance, RibbonInterpolateColour 51 52from . import bar as BAR, panel as PANEL 53 54from .art import * 55 56if wx.Platform == "__WXMAC__": 57 try: 58 import Carbon.Appearance 59 except ImportError: 60 CARBON = False 61 else: 62 CARBON = True 63 64 65def FontFromFont(original): 66 67 newFont = wx.Font(original.GetPointSize(), original.GetFamily(), 68 original.GetStyle(), original.GetWeight(), original.GetUnderlined(), 69 original.GetFaceName(), original.GetEncoding()) 70 71 return newFont 72 73 74class RibbonAUIArtProvider(RibbonMSWArtProvider): 75 76 def __init__(self): 77 78 RibbonMSWArtProvider.__init__(self) 79 80 if wx.Platform == "__WXMAC__": 81 k = Carbon.Appearance.kThemeBrushToolbarBackground if CARBON else 52 82 if hasattr(wx, 'MacThemeColour'): 83 base_colour = wx.MacThemeColour(k) 84 else: 85 brush = wx.Brush(wx.BLACK) 86 brush.MacSetTheme(k) 87 base_colour = brush.GetColour() 88 else: 89 90 base_colour = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE) 91 92 self.SetColourScheme(base_colour, wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHT), 93 wx.SystemSettings.GetColour(wx.SYS_COLOUR_HIGHLIGHTTEXT)) 94 95 self._tab_active_label_font = FontFromFont(self._tab_label_font) 96 self._tab_active_label_font.SetWeight(wx.FONTWEIGHT_BOLD) 97 98 self._page_border_left = 1 99 self._page_border_right = 1 100 self._page_border_top = 1 101 self._page_border_bottom = 2 102 self._tab_separation_size = 0 103 104 self._gallery_bitmap_padding_left_size = 3 105 self._gallery_bitmap_padding_right_size = 3 106 self._gallery_bitmap_padding_top_size = 3 107 self._gallery_bitmap_padding_bottom_size = 3 108 109 110 def Clone(self): 111 """ 112 Create a new art provider which is a clone of this one. 113 """ 114 115 copy = RibbonAUIArtProvider() 116 self.CloneTo(copy) 117 118 copy._tab_ctrl_background_colour = self._tab_ctrl_background_colour 119 copy._tab_ctrl_background_gradient_colour = self._tab_ctrl_background_gradient_colour 120 copy._panel_label_background_colour = self._panel_label_background_colour 121 copy._panel_label_background_gradient_colour = self._panel_label_background_gradient_colour 122 copy._panel_hover_label_background_colour = self._panel_hover_label_background_colour 123 copy._panel_hover_label_background_gradient_colour = self._panel_hover_label_background_gradient_colour 124 125 copy._background_brush = self._background_brush 126 copy._tab_active_top_background_brush = self._tab_active_top_background_brush 127 copy._tab_hover_background_brush = self._tab_hover_background_brush 128 copy._button_bar_hover_background_brush = self._button_bar_hover_background_brush 129 copy._button_bar_active_background_brush = self._button_bar_active_background_brush 130 copy._gallery_button_active_background_brush = self._gallery_button_active_background_brush 131 copy._gallery_button_hover_background_brush = self._gallery_button_hover_background_brush 132 copy._gallery_button_disabled_background_brush = self._gallery_button_disabled_background_brush 133 134 copy._toolbar_hover_borden_pen = self._toolbar_hover_borden_pen 135 copy._tool_hover_background_brush = self._tool_hover_background_brush 136 copy._tool_active_background_brush = self._tool_active_background_brush 137 138 return copy 139 140 141 def SetFont(self, id, font): 142 """ 143 Set the value of a certain font setting to the value. 144 145 can be one of the font values of `RibbonArtSetting`. 146 147 :param `id`: the font id; 148 :param `font`: MISSING DESCRIPTION. 149 150 """ 151 152 RibbonMSWArtProvider.SetFont(self, id, font) 153 154 if id == RIBBON_ART_TAB_LABEL_FONT: 155 self._tab_active_label_font = FontFromFont(self._tab_label_font) 156 self._tab_active_label_font.SetWeight(wx.FONTWEIGHT_BOLD) 157 158 159 def GetColour(self, id): 160 """ 161 Get the value of a certain colour setting. 162 163 can be one of the colour values of `RibbonArtSetting`. 164 165 :param `id`: the colour id. 166 167 """ 168 169 if id in [RIBBON_ART_PAGE_BACKGROUND_COLOUR, RIBBON_ART_PAGE_BACKGROUND_GRADIENT_COLOUR]: 170 return self._background_brush.GetColour() 171 elif id == RIBBON_ART_TAB_CTRL_BACKGROUND_COLOUR: 172 return self._tab_ctrl_background_colour 173 elif id == RIBBON_ART_TAB_CTRL_BACKGROUND_GRADIENT_COLOUR: 174 return self._tab_ctrl_background_gradient_colour 175 elif id in [RIBBON_ART_TAB_ACTIVE_BACKGROUND_TOP_COLOUR, RIBBON_ART_TAB_ACTIVE_BACKGROUND_TOP_GRADIENT_COLOUR]: 176 return self._tab_active_top_background_brush.GetColour() 177 elif id in [RIBBON_ART_TAB_HOVER_BACKGROUND_COLOUR, RIBBON_ART_TAB_HOVER_BACKGROUND_GRADIENT_COLOUR]: 178 return self._tab_hover_background_brush.GetColour() 179 elif id == RIBBON_ART_PANEL_LABEL_BACKGROUND_COLOUR: 180 return self._panel_label_background_colour 181 elif id == RIBBON_ART_PANEL_LABEL_BACKGROUND_GRADIENT_COLOUR: 182 return self._panel_label_background_gradient_colour 183 elif id == RIBBON_ART_PANEL_HOVER_LABEL_BACKGROUND_COLOUR: 184 return self._panel_hover_label_background_colour 185 elif id == RIBBON_ART_PANEL_HOVER_LABEL_BACKGROUND_GRADIENT_COLOUR: 186 return self._panel_hover_label_background_gradient_colour 187 elif id in [RIBBON_ART_BUTTON_BAR_HOVER_BACKGROUND_COLOUR, RIBBON_ART_BUTTON_BAR_HOVER_BACKGROUND_GRADIENT_COLOUR]: 188 return self._button_bar_hover_background_brush.GetColour() 189 elif id in [RIBBON_ART_GALLERY_BUTTON_HOVER_BACKGROUND_COLOUR, RIBBON_ART_GALLERY_BUTTON_HOVER_BACKGROUND_GRADIENT_COLOUR]: 190 return self._gallery_button_hover_background_brush.GetColour() 191 elif id in [RIBBON_ART_GALLERY_BUTTON_ACTIVE_BACKGROUND_COLOUR, RIBBON_ART_GALLERY_BUTTON_ACTIVE_BACKGROUND_GRADIENT_COLOUR]: 192 return self._gallery_button_active_background_brush.GetColour() 193 elif id in [RIBBON_ART_GALLERY_BUTTON_DISABLED_BACKGROUND_COLOUR, RIBBON_ART_GALLERY_BUTTON_DISABLED_BACKGROUND_GRADIENT_COLOUR]: 194 return self._gallery_button_disabled_background_brush.GetColour() 195 else: 196 return RibbonMSWArtProvider.GetColour(self, id) 197 198 199 def SetColour(self, id, colour): 200 """ 201 Set the value of a certain colour setting to the value. 202 203 can be one of the colour values of `RibbonArtSetting`, though not all colour 204 settings will have an affect on every art provider. 205 206 :param `id`: the colour id; 207 :param `colour`: MISSING DESCRIPTION. 208 209 :see: :meth:`~RibbonAUIArtProvider.SetColourScheme` 210 """ 211 212 if id in [RIBBON_ART_PAGE_BACKGROUND_COLOUR, RIBBON_ART_PAGE_BACKGROUND_GRADIENT_COLOUR]: 213 self._background_brush.SetColour(colour) 214 elif id == RIBBON_ART_TAB_CTRL_BACKGROUND_COLOUR: 215 self._tab_ctrl_background_colour = colour 216 elif id == RIBBON_ART_TAB_CTRL_BACKGROUND_GRADIENT_COLOUR: 217 self._tab_ctrl_background_gradient_colour = colour 218 elif id in [RIBBON_ART_TAB_ACTIVE_BACKGROUND_TOP_COLOUR, RIBBON_ART_TAB_ACTIVE_BACKGROUND_TOP_GRADIENT_COLOUR]: 219 self._tab_active_top_background_brush.SetColour(colour) 220 elif id in [RIBBON_ART_TAB_HOVER_BACKGROUND_COLOUR, RIBBON_ART_TAB_HOVER_BACKGROUND_GRADIENT_COLOUR]: 221 self._tab_hover_background_brush.SetColour(colour) 222 elif id == RIBBON_ART_PANEL_LABEL_BACKGROUND_COLOUR: 223 self._panel_label_background_colour = colour 224 elif id == RIBBON_ART_PANEL_LABEL_BACKGROUND_GRADIENT_COLOUR: 225 self._panel_label_background_gradient_colour = colour 226 elif id in [RIBBON_ART_BUTTON_BAR_HOVER_BACKGROUND_COLOUR, RIBBON_ART_BUTTON_BAR_HOVER_BACKGROUND_GRADIENT_COLOUR]: 227 self._button_bar_hover_background_brush.SetColour(colour) 228 elif id in [RIBBON_ART_GALLERY_BUTTON_HOVER_BACKGROUND_COLOUR, RIBBON_ART_GALLERY_BUTTON_HOVER_BACKGROUND_GRADIENT_COLOUR]: 229 self._gallery_button_hover_background_brush.SetColour(colour) 230 elif id in [RIBBON_ART_GALLERY_BUTTON_ACTIVE_BACKGROUND_COLOUR, RIBBON_ART_GALLERY_BUTTON_ACTIVE_BACKGROUND_GRADIENT_COLOUR]: 231 self._gallery_button_active_background_brush.SetColour(colour) 232 elif id in [RIBBON_ART_GALLERY_BUTTON_DISABLED_BACKGROUND_COLOUR, RIBBON_ART_GALLERY_BUTTON_DISABLED_BACKGROUND_GRADIENT_COLOUR]: 233 self._gallery_button_disabled_background_brush.SetColour(colour) 234 else: 235 RibbonMSWArtProvider.SetColour(self, id, colour) 236 237 238 def SetColourScheme(self, primary, secondary, tertiary): 239 """ 240 Set all applicable colour settings from a few base colours. 241 242 Uses any or all of the three given colours to create a colour scheme, and then 243 sets all colour settings which are relevant to the art provider using that 244 scheme. Note that some art providers may not use the tertiary colour for 245 anything, and some may not use the secondary colour either. 246 247 :param `primary`: MISSING DESCRIPTION; 248 :param `secondary`: MISSING DESCRIPTION; 249 :param `tertiary`: MISSING DESCRIPTION. 250 251 :see: :meth:`~RibbonAUIArtProvider.SetColour`, :meth:`RibbonMSWArtProvider.GetColourScheme() <lib.agw.ribbon.art_msw.RibbonMSWArtProvider.GetColourScheme>` 252 """ 253 254 primary_hsl = RibbonHSLColour(primary) 255 secondary_hsl = RibbonHSLColour(secondary) 256 tertiary_hsl = RibbonHSLColour(tertiary) 257 258 # Map primary & secondary luminance from [0, 1] to [0.15, 0.85] 259 primary_hsl.luminance = cos(primary_hsl.luminance * M_PI) * -0.35 + 0.5 260 secondary_hsl.luminance = cos(secondary_hsl.luminance * M_PI) * -0.35 + 0.5 261 262 # TODO: Remove next line once this provider stops piggybacking MSW 263 RibbonMSWArtProvider.SetColourScheme(self, primary, secondary, tertiary) 264 265 self._tab_ctrl_background_colour = RibbonShiftLuminance(primary_hsl, 0.9).ToRGB() 266 self._tab_ctrl_background_gradient_colour = RibbonShiftLuminance(primary_hsl, 1.7).ToRGB() 267 self._tab_border_pen = wx.Pen(RibbonShiftLuminance(primary_hsl, 0.75).ToRGB()) 268 self._tab_label_colour = RibbonShiftLuminance(primary_hsl, 0.1).ToRGB() 269 self._tab_hover_background_top_colour = primary_hsl.ToRGB() 270 self._tab_hover_background_top_gradient_colour = RibbonShiftLuminance(primary_hsl, 1.6).ToRGB() 271 self._tab_hover_background_brush = wx.Brush(self._tab_hover_background_top_colour) 272 self._tab_active_background_colour = self._tab_ctrl_background_gradient_colour 273 self._tab_active_background_gradient_colour = primary_hsl.ToRGB() 274 self._tab_active_top_background_brush = wx.Brush(self._tab_active_background_colour) 275 self._panel_label_colour = self._tab_label_colour 276 self._panel_minimised_label_colour = self._panel_label_colour 277 self._panel_hover_label_colour = tertiary_hsl.ToRGB() 278 self._page_border_pen = self._tab_border_pen 279 self._panel_border_pen = self._tab_border_pen 280 self._background_brush = wx.Brush(primary_hsl.ToRGB()) 281 self._page_hover_background_colour = RibbonShiftLuminance(primary_hsl, 1.5).ToRGB() 282 self._page_hover_background_gradient_colour = RibbonShiftLuminance(primary_hsl, 0.9).ToRGB() 283 self._panel_label_background_colour = RibbonShiftLuminance(primary_hsl, 0.85).ToRGB() 284 self._panel_label_background_gradient_colour = RibbonShiftLuminance(primary_hsl, 0.97).ToRGB() 285 self._panel_hover_label_background_gradient_colour = secondary_hsl.ToRGB() 286 self._panel_hover_label_background_colour = secondary_hsl.Lighter(0.2).ToRGB() 287 self._button_bar_hover_border_pen = wx.Pen(secondary_hsl.ToRGB()) 288 self._button_bar_hover_background_brush = wx.Brush(RibbonShiftLuminance(secondary_hsl, 1.7).ToRGB()) 289 self._button_bar_active_background_brush = wx.Brush(RibbonShiftLuminance(secondary_hsl, 1.4).ToRGB()) 290 self._button_bar_label_colour = self._tab_label_colour 291 self._gallery_border_pen = self._tab_border_pen 292 self._gallery_item_border_pen = self._button_bar_hover_border_pen 293 self._gallery_hover_background_brush = wx.Brush(RibbonShiftLuminance(primary_hsl, 1.2).ToRGB()) 294 self._gallery_button_background_colour = self._page_hover_background_colour 295 self._gallery_button_background_gradient_colour = self._page_hover_background_gradient_colour 296 self._gallery_button_hover_background_brush = self._button_bar_hover_background_brush 297 self._gallery_button_active_background_brush = self._button_bar_active_background_brush 298 self._gallery_button_disabled_background_brush = wx.Brush(primary_hsl.Desaturated(0.15).ToRGB()) 299 self.SetColour(RIBBON_ART_GALLERY_BUTTON_FACE_COLOUR, RibbonShiftLuminance(primary_hsl, 0.1).ToRGB()) 300 self.SetColour(RIBBON_ART_GALLERY_BUTTON_DISABLED_FACE_COLOUR, wx.Colour(128, 128, 128)) 301 self.SetColour(RIBBON_ART_GALLERY_BUTTON_ACTIVE_FACE_COLOUR, RibbonShiftLuminance(secondary_hsl, 0.1).ToRGB()) 302 self.SetColour(RIBBON_ART_GALLERY_BUTTON_HOVER_FACE_COLOUR, RibbonShiftLuminance(secondary_hsl, 0.1).ToRGB()) 303 self._toolbar_border_pen = self._tab_border_pen 304 self.SetColour(RIBBON_ART_TOOLBAR_FACE_COLOUR, RibbonShiftLuminance(primary_hsl, 0.1).ToRGB()) 305 self._tool_background_colour = self._page_hover_background_colour 306 self._tool_background_gradient_colour = self._page_hover_background_gradient_colour 307 self._toolbar_hover_borden_pen = self._button_bar_hover_border_pen 308 self._tool_hover_background_brush = self._button_bar_hover_background_brush 309 self._tool_active_background_brush = self._button_bar_active_background_brush 310 311 312 def DrawTabCtrlBackground(self, dc, wnd, rect): 313 """ 314 Draw the background of the tab region of a ribbon bar. 315 316 :param `dc`: The device context to draw onto; 317 :param `wnd`: The window which is being drawn onto; 318 :param `rect`: The rectangle within which to draw. 319 320 """ 321 322 gradient_rect = wx.Rect(*rect) 323 gradient_rect.height -= 1 324 dc.GradientFillLinear(gradient_rect, self._tab_ctrl_background_colour, self._tab_ctrl_background_gradient_colour, wx.SOUTH) 325 dc.SetPen(self._tab_border_pen) 326 dc.DrawLine(rect.x, rect.GetBottom(), rect.GetRight()+1, rect.GetBottom()) 327 328 329 def GetTabCtrlHeight(self, dc, wnd, pages): 330 """ 331 Calculate the height (in pixels) of the tab region of a ribbon bar. 332 333 Note that as the tab region can contain scroll buttons, the height should be 334 greater than or equal to the minimum height for a tab scroll button. 335 336 :param `dc`: A device context to use when one is required for size calculations; 337 :param `wnd`: The window onto which the tabs will eventually be drawn; 338 :param `pages`: The tabs which will acquire the returned height. 339 340 """ 341 342 text_height = 0 343 icon_height = 0 344 345 if len(pages) <= 1 and (self._flags & RIBBON_BAR_ALWAYS_SHOW_TABS) == 0: 346 # To preserve space, a single tab need not be displayed. We still need 347 # one pixel of border though. 348 return 1 349 350 if self._flags & RIBBON_BAR_SHOW_PAGE_LABELS: 351 dc.SetFont(self._tab_active_label_font) 352 text_height = dc.GetTextExtent("ABCDEFXj")[1] 353 354 if self._flags & RIBBON_BAR_SHOW_PAGE_ICONS: 355 for info in pages: 356 if info.page.GetIcon().IsOk(): 357 icon_height = max(icon_height, info.page.GetIcon().GetHeight()) 358 359 return max(text_height, icon_height) + 10 360 361 362 def DrawTab(self, dc, wnd, tab): 363 """ 364 Draw a single tab in the tab region of a ribbon bar. 365 366 :param `dc`: The device context to draw onto; 367 :param `wnd`: The window which is being drawn onto (not the :class:`~wx.lib.agw.ribbon.page.RibbonPage` 368 associated with the tab being drawn); 369 :param `tab`: The rectangle within which to draw, and also the tab label, 370 icon, and state (active and/or hovered). The drawing rectangle will be 371 entirely within a rectangle on the same device context previously painted 372 with :meth:`~RibbonAUIArtProvider.DrawTabCtrlBackground`. The rectangle's width will be at least the 373 minimum value returned by :meth:`~RibbonAUIArtProvider.GetBarTabWidth`, and height will be the value 374 returned by :meth:`~RibbonAUIArtProvider.GetTabCtrlHeight`. 375 376 """ 377 378 if tab.rect.height <= 1: 379 return 380 381 dc.SetFont(self._tab_label_font) 382 dc.SetPen(wx.TRANSPARENT_PEN) 383 384 if tab.active or tab.hovered: 385 if tab.active: 386 dc.SetFont(self._tab_active_label_font) 387 dc.SetBrush(self._background_brush) 388 dc.DrawRectangle(tab.rect.x, tab.rect.y + tab.rect.height - 1, tab.rect.width - 1, 1) 389 390 grad_rect = wx.Rect(*tab.rect) 391 grad_rect.height -= 4 392 grad_rect.width -= 1 393 grad_rect.height /= 2 394 grad_rect.y = grad_rect.y + tab.rect.height - grad_rect.height - 1 395 dc.SetBrush(self._tab_active_top_background_brush) 396 dc.DrawRectangle(tab.rect.x, tab.rect.y + 3, tab.rect.width - 1, grad_rect.y - tab.rect.y - 3) 397 dc.GradientFillLinear(grad_rect, self._tab_active_background_colour, self._tab_active_background_gradient_colour, wx.SOUTH) 398 399 else: 400 401 btm_rect = wx.Rect(*tab.rect) 402 btm_rect.height -= 4 403 btm_rect.width -= 1 404 btm_rect.height /= 2 405 btm_rect.y = btm_rect.y + tab.rect.height - btm_rect.height - 1 406 dc.SetBrush(self._tab_hover_background_brush) 407 dc.DrawRectangle(btm_rect.x, btm_rect.y, btm_rect.width, btm_rect.height) 408 grad_rect = wx.Rect(*tab.rect) 409 grad_rect.width -= 1 410 grad_rect.y += 3 411 grad_rect.height = btm_rect.y - grad_rect.y 412 dc.GradientFillLinear(grad_rect, self._tab_hover_background_top_colour, self._tab_hover_background_top_gradient_colour, wx.SOUTH) 413 414 border_points = [wx.Point() for i in range(5)] 415 border_points[0] = wx.Point(0, 3) 416 border_points[1] = wx.Point(1, 2) 417 border_points[2] = wx.Point(tab.rect.width - 3, 2) 418 border_points[3] = wx.Point(tab.rect.width - 1, 4) 419 border_points[4] = wx.Point(tab.rect.width - 1, tab.rect.height - 1) 420 421 dc.SetPen(self._tab_border_pen) 422 dc.DrawLines(border_points, tab.rect.x, tab.rect.y) 423 424 old_clip = dc.GetClippingRect() 425 is_first_tab = False 426 427 bar = tab.page.GetParent() 428 icon = wx.NullBitmap 429 430 if isinstance(bar, BAR.RibbonBar) and bar.GetPage(0) == tab.page: 431 is_first_tab = True 432 433 if self._flags & RIBBON_BAR_SHOW_PAGE_ICONS: 434 icon = tab.page.GetIcon() 435 if self._flags & RIBBON_BAR_SHOW_PAGE_LABELS == 0: 436 if icon.IsOk(): 437 x = tab.rect.x + (tab.rect.width - icon.GetWidth()) / 2 438 dc.DrawBitmap(icon, x, tab.rect.y + 1 + (tab.rect.height - 1 - icon.GetHeight()) / 2, True) 439 440 if self._flags & RIBBON_BAR_SHOW_PAGE_LABELS: 441 label = tab.page.GetLabel() 442 443 if label.strip(): 444 dc.SetTextForeground(self._tab_label_colour) 445 dc.SetBackgroundMode(wx.TRANSPARENT) 446 447 offset = 0 448 449 if icon.IsOk(): 450 offset += icon.GetWidth() + 2 451 452 text_width, text_height = dc.GetTextExtent(label) 453 x = (tab.rect.width - 2 - text_width - offset) / 2 454 if x > 8: 455 x = 8 456 elif x < 1: 457 x = 1 458 459 width = tab.rect.width - x - 2 460 x += tab.rect.x + offset 461 y = tab.rect.y + (tab.rect.height - text_height) / 2 462 463 if icon.IsOk(): 464 dc.DrawBitmap(icon, x - offset, tab.rect.y + (tab.rect.height - icon.GetHeight()) / 2, True) 465 466 dc.SetClippingRegion(x, tab.rect.y, width, tab.rect.height) 467 dc.DrawText(label, x, y) 468 469 # Draw the left hand edge of the tab only for the first tab (subsequent 470 # tabs use the right edge of the prior tab as their left edge). As this is 471 # outside the rectangle for the tab, only draw it if the leftmost part of 472 # the tab is within the clip rectangle (the clip region has to be cleared 473 # to draw outside the tab). 474 if is_first_tab and old_clip.x <= tab.rect.x and tab.rect.x < old_clip.x + old_clip.width: 475 dc.DestroyClippingRegion() 476 dc.DrawLine(tab.rect.x - 1, tab.rect.y + 4, tab.rect.x - 1, tab.rect.y + tab.rect.height - 1) 477 478 479 def GetBarTabWidth(self, dc, wnd, label, bitmap, ideal=None, small_begin_need_separator=None, 480 small_must_have_separator=None, minimum=None): 481 """ 482 Calculate the ideal and minimum width (in pixels) of a tab in a ribbon bar. 483 484 :param `dc`: A device context to use when one is required for size calculations; 485 :param `wnd`: The window onto which the tab will eventually be drawn; 486 :param `label`: The tab's label (or an empty string if it has none); 487 :param `bitmap`: The tab's icon (or :class:`NullBitmap` if it has none); 488 :param `ideal`: The ideal width (in pixels) of the tab; 489 :param `small_begin_need_separator`: A size less than the size, at which a tab 490 separator should begin to be drawn (i.e. drawn, but still fairly transparent); 491 :param `small_must_have_separator`: A size less than the size, at which a tab 492 separator must be drawn (i.e. drawn at full opacity); 493 :param `minimum`: A size less than the size, and greater than or equal to zero, 494 which is the minimum pixel width for the tab. 495 496 """ 497 498 width = mini = 0 499 500 if self._flags & RIBBON_BAR_SHOW_PAGE_LABELS and label.strip(): 501 dc.SetFont(self._tab_active_label_font) 502 width += dc.GetTextExtent(label)[0] 503 mini += min(30, width) # enough for a few chars 504 505 if bitmap.IsOk(): 506 # gap between label and bitmap 507 width += 4 508 mini += 2 509 510 if self._flags & RIBBON_BAR_SHOW_PAGE_ICONS and bitmap.IsOk(): 511 width += bitmap.GetWidth() 512 mini += bitmap.GetWidth() 513 514 ideal = width + 16 515 small_begin_need_separator = mini 516 small_must_have_separator = mini 517 minimum = mini 518 519 return ideal, small_begin_need_separator, small_must_have_separator, minimum 520 521 522 def DrawTabSeparator(self, dc, wnd, rect, visibility): 523 """ 524 Draw a separator between two tabs in a ribbon bar. 525 526 :param `dc`: The device context to draw onto; 527 :param `wnd`: The window which is being drawn onto; 528 :param `rect`: The rectangle within which to draw, which will be entirely 529 within a rectangle on the same device context previously painted with 530 :meth:`~RibbonAUIArtProvider.DrawTabCtrlBackground`; 531 :param `visibility`: The opacity with which to draw the separator. Values 532 are in the range [0, 1], with 0 being totally transparent, and 1 being totally 533 opaque. 534 535 """ 536 537 # No explicit separators between tabs 538 pass 539 540 541 def DrawPageBackground(self, dc, wnd, rect): 542 """ 543 Draw the background of a ribbon page. 544 545 :param `dc`: The device context to draw onto; 546 :param `wnd`: The window which is being drawn onto (which is commonly the 547 :class:`~wx.lib.agw.ribbon.page.RibbonPage` whose background is being drawn, but doesn't have to be); 548 :param `rect`: The rectangle within which to draw. 549 550 :see: :meth:`RibbonMSWArtProvider.GetPageBackgroundRedrawArea() <lib.agw.ribbon.art_msw.RibbonMSWArtProvider.GetPageBackgroundRedrawArea>` 551 """ 552 553 dc.SetPen(wx.TRANSPARENT_PEN) 554 dc.SetBrush(self._background_brush) 555 dc.DrawRectangle(rect.x + 1, rect.y, rect.width - 2, rect.height - 1) 556 557 dc.SetPen(self._page_border_pen) 558 dc.DrawLine(rect.x, rect.y, rect.x, rect.y + rect.height) 559 dc.DrawLine(rect.GetRight(), rect.y, rect.GetRight(), rect.y +rect.height) 560 dc.DrawLine(rect.x, rect.GetBottom(), rect.GetRight()+1, rect.GetBottom()) 561 562 563 def GetScrollButtonMinimumSize(self, dc, wnd, style): 564 """ 565 Calculate the minimum size (in pixels) of a scroll button. 566 567 :param `dc`: A device context to use when one is required for size calculations; 568 :param `wnd`: The window onto which the scroll button will eventually be drawn; 569 :param `style`: A combination of flags from `RibbonScrollButtonStyle`, including 570 a direction, and a for flag (state flags may be given too, but should be ignored, 571 as a button should retain a constant size, regardless of its state). 572 573 """ 574 575 return wx.Size(11, 11) 576 577 578 def DrawScrollButton(self, dc, wnd, rect, style): 579 """ 580 Draw a ribbon-style scroll button. 581 582 :param `dc`: The device context to draw onto; 583 :param `wnd`: The window which is being drawn onto; 584 :param `rect`: The rectangle within which to draw. The size of this rectangle 585 will be at least the size returned by :meth:`~RibbonAUIArtProvider.GetScrollButtonMinimumSize` for a 586 scroll button with the same style. For tab scroll buttons, this rectangle 587 will be entirely within a rectangle on the same device context previously 588 painted with :meth:`~RibbonAUIArtProvider.DrawTabCtrlBackground`, but this is not guaranteed for other 589 types of button (for example, page scroll buttons will not be painted on 590 an area previously painted with :meth:`~RibbonAUIArtProvider.DrawPageBackground`); 591 :param `style`: A combination of flags from `RibbonScrollButtonStyle`, 592 including a direction, a for flag, and one or more states. 593 594 """ 595 596 true_rect = wx.Rect(*rect) 597 arrow_points = [wx.Point() for i in range(3)] 598 599 if style & RIBBON_SCROLL_BTN_FOR_MASK == RIBBON_SCROLL_BTN_FOR_TABS: 600 true_rect.y += 2 601 true_rect.height -= 2 602 dc.SetPen(self._tab_border_pen) 603 else: 604 dc.SetPen(wx.TRANSPARENT_PEN) 605 dc.SetBrush(self._background_brush) 606 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) 607 dc.SetPen(self._page_border_pen) 608 609 result = style & RIBBON_SCROLL_BTN_DIRECTION_MASK 610 611 if result == RIBBON_SCROLL_BTN_LEFT: 612 dc.DrawLine(true_rect.GetRight(), true_rect.y, true_rect.GetRight(), true_rect.y + true_rect.height) 613 arrow_points[0] = wx.Point(rect.width / 2 - 2, rect.height / 2) 614 arrow_points[1] = arrow_points[0] + wx.Point(5, -5) 615 arrow_points[2] = arrow_points[0] + wx.Point(5, 5) 616 617 elif result == RIBBON_SCROLL_BTN_RIGHT: 618 dc.DrawLine(true_rect.x, true_rect.y, true_rect.x, true_rect.y + true_rect.height) 619 arrow_points[0] = wx.Point(rect.width / 2 + 3, rect.height / 2) 620 arrow_points[1] = arrow_points[0] - wx.Point(5, -5) 621 arrow_points[2] = arrow_points[0] - wx.Point(5, 5) 622 623 elif result == RIBBON_SCROLL_BTN_DOWN: 624 dc.DrawLine(true_rect.x, true_rect.y, true_rect.x + true_rect.width, true_rect.y) 625 arrow_points[0] = wx.Point(rect.width / 2, rect.height / 2 + 3) 626 arrow_points[1] = arrow_points[0] - wx.Point( 5, 5) 627 arrow_points[2] = arrow_points[0] - wx.Point(-5, 5) 628 629 elif result == RIBBON_SCROLL_BTN_UP: 630 dc.DrawLine(true_rect.x, true_rect.GetBottom(), true_rect.x + true_rect.width, true_rect.GetBottom()) 631 arrow_points[0] = wx.Point(rect.width / 2, rect.height / 2 - 2) 632 arrow_points[1] = arrow_points[0] + wx.Point( 5, 5) 633 arrow_points[2] = arrow_points[0] + wx.Point(-5, 5) 634 635 else: 636 return 637 638 x = rect.x 639 y = rect.y 640 641 if style & RIBBON_SCROLL_BTN_ACTIVE: 642 x += 1 643 y += 1 644 645 dc.SetPen(wx.TRANSPARENT_PEN) 646 B = wx.Brush(self._tab_label_colour) 647 dc.SetBrush(B) 648 dc.DrawPolygon(arrow_points, x, y) 649 650 651 def GetPanelSize(self, dc, wnd, client_size, client_offset=None): 652 """ 653 Calculate the size of a panel for a given client size. 654 655 This should increment the given size by enough to fit the panel label and other 656 chrome. 657 658 :param `dc`: A device context to use if one is required for size calculations; 659 :param `wnd`: The ribbon panel in question; 660 :param `client_size`: The client size; 661 :param `client_offset`: The offset where the client rectangle begins within 662 the panel (may be ``None``). 663 664 :see: :meth:`~RibbonAUIArtProvider.GetPanelClientSize` 665 """ 666 667 dc.SetFont(self._panel_label_font) 668 label_size = wx.Size(*dc.GetTextExtent(wnd.GetLabel())) 669 label_height = label_size.GetHeight() + 5 670 671 if self._flags & RIBBON_BAR_FLOW_VERTICAL: 672 client_size.IncBy(4, label_height + 6) 673 if client_offset is not None: 674 client_offset = wx.Point(2, label_height + 3) 675 676 else: 677 client_size.IncBy(6, label_height + 4) 678 if client_offset is not None: 679 client_offset = wx.Point(3, label_height + 2) 680 681 return client_size 682 683 684 def GetPanelClientSize(self, dc, wnd, size, client_offset=None): 685 """ 686 Calculate the client size of a panel for a given overall size. 687 688 This should act as the inverse to :meth:`~RibbonAUIArtProvider.GetPanelSize`, and decrement the given size 689 by enough to fit the panel label and other chrome. 690 691 :param `dc`: A device context to use if one is required for size calculations; 692 :param `wnd`: The ribbon panel in question; 693 :param `size`: The overall size to calculate client size for; 694 :param `client_offset`: The offset where the returned client size begins within 695 the given (may be ``None``). 696 697 :see: :meth:`~RibbonAUIArtProvider.GetPanelSize` 698 """ 699 700 dc.SetFont(self._panel_label_font) 701 label_size = wx.Size(*dc.GetTextExtent(wnd.GetLabel())) 702 label_height = label_size.GetHeight() + 5 703 704 if self._flags & RIBBON_BAR_FLOW_VERTICAL: 705 size.DecBy(4, label_height + 6) 706 if client_offset is not None: 707 client_offset = wx.Point(2, label_height + 3) 708 709 else: 710 size.DecBy(6, label_height + 4) 711 if client_offset is not None: 712 client_offset = wx.Point(3, label_height + 2) 713 714 if size.x < 0: 715 size.x = 0 716 if size.y < 0: 717 size.y = 0 718 719 return size, client_offset 720 721 722 def GetPanelExtButtonArea(self, dc, wnd, rect): 723 """ 724 Retrieve the extension button area rectangle. 725 726 :param `dc`: The device context used to measure text extents; 727 :param `wnd`: The panel where the extension button resides; 728 :param `rect`: The panel client rectangle. 729 """ 730 731 true_rect = wx.Rect(rect) 732 true_rect = self.RemovePanelPadding(true_rect) 733 734 true_rect.x += 1 735 true_rect.width -= 2 736 true_rect.y += 1 737 738 dc.SetFont(self._panel_label_font) 739 label_size = dc.GetTextExtent(wnd.GetLabel()) 740 label_height = label_size[1] + 5 741 label_rect = wx.Rect(*true_rect) 742 label_rect.height = label_height - 1 743 744 rect = wx.Rect(label_rect.GetRight()-13, label_rect.GetBottom()-13, 13, 13) 745 return rect 746 747 748 def DrawPanelBackground(self, dc, wnd, rect): 749 """ 750 Draw the background and chrome for a ribbon panel. 751 752 This should draw the border, background, label, and any other items of a panel 753 which are outside the client area of a panel. Note that when a panel is 754 minimised, this function is not called - only :meth:`~RibbonAUIArtProvider.DrawMinimisedPanel` is called, 755 so a background should be explicitly painted by that if required. 756 757 :param `dc`: The device context to draw onto; 758 :param `wnd`: The window which is being drawn onto, which is always the panel 759 whose background and chrome is being drawn. The panel label and other panel 760 attributes can be obtained by querying this; 761 :param `rect`: The rectangle within which to draw. 762 763 """ 764 765 dc.SetPen(wx.TRANSPARENT_PEN) 766 dc.SetBrush(self._background_brush) 767 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) 768 769 true_rect = wx.Rect(*rect) 770 true_rect = self.RemovePanelPadding(true_rect) 771 772 dc.SetPen(self._panel_border_pen) 773 dc.SetBrush(wx.TRANSPARENT_BRUSH) 774 dc.DrawRectangle(true_rect.x, true_rect.y, true_rect.width, true_rect.height) 775 776 true_rect.x += 1 777 true_rect.width -= 2 778 true_rect.y += 1 779 780 dc.SetFont(self._panel_label_font) 781 label_size = wx.Size(*dc.GetTextExtent(wnd.GetLabel())) 782 label_height = label_size.GetHeight() + 5 783 label_rect = wx.Rect(*true_rect) 784 label_rect.height = label_height - 1 785 786 dc.DrawLine(label_rect.x, label_rect.y + label_rect.height, label_rect.x + label_rect.width, label_rect.y + label_rect.height) 787 788 label_bg_colour = self._panel_label_background_colour 789 label_bg_grad_colour = self._panel_label_background_gradient_colour 790 791 if wnd.IsHovered(): 792 label_bg_colour = self._panel_hover_label_background_colour 793 label_bg_grad_colour = self._panel_hover_label_background_gradient_colour 794 dc.SetTextForeground(self._panel_hover_label_colour) 795 else: 796 dc.SetTextForeground(self._panel_label_colour) 797 798 if wx.Platform == "__WXMAC__": 799 dc.GradientFillLinear(label_rect, label_bg_grad_colour, label_bg_colour, wx.SOUTH) 800 else: 801 dc.GradientFillLinear(label_rect, label_bg_colour, label_bg_grad_colour, wx.SOUTH) 802 803 dc.SetFont(self._panel_label_font) 804 dc.DrawText(wnd.GetLabel(), label_rect.x + 3, label_rect.y + 2) 805 806 if wnd.IsHovered(): 807 808 gradient_rect = wx.Rect(*true_rect) 809 gradient_rect.y += label_rect.height + 1 810 gradient_rect.height = true_rect.height - label_rect.height - 3 811 if wx.Platform == "__WXMAC__": 812 colour = self._page_hover_background_gradient_colour 813 gradient = self._page_hover_background_colour 814 else: 815 colour = self._page_hover_background_colour 816 gradient = self._page_hover_background_gradient_colour 817 818 dc.GradientFillLinear(gradient_rect, colour, gradient, wx.SOUTH) 819 820 if wnd.HasExtButton(): 821 if wnd.IsExtButtonHovered(): 822 dc.SetPen(self._panel_hover_button_border_pen) 823 dc.SetBrush(self._panel_hover_button_background_brush) 824 dc.DrawRoundedRectangle(label_rect.GetRight() - 13, label_rect.GetBottom() - 13, 13, 13, 1) 825 dc.DrawBitmap(self._panel_extension_bitmap[1], label_rect.GetRight() - 10, label_rect.GetBottom() - 10, True) 826 827 else: 828 dc.DrawBitmap(self._panel_extension_bitmap[0], label_rect.GetRight() - 10, label_rect.GetBottom() - 10, True) 829 830 831 def DrawMinimisedPanel(self, dc, wnd, rect, bitmap): 832 """ 833 Draw a minimised ribbon panel. 834 835 :param `dc`: The device context to draw onto; 836 :param `wnd`: The window which is being drawn onto, which is always the panel 837 which is minimised. The panel label can be obtained from this window. The 838 minimised icon obtained from querying the window may not be the size requested 839 by :meth:`RibbonMSWArtProvider.GetMinimisedPanelMinimumSize() <lib.agw.ribbon.art_msw.RibbonMSWArtProvider.GetMinimisedPanelMinimumSize>` - the argument contains the icon in the 840 requested size; 841 :param `rect`: The rectangle within which to draw. The size of the rectangle 842 will be at least the size returned by :meth:`RibbonMSWArtProvider.GetMinimisedPanelMinimumSize() <lib.agw.ribbon.art_msw.RibbonMSWArtProvider.GetMinimisedPanelMinimumSize>`; 843 :param `bitmap`: A copy of the panel's minimised bitmap rescaled to the size 844 returned by :meth:`RibbonMSWArtProvider.GetMinimisedPanelMinimumSize() <lib.agw.ribbon.art_msw.RibbonMSWArtProvider.GetMinimisedPanelMinimumSize>`. 845 846 """ 847 848 dc.SetPen(wx.TRANSPARENT_PEN) 849 dc.SetBrush(self._background_brush) 850 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) 851 852 true_rect = wx.Rect(*rect) 853 true_rect = self.RemovePanelPadding(true_rect) 854 855 dc.SetPen(self._panel_border_pen) 856 dc.SetBrush(wx.TRANSPARENT_BRUSH) 857 dc.DrawRectangle(true_rect.x, true_rect.y, true_rect.width, true_rect.height) 858 true_rect.Deflate(1, 1) 859 860 if wnd.IsHovered() or wnd.GetExpandedPanel(): 861 colour = self._page_hover_background_colour 862 gradient = self._page_hover_background_gradient_colour 863 if (wx.Platform == "__WXMAC__" and not wnd.GetExpandedPanel()) or \ 864 (wx.Platform != "__WXMAC__" and wnd.GetExpandedPanel()): 865 temp = colour 866 colour = gradient 867 gradient = temp 868 869 dc.GradientFillLinear(true_rect, colour, gradient, wx.SOUTH) 870 871 preview = self.DrawMinimisedPanelCommon(dc, wnd, true_rect) 872 873 dc.SetPen(self._panel_border_pen) 874 dc.SetBrush(wx.TRANSPARENT_BRUSH) 875 dc.DrawRectangle(preview.x, preview.y, preview.width, preview.height) 876 preview.Deflate(1, 1) 877 878 preview_caption_rect = wx.Rect(*preview) 879 preview_caption_rect.height = 7 880 preview.y += preview_caption_rect.height 881 preview.height -= preview_caption_rect.height 882 883 if wx.Platform == "__WXMAC__": 884 dc.GradientFillLinear(preview_caption_rect, self._panel_hover_label_background_gradient_colour, 885 self._panel_hover_label_background_colour, wx.SOUTH) 886 dc.GradientFillLinear(preview, self._page_hover_background_gradient_colour, 887 self._page_hover_background_colour, wx.SOUTH) 888 else: 889 dc.GradientFillLinear(preview_caption_rect, self._panel_hover_label_background_colour, 890 self._panel_hover_label_background_gradient_colour, wx.SOUTH) 891 dc.GradientFillLinear(preview, self._page_hover_background_colour, 892 self._page_hover_background_gradient_colour, wx.SOUTH) 893 894 if bitmap.IsOk(): 895 dc.DrawBitmap(bitmap, preview.x + (preview.width - bitmap.GetWidth()) / 2, 896 preview.y + (preview.height - bitmap.GetHeight()) / 2, True) 897 898 899 def DrawPartialPanelBackground(self, dc, wnd, rect): 900 901 dc.SetPen(wx.TRANSPARENT_PEN) 902 dc.SetBrush(self._background_brush) 903 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) 904 905 offset = wx.Point(*wnd.GetPosition()) 906 parent = wnd.GetParent() 907 panel = None 908 909 while 1: 910 panel = parent 911 if isinstance(panel, PANEL.RibbonPanel): 912 if not panel.IsHovered(): 913 return 914 break 915 916 offset += parent.GetPosition() 917 parent = panel.GetParent() 918 919 if panel is None: 920 return 921 922 background = wx.Rect(0, 0, *panel.GetSize()) 923 background = self.RemovePanelPadding(background) 924 925 background.x += 1 926 background.width -= 2 927 dc.SetFont(self._panel_label_font) 928 caption_height = dc.GetTextExtent(panel.GetLabel())[1] + 7 929 background.y += caption_height - 1 930 background.height -= caption_height 931 932 paint_rect = wx.Rect(*rect) 933 paint_rect.x += offset.x 934 paint_rect.y += offset.y 935 936 if wx.Platform == "__WXMAC__": 937 bg_grad_clr = self._page_hover_background_colour 938 bg_clr = self._page_hover_background_gradient_colour 939 else: 940 bg_clr = self._page_hover_background_colour 941 bg_grad_clr = self._page_hover_background_gradient_colour 942 943 paint_rect.Intersect(background) 944 945 if not paint_rect.IsEmpty(): 946 starting_colour = RibbonInterpolateColour(bg_clr, bg_grad_clr, paint_rect.y, background.y, background.y + background.height) 947 ending_colour = RibbonInterpolateColour(bg_clr, bg_grad_clr, paint_rect.y + paint_rect.height, background.y, background.y + background.height) 948 paint_rect.x -= offset.x 949 paint_rect.y -= offset.y 950 dc.GradientFillLinear(paint_rect, starting_colour, ending_colour, wx.SOUTH) 951 952 953 def DrawGalleryBackground(self, dc, wnd, rect): 954 """ 955 Draw the background and chrome for a :class:`~wx.lib.agw.ribbon.gallery.RibbonGallery` control. 956 957 This should draw the border, brackground, scroll buttons, extension button, and 958 any other UI elements which are not attached to a specific gallery item. 959 960 :param `dc`: The device context to draw onto; 961 :param `wnd`: The window which is being drawn onto, which is always the gallery 962 whose background and chrome is being drawn. Attributes used during drawing like 963 the gallery hover state and individual button states can be queried from this 964 parameter by :meth:`RibbonGallery.IsHovered() <lib.agw.ribbon.gallery.RibbonGallery.IsHovered>`, 965 :meth:`RibbonGallery.GetExtensionButtonState() <lib.agw.ribbon.gallery.RibbonGallery.GetExtensionButtonState>`, 966 :meth:`RibbonGallery.GetUpButtonState() <lib.agw.ribbon.gallery.RibbonGallery.GetUpButtonState>`, and 967 :meth:`RibbonGallery.GetDownButtonState() <lib.agw.ribbon.gallery.RibbonGallery.GetDownButtonState>`; 968 :param `rect`: The rectangle within which to draw. This rectangle is the entire 969 area of the gallery control, not just the client rectangle. 970 971 """ 972 973 self.DrawPartialPanelBackground(dc, wnd, rect) 974 975 if wnd.IsHovered(): 976 dc.SetPen(wx.TRANSPARENT_PEN) 977 dc.SetBrush(self._gallery_hover_background_brush) 978 979 if self._flags & RIBBON_BAR_FLOW_VERTICAL: 980 dc.DrawRectangle(rect.x + 1, rect.y + 1, rect.width - 2, rect.height - 16) 981 else: 982 dc.DrawRectangle(rect.x + 1, rect.y + 1, rect.width - 16, rect.height - 2) 983 984 dc.SetPen(self._gallery_border_pen) 985 dc.SetBrush(wx.TRANSPARENT_BRUSH) 986 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) 987 988 self.DrawGalleryBackgroundCommon(dc, wnd, rect) 989 990 991 def DrawGalleryButton(self, dc, rect, state, bitmaps): 992 993 extra_height = 0 994 extra_width = 0 995 reduced_rect = wx.Rect(*rect) 996 reduced_rect.Deflate(1, 1) 997 998 if self._flags & RIBBON_BAR_FLOW_VERTICAL: 999 reduced_rect.width += 1 1000 extra_width = 1 1001 else: 1002 reduced_rect.height += 1 1003 extra_height = 1 1004 1005 if state == RIBBON_GALLERY_BUTTON_NORMAL: 1006 dc.GradientFillLinear(reduced_rect, self._gallery_button_background_colour, self._gallery_button_background_gradient_colour, wx.SOUTH) 1007 btn_bitmap = bitmaps[0] 1008 1009 elif state == RIBBON_GALLERY_BUTTON_HOVERED: 1010 dc.SetPen(self._gallery_item_border_pen) 1011 dc.SetBrush(self._gallery_button_hover_background_brush) 1012 dc.DrawRectangle(rect.x, rect.y, rect.width + extra_width, rect.height + extra_height) 1013 btn_bitmap = bitmaps[1] 1014 1015 elif state == RIBBON_GALLERY_BUTTON_ACTIVE: 1016 dc.SetPen(self._gallery_item_border_pen) 1017 dc.SetBrush(self._gallery_button_active_background_brush) 1018 dc.DrawRectangle(rect.x, rect.y, rect.width + extra_width, rect.height + extra_height) 1019 btn_bitmap = bitmaps[2] 1020 1021 elif state == RIBBON_GALLERY_BUTTON_DISABLED: 1022 dc.SetPen(wx.TRANSPARENT_PEN) 1023 dc.SetBrush(self._gallery_button_disabled_background_brush) 1024 dc.DrawRectangle(reduced_rect.x, reduced_rect.y, reduced_rect.width, reduced_rect.height) 1025 btn_bitmap = bitmaps[3] 1026 1027 dc.DrawBitmap(btn_bitmap, reduced_rect.x + reduced_rect.width / 2 - 2, (rect.y + rect.height / 2) - 2, True) 1028 1029 1030 def DrawGalleryItemBackground(self, dc, wnd, rect, item): 1031 """ 1032 Draw the background of a single item in a :class:`~wx.lib.agw.ribbon.gallery.RibbonGallery` control. 1033 1034 This is painted on top of a gallery background, and behind the items bitmap. 1035 Unlike :meth:`~RibbonAUIArtProvider.DrawButtonBarButton` and :meth:`~RibbonAUIArtProvider.DrawTool`, it is not expected to draw the 1036 item bitmap - that is done by the gallery control itself. 1037 1038 :param `dc`: The device context to draw onto; 1039 :param `wnd`: The window which is being drawn onto, which is always the gallery 1040 which contains the item being drawn; 1041 :param `rect`: The rectangle within which to draw. The size of this rectangle 1042 will be the size of the item's bitmap, expanded by gallery item padding values 1043 (``RIBBON_ART_GALLERY_BITMAP_PADDING_LEFT_SIZE``, ``RIBBON_ART_GALLERY_BITMAP_PADDING_RIGHT_SIZE``, 1044 ``RIBBON_ART_GALLERY_BITMAP_PADDING_TOP_SIZE``, and ``RIBBON_ART_GALLERY_BITMAP_PADDING_BOTTOM_SIZE``). 1045 The drawing rectangle will be entirely within a rectangle on the same device 1046 context previously painted with :meth:`~RibbonAUIArtProvider.DrawGalleryBackground`; 1047 :param `item`: The item whose background is being painted. Typically the 1048 background will vary if the item is hovered, active, or selected; 1049 :meth:`RibbonGallery.GetSelection() <lib.agw.ribbon.gallery.RibbonGallery.GetSelection>`, 1050 :meth:`RibbonGallery.GetActiveItem() <lib.agw.ribbon.gallery.RibbonGallery.GetActiveItem>`, and 1051 :meth:`RibbonGallery.GetHoveredItem() <lib.agw.ribbon.gallery.RibbonGallery.GetHoveredItem>` 1052 can be called to test if the given item is in one of these states. 1053 1054 """ 1055 1056 if wnd.GetHoveredItem() != item and wnd.GetActiveItem() != item and wnd.GetSelection() != item: 1057 return 1058 1059 dc.SetPen(self._gallery_item_border_pen) 1060 1061 if wnd.GetActiveItem() == item or wnd.GetSelection() == item: 1062 dc.SetBrush(self._gallery_button_active_background_brush) 1063 else: 1064 dc.SetBrush(self._gallery_button_hover_background_brush) 1065 1066 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) 1067 1068 1069 def DrawButtonBarBackground(self, dc, wnd, rect): 1070 """ 1071 Draw the background for a :class:`~wx.lib.agw.ribbon.buttonbar.RibbonButtonBar` control. 1072 1073 :param `dc`: The device context to draw onto; 1074 :param `wnd`: The window which is being drawn onto (which will typically 1075 be the button bar itself, though this is not guaranteed); 1076 :param `rect`: The rectangle within which to draw. 1077 1078 """ 1079 1080 self.DrawPartialPanelBackground(dc, wnd, rect) 1081 1082 1083 def DrawButtonBarButton(self, dc, wnd, rect, kind, state, label, bitmap_large, bitmap_small): 1084 """ 1085 Draw a single button for a :class:`~wx.lib.agw.ribbon.buttonbar.RibbonButtonBar` control. 1086 1087 :param `dc`: The device context to draw onto; 1088 :param `wnd`: The window which is being drawn onto; 1089 :param `rect`: The rectangle within which to draw. The size of this rectangle 1090 will be a size previously returned by :meth:`RibbonMSWArtProvider.GetButtonBarButtonSize() <lib.agw.ribbon.art_msw.RibbonMSWArtProvider.GetButtonBarButtonSize>`, and the 1091 rectangle will be entirely within a rectangle on the same device context 1092 previously painted with :meth:`~RibbonAUIArtProvider.DrawButtonBarBackground`; 1093 :param `kind`: The kind of button to draw (normal, dropdown or hybrid); 1094 :param `state`: Combination of a size flag and state flags from the 1095 `RibbonButtonBarButtonState` enumeration; 1096 :param `label`: The label of the button; 1097 :param `bitmap_large`: The large bitmap of the button (or the large disabled 1098 bitmap when ``RIBBON_BUTTONBAR_BUTTON_DISABLED`` is set in ); 1099 :param `bitmap_small`: The small bitmap of the button (or the small disabled 1100 bitmap when ``RIBBON_BUTTONBAR_BUTTON_DISABLED`` is set in ). 1101 1102 """ 1103 1104 if kind == RIBBON_BUTTON_TOGGLE: 1105 kind = RIBBON_BUTTON_NORMAL 1106 if state & RIBBON_BUTTONBAR_BUTTON_TOGGLED: 1107 state ^= RIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK 1108 1109 if state & (RIBBON_BUTTONBAR_BUTTON_HOVER_MASK | RIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK): 1110 dc.SetPen(self._button_bar_hover_border_pen) 1111 bg_rect = wx.Rect(*rect) 1112 bg_rect.Deflate(1, 1) 1113 1114 if kind == RIBBON_BUTTON_HYBRID: 1115 result = state & RIBBON_BUTTONBAR_BUTTON_SIZE_MASK 1116 1117 if result == RIBBON_BUTTONBAR_BUTTON_LARGE: 1118 iYBorder = rect.y + bitmap_large.GetHeight() + 4 1119 partial_bg = wx.Rect(*rect) 1120 1121 if state & RIBBON_BUTTONBAR_BUTTON_NORMAL_HOVERED: 1122 partial_bg.SetBottom(iYBorder - 1) 1123 else: 1124 partial_bg.height -= (iYBorder - partial_bg.y + 1) 1125 partial_bg.y = iYBorder + 1 1126 1127 dc.DrawLine(rect.x, iYBorder, rect.x + rect.width, iYBorder) 1128 bg_rect.Intersect(partial_bg) 1129 1130 elif result == RIBBON_BUTTONBAR_BUTTON_MEDIUM: 1131 iArrowWidth = 9 1132 1133 if state & RIBBON_BUTTONBAR_BUTTON_NORMAL_HOVERED: 1134 bg_rect.width -= iArrowWidth 1135 dc.DrawLine(bg_rect.x + bg_rect.width, rect.y, bg_rect.x + bg_rect.width, rect.y + rect.height) 1136 else: 1137 iArrowWidth -= 1 1138 bg_rect.x += bg_rect.width - iArrowWidth 1139 bg_rect.width = iArrowWidth 1140 dc.DrawLine(bg_rect.x - 1, rect.y, bg_rect.x - 1, rect.y + rect.height) 1141 1142 dc.SetBrush(wx.TRANSPARENT_BRUSH) 1143 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) 1144 1145 dc.SetPen(wx.TRANSPARENT_PEN) 1146 1147 if state & RIBBON_BUTTONBAR_BUTTON_ACTIVE_MASK: 1148 dc.SetBrush(self._button_bar_active_background_brush) 1149 else: 1150 dc.SetBrush(self._button_bar_hover_background_brush) 1151 1152 dc.DrawRectangle(bg_rect.x, bg_rect.y, bg_rect.width, bg_rect.height) 1153 1154 dc.SetFont(self._button_bar_label_font) 1155 dc.SetTextForeground(self._button_bar_label_colour) 1156 self.DrawButtonBarButtonForeground(dc, rect, kind, state, label, bitmap_large, bitmap_small) 1157 1158 1159 def DrawToolBarBackground(self, dc, wnd, rect): 1160 """ 1161 Draw the background for a :class:`~wx.lib.agw.ribbon.toolbar.RibbonToolBar` control. 1162 1163 :param `dc`: The device context to draw onto; 1164 :param `wnd`: The which is being drawn onto. In most cases this will be 1165 a :class:`~wx.lib.agw.ribbon.toolbar.RibbonToolBar`, but it doesn't have to be; 1166 :param `rect`: The rectangle within which to draw. Some of this rectangle 1167 will later be drawn over using :meth:`~RibbonAUIArtProvider.DrawToolGroupBackground` and :meth:`~RibbonAUIArtProvider.DrawTool`, 1168 but not all of it will (unless there is only a single group of tools). 1169 1170 """ 1171 1172 self.DrawPartialPanelBackground(dc, wnd, rect) 1173 1174 1175 def DrawToolGroupBackground(self, dc, wnd, rect): 1176 """ 1177 Draw the background for a group of tools on a :class:`~wx.lib.agw.ribbon.toolbar.RibbonToolBar` control. 1178 1179 :param `dc`: The device context to draw onto; 1180 :param `wnd`: The window which is being drawn onto. In most cases this will 1181 be a :class:`~wx.lib.agw.ribbon.toolbar.RibbonToolBar`, but it doesn't have to be; 1182 :param `rect`: The rectangle within which to draw. This rectangle is a union 1183 of the individual tools' rectangles. As there are no gaps between tools, this 1184 rectangle will be painted over exactly once by calls to :meth:`~RibbonAUIArtProvider.DrawTool`. The 1185 group background could therefore be painted by :meth:`~RibbonAUIArtProvider.DrawTool`, though it can be 1186 conceptually easier and more efficient to draw it all at once here. The 1187 rectangle will be entirely within a rectangle on the same device context 1188 previously painted with :meth:`~RibbonAUIArtProvider.DrawToolBarBackground`. 1189 1190 """ 1191 1192 dc.SetPen(self._toolbar_border_pen) 1193 dc.SetBrush(wx.TRANSPARENT_BRUSH) 1194 dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height) 1195 bg_rect = wx.Rect(*rect) 1196 bg_rect.Deflate(1, 1) 1197 dc.GradientFillLinear(bg_rect, self._tool_background_colour, self._tool_background_gradient_colour, wx.SOUTH) 1198 1199 1200 def DrawTool(self, dc, wnd, rect, bitmap, kind, state): 1201 """ 1202 Draw a single tool (for a :class:`~wx.lib.agw.ribbon.toolbar.RibbonToolBar` control). 1203 1204 :param `dc`: The device context to draw onto; 1205 :param `wnd`: The window which is being drawn onto. In most cases this will 1206 be a :class:`~wx.lib.agw.ribbon.toolbar.RibbonToolBar`, but it doesn't have to be; 1207 :param `rect`: The rectangle within which to draw. The size of this rectangle 1208 will at least the size returned by :meth:`RibbonMSWArtProvider.GetToolSize() <lib.agw.ribbon.art_msw.RibbonMSWArtProvider.GetToolSize>`, 1209 and the height of it will 1210 be equal for all tools within the same group. The rectangle will be entirely 1211 within a rectangle on the same device context previously painted with 1212 :meth:`~RibbonAUIArtProvider.DrawToolGroupBackground`; 1213 :param `bitmap`: The bitmap to use as the tool's foreground. If the tool is a 1214 hybrid or dropdown tool, then the foreground should also contain a standard 1215 dropdown button; 1216 :param `kind`: The kind of tool to draw (normal, dropdown, or hybrid); 1217 :param `state`: A combination of `RibbonToolBarToolState` flags giving the 1218 state of the tool and it's relative position within a tool group. 1219 1220 """ 1221 1222 if kind == RIBBON_BUTTON_TOGGLE: 1223 if state & RIBBON_TOOLBAR_TOOL_TOGGLED: 1224 state ^= RIBBON_TOOLBAR_TOOL_ACTIVE_MASK 1225 1226 bg_rect = wx.Rect(*rect) 1227 bg_rect.Deflate(1, 1) 1228 1229 if state & RIBBON_TOOLBAR_TOOL_LAST == 0: 1230 bg_rect.width += 1 1231 1232 is_custom_bg = (state & (RIBBON_TOOLBAR_TOOL_HOVER_MASK | RIBBON_TOOLBAR_TOOL_ACTIVE_MASK)) != 0 1233 is_split_hybrid = kind == RIBBON_BUTTON_HYBRID and is_custom_bg 1234 1235 # Background 1236 if is_custom_bg: 1237 dc.SetPen(wx.TRANSPARENT_PEN) 1238 dc.SetBrush(self._tool_hover_background_brush) 1239 dc.DrawRectangle(bg_rect.x, bg_rect.y, bg_rect.width, bg_rect.height) 1240 1241 if state & RIBBON_TOOLBAR_TOOL_ACTIVE_MASK: 1242 active_rect = wx.Rect(*bg_rect) 1243 1244 if kind == RIBBON_BUTTON_HYBRID: 1245 active_rect.width -= 8 1246 1247 if state & RIBBON_TOOLBAR_TOOL_DROPDOWN_ACTIVE: 1248 active_rect.x += active_rect.width 1249 active_rect.width = 8 1250 1251 dc.SetBrush(self._tool_active_background_brush) 1252 dc.DrawRectangle(active_rect.x, active_rect.y, active_rect.width, active_rect.height) 1253 1254 # Border 1255 if is_custom_bg: 1256 dc.SetPen(self._toolbar_hover_borden_pen) 1257 else: 1258 dc.SetPen(self._toolbar_border_pen) 1259 1260 if state & RIBBON_TOOLBAR_TOOL_FIRST == 0: 1261 existing = dc.GetPixel(rect.x, rect.y + 1) 1262 1263 if existing == wx.NullColour or existing != self._toolbar_hover_borden_pen.GetColour(): 1264 dc.DrawLine(rect.x, rect.y + 1, rect.x, rect.y + rect.height - 1) 1265 1266 if is_custom_bg: 1267 border_rect = wx.Rect(*bg_rect) 1268 border_rect.Inflate(1, 1) 1269 dc.SetBrush(wx.TRANSPARENT_BRUSH) 1270 dc.DrawRectangle(border_rect.x, border_rect.y, border_rect.width, border_rect.height) 1271 1272 # Foreground 1273 avail_width = bg_rect.GetWidth() 1274 1275 if kind & RIBBON_BUTTON_DROPDOWN: 1276 avail_width -= 8 1277 if is_split_hybrid: 1278 dc.DrawLine(rect.x + avail_width + 1, rect.y, rect.x + avail_width + 1, rect.y + rect.height) 1279 1280 dc.DrawBitmap(self._toolbar_drop_bitmap, bg_rect.x + avail_width + 2, bg_rect.y + (bg_rect.height / 2) - 2, True) 1281 1282 dc.DrawBitmap(bitmap, bg_rect.x + (avail_width - bitmap.GetWidth()) / 2, bg_rect.y + (bg_rect.height - bitmap.GetHeight()) / 2, True) 1283 1284