-import sys\r
-import time\r
-import math\r
-import os.path\r
-import pdb\r
-\r
-import wx\r
-import wx.propgrid as wxpg\r
-import wx.stc\r
-\r
-\r
-class Display:\r
- property_descriptor = []\r
- def __init__(self):\r
- pass\r
-\r
-\r
-class ValueObject:\r
- def __init__(self):\r
- pass\r
-\r
-\r
-class IntProperty2(wxpg.PyProperty):\r
- """\\r
- This is a simple re-implementation of wxIntProperty.\r
- """\r
- def __init__(self, label, name = wxpg.LABEL_AS_NAME, value=0):\r
- wxpg.PyProperty.__init__(self, label, name)\r
- self.SetValue(value)\r
-\r
- def GetClassName(self):\r
- """\\r
- This is not 100% necessary and in future is probably going to be\r
- automated to return class name.\r
- """\r
- return "IntProperty2"\r
-\r
- def GetEditor(self):\r
- return "TextCtrl"\r
-\r
- def GetValueAsString(self, flags):\r
- return str(self.GetValue())\r
-\r
- def PyStringToValue(self, s, flags):\r
- try:\r
- v = int(s)\r
- if self.GetValue() != v:\r
- return v\r
- except TypeError:\r
- if flags & wxpg.PG_REPORT_ERROR:\r
- wx.MessageBox("Cannot convert '%s' into a number."%s, "Error")\r
- return False\r
-\r
- def PyIntToValue(self, v, flags):\r
- if (self.GetValue() != v):\r
- return v\r
-\r
-\r
-class PyFilesProperty(wxpg.PyArrayStringProperty):\r
- def __init__(self, label, name = wxpg.LABEL_AS_NAME, value=[]):\r
- wxpg.PyArrayStringProperty.__init__(self, label, name, value)\r
- self.SetValue(value)\r
-\r
- def OnSetValue(self, v):\r
- self.value = v\r
- self.display = ', '.join(self.value)\r
-\r
- def GetValueAsString(self, argFlags):\r
- return self.display\r
-\r
- def PyStringToValue(self, s, flags):\r
- return [a.strip() for a in text.split(',')]\r
-\r
- def OnEvent(self, propgrid, ctrl, event):\r
- if event.GetEventType() == wx.wxEVT_COMMAND_BUTTON_CLICKED:\r
- # Show dialog to select a string, call DoSetValue and\r
- # return True, if value changed.\r
- return True\r
-\r
- return False\r
-\r
-\r
-class PyObjectPropertyValue:\r
- """\\r
- Value type of our sample PyObjectProperty. We keep a simple dash-delimited\r
- list of string given as argument to constructor.\r
- """\r
- def __init__(self, s=None):\r
- try:\r
- self.ls = [a.strip() for a in s.split('-')]\r
- except:\r
- self.ls = []\r
-\r
- def __repr__(self):\r
- return ' - '.join(self.ls)\r
-\r
-\r
-\r
-class PyObjectProperty(wxpg.PyProperty):\r
- """\\r
- Another simple example. This time our value is a PyObject (NOTE: we can't\r
- return an arbitrary python object in DoGetValue. It cannot be a simple\r
- type such as int, bool, double, or string, nor an array or wxObject based.\r
- Dictionary, None, or any user-specified Python object is allowed).\r
- """\r
- def __init__(self, label, name = wxpg.LABEL_AS_NAME, value=None):\r
- wxpg.PyProperty.__init__(self, label, name)\r
- self.SetValue(value)\r
-\r
- def GetClassName(self):\r
- return self.__class__.__name__\r
-\r
- def GetEditor(self):\r
- return "TextCtrl"\r
-\r
- def GetValueAsString(self, flags):\r
- return repr(self.GetValue())\r
-\r
- def PyStringToValue(self, s, flags):\r
- return PyObjectPropertyValue(s)\r
-\r
-\r
-class ShapeProperty(wxpg.PyEnumProperty):\r
- """\\r
- Demonstrates use of OnCustomPaint method.\r
- """\r
- def __init__(self, label, name = wxpg.LABEL_AS_NAME, value=-1):\r
- wxpg.PyEnumProperty.__init__(self, label, name, ['Line','Circle','Rectangle'], [0,1,2], value)\r
-\r
- def OnMeasureImage(self, index):\r
- return wxpg.DEFAULT_IMAGE_SIZE\r
-\r
- def OnCustomPaint(self, dc, rect, paint_data):\r
- """\\r
- paint_data.m_choiceItem is -1 if we are painting the control,\r
- in which case we need to get the drawn item using DoGetValue.\r
- """\r
- item = paint_data.m_choiceItem\r
- if item == -1:\r
- item = self.DoGetValue()\r
-\r
- dc.SetPen(wx.Pen(wx.BLACK))\r
- dc.SetBrush(wx.Brush(wx.BLACK))\r
-\r
- if item == 0:\r
- dc.DrawLine(rect.x,rect.y,rect.x+rect.width,rect.y+rect.height)\r
- elif item == 1:\r
- half_width = rect.width / 2\r
- dc.DrawCircle(rect.x+half_width,rect.y+half_width,half_width-3)\r
- elif item == 2:\r
- dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)\r
-\r
-\r
-class LargeImagePickerCtrl(wx.Window):\r
- """\\r
- Control created and used by LargeImageEditor.\r
- """\r
- def __init__(self):\r
- pre = wx.PreWindow()\r
- self.PostCreate(pre)\r
-\r
- def Create(self, parent, id_, pos, size, style = 0):\r
- wx.Window.Create(self, parent, id_, pos, size, style | wx.BORDER_SIMPLE)\r
- img_spc = size[1]\r
- self.tc = wx.TextCtrl(self, -1, "", (img_spc,0), (2048,size[1]), wx.BORDER_NONE)\r
- self.SetBackgroundColour(wx.WHITE)\r
- self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)\r
- self.property = None\r
- self.bmp = None\r
- self.Bind(wx.EVT_PAINT, self.OnPaint)\r
-\r
- def OnPaint(self, event):\r
- dc = wx.BufferedPaintDC(self)\r
-\r
- whiteBrush = wx.Brush(wx.WHITE)\r
- dc.SetBackground(whiteBrush)\r
- dc.Clear()\r
-\r
- bmp = self.bmp\r
- if bmp:\r
- dc.DrawBitmap(bmp, 2, 2)\r
- else:\r
- dc.SetPen(wx.Pen(wx.BLACK))\r
- dc.SetBrush(whiteBrush)\r
- dc.DrawRectangle(2, 2, 64, 64)\r
-\r
- def RefreshThumbnail(self):\r
- """\\r
- We use here very simple image scaling code.\r
- """\r
- if not self.property:\r
- self.bmp = None\r
- return\r
-\r
- path = self.property.DoGetValue()\r
-\r
- if not os.path.isfile(path):\r
- self.bmp = None\r
- return\r
-\r
- image = wx.Image(path)\r
- image.Rescale(64, 64)\r
- self.bmp = wx.BitmapFromImage(image)\r
-\r
- def SetProperty(self, property):\r
- self.property = property\r
- self.tc.SetValue(property.GetDisplayedString())\r
- self.RefreshThumbnail()\r
-\r
- def SetValue(self, s):\r
- self.RefreshThumbnail()\r
- self.tc.SetValue(s)\r
-\r
- def GetLastPosition(self):\r
- return self.tc.GetLastPosition()\r
-\r
-\r
-class LargeImageEditor(wxpg.PyEditor):\r
- """\\r
- Double-height text-editor with image in front.\r
- """\r
- def __init__(self):\r
- wxpg.PyEditor.__init__(self)\r
-\r
- def CreateControls(self, propgrid, property, pos, sz):\r
- try:\r
- h = 64 + 6\r
- x = propgrid.GetSplitterPosition()\r
- x2 = propgrid.GetClientSize().x\r
- bw = propgrid.GetRowHeight()\r
- lipc = LargeImagePickerCtrl()\r
- if sys.platform == 'win32':\r
- lipc.Hide()\r
- lipc.Create(propgrid, wxpg.PG_SUBID1, (x,pos[1]), (x2-x-bw,h))\r
- lipc.SetProperty(property)\r
- # Hmmm.. how to have two-stage creation without subclassing?\r
- #btn = wx.PreButton()\r
- #pre = wx.PreWindow()\r
- #self.PostCreate(pre)\r
- #if sys.platform == 'win32':\r
- # btn.Hide()\r
- #btn.Create(propgrid, wxpg.PG_SUBID2, '...', (x2-bw,pos[1]), (bw,h), wx.WANTS_CHARS)\r
- btn = wx.Button(propgrid, wxpg.PG_SUBID2, '...', (x2-bw,pos[1]), (bw,h), wx.WANTS_CHARS)\r
- return (lipc, btn)\r
- except:\r
- import traceback\r
- print traceback.print_exc()\r
-\r
- def UpdateControl(self, property, ctrl):\r
- ctrl.SetValue(property.GetDisplayedString())\r
-\r
- def DrawValue(self, dc, property, rect):\r
- if not (property.GetFlags() & wxpg.PG_PROP_UNSPECIFIED):\r
- dc.DrawText( property.GetDisplayedString(), rect.x+5, rect.y );\r
-\r
- def OnEvent(self, propgrid, ctrl, event):\r
- if not ctrl:\r
- return False\r
-\r
- evtType = event.GetEventType()\r
-\r
- if evtType == wx.wxEVT_COMMAND_TEXT_ENTER:\r
- if propgrid.IsEditorsValueModified():\r
- return True\r
-\r
- elif evtType == wx.wxEVT_COMMAND_TEXT_UPDATED:\r
- if not property.HasFlag(wxpg.PG_PROP_UNSPECIFIED) or not ctrl or \\r
- ctrl.GetLastPosition() > 0:\r
-\r
- # We must check this since an 'empty' text event\r
- # may be triggered when creating the property.\r
- PG_FL_IN_SELECT_PROPERTY = 0x00100000\r
- if not (propgrid.GetInternalFlags() & PG_FL_IN_SELECT_PROPERTY):\r
- event.Skip();\r
- event.SetId(propGrid.GetId());\r
-\r
- propgrid.EditorsValueWasModified();\r
-\r
- return False\r
-\r
-\r
- def CopyValueFromControl(self, property, ctrl):\r
- tc = ctrl.tc\r
- res = property.SetValueFromString(tc.GetValue(),0)\r
- # Changing unspecified always causes event (returning\r
- # true here should be enough to trigger it).\r
- if not res and property.IsFlagSet(wxpg.PG_PROP_UNSPECIFIED):\r
- res = true\r
-\r
- return res\r
-\r
- def SetValueToUnspecified(self, ctrl):\r
- ctrl.tc.Remove(0,len(ctrl.tc.GetValue()));\r
-\r
- def SetControlStringValue(self, ctrl, txt):\r
- ctrl.SetValue(txt)\r
-\r
- def OnFocus(self, property, ctrl):\r
- ctrl.tc.SetSelection(-1,-1)\r
- ctrl.tc.SetFocus()\r
-\r
-\r
-class PropertyEditor(wx.Panel):\r
-\r
- def __init__(self, parent):\r
- # Use the WANTS_CHARS style so the panel doesn't eat the Return key.\r
- wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS, size=(160, 200))\r
-\r
- sizer = wx.BoxSizer(wx.VERTICAL)\r
-\r
- self.pg = wxpg.PropertyGrid(self, style=wxpg.PG_SPLITTER_AUTO_CENTER|wxpg.PG_AUTO_SORT)\r
-\r
- # Show help as tooltips\r
- self.pg.SetExtraStyle(wxpg.PG_EX_HELP_AS_TOOLTIPS)\r
-\r
- #pg.Bind(wxpg.EVT_PG_CHANGED, self.OnPropGridChange)\r
- #pg.Bind(wxpg.EVT_PG_SELECTED, self.OnPropGridSelect)\r
- #self.pg.Bind(wxpg.EVT_PG_RIGHT_CLICK, self.OnPropGridRightClick)\r
-\r
- # Needed by custom image editor\r
- wx.InitAllImageHandlers()\r
-\r
- #\r
- # Let's create a simple custom editor\r
- #\r
- # NOTE: Editor must be registered *before* adding a property that uses it.\r
- self.pg.RegisterEditor(LargeImageEditor)\r
-\r
- '''\r
- #\r
- # Add properties\r
- #\r
-\r
- pg.Append( wxpg.PropertyCategory("1 - Basic Properties") )\r
- pg.Append( wxpg.StringProperty("String",value="Some Text") )\r
- pg.Append( wxpg.IntProperty("Int",value=100) )\r
- pg.Append( wxpg.FloatProperty("Float",value=100.0) )\r
- pg.Append( wxpg.BoolProperty("Bool",value=True) )\r
- pg.Append( wxpg.BoolProperty("Bool_with_Checkbox",value=True) )\r
- pg.SetPropertyAttribute("Bool_with_Checkbox", "UseCheckbox", True)\r
-\r
- pg.Append( wxpg.PropertyCategory("2 - More Properties") )\r
- pg.Append( wxpg.LongStringProperty("LongString",value="This is a\\nmulti-line string\\nwith\\ttabs\\nmixed\\tin.") )\r
- pg.Append( wxpg.DirProperty("Dir",value="C:\\Windows") )\r
- pg.Append( wxpg.FileProperty("File",value="C:\\Windows\\system.ini") )\r
- pg.Append( wxpg.ArrayStringProperty("ArrayString",value=['A','B','C']) )\r
-\r
- pg.Append( wxpg.EnumProperty("Enum","Enum",\r
- ['wxPython Rules','wxPython Rocks','wxPython Is The Best'],\r
- [10,11,12],0) )\r
- pg.Append( wxpg.EditEnumProperty("EditEnum","EditEnumProperty",['A','B','C'],[0,1,2],"Text Not in List") )\r
-\r
- pg.Append( wxpg.PropertyCategory("3 - Advanced Properties") )\r
- pg.Append( wxpg.DateProperty("Date",value=wx.DateTime_Now()) )\r
- pg.Append( wxpg.FontProperty("Font",value=self.GetFont()) )\r
- pg.Append( wxpg.ColourProperty("Colour",value=self.GetBackgroundColour()) )\r
- pg.Append( wxpg.SystemColourProperty("SystemColour") )\r
- pg.Append( wxpg.ImageFileProperty("ImageFile") )\r
- pg.Append( wxpg.MultiChoiceProperty("MultiChoice",choices=['wxWidgets','QT','GTK+']) )\r
-\r
- pg.Append( wxpg.PropertyCategory("4 - Additional Properties") )\r
- pg.Append( wxpg.PointProperty("Point",value=self.GetPosition()) )\r
- pg.Append( wxpg.SizeProperty("Size",value=self.GetSize()) )\r
- pg.Append( wxpg.FontDataProperty("FontData") )\r
- pg.Append( wxpg.IntProperty("IntWithSpin",value=256) )\r
- pg.SetPropertyEditor("IntWithSpin","SpinCtrl")\r
- pg.Append( wxpg.DirsProperty("Dirs",value=['C:/Lib','C:/Bin']) )\r
- pg.SetPropertyHelpString( "String", "String Property help string!" )\r
- pg.SetPropertyHelpString( "Dirs", "Dirs Property help string!" )\r
-\r
- pg.SetPropertyAttribute( "File", wxpg.PG_FILE_SHOW_FULL_PATH, 0 )\r
- pg.SetPropertyAttribute( "File", wxpg.PG_FILE_INITIAL_PATH, "C:\\Program Files\\Internet Explorer" )\r
- pg.SetPropertyAttribute( "Date", wxpg.PG_DATE_PICKER_STYLE, wx.DP_DROPDOWN|wx.DP_SHOWCENTURY )\r
-\r
- pg.Append( wxpg.PropertyCategory("5 - Custom Properties") )\r
- pg.Append( IntProperty2("IntProperty2", value=1024) )\r
-\r
- pg.Append( ShapeProperty("ShapeProperty", value=0) )\r
- pg.Append( PyObjectProperty("PyObjectProperty") )\r
-\r
- pg.Append( wxpg.ImageFileProperty("ImageFileWithLargeEditor") )\r
- pg.SetPropertyEditor("ImageFileWithLargeEditor", "LargeImageEditor")\r
-\r
-\r
- pg.SetPropertyClientData( "Point", 1234 )\r
- if pg.GetPropertyClientData( "Point" ) != 1234:\r
- raise ValueError("Set/GetPropertyClientData() failed")\r
-\r
- # Test setting unicode string\r
- pg.GetPropertyByName("String").SetValue(u"Some Unicode Text")\r
-\r
- #\r
- # Test some code that *should* fail (but not crash)\r
- #try:\r
- #a_ = pg.GetPropertyValue( "NotARealProperty" )\r
- #pg.EnableProperty( "NotAtAllRealProperty", False )\r
- #pg.SetPropertyHelpString( "AgaintNotARealProperty", "Dummy Help String" )\r
- #except:\r
- #pass\r
- #raise\r
-\r
- '''\r
- sizer.Add(self.pg, 1, wx.EXPAND)\r
- self.SetSizer(sizer)\r
- sizer.SetSizeHints(self)\r
-\r
- self.SelectedTreeItem = None\r
-\r
- def GetPropertyValues(self):\r
- #return self.pg.GetPropertyValues(as_strings=True)\r
- return self.pg.GetPropertyValues()\r
-\r
-\r
- def Initialize(self, properties):\r
- pg = self.pg\r
- pg.Clear()\r
-\r
- if properties:\r
- for element in properties:\r
- if element[1]['type'] == 'integer':\r
- if 'value' in element[1]:\r
- property_value = element[1].as_int('value')\r
- else:\r
- property_value = element[1].as_int('default')\r
- property_control = wxpg.IntProperty(element[0], value=property_value)\r
- if 'maximum' in element[1]:\r
- property_control.SetAttribute('Max', element[1].as_int('maximum'))\r
- if 'minimum' in element[1]:\r
- property_control.SetAttribute('Min', element[1].as_int('minimum'))\r
- property_control.SetAttribute('Wrap', True)\r
- pg.Append(property_control)\r
- pg.SetPropertyEditor(element[0], 'SpinCtrl')\r
-\r
- if element[1]['type'] == 'float':\r
- if 'value' in element[1]:\r
- property_value = element[1].as_float('value')\r
- else:\r
- property_value = element[1].as_float('default')\r
- property_control = wxpg.FloatProperty(element[0], value=property_value)\r
- if 'maximum' in element[1]:\r
- property_control.SetAttribute('Max', element[1].as_float('maximum'))\r
- if 'minimum' in element[1]:\r
- property_control.SetAttribute('Min', element[1].as_float('minimum'))\r
- property_control.SetAttribute('Wrap', True)\r
- pg.Append(property_control)\r
- pg.SetPropertyEditor(element[0], 'SpinCtrl')\r
-\r
- if element[1]['type'] == 'boolean':\r
- if 'value' in element[1]:\r
- property_value = element[1].as_bool('value')\r
- else:\r
- property_value = element[1].as_bool('default')\r
- property_control = wxpg.BoolProperty(element[0], value=property_value)\r
- pg.Append(property_control)\r
- pg.SetPropertyAttribute(element[0], 'UseCheckbox', True)\r
- if element[1]['type'] == 'string':\r
- if 'value' in element[1]:\r
- property_value = element[1]['value']\r
- else:\r
- property_value = element[1]['default']\r
- pg.Append(wxpg.StringProperty(element[0], value=property_value))\r
- if element[1]['type'] == 'folder':\r
- if 'value' in element[1]:\r
- property_value = element[1]['value']\r
- else:\r
- property_value = element[1]['default']\r
- pg.Append(wxpg.DirProperty(element[0], value=property_value))\r
- if element[1]['type'] == 'filename':\r
- if 'value' in element[1]:\r
- property_value = element[1]['value']\r
- else:\r
- property_value = element[1]['default']\r
- pg.Append(wxpg.FileProperty(element[0], value=property_value))\r
- #if element[0] == 'category':\r
- #pg.Append(wxpg.PropertyCategory(element[1]))\r
- #if element[0] == 'folder':\r
- #pg.Append(wxpg.DirProperty(element[1], value=element[2]))\r
- #if element[0] == 'string':\r
- #pg.Append(wxpg.StringProperty(element[1], value=element[2]))\r
-\r
- pg.Refresh()\r
-\r
- def OnReserved(self, event):\r
- pass\r
-\r
-\r
-#---------------------------------------------------------------------------\r
-\r
-\r
-class MemoDialog(wx.Dialog):\r
- """\\r
- Dialog for multi-line text editing.\r
- """\r
- def __init__(self, parent=None, title='', text='', pos=None, size=(500,500)):\r
- wx.Dialog.__init__(self, parent, -1, title, style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)\r
-\r
- sizer = wx.BoxSizer(wx.VERTICAL)\r
-\r
- tc = wx.TextCtrl(self, 11, text, style=wx.TE_MULTILINE)\r
- self.tc = tc\r
- topsizer.Add(tc,1,wx.EXPAND|wx.ALL,8)\r
-\r
- rowsizer = wx.BoxSizer( wx.HORIZONTAL )\r
- rowsizer.Add(wx.Button(self,wx.ID_OK,'Ok'),0,wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL,8)\r
- rowsizer.Add((0,0),1,wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL,8)\r
- rowsizer.Add(wx.Button(self,wx.ID_CANCEL,'Cancel'),0,wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL,8)\r
- topsizer.Add(rowsizer,0,wx.EXPAND|wx.ALL,8)\r
-\r
- self.SetSizer( topsizer )\r
- topsizer.Layout()\r
-\r
- self.SetSize( size )\r
- if not pos:\r
- self.CenterOnScreen()\r
- else:\r
- self.Move(pos)\r
-\r
-\r
-#---------------------------------------------------------------------------\r
+# Copyright
+
+import sys
+import time
+import math
+import os.path
+import pdb
+
+import wx
+import wx.propgrid as wxpg
+import wx.stc
+
+
+class Display:
+ property_descriptor = []
+ def __init__(self):
+ pass
+
+
+class ValueObject:
+ def __init__(self):
+ pass
+
+
+class IntProperty2(wxpg.PyProperty):
+ """\
+ This is a simple re-implementation of wxIntProperty.
+ """
+ def __init__(self, label, name = wxpg.LABEL_AS_NAME, value=0):
+ wxpg.PyProperty.__init__(self, label, name)
+ self.SetValue(value)
+
+ def GetClassName(self):
+ """\
+ This is not 100% necessary and in future is probably going to be
+ automated to return class name.
+ """
+ return "IntProperty2"
+
+ def GetEditor(self):
+ return "TextCtrl"
+
+ def GetValueAsString(self, flags):
+ return str(self.GetValue())
+
+ def PyStringToValue(self, s, flags):
+ try:
+ v = int(s)
+ if self.GetValue() != v:
+ return v
+ except TypeError:
+ if flags & wxpg.PG_REPORT_ERROR:
+ wx.MessageBox("Cannot convert '%s' into a number."%s, "Error")
+ return False
+
+ def PyIntToValue(self, v, flags):
+ if (self.GetValue() != v):
+ return v
+
+
+class PyFilesProperty(wxpg.PyArrayStringProperty):
+ def __init__(self, label, name = wxpg.LABEL_AS_NAME, value=[]):
+ wxpg.PyArrayStringProperty.__init__(self, label, name, value)
+ self.SetValue(value)
+
+ def OnSetValue(self, v):
+ self.value = v
+ self.display = ', '.join(self.value)
+
+ def GetValueAsString(self, argFlags):
+ return self.display
+
+ def PyStringToValue(self, s, flags):
+ return [a.strip() for a in text.split(',')]
+
+ def OnEvent(self, propgrid, ctrl, event):
+ if event.GetEventType() == wx.wxEVT_COMMAND_BUTTON_CLICKED:
+ # Show dialog to select a string, call DoSetValue and
+ # return True, if value changed.
+ return True
+
+ return False
+
+
+class PyObjectPropertyValue:
+ """\
+ Value type of our sample PyObjectProperty. We keep a simple dash-delimited
+ list of string given as argument to constructor.
+ """
+ def __init__(self, s=None):
+ try:
+ self.ls = [a.strip() for a in s.split('-')]
+ except:
+ self.ls = []
+
+ def __repr__(self):
+ return ' - '.join(self.ls)
+
+
+
+class PyObjectProperty(wxpg.PyProperty):
+ """\
+ Another simple example. This time our value is a PyObject (NOTE: we can't
+ return an arbitrary python object in DoGetValue. It cannot be a simple
+ type such as int, bool, double, or string, nor an array or wxObject based.
+ Dictionary, None, or any user-specified Python object is allowed).
+ """
+ def __init__(self, label, name = wxpg.LABEL_AS_NAME, value=None):
+ wxpg.PyProperty.__init__(self, label, name)
+ self.SetValue(value)
+
+ def GetClassName(self):
+ return self.__class__.__name__
+
+ def GetEditor(self):
+ return "TextCtrl"
+
+ def GetValueAsString(self, flags):
+ return repr(self.GetValue())
+
+ def PyStringToValue(self, s, flags):
+ return PyObjectPropertyValue(s)
+
+
+class ShapeProperty(wxpg.PyEnumProperty):
+ """\
+ Demonstrates use of OnCustomPaint method.
+ """
+ def __init__(self, label, name = wxpg.LABEL_AS_NAME, value=-1):
+ wxpg.PyEnumProperty.__init__(self, label, name, ['Line','Circle','Rectangle'], [0,1,2], value)
+
+ def OnMeasureImage(self, index):
+ return wxpg.DEFAULT_IMAGE_SIZE
+
+ def OnCustomPaint(self, dc, rect, paint_data):
+ """\
+ paint_data.m_choiceItem is -1 if we are painting the control,
+ in which case we need to get the drawn item using DoGetValue.
+ """
+ item = paint_data.m_choiceItem
+ if item == -1:
+ item = self.DoGetValue()
+
+ dc.SetPen(wx.Pen(wx.BLACK))
+ dc.SetBrush(wx.Brush(wx.BLACK))
+
+ if item == 0:
+ dc.DrawLine(rect.x,rect.y,rect.x+rect.width,rect.y+rect.height)
+ elif item == 1:
+ half_width = rect.width / 2
+ dc.DrawCircle(rect.x+half_width,rect.y+half_width,half_width-3)
+ elif item == 2:
+ dc.DrawRectangle(rect.x, rect.y, rect.width, rect.height)
+
+
+class LargeImagePickerCtrl(wx.Window):
+ """\
+ Control created and used by LargeImageEditor.
+ """
+ def __init__(self):
+ pre = wx.PreWindow()
+ self.PostCreate(pre)
+
+ def Create(self, parent, id_, pos, size, style = 0):
+ wx.Window.Create(self, parent, id_, pos, size, style | wx.BORDER_SIMPLE)
+ img_spc = size[1]
+ self.tc = wx.TextCtrl(self, -1, "", (img_spc,0), (2048,size[1]), wx.BORDER_NONE)
+ self.SetBackgroundColour(wx.WHITE)
+ self.SetBackgroundStyle(wx.BG_STYLE_CUSTOM)
+ self.property = None
+ self.bmp = None
+ self.Bind(wx.EVT_PAINT, self.OnPaint)
+
+ def OnPaint(self, event):
+ dc = wx.BufferedPaintDC(self)
+
+ whiteBrush = wx.Brush(wx.WHITE)
+ dc.SetBackground(whiteBrush)
+ dc.Clear()
+
+ bmp = self.bmp
+ if bmp:
+ dc.DrawBitmap(bmp, 2, 2)
+ else:
+ dc.SetPen(wx.Pen(wx.BLACK))
+ dc.SetBrush(whiteBrush)
+ dc.DrawRectangle(2, 2, 64, 64)
+
+ def RefreshThumbnail(self):
+ """\
+ We use here very simple image scaling code.
+ """
+ if not self.property:
+ self.bmp = None
+ return
+
+ path = self.property.DoGetValue()
+
+ if not os.path.isfile(path):
+ self.bmp = None
+ return
+
+ image = wx.Image(path)
+ image.Rescale(64, 64)
+ self.bmp = wx.BitmapFromImage(image)
+
+ def SetProperty(self, property):
+ self.property = property
+ self.tc.SetValue(property.GetDisplayedString())
+ self.RefreshThumbnail()
+
+ def SetValue(self, s):
+ self.RefreshThumbnail()
+ self.tc.SetValue(s)
+
+ def GetLastPosition(self):
+ return self.tc.GetLastPosition()
+
+
+class LargeImageEditor(wxpg.PyEditor):
+ """\
+ Double-height text-editor with image in front.
+ """
+ def __init__(self):
+ wxpg.PyEditor.__init__(self)
+
+ def CreateControls(self, propgrid, property, pos, sz):
+ try:
+ h = 64 + 6
+ x = propgrid.GetSplitterPosition()
+ x2 = propgrid.GetClientSize().x
+ bw = propgrid.GetRowHeight()
+ lipc = LargeImagePickerCtrl()
+ if sys.platform == 'win32':
+ lipc.Hide()
+ lipc.Create(propgrid, wxpg.PG_SUBID1, (x,pos[1]), (x2-x-bw,h))
+ lipc.SetProperty(property)
+ # Hmmm.. how to have two-stage creation without subclassing?
+ #btn = wx.PreButton()
+ #pre = wx.PreWindow()
+ #self.PostCreate(pre)
+ #if sys.platform == 'win32':
+ # btn.Hide()
+ #btn.Create(propgrid, wxpg.PG_SUBID2, '...', (x2-bw,pos[1]), (bw,h), wx.WANTS_CHARS)
+ btn = wx.Button(propgrid, wxpg.PG_SUBID2, '...', (x2-bw,pos[1]), (bw,h), wx.WANTS_CHARS)
+ return (lipc, btn)
+ except:
+ import traceback
+ print traceback.print_exc()
+
+ def UpdateControl(self, property, ctrl):
+ ctrl.SetValue(property.GetDisplayedString())
+
+ def DrawValue(self, dc, property, rect):
+ if not (property.GetFlags() & wxpg.PG_PROP_UNSPECIFIED):
+ dc.DrawText( property.GetDisplayedString(), rect.x+5, rect.y );
+
+ def OnEvent(self, propgrid, ctrl, event):
+ if not ctrl:
+ return False
+
+ evtType = event.GetEventType()
+
+ if evtType == wx.wxEVT_COMMAND_TEXT_ENTER:
+ if propgrid.IsEditorsValueModified():
+ return True
+
+ elif evtType == wx.wxEVT_COMMAND_TEXT_UPDATED:
+ if not property.HasFlag(wxpg.PG_PROP_UNSPECIFIED) or not ctrl or \
+ ctrl.GetLastPosition() > 0:
+
+ # We must check this since an 'empty' text event
+ # may be triggered when creating the property.
+ PG_FL_IN_SELECT_PROPERTY = 0x00100000
+ if not (propgrid.GetInternalFlags() & PG_FL_IN_SELECT_PROPERTY):
+ event.Skip();
+ event.SetId(propGrid.GetId());
+
+ propgrid.EditorsValueWasModified();
+
+ return False
+
+
+ def CopyValueFromControl(self, property, ctrl):
+ tc = ctrl.tc
+ res = property.SetValueFromString(tc.GetValue(),0)
+ # Changing unspecified always causes event (returning
+ # true here should be enough to trigger it).
+ if not res and property.IsFlagSet(wxpg.PG_PROP_UNSPECIFIED):
+ res = true
+
+ return res
+
+ def SetValueToUnspecified(self, ctrl):
+ ctrl.tc.Remove(0,len(ctrl.tc.GetValue()));
+
+ def SetControlStringValue(self, ctrl, txt):
+ ctrl.SetValue(txt)
+
+ def OnFocus(self, property, ctrl):
+ ctrl.tc.SetSelection(-1,-1)
+ ctrl.tc.SetFocus()
+
+
+class PropertyEditor(wx.Panel):
+
+ def __init__(self, parent):
+ # Use the WANTS_CHARS style so the panel doesn't eat the Return key.
+ wx.Panel.__init__(self, parent, -1, style=wx.WANTS_CHARS, size=(160, 200))
+
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ self.pg = wxpg.PropertyGrid(self, style=wxpg.PG_SPLITTER_AUTO_CENTER|wxpg.PG_AUTO_SORT)
+
+ # Show help as tooltips
+ self.pg.SetExtraStyle(wxpg.PG_EX_HELP_AS_TOOLTIPS)
+
+ #pg.Bind(wxpg.EVT_PG_CHANGED, self.OnPropGridChange)
+ #pg.Bind(wxpg.EVT_PG_SELECTED, self.OnPropGridSelect)
+ #self.pg.Bind(wxpg.EVT_PG_RIGHT_CLICK, self.OnPropGridRightClick)
+
+ # Needed by custom image editor
+ wx.InitAllImageHandlers()
+
+ #
+ # Let's create a simple custom editor
+ #
+ # NOTE: Editor must be registered *before* adding a property that uses it.
+ self.pg.RegisterEditor(LargeImageEditor)
+
+ '''
+ #
+ # Add properties
+ #
+
+ pg.Append( wxpg.PropertyCategory("1 - Basic Properties") )
+ pg.Append( wxpg.StringProperty("String",value="Some Text") )
+ pg.Append( wxpg.IntProperty("Int",value=100) )
+ pg.Append( wxpg.FloatProperty("Float",value=100.0) )
+ pg.Append( wxpg.BoolProperty("Bool",value=True) )
+ pg.Append( wxpg.BoolProperty("Bool_with_Checkbox",value=True) )
+ pg.SetPropertyAttribute("Bool_with_Checkbox", "UseCheckbox", True)
+
+ pg.Append( wxpg.PropertyCategory("2 - More Properties") )
+ pg.Append( wxpg.LongStringProperty("LongString",value="This is a\\nmulti-line string\\nwith\\ttabs\\nmixed\\tin.") )
+ pg.Append( wxpg.DirProperty("Dir",value="C:\\Windows") )
+ pg.Append( wxpg.FileProperty("File",value="C:\\Windows\\system.ini") )
+ pg.Append( wxpg.ArrayStringProperty("ArrayString",value=['A','B','C']) )
+
+ pg.Append( wxpg.EnumProperty("Enum","Enum",
+ ['wxPython Rules','wxPython Rocks','wxPython Is The Best'],
+ [10,11,12],0) )
+ pg.Append( wxpg.EditEnumProperty("EditEnum","EditEnumProperty",['A','B','C'],[0,1,2],"Text Not in List") )
+
+ pg.Append( wxpg.PropertyCategory("3 - Advanced Properties") )
+ pg.Append( wxpg.DateProperty("Date",value=wx.DateTime_Now()) )
+ pg.Append( wxpg.FontProperty("Font",value=self.GetFont()) )
+ pg.Append( wxpg.ColourProperty("Colour",value=self.GetBackgroundColour()) )
+ pg.Append( wxpg.SystemColourProperty("SystemColour") )
+ pg.Append( wxpg.ImageFileProperty("ImageFile") )
+ pg.Append( wxpg.MultiChoiceProperty("MultiChoice",choices=['wxWidgets','QT','GTK+']) )
+
+ pg.Append( wxpg.PropertyCategory("4 - Additional Properties") )
+ pg.Append( wxpg.PointProperty("Point",value=self.GetPosition()) )
+ pg.Append( wxpg.SizeProperty("Size",value=self.GetSize()) )
+ pg.Append( wxpg.FontDataProperty("FontData") )
+ pg.Append( wxpg.IntProperty("IntWithSpin",value=256) )
+ pg.SetPropertyEditor("IntWithSpin","SpinCtrl")
+ pg.Append( wxpg.DirsProperty("Dirs",value=['C:/Lib','C:/Bin']) )
+ pg.SetPropertyHelpString( "String", "String Property help string!" )
+ pg.SetPropertyHelpString( "Dirs", "Dirs Property help string!" )
+
+ pg.SetPropertyAttribute( "File", wxpg.PG_FILE_SHOW_FULL_PATH, 0 )
+ pg.SetPropertyAttribute( "File", wxpg.PG_FILE_INITIAL_PATH, "C:\\Program Files\\Internet Explorer" )
+ pg.SetPropertyAttribute( "Date", wxpg.PG_DATE_PICKER_STYLE, wx.DP_DROPDOWN|wx.DP_SHOWCENTURY )
+
+ pg.Append( wxpg.PropertyCategory("5 - Custom Properties") )
+ pg.Append( IntProperty2("IntProperty2", value=1024) )
+
+ pg.Append( ShapeProperty("ShapeProperty", value=0) )
+ pg.Append( PyObjectProperty("PyObjectProperty") )
+
+ pg.Append( wxpg.ImageFileProperty("ImageFileWithLargeEditor") )
+ pg.SetPropertyEditor("ImageFileWithLargeEditor", "LargeImageEditor")
+
+
+ pg.SetPropertyClientData( "Point", 1234 )
+ if pg.GetPropertyClientData( "Point" ) != 1234:
+ raise ValueError("Set/GetPropertyClientData() failed")
+
+ # Test setting unicode string
+ pg.GetPropertyByName("String").SetValue(u"Some Unicode Text")
+
+ #
+ # Test some code that *should* fail (but not crash)
+ #try:
+ #a_ = pg.GetPropertyValue( "NotARealProperty" )
+ #pg.EnableProperty( "NotAtAllRealProperty", False )
+ #pg.SetPropertyHelpString( "AgaintNotARealProperty", "Dummy Help String" )
+ #except:
+ #pass
+ #raise
+
+ '''
+ sizer.Add(self.pg, 1, wx.EXPAND)
+ self.SetSizer(sizer)
+ sizer.SetSizeHints(self)
+
+ self.SelectedTreeItem = None
+
+ def GetPropertyValues(self):
+ #return self.pg.GetPropertyValues(as_strings=True)
+ return self.pg.GetPropertyValues()
+
+
+ def Initialize(self, properties):
+ pg = self.pg
+ pg.Clear()
+
+ if properties:
+ for element in properties:
+ if element[1]['type'] == 'integer':
+ if 'value' in element[1]:
+ property_value = element[1].as_int('value')
+ else:
+ property_value = element[1].as_int('default')
+ property_control = wxpg.IntProperty(element[0], value=property_value)
+ if 'maximum' in element[1]:
+ property_control.SetAttribute('Max', element[1].as_int('maximum'))
+ if 'minimum' in element[1]:
+ property_control.SetAttribute('Min', element[1].as_int('minimum'))
+ property_control.SetAttribute('Wrap', True)
+ pg.Append(property_control)
+ pg.SetPropertyEditor(element[0], 'SpinCtrl')
+
+ if element[1]['type'] == 'float':
+ if 'value' in element[1]:
+ property_value = element[1].as_float('value')
+ else:
+ property_value = element[1].as_float('default')
+ property_control = wxpg.FloatProperty(element[0], value=property_value)
+ if 'maximum' in element[1]:
+ property_control.SetAttribute('Max', element[1].as_float('maximum'))
+ if 'minimum' in element[1]:
+ property_control.SetAttribute('Min', element[1].as_float('minimum'))
+ property_control.SetAttribute('Wrap', True)
+ pg.Append(property_control)
+ pg.SetPropertyEditor(element[0], 'SpinCtrl')
+
+ if element[1]['type'] == 'boolean':
+ if 'value' in element[1]:
+ property_value = element[1].as_bool('value')
+ else:
+ property_value = element[1].as_bool('default')
+ property_control = wxpg.BoolProperty(element[0], value=property_value)
+ pg.Append(property_control)
+ pg.SetPropertyAttribute(element[0], 'UseCheckbox', True)
+ if element[1]['type'] == 'string':
+ if 'value' in element[1]:
+ property_value = element[1]['value']
+ else:
+ property_value = element[1]['default']
+ pg.Append(wxpg.StringProperty(element[0], value=property_value))
+ if element[1]['type'] == 'folder':
+ if 'value' in element[1]:
+ property_value = element[1]['value']
+ else:
+ property_value = element[1]['default']
+ pg.Append(wxpg.DirProperty(element[0], value=property_value))
+ if element[1]['type'] == 'filename':
+ if 'value' in element[1]:
+ property_value = element[1]['value']
+ else:
+ property_value = element[1]['default']
+ pg.Append(wxpg.FileProperty(element[0], value=property_value))
+ #if element[0] == 'category':
+ #pg.Append(wxpg.PropertyCategory(element[1]))
+ #if element[0] == 'folder':
+ #pg.Append(wxpg.DirProperty(element[1], value=element[2]))
+ #if element[0] == 'string':
+ #pg.Append(wxpg.StringProperty(element[1], value=element[2]))
+
+ pg.Refresh()
+
+ def OnReserved(self, event):
+ pass
+
+
+#---------------------------------------------------------------------------
+
+
+class MemoDialog(wx.Dialog):
+ """\
+ Dialog for multi-line text editing.
+ """
+ def __init__(self, parent=None, title='', text='', pos=None, size=(500,500)):
+ wx.Dialog.__init__(self, parent, -1, title, style=wx.DEFAULT_DIALOG_STYLE|wx.RESIZE_BORDER)
+
+ sizer = wx.BoxSizer(wx.VERTICAL)
+
+ tc = wx.TextCtrl(self, 11, text, style=wx.TE_MULTILINE)
+ self.tc = tc
+ topsizer.Add(tc,1,wx.EXPAND|wx.ALL,8)
+
+ rowsizer = wx.BoxSizer( wx.HORIZONTAL )
+ rowsizer.Add(wx.Button(self,wx.ID_OK,'Ok'),0,wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL,8)
+ rowsizer.Add((0,0),1,wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL,8)
+ rowsizer.Add(wx.Button(self,wx.ID_CANCEL,'Cancel'),0,wx.ALIGN_RIGHT|wx.ALIGN_CENTRE_VERTICAL,8)
+ topsizer.Add(rowsizer,0,wx.EXPAND|wx.ALL,8)
+
+ self.SetSizer( topsizer )
+ topsizer.Layout()
+
+ self.SetSize( size )
+ if not pos:
+ self.CenterOnScreen()
+ else:
+ self.Move(pos)
+
+
+#---------------------------------------------------------------------------