Commit 45f41b2a92b435fa35550745dc4b4764a4695b83

Authored by tatiana
1 parent 765497ba

ADD: PlateButton with toggle functionality

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