-
import wx
import wx.lib.buttonpanel as bp
import images
+import random
+
+#----------------------------------------------------------------------
+
+ID_BackgroundColour = wx.NewId()
+ID_GradientFrom = wx.NewId()
+ID_GradientTo = wx.NewId()
+ID_BorderColour = wx.NewId()
+ID_CaptionColour = wx.NewId()
+ID_ButtonTextColour = wx.NewId()
+ID_SelectionBrush = wx.NewId()
+ID_SelectionPen = wx.NewId()
+ID_SeparatorColour = wx.NewId()
+
+
+#----------------------------------------------------------------------
+# Some icons for the demo
+#----------------------------------------------------------------------
+def GetMondrianData():
+ return \
+'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00 \x00\x00\x00 \x08\x06\x00\
+\x00\x00szz\xf4\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\x00qID\
+ATX\x85\xed\xd6;\n\x800\x10E\xd1{\xc5\x8d\xb9r\x97\x16\x0b\xad$\x8a\x82:\x16\
+o\xda\x84pB2\x1f\x81Fa\x8c\x9c\x08\x04Z{\xcf\xa72\xbcv\xfa\xc5\x08 \x80r\x80\
+\xfc\xa2\x0e\x1c\xe4\xba\xfaX\x1d\xd0\xde]S\x07\x02\xd8>\xe1wa-`\x9fQ\xe9\
+\x86\x01\x04\x10\x00\\(Dk\x1b-\x04\xdc\x1d\x07\x14\x98;\x0bS\x7f\x7f\xf9\x13\
+\x04\x10@\xf9X\xbe\x00\xc9 \x14K\xc1<={\x00\x00\x00\x00IEND\xaeB`\x82'
+
+
+def GetMondrianBitmap():
+ return wx.BitmapFromImage(GetMondrianImage())
+
+
+def GetMondrianImage():
+ import cStringIO
+ stream = cStringIO.StringIO(GetMondrianData())
+ return wx.ImageFromStream(stream)
+
+
+def GetMondrianIcon():
+ icon = wx.EmptyIcon()
+ icon.CopyFromBitmap(GetMondrianBitmap())
+ return icon
+
+#----------------------------------------------------------------------
+
+class SettingsPanel(wx.MiniFrame):
+
+ def __init__(self, parent, id=wx.ID_ANY, title="Settings Panel", pos=wx.DefaultPosition,
+ size=wx.DefaultSize,
+ style=wx.SYSTEM_MENU | wx.CAPTION | wx.CLOSE_BOX | wx.FRAME_NO_TASKBAR
+ | wx.FRAME_FLOAT_ON_PARENT | wx.CLIP_CHILDREN):
+
+ wx.MiniFrame.__init__(self, parent, id, title, pos, size, style)
+
+ self.targetTitleBar = parent.titleBar
+ self.parent = parent
+ self.panel = wx.Panel(self, -1)
+
+ self.coloursizer_staticbox = wx.StaticBox(self.panel, -1, "Colour Options")
+ self.bottomsizer_staticbox = wx.StaticBox(self.panel, -1, "Size Options")
+ self.stylesizer_staticbox = wx.StaticBox(self.panel, -1, "ButtonPanel Styles")
+ self.defaultstyle = wx.RadioButton(self.panel, -1, "Default Style", style=wx.RB_GROUP)
+ self.gradientstyle = wx.RadioButton(self.panel, -1, "Gradient Style")
+ self.verticalgradient = wx.RadioButton(self.panel, -1, "Vertical Gradient", style=wx.RB_GROUP)
+ self.horizontalgradient = wx.RadioButton(self.panel, -1, "Horizontal Gradient")
+
+ b = self.CreateColorBitmap(wx.BLACK)
+
+ self.bakbrush = wx.BitmapButton(self.panel, ID_BackgroundColour, b, size=wx.Size(50,25))
+ self.gradientfrom = wx.BitmapButton(self.panel, ID_GradientFrom, b, size=wx.Size(50,25))
+ self.gradientto = wx.BitmapButton(self.panel, ID_GradientTo, b, size=wx.Size(50,25))
+ self.bordercolour = wx.BitmapButton(self.panel, ID_BorderColour, b, size=wx.Size(50,25))
+ self.captioncolour = wx.BitmapButton(self.panel, ID_CaptionColour, b, size=wx.Size(50,25))
+ self.textbuttoncolour = wx.BitmapButton(self.panel, ID_ButtonTextColour, b, size=wx.Size(50,25))
+ self.selectionbrush = wx.BitmapButton(self.panel, ID_SelectionBrush, b, size=wx.Size(50,25))
+ self.selectionpen = wx.BitmapButton(self.panel, ID_SelectionPen, b, size=wx.Size(50,25))
+ self.separatorcolour = wx.BitmapButton(self.panel, ID_SeparatorColour, b, size=wx.Size(50,25))
+
+ self.separatorspin = wx.SpinCtrl(self.panel, -1, "7", min=3, max=20,
+ style=wx.SP_ARROW_KEYS)
+ self.marginspin = wx.SpinCtrl(self.panel, -1, "6", min=3, max=20,
+ style=wx.SP_ARROW_KEYS)
+ self.paddingspin = wx.SpinCtrl(self.panel, -1, "6", min=3, max=20,
+ style=wx.SP_ARROW_KEYS)
+ self.borderspin = wx.SpinCtrl(self.panel, -1, "3", min=3, max=7,
+ style=wx.SP_ARROW_KEYS)
+
+ self.__set_properties()
+ self.__do_layout()
+
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnDefaultStyle, self.defaultstyle)
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnGradientStyle, self.gradientstyle)
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnVerticalGradient, self.verticalgradient)
+ self.Bind(wx.EVT_RADIOBUTTON, self.OnHorizontalGradient, self.horizontalgradient)
+ self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_BackgroundColour)
+ self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_GradientFrom)
+ self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_GradientTo)
+ self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_BorderColour)
+ self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_CaptionColour)
+ self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_ButtonTextColour)
+ self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_SelectionBrush)
+ self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_SelectionPen)
+ self.Bind(wx.EVT_BUTTON, self.OnSetColour, id=ID_SeparatorColour)
+
+ self.Bind(wx.EVT_SPINCTRL, self.OnSeparator, self.separatorspin)
+ self.Bind(wx.EVT_SPINCTRL, self.OnMargins, self.marginspin)
+ self.Bind(wx.EVT_SPINCTRL, self.OnPadding, self.paddingspin)
+ self.Bind(wx.EVT_SPINCTRL, self.OnBorder, self.borderspin)
+
+ self.Bind(wx.EVT_CLOSE, self.OnClose)
+
+
+ def __set_properties(self):
+
+ self.defaultstyle.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
+ self.defaultstyle.SetValue(1)
+ self.gradientstyle.SetFont(wx.Font(8, wx.DEFAULT, wx.NORMAL, wx.BOLD, 0, ""))
+ self.verticalgradient.SetValue(1)
+
+ if self.targetTitleBar.GetStyle() & bp.BP_DEFAULT_STYLE:
+ self.verticalgradient.Enable(False)
+ self.horizontalgradient.Enable(False)
+ self.defaultstyle.SetValue(1)
+ else:
+ self.gradientstyle.SetValue(1)
+
+ self.borderspin.SetValue(self.targetTitleBar.GetBPArt().GetMetric(bp.BP_BORDER_SIZE))
+ self.separatorspin.SetValue(self.targetTitleBar.GetBPArt().GetMetric(bp.BP_SEPARATOR_SIZE))
+ self.marginspin.SetValue(self.targetTitleBar.GetBPArt().GetMetric(bp.BP_MARGINS_SIZE).x)
+ self.paddingspin.SetValue(self.targetTitleBar.GetBPArt().GetMetric(bp.BP_PADDING_SIZE).x)
+
+ self.UpdateColors()
+
+
+ def __do_layout(self):
+
+ mainsizer = wx.BoxSizer(wx.VERTICAL)
+ buttonsizer = wx.BoxSizer(wx.HORIZONTAL)
+ bottomsizer = wx.StaticBoxSizer(self.bottomsizer_staticbox, wx.VERTICAL)
+ sizer_13 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_12 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_11 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_10 = wx.BoxSizer(wx.HORIZONTAL)
+ coloursizer = wx.StaticBoxSizer(self.coloursizer_staticbox, wx.HORIZONTAL)
+ rightsizer = wx.BoxSizer(wx.VERTICAL)
+ sizer_9 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_8 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_7 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_6 = wx.BoxSizer(wx.HORIZONTAL)
+ leftsizer = wx.BoxSizer(wx.VERTICAL)
+ sizer_5 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_4 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_3 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_2 = wx.BoxSizer(wx.HORIZONTAL)
+ sizer_1 = wx.BoxSizer(wx.HORIZONTAL)
+ stylesizer = wx.StaticBoxSizer(self.stylesizer_staticbox, wx.VERTICAL)
+ tophsizer = wx.BoxSizer(wx.HORIZONTAL)
+ tophsizer2 = wx.BoxSizer(wx.VERTICAL)
+
+ stylesizer.Add(self.defaultstyle, 0, wx.ALL|wx.EXPAND|wx.ADJUST_MINSIZE, 5)
+
+ tophsizer.Add(self.gradientstyle, 0, wx.LEFT|wx.RIGHT|wx.EXPAND|
+ wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+
+ tophsizer2.Add(self.verticalgradient, 0, wx.BOTTOM|wx.ADJUST_MINSIZE, 3)
+ tophsizer2.Add(self.horizontalgradient, 0, wx.ADJUST_MINSIZE, 0)
+
+ tophsizer.Add(tophsizer2, 1, wx.LEFT|wx.EXPAND|wx.ALIGN_CENTER_VERTICAL, 10)
+
+ stylesizer.Add(tophsizer, 1, wx.EXPAND, 0)
+
+ mainsizer.Add(stylesizer, 0, wx.ALL|wx.EXPAND, 5)
+
+ label_1 = wx.StaticText(self.panel, -1, "Background Brush Colour:")
+ sizer_1.Add(label_1, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+ sizer_1.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_1.Add(self.bakbrush, 0, wx.ADJUST_MINSIZE, 0)
+
+ leftsizer.Add(sizer_1, 1, wx.EXPAND, 0)
+
+ label_2 = wx.StaticText(self.panel, -1, "Gradient Colour From:")
+ sizer_2.Add(label_2, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+ sizer_2.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_2.Add(self.gradientfrom, 0, wx.ADJUST_MINSIZE, 0)
+
+ leftsizer.Add(sizer_2, 1, wx.EXPAND, 0)
+
+ label_3 = wx.StaticText(self.panel, -1, "Gradient Colour To:")
+ sizer_3.Add(label_3, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+ sizer_3.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_3.Add(self.gradientto, 0, wx.ADJUST_MINSIZE, 0)
+
+ leftsizer.Add(sizer_3, 1, wx.EXPAND, 0)
+
+ label_4 = wx.StaticText(self.panel, -1, "Border Colour:")
+ sizer_4.Add(label_4, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+ sizer_4.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_4.Add(self.bordercolour, 0, wx.ADJUST_MINSIZE, 0)
+
+ leftsizer.Add(sizer_4, 1, wx.EXPAND, 0)
+
+ label_5 = wx.StaticText(self.panel, -1, "Main Caption Colour:")
+ sizer_5.Add(label_5, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+ sizer_5.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_5.Add(self.captioncolour, 0, wx.ADJUST_MINSIZE, 0)
+
+ leftsizer.Add(sizer_5, 1, wx.EXPAND, 0)
+
+ coloursizer.Add(leftsizer, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5)
+ coloursizer.Add((20, 20), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+
+ label_6 = wx.StaticText(self.panel, -1, "Text Button Colour:")
+ sizer_6.Add(label_6, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+ sizer_6.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_6.Add(self.textbuttoncolour, 0, wx.ADJUST_MINSIZE, 0)
+
+ rightsizer.Add(sizer_6, 1, wx.EXPAND, 0)
+
+ label_7 = wx.StaticText(self.panel, -1, "Selection Brush Colour:")
+ sizer_7.Add(label_7, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+ sizer_7.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_7.Add(self.selectionbrush, 0, wx.ADJUST_MINSIZE, 0)
+
+ rightsizer.Add(sizer_7, 1, wx.EXPAND, 0)
+
+ label_8 = wx.StaticText(self.panel, -1, "Selection Pen Colour:")
+ sizer_8.Add(label_8, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+ sizer_8.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_8.Add(self.selectionpen, 0, wx.ADJUST_MINSIZE, 0)
+
+ rightsizer.Add(sizer_8, 1, wx.EXPAND, 0)
+
+ label_9 = wx.StaticText(self.panel, -1, "Separator Colour:")
+ sizer_9.Add(label_9, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+ sizer_9.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_9.Add(self.separatorcolour, 0, wx.ADJUST_MINSIZE, 0)
+
+ rightsizer.Add(sizer_9, 1, wx.EXPAND, 0)
+
+ coloursizer.Add(rightsizer, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL, 5)
+
+ mainsizer.Add(coloursizer, 0, wx.ALL|wx.EXPAND, 5)
+
+ label_10 = wx.StaticText(self.panel, -1, "Separator Size:")
+ sizer_10.Add(label_10, 0, wx.ALL|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+ sizer_10.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_10.Add(self.separatorspin, 0, wx.ALL|wx.ADJUST_MINSIZE, 5)
+
+ bottomsizer.Add(sizer_10, 1, wx.EXPAND, 0)
+
+ label_11 = wx.StaticText(self.panel, -1, "Margins Size:")
+ sizer_11.Add(label_11, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+ sizer_11.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_11.Add(self.marginspin, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ADJUST_MINSIZE, 5)
+
+ bottomsizer.Add(sizer_11, 1, wx.EXPAND, 0)
+
+ label_12 = wx.StaticText(self.panel, -1, "Padding Size:")
+ sizer_12.Add(label_12, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+ sizer_12.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_12.Add(self.paddingspin, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ADJUST_MINSIZE, 5)
+
+ bottomsizer.Add(sizer_12, 1, wx.EXPAND, 0)
+
+ label_13 = wx.StaticText(self.panel, -1, "Border Size:")
+ sizer_13.Add(label_13, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ALIGN_CENTER_VERTICAL|wx.ADJUST_MINSIZE, 5)
+ sizer_13.Add((0, 0), 1, wx.EXPAND|wx.ADJUST_MINSIZE, 0)
+ sizer_13.Add(self.borderspin, 0, wx.LEFT|wx.RIGHT|wx.BOTTOM|wx.ADJUST_MINSIZE, 5)
+
+ bottomsizer.Add(sizer_13, 1, wx.EXPAND, 0)
+
+ mainsizer.Add(bottomsizer, 0, wx.ALL|wx.EXPAND, 5)
+
+ self.panel.SetSizer(mainsizer)
+ sizer = wx.BoxSizer()
+ sizer.Add(self.panel, 1, wx.EXPAND)
+ self.SetSizer(sizer)
+ self.Fit()
+
+
+ def CreateColorBitmap(self, c):
+
+ image = wx.EmptyImage(25, 14)
+
+ for x in xrange(25):
+ for y in xrange(14):
+ pixcol = c
+ if x == 0 or x == 24 or y == 0 or y == 13:
+ pixcol = wx.BLACK
+
+ image.SetRGB(x, y, pixcol.Red(), pixcol.Green(), pixcol.Blue())
+
+ return image.ConvertToBitmap()
+
+
+ def UpdateColors(self):
+
+ bk = self.targetTitleBar.GetBPArt().GetColor(bp.BP_BACKGROUND_COLOR)
+ self.bakbrush.SetBitmapLabel(self.CreateColorBitmap(bk))
+
+ capfrom = self.targetTitleBar.GetBPArt().GetColor(bp.BP_GRADIENT_COLOR_FROM)
+ self.gradientfrom.SetBitmapLabel(self.CreateColorBitmap(capfrom))
+
+ capto = self.targetTitleBar.GetBPArt().GetColor(bp.BP_GRADIENT_COLOR_TO)
+ self.gradientto.SetBitmapLabel(self.CreateColorBitmap(capto))
+
+ captxt = self.targetTitleBar.GetBPArt().GetColor(bp.BP_TEXT_COLOR)
+ self.captioncolour.SetBitmapLabel(self.CreateColorBitmap(captxt))
+
+ bor = self.targetTitleBar.GetBPArt().GetColor(bp.BP_BORDER_COLOR)
+ self.bordercolour.SetBitmapLabel(self.CreateColorBitmap(bor))
+
+ btntext = self.targetTitleBar.GetBPArt().GetColor(bp.BP_BUTTONTEXT_COLOR)
+ self.textbuttoncolour.SetBitmapLabel(self.CreateColorBitmap(btntext))
+
+ selb = self.targetTitleBar.GetBPArt().GetColor(bp.BP_SELECTION_BRUSH_COLOR)
+ self.selectionbrush.SetBitmapLabel(self.CreateColorBitmap(selb))
+
+ selp = self.targetTitleBar.GetBPArt().GetColor(bp.BP_SELECTION_PEN_COLOR)
+ self.selectionpen.SetBitmapLabel(self.CreateColorBitmap(selp))
+
+ sepc = self.targetTitleBar.GetBPArt().GetColor(bp.BP_SEPARATOR_COLOR)
+ self.separatorcolour.SetBitmapLabel(self.CreateColorBitmap(sepc))
+
+
+ def OnDefaultStyle(self, event):
+
+ self.verticalgradient.Enable(False)
+ self.horizontalgradient.Enable(False)
+ self.targetTitleBar.SetStyle(bp.BP_DEFAULT_STYLE)
+
+ self.targetTitleBar.Refresh()
+
+ event.Skip()
+
+
+ def OnGradientStyle(self, event):
+
+ self.verticalgradient.Enable(True)
+ self.horizontalgradient.Enable(True)
+ self.targetTitleBar.SetStyle(bp.BP_USE_GRADIENT)
+ self.targetTitleBar.Refresh()
+
+ event.Skip()
+
+
+ def OnVerticalGradient(self, event):
+
+ self.targetTitleBar.GetBPArt().SetGradientType(bp.BP_GRADIENT_VERTICAL)
+ self.targetTitleBar.SetStyle(bp.BP_USE_GRADIENT)
+ self.targetTitleBar.Refresh()
+
+ event.Skip()
+
+
+ def OnHorizontalGradient(self, event):
+
+ self.targetTitleBar.GetBPArt().SetGradientType(bp.BP_GRADIENT_HORIZONTAL)
+ self.targetTitleBar.SetStyle(bp.BP_USE_GRADIENT)
+ self.targetTitleBar.Refresh()
+
+ event.Skip()
+
+
+ def OnSetColour(self, event):
+
+ dlg = wx.ColourDialog(self.parent)
+
+ dlg.SetTitle("Color Picker")
+
+ if dlg.ShowModal() != wx.ID_OK:
+ return
+
+ var = 0
+ if event.GetId() == ID_BackgroundColour:
+ var = bp.BP_BACKGROUND_COLOR
+ elif event.GetId() == ID_GradientFrom:
+ var = bp.BP_GRADIENT_COLOR_FROM
+ elif event.GetId() == ID_GradientTo:
+ var = bp.BP_GRADIENT_COLOR_TO
+ elif event.GetId() == ID_BorderColour:
+ var = bp.BP_BORDER_COLOR
+ elif event.GetId() == ID_CaptionColour:
+ var = bp.BP_TEXT_COLOR
+ elif event.GetId() == ID_ButtonTextColour:
+ var = bp.BP_BUTTONTEXT_COLOR
+ elif event.GetId() == ID_SelectionBrush:
+ var = bp.BP_SELECTION_BRUSH_COLOR
+ elif event.GetId() == ID_SelectionPen:
+ var = bp.BP_SELECTION_PEN_COLOR
+ elif event.GetId() == ID_SeparatorColour:
+ var = bp.BP_SEPARATOR_COLOR
+ else:
+ return
+
+ self.targetTitleBar.GetBPArt().SetColor(var, dlg.GetColourData().GetColour())
+ self.targetTitleBar.Refresh()
+ self.UpdateColors()
+
+ self.parent.useredited = True
+
+
+ def OnSeparator(self, event):
+
+ self.targetTitleBar.GetBPArt().SetMetric(bp.BP_SEPARATOR_SIZE,
+ event.GetInt())
+
+ self.targetTitleBar.DoLayout()
+ self.parent.mainPanel.Layout()
+ self.parent.useredited = True
+
+ event.Skip()
+
+
+ def OnMargins(self, event):
+
+ self.targetTitleBar.GetBPArt().SetMetric(bp.BP_MARGINS_SIZE,
+ wx.Size(event.GetInt(), event.GetInt()))
+
+ self.targetTitleBar.DoLayout()
+ self.parent.mainPanel.Layout()
+
+ self.parent.useredited = True
+
+ event.Skip()
+
+
+ def OnPadding(self, event):
+
+ self.targetTitleBar.GetBPArt().SetMetric(bp.BP_PADDING_SIZE,
+ wx.Size(event.GetInt(), event.GetInt()))
+
+ self.targetTitleBar.DoLayout()
+ self.parent.mainPanel.Layout()
+ self.parent.useredited = True
+
+ event.Skip()
+
+
+ def OnBorder(self, event):
+
+ self.targetTitleBar.GetBPArt().SetMetric(bp.BP_BORDER_SIZE,
+ event.GetInt())
+
+ self.targetTitleBar.DoLayout()
+ self.parent.mainPanel.Layout()
+
+ self.parent.useredited = True
+
+ event.Skip()
+
+
+ def OnClose(self, event):
+
+ self.parent.hassettingpanel = False
+ self.Destroy()
+
+
+
#----------------------------------------------------------------------
+
class ButtonPanelDemo(wx.Frame):
- def __init__(self, parent, id=wx.ID_ANY, title="ButtonPanel wxPython Demo", *args, **kw):
+ def __init__(self, parent, id=wx.ID_ANY, title="ButtonPanel wxPython Demo ;-)",
+ pos=wx.DefaultPosition, size=(640, 400), style=wx.DEFAULT_FRAME_STYLE):
- wx.Frame.__init__(self, parent, id, title, *args, **kw)
+ wx.Frame.__init__(self, parent, id, title, pos, size, style)
+ self.useredited = False
+ self.hassettingpanel = False
+
+ self.SetIcon(GetMondrianIcon())
self.CreateMenuBar()
self.statusbar = self.CreateStatusBar(2, wx.ST_SIZEGRIP)
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)
+ self.mainPanel = wx.Panel(self, -1)
+ self.logtext = wx.TextCtrl(self.mainPanel, -1, "", style=wx.TE_MULTILINE|wx.TE_READONLY)
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()
+ self.mainPanel.SetSizer(vSizer)
- sizer = wx.BoxSizer()
- sizer.Add(mainPanel, 1, wx.EXPAND)
- self.SetSizer(sizer)
- self.Fit()
+ self.alignments = [bp.BP_ALIGN_LEFT, bp.BP_ALIGN_RIGHT, bp.BP_ALIGN_TOP, bp.BP_ALIGN_BOTTOM]
+ self.alignment = bp.BP_ALIGN_LEFT
+ self.style = bp.BP_USE_GRADIENT
+
+ self.titleBar = bp.ButtonPanel(self.mainPanel, -1, "A Simple Test & Demo",
+ style=self.style, alignment=self.alignment)
+
+ self.created = False
+ self.pngs = [ (images.get_bp_btn1Bitmap(), 'label1'),
+ (images.get_bp_btn2Bitmap(), 'label2'),
+ (images.get_bp_btn3Bitmap(), 'label3'),
+ (images.get_bp_btn4Bitmap(), 'label4'),
+ ]
+ self.CreateButtons()
+ self.SetProperties()
+
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)
+
+ item = wx.MenuItem(edit_menu, wx.ID_ANY, "Set Bar Text")
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)
+ self.Bind(wx.EVT_MENU, self.OnSetBarText, item)
+
+ edit_menu.AppendSeparator()
+
+ submenu = wx.Menu()
+
+ item = wx.MenuItem(submenu, wx.ID_ANY, "BP_ALIGN_LEFT", kind=wx.ITEM_RADIO)
+ submenu.AppendItem(item)
+ item.Check(True)
+ self.Bind(wx.EVT_MENU, self.OnAlignment, item)
+
+ item = wx.MenuItem(submenu, wx.ID_ANY, "BP_ALIGN_RIGHT", kind=wx.ITEM_RADIO)
+ submenu.AppendItem(item)
+ self.Bind(wx.EVT_MENU, self.OnAlignment, item)
+
+ item = wx.MenuItem(submenu, wx.ID_ANY, "BP_ALIGN_TOP", kind=wx.ITEM_RADIO)
+ submenu.AppendItem(item)
+ self.Bind(wx.EVT_MENU, self.OnAlignment, item)
+
+ item = wx.MenuItem(submenu, wx.ID_ANY, "BP_ALIGN_BOTTOM", kind=wx.ITEM_RADIO)
+ submenu.AppendItem(item)
+ self.Bind(wx.EVT_MENU, self.OnAlignment, item)
+
+ edit_menu.AppendMenu(wx.ID_ANY, "&Alignment", submenu)
+
+ submenu = wx.Menu()
+
+ item = wx.MenuItem(submenu, wx.ID_ANY, "Default Style", kind=wx.ITEM_RADIO)
+ submenu.AppendItem(item)
+ self.Bind(wx.EVT_MENU, self.OnDefaultStyle, item)
+
+ item = wx.MenuItem(submenu, wx.ID_ANY, "Gradient Style", kind=wx.ITEM_RADIO)
+ submenu.AppendItem(item)
+ item.Check(True)
+ self.Bind(wx.EVT_MENU, self.OnGradientStyle, item)
+
+ edit_menu.AppendMenu(wx.ID_ANY, "&Styles", submenu)
+
+ edit_menu.AppendSeparator()
+
+ item = wx.MenuItem(submenu, wx.ID_ANY, "Settings Panel")
edit_menu.AppendItem(item)
- self.Bind(wx.EVT_MENU, self.OnAlignLeft, item)
+ self.Bind(wx.EVT_MENU, self.OnSettingsPanel, item)
+
+ demo_menu = wx.Menu()
+
+ item = wx.MenuItem(demo_menu, wx.ID_ANY, "Default Demo", kind=wx.ITEM_RADIO)
+ demo_menu.AppendItem(item)
+ self.Bind(wx.EVT_MENU, self.OnDefaultDemo, item)
+ item = wx.MenuItem(demo_menu, wx.ID_ANY, "Button Only Demo", kind=wx.ITEM_RADIO)
+ demo_menu.AppendItem(item)
+ self.Bind(wx.EVT_MENU, self.OnButtonOnly, 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(demo_menu, "&Demo")
mb.Append(help_menu, "&Help")
self.SetMenuBar(mb)
- def CreateButtons(self, alignment=bp.BP_ALIGN_RIGHT):
- self.buttons = []
+ def CreateButtons(self):
+
+ # Here we (re)create the buttons for the default startup demo
self.Freeze()
+
+ if self.created:
+ sizer = self.mainPanel.GetSizer()
+ sizer.Detach(0)
+ self.titleBar.Hide()
+ wx.CallAfter(self.titleBar.Destroy)
+ self.titleBar = bp.ButtonPanel(self.mainPanel, -1, "A Simple Test & Demo",
+ style=self.style, alignment=self.alignment)
+ self.SetProperties()
+
+ self.indices = []
+ for count, png in enumerate(self.pngs):
+
+ if count < 2:
+ # First 2 buttons are togglebuttons
+ kind = wx.ITEM_CHECK
+ else:
+ kind = wx.ITEM_NORMAL
+
+ btn = bp.ButtonInfo(self.titleBar, wx.NewId(),
+ png[0],
+ kind=kind)
+
+ self.titleBar.AddButton(btn)
+ self.Bind(wx.EVT_BUTTON, self.OnButton, id=btn.GetId())
+
+ self.indices.append(btn.GetId())
+
+ if count < 2:
+ # First 2 buttons have also a text
+ btn.SetText(png[1])
+
+ if count == 2:
+ # Append a separator after the second button
+ self.titleBar.AddSeparator()
+
+ if count == 1:
+ # Add a wx.TextCtrl to ButtonPanel
+ self.titleBar.AddControl(wx.TextCtrl(self.titleBar, -1, "Hello wxPython!"))
+ btn.SetTextAlignment(bp.BP_BUTTONTEXT_ALIGN_RIGHT)
+
+ # Add a wx.Choice to ButtonPanel
+ self.titleBar.AddControl(wx.Choice(self.titleBar, -1,
+ choices=["Hello", "From", "wxPython!"]))
+
+ self.strings = ["First", "Second", "Third", "Fourth"]
+
+ self.ChangeLayout()
+ self.Thaw()
+ self.titleBar.DoLayout()
+
+ self.created = True
- self.titleBar.RemoveAllButtons()
- bmps = [ self.btn1bmp,
- self.btn2bmp,
- self.btn3bmp,
- self.btn4bmp,
- ]
- if alignment == bp.BP_ALIGN_LEFT:
- bmps.reverse()
+ def ButtonOnly(self):
+
+ # Here we (re)create the buttons for the button-only demo
+ self.Freeze()
+
+ if self.created:
+ sizer = self.mainPanel.GetSizer()
+ sizer.Detach(0)
+ self.titleBar.Destroy()
+ self.titleBar = bp.ButtonPanel(self.mainPanel, -1, "A Simple Test & Demo",
+ style=self.style, alignment=self.alignment)
+ self.SetProperties()
+
+ # Buttons are created completely random, with random images, toggle behavior
+ # and text
+
+ self.indices = []
+ for count in xrange(8):
+
+ itemImage = random.randint(0, 3)
+ hasText = random.randint(0, 1)
+ itemKind = random.randint(0, 1)
+
+ btn = bp.ButtonInfo(self.titleBar, wx.NewId(), self.pngs[itemImage][0],
+ kind=itemKind)
+
+ if hasText:
+ btn.SetText(self.pngs[itemImage][1])
+ rightText = random.randint(0, 1)
+ if rightText:
+ btn.SetTextAlignment(bp.BP_BUTTONTEXT_ALIGN_RIGHT)
- 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.Bind(wx.EVT_BUTTON, self.OnButton, id=btn.GetId())
+
+ self.indices.append(btn.GetId())
- self.strings = ["First", "Second", "Third", "Fourth"]
- if alignment == bp.BP_ALIGN_RIGHT:
- self.strings.reverse()
+ if count in [0, 3, 5]:
+ self.titleBar.AddSeparator()
+
+ self.strings = ["First", "Second", "Third", "Fourth", "Fifth", "Sixth", "Seventh", "Eighth"]
- self.titleBar.SetAlignment(alignment)
+ self.ChangeLayout()
self.Thaw()
+ self.titleBar.DoLayout()
+
+ def ChangeLayout(self):
- def OnAlignLeft(self, event):
- self.CreateButtons(alignment=bp.BP_ALIGN_LEFT)
- event.Skip()
+ # Change the layout after a switch in ButtonPanel alignment
+ self.Freeze()
+
+ if self.alignment in [bp.BP_ALIGN_LEFT, bp.BP_ALIGN_RIGHT]:
+ vSizer = wx.BoxSizer(wx.VERTICAL)
+ else:
+ vSizer = wx.BoxSizer(wx.HORIZONTAL)
+ self.mainPanel.SetSizer(vSizer)
+
+ vSizer.Add(self.titleBar, 0, wx.EXPAND)
+ vSizer.Add((20, 20))
+ vSizer.Add(self.logtext, 1, wx.EXPAND|wx.ALL, 5)
+
+ vSizer.Layout()
+ self.mainPanel.Layout()
+ self.Thaw()
+
+
+ def SetProperties(self):
+
+ # No resetting if the user is using the Settings Panel
+ if self.useredited:
+ return
+
+ # Sets the colours for the two demos: called only if the user didn't
+ # modify the colours and sizes using the Settings Panel
+ bpArt = self.titleBar.GetBPArt()
+
+ if self.style & bp.BP_USE_GRADIENT:
+ # set the color the text is drawn with
+ bpArt.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.
+ bpArt.SetColor(bp.BP_BORDER_COLOR, wx.Colour(120,23,224))
+ bpArt.SetColor(bp.BP_GRADIENT_COLOR_FROM, wx.Colour(60,11,112))
+ bpArt.SetColor(bp.BP_GRADIENT_COLOR_TO, wx.Colour(120,23,224))
+ bpArt.SetColor(bp.BP_BUTTONTEXT_COLOR, wx.Colour(70,143,255))
+ bpArt.SetColor(bp.BP_SEPARATOR_COLOR,
+ bp.BrightenColour(wx.Colour(60, 11, 112), 0.85))
+ bpArt.SetColor(bp.BP_SELECTION_BRUSH_COLOR, wx.Color(225, 225, 255))
+ bpArt.SetColor(bp.BP_SELECTION_PEN_COLOR, wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION))
+
+ else:
+
+ background = self.titleBar.GetBackgroundColour()
+ bpArt.SetColor(bp.BP_TEXT_COLOR, wx.BLUE)
+ bpArt.SetColor(bp.BP_BORDER_COLOR,
+ bp.BrightenColour(background, 0.85))
+ bpArt.SetColor(bp.BP_SEPARATOR_COLOR,
+ bp.BrightenColour(background, 0.85))
+ bpArt.SetColor(bp.BP_BUTTONTEXT_COLOR, wx.BLACK)
+ bpArt.SetColor(bp.BP_SELECTION_BRUSH_COLOR, wx.Colour(242, 242, 235))
+ bpArt.SetColor(bp.BP_SELECTION_PEN_COLOR, wx.Colour(206, 206, 195))
+
+ self.titleBar.SetStyle(self.style)
+
+
+ def OnAlignment(self, event):
+
+ # Here we change the alignment property of ButtonPanel
+ current = event.GetId()
+ edit_menu = self.GetMenuBar().FindMenu("Edit")
+ edit_menu = self.GetMenuBar().GetMenu(edit_menu)
+ menu = edit_menu.FindItem("BP_ALIGN_LEFT")
+
+ alignment = self.alignments[current - menu]
+ self.alignment = alignment
- def OnAlignRight(self, event):
- self.CreateButtons(alignment=bp.BP_ALIGN_RIGHT)
+ self.ChangeLayout()
+ self.titleBar.SetAlignment(alignment)
+ self.mainPanel.Layout()
+
event.Skip()
+ def OnDefaultStyle(self, event):
+
+ # Restore the ButtonPanel default style (no gradient)
+ self.style = bp.BP_DEFAULT_STYLE
+ self.SetProperties()
+
+ event.Skip()
+
+
+ def OnGradientStyle(self, event):
+
+ # Use gradients to paint ButtonPanel background
+ self.style = bp.BP_USE_GRADIENT
+ self.SetProperties()
+
+ event.Skip()
+
+
+ def OnDefaultDemo(self, event):
+
+ # Reload the default startup demo
+ self.CreateButtons()
+ event.Skip()
+
+
+ def OnButtonOnly(self, event):
+
+ # Reload the button-only demo
+ self.ButtonOnly()
+ event.Skip()
+
+
def OnButton(self, event):
+
btn = event.GetId()
- indx = self.buttons.index(btn)
+ indx = self.indices.index(btn)
+
self.logtext.AppendText("Event Fired From " + self.strings[indx] + " Button\n")
event.Skip()
+ def OnSetBarText(self, event):
+
+ dlg = wx.TextEntryDialog(self, "Enter The Text You Wish To Display On The Bar (Clear If No Text):",
+ "Set Text", self.titleBar.GetBarText())
+
+ if dlg.ShowModal() == wx.ID_OK:
+
+ val = dlg.GetValue()
+ self.titleBar.SetBarText(val)
+ self.titleBar.DoLayout()
+ self.mainPanel.Layout()
+
+
+ def OnSettingsPanel(self, event):
+
+ if self.hassettingpanel:
+ self.settingspanel.Raise()
+ return
+
+ self.settingspanel = SettingsPanel(self, -1)
+ self.settingspanel.Show()
+ self.hassettingpanel = True
+
+
def OnClose(self, event):
+
self.Destroy()
- event.Skip()
+ event.Skip()
def OnAbout(self, event):
dlg.ShowModal()
dlg.Destroy()
+
+
#----------------------------------------------------------------------
class TestPanel(wx.Panel):
# Python Code By:
#
# Andrea Gavana, @ 02 Oct 2006
-# Latest Revision: 02 Oct 2006, 17.00 GMT
+# Latest Revision: 16 Oct 2006, 17.00 GMT
#
#
# For All Kind Of Problems, Requests Of Enhancements And Bug Reports, Please
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)
ButtonPanel Is Freeware And Distributed Under The wxPython License.
-Latest Revision: Andrea Gavana @ 02 Oct 2006, 17.00 GMT
-Version 0.1.
+Latest Revision: Andrea Gavana @ 12 Oct 2006, 17.00 GMT
+Version 0.3.
"""
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
+# Some constants to tune the BPArt class
+BP_BACKGROUND_COLOR = 0
+""" Background brush colour when no gradient shading exists. """
+BP_GRADIENT_COLOR_FROM = 1
+""" Starting gradient colour, used only when BP_USE_GRADIENT style is applied. """
+BP_GRADIENT_COLOR_TO = 2
+""" Ending gradient colour, used only when BP_USE_GRADIENT style is applied. """
+BP_BORDER_COLOR = 3
+""" Pen colour to paint the border of ButtonPanel. """
+BP_TEXT_COLOR = 4
+""" Main ButtonPanel caption colour. """
+BP_BUTTONTEXT_COLOR = 5
+""" Text colour for buttons with text. """
+BP_BUTTONTEXT_INACTIVE_COLOR = 6
+""" Text colour for inactive buttons with text. """
+BP_SELECTION_BRUSH_COLOR = 7
+""" Brush colour to be used when hovering or selecting a button. """
+BP_SELECTION_PEN_COLOR = 8
+""" Pen colour to be used when hovering or selecting a button. """
+BP_SEPARATOR_COLOR = 9
+""" Pen colour used to paint the separators. """
+BP_TEXT_FONT = 10
+""" Font of the ButtonPanel main caption. """
+BP_BUTTONTEXT_FONT = 11
+""" Text font for the buttons with text. """
+
+BP_BUTTONTEXT_ALIGN_BOTTOM = 12
+""" Flag that indicates the image and text in buttons is stacked. """
+BP_BUTTONTEXT_ALIGN_RIGHT = 13
+""" Flag that indicates the text is shown alongside the image in buttons with text. """
+
+BP_SEPARATOR_SIZE = 14
+"""
+Separator size. NB: This is not the line width, but the sum of the space before
+and after the separator line plus the width of the line.
+"""
+BP_MARGINS_SIZE = 15
+"""
+Size of the left/right margins in ButtonPanel (top/bottom for vertically
+aligned ButtonPanels).
+"""
+BP_BORDER_SIZE = 16
+""" Size of the border. """
+BP_PADDING_SIZE = 17
+""" Inter-tool separator size. """
+
+# Caption Gradient Type
+BP_GRADIENT_NONE = 0
+""" No gradient shading should be used to paint the background. """
+BP_GRADIENT_VERTICAL = 1
+""" Vertical gradient shading should be used to paint the background. """
+BP_GRADIENT_HORIZONTAL = 2
+""" Horizontal gradient shading should be used to paint the background. """
# 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
+BP_ALIGN_RIGHT = 1
+BP_ALIGN_LEFT = 2
+BP_ALIGN_TOP = 4
+BP_ALIGN_BOTTOM = 8
+
+# ButtonPanel styles
+BP_DEFAULT_STYLE = 1
+BP_USE_GRADIENT = 2
-# ButtonPanel default style
-BP_DEFAULT_STYLE = 2
+
+# Check for the new method in 2.7 (not present in 2.6.3.3)
+if wx.VERSION_STRING < "2.7":
+ wx.Rect.Contains = lambda self, point: wx.Rect.Inside(self, point)
-def BrightenColor(color, factor):
+def BrightenColour(color, factor):
""" Bright the input colour by a factor."""
val = color.Red()*factor
return wx.Color(red, green, blue)
+def GrayOut(anImage):
+ """
+ Convert the given image (in place) to a grayed-out version,
+ appropriate for a 'Disabled' appearance.
+ """
+
+ factor = 0.7 # 0 < f < 1. Higher Is Grayer
+
+ anImage = anImage.ConvertToImage()
+ if anImage.HasAlpha():
+ anImage.ConvertAlphaToMask(1)
+
+ if anImage.HasMask():
+ maskColor = (anImage.GetMaskRed(), anImage.GetMaskGreen(), anImage.GetMaskBlue())
+ else:
+ maskColor = None
+
+ data = map(ord, list(anImage.GetData()))
+
+ for i in range(0, len(data), 3):
+
+ pixel = (data[i], data[i+1], data[i+2])
+ pixel = MakeGray(pixel, factor, maskColor)
+
+ for x in range(3):
+ data[i+x] = pixel[x]
+
+ anImage.SetData(''.join(map(chr, data)))
+
+ anImage = anImage.ConvertToBitmap()
+
+ return anImage
+
+
+def MakeGray((r,g,b), factor, maskColor):
+ """
+ Make a pixel grayed-out. If the pixel matches the maskColor, it won't be
+ changed.
+ """
+
+ if (r,g,b) != maskColor:
+ return map(lambda x: int((230 - x) * factor) + x, (r,g,b))
+ else:
+ return (r,g,b)
+
+
+# ---------------------------------------------------------------------------- #
+# Class BPArt
+# Handles all the drawings for buttons, separators and text and allows the
+# programmer to set colours, sizes and gradient shadings for ButtonPanel
+# ---------------------------------------------------------------------------- #
+
+class BPArt:
+ """
+ BPArt is an art provider class which does all of the drawing for ButtonPanel.
+ This allows the library caller to customize the BPArt or to completely replace
+ all drawing with custom BPArts.
+ """
+
+ def __init__(self, parentStyle):
+ """ Default class constructor. """
+
+ base_color = wx.SystemSettings_GetColour(wx.SYS_COLOUR_3DFACE)
+
+ self._background_brush = wx.Brush(base_color, wx.SOLID)
+ self._gradient_color_to = wx.WHITE
+ self._gradient_color_from = wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION)
+
+ if parentStyle & BP_USE_GRADIENT:
+ self._border_pen = wx.Pen(wx.WHITE, 3)
+ self._caption_text_color = wx.WHITE
+ self._buttontext_color = wx.Colour(70, 143, 255)
+ self._separator_pen = wx.Pen(BrightenColour(self._gradient_color_from, 1.4))
+ self._gradient_type = BP_GRADIENT_VERTICAL
+ else:
+ self._border_pen = wx.Pen(BrightenColour(base_color, 0.9), 3)
+ self._caption_text_color = wx.BLACK
+ self._buttontext_color = wx.SystemSettings_GetColour(wx.SYS_COLOUR_BTNTEXT)
+ self._separator_pen = wx.Pen(BrightenColour(base_color, 0.9))
+ self._gradient_type = BP_GRADIENT_NONE
+
+ self._buttontext_inactive_color = wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT)
+ self._selection_brush = wx.Brush(wx.Color(225, 225, 255))
+ self._selection_pen = wx.Pen(wx.SystemSettings_GetColour(wx.SYS_COLOUR_ACTIVECAPTION))
+
+ sysfont = wx.SystemSettings.GetFont(wx.SYS_DEFAULT_GUI_FONT)
+ self._caption_font = wx.Font(sysfont.GetPointSize(), wx.DEFAULT, wx.NORMAL, wx.BOLD,
+ False, sysfont.GetFaceName())
+ self._buttontext_font = wx.Font(sysfont.GetPointSize(), wx.DEFAULT, wx.NORMAL, wx.NORMAL,
+ False, sysfont.GetFaceName())
+
+ self._separator_size = 7
+ self._margins_size = wx.Size(6, 6)
+ self._caption_border_size = 3
+ self._padding_size = wx.Size(6, 6)
+
+
+ def GetMetric(self, id):
+ """ Returns sizes of customizable options. """
+
+ if id == BP_SEPARATOR_SIZE:
+ return self._separator_size
+ elif id == BP_MARGINS_SIZE:
+ return self._margins_size
+ elif id == BP_BORDER_SIZE:
+ return self._caption_border_size
+ elif id == BP_PADDING_SIZE:
+ return self._padding_size
+ else:
+ raise "\nERROR: Invalid Metric Ordinal. "
+
+
+ def SetMetric(self, id, new_val):
+ """ Sets sizes for customizable options. """
+
+ if id == BP_SEPARATOR_SIZE:
+ self._separator_size = new_val
+ elif id == BP_MARGINS_SIZE:
+ self._margins_size = new_val
+ elif id == BP_BORDER_SIZE:
+ self._caption_border_size = new_val
+ self._border_pen.SetWidth(new_val)
+ elif id == BP_PADDING_SIZE:
+ self._padding_size = new_val
+ else:
+ raise "\nERROR: Invalid Metric Ordinal. "
+
+
+ def GetColor(self, id):
+ """ Returns colours of customizable options. """
+
+ if id == BP_BACKGROUND_COLOR:
+ return self._background_brush.GetColour()
+ elif id == BP_GRADIENT_COLOR_FROM:
+ return self._gradient_color_from
+ elif id == BP_GRADIENT_COLOR_TO:
+ return self._gradient_color_to
+ elif id == BP_BORDER_COLOR:
+ return self._border_pen.GetColour()
+ elif id == BP_TEXT_COLOR:
+ return self._caption_text_color
+ elif id == BP_BUTTONTEXT_COLOR:
+ return self._buttontext_color
+ elif id == BP_BUTTONTEXT_INACTIVE_COLOR:
+ return self._buttontext_inactive_color
+ elif id == BP_SELECTION_BRUSH_COLOR:
+ return self._selection_brush.GetColour()
+ elif id == BP_SELECTION_PEN_COLOR:
+ return self._selection_pen.GetColour()
+ elif id == BP_SEPARATOR_COLOR:
+ return self._separator_pen.GetColour()
+ else:
+ raise "\nERROR: Invalid Colour Ordinal. "
+
+
+ def SetColor(self, id, colour):
+ """ Sets colours for customizable options. """
+
+ if id == BP_BACKGROUND_COLOR:
+ self._background_brush.SetColour(colour)
+ elif id == BP_GRADIENT_COLOR_FROM:
+ self._gradient_color_from = colour
+ elif id == BP_GRADIENT_COLOR_TO:
+ self._gradient_color_to = colour
+ elif id == BP_BORDER_COLOR:
+ self._border_pen.SetColour(colour)
+ elif id == BP_TEXT_COLOR:
+ self._caption_text_color = colour
+ elif id == BP_BUTTONTEXT_COLOR:
+ self._buttontext_color = colour
+ elif id == BP_BUTTONTEXT_INACTIVE_COLOR:
+ self._buttontext_inactive_color = colour
+ elif id == BP_SELECTION_BRUSH_COLOR:
+ self._selection_brush.SetColour(colour)
+ elif id == BP_SELECTION_PEN_COLOR:
+ self._selection_pen.SetColour(colour)
+ elif id == BP_SEPARATOR_COLOR:
+ self._separator_pen.SetColour(colour)
+ else:
+ raise "\nERROR: Invalid Colour Ordinal. "
+
+
+ GetColour = GetColor
+ SetColour = SetColor
+
+
+ def SetFont(self, id, font):
+ """ Sets font for customizable options. """
+
+ if id == BP_TEXT_FONT:
+ self._caption_font = font
+ elif id == BP_BUTTONTEXT_FONT:
+ self._buttontext_font = font
+
+
+ def GetFont(self, id):
+ """ Returns font of customizable options. """
+
+ if id == BP_TEXT_FONT:
+ return self._caption_font
+ elif id == BP_BUTTONTEXT_FONT:
+ return self._buttontext_font
+
+ return wx.NoneFont
+
+
+ def SetGradientType(self, gradient):
+ """ Sets the gradient type for BPArt drawings. """
+
+ self._gradient_type = gradient
+
+
+ def GetGradientType(self):
+ """ Returns the gradient type for BPArt drawings. """
+
+ return self._gradient_type
+
+
+ def DrawSeparator(self, dc, rect, isVertical):
+ """ Draws a separator in ButtonPanel. """
+
+ dc.SetPen(self._separator_pen)
+
+ if isVertical:
+ ystart = yend = rect.y + rect.height/2
+ xstart = int(rect.x + 1.5*self._caption_border_size)
+ xend = int(rect.x + rect.width - 1.5*self._caption_border_size)
+ dc.DrawLine(xstart, ystart, xend, yend)
+ else:
+ xstart = xend = rect.x + rect.width/2
+ ystart = int(rect.y + 1.5*self._caption_border_size)
+ yend = int(rect.y + rect.height - 1.5*self._caption_border_size)
+ dc.DrawLine(xstart, ystart, xend, yend)
+
+
+ def DrawCaption(self, dc, rect, captionText):
+ """ Draws the main caption text in ButtonPanel. """
+
+ textColour = self._caption_text_color
+ textFont = self._caption_font
+ padding = self._padding_size
+
+ dc.SetTextForeground(textColour)
+ dc.SetFont(textFont)
+
+ dc.DrawText(captionText, rect.x + padding.x, rect.y+padding.y)
+
+
+ def DrawButton(self, dc, rect, parentSize, buttonBitmap, isVertical,
+ buttonStatus, isToggled, textAlignment, text=""):
+ """ Draws a button in ButtonPanel, together with its text (if any). """
+
+ bmpxsize, bmpysize = buttonBitmap.GetWidth(), buttonBitmap.GetHeight()
+ dx = dy = focus = 0
+
+ borderw = self._caption_border_size
+ padding = self._padding_size
+
+ buttonFont = self._buttontext_font
+ dc.SetFont(buttonFont)
+
+ if isVertical:
+
+ rect = wx.Rect(borderw, rect.y, rect.width-2*borderw, rect.height)
+
+ if text != "":
+
+ textW, textH = dc.GetTextExtent(text)
+
+ if textAlignment == BP_BUTTONTEXT_ALIGN_RIGHT:
+ fullExtent = bmpxsize + padding.x/2 + textW
+ bmpypos = rect.y + (rect.height - bmpysize)/2
+ bmpxpos = rect.x + (rect.width - fullExtent)/2
+ textxpos = bmpxpos + padding.x/2 + bmpxsize
+ textypos = bmpypos + (bmpysize - textH)/2
+ else:
+ bmpxpos = rect.x + (rect.width - bmpxsize)/2
+ bmpypos = rect.y + padding.y
+ textxpos = rect.x + (rect.width - textW)/2
+ textypos = bmpypos + bmpysize + padding.y/2
+ else:
+ bmpxpos = rect.x + (rect.width - bmpxsize)/2
+ bmpypos = rect.y + (rect.height - bmpysize)/2
+
+
+ else:
+
+ rect = wx.Rect(rect.x, borderw, rect.width, rect.height-2*borderw)
+
+ if text != "":
+
+ textW, textH = dc.GetTextExtent(text)
+
+ if textAlignment == BP_BUTTONTEXT_ALIGN_RIGHT:
+ fullExtent = bmpxsize + padding.x/2 + textW
+ bmpypos = rect.y + (rect.height - bmpysize)/2
+ bmpxpos = rect.x + (rect.width - fullExtent)/2
+ textxpos = bmpxpos + padding.x/2 + bmpxsize
+ textypos = bmpypos + (bmpysize - textH)/2
+ else:
+ fullExtent = bmpysize + padding.y/2 + textH
+ bmpxpos = rect.x + (rect.width - bmpxsize)/2
+ bmpypos = rect.y + (rect.height - fullExtent)/2
+ textxpos = rect.x + (rect.width - textW)/2
+ textypos = bmpypos + bmpysize + padding.y/2
+ else:
+ bmpxpos = rect.x + (rect.width - bmpxsize)/2
+ bmpypos = rect.y + (rect.height - bmpysize)/2
+
+ # Draw a button
+ # [ Padding | Text | .. Buttons .. | Padding ]
+
+ if buttonStatus in ["Pressed", "Toggled", "Hover"]:
+ dc.SetBrush(self._selection_brush)
+ dc.SetPen(self._selection_pen)
+ dc.DrawRoundedRectangleRect(rect, 4)
+
+ if buttonStatus == "Pressed" or isToggled:
+ dx = dy = 1
+
+ dc.DrawBitmap(buttonBitmap, bmpxpos+dx, bmpypos+dy, True)
+
+ if text != "":
+ isEnabled = buttonStatus != "Disabled"
+ self.DrawLabel(dc, text, isEnabled, textxpos+dx, textypos+dy)
+
+
+ def DrawLabel(self, dc, text, isEnabled, xpos, ypos):
+ """ Draws the label for a button. """
+
+ if not isEnabled:
+ dc.SetTextForeground(self._buttontext_inactive_color)
+ else:
+ dc.SetTextForeground(self._buttontext_color)
+
+ dc.DrawText(text, xpos, ypos)
+
+
+ def DrawButtonPanel(self, dc, rect, style):
+ """ Paint the ButtonPanel's background. """
+
+ if style & BP_USE_GRADIENT:
+ # Draw gradient color in the backgroud of the panel
+ self.FillGradientColor(dc, rect)
+
+ # Draw a rectangle around the panel
+ backBrush = (style & BP_USE_GRADIENT and [wx.TRANSPARENT_BRUSH] or \
+ [self._background_brush])[0]
+
+ dc.SetBrush(backBrush)
+ dc.SetPen(self._border_pen)
+ dc.DrawRectangleRect(rect)
+
+
+ def FillGradientColor(self, dc, rect):
+ """ Gradient fill from colour 1 to colour 2 with top to bottom or left to right. """
+
+ if rect.height < 1 or rect.width < 1:
+ return
+
+ isVertical = self._gradient_type == BP_GRADIENT_VERTICAL
+ size = (isVertical and [rect.height] or [rect.width])[0]
+ start = (isVertical and [rect.y] or [rect.x])[0]
+
+ # calculate gradient coefficients
+
+ col2 = self._gradient_color_from
+ col1 = self._gradient_color_to
+
+ 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 coord in xrange(start, start + 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))
+ if isVertical:
+ dc.DrawLine(rect.x, coord, rect.x + rect.width, coord)
+ else:
+ dc.DrawLine(coord, rect.y, coord, rect.y + rect.width)
+
+ rf += rstep
+ gf += gstep
+ bf += bstep
+
+
+class Control(wx.EvtHandler):
+
+ def __init__(self, parent, size=wx.Size(-1, -1)):
+ """
+ Default class constructor.
+
+ Base class for all pseudo controls
+ parent = parent object
+ size = (width, height)
+ """
+
+ wx.EvtHandler.__init__(self)
+
+ self._parent = parent
+ self._id = wx.NewId()
+ self._size = size
+ self._isshown = True
+ self._focus = False
+
+
+ def Show(self, show=True):
+ """ Shows or hide the control. """
+
+ self._isshown = show
+
+
+ def Hide(self):
+ """ Hides the control. """
+
+ self.Show(False)
+
+
+ def IsShown(self):
+ """ Returns whether the control is shown or not. """
+
+ return self._isshown
+
+
+ def GetId(self):
+ """ Returns the control id. """
+
+ return self._id
+
+
+ def GetBestSize(self):
+ """ Returns the control best size. """
+
+ return self._size
+
+
+ def Disable(self):
+ """ Disables the control. """
+
+ self.Enable(False)
+
+
+ def Enable(self, value=True):
+ """ Enables or disables the control. """
+
+ self.disabled = not value
+
+
+ def SetFocus(self, focus=True):
+ """ Sets or kills the focus on the control. """
+
+ self._focus = focus
+
+
+ def HasFocus(self):
+ """ Returns whether the control has the focus or not. """
+
+ return self._focus
+
+
+ def OnMouseEvent(self, x, y, event):
+ pass
+
+ def Draw(self, rect):
+ pass
+
+
+
+class Sizer(object):
+ """
+ Sizer
+
+ This is a mix-in class to add pseudo support to a wx sizer. Just create
+ a new class that derives from this class and the wx sizer and intercepts
+ any methods that add to the wx sizer.
+ """
+ def __init__(self):
+ self.children = [] # list of child Pseudo Controls
+
+ # Sizer doesn't use the x1,y1,x2,y2 so allow it to
+ # be called with or without the coordinates
+ def Draw(self, dc, x1=0, y1=0, x2=0, y2=0):
+ for item in self.children:
+ # use sizer coordinates rather than
+ # what is passed in
+ c = item.GetUserData()
+ c.Draw(dc, item.GetRect())
+
+ def GetBestSize(self):
+ # this should be handled by the wx.Sizer based class
+ return self.GetMinSize()
+
+
+# Pseudo BoxSizer
+class BoxSizer(Sizer, wx.BoxSizer):
+ def __init__(self, orient=wx.HORIZONTAL):
+ wx.BoxSizer.__init__(self, orient)
+ Sizer.__init__(self)
+
+ #-------------------------------------------
+ # sizer overrides (only called from Python)
+ #-------------------------------------------
+ # no support for user data if it's a pseudocontrol
+ # since that is already used
+ def Add(self, item, proportion=0, flag=0, border=0, userData=None):
+ # check to see if it's a pseudo object or sizer
+ if isinstance(item, Sizer):
+ szitem = wx.BoxSizer.Add(self, item, proportion, flag, border, item)
+ self.children.append(szitem)
+ elif isinstance(item, Control): # Control should be what ever class your controls come from
+ sz = item.GetBestSize()
+ # add a spacer to track this object
+ szitem = wx.BoxSizer.Add(self, sz, proportion, flag, border, item)
+ self.children.append(szitem)
+ else:
+ wx.BoxSizer.Add(self, item, proportion, flag, border, userData)
+
+ def Prepend(self, item, proportion=0, flag=0, border=0, userData=None):
+ # check to see if it's a pseudo object or sizer
+ if isinstance(item, Sizer):
+ szitem = wx.BoxSizer.Prepend(self, item, proportion, flag, border, item)
+ self.children.append(szitem)
+ elif isinstance(item, Control): # Control should be what ever class your controls come from
+ sz = item.GetBestSize()
+ # add a spacer to track this object
+ szitem = wx.BoxSizer.Prepend(self, sz, proportion, flag, border, item)
+ self.children.insert(0,szitem)
+ else:
+ wx.BoxSizer.Prepend(self, item, proportion, flag, border, userData)
+
+ def Insert(self, before, item, proportion=0, flag=0, border=0, userData=None, realIndex=None):
+ # check to see if it's a pseudo object or sizer
+ if isinstance(item, Sizer):
+ szitem = wx.BoxSizer.Insert(self, before, item, proportion, flag, border, item)
+ self.children.append(szitem)
+ elif isinstance(item, Control): # Control should be what ever class your controls come from
+ sz = item.GetBestSize()
+ # add a spacer to track this object
+ szitem = wx.BoxSizer.Insert(self, before, sz, proportion, flag, border, item)
+ if realIndex is not None:
+ self.children.insert(realIndex,szitem)
+ else:
+ self.children.insert(before,szitem)
+
+ else:
+ wx.BoxSizer.Insert(self, before, item, proportion, flag, border, userData)
+
+
+ def Remove(self, indx, pop=-1):
+
+ if pop >= 0:
+ self.children.pop(pop)
+
+ wx.BoxSizer.Remove(self, indx)
+
+
+ def Layout(self):
+
+ for ii, child in enumerate(self.GetChildren()):
+ item = child.GetUserData()
+ if item and child.IsShown():
+ self.SetItemMinSize(ii, *item.GetBestSize())
+
+ wx.BoxSizer.Layout(self)
+
+
+ def Show(self, item, show=True):
+
+ child = self.GetChildren()[item]
+ if child and child.GetUserData():
+ child.GetUserData().Show(show)
+
+ wx.BoxSizer.Show(self, item, show)
+
+
+# ---------------------------------------------------------------------------- #
+# Class Separator
+# This class holds all the information to size and draw a separator inside
+# ButtonPanel
+# ---------------------------------------------------------------------------- #
+
+class Separator(Control):
+
+ def __init__(self, parent):
+ """ Default class constructor. """
+
+ self._isshown = True
+ self._parent = parent
+ Control.__init__(self, parent)
+
+
+ def GetBestSize(self):
+ """ Returns the separator best size. """
+
+ # 10 is completely arbitrary, but it works anyhow
+ if self._parent.IsVertical():
+ return wx.Size(10, self._parent._art.GetMetric(BP_SEPARATOR_SIZE))
+ else:
+ return wx.Size(self._parent._art.GetMetric(BP_SEPARATOR_SIZE), 10)
+
+
+ def Draw(self, dc, rect):
+ """ Draws the separator. Actually the drawing is done in BPArt. """
+
+ if not self.IsShown():
+ return
+
+ isVertical = self._parent.IsVertical()
+ self._parent._art.DrawSeparator(dc, rect, isVertical)
+
+
+# ---------------------------------------------------------------------------- #
+# Class ButtonPanelText
+# This class is used to hold data about the main caption in ButtonPanel
+# ---------------------------------------------------------------------------- #
+
+class ButtonPanelText(Control):
+
+ def __init__(self, parent, text=""):
+ """ Default class constructor. """
+
+ self._text = text
+ self._isshown = True
+ self._parent = parent
+
+ Control.__init__(self, parent)
+
+
+ def GetText(self):
+ """ Returns the caption text. """
+
+ return self._text
+
+
+ def SetText(self, text=""):
+ """ Sets the caption text. """
+
+ self._text = text
+
+
+ def CreateDC(self):
+ """ Convenience function to create a DC. """
+
+ dc = wx.ClientDC(self._parent)
+ textFont = self._parent._art.GetFont(BP_TEXT_FONT)
+ dc.SetFont(textFont)
+
+ return dc
+
+
+ def GetBestSize(self):
+ """ Returns the best size for the main caption in ButtonPanel. """
+
+ if self._text == "":
+ return wx.Size(0, 0)
+
+ dc = self.CreateDC()
+ rect = self._parent.GetClientRect()
+
+ tw, th = dc.GetTextExtent(self._text)
+ padding = self._parent._art.GetMetric(BP_PADDING_SIZE)
+ self._size = wx.Size(tw+2*padding.x, th+2*padding.y)
+
+ return self._size
+
+
+ def Draw(self, dc, rect):
+ """ Draws the main caption. Actually the drawing is done in BPArt. """
+
+ if not self.IsShown():
+ return
+
+ captionText = self.GetText()
+ self._parent._art.DrawCaption(dc, rect, captionText)
+
+
# -- 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:
+class ButtonInfo(Control):
- def __init__(self, id=wx.ID_ANY, bmp=wx.NullBitmap, status=-1):
+ def __init__(self, parent, id=wx.ID_ANY, bmp=wx.NullBitmap,
+ status="Normal", text="", kind=wx.ITEM_NORMAL):
"""
Default class constructor.
Parameters:
+ - parent: the parent window (ButtonPanel);
- id: the button id;
- bmp: the associated bitmap;
- status: button status (pressed, hovered, None).
+ - text to be displayed either below of to the right of the button
"""
+
if id == wx.ID_ANY:
id = wx.NewId()
- self._id = id
- self._bmp = bmp
+
self._status = status
self._rect = wx.Rect()
+ self._text = text
+ self._kind = kind
+ self._toggle = False
+ self._textAlignment = BP_BUTTONTEXT_ALIGN_BOTTOM
+
+ disabledbmp = GrayOut(bmp)
+
+ self._bitmaps = {"Normal": bmp, "Toggled": None, "Disabled": disabledbmp,
+ "Hover": None, "Pressed": None}
+
+ Control.__init__(self, parent)
- def GetBitmap(self):
+ def GetBestSize(self):
+ """ Returns the best size for the button. """
+
+ xsize = self.GetBitmap().GetWidth()
+ ysize = self.GetBitmap().GetHeight()
+
+ if self.HasText():
+ # We have text in the button
+ dc = wx.ClientDC(self._parent)
+ normalFont = self._parent._art.GetFont(BP_BUTTONTEXT_FONT)
+ dc.SetFont(normalFont)
+ tw, th = dc.GetTextExtent(self.GetText())
+
+ if self.GetTextAlignment() == BP_BUTTONTEXT_ALIGN_BOTTOM:
+ xsize = max(xsize, tw)
+ ysize = ysize + th
+ else:
+ xsize = xsize + tw
+ ysize = max(ysize, th)
+
+ border = self._parent._art.GetMetric(BP_BORDER_SIZE)
+ padding = self._parent._art.GetMetric(BP_PADDING_SIZE)
+
+ if self._parent.IsVertical():
+ xsize = xsize + 2*border
+ else:
+ ysize = ysize + 2*border
+
+ self._size = wx.Size(xsize+2*padding.x, ysize+2*padding.y)
+
+ return self._size
+
+
+ def Draw(self, dc, rect):
+ """ Draws the button on ButtonPanel. Actually the drawing is done in BPArt. """
+
+ if not self.IsShown():
+ return
+
+ buttonBitmap = self.GetBitmap()
+ isVertical = self._parent.IsVertical()
+ text = self.GetText()
+ parentSize = self._parent.GetSize()[not isVertical]
+ buttonStatus = self.GetStatus()
+ isToggled = self.GetToggled()
+ textAlignment = self.GetTextAlignment()
+
+ self._parent._art.DrawButton(dc, rect, parentSize, buttonBitmap, isVertical,
+ buttonStatus, isToggled, textAlignment, text)
+
+ self.SetRect(rect)
+
+
+ def CheckRefresh(self, status):
+ """ Checks whether a ButtonPanel repaint is needed or not. Convenience function. """
+
+ if status == self._status:
+ self._parent.Refresh()
+
+
+ def SetBitmap(self, bmp, status="Normal"):
+ """ Sets the associated bitmap. """
+
+ self._bitmaps[status] = bmp
+ self.CheckRefresh(status)
+
+
+ def GetBitmap(self, status=None):
""" Returns the associated bitmap. """
- return self._bmp
+ if status is None:
+ status = self._status
+
+ if not self.IsEnabled():
+ status = "Disabled"
+
+ if self._bitmaps[status] is None:
+ return self._bitmaps["Normal"]
+
+ return self._bitmaps[status]
def GetRect(self):
""" 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. """
+ if status == self._status:
+ return
+
+ if self.GetToggled() and status == "Normal":
+ status = "Toggled"
+
self._status = status
+ self._parent.Refresh()
+
+
+ def GetTextAlignment(self):
+ """ Returns the text alignment in the button (bottom or right). """
+
+ return self._textAlignment
+
+
+ def SetTextAlignment(self, alignment):
+ """ Sets the text alignment in the button (bottom or right). """
+
+ if alignment == self._textAlignment:
+ return
+
+ self._alignment = alignment
+
+
+ def GetToggled(self):
+ """ Returns whether a wx.ITEM_CHECK button is toggled or not. """
+
+ if self._kind == wx.ITEM_NORMAL:
+ return False
+
+ return self._toggle
+
+
+ def SetToggled(self, toggle=True):
+ """ Sets a wx.ITEM_CHECK button toggled/not toggled. """
+
+ if self._kind == wx.ITEM_NORMAL:
+ return
+
+ self._toggle = toggle
def SetId(self, id):
self._id = id
+
+ def AddStatus(self, name="Custom", bmp=wx.NullBitmap):
+ """
+ Add a programmer-defined status in addition to the 5 default status:
+ - Normal;
+ - Disabled;
+ - Hover;
+ - Pressed;
+ - Toggled.
+ """
+
+ self._bitmaps.update({name: bmp})
+
+
+ def Enable(self, enable=True):
+
+ if enable:
+ self._status = "Normal"
+ else:
+ self._status = "Disabled"
+
+
+ def IsEnabled(self):
+
+ return self._status != "Disabled"
+
+
+ def SetText(self, text=""):
+ """ Sets the text of the button. """
+
+ self._text = text
+
+
+ def GetText(self):
+ """ Returns the text associated to the button. """
+
+ return self._text
+
+
+ def HasText(self):
+ """ Returns whether the button has text or not. """
+
+ return self._text != ""
+
+
+ def SetKind(self, kind=wx.ITEM_NORMAL):
+ """ Sets the button type (standard or toggle). """
+
+ self._kind = kind
+
+
+ def GetKind(self):
+ """ Returns the button type (standard or toggle). """
+
+ return self._kind
+
+
Bitmap = property(GetBitmap, SetBitmap)
Id = property(GetId, SetId)
Rect = property(GetRect, SetRect)
Status = property(GetStatus, SetStatus)
-
-
# -- ButtonPanel class implementation ----------------------------------
# This is the main class.
class ButtonPanel(wx.PyPanel):
def __init__(self, parent, id=wx.ID_ANY, text="", style=BP_DEFAULT_STYLE,
- alignment=BP_ALIGN_RIGHT, name="buttonPanel"):
+ alignment=BP_ALIGN_LEFT, name="buttonPanel"):
"""
Default class constructor.
wx.PyPanel.__init__(self, parent, id, wx.DefaultPosition, wx.DefaultSize,
wx.NO_BORDER, name=name)
+
self._vButtons = []
+ self._vSeparators = []
- 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._art = BPArt(style)
+
+ self._controlCreated = False
+
+ direction = (self.IsVertical() and [wx.VERTICAL] or [wx.HORIZONTAL])[0]
+ self._mainsizer = BoxSizer(direction)
+ self.SetSizer(self._mainsizer)
+
+ margins = self._art.GetMetric(BP_MARGINS_SIZE)
+
+ # First spacer to create some room before the first text/button/control
+ self._mainsizer.Add((margins.x, margins.y), 0)
+ # Last spacer to create some room before the last text/button/control
+ self._mainsizer.Add((margins.x, margins.y), 0)
+
+ self.Bind(wx.EVT_SIZE, self.OnSize)
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_LEAVE_WINDOW, self.OnMouseLeave)
self.Bind(wx.EVT_ENTER_WINDOW, self.OnMouseEnterWindow)
+ self.SetBarText(text)
+ self.LayoutItems()
+
+
+ def SetBarText(self, text):
+ """ Sets the main caption text (leave text="" for no text). """
+
+ self.Freeze()
+
+ text = text.strip()
+
+ if self._controlCreated:
+ self.RemoveText()
+
+ self._text = ButtonPanelText(self, text)
+ lenChildren = len(self._mainsizer.GetChildren())
+
+ if text == "":
+ # Even if we have no text, we insert it an empty spacer anyway
+ # it is easier to handle if you have to recreate the sizer after.
+ if self.IsStandard():
+ self._mainsizer.Insert(1, self._text, 0, wx.ALIGN_CENTER,
+ userData=self._text, realIndex=0)
+ else:
+ self._mainsizer.Insert(lenChildren-1, self._text, 0, wx.ALIGN_CENTER,
+ userData=self._text, realIndex=lenChildren)
+
+ return
+
+ # We have text, so insert the text and an expandable spacer
+ # alongside it. "Standard" ButtonPanel are left or top aligned.
+ if self.IsStandard():
+ self._mainsizer.Insert(1, self._text, 0, wx.ALIGN_CENTER,
+ userData=self._text, realIndex=0)
+ self._mainsizer.Insert(2, (0, 0), 1, wx.EXPAND)
+
+ else:
+ self._mainsizer.Insert(lenChildren-1, self._text, 0, wx.ALIGN_CENTER,
+ userData=self._text, realIndex=lenChildren)
+ self._mainsizer.Insert(lenChildren-1, (0, 0), 1, wx.EXPAND)
+
+
+ def RemoveText(self):
+ """ Removes the main caption text. """
+
+ lenChildren = len(self._mainsizer.GetChildren())
+ lenCustom = len(self._vButtons) + len(self._vSeparators) + 1
+
+ if self.IsStandard():
+ # Detach the text
+ self._mainsizer.Remove(1, 0)
+ if self.HasBarText():
+ # Detach the expandable spacer
+ self._mainsizer.Remove(1, -1)
+ else:
+ # Detach the text
+ self._mainsizer.Remove(lenChildren-2, lenCustom-1)
+ if self.HasBarText():
+ # Detach the expandable spacer
+ self._mainsizer.Remove(lenChildren-3, -1)
+
+ def GetBarText(self):
+ """ Returns the main caption text. """
+
+ return self._text.GetText()
+
+
+ def HasBarText(self):
+ """ Returns whether ButtonPanel has a main caption text or not. """
+
+ return hasattr(self, "_text") and self._text.GetText() != ""
+
+
def AddButton(self, btnInfo):
"""
Adds a button to ButtonPanel. Remember to pass a ButtonInfo instance to
this method. See the demo for details.
"""
+ lenChildren = len(self._mainsizer.GetChildren())
+ self._mainsizer.Insert(lenChildren-1, btnInfo, 0, wx.ALIGN_CENTER|wx.EXPAND, userData=btnInfo)
+
self._vButtons.append(btnInfo)
- self.Refresh()
-
+
+
+ def AddSpacer(self, size=(0, 0), proportion=1, flag=wx.EXPAND):
+ """ Adds a spacer (stretchable or fixed-size) to ButtonPanel. """
+
+ lenChildren = len(self._mainsizer.GetChildren())
+ self._mainsizer.Insert(lenChildren-1, size, proportion, flag)
+
+
+ def AddControl(self, control, proportion=0, flag=wx.ALIGN_CENTER|wx.ALL, border=None):
+ """ Adds a wxPython control to ButtonPanel. """
+
+ lenChildren = len(self._mainsizer.GetChildren())
+
+ if border is None:
+ border = self._art.GetMetric(BP_PADDING_SIZE)
+ border = max(border.x, border.y)
+
+ self._mainsizer.Insert(lenChildren-1, control, proportion, flag, border)
+
+
+ def AddSeparator(self):
+ """ Adds a separator line to ButtonPanel. """
+
+ lenChildren = len(self._mainsizer.GetChildren())
+ separator = Separator(self)
+
+ self._mainsizer.Insert(lenChildren-1, separator, 0, wx.EXPAND)
+ self._vSeparators.append(separator)
+
def RemoveAllButtons(self):
""" Remove all the buttons from ButtonPanel. """
self._vButtons = []
- self.Refresh()
+
+ def RemoveAllSeparators(self):
+ """ Remove all the separators from ButtonPanel. """
+ self._vSeparators = []
+
+
def GetAlignment(self):
- """ Returns the button alignment (left, right). """
+ """ Returns the button alignment (left, right, top, bottom). """
return self._alignment
def SetAlignment(self, alignment):
- """ Sets the button alignment (left, right). """
+ """ Sets the button alignment (left, right, top, bottom). """
- self._alignment = alignment
+ if alignment == self._alignment:
+ return
+ self.Freeze()
+
+ text = self.GetBarText()
+
+ # Remove the text in any case
+ self.RemoveText()
- 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)
+ # Remove the first and last spacers
+ self._mainsizer.Remove(0, -1)
+ self._mainsizer.Remove(len(self._mainsizer.GetChildren())-1, -1)
+
+ self._alignment = alignment
- bw = (len(self._vButtons)+1) * (bw + 2*self._nPadding)
- w += bw
-
- return (w, h)
+ # Recreate the sizer accordingly to the new alignment
+ self.ReCreateSizer(text)
+ def IsVertical(self):
+ """ Returns whether ButtonPanel is vertically aligned or not. """
- def OnPaint(self, event):
- """ Handles the wx.EVT_PAINT event for ButtonPanel. """
+ return self._alignment not in [BP_ALIGN_RIGHT, BP_ALIGN_LEFT]
- dc = wx.BufferedPaintDC(self)
- rect = self.GetClientRect()
- ##print rect, self.GetRect(), self.GetBestSize(), self.GetMinSize()
+ def IsStandard(self):
+ """ Returns whether ButtonPanel is aligned "Standard" (left/top) or not. """
+
+ return self._alignment in [BP_ALIGN_LEFT, BP_ALIGN_TOP]
+
+
+ def DoLayout(self):
+ """
+ Do the Layout for ButtonPanel.
+ NB: Call this method every time you make a modification to the layout
+ or to the customizable sizes of the pseudo controls.
+ """
+
+ margins = self._art.GetMetric(BP_MARGINS_SIZE)
+ lenChildren = len(self._mainsizer.GetChildren())
+
+ self._mainsizer.SetItemMinSize(0, (margins.x, margins.y))
+ self._mainsizer.SetItemMinSize(lenChildren-1, (margins.x, margins.y))
+
+ self._controlCreated = True
+ self.LayoutItems()
+
+ # *VERY* WEIRD: the sizer seems not to respond to any layout until I
+ # change the ButtonPanel size and restore it back
+ size = self.GetSize()
+ self.SetSize((size.x+1, size.y+1))
+ self.SetSize((size.x, size.y))
+
+ if self.IsFrozen():
+ self.Thaw()
- # 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)
+ def ReCreateSizer(self, text):
+ """ Recreates the ButtonPanel sizer accordingly to the alignment specified. """
+
+ children = self._mainsizer.GetChildren()
+ self.RemoveAllButtons()
+ self.RemoveAllSeparators()
- # Draw a rectangle around the panel
- dc.SetBrush(backBrush)
- dc.SetPen(borderPen)
- dc.DrawRectangleRect(rect)
+ # Create a new sizer depending on the alignment chosen
+ direction = (self.IsVertical() and [wx.VERTICAL] or [wx.HORIZONTAL])[0]
+ self._mainsizer = BoxSizer(direction)
- # Draw the text
- textWidth, textHeight = 0, 0
+ margins = self._art.GetMetric(BP_MARGINS_SIZE)
+ # First spacer to create some room before the first text/button/control
+ self._mainsizer.Add((margins.x, margins.y), 0)
+
+ # Last spacer to create some room before the last text/button/control
+ self._mainsizer.Add((margins.x, margins.y), 0)
+
+ # This is needed otherwise SetBarText goes mad
+ self._controlCreated = False
+
+ for child in children:
+ userData = child.GetUserData()
+ if userData:
+ if isinstance(userData, ButtonInfo):
+ # It is a ButtonInfo, can't be anything else
+ self.AddButton(child.GetUserData())
+ elif isinstance(userData, Separator):
+ self.AddSeparator()
+
+ else:
+ if child.IsSpacer():
+ # This is a spacer, expandable or not
+ self.AddSpacer(child.GetSize(), child.GetProportion(),
+ child.GetFlag())
+ else:
+ # This is a wxPython control
+ self.AddControl(child.GetWindow(), child.GetProportion(),
+ child.GetFlag(), child.GetBorder())
+
+ self.SetSizer(self._mainsizer)
+
+ # Now add the text. It doesn't matter if there is no text
+ self.SetBarText(text)
+
+ self.DoLayout()
+
+ self.Thaw()
- 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
+ def DoGetBestSize(self):
+ """ Returns the best size of ButtonPanel. """
+
+ w = h = btnWidth = btnHeight = 0
+ isVertical = self.IsVertical()
+
+ padding = self._art.GetMetric(BP_PADDING_SIZE)
+ border = self._art.GetMetric(BP_BORDER_SIZE)
+ margins = self._art.GetMetric(BP_MARGINS_SIZE)
+ separator_size = self._art.GetMetric(BP_SEPARATOR_SIZE)
+
+ # Add the space required for the main caption
+ if self.HasBarText():
+ w, h = self._text.GetBestSize()
+ if isVertical:
+ h += padding.y
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
+ w += padding.x
+ else:
+ w = h = border
- 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 ]
+ # Add the button's sizes
+ for btn in self._vButtons:
- totalWidth = rect.width - self._nPadding*2 - textWidth
+ bw, bh = btn.GetBestSize()
+ btnWidth = max(btnWidth, bw)
+ btnHeight = max(btnHeight, bh)
- # 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 isVertical:
+ w = max(w, btnWidth)
+ h += bh
+ else:
+ h = max(h, btnHeight)
+ w += bw
+
+ # Add the control's sizes
+ for control in self.GetControls():
+ cw, ch = control.GetSize()
+ if isVertical:
+ h += ch
+ w = max(w, cw)
+ else:
+ w += cw
+ h = max(h, ch)
- if self._alignment == BP_ALIGN_RIGHT:
+ # Add the separator's sizes and the 2 SizerItems at the beginning
+ # and at the end
+ if self.IsVertical():
+ h += 2*margins.y + len(self._vSeparators)*separator_size
+ else:
+ w += 2*margins.x + len(self._vSeparators)*separator_size
- 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
+ return wx.Size(w, h)
- 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 OnPaint(self, event):
+ """ Handles the wx.EVT_PAINT event for ButtonPanel. """
+
+ dc = wx.BufferedPaintDC(self)
+ rect = self.GetClientRect()
+ self._art.DrawButtonPanel(dc, rect, self._nStyle)
+ self._mainsizer.Draw(dc)
+
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()
+
+ # NOTE: It seems like LayoutItems number of calls can be optimized in some way.
+ # Currently every DoLayout (or every parent Layout()) calls about 3 times
+ # the LayoutItems method. Any idea on how to improve it?
+ self.LayoutItems()
+ self.Refresh()
+
event.Skip()
-
- def SetColor(self, switch, color):
+
+ def LayoutItems(self):
+ """
+ Layout the items using a different algorithm depending on the existance
+ of the main caption.
"""
- 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
+ nonspacers, allchildren = self.GetNonFlexibleChildren()
+
+ if self.HasBarText():
+ self.FlexibleLayout(nonspacers, allchildren)
+ else:
+ self.SizeLayout(nonspacers, allchildren)
+
+ self._mainsizer.Layout()
- size = rect.height
- # calculate gradient coefficients
- style = self.GetParent().GetWindowStyleFlag()
- col2 = self._colorFrom
- col1 = self._colorTo
+ def SizeLayout(self, nonspacers, children):
+ """ Layout the items when no main caption exists. """
- 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)
+ size = self.GetSize()
+ isVertical = self.IsVertical()
+
+ corner = 0
+ indx1 = len(nonspacers)
+
+ for item in nonspacers:
+ corner += self.GetItemSize(item, isVertical)
+ if corner > size[isVertical]:
+ indx1 = nonspacers.index(item)
+ break
+
+ # Leave out the last spacer, it has to be there always
+ for ii in xrange(len(nonspacers)-1):
+ indx = children.index(nonspacers[ii])
+ self._mainsizer.Show(indx, ii < indx1)
+
- 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 GetItemSize(self, item, isVertical):
+ """ Returns the size of an item in the main ButtonPanel sizer. """
+
+ if item.GetUserData():
+ return item.GetUserData().GetBestSize()[isVertical]
+ else:
+ return item.GetSize()[isVertical]
-
+
+ def FlexibleLayout(self, nonspacers, allchildren):
+ """ Layout the items when the main caption exists. """
+
+ if len(nonspacers) < 2:
+ return
+
+ isVertical = self.IsVertical()
+ isStandard = self.IsStandard()
+
+ size = self.GetSize()[isVertical]
+ padding = self._art.GetMetric(BP_PADDING_SIZE)
+
+ fixed = (isStandard and [nonspacers[1]] or [nonspacers[-2]])[0]
+
+ if isStandard:
+ nonspacers.reverse()
+ leftendx = fixed.GetSize()[isVertical] + padding.x
+ else:
+ rightstartx = size - fixed.GetSize()[isVertical]
+ size = 0
+
+ count = lennonspacers = len(nonspacers)
+
+ for item in nonspacers:
+ if isStandard:
+ size -= self.GetItemSize(item, isVertical)
+ if size < leftendx:
+ break
+ else:
+ size += self.GetItemSize(item, isVertical)
+ if size > rightstartx:
+ break
+
+ count = count - 1
+
+ nonspacers.reverse()
+
+ for jj in xrange(2, lennonspacers):
+ indx = allchildren.index(nonspacers[jj])
+ self._mainsizer.Show(indx, jj >= count)
+
+
+ def GetNonFlexibleChildren(self):
+ """
+ Returns all the ButtonPanel main sizer's children that are not
+ flexible spacers.
+ """
+
+ children1 = []
+ children2 = self._mainsizer.GetChildren()
+
+ for child in children2:
+ if child.IsSpacer():
+ if child.GetUserData() or child.GetProportion() == 0:
+ children1.append(child)
+ else:
+ children1.append(child)
+
+ return children1, children2
+
+
+ def GetControls(self):
+ """ Returns the wxPython controls that belongs to ButtonPanel. """
+
+ children2 = self._mainsizer.GetChildren()
+ children1 = [child for child in children2 if not child.IsSpacer()]
+
+ return children1
+
+
+ def SetStyle(self, style):
+ """ Sets ButtonPanel style. """
+
+ if style == self._nStyle:
+ return
+
+ self._nStyle = style
+ self.Refresh()
+
+
+ def GetStyle(self):
+ """ Returns the ButtonPanel style. """
+
+ return self._nStyle
+
+
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)
+ for btn in self._vButtons:
+
+ if not btn.IsEnabled():
+ continue
+
+ if btn.GetRect().Contains(event.GetPosition()):
+ btn.SetStatus("Hover")
else:
- self._vButtons[ii].SetStatus(BP_BTN_NONE)
+ btn.SetStatus("Normal")
self.Refresh()
event.Skip()
tabId, hit = self.HitTest(event.GetPosition())
- if hit == BP_HT_BUTTON:
-
- self._vButtons[tabId].SetStatus(BP_BTN_PRESSED)
+ if hit == BP_HT_BUTTON and self._vButtons[tabId].IsEnabled():
+
+ self._vButtons[tabId].SetStatus("Pressed")
self.Refresh()
def OnLeftUp(self, event):
""" Handles the wx.EVT_LEFT_UP event for ButtonPanel. """
- tabId, hit = self.HitTest(event.GetPosition())
+ tabId, flags = self.HitTest(event.GetPosition())
+ hit = self._vButtons[tabId]
- if hit == BP_HT_BUTTON:
- if self._vButtons[tabId].GetStatus() == BP_BTN_PRESSED:
+ if flags == BP_HT_BUTTON:
+
+ if hit.GetStatus() == "Disabled":
+ return
+
+ for btn in self._vButtons:
+ if btn != hit:
+ btn.SetFocus(False)
+
+ if hit.GetStatus() == "Pressed":
# Fire a button click event
- btnEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, self._vButtons[tabId].GetId())
+ btnEvent = wx.CommandEvent(wx.wxEVT_COMMAND_BUTTON_CLICKED, hit.GetId())
self.GetEventHandler().ProcessEvent(btnEvent)
+ hit.SetToggled(not hit.GetToggled())
+
# Update the button status to be hovered
- self._vButtons[tabId].SetStatus(BP_BTN_HOVER)
+ hit.SetStatus("Hover")
+ hit.SetFocus()
+
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)
+ # Reset all buttons statuses
+ for btn in self._vButtons:
+ if not btn.IsEnabled():
+ continue
+ btn.SetStatus("Normal")
self.Refresh()
event.Skip()
btnIdx = -1
for ii in xrange(len(self._vButtons)):
- if self._vButtons[ii].GetRect().Inside(pt):
+ if not self._vButtons[ii].IsEnabled():
+ continue
+ if self._vButtons[ii].GetRect().Contains(pt):
return ii, BP_HT_BUTTON
return -1, BP_HT_NONE
+ def GetBPArt(self):
+ """ Returns the associated BPArt art provider. """
+ return self._art
+