From: Robin Dunn Date: Tue, 3 Oct 2006 21:23:17 +0000 (+0000) Subject: Added the wx.lib.buttonpanel module, which is a tweaked version of X-Git-Url: https://git.saurik.com/wxWidgets.git/commitdiff_plain/66dae888d1b46d754469d990a2bbc957163f0bad Added the wx.lib.buttonpanel module, which is a tweaked version of Andrea Gavana's FancyButtonPanel module. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41605 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- diff --git a/wxPython/demo/ButtonPanel.py b/wxPython/demo/ButtonPanel.py new file mode 100644 index 0000000000..97875b6a40 --- /dev/null +++ b/wxPython/demo/ButtonPanel.py @@ -0,0 +1,198 @@ + +import wx +import wx.lib.buttonpanel as bp +import images + +#---------------------------------------------------------------------- +class ButtonPanelDemo(wx.Frame): + + def __init__(self, parent, id=wx.ID_ANY, title="ButtonPanel wxPython Demo", *args, **kw): + + wx.Frame.__init__(self, parent, id, title, *args, **kw) + + self.CreateMenuBar() + + self.statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP) + self.statusbar.SetStatusWidths([-2, -1]) + # statusbar fields + statusbar_fields = [("ButtonPanel wxPython Demo, Andrea Gavana @ 02 Oct 2006"), + ("Welcome To wxPython!")] + + for i in range(len(statusbar_fields)): + self.statusbar.SetStatusText(statusbar_fields[i], i) + + mainPanel = wx.Panel(self, -1) + self.logtext = wx.TextCtrl(mainPanel, -1, "", size=(-1, 250), + style=wx.TE_MULTILINE|wx.TE_READONLY|wx.TE_RICH2) + + vSizer = wx.BoxSizer(wx.VERTICAL) + mainPanel.SetSizer(vSizer) + + # Create the buttons and place them on the + # tab area of the main book + alignment = bp.BP_ALIGN_RIGHT + self.titleBar = bp.ButtonPanel(mainPanel, -1, "A Simple Test & Demo", + alignment=alignment) + + self.btn1bmp = images.get_bp_btn1Bitmap() + self.btn2bmp = images.get_bp_btn2Bitmap() + self.btn3bmp = images.get_bp_btn3Bitmap() + self.btn4bmp = images.get_bp_btn4Bitmap() + self.CreateButtons(alignment) + + # set the color the text is drawn with + self.titleBar.SetColor(bp.BP_TEXT_COLOR, wx.WHITE) + + # These default to white and whatever is set in the system + # settings for the wx.SYS_COLOUR_ACTIVECAPTION. We'll use + # some specific settings to ensure a consistent look for the + # demo. + self.titleBar.SetColor(bp.BP_CAPTION_BORDER_COLOR, wx.Colour(120,23,224)) + self.titleBar.SetColor(bp.BP_CAPTION_COLOR, wx.Colour(60,11,112)) + self.titleBar.SetColor(bp.BP_CAPTION_GRADIENT_COLOR, wx.Colour(120,23,224)) + + vSizer.Add(self.titleBar, 0, wx.EXPAND) + vSizer.Add(self.logtext, 1, wx.EXPAND|wx.ALL, 5) + vSizer.Layout() + + sizer = wx.BoxSizer() + sizer.Add(mainPanel, 1, wx.EXPAND) + self.SetSizer(sizer) + self.Fit() + + + def CreateMenuBar(self): + mb = wx.MenuBar() + + file_menu = wx.Menu() + item = wx.MenuItem(file_menu, wx.ID_ANY, "&Quit") + file_menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnClose, item) + + edit_menu = wx.Menu() + item = wx.MenuItem(edit_menu, wx.ID_ANY, "BP_ALIGN_RIGHT", kind=wx.ITEM_RADIO) + edit_menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnAlignRight, item) + item = wx.MenuItem(edit_menu, wx.ID_ANY, "BP_ALIGN_LEFT", kind=wx.ITEM_RADIO) + edit_menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnAlignLeft, item) + + help_menu = wx.Menu() + item = wx.MenuItem(help_menu, wx.ID_ANY, "&About...") + help_menu.AppendItem(item) + self.Bind(wx.EVT_MENU, self.OnAbout, item) + + mb.Append(file_menu, "&File") + mb.Append(edit_menu, "&Edit") + mb.Append(help_menu, "&Help") + + self.SetMenuBar(mb) + + + def CreateButtons(self, alignment=bp.BP_ALIGN_RIGHT): + self.buttons = [] + self.Freeze() + + self.titleBar.RemoveAllButtons() + + bmps = [ self.btn1bmp, + self.btn2bmp, + self.btn3bmp, + self.btn4bmp, + ] + if alignment == bp.BP_ALIGN_LEFT: + bmps.reverse() + + for bmp in bmps: + btn = bp.ButtonInfo(wx.NewId(), bmp) + self.titleBar.AddButton(btn) + self.Bind(wx.EVT_BUTTON, self.OnButton, btn) + self.buttons.append(btn.GetId()) + + self.strings = ["First", "Second", "Third", "Fourth"] + if alignment == bp.BP_ALIGN_RIGHT: + self.strings.reverse() + + self.titleBar.SetAlignment(alignment) + self.Thaw() + + + def OnAlignLeft(self, event): + self.CreateButtons(alignment=bp.BP_ALIGN_LEFT) + event.Skip() + + + def OnAlignRight(self, event): + self.CreateButtons(alignment=bp.BP_ALIGN_RIGHT) + event.Skip() + + + def OnButton(self, event): + btn = event.GetId() + indx = self.buttons.index(btn) + self.logtext.AppendText("Event Fired From " + self.strings[indx] + " Button\n") + event.Skip() + + + def OnClose(self, event): + self.Destroy() + event.Skip() + + + def OnAbout(self, event): + + msg = "This Is The About Dialog Of The ButtonPanel Demo.\n\n" + \ + "Author: Andrea Gavana @ 02 Oct 2006\n\n" + \ + "Please Report Any Bug/Requests Of Improvements\n" + \ + "To Me At The Following Adresses:\n\n" + \ + "andrea.gavana@gmail.com\n" + "gavana@kpo.kz\n\n" + \ + "Based On Eran C++ Implementation (wxWidgets Forum).\n\n" + \ + "Welcome To wxPython " + wx.VERSION_STRING + "!!" + + dlg = wx.MessageDialog(self, msg, "ButtonPanel wxPython Demo", + wx.OK | wx.ICON_INFORMATION) + dlg.ShowModal() + dlg.Destroy() + +#---------------------------------------------------------------------- + +class TestPanel(wx.Panel): + def __init__(self, parent, log): + self.log = log + wx.Panel.__init__(self, parent, -1) + + b = wx.Button(self, -1, " Test ButtonPanel ", (50,50)) + self.Bind(wx.EVT_BUTTON, self.OnButton, b) + + + def OnButton(self, evt): + self.win = ButtonPanelDemo(self) + self.win.Show(True) + + +#---------------------------------------------------------------------- + +def runTest(frame, nb, log): + win = TestPanel(nb, log) + return win + +#---------------------------------------------------------------------- + + + +overview = """ +

Say something nice here

+ + +""" + + + +if __name__ == '__main__': + import sys,os + import run + run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:]) + + + + diff --git a/wxPython/demo/Main.py b/wxPython/demo/Main.py index c7bbb1b03e..f45ed72242 100644 --- a/wxPython/demo/Main.py +++ b/wxPython/demo/Main.py @@ -63,6 +63,7 @@ _treeList = [ ## 'AlphaDrawing', 'DelayedResult', 'ExpandoTextCtrl', + 'ButtonPanel', ]), # managed windows == things with a (optional) caption you can close @@ -146,6 +147,7 @@ _treeList = [ ('Custom Controls', [ 'AnalogClock', + 'ButtonPanel', 'ColourSelect', 'ComboTreeBox', 'Editor', diff --git a/wxPython/demo/bmp_source/bp_btn1.png b/wxPython/demo/bmp_source/bp_btn1.png new file mode 100644 index 0000000000..4148ab8811 Binary files /dev/null and b/wxPython/demo/bmp_source/bp_btn1.png differ diff --git a/wxPython/demo/bmp_source/bp_btn2.png b/wxPython/demo/bmp_source/bp_btn2.png new file mode 100644 index 0000000000..b6e026a630 Binary files /dev/null and b/wxPython/demo/bmp_source/bp_btn2.png differ diff --git a/wxPython/demo/bmp_source/bp_btn3.png b/wxPython/demo/bmp_source/bp_btn3.png new file mode 100644 index 0000000000..ba62593ee2 Binary files /dev/null and b/wxPython/demo/bmp_source/bp_btn3.png differ diff --git a/wxPython/demo/bmp_source/bp_btn4.png b/wxPython/demo/bmp_source/bp_btn4.png new file mode 100644 index 0000000000..0109cecda4 Binary files /dev/null and b/wxPython/demo/bmp_source/bp_btn4.png differ diff --git a/wxPython/demo/encode_bitmaps.py b/wxPython/demo/encode_bitmaps.py index 5dfd878cf6..6574d39229 100644 --- a/wxPython/demo/encode_bitmaps.py +++ b/wxPython/demo/encode_bitmaps.py @@ -91,6 +91,11 @@ command_lines = [ "-a -u -n _rt_undo bmp_source/rt_undo.xpm images.py", "-a -u -n _rt_zebra bmp_source/rt_zebra.xpm images.py", + "-a -u -n _bp_btn1 bmp_source/bp_btn1.png images.py", + "-a -u -n _bp_btn2 bmp_source/bp_btn2.png images.py", + "-a -u -n _bp_btn3 bmp_source/bp_btn3.png images.py", + "-a -u -n _bp_btn4 bmp_source/bp_btn4.png images.py", + " -u -c bmp_source/001.png throbImages.py", "-a -u -c bmp_source/002.png throbImages.py", "-a -u -c bmp_source/003.png throbImages.py", diff --git a/wxPython/demo/images.py b/wxPython/demo/images.py index d9678bdbb1..5e852ddb55 100644 --- a/wxPython/demo/images.py +++ b/wxPython/demo/images.py @@ -12932,3 +12932,243 @@ def get_rt_zebraImage(): stream = cStringIO.StringIO(get_rt_zebraData()) return ImageFromStream(stream) +#---------------------------------------------------------------------- +def get_bp_btn1Data(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ +\x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ +\x04\xb9IDAT8\x8d\x8d\x95[l\x14U\x18\xc7\x7fgn;;\xbb\xdbv/\x14[J\xa1\\*\xb7\ +\x16\xe5"E@\xd2\x82\x12!\r\x12\x02\xc6H\x82D\x8d\x89\x89\x89\xf8 \x89\x89\ +\xf0\x82\x0f\xea\x8b\x86\x07/\x81\x17\x13#JH$"P\xc1\xa8\x14\x11)5`\xb17*mi\ +\xa1\xf4\xc2\x96vw\xbb;\xbb\xb33>\x0ctA.z\x92\xefe\xce\x9c\xdf\xf9\xce\xf7\ +\xff\x9f\xf3\t\xfesl\xf7\xa2\xa7"\xd8\x9a\x01\x96\x83l%HjC\xb0\xc7|\xd8*\xf1\ +\xc0\x19\xcf\xf6j\x1c^F\xd6\x9f\xc2\x93W\x84\xe6U\x00H\'\xd2\x98\xb1\x1e\xb2\ +\xa9\x13\xc8\xec%\xf9\xd1\xb9\xff\x076\xde)"\x9b\xfa\x18\xa3pSx\xce\x12\x16U\ +\x95S1;\xc4\x84\xa0\x86\x95\x85\xab\x03&\xe7/\x0e\xd1\xd4\xd0B\xac\xe3w\x9b\ +\xe4\xf0\xe7\xf8\xad\x1dD\xf7\x8c>\x18\xec\xdbQA\xd6>d\x94//{~\xeb*^Z\xe7\ +\xa3l\x02X\x16\xa4\xd2\x90\xb5\xdd\xdf\xcc,\\\xec\x81/\x0e\x0fs\xf2\xdb:\xac\ +\x9es\x8d\x08\xf99\x92\x1f\xf4\xde\x0b\xd6\xdf\x9a\x8c\x90\xeb#\x8bk\xa7\xec\ +~w\x05\x1b\x97\xc0\xf5a\xe8\xec\x87\x84\xe9B%\x01\xb2\x04\x92\x04>\x0f \xc1\ +\x81S\xb0\x7f\xdfQ\x92\xad?6b\xa4kng.\x8f\x83\xe5\xaa/\xfd\xb3k\x9ex\x7f\xf7\ +j\xd6/\x82\xd6^\x18\x8aA&\x0b\xaa\x02s&\xbb\x1bD\xe3\x90\xb6 \x96\x82\xb1\ +\x14\x94O\x02+8\x93\x8e\x8eh\xb1=\xd8\x17${\xe6\xfb\x1cX{s=y\xa5;\xb7m\xdf\ +\xcc\xd6U\n\x17\xba`d\x0c\xcc\x0ch\n\xd4TBI\x18\xf2\r\xf8\xe3\xb2\x0bN[\xee|\ +\xd2\x84\xe20\\1\'1\xd8\xd1\xb4\x001\xff\x08\xd6\x99k\x12\x00\x92\xf2Z\xc9\ +\x82\'\xd9\\\xa3\xd3\xda\x0b\x83\xa3\x10K\x82*Cu\x05\xf8u\xf7P\xcd\xdd\x16#\ +\t\x88\xa7r1\x9a\x84\xac\x05\x15s\x83\x18eU\x12B\xbc\n\xa0\x90\xb7+\x84\xaa-\ +\xadZV\x8e\xae@{\x8f\x9b\xcd\xa4\x10<\xf3\xf8\xadZ\x02G\xcf\x9a\xd4\xfd\xa9\ +\xa0( DN !\xb9\xb5\x8f\x04 8}6\xa9\xaeS\xab\xed\xfc]\x86\x84\x9c-\x92\x0b\ +\x1e)\x985=\x9f\xe6+\xd0\xd2\x0b\xb2\x80\xb5\x0bs\xd0\x86\xb64\xbf]R\x08\xe5\ +\xc9\xe4\xfb\xdc\xef\x86\xc7\x15q$\x01\xa3cn\xd6y\xe1\x08J T\x82\x99\x9d\xa2\ +(\xaa\xc8\xf3\x04\x82\x08Y\xe2|\xa7\x9b\xcd\x96\x95\xe0\xd5r.\xac\x9c\xa6\ +\xf1\xd8\x8c\x9c\x85l\x07\x1c\xc7u\xca\'u\xd0\xd8\xe1\n,\xab\x1a\xb2\x91\xaf\ +)\xe9\x1b\x11\x05\xc5\x8b\xeaQH\xa4\xe1\xea0\x94\x84\x9c[5\xcd9\xd1\xa3\xdes\ +\x8d\xc6G\xd8\xef0\x14\x17\x8ce \xed\x80\xeaQqdM(B\xf7\xc4!\xcdX\xc6\xe1FR\ +\xd0\xd9\x01\xef\x1d\xcc\xb0s\xb3:\x0e\xafo\xcep\xa6\xdd&\xe0u3\xb5\x1d\xb0m\ +\xd79\xc7\x9b\x15F\x922\x08\xd0=\x16\x02+#k\xc6\xb0\xe2\x91\x94\xeb\x96\x19\ +\x8b\xdf\x8c\x8d\xf9#!\x1f\xe9a\xc1\xa1\x8b*\xba\xd7\xe2\xedZ\x05\x10TNU\xf9\ +\xba\xc1\xe1d\x03x\x14\x17|[>\x8f\n>?h*\x8c\x0e\xc6\xb0m\xf3zBR\xba\xe5t\xf4\ +\xd8\x98Z\xb8n\x8d\x11\x998u\xda\x8c \x89\x0c\x18\x86\xa0\xa5_b4aQ5]BW\x05\ +\xd5s\x05\xdd\xc3\x82aS\xe0\xf7\t\x0c\xaf\xc0\xf0\x82\xc7\xe3F\xc0\x0f\xfd\ +\x1d\x9d\x8c\\\xeb:\x9cn}\xe3+\t@\x92\xe5\xbdW\xda:\xc8:6\xc5\x110|\x10\n\n\ +\xea\xfeV\xd8{\xca\x02\x1c\xbc*\xbc\xb8\x14\xbc>\xf0\xdd\x11\x86\x0f&\x86\ +\x01\xcb$\xda}\tY\xd3\xf6\x8d\xdf\xbc\xf4\x8a-\x7fI}\xb1Uh\xde\xd2Ys\xc3\xa8\ +282\x18\xba\xa0\xfd\x86D-,-Z6\x7f\xe1d\x1e\x9dY@8_Cu\xfb\x07f\xc6a(j\xd2\xd2v\x93\x0b\xe7\xba\ +\x88\xf6\r\x1dV\x85\xf5\xfa\xb5\x1f6\xf4\xdc\xc9\xb9\x7fk\xda\xf4\x8d\\\x98\ +\xf0\xbf \x84\xf4\x8a\x11\xf0.,\x08\x05\xfc\x86O\xc7q\x1c\x12\xf1$7\xa3\xb1\ +\x91d\x08\x06\x04\x01\xbf\xc0\xe7\x13\x94\x95\x08\xde\ +\xd9"h\xae\xcd\x93\x9e\xed\xce\xb1\xff;\x81\xec\x90\xf1z\xa0\xb0\x10\x8a\x8a\ +`j|\x10\xcb\xa6\x95\xeb\xbb2\x12\x80\xac+\x87\x86\xbb;\xedx2\xcd\xecRp\xb9\ +\xc1]\x90?\x9a\x03\x9aka\xc5Cy_/\xf5\xe5x\xb7U\xa08e<\x1ep\x15@I\x00\xecl\ +\x9aho\xa7-\xcb\xca\xa1\xe9\xc9\xcb\x0c\x1d\xbb\xa5\x95\xb6TfL\xa5q~}\x08\ +\x87\x0e\x96\x04\x9a\x06\xba\x0e&\x16\x95^\x8b\x1ba\x8b\x8f\xdb\x049Y\xc6\ +\xa9\x83\xaaA\xd0\x03\x0e\x07\\>}\x8d\xe8\xc0\xe0g\xb1\x0b\xdb?\xbagW(U\x1bO\ +\xa7\xc2\x13-\x96\xe2\x0c\xd6\xce\xf7Q\xe4\x06[\x06E\x03\x03\xc1\x99~\x9b\ +\xf3\xc3\x12\x92&\xa3\xeb\xe0r@\xa8\x08\x9cN8\xf7K7\xdd\x17\xae\xb6\x1b\xaa\ +\xbd\xc5\xe8=2\x99\x0f\xe7]\x08\xac>Z#\xcb|[\xbd\xac\xae\xaayu%%\x01\x95\xb4\ +q{\'X\xb7\x05H\xe0\xd2\xc0\xa1\xc1h4\xcb\xa9\x937\xe9<{\xed\xbai\xb2>\xd2\ +\xfax\xc7\x9d\xd4\xff\r\xc15_\x95ai\x1f\xfaC\xfe\'\xeb\x97\xce\xa1\xae\xc6G\ +\xd0\xafO\xe7\xda\xc8\xda\x84\xa3\x19\xaeu\x8cs\xf9\\\x0f\xd1\xe1\xe8\x11$\ +\xe3\xa5\xf0\x89\xa7\x86\xee\xc9\xf8L\xe1/^s|\r\xb2\xb4\xd3\xe5VWz|\x05Aw\ +\x81\x13\x80T2M|<\x19\x9eLe~\xc6\xe4\xc0\xd8\x89u\'\xfeuxf"\xfe\x0b%\x8f}_j\ +\xe7\xcc*\x0b\xbb\x18@B\x8c\tE\xbe>z\xec\xd1\x91\xff\xaa\xfb\x13)}\xd4EY\xc6\ +\xa7X\x00\x00\x00\x00IEND\xaeB`\x82' + +def get_bp_btn2Bitmap(): + return BitmapFromImage(get_bp_btn2Image()) + +def get_bp_btn2Image(): + stream = cStringIO.StringIO(get_bp_btn2Data()) + return ImageFromStream(stream) + +#---------------------------------------------------------------------- +def get_bp_btn3Data(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ +\x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ +\x04\\IDAT8\x8d\xb5\x95[lTU\x14\x86\xbf}93\xd3a\x98V\x18-\x97^(\x08\x8a\xe1R\ +n&-\xb1@\x94\x07\x05#%&j4&*\xc6\x07\x85\xc4HT0\x88\x08\x0f\x92\x90\xa8\xc8\ +\x83\x11\x13\xf1\x82\xc6\x10\xf0\x16\x08\xb1&\x16\x1f*$\x96T\xaa\xa8\xc5\x96\ +\xd2N[:\x9d\x9evf:\xd39\xd3\x99\xb3}\x18JhK}c%;\xd9\xc9\xca\xfa\xf6\x9f\x7f\ +\xad\xec%\x8c1\xdc\x8a\xd0\xa3\x17\xef\xc63u\xa1\xa9\xbe\xfb\x1c\xa3\rJ\xc9\ +\xa4#\x87\xd3X\xfb\xf0\x15\x1c\xc0*\x00\xcb\x07\xd2\x02!\xf2\x059\xf1\x0cZ\ +\x1d@\xe9\xa0\x14\xc2h\x85\xc9\xba\x9c\xcf\xbdO\xd5\x18\xb0%t\xf5\xebO\xcd\ +\xf1\xde\xb3h\x1a\x7f\xdb.\x17\xdb\x1c\xcf\xd1\x1f\xfa\xf6\xc7\x92\xb92,\xb6\ +\x01p\x8dI\x96]EA\xf9\xa6\xd1Z;9A\xe9\x1d\xf9T[7\xcbGyr\xf4\x92t\xe5\x9eC\ +\xc7#\xd9x$\xcd\xda\xf9^\x96\xdc\x15\xa4\xf6\xc1\xd9rz\xc8\xbf\x95\x11\xf7\ +\x04\x00\x06\x18\xe1\xc3\xb9\xc5jO\xf9\x0cK\x0b%\x98S\x0c\x1e\r]\x11\xdcl\ +\x8ewGyb\xd4cQ{\x0e\x1c\xfdX0Ppd\xd7\xd3\xb3|+\x96\x16\xf1S+4\xb5\xe58\xdb\ +\x94\xc0\x1e\xa2\x0e\xedI,+\xb7j\xfdS,\xd1|\x15\x8ao\x03c\xa0\xa3\x87\x91L\ +\x8e\xedH\x0e\x9a\x83\xe3<\xc6\x00~\xf5u<+\x86\xde\xf8\xcc>\xfa\xf2\xa3\xb2p\ +\xed\xca \xd1\xb8bfi\x10\xa7+\xb3\xde\xa0H\xb8\x16\x97{!T\x04\x99\x11\xe8\ +\x8c\x90r]^@\xf2\xc5M\x9b\x87\x94y\x13\xbd\xf2d\x06u\xef\xfe\xe3\xc9z;\xa5fn\ +X\xed\'\x1a\x97\x84m\x1f\xa94t\x0e\xc2\xec\x10\xa4\x1d\xe8\xe9c\xc0\xc0F$\r\ +\xd7\xfd\x1f\xef1\x89~p\x92 \x14xd\x0b\x05\xba\xeap\xddH\xcbG\xa73<\xbe\xdc\ +\xb0\xaa\x02r&\x0f\x8d\'\xa1\xbb\x8f.#\xa9A\xd1\x80$_\x1b\xef\xbb\x89\xe2\ +\xd1D\x7f;\x94,\x01\x9d\xbd\x82w\xfa\xb2S\x8d\xa2n\xd0\xa1\xfa\xb9\xfb!T\x08\ +\xdf\xff\x06\xa9\x14\x17P\xac\x83\x9c\x8d\xe3@\xbc\x1b\xdc\xec\xb5Q\xbc}\xbc\ +\x15\x1a\x8c\x0b\xc3\th\xfd5o\xcd\xcc\xc5)JV\xadih\x11\'\xe2\x0e\x0f[\x1eH%9\ +\x83r\x1f"i\xa7H\xf6\xc3p\x1c\xb4\x07\x94\x07\xb4u\x13\xc5\x98\xfc\x8bB\xe6\ +\x8f\xb2 z\t\x94\'KY\xe5\xa6?\xba\xd8\t\xf8\xb1x\x9bhG\x9aX8/F{\xaf\xd5\x8c\ +\xf5\xf8\x0605$3\xb5d2\x02\x8d\xc2+\xc3\x04\xbc\x87\xb1[m\x94v)Y\xb4\x0f\x80\ +\xdeVH\xf4\x80\xd4\x01\x10\xcf\xe2\xe6\xe6cd\x0e\x0c(N\x01?\x8e\x01\xfbq\xbe\ +[\xbfi^\x91\xb2<\x0c\xa5\x05\xed\x9dqZ\xfe\xb1\x9f\xc0\xef}\x80\xc1\xce(R\ +\x81\xd2\x90\xe8\x05\xa1\xa5p\xcdI\x11\x08\xd6\x18o\x90\x80_Q\xe0\x15\xd8vz\ +\x0b\x10\x18\x03N\x0f\x0e\xf4\x97\x17W\x14m}q\x15\xe1!A\xe3_\x19\xbe\xfa\xf2\ +\xc2\xd2\xc6sW\x9a\xd0r#C\x91&\x94\x06WUx\xa4{\xba\xec\xce\xe2\x05\xfd\x05\ +\xe5h\x9f\xa64\x04v\xcf }v6>a\xdc\\\xa8>x\xe8\xfc\xc5\x9d{\x1b\xf0\x99\x0c\ +\xb3\x8a=\xd4lXI\xe5\x9aE\xb3\x05\xa6\x1e\xc42\x8c,\rxiX\xb1\xbcd\x81\t\xcdE\ +y5\xb3\n]\xae\xb6Gio\x8bu\x18\xc4\xea\x89sl\xe9\x08ES\xaa\x8e\x1dk=\xbbc\xf7\ +YBV\x8a\xbbK\xa1b\xe9\x02**\x17\x16b\xc4/\n\xd3\\YY>\xc3\xf6\x95\xd1\xef\x08\ +\x8a\x03Y\xc2m}t\x87\x87\xfeD\xabj\x84\xb8<\xb1yR\x80W\xc7\x81\xaa\xfa\x9f{\ +\xbf\x1d\x18n|d\xcf\xab\x95\xac]<\x95\x8eh9\xd3r\x81\x80\x9314%C\xf8\xfc0#\ +\x90!\xdc\x1a%60R\x8fV\xeb\xae\x7f\xa7\x13\x14C\xfeG\x11@\xd0\xda\xf4{s\xe2\ +\xe3\xedo5\x9b"\x13\xe3\xc9\x1a\x10S\xa7\x93T!\xfc~(\xb4\xd2t^\x8a\x10\x8be\ +\xbe\xc1\xa3\xd6!\xc7\xcd\xda\x04\xf0\x8d\xe1\xd7\xcf\xff{\xc5\xd9\xfd\xca\ +\xbe\x96\xacL\x0c\xb0c3,,\x07O6I\xb8%\xe2&\x93\xd9\x0fPj3\x93,\xa0\xc9\xc1\ +\x00\x01\xbd7\x1aw\xb7\xec~\xaf\xd3\x89\xf7\x0e\xb0f^\x92pk_\xd6\xc9\xb8\xaf\ +\xa1\xe56\xfeg\xad\xe9I3\x90\xb7\xc6\'?\x8d\xb9\xd2~\xe7H\xf4\x13\x8f\xcf\ +\xb2\x10\xe2%\xa4\xf8|2\xa5\xa3!n\xd52\xfd\x0f\xde]\xc0!W\x86\x86C\x00\x00\ +\x00\x00IEND\xaeB`\x82' + +def get_bp_btn3Bitmap(): + return BitmapFromImage(get_bp_btn3Image()) + +def get_bp_btn3Image(): + stream = cStringIO.StringIO(get_bp_btn3Data()) + return ImageFromStream(stream) + +#---------------------------------------------------------------------- +def get_bp_btn4Data(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x16\x00\x00\x00\x16\x08\x06\ +\x00\x00\x00\xc4\xb4l;\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ +\x04\xb5IDAT8\x8du\x95[l\x15U\x18\x85\xbf\xbdg\xcf\xcc\xe99\x96Rl\x01+\xa5\ +\x08\x14\n\xa5\xb55@\xaa4\xd6\x98H\x1411\xc4\x18M\x94\xa8\x18%>\xa8\xf1\x12c\ +4\x9a\xa81\x06}0\x9ahD\xc3\x9bAn\x89\x06\xbc\xa1&4\x12\n(Bi\x83\x15\xb0b\xa9\ +\xf6B\xaf\xf4\x9c\xd3sff\xef\xed\xc3T\x0b\xb4\xfeO3\x93\xd9+k\xad\x7f\xad\ +\x19a\xad\x05@\xac\xdc\n\x00\xda\x82\x14 \x01cA\x08\xb0\xa0\x948\x94\x90\xb2\ +.=2\xfe.\xae|\x05)"\xb0 \x9d\xf8\xdd\x9c\x06Wb\x8fo\x06\xe2G\xff?\x16\x88\ +\x0cD\xda\xf3|\xb5\xf4\xed-k\x0b6\xdc\xb3\xe2E\xb4\xed&\x1f=\x8c\xb1\xff{tz`\ +\x01\x08$\xc6\xce!2\xe5D\xb6"\xc8FvFi\x11\x9b\x9e\xbf\x85\x97\xb7l\x98\xb3\ +\xb8v\xfe6B{\x92 lD\x88\xf8\xcc%\xa3\xa6\xa1\xa9\xc8\xe9\x97\xc0<\x94,\xf4\ +\xae.H\xb8\x8e\xd1\x16\xdfU\x05\xa7{,&\x0b\xc9\x05\xd7\xb0\xf1\x85\xf5\xfcr\ +\xf0\x8f\x9a\xc3_\x1fk\xee=\xd7w\x00+\x1e\xc5\x91\x7f\xfc\xc7\xed2\x8f-\xb3\ +\xc9\xe5\x9b+W\x94U\xad\xbe\xad\x86\x19sJQ\xae\x8b\x9d\x90&\xbd$}Y\x19{\xeeB\ +A\x12t&O_k\x07\'\x9a\xdb\xf2\x7f\xf5\xa5\xb7\x9a_6?y%cE>\xdf\xbcdMMU\xf5\xba\ +5\xf4\x87.]\x17AN\x98%\x04\x14\x02\x83\xe3\xf1n\'\xf8\xe0\xf8>%\xf5\xd7S\x93\ +H\xf8\x03\x9f5?\x0e\\\x01\x9c\x0f^\x9b\xb5`^U\xf5\xba\x9b\xc9E\x92\x84\x03\ +\xb9\xd1!\xc6\x86\xc7@\x80#\x05%\x0b\xcb\x98\x91T`\xc0K\x80\xf2`\xb0{\x98\ +\x1f\xf7\x1e\xe7B\xc7\xd9^\xe1\xd8g\xa7z,\xe4\xfd\rkkYV!1\x06Z\xf6\xb5\xd2\ +\xf2yK\x10i\xdd\x8fE*_\xcd]\xf9\xea\xbdr\xe1\xdcb|\x17\x86\x07\xb2\x1c\xfd\ +\xbe\x9d\xd6\x03m\x99\xfc\xc5\xf4\x87\xb8\xee\xf3VNf\xe1?\xe0\xc2\xc2DY\xc3\ +\xca\x99,\x9a\x07\x9dg\x87\xf8\xe9\xcb\xa3&\x8a\xccz\x12\xeewh\xeb\t\xa5\xba\ +\x97T\xb8\xa5\xc5%\x86o\xbf\xf8\x95\xfd\xbb\x8fG\x83\xdd\x83\xbb\xf0\xdd\xa7\ +\xf1\xbd\xfe\xc98]\x01<\x1ej\xfd\xc9\x96\xef\xf1%\xc7\xcd82\x8e\x81\x92\xf1\xdaM\xcc\x96 \xaa\'\xa0J\xfb\xaa\x99\x94\ +\xbf\x031QuX\x821\x15h\x13a\xa5\xc22\x04\x1c\xbb\x1c\xd8\x02\xae\x13_H\x11\ +\xb3\x08\xa2\x99\x04\xe6\xfdy\x95%\xf7\xddvW\x95\xda\xb5\xb3\xbd1=<\xfe\x06J\ +\x0e\x00`\xec\xde\xa2\xd2\xd4\xe2T\xca\xb7\x916bh0\x9b%N\xe5\xa5\x8cE|g\x00C\ +\x82\\\xf8\xa2_\x94|\xb6\xe9\x8e\xea\xd4\x86\x07\xea1\x06\xb6\x7fz\xd2\xe0`\ +\x90@\xa8\xafq\xb5\x99\xbf\xe9\x99u\xb2nU9\x7f\x9f\x1f\xe1\x9d\x17\xf6\x16L\ +\x8d\x1b\xff\xca\x0e\x1e\x91J\xbd\xbe\xb4\xa9\xba\xac\xf1\xce\x1b(\xbf\xae\ +\x98\xbf\xd20\xdas\x11\x9d\x0bR\xe4\xc3\xc3H\x11b(\xafY{}"YVN\xe7\x058}f\x9c\ +\xe1\xd1\xec\xe84\xc0\xf6&B\xfb\xe1\x8c\x8a\x8a\xda\xea[WR\xbe\xecZF\x0c\xf4\ +v\xc4b\x92\xa2\x80\xba\xbbo\x95Qd+\xad\xb5\x14\x14]\xc5\xdc\x85e\xb4\x9e\x83\ +D\x12Z\xbelG\xe7\xc3\x1f\xa6\x00{\x8e\xfd\xa6\xf1\xbe\x1b\x0bS\xb5u\x8c\x8eA\ +w\xdf\x84\xef"\x162\xab\xc0%UY\x896\x13\xe2L\\\xef\xe2\x94\xe5\xcc\x81\x13t\ +\xb7\x9f\x19\xc0w\x9f\x9a\x02\x1c\x86bg\xe7\x91\x8e\x8d\xf5I\xe5VV-\xc5&\\\ +\xb2\x190:\xb6}n\xd2\xe2\xba\x01\xdaX\x84\x00\x13Y\xc6.\x0c\xd2\xf6u;\'\x0f\ +\xfd>\x88r\xd6#D\xcf\xd4\x1c\xd7\x7f\x04\xb9p9\xc2|<\xaf\xb2\xac\xa1\xe1\x8e\ +Ur\xc5\xear\xa4\x92dr\xe0\x8f\xa7\xd9\xf3\xde>r\xf90\x90\x8e$3\x1e\xd9\x9e\ +\xfeL\xda\x06z?\t\xef\t\x1c1\x82\x05\xfb\xf3c\xd3,\xcf\x95\xa7\xf0\xbc5\xddg\ +{\xd7\xee~o\xdf\x07\xed7,Xt\xef\x83\xabhX=\x9b\xb1>8\xdd5\x96\tGr\xb7c\xec\ +\x00\x9e\x03)\xb7\x0b\xc7\xc92\xcd\\\xfe\x07\xb1\xc4\xc5\xf0\xd5~\x1c\x16w\ +\x1c\xeb|\xf2\xf5\xe7\xf6\x0cm\x7f\xff v,M"\xe5BRu\x90P\x1d8\xa2\x03\x98\x16\ +t\xaa\x15\x91\x06\xcf\x89\xb7eL\xdc.m\x92D\xf6\xcd\x99%\xa9\xcd\x99Pw\x87\ +\xa1^\x0e"@\x9b\xc9\x86\xc2\xc4Gz\xd2\x8a\x7f\x00E\xb8\x1e\xc0\xd9\xc98\xaa\ +\x00\x00\x00\x00IEND\xaeB`\x82' + +def get_bp_btn4Bitmap(): + return BitmapFromImage(get_bp_btn4Image()) + +def get_bp_btn4Image(): + stream = cStringIO.StringIO(get_bp_btn4Data()) + return ImageFromStream(stream) + diff --git a/wxPython/docs/CHANGES.txt b/wxPython/docs/CHANGES.txt index 2d3ba3b317..8a907cbecd 100644 --- a/wxPython/docs/CHANGES.txt +++ b/wxPython/docs/CHANGES.txt @@ -258,6 +258,8 @@ defaults to the current behavior of just replicating pixels, if wx.IMAGE_QUALITY_HIGH is passed then it uses bicubic and box averaging resampling methods for upsampling and downsampling respectively. +Added the wx.lib.buttonpanel module, which is a tweaked version of +Andrea Gavana's FancyButtonPanel module. diff --git a/wxPython/wx/lib/buttonpanel.py b/wxPython/wx/lib/buttonpanel.py new file mode 100644 index 0000000000..d99ebee363 --- /dev/null +++ b/wxPython/wx/lib/buttonpanel.py @@ -0,0 +1,607 @@ +# --------------------------------------------------------------------------- # +# FANCYBUTTONPANEL Widget wxPython IMPLEMENTATION +# +# Original C++ Code From Eran. You Can Find It At: +# +# http://wxforum.shadonet.com/viewtopic.php?t=6619 +# +# License: wxWidgets license +# +# +# Python Code By: +# +# Andrea Gavana, @ 02 Oct 2006 +# Latest Revision: 02 Oct 2006, 17.00 GMT +# +# +# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please +# Write To Me At: +# +# andrea.gavana@gmail.com +# gavana@kpo.kz +# +# Or, Obviously, To The wxPython Mailing List!!! +# +# +# End Of Comments +# --------------------------------------------------------------------------- # + +""" +With `ButtonPanel` class you have a panel with gradient coloring +on it and with the possibility to place some buttons on it. Using a +standard panel with normal wx.Buttons leads to an ugly result: the +buttons are placed correctly on the panel - but with grey area around +them. Gradient coloring is kept behind the images - this was achieved +due to the PNG format and the transparency of the bitmaps. + +The image are functioning like a buttons and can be caught in your +code using the usual self.Bind(wx.EVT_BUTTON, self.OnButton) method. + +The control is generic, and support theming (well, I tested it under +Windows with the three defauls themes: grey, blue, silver and the +classic look). + + +Usage +----- + +The following example shows a simple implementation that uses ButtonPanel +inside a very simple frame:: + + class MyFrame(wx.Frame): + + def __init__(self, parent, id=-1, title="ButtonPanel", pos=wx.DefaultPosition, + size=(800, 600), style=wx.DEFAULT_FRAME_STYLE): + + wx.Frame.__init__(self, parent, id, title, pos, size, style) + + mainPanel = wx.Panel(self, -1) + self.logtext = wx.TextCtrl(mainPanel, -1, "", style=wx.TE_MULTILINE) + + vSizer = wx.BoxSizer(wx.VERTICAL) + mainPanel.SetSizer(vSizer) + + alignment = BP_ALIGN_RIGHT + + titleBar = ButtonPanel(mainPanel, -1, "A Simple Test & Demo") + + btn1 = ButtonInfo(wx.NewId(), wx.Bitmap("png4.png", wx.BITMAP_TYPE_PNG)) + titleBar.AddButton(btn1) + self.Bind(wx.EVT_BUTTON, self.OnButton, btn1) + + btn2 = ButtonInfo(wx.NewId(), wx.Bitmap("png3.png", wx.BITMAP_TYPE_PNG)) + titleBar.AddButton(btn2) + self.Bind(wx.EVT_BUTTON, self.OnButton, btn2) + + btn3 = ButtonInfo(wx.NewId(), wx.Bitmap("png2.png", wx.BITMAP_TYPE_PNG)) + titleBar.AddButton(btn3) + self.Bind(wx.EVT_BUTTON, self.OnButton, btn3) + + btn4 = ButtonInfo(wx.NewId(), wx.Bitmap("png1.png", wx.BITMAP_TYPE_PNG)) + titleBar.AddButton(btn4) + self.Bind(wx.EVT_BUTTON, self.OnButton, btn4) + + titleBar.SetColor(BP_TEXT_COLOR, wx.WHITE) + titleBar.SetColor(BP_CAPTION_BORDER_COLOR, wx.WHITE) + vSizer.Add(titleBar, 0, wx.EXPAND) + vSizer.Add((20, 20)) + vSizer.Add(self.logtext, 1, wx.EXPAND|wx.ALL, 5) + + vSizer.Layout() + + # our normal wxApp-derived class, as usual + + app = wx.PySimpleApp() + + frame = MyFrame(None) + app.SetTopWindow(frame) + frame.Show() + + app.MainLoop() + + +License And Version: + +ButtonPanel Is Freeware And Distributed Under The wxPython License. + +Latest Revision: Andrea Gavana @ 02 Oct 2006, 17.00 GMT +Version 0.1. + +""" + + +import wx + +# Some constants +BP_CAPTION_COLOR = 0, +BP_CAPTION_GRADIENT_COLOR = 1 +BP_CAPTION_BORDER_COLOR = 2 +BP_TEXT_COLOR = 3 + +# Buttons states +BP_BTN_NONE = 100 +BP_BTN_PRESSED = 101 +BP_BTN_HOVER = 102 + +# Flags for HitTest() method +BP_HT_BUTTON = 200 +BP_HT_NONE = 201 + +# Alignment of buttons in the panel +BP_ALIGN_RIGHT = 1 +BP_ALIGN_LEFT = 2 + +# ButtonPanel default style +BP_DEFAULT_STYLE = 2 + + +def BrightenColor(color, factor): + """ Bright the input colour by a factor.""" + + val = color.Red()*factor + if val > 255: + red = 255 + else: + red = val + + val = color.Green()*factor + if val > 255: + green = 255 + else: + green = val + + val = color.Blue()*factor + if val > 255: + blue = 255 + else: + blue = val + + return wx.Color(red, green, blue) + + +# -- ButtonInfo class implementation ---------------------------------------- +# This class holds information about every button that is added to +# ButtonPanel. It is an auxiliary class that you should use +# every time you add a button. + +class ButtonInfo: + + def __init__(self, id=wx.ID_ANY, bmp=wx.NullBitmap, status=-1): + """ + Default class constructor. + + Parameters: + - id: the button id; + - bmp: the associated bitmap; + - status: button status (pressed, hovered, None). + """ + if id == wx.ID_ANY: + id = wx.NewId() + self._id = id + self._bmp = bmp + self._status = status + self._rect = wx.Rect() + + + def GetBitmap(self): + """ Returns the associated bitmap. """ + + return self._bmp + + + def GetRect(self): + """ Returns the button rect. """ + + return self._rect + + + def GetStatus(self): + """ Returns the button status. """ + + return self._status + + + def GetId(self): + """ Returns the button id. """ + + return self._id + + + def SetRect(self, rect): + """ Sets the button rect. """ + + self._rect = rect + + + def SetBitmap(self, bmp): + """ Sets the associated bitmap. """ + + self._bmp = bmp + + + def SetStatus(self, status): + """ Sets the button status. """ + + self._status = status + + + def SetId(self, id): + """ Sets the button id. """ + + self._id = id + + Bitmap = property(GetBitmap, SetBitmap) + Id = property(GetId, SetId) + Rect = property(GetRect, SetRect) + Status = property(GetStatus, SetStatus) + + + + +# -- ButtonPanel class implementation ---------------------------------- +# This is the main class. + +BASE = wx.PyPanel + +class ButtonPanel(BASE): + + def __init__(self, parent, id=wx.ID_ANY, text="", style=BP_DEFAULT_STYLE, + alignment=BP_ALIGN_RIGHT, name="buttonPanel"): + """ + Default class constructor. + + - parent: parent window + - id: window ID + - text: text to draw + - style: window style + - alignment: alignment of buttons (left or right) + - name: window class name + """ + + BASE.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize, + wx.NO_BORDER, name=name) + self._vButtons = [] + + self._text = text + self._nStyle = style + self._alignment = alignment + self._nPadding = 6 + self._nBmpSize = 16 + self._colorFrom = wx.SystemSettings.GetColour(wx.SYS_COLOUR_ACTIVECAPTION) + self._colorTo = wx.WHITE + self._colorBorder = wx.SystemSettings.GetColour(wx.SYS_COLOUR_3DFACE) + self._colorText = wx.SystemSettings.GetColour(wx.SYS_COLOUR_WINDOWTEXT) + self._firsttime = True + self._borderPenWidth = 3 + + self.Bind(wx.EVT_PAINT, self.OnPaint) + self.Bind(wx.EVT_SIZE, self.OnSize) + self.Bind(wx.EVT_ERASE_BACKGROUND, self.OnEraseBackground) + self.Bind(wx.EVT_MOTION, self.OnMouseMove) + self.Bind(wx.EVT_LEFT_DOWN, self.OnLeftDown) + self.Bind(wx.EVT_LEFT_UP, self.OnLeftUp) + self.Bind(wx.EVT_LEAVE_WINDOW, self.OnMouseLeave) + self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnterWindow) + + + def AddButton(self, btnInfo): + """ + Adds a button to ButtonPanel. Remember to pass a ButtonInfo instance to + this method. See the demo for details. + """ + + self._vButtons.append(btnInfo) + self.Refresh() + + + def RemoveAllButtons(self): + """ Remove all the buttons from ButtonPanel. """ + + self._vButtons = [] + self.Refresh() + + + def GetAlignment(self): + """ Returns the button alignment (left, right). """ + + return self._alignment + + + def SetAlignment(self, alignment): + """ Sets the button alignment (left, right). """ + + self._alignment = alignment + + + def DoGetBestSize(self): + w = h = 0 + if self._text: + dc = wx.ClientDC(self) + boldFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) + boldFont.SetWeight(wx.FONTWEIGHT_BOLD) + dc.SetFont(boldFont) + tw, th = dc.GetTextExtent(self._text) + h = max(h, th) + w += tw + self._nPadding + + if self._vButtons: + bh = self._vButtons[0].GetBitmap().GetHeight() + bw = self._vButtons[0].GetBitmap().GetWidth() + + bh += 2*self._nPadding + 2*self._borderPenWidth + h = max(h, bh) + + bw = (len(self._vButtons)+1) * (bw + 2*self._nPadding) + w += bw + + return (w, h) + + + + def OnPaint(self, event): + """ Handles the wx.EVT_PAINT event for ButtonPanel. """ + + dc = wx.BufferedPaintDC(self) + rect = self.GetClientRect() + + ##print rect, self.GetRect(), self.GetBestSize(), self.GetMinSize() + + # Draw gradient color in the background of the panel + self.FillGradientColor(dc, rect) + + backBrush = wx.TRANSPARENT_BRUSH + borderPen = wx.Pen(self._colorBorder) + size = self.GetSize() + borderPen.SetWidth(self._borderPenWidth) + + # Draw a rectangle around the panel + dc.SetBrush(backBrush) + dc.SetPen(borderPen) + dc.DrawRectangleRect(rect) + + # Draw the text + textWidth, textHeight = 0, 0 + + if self._text != "": + + dc.SetTextForeground(self._colorText) + borderPen.SetWidth(2) + boldFont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT) + boldFont.SetWeight(wx.FONTWEIGHT_BOLD) + dc.SetFont(boldFont) + + textWidth, textHeight = dc.GetTextExtent(self._text) + + if self._alignment == BP_ALIGN_RIGHT: + textX = self._nPadding + else: + textX = rect.width - textWidth - self._nPadding + + textY = (rect.GetHeight() - textHeight)/2 + dc.DrawText(self._text, textX, textY) + + if self._vButtons: + + height = self._vButtons[0].GetBitmap().GetHeight() + self._nBmpSize = self._vButtons[0].GetBitmap().GetWidth() + height += 2*self._nPadding + 2*self._borderPenWidth + + if self._firsttime: # this probably isn't needed anymore now that DoGetBestSize is implemented... + self.GetContainingSizer().Layout() + self._firsttime = False + + # Draw all buttons + # [ Padding | Text | .. Buttons .. | Padding ] + + totalWidth = rect.width - self._nPadding*2 - textWidth + + # The button is drawn inside a circle with padding of self._nPadding around it + # so the width of each image = imageWidth + 2 * self._nPadding + nImageWidth = self._nBmpSize + 2*self._nPadding + + if self._alignment == BP_ALIGN_RIGHT: + + leftEndX = self._nPadding + textWidth + posx = rect.width - nImageWidth - self._nPadding + + for ii in xrange(len(self._vButtons)): + + # Make sure we can keep drawing + if posx < leftEndX: + break + + # Draw a rectangle around the buttons + if self._vButtons[ii].GetStatus() == BP_BTN_HOVER: + + dc.SetBrush(wx.Brush(wx.Color(225, 225, 255))) + dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_ACTIVECAPTION))) + dc.DrawRectangle(posx, self._borderPenWidth, nImageWidth, nImageWidth) + dc.DrawBitmap(self._vButtons[ii].GetBitmap(), posx + self._nPadding, self._nPadding + self._borderPenWidth, True) + + elif self._vButtons[ii].GetStatus() == BP_BTN_PRESSED: + + dc.SetBrush(wx.Brush(wx.Color(225, 225, 255))) + dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_ACTIVECAPTION))) + dc.DrawRectangle(posx, self._borderPenWidth, nImageWidth, nImageWidth) + dc.DrawBitmap(self._vButtons[ii].GetBitmap(), posx + self._nPadding, self._nPadding + self._borderPenWidth + 1, True) + + else: + + dc.DrawBitmap(self._vButtons[ii].GetBitmap(), posx + self._nPadding, self._nPadding + self._borderPenWidth, True) + + self._vButtons[ii].SetRect(wx.Rect(posx, self._borderPenWidth, nImageWidth, nImageWidth)) + posx -= nImageWidth + + else: + + rightStartX = textX - self._nPadding - nImageWidth + posx = self._nPadding + + for ii in xrange(len(self._vButtons)): + + # Make sure we can keep drawing + if posx > rightStartX: + break + + # Draw a rectangle around the buttons + if self._vButtons[ii].GetStatus() == BP_BTN_HOVER: + + dc.SetBrush(wx.Brush(wx.Color(225, 225, 255))) + dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_ACTIVECAPTION))) + dc.DrawRectangle(posx, self._borderPenWidth, nImageWidth, nImageWidth) + dc.DrawBitmap(self._vButtons[ii].GetBitmap(), posx + self._nPadding, self._nPadding + self._borderPenWidth, True) + + elif self._vButtons[ii].GetStatus() == BP_BTN_PRESSED: + + dc.SetBrush(wx.Brush(wx.Color(225, 225, 255))) + dc.SetPen(wx.Pen(wx.SystemSettings.GetColour(wx.SYS_COLOUR_ACTIVECAPTION))) + dc.DrawRectangle(posx, self._borderPenWidth, nImageWidth, nImageWidth) + dc.DrawBitmap(self._vButtons[ii].GetBitmap(), posx + self._nPadding, self._nPadding + self._borderPenWidth + 1, True) + + else: + + dc.DrawBitmap(self._vButtons[ii].GetBitmap(), posx + self._nPadding, self._nPadding + self._borderPenWidth, True) + + self._vButtons[ii].SetRect(wx.Rect(posx, self._borderPenWidth, nImageWidth, nImageWidth)) + posx += nImageWidth + + # Update all other buttons that they are not drawn (by setting the rect to 0) + for cur in xrange(ii+1, len(self._vButtons)): + self._vButtons[cur].SetRect(wx.Rect(0, 0, 0, 0)) + + + def OnEraseBackground(self, event): + """ Handles the wx.EVT_ERASE_BACKGROUND event for ButtonPanel (does nothing). """ + + pass + + + def OnSize(self, event): + """ Handles the wx.EVT_SIZE event for ButtonPanel. """ + + self.Refresh() + event.Skip() + + + def SetColor(self, switch, color): + """ + Sets the color depending on switch: + - BP_CAPTION_COLOR: caption color; + - BP_CAPTION_GRADIENT_COLOR: gradient color; + - BP_CAPTION_BORDER_COLOR; border color; + - BP_TEXT_COLOR: text color. + """ + + if switch == BP_CAPTION_COLOR: + self._colorFrom = color + elif switch == BP_CAPTION_GRADIENT_COLOR: + self._colorTo = color + elif switch == BP_CAPTION_BORDER_COLOR: + self._colorBorder = color + elif switch == BP_TEXT_COLOR: + self._colorText = color + + + def FillGradientColor(self, dc, rect): + """ Gradient fill from colour 1 to colour 2 with top to bottom. """ + + if rect.height < 1 or rect.width < 1: + return + + size = rect.height + + # calculate gradient coefficients + style = self.GetParent().GetWindowStyleFlag() + col2 = self._colorFrom + col1 = self._colorTo + + rf, gf, bf = 0, 0, 0 + rstep = float((col2.Red() - col1.Red()))/float(size) + gstep = float((col2.Green() - col1.Green()))/float(size) + bstep = float((col2.Blue() - col1.Blue()))/float(size) + + for y in xrange(rect.y, rect.y + size): + + currCol = wx.Colour(col1.Red() + rf, col1.Green() + gf, col1.Blue() + bf) + dc.SetBrush(wx.Brush(currCol, wx.SOLID)) + dc.SetPen(wx.Pen(currCol)) + dc.DrawLine(rect.x, y, rect.x + rect.width, y) + rf += rstep + gf += gstep + bf += bstep + + + def OnMouseMove(self, event): + """ Handles the wx.EVT_MOTION event for ButtonPanel. """ + + # Check to see if we are hovering a button + for ii in xrange(len(self._vButtons)): + if self._vButtons[ii].GetRect().Inside(event.GetPosition()): + self._vButtons[ii].SetStatus(BP_BTN_HOVER) + else: + self._vButtons[ii].SetStatus(BP_BTN_NONE) + + self.Refresh() + event.Skip() + + + def OnLeftDown(self, event): + """ Handles the wx.EVT_LEFT_DOWN event for ButtonPanel. """ + + tabId, hit = self.HitTest(event.GetPosition()) + + if hit == BP_HT_BUTTON: + + self._vButtons[tabId].SetStatus(BP_BTN_PRESSED) + self.Refresh() + + + def OnLeftUp(self, event): + """ Handles the wx.EVT_LEFT_UP event for ButtonPanel. """ + + tabId, hit = self.HitTest(event.GetPosition()) + + if hit == BP_HT_BUTTON: + if self._vButtons[tabId].GetStatus() == BP_BTN_PRESSED: + # Fire a button click event + btnEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, self._vButtons[tabId].GetId()) + self.GetEventHandler().ProcessEvent(btnEvent) + + # Update the button status to be hovered + self._vButtons[tabId].SetStatus(BP_BTN_HOVER) + self.Refresh() + + + def OnMouseLeave(self, event): + """ Handles the wx.EVT_LEAVE_WINDOW event for ButtonPanel. """ + + # Reset all buttons statuses + for ii in xrange(len(self._vButtons)): + self._vButtons[ii].SetStatus(BP_BTN_NONE) + + self.Refresh() + event.Skip() + + + def OnMouseEnterWindow(self, event): + """ Handles the wx.EVT_ENTER_WINDOW event for ButtonPanel. """ + + event.Skip() + + + def HitTest(self, pt): + """ + HitTest method for ButtonPanel. Returns the button (if any) and + a flag (if any). + """ + + btnIdx = -1 + + for ii in xrange(len(self._vButtons)): + if self._vButtons[ii].GetRect().Inside(pt): + return ii, BP_HT_BUTTON + + return -1, BP_HT_NONE + + +