1############################################################################### 2# Name: platebtn.py # 3# Purpose: PlateButton is a flat label button with support for bitmaps and # 4# drop menu. # 5# Author: Cody Precord <cprecord@editra.org> # 6# Copyright: (c) 2007 Cody Precord <staff@editra.org> # 7# Licence: wxWindows Licence # 8# Tags: phoenix-port 9############################################################################### 10 11""" 12Editra Control Library: PlateButton 13 14The PlateButton is a custom owner drawn flat button, that in many ways emulates 15the buttons found the bookmark bar of the Safari browser. It can be used as a 16drop in replacement for wx.Button/wx.BitmapButton under most circumstances. It 17also offers a wide range of options for customizing its appearance, a 18description of each of the main style settings is listed below. 19 20Main Button Styles: 21Any combination of the following values may be passed to the constructor's style 22keyword parameter. 23 24PB_STYLE_DEFAULT: 25Creates a flat label button with rounded corners, the highlight for mouse over 26and press states is based off of the hightlight color from the systems current 27theme. 28 29PB_STYLE_GRADIENT: 30The highlight and press states are drawn with gradient using the current 31highlight color. 32 33PB_STYLE_SQUARE: 34Instead of the default rounded shape use a rectangular shaped button with 35square edges. 36 37PB_STYLE_NOBG: 38This style only has an effect on Windows but does not cause harm to use on the 39platforms. It should only be used when the control is shown on a panel or other 40window that has a non solid color for a background. i.e a gradient or image is 41painted on the background of the parent window. If used on a background with 42a solid color it may cause the control to loose its transparent appearance. 43 44PB_STYLE_DROPARROW: 45Add a drop button arrow to the button that will send a separate event when 46clicked on. 47 48Other attributes can be configured after the control has been created. The 49settings that are currently available are as follows: 50 51 - SetBitmap: Change/Add the bitmap at any time and the control will resize and 52 refresh to display it. 53 - SetLabelColor: Explicitly set text colors 54 - SetMenu: Set the button to have a popupmenu. When a menu is set a small drop 55 arrow will be drawn on the button that can then be clicked to show 56 a menu. 57 - SetPressColor: Use a custom highlight color 58 59 60Overridden Methods Inherited from PyControl: 61 62 - SetFont: Changing the font is one way to set the size of the button, by 63 default the control will inherit its font from its parent. 64 65 - SetWindowVariant: Setting the window variant will cause the control to 66 resize to the corresponding variant size. However if the 67 button is using a bitmap the bitmap will remain unchanged 68 and only the font will be adjusted. 69 70Requirements: 71 - python2.4 or higher 72 - wxPython2.8 or higher 73 74""" 75 76__author__ = "Cody Precord <cprecord@editra.org>" 77 78__all__ = ["PlateButton", 79 "PLATE_NORMAL", "PLATE_PRESSED", "PLATE_HIGHLIGHT", 80 81 "PB_STYLE_DEFAULT", "PB_STYLE_GRADIENT", "PB_STYLE_SQUARE", 82 "PB_STYLE_NOBG", "PB_STYLE_DROPARROW", "PB_STYLE_TOGGLE", 83 84 "EVT_PLATEBTN_DROPARROW_PRESSED"] 85 86#-----------------------------------------------------------------------------# 87# Imports 88import wx 89import wx.lib.newevent 90 91# Local Imports 92from wx.lib.colourutils import * 93 94#-----------------------------------------------------------------------------# 95# Button States 96PLATE_NORMAL = 0 97PLATE_PRESSED = 1 98PLATE_HIGHLIGHT = 2 99 100# Button Styles 101PB_STYLE_DEFAULT = 1 # Normal Flat Background 102PB_STYLE_GRADIENT = 2 # Gradient Filled Background 103PB_STYLE_SQUARE = 4 # Use square corners instead of rounded 104PB_STYLE_NOBG = 8 # Useful on Windows to get a transparent appearance 105 # when the control is shown on a non solid background 106PB_STYLE_DROPARROW = 16 # Draw drop arrow and fire EVT_PLATEBTN_DROPRROW_PRESSED event 107PB_STYLE_TOGGLE = 32 # Stay pressed until clicked again 108 109#-----------------------------------------------------------------------------# 110 111# EVT_BUTTON used for normal event notification 112# EVT_TOGGLE_BUTTON used for toggle button mode notification 113PlateBtnDropArrowPressed, EVT_PLATEBTN_DROPARROW_PRESSED = wx.lib.newevent.NewEvent() 114 115#-----------------------------------------------------------------------------# 116 117class PlateButton(wx.Control): 118 """PlateButton is a custom type of flat button with support for 119 displaying bitmaps and having an attached dropdown menu. 120 121 """ 122 def __init__(self, parent, id=wx.ID_ANY, label='', bmp=None, 123 pos=wx.DefaultPosition, size=wx.DefaultSize, 124 style=PB_STYLE_DEFAULT, name=wx.ButtonNameStr): 125 """Create a PlateButton 126 127 :keyword string `label`: Buttons label text 128 :keyword wx.Bitmap `bmp`: Buttons bitmap 129 :keyword `style`: Button style 130 131 """ 132 super(PlateButton, self).__init__(parent, id, pos, size, 133 wx.BORDER_NONE|wx.TRANSPARENT_WINDOW, 134 name=name) 135 136 # Attributes 137 self.InheritAttributes() 138 self._bmp = dict(enable=None, disable=None) 139 if bmp is not None: 140 assert isinstance(bmp, wx.Bitmap) and bmp.IsOk() 141 self._bmp['enable'] = bmp 142 img = bmp.ConvertToImage() 143 img = img.ConvertToGreyscale(.795, .073, .026) #(.634, .224, .143) 144 self._bmp['disable'] = wx.Bitmap(img) 145 146 self._menu = None 147 self.SetLabel(label) 148 self._style = style 149 self._state = dict(pre=PLATE_NORMAL, cur=PLATE_NORMAL) 150 self._color = self.__InitColors() 151 self._pressed = False 152 153 # Setup Initial Size 154 self.SetInitialSize(size) 155 156 # Event Handlers 157 self.Bind(wx.EVT_PAINT, lambda evt: self.__DrawButton()) 158 self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnErase) 159 self.Bind(wx.EVT_SET_FOCUS, self.OnFocus) 160 self.Bind(wx.EVT_KILL_FOCUS, self.OnKillFocus) 161 162 # Mouse Events 163 self.Bind(wx.EVT_LEFT_DCLICK, lambda evt: self._ToggleState()) 164 self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) 165 self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) 166 self.Bind(wx.EVT_ENTER_WINDOW, 167 lambda evt: self._SetState(PLATE_HIGHLIGHT)) 168 self.Bind(wx.EVT_LEAVE_WINDOW, 169 lambda evt: wx.CallLater(80, self.__LeaveWindow)) 170 171 # Other events 172 self.Bind(wx.EVT_KEY_UP, self.OnKeyUp) 173 self.Bind(wx.EVT_CONTEXT_MENU, lambda evt: self.ShowMenu()) 174 175 176 def __DrawBitmap(self, gc): 177 """Draw the bitmap if one has been set 178 179 :param wx.GCDC `gc`: :class:`wx.GCDC` to draw with 180 :return: x cordinate to draw text at 181 182 """ 183 if self.IsEnabled(): 184 bmp = self._bmp['enable'] 185 else: 186 bmp = self._bmp['disable'] 187 188 if bmp is not None and bmp.IsOk(): 189 bw, bh = bmp.GetSize() 190 ypos = (self.GetSize()[1] - bh) // 2 191 gc.DrawBitmap(bmp, 6, ypos, bmp.GetMask() != None) 192 return bw + 6 193 else: 194 return 6 195 196 197 def __DrawDropArrow(self, gc, xpos, ypos): 198 """Draw a drop arrow if needed and restore pen/brush after finished 199 200 :param wx.GCDC `gc`: :class:`wx.GCDC` to draw with 201 :param int `xpos`: x cord to start at 202 :param int `ypos`: y cord to start at 203 204 """ 205 if self._menu is not None or self._style & PB_STYLE_DROPARROW: 206 # Positioning needs a little help on Windows 207 if wx.Platform == '__WXMSW__': 208 xpos -= 2 209 tripoints = [(xpos, ypos), (xpos + 6, ypos), (xpos + 3, ypos + 5)] 210 brush_b = gc.GetBrush() 211 pen_b = gc.GetPen() 212 gc.SetPen(wx.TRANSPARENT_PEN) 213 gc.SetBrush(wx.Brush(gc.GetTextForeground())) 214 gc.DrawPolygon(tripoints) 215 gc.SetBrush(brush_b) 216 gc.SetPen(pen_b) 217 else: 218 pass 219 220 221 def __DrawHighlight(self, gc, width, height): 222 """Draw the main highlight/pressed state 223 224 :param wx.GCDC `gc`: :class:`wx.GCDC` to draw with 225 :param int `width`: width of highlight 226 :param int `height`: height of highlight 227 228 """ 229 if self._state['cur'] == PLATE_PRESSED: 230 color = self._color['press'] 231 else: 232 color = self._color['hlight'] 233 234 if self._style & PB_STYLE_SQUARE: 235 rad = 0 236 else: 237 rad = (height - 3) / 2 238 239 if self._style & PB_STYLE_GRADIENT: 240 gc.SetBrush(wx.TRANSPARENT_BRUSH) 241 rgc = gc.GetGraphicsContext() 242 brush = rgc.CreateLinearGradientBrush(0, 1, 0, height, 243 color, AdjustAlpha(color, 55)) 244 rgc.SetBrush(brush) 245 else: 246 gc.SetBrush(wx.Brush(color)) 247 248 gc.DrawRoundedRectangle(1, 1, width - 2, height - 2, rad) 249 250 251 def __PostEvent(self): 252 """Post a button event to parent of this control""" 253 if self._style & PB_STYLE_TOGGLE: 254 etype = wx.wxEVT_COMMAND_TOGGLEBUTTON_CLICKED 255 else: 256 etype = wx.wxEVT_COMMAND_BUTTON_CLICKED 257 bevt = wx.CommandEvent(etype, self.GetId()) 258 bevt.SetEventObject(self) 259 bevt.SetString(self.GetLabel()) 260 self.GetEventHandler().ProcessEvent(bevt) 261 262 263 def __DrawButton(self): 264 """Draw the button""" 265 # TODO using a buffered paintdc on windows with the nobg style 266 # causes lots of weird drawing. So currently the use of a 267 # buffered dc is dissabled for this style. 268 if PB_STYLE_NOBG & self._style: 269 dc = wx.PaintDC(self) 270 else: 271 dc = wx.AutoBufferedPaintDCFactory(self) 272 273 gc = wx.GCDC(dc) 274 275 # Setup 276 dc.SetBrush(wx.TRANSPARENT_BRUSH) 277 gc.SetBrush(wx.TRANSPARENT_BRUSH) 278 gc.SetFont(self.Font) 279 dc.SetFont(self.Font) 280 gc.SetBackgroundMode(wx.TRANSPARENT) 281 282 # The background needs some help to look transparent on 283 # on Gtk and Windows 284 if wx.Platform in ['__WXGTK__', '__WXMSW__']: 285 gc.SetBackground(self.GetBackgroundBrush(gc)) 286 gc.Clear() 287 288 # Calc Object Positions 289 width, height = self.GetSize() 290 if wx.Platform == '__WXGTK__': 291 tw, th = dc.GetTextExtent(self.Label) 292 else: 293 tw, th = gc.GetTextExtent(self.Label) 294 txt_y = max((height - th) // 2, 1) 295 296 if self._state['cur'] == PLATE_HIGHLIGHT: 297 gc.SetTextForeground(self._color['htxt']) 298 gc.SetPen(wx.TRANSPARENT_PEN) 299 self.__DrawHighlight(gc, width, height) 300 301 elif self._state['cur'] == PLATE_PRESSED: 302 gc.SetTextForeground(self._color['htxt']) 303 if wx.Platform == '__WXMAC__': 304 pen = wx.Pen(GetHighlightColour(), 1, wx.PENSTYLE_SOLID) 305 else: 306 pen = wx.Pen(AdjustColour(self._color['press'], -80, 220), 1) 307 gc.SetPen(pen) 308 309 self.__DrawHighlight(gc, width, height) 310 txt_x = self.__DrawBitmap(gc) 311 if wx.Platform == '__WXGTK__': 312 dc.DrawText(self.Label, txt_x + 2, txt_y) 313 else: 314 gc.DrawText(self.Label, txt_x + 2, txt_y) 315 self.__DrawDropArrow(gc, width - 10, (height // 2) - 2) 316 317 else: 318 if self.IsEnabled(): 319 gc.SetTextForeground(self.GetForegroundColour()) 320 else: 321 txt_c = wx.SystemSettings.GetColour(wx.SYS_COLOUR_GRAYTEXT) 322 gc.SetTextForeground(txt_c) 323 324 # Draw bitmap and text 325 if self._state['cur'] != PLATE_PRESSED: 326 txt_x = self.__DrawBitmap(gc) 327 if wx.Platform == '__WXGTK__': 328 dc.DrawText(self.Label, txt_x + 2, txt_y) 329 else: 330 gc.DrawText(self.Label, txt_x + 2, txt_y) 331 self.__DrawDropArrow(gc, width - 10, (height // 2) - 2) 332 333 334 def __InitColors(self): 335 """Initialize the default colors""" 336 color = GetHighlightColour() 337 pcolor = AdjustColour(color, -12) 338 colors = dict(default=True, 339 hlight=color, 340 press=pcolor, 341 htxt=BestLabelColour(self.GetForegroundColour())) 342 return colors 343 344 345 def __LeaveWindow(self): 346 """Handle updating the buttons state when the mouse cursor leaves""" 347 if (self._style & PB_STYLE_TOGGLE) and self._pressed: 348 self._SetState(PLATE_PRESSED) 349 else: 350 self._SetState(PLATE_NORMAL) 351 self._pressed = False 352 353 354 def _SetState(self, state): 355 """Manually set the state of the button 356 357 :param `state`: one of the PLATE_* values 358 359 .. note:: 360 the state may be altered by mouse actions 361 362 .. note:: 363 Internal use only! 364 365 """ 366 self._state['pre'] = self._state['cur'] 367 self._state['cur'] = state 368 if wx.Platform == '__WXMSW__': 369 self.Parent.RefreshRect(self.Rect, False) 370 else: 371 self.Refresh() 372 373 374 def _ToggleState(self): 375 """Toggle button state 376 377 ..note:: 378 Internal Use Only! 379 380 """ 381 if self._state['cur'] != PLATE_PRESSED: 382 self._SetState(PLATE_PRESSED) 383 else: 384 self._SetState(PLATE_HIGHLIGHT) 385 386 #---- End Private Member Function ----# 387 388 #---- Public Member Functions ----# 389 390 BitmapDisabled = property(lambda self: self.GetBitmapDisabled(), 391 lambda self, bmp: self.SetBitmapDisabled(bmp)) 392 BitmapLabel = property(lambda self: self.GetBitmapLabel(), 393 lambda self, bmp: self.SetBitmap(bmp)) 394 395 # Aliases 396 BitmapFocus = BitmapLabel 397 BitmapHover = BitmapLabel 398 BitmapSelected = BitmapLabel 399 400 LabelText = property(lambda self: self.GetLabel(), 401 lambda self, lbl: self.SetLabel(lbl)) 402 403 404 def AcceptsFocus(self): 405 """Can this window have the focus?""" 406 return self.IsEnabled() 407 408 409 def Disable(self): 410 """Disable the control""" 411 super(PlateButton, self).Disable() 412 self.Refresh() 413 414 415 def DoGetBestSize(self): 416 """Calculate the best size of the button 417 418 :return: :class:`wx.Size` 419 420 """ 421 width = 4 422 height = 6 423 if self.Label: 424 # NOTE: Should measure with a GraphicsContext to get right 425 # size, but due to random segfaults on linux special 426 # handling is done in the drawing instead... 427 lsize = self.GetFullTextExtent(self.Label) 428 width += lsize[0] 429 height += lsize[1] 430 431 if self._bmp['enable'] is not None: 432 bsize = self._bmp['enable'].Size 433 width += (bsize[0] + 10) 434 if height <= bsize[1]: 435 height = bsize[1] + 6 436 else: 437 height += 3 438 else: 439 width += 10 440 441 if self._menu is not None or self._style & PB_STYLE_DROPARROW: 442 width += 12 443 444 best = wx.Size(width, height) 445 self.CacheBestSize(best) 446 return best 447 448 449 def Enable(self, enable=True): 450 """Enable/Disable the control""" 451 super(PlateButton, self).Enable(enable) 452 self.Refresh() 453 454 455 def GetBackgroundBrush(self, dc): 456 """Get the brush for drawing the background of the button 457 458 :return: :class:`wx.Brush` 459 460 ..note:: 461 used internally when on gtk 462 463 """ 464 if wx.Platform == '__WXMAC__' or self._style & PB_STYLE_NOBG: 465 return wx.TRANSPARENT_BRUSH 466 467 bkgrd = self.GetBackgroundColour() 468 brush = wx.Brush(bkgrd, wx.BRUSHSTYLE_SOLID) 469 my_attr = self.GetDefaultAttributes() 470 p_attr = self.Parent.GetDefaultAttributes() 471 my_def = bkgrd == my_attr.colBg 472 p_def = self.Parent.GetBackgroundColour() == p_attr.colBg 473 if my_def and not p_def: 474 bkgrd = self.Parent.GetBackgroundColour() 475 brush = wx.Brush(bkgrd, wx.BRUSHSTYLE_SOLID) 476 return brush 477 478 479 def GetBitmapDisabled(self): 480 """Get the bitmap of the disable state 481 482 :return: :class:`wx.Bitmap` or None 483 484 """ 485 return self.BitmapDisabled 486 487 488 def GetBitmapLabel(self): 489 """Get the label bitmap 490 491 :return: :class:`wx.Bitmap` or None 492 493 """ 494 return self.BitmapLabel 495 496 # GetBitmap Aliases for BitmapButton api 497 GetBitmapFocus = GetBitmapLabel 498 GetBitmapHover = GetBitmapLabel 499 500 # Alias for GetLabel 501 GetLabelText = wx.Control.GetLabel 502 503 504 def GetMenu(self): 505 """Return the menu associated with this button or None if no 506 menu is associated with it. 507 508 """ 509 return self._menu 510 511 512 def GetState(self): 513 """Get the current state of the button 514 515 :return: int 516 517 .. seeAlso:: 518 PLATE_NORMAL, PLATE_HIGHLIGHT, PLATE_PRESSED 519 520 """ 521 return self._state['cur'] 522 523 524 def HasTransparentBackground(self): 525 """Override setting of background fill""" 526 return True 527 528 529 def IsPressed(self): 530 """Return if button is pressed (PB_STYLE_TOGGLE) 531 532 :return: bool 533 534 """ 535 return self._pressed 536 537 538 #---- Event Handlers ----# 539 540 def OnErase(self, evt): 541 """Trap the erase event to keep the background transparent 542 on windows. 543 544 :param `evt`: wx.EVT_ERASE_BACKGROUND 545 546 """ 547 pass 548 549 550 def OnFocus(self, evt): 551 """Set the visual focus state if need be""" 552 if self._state['cur'] == PLATE_NORMAL: 553 self._SetState(PLATE_HIGHLIGHT) 554 555 556 def OnKeyUp(self, evt): 557 """Execute a single button press action when the Return key is pressed 558 and this control has the focus. 559 560 :param `evt`: wx.EVT_KEY_UP 561 562 """ 563 if evt.GetKeyCode() == wx.WXK_SPACE: 564 self._SetState(PLATE_PRESSED) 565 self.__PostEvent() 566 wx.CallLater(100, self._SetState, PLATE_HIGHLIGHT) 567 else: 568 evt.Skip() 569 570 571 def OnKillFocus(self, evt): 572 """Set the visual state back to normal when focus is lost 573 unless the control is currently in a pressed state. 574 575 """ 576 # Note: this delay needs to be at least as much as the on in the KeyUp 577 # handler to prevent ghost highlighting from happening when 578 # quickly changing focus and activating buttons 579 if self._state['cur'] != PLATE_PRESSED: 580 self._SetState(PLATE_NORMAL) 581 582 583 def OnLeftDown(self, evt): 584 """Sets the pressed state and depending on the click position will 585 show the popup menu if one has been set. 586 587 """ 588 if (self._style & PB_STYLE_TOGGLE): 589 self._pressed = not self._pressed 590 591 pos = evt.GetPosition() 592 self._SetState(PLATE_PRESSED) 593 size = self.GetSize() 594 if pos[0] >= size[0] - 16: 595 if self._menu is not None: 596 self.ShowMenu() 597 elif self._style & PB_STYLE_DROPARROW: 598 event = PlateBtnDropArrowPressed() 599 event.SetEventObject(self) 600 self.EventHandler.ProcessEvent(event) 601 602 self.SetFocus() 603 604 605 def OnLeftUp(self, evt): 606 """Post a button event if the control was previously in a 607 pressed state. 608 609 :param `evt`: :class:`wx.MouseEvent` 610 611 """ 612 if self._state['cur'] == PLATE_PRESSED: 613 pos = evt.GetPosition() 614 size = self.GetSize() 615 if not (self._style & PB_STYLE_DROPARROW and pos[0] >= size[0] - 16): 616 self.__PostEvent() 617 618 if self._pressed: 619 self._SetState(PLATE_PRESSED) 620 else: 621 self._SetState(PLATE_HIGHLIGHT) 622 623 624 def OnMenuClose(self, evt): 625 """Refresh the control to a proper state after the menu has been 626 dismissed. 627 628 :param `evt`: wx.EVT_MENU_CLOSE 629 630 """ 631 mpos = wx.GetMousePosition() 632 if self.HitTest(self.ScreenToClient(mpos)) != wx.HT_WINDOW_OUTSIDE: 633 self._SetState(PLATE_HIGHLIGHT) 634 else: 635 self._SetState(PLATE_NORMAL) 636 evt.Skip() 637 638 #---- End Event Handlers ----# 639 640 641 def SetBitmap(self, bmp): 642 """Set the bitmap displayed in the button 643 644 :param `bmp`: :class:`wx.Bitmap` 645 646 """ 647 self._bmp['enable'] = bmp 648 img = bmp.ConvertToImage() 649 img = img.ConvertToGreyscale(.795, .073, .026) #(.634, .224, .143) 650 self._bmp['disable'] = img.ConvertToBitmap() 651 self.InvalidateBestSize() 652 653 654 def SetBitmapDisabled(self, bmp): 655 """Set the bitmap for the disabled state 656 657 :param `bmp`: :class:`wx.Bitmap` 658 659 """ 660 self._bmp['disable'] = bmp 661 662 # Aliases for SetBitmap* functions from BitmapButton 663 SetBitmapFocus = SetBitmap 664 SetBitmapHover = SetBitmap 665 SetBitmapLabel = SetBitmap 666 SetBitmapSelected = SetBitmap 667 668 669 def SetFocus(self): 670 """Set this control to have the focus""" 671 if self._state['cur'] != PLATE_PRESSED: 672 self._SetState(PLATE_HIGHLIGHT) 673 super(PlateButton, self).SetFocus() 674 675 676 def SetFont(self, font): 677 """Adjust size of control when font changes""" 678 super(PlateButton, self).SetFont(font) 679 self.InvalidateBestSize() 680 681 682 def SetLabel(self, label): 683 """Set the label of the button 684 685 :param string `label`: label string 686 687 """ 688 super(PlateButton, self).SetLabel(label) 689 self.InvalidateBestSize() 690 691 692 def SetLabelColor(self, normal, hlight=wx.NullColour): 693 """Set the color of the label. The optimal label color is usually 694 automatically selected depending on the button color. In some 695 cases the colors that are chosen may not be optimal. 696 697 The normal state must be specified, if the other two params are left 698 Null they will be automatically guessed based on the normal color. To 699 prevent this automatic color choices from happening either specify 700 a color or None for the other params. 701 702 :param wx.Colour `normal`: Label color for normal state (:class:`wx.Colour`) 703 :keyword wx.Colour `hlight`: Color for when mouse is hovering over 704 705 """ 706 assert isinstance(normal, wx.Colour), "Must supply a colour object" 707 self._color['default'] = False 708 self.SetForegroundColour(normal) 709 710 if hlight is not None: 711 if hlight.IsOk(): 712 self._color['htxt'] = hlight 713 else: 714 self._color['htxt'] = BestLabelColour(normal) 715 716 if wx.Platform == '__WXMSW__': 717 self.Parent.RefreshRect(self.GetRect(), False) 718 else: 719 self.Refresh() 720 721 722 def SetMenu(self, menu): 723 """Set the menu that can be shown when clicking on the 724 drop arrow of the button. 725 726 :param wx.Menu `menu`: :class:`wx.Menu` to use as a PopupMenu 727 728 .. note:: 729 Arrow is not drawn unless a menu is set 730 731 """ 732 if self._menu is not None: 733 self.Unbind(wx.EVT_MENU_CLOSE) 734 735 self._menu = menu 736 self.Bind(wx.EVT_MENU_CLOSE, self.OnMenuClose) 737 self.InvalidateBestSize() 738 739 740 def SetPressColor(self, color): 741 """Set the color used for highlighting the pressed state 742 743 :param wx.Colour `color`: :class:`wx.Colour` 744 745 .. note:: 746 also resets all text colours as necessary 747 748 """ 749 self._color['default'] = False 750 if color.Alpha() == 255: 751 self._color['hlight'] = AdjustAlpha(color, 200) 752 else: 753 self._color['hlight'] = color 754 self._color['press'] = AdjustColour(color, -10, 160) 755 self._color['htxt'] = BestLabelColour(self._color['hlight']) 756 self.Refresh() 757 758 759 def SetWindowStyle(self, style): 760 """Sets the window style bytes, the updates take place 761 immediately no need to call refresh afterwards. 762 763 :param `style`: bitmask of PB_STYLE_* values 764 765 """ 766 self._style = style 767 self.Refresh() 768 769 770 def SetWindowVariant(self, variant): 771 """Set the variant/font size of this control""" 772 super(PlateButton, self).SetWindowVariant(variant) 773 self.InvalidateBestSize() 774 775 776 def ShouldInheritColours(self): 777 """Overridden base class virtual. If the parent has non-default 778 colours then we want this control to inherit them. 779 780 """ 781 return True 782 783 784 def ShowMenu(self): 785 """Show the dropdown menu if one is associated with this control""" 786 if self._menu is not None: 787 self.PopupMenu(self._menu) 788 789 #---- End Public Member Functions ----# 790