""" MultiStateButton class @copyright: Copyright (c) 2006 Open Source Applications Foundation @license: http://osafoundation.org/Chandler_0.1_license_terms.htm """ import os import wx from wx.lib.buttons import GenBitmapButton class MultiStateButton(GenBitmapButton): """ A MultiStateButton can have more one of multiple bitmaps in its default state. These bitmaps are passed in as a list of names, which are also the names of the PNG/GIF/JPG/TIFF/PSD bitmaps. mailButton = MultiStateButton(view, 100, multibitmaps=["NoMailState", "MailState"]) will create a button with the two bitmaps MailState.png and NoMailState.png. The default initial value will be the first named state; in this case "NoMailState". When desired (presumably when mail comes in), the state of the button can be changed thusly: mailButton.SetState("MailState") and the button's bitmap will change to MailState.png. Later, after all the mail has been read, the button can be changed back: mailButton.SetState("NoMailState") """ kBitmapFileExtensions = ["png", "gif", "jpg", "tiff", "psd"] kBitsKey = "bitmap" kRolloverKey = "rollover" def __init__(self, parent, ID, label="", pos = wx.DefaultPosition, size = wx.DefaultSize, style = 0, validator = wx.DefaultValidator, name = "multistatebutton", multibitmaps = ()): """ Initialize the button to the usual button states, plus a list of button bitmap filenames and their optional rollover bitmap filenames @param multibitmaps: a list containing strings and/or tuples of two strings. Each item in the list represents a button state, the name of which is the base root name of the bitmap file. e.g. /var/share/NoMail.png would become the state "NoMail", and could thus be passed in to SetState(): SetState("NoMail"). If an item in the list is a tuple of two strings, the first string is the normal button bitmap filename, while the second is the rollover button bitmap filename. The rollover bitmap is displayed when the mouse just moves over the button. """ self.bitmapDict = {} self.unrolledStateName="" ##rae - Should really assert firstBitmap is not None somehow here super(MultiStateButton, self).__init__(parent, ID, firstBitmap, pos, size, style, validator, name) firstBitmapName, firstBitmap = self.AddStates(multibitmaps) self.stateName = firstBitmapName self.unrolledStateName=self.stateName # calls to Bind must come after call to super's __init__ self.Bind(wx.EVT_ENTER_WINDOW, self._RolloverStart) self.Bind(wx.EVT_LEAVE_WINDOW, self._RolloverFinish) def AddStates(self, multibitmaps): """ Add more state bitmaps to the button. @param multibitmaps: a list of strings or tuples of two strings. See __init__ for a description of this list. More bitmap states can be added at any time to the button. """ firstFound = None firstNameFound = None for name in multibitmaps: ## Suggestion from Heikki - use exceptions to handle non-tuple types ## a=(1,2) ## for b in a: ## print b ## ## c=3 ## try: ## for b in c: ## print b ## except TypeError: ## print c bitmap = None if type(name) == types.StringType: found = False bitmap = _GetBitmapFor(name) if bitmap is not None: self.bitmapDict[name] = {MultiStateButton.kBitsKey: bitmap} if not found: firstFound = self.bitmapDict[name][MultiStateButton.kBitsKey] firstNameFound = name found = True else: ##rae # should raise an error here somehow return firstNameFound, firstFound def SetState(self, inStateName): """ Set the current state name of the button. The appropriate bitmap will be used. @param multibitmaps: a list of strings or tuples of two strings. See __init__ for a description of this list. More bitmap states can be added at any time to the button. """ if(inStateName != self.stateName): bitmapDict = self.bitmapDict.get(inStateName) if bitmapDict != None: bitmap = bitmapDict[MultiStateButton.kBitsKey] self.SetBitmapLabel(bitmap) self.stateName = inStateName self.Refresh() # will the app need this call to Update? Perhaps not. Try removing it. self.Update() def GetState(self): """ Return the current state name of the button. """ return self.stateName def _RolloverStart(self, event): """ Change the state of the button to its possible rollover state. """ ##rae assert self.bitmapDict.get(self.stateName) is not None stateDict = self.bitmapDict[self.stateName] if stateDict.get(kRolloverKey) is not None: self.SetState(stateDict[kRolloverKey]) self.unrolledStateName = self.stateName self.SetState("button3") def _RolloverFinish(self, event): """ Return the button to its non-rollover state. """ self.SetState(self.unrolledStateName) def _GetBitmapFor(str): """ Find the named bitmap, checking various file type extensions (are these available inside wx.Image somewhere?) """ bitmap = None for ext in MultiStateButton.kBitmapFileExtensions: try: img = wx.Image('%s.%s' % str, ext) bitmap = img.ConvertToBitmap() break except IOError: # file was not found pass return bitmap if __name__ == "__main__": theWindow = wx.Frame(parent=None, id=-1, title="MultiButton testing") b = MultiStateButton(theWindow, 1010, multibitmaps=['button1', 'button2', 'button3', 'button4']) box = wx.BoxSizer(wx.HORIZONTAL) box.Add(b) theWindow.SetSizer(box) theWindow.Show() #box.Add(MultiStateButton(theWindow, 1010, multibitmaps=['button1', 'button2'])) #box.Add(MultiStateButton(theWindow, 1010, multibitmaps=['button3', 'button4'])) #box.Add(MultiStateButton(theWindow, 1010, multibitmaps=['button1', 'button2', 'button3', 'button4', 'button5']))