]> git.saurik.com Git - wxWidgets.git/commitdiff
Added the wx.lib.buttonpanel module, which is a tweaked version of
authorRobin Dunn <robin@alldunn.com>
Tue, 3 Oct 2006 21:23:17 +0000 (21:23 +0000)
committerRobin Dunn <robin@alldunn.com>
Tue, 3 Oct 2006 21:23:17 +0000 (21:23 +0000)
Andrea Gavana's FancyButtonPanel module.

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@41605 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775

wxPython/demo/ButtonPanel.py [new file with mode: 0644]
wxPython/demo/Main.py
wxPython/demo/bmp_source/bp_btn1.png [new file with mode: 0644]
wxPython/demo/bmp_source/bp_btn2.png [new file with mode: 0644]
wxPython/demo/bmp_source/bp_btn3.png [new file with mode: 0644]
wxPython/demo/bmp_source/bp_btn4.png [new file with mode: 0644]
wxPython/demo/encode_bitmaps.py
wxPython/demo/images.py
wxPython/docs/CHANGES.txt
wxPython/wx/lib/buttonpanel.py [new file with mode: 0644]

diff --git a/wxPython/demo/ButtonPanel.py b/wxPython/demo/ButtonPanel.py
new file mode 100644 (file)
index 0000000..97875b6
--- /dev/null
@@ -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 = """<html><body>
+<h2><center>Say something nice here</center></h2>
+
+</body></html>
+"""
+
+
+
+if __name__ == '__main__':
+    import sys,os
+    import run
+    run.main(['', os.path.basename(sys.argv[0])] + sys.argv[1:])
+
+
+  
+    
index c7bbb1b03e63c49e60880a7cff46eecdb171f8ac..f45ed7224289bfa4a25354cf8c6c2fa8b111f940 100644 (file)
@@ -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 (file)
index 0000000..4148ab8
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 (file)
index 0000000..b6e026a
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 (file)
index 0000000..ba62593
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 (file)
index 0000000..0109cec
Binary files /dev/null and b/wxPython/demo/bmp_source/bp_btn4.png differ
index 5dfd878cf64b21ef9d5f4000f85a64a271815783..6574d392294ed66e6cf172eddc862df8c331a776 100644 (file)
@@ -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",
index d9678bdbb10a81117e7292d228d47c35f7bc2e52..5e852ddb5513cea8ed5a119b8f8c412c44bd9082 100644 (file)
@@ -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<i\x111\xe0x\xbb\xc3@RB\xd7AUA\xd5 \x92\x07\xba\x0eM\
+\xbf63\xd4\xd3s`\xa4a\xdb\x87wI\x1f\\\xb9\x7f\x9e"+\xf5\x8b\xd7,-X\xb4\xa4\
+\x98t\x06FR`\xd9`e\x1ddll!\xa1H\x02\x07P%(\xf0\xba\x0f\xd1\xe9\x9f;i\xfa\xa5\
+\xf1\xb2\xb0\xa5\xe5C\xf5\x1b\xfb\xee\xf6\x14\x10\xae\xf9\xb6ZQ\xa5\x83\x95\
+\xcb+\x82\xcbV\x94R\x10\x90\x183!\x99\xc9=\x99\x8a\x04\x86\x06\xba\x06\x83Q\
+\x8b\x93?u\xd2z\xb6\xb9[\xe0\xd4\x0e\x9c\xd8\xd0\x94\x93\xf5_c\xe2\xd3\xdf\
+\xcds$>-,-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<u\x1a\xf8l\xe0\xc8\xb3\x87\xee\x87xp\xcf\xbb}\x82\xda\xba2\xdb\x16\xe5\
+6v\x04[vd\xd9\xe9W-\xab\xed\xea\xb1\xb5\xbd\x0f[\xf7\x0f@\x01\xd7\x0c\xb0\
+\xdfs2\x00\x00\x00\x00IEND\xaeB`\x82' 
+
+def get_bp_btn1Bitmap():
+    return BitmapFromImage(get_bp_btn1Image())
+
+def get_bp_btn1Image():
+    stream = cStringIO.StringIO(get_bp_btn1Data())
+    return ImageFromStream(stream)
+
+#----------------------------------------------------------------------
+def get_bp_btn2Data():
+    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\xb8IDAT8\x8d\x8d\x94Yl\x94U\x18\x86\x9f\xf3\xaf\xb3\xb43\x9d\xa5\xed\
+\xb4\x82-X\xdaR\xa0\x0b["!\r\x18\x13 \xc1\xe2B\x04\x12\x83 7\xb8\x05\x134\
+\x1a/$\x90\x10\xe3\x85\x17.Qbb\xc0h\x0c7"\x11\x13$QjP\xa4\x91U@\xec\x02-]\
+\xe8:3\xedl\x9d\xce?\xf3\xff\xbf\x17\x83\x05\xd4\x8aor\x92\x93\x9c|\xef\xf7\
+\xe6=\xef\xf7\t\xfe\x17\xf6(0\xa4\xe5\xefe\x06\xec\xcd\xdd\xafB\xcc\xf8\xe2\
+\xdf\xe3!1\xfe\x04\xc8\xeb\x91\xf5\x05\xc8\xaa\x17\x003\x1b\xc3\xcc\xfc\x0e\
+\xd61\n\xad\xa3D?\x88\xff\x7fb}\xd76\x84\xe3-QR=\xe7\xc1\xba\x85\xcc\xab-\
+\xa7\xb4\xd8\x85e\xc3\xf0\xc8$]\x1d\x83\xdcj\xbf\x8a=\xd6\xd1\x83\x95\xd9G\
+\xe6\xbdC\xf7!\xde\xa3\xe0\x88\x1d\xa0\xb0rG\xe3\xbau\xec\xd8TM\xf3"\xf0\xba\
+\xc04!g\x82a\xc2h\x1cN]\x81\xc3_w\xd2\xd1z\x1c\xe27?e\xca\xbb\xf3n\x8b\xe4{\
+\x956\x1d\x94B\r\xdb\xb7\xed\xde\xca\xfb\xbbC,\x9c\r\x83\x11\xe8\x1d\x85\xfe\
+0\x8cL\xc0D\x12,\x13\xaa\xcba\xc5\xb2\x00\x13\xeezzz"\x8b\xedto%f\xdb\xd1\
+\x7f\x12\xeb\xaf\xbc\x8co\xde\x1b;^{\x86}\xdb\\\xc4\x92ps\x14R\x19HNAY\x11\
+\xd86\x84\xe30\x95\x85\xf1\x14\xd8\x16\xd4W\xa9D\xb4\x1a\xfa\xba\xfa\x1a0\
+\xaa\xa3\x98m\xbf\xde!v\xbeX\x8e(8\xfc\xf0\xa6-\xae\xb7_\x082\x14\x81\xfe\
+\x08X\x16\xc4\'!\xe4\x83G\x16\xc1\xdcR\x18\x89\xc1\xad0\xe4,H\x1b\x90\xcb\
+\xc1\x03\xa5*]\xb1\x12b7./E]\xf2\x05\xd9\xb6\xa4\x04\x80\xadn\xd5+\x9a\x82\
+\xcf=]A"\x05\xdd#0e@8\x01\xbda\x18\x0c\x9b\xd8\x96\x8d"\xc3\xda&\xa8(\x81h\
+\x02\x92i\x98H\x81*A\xc3\xe2\n\xb4Y\r\xc5Xb+@\x9eXq\xb5\xd4.k\xa0v\x16\xb4\
+\x0f\xe4\x95\xc4\xd3y+\x12i\xf8\xadW\xe2\xf3\x1f\x0cL\xd3F\x96`\xc3r\x98W\
+\x9eo\x1cOC,\x05\xe5~(\xaajD8\x9c\x1b\x00\x14|\xaf{\xd1\xbc5\x0b\xeaB\x8c\
+\x8e\xc3\x1f\x03y\xcbU%\xafZ\x92@Q\x04\x17\xfb5\x94SY6\xafR\x91%\xc1\xe6\x95\
+`\xe4\xe0L\x07hJ\xbe\xa6\xb04\xc4\xb8\xcb[\x93U_\r)\xb8\xe5\x02E\xf5\x14x<\
+\x0e.v\xc3`\x14\x9e_\x0b\xf3g\xdd\xfe]\xe9N2MK\x03;\x1fRI\xc0\xb3\xab`,\x06\
+\x97z@Q@\xd5\x1d\xc8nO\x01\xf1D@q\xda\x1ea\xe9\xba0\x91\xe8\x8b\x80$\xdb,\
+\x99\x0b\x9a:\xf3PN\xb7\x12\x10(\xb4\x89\xa6\x04\x93Y0\x85\x84\xa2\xe9\xc2T5\
+I\x91\xdd\xca\x14\xb2\x95\x994\xb2j\xd4P\x18\x1e\x17\xbc\xf9\xa5Ac\xa5\r\xe4\
+\x95IB\x90\xc9\xd9\xb8uhY\xae\xa1)\xf9\xa6\xadWr\x1c\xfcI\x90\x98\x92\xb1\
+\x01]\xcb"\xc9VF\x92\xd5\x84\x92,\xec\x8c9\xd3M\x03\xd1\x89d\xad\xbf\xdcI$\r\
+?\xde\xd08\xd9e#D^\x95m\x83K\x87\xfd\x1b\x99&=\xdd\x9ec\xef7\x02C\xc8\xb8\
+\xdd\xa0\xaa\x10\x1bNb\xdb\xd9\x81\x8c\xea\x1a\x928\xffIV\x92h\x1d\xe8\x1b\
+\xc4\xeb\x01\xaf\x07\xfc>\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<e\xd3\x99\xbc\xc8\x86\xa6\
+\x1f_}\x87\x05\x8c\xc5\xf5\xa4\xf3\xe7\xa9\xf3l\xfb\xea7\xdbv\xb8\xeb(\xbez\
+\x94\xa4\xdf\x8e1\x93\xa5\xba$r\x97\xa4\xe2\xa3&\xd2\xc1lB\xa3\xf1\x94K\xca=\
+\x87\xe0\x089\rJ\x82\x12\xef:\x81n\xd2\xb9\xe8-R\xee\x0e\x98hg`@\x9b\x18\xd8\
+w\xb0??>%\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)
+
index 2d3ba3b317f8ef31057d23039f47617133211072..8a907cbecda9ff8b868c334ac2985459cf445cc0 100644 (file)
@@ -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 (file)
index 0000000..d99ebee
--- /dev/null
@@ -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
+
+