diff --git a/wxPython/wx/tools/XRCed/CHANGES.txt b/wxPython/wx/tools/XRCed/CHANGES.txt index 39db47d191..212c61507f 100644 --- a/wxPython/wx/tools/XRCed/CHANGES.txt +++ b/wxPython/wx/tools/XRCed/CHANGES.txt @@ -1,3 +1,47 @@ +0.1.8-5 (under construction) +------- + +Preferences for default "sizeritem" parameters for new panels and +controls can be configured ("File">"Preferences..."). + +Implemented comment object for including simple one-line comments and +comment directives as tree nodes. No validation is performed for a +valid XML string so comments must not contain "-->". Comment directive +is a special comment starting with '%' character, followed by a line +of python code. It is executed using 'exec' when the resource file is +opened. This is useful to import plugin modules containing custom +handlers which are specific to the resource file, hovewer this is of +course a security hole if you use foreign XRC files. A warning is +displayed if the preference option 'ask' is selected (by default). + +Added support for custom controls and plugin modules. Refer to this +wxPythonWiki for the details: + http://wiki.wxpython.org/index.cgi/XRCed#custom + +Tool panel sections can be collapsed/expanded by clicking on the +label of a tool group. + +Some undo/redo and other fixes. + +0.1.8-4 +------- + +Fixes for wxMSW (notebook highlighting, control sizes, tree Unselect). + +0.1.8-3 +------- + +Notebook page highlighting fix. Highlight resizes when the window +is resized. ParamUnit spin button detects event handler re-entry +(wxGTK probably has a bug in wxSpinButton with repeated events). + +0.1.8-2 +------- + +Fix for dealing with empty 'growable' property, using MiniFrame +for properties panel, the panel is restored together with the +main window. + 0.1.8-1 ------- diff --git a/wxPython/wx/tools/XRCed/globals.py b/wxPython/wx/tools/XRCed/globals.py index 0313077656..ca71046967 100644 --- a/wxPython/wx/tools/XRCed/globals.py +++ b/wxPython/wx/tools/XRCed/globals.py @@ -15,7 +15,7 @@ import sys # Global constants progname = 'XRCed' -version = '0.1.8-1' +version = '0.1.8-5' # Minimal wxWidgets version MinWxVersion = (2,6,0) if wx.VERSION[:3] < MinWxVersion: @@ -48,6 +48,7 @@ class Globals: testWinPos = wx.DefaultPosition currentXXX = None currentEncoding = defaultEncoding + conf = None def _makeFonts(self): self._sysFont = wx.SystemSettings.GetFont(wx.SYS_SYSTEM_FONT) diff --git a/wxPython/wx/tools/XRCed/images.py b/wxPython/wx/tools/XRCed/images.py index bf56f98b2b..6d133911ce 100644 --- a/wxPython/wx/tools/XRCed/images.py +++ b/wxPython/wx/tools/XRCed/images.py @@ -470,11 +470,10 @@ def getToolGaugeData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x18\x00\x00\x00\x0e\x08\x02\ \x00\x00\x00\xba\x9aK)\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\ -\x00XIDAT(\x91c\x9c2u\n\x03U\x00U\x0c\xfa\xff\xff?\x0b\x9c\x85)\xcd\xc8\xc8x\ +\x00TIDAT(\x91c\x9c2u\n\x03U\x00U\x0c\xfa\xff\xff?\x0b\x9c\x85)\xcd\xc8\xc8x\ \xf5\xdaU"\xcdb\x81\xb3\xde\xbf~O\x89\xa3\x98pIl\xdb\xbd\x8d:\x06\x91\nF\r"\ -\x0cX\x909\xa4\xc6\x14\x16\x83\x18\x19\x19)r\x0f\xdc \xe2S0>\x83\xfe\xff\xff\ -O\xa1)\x0c\x0c\x0c\x00U\xa6\x18\xb48\xff\xd0\x00\x00\x00\x00\x00IEND\xaeB`\ -\x82' +\x0cX\x909\xa4\xc6\x14\x16\x83\x18\x19\x19)r\x0f\xdc \xe2S0>\x83\xb0\xe6\x0f\ +R\x01\x00U\xa6\x18\xb4\x82\x95pI\x00\x00\x00\x00IEND\xaeB`\x82' def getToolGaugeBitmap(): return BitmapFromImage(getToolGaugeImage()) @@ -842,13 +841,13 @@ def getToolRadioButtonData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x0b\x00\x00\x00\x0b\x08\x06\ \x00\x00\x00\xa9\xacw&\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ -\x00\x98IDAT\x18\x95m\x8f\xc1\r\xc20\x0cE\x9f\x1d\x06\xe8\x81)\xe8\x06\x91:V\ -\xc5\x08P\xb2\x15\xa8\xdd\xa0L\xd1C\x06\x00\xc2\xa1\xa4J\x83\xbfd\xc5N\xde\ -\xb7~\x10u\xd4\x15\x86\x90\xac{\xa5\xd2\xedrM\xe5YJ-\xb0?\xf7X\x06\xb5\xc0\ -\xf99\x9b\x06\xb5@\xc04H\x18\xc2\x1fX\xaa=\xb5\x84!\x00 \xa2\x8e\xcf\xfb\x95\ -\x00\xa6\xc7Dsl60.\x11\xdf\xf95\x82;\x88\xe6\x06\xc0w\x9e\xb8D\x13\\W\xab\ -\xdb*\xfd4\xde\xc7\xdc\xa6\xf2]D\xdd.c\x8e\xb4\xdb\x98\xe7\xfaC\x19\xa8A\x80\ -/\x17\xa5W:\x12\xac\xa3\xbe\x00\x00\x00\x00IEND\xaeB`\x82' +\x00\x96IDAT\x18\x95m\x90\xc1\r\xc20\x10\x04\xc7g\n\xc8\x83*H\x07\x96RVD\t`\ +\xdc\x15(\xe9 T\x91\x87\x0b\x00\xcc#1\xb2\xcd\xadd\xf9t\x9a=\xad\x16#\x96\ +\xf6\x05\x1f\x92\xb6\x17\x1a\xdd.\xd7T\xfe\xa5D\x03\xc7\xf3\x88f\x10\r\\\x9e\ +\x8bj\x10\r\x04T\x83\t>\xfc\x81\xa5\xfaSO\xf0\x01\x00c\xc4\xf2y\xbf\x12\xc0\ +\xfc\x98\xe9\x8e\xdd\x0f\x8ck\xc4\rn\x8b`\x0fF\xf2\x00\xe0\x06G\\\xa3\nn\xa7\ +\x8b\x1e\xd3\xae\xe9>\xe5\xb1\xee\xdb\x88\xad2\xe6H\xd5E\xad\xe7\x12hA\x80/\ +\x17\xa5W:+\xbbb\xd2\x00\x00\x00\x00IEND\xaeB`\x82' def getToolRadioButtonBitmap(): return BitmapFromImage(getToolRadioButtonImage()) @@ -865,13 +864,13 @@ def getToolRadioButtonIcon(): #---------------------------------------------------------------------- def getToolRootData(): return \ -"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ \x00\x00\x00&/\x9c\x8a\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ -\x00cIDAT(\x91\xed\x90\xc1\x0e\x800\x08C[\xf0\x97T\xfe\xff\xa6~\x93n\xb7e.`\ -\xa6\xbb\xda\x84\x03\xa4m\xf2 E1\xa2\xc9;\xa6\xebL\xf5NQ\x86\x05\xeb2\xdf\ -\xcc\xdb~\x84fW\x14\x85\x99%\x8a\xe2\xcb\xb8\x08\x1eF\x84T\nj\x947\x18\xa5\ -\xa0\r==\xce-h\xf5#\xf4#\x90\xa2\xbd^W2\x94\x06\x90\x01\x0f\xb3'\x06\xe8\x11\ -R\xf1\x00\x00\x00\x00IEND\xaeB`\x82" +\x00aIDAT(\x91\xed\x93\xc1\n\x80@\x08Dg\xb4_\xaa\xfc\xff[\xf5M\xb5\xdd\x96m\ +\xd1\xa8\xbc6\xe0A\x19\x07\x9e )\x8a\x8c\x06oX\x8e\xbd\xb4=E\x19\x06\xcc\xd3\ +x1/\xeb\x16\x9a]Q\x14fV(\x8a/\xe5"x\x18\x11R\rhQ\xde`\xd4\x80~\xe9\xeepn@\ +\xaf\x1f\xe19\x02\xb3\xbf \xa9m\x00\'\x0f\xb3\'\x06(\x95\x90F\x00\x00\x00\ +\x00IEND\xaeB`\x82' def getToolRootBitmap(): return BitmapFromImage(getToolRootImage()) @@ -917,8 +916,8 @@ def getToolSeparatorData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x0e\x00\x00\x00\x02\x08\x02\ \x00\x00\x00\xe7\xe8z\xfd\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\ -\x00\x00\x17IDAT\x18\x95c\x9c2u\n\x03\x11 ;+\x9b\x05B\x11\xa3\x1a\x00\xfb\ -\x1c\x04C\xb1\x8cE\xa0\x00\x00\x00\x00IEND\xaeB`\x82' +\x00\x00\x17IDAT\x08\x99c\x9c2u\n\x03\x11 ;+\x9b\x05B\x11\xa3\x1a\x00\xfb\ +\x1c\x04CU\x1cv\xec\x00\x00\x00\x00IEND\xaeB`\x82' def getToolSeparatorBitmap(): return BitmapFromImage(getToolSeparatorImage()) @@ -1052,28 +1051,28 @@ def getToolSplitterWindowIcon(): #---------------------------------------------------------------------- def getToolStaticBitmapData(): return \ -'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x0e\x00\x00\x00\x11\x08\x06\ +"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x0e\x00\x00\x00\x11\x08\x06\ \x00\x00\x00\xed\xc8\x9d\x9f\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\ -\x00\x00\x01\xf7IDAT(\x91\x85\x921h\x13Q\x18\xc7\x7fw\xf7\x86\x17p\xb8\x83\ -\x0c\x97-\x05\x1dts\xb3N\x9et\x90\xe0`[\\\\\x9c:X\xe9PN\xa7\xea\x16\x10\x95\ -\x0ejq\x10\xb2\x08\xe9Rt\xd0:\xf6:\x14\x13P\x92.\xd6\x82C\xb3\x14\x92A\x92S\ -\x03\xf7\xc0k?\x87pgC\xab\xfdO\xef}\xef\xfd\xbe\xef}\xff\xefY\x96\xedpT\x87\ -\x07\xa9p\x82lGYc\xfb\xa3@\x06%\xbf\x12\xda\x9f\xdb\x0c\x06\x83\x7f&\xb4,\ -\xdb\xc9\x83\x8d\xad\x06o\xd7j,-\x9eG\xab\x02f\x98\xd0\xf8\x12\xb3\xfa~\x9b\ -\xfa\xeb\x0fc\x95s\xb0\xb1\xd5\xa0\xe4k\\"<\xff2\xe0\x82i\x92\xa4\x86\xf8\ -\xfb\x80{\x8fv\xa9\xaf\xd6s\xd8\xce\xaa-\xbfX\xc6W\x11^\xf1*\xa8\tP\x1e\x9c\ -\xa9PP\x1a\xd7\xf5X\x9a+1;=\x9b?Ue\x8bp\xae\x02\x1a\xd0\xa5Q 5\x00$\xa9\xa6\ -\xa0\x0c^Q\xe3z:\xef77\xc7\x18\x93_\x06\r\xca%1#s\x124(M\xc9\xcd\xce\xc1\xce\ -\x9a\xad>\x7f\x03i\x02\x18Hc0\x1dH\xbb\xa3d\xa9\xc1\xc41\xf5\xb5\xe8\xf88j\ -\xafj\x98\x94\x11\xac4\x89\xe9\x001\xa4\x86^\xafKg\x7f@\xf5\xf1JnN\xde\xa3\ -\xd6\x1am\x0cP \x19v \x8d1f@\xb7\xd7\xc3\x0c\x13\xaa/w\x896k\xe3\xe6\xd8\x8e\ -\xb2\xee\xdc\xbd-\xdb\xcd\x88\x89sMV\x1e\x06\xc4qLg\xbf\xcb\x83\'\x11^\xf1\ -\x02\xd1fcl\x8eX\xb6\x83e;\xa0\x90\x99\x9b\x15\xd9\xf9\xba#\xadO\x1f\xa5r=\ -\x90p\xe1\x96\xec}\xdb\x93L\xd9]\xcbv\xfe\x8237*""\xd2j\xb7$\x98\n$\xbc\x1fJ\ -\xbf\xdf?\x06\x8c\x81\xbe\xef\xcbF\xb4!\x95k\x81\xac<{*\xf3\x0b\xf3\xe2\x16\ -\xdd\x13\x811\x10\x90`jR\xd6\xdf\xad\x8f*^\t\xa4|\xb6|:\x98\xc1\xe5\xb2/\x93\ -\x97.J\xb8\x18\xfe\x17\xb2lg\xf4\xc9\x01\xe4\xf0@|\xdf\xc5\x18\xc3\x8f\x9f\ -\xbf-N\xd1\x1f(\xba\xfe\xd4\xf5\xbb\xa30\x00\x00\x00\x00IEND\xaeB`\x82' +\x00\x00\x01\xf9IDAT(\x91\x85\x931h\x13Q\x18\xc7\x7fw\xf7\x86\x17p\xb8\x83\ +\x0c\x97-\x05\x1dts\xb3N\x9et\x90\xe0\xa0-..N\x1d\xact(\xd1\xa9\xba\x05D\xa5\ +\x83Z\x1c\x84,B\xba\x14\x1d\xb4\x8e\xbd\x0e\xc5\x04\x94\xa4\x8b\xb5\xe0\xd0,\ +\x85d\x90\xe4\xd4\xc0=\xf0\xda\xcf!\xdc\xd9\xa3Q\xbf\xe9\xbd\xef}\xbf\xef{\ +\xdf\xff{\xcf\xb2l\x87\xe3vt\x98\x08\x13\xccv\x94\x95\xdb\x1f\x07R(\xfe\x19\ +\xd3\xf9\xd4a8\x1c\xfe5\xa1e\xd9N\xe6ln7y\xb3^gy\xe9,Z\x150\xa3\x98\xe6\xe7\ +\x88\xb5w;4^\xbd\xcfU\xce\xc0\xe6v\x93\x92\xafq\t\xf1\xfc\x8b\x80\x0b\xa6E\ +\x9c\x18\xa2oC\xee>\xdc\xa3\xb1\xd6\xc8`;\xad\xb6\xf2|\x05_\x85x\xc5\xcb\xa0\ +\xa6@yp\xaaBAi\\\xd7cy\xbe\xc4\xdc\xf5\xb9\xec\xaa*]T\xe7+\xa0\x01]\x1a;\x12\ +\x03@\x9ch\n\xca\xe0\x155\xae\xa7\xb3~3q\x8c1Y0hP.\xb1\x19\x8b\x13\xa3AiJnz\ +\x0ev\xdal\xed\xd9kHb\xc0@\x12\x81\xe9B\xd2\x1b'K\x0c&\x8ah\xac\x87'\xc7Q\ +\x7fY\xc7$\x8ca\xa5\x89M\x17\x88 1\xf4\xfb=\xba\x07Cj\x8fV3q\xb2\x1e\xb5\xd6\ +hc\x80\x02\xf1\xa8\x0bI\x841Cz\xfd>f\x14S{\xb1G\xb8U\xcf\x8bc;\xca\xba}\xe7\ +\x96\xec\xb4B\xa6\xce\xb4X}\x10\x10E\x11\xdd\x83\x1e\xf7\x1f\x87x\xc5s\x84[\ +\xcd\xdc\x1c\xb1l\x07\xcbv@!\xb37*\xb2\xfbeW\xda\x1f?H\xe5j \xd5\xc5\x9b\xb2\ +\xffu_RKc-\xdb\xf9\x03\xce^\xab\x88\x88H\xbb\xd3\x96`&\x90\xea\xbd\xaa\x0c\ +\x06\x83\x13@\x0e\xf4}_6\xc3M\xa9\\\td\xf5\xe9\x13YX\\\x10\xb7\xe8N\x04r \ +\xc1\xcc\xb4l\xbc\xdd\x18W\xbc\x14H\xf9t\xf9\xff`\n\x97\xcb\xbeL_8/\xd5\xa5\ +\xea?!\xcbv\xc6\x8f\x1c@\x8e\x0e\xc5\xf7]\x8c1|\xff\xf1+\xf7\xf7&\xd9o(\xba\ +\xfe\xd4S\x004\x8f\x00\x00\x00\x00IEND\xaeB`\x82" def getToolStaticBitmapBitmap(): return BitmapFromImage(getToolStaticBitmapImage()) @@ -1140,8 +1139,8 @@ def getToolStaticLineData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x14\x00\x00\x00\x02\x08\x02\ \x00\x00\x00\xd7dk\xdc\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\ -\x00\x17IDAT\x18\x95c\x9c2u\n\x03Y ;+\x9b\x05B\x91\xa7\x1f\x00gO\x04C\xda+\ -\x0c\xd5\x00\x00\x00\x00IEND\xaeB`\x82' +\x00\x17IDAT\x08\x99c\x9c2u\n\x03Y ;+\x9b\x05B\x91\xa7\x1f\x00gO\x04C>\xbb?\ +\x99\x00\x00\x00\x00IEND\xaeB`\x82' def getToolStaticLineBitmap(): return BitmapFromImage(getToolStaticLineImage()) @@ -1204,9 +1203,9 @@ def getToolToolData(): return \ '\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\t\x00\x00\x00\t\x08\x02\x00\ \x00\x00o\xf3\x91G\x00\x00\x00\x03sBIT\x08\x08\x08\xdb\xe1O\xe0\x00\x00\x00>\ -IDAT\x18\x95c\xfc\xf1\xe7\x07\x036\xc0\xc1\xc2\xc1\xc2\xc0\xc0p\xe3\xc6\r4\ +IDAT\x08\x99c\xfc\xf1\xe7\x07\x036\xc0\xc1\xc2\xc1\xc2\xc0\xc0p\xe3\xc6\r4\ \x89\x03\x07\x0e0000a\xd5\x04\x01,hj\x19\x18\x18\x1c\x1c\x1c \x0c|\xfa\x883\ -\x13n\x14\x8a\x1c\xdc&\x12\x00\x00b\xc7\r\xe0\xb7\\uG\x00\x00\x00\x00IEND\ +\x13n\x14\x8a\x1c\xdc&\x12\x00\x00b\xc7\r\xe0y\xf1\x04O\x00\x00\x00\x00IEND\ \xaeB`\x82' def getToolToolBitmap(): @@ -1248,13 +1247,13 @@ def getToolToolBarIcon(): #---------------------------------------------------------------------- def getToolTreeCtrlData(): return \ -"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ \x00\x00\x00&/\x9c\x8a\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ -\x00cIDAT(\x91\xed\x90\xc1\x0e\x800\x08C[\xf0\x97T\xfe\xff\xa6~\x93n\xb7e.`\ -\xa6\xbb\xda\x84\x03\xa4m\xf2 E1\xa2\xc9;\xa6\xebL\xf5NQ\x86\x05\xeb2\xdf\ -\xcc\xdb~\x84fW\x14\x85\x99%\x8a\xe2\xcb\xb8\x08\x1eF\x84T\nj\x947\x18\xa5\ -\xa0\r==\xce-h\xf5#\xf4#\x90\xa2\xbd^W2\x94\x06\x90\x01\x0f\xb3'\x06\xe8\x11\ -R\xf1\x00\x00\x00\x00IEND\xaeB`\x82" +\x00aIDAT(\x91\xed\x93\xc1\n\x80@\x08Dg\xb4_\xaa\xfc\xff[\xf5M\xb5\xdd\x96m\ +\xd1\xa8\xbc6\xe0A\x19\x07\x9e )\x8a\x8c\x06oX\x8e\xbd\xb4=E\x19\x06\xcc\xd3\ +x1/\xeb\x16\x9a]Q\x14fV(\x8a/\xe5"x\x18\x11R\rhQ\xde`\xd4\x80~\xe9\xeepn@\ +\xaf\x1f\xe19\x02\xb3\xbf \xa9m\x00\'\x0f\xb3\'\x06(\x95\x90F\x00\x00\x00\ +\x00IEND\xaeB`\x82' def getToolTreeCtrlBitmap(): return BitmapFromImage(getToolTreeCtrlImage()) @@ -1290,6 +1289,27 @@ def getToolUnknownIcon(): icon.CopyFromBitmap(getToolUnknownBitmap()) return icon +#---------------------------------------------------------------------- +def getTreeCommentData(): + return \ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ +\x00\x00\x00&/\x9c\x8a\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ +\x00AIDAT(\x91cddbf\xa0\x040Q\xa4\x9bf\x06\xfc\xff\xf7\xf7\xff\xff\x7f\x7f\ +\xff\xa3\xb3\xe9\xe7\x02R\x00#z,\xe0s.#\x133#A\x17 +\xc2\xc5\xc6k\x00\xa9`\ +\x18x\x81\xfaa@*\x00\x00\xb0\xac\x18?Q\xffAR\x00\x00\x00\x00IEND\xaeB`\x82' + +def getTreeCommentBitmap(): + return BitmapFromImage(getTreeCommentImage()) + +def getTreeCommentImage(): + stream = cStringIO.StringIO(getTreeCommentData()) + return ImageFromStream(stream) + +def getTreeCommentIcon(): + icon = EmptyIcon() + icon.CopyFromBitmap(getTreeCommentBitmap()) + return icon + #---------------------------------------------------------------------- def getTreeDefaultData(): return \ @@ -1449,13 +1469,13 @@ def getTreePanelIcon(): #---------------------------------------------------------------------- def getTreeRootData(): return \ -"\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ +'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x10\x00\x00\x00\x0e\x08\x06\ \x00\x00\x00&/\x9c\x8a\x00\x00\x00\x04sBIT\x08\x08\x08\x08|\x08d\x88\x00\x00\ -\x00cIDAT(\x91\xed\x90\xc1\x0e\x800\x08C[\xf0\x97T\xfe\xff\xa6~\x93n\xb7e.`\ -\xa6\xbb\xda\x84\x03\xa4m\xf2 E1\xa2\xc9;\xa6\xebL\xf5NQ\x86\x05\xeb2\xdf\ -\xcc\xdb~\x84fW\x14\x85\x99%\x8a\xe2\xcb\xb8\x08\x1eF\x84T\nj\x947\x18\xa5\ -\xa0\r==\xce-h\xf5#\xf4#\x90\xa2\xbd^W2\x94\x06\x90\x01\x0f\xb3'\x06\xe8\x11\ -R\xf1\x00\x00\x00\x00IEND\xaeB`\x82" +\x00aIDAT(\x91\xed\x93\xc1\n\x80@\x08Dg\xb4_\xaa\xfc\xff[\xf5M\xb5\xdd\x96m\ +\xd1\xa8\xbc6\xe0A\x19\x07\x9e )\x8a\x8c\x06oX\x8e\xbd\xb4=E\x19\x06\xcc\xd3\ +x1/\xeb\x16\x9a]Q\x14fV(\x8a/\xe5"x\x18\x11R\rhQ\xde`\xd4\x80~\xe9\xeepn@\ +\xaf\x1f\xe19\x02\xb3\xbf \xa9m\x00\'\x0f\xb3\'\x06(\x95\x90F\x00\x00\x00\ +\x00IEND\xaeB`\x82' def getTreeRootBitmap(): return BitmapFromImage(getTreeRootImage()) diff --git a/wxPython/wx/tools/XRCed/panel.py b/wxPython/wx/tools/XRCed/panel.py index d231a933cc..d05dc3793c 100644 --- a/wxPython/wx/tools/XRCed/panel.py +++ b/wxPython/wx/tools/XRCed/panel.py @@ -22,7 +22,7 @@ class Panel(wx.Notebook): # Set common button size for parameter buttons bTmp = wx.Button(self, -1, '') import params - params.buttonSize = (self.DLG_SZE(buttonSize)[0], bTmp.GetSize()[1]) + params.buttonSize = (self.DLG_SZE(buttonSizeD)[0], bTmp.GetSize()[1]) bTmp.Destroy() del bTmp @@ -160,6 +160,7 @@ class Panel(wx.Notebook): # Register undo object when modifying first time if not self.modified and value: g.undoMan.RegisterUndo(UndoEdit()) + g.frame.SetModified() self.modified = value def Apply(self): @@ -184,7 +185,7 @@ class ParamPage(wx.Panel): param = evt.GetEventObject().GetName() w = self.controls[param] w.Enable(True) - objElem = xxx.element + objElem = xxx.node if evt.IsChecked(): # Ad new text node in order of allParams w.SetValue('') # set empty (default) value @@ -192,7 +193,7 @@ class ParamPage(wx.Panel): elem = g.tree.dom.createElement(param) # Some classes are special if param == 'font': - xxx.params[param] = xxxParamFont(xxx.element, elem) + xxx.params[param] = xxxParamFont(xxx.node, elem) elif param in xxxObject.bitmapTags: xxx.params[param] = xxxParamBitmap(elem) else: @@ -218,7 +219,7 @@ class ParamPage(wx.Panel): xxx.params[param].remove() del xxx.params[param] w.SetValue('') - w.modified = False # mark as not changed + w.SetModified(False) # mark as not changed w.Enable(False) # Set modified flag (provokes undo storing is necessary) panel.SetModified(True) @@ -228,7 +229,7 @@ class ParamPage(wx.Panel): name = self.controlName.GetValue() if xxx.name != name: xxx.name = name - xxx.element.setAttribute('name', name) + xxx.node.setAttribute('name', name) for param, w in self.controls.items(): if w.modified: paramObj = xxx.params[param] @@ -237,10 +238,11 @@ class ParamPage(wx.Panel): xxx.setSpecial(param, value) else: paramObj.update(value) + # Save current state def SaveState(self): self.origChecks = map(lambda i: (i[0], i[1].GetValue()), self.checks.items()) - self.origControls = map(lambda i: (i[0], i[1].GetValue(), i[1].IsEnabled()), + self.origControls = map(lambda i: (i[0], i[1].GetValue(), i[1].enabled), self.controls.items()) if self.controlName: self.origName = self.controlName.GetValue() @@ -257,7 +259,8 @@ class ParamPage(wx.Panel): for k,v,e in state[1]: self.controls[k].SetValue(v) self.controls[k].Enable(e) - if e: self.controls[k].modified = True + # Set all states to modified + if e and k in self.xxx.params: self.controls[k].modified = True if self.controlName: self.controlName.SetValue(state[2]) @@ -283,11 +286,15 @@ class PropPage(ParamPage): for param in xxx.allParams: present = xxx.params.has_key(param) if param in xxx.required: - label = wx.StaticText(self, paramIDs[param], param + ':', - size = (LABEL_WIDTH,-1), name = param) + if isinstance(xxx, xxxComment): + label = None + else: + label = wx.StaticText(self, paramIDs[param], param + ':', + size = (LABEL_WIDTH,-1), name = param) else: - # Notebook has one very loooooong parameter + # Rename some parameters if param == 'usenotebooksizer': sParam = 'usesizer:' + elif param == 'option': sParam = 'proportion' else: sParam = param + ':' label = wx.CheckBox(self, paramIDs[param], sParam, size = (LABEL_WIDTH,-1), name = param) @@ -303,13 +310,19 @@ class PropPage(ParamPage): typeClass = ParamText control = typeClass(self, param) control.Enable(present) - sizer.AddMany([ (label, 0, wx.ALIGN_CENTER_VERTICAL), - (control, 0, wx.ALIGN_CENTER_VERTICAL | wx.GROW) ]) + # Comment has only one parameter + if isinstance(xxx, xxxComment): + # Bind char event to check Enter key + control.text.Bind(wx.EVT_CHAR, self.OnEnter) + sizer.Add(control, 0, wx.ALIGN_CENTER_VERTICAL | wx.GROW) + else: + sizer.AddMany([ (label, 0, wx.ALIGN_CENTER_VERTICAL), + (control, 0, wx.ALIGN_CENTER_VERTICAL | wx.GROW) ]) self.controls[param] = control topSizer.Add(sizer, 1, wx.ALL | wx.EXPAND, 3) - self.SetAutoLayout(True) self.SetSizer(topSizer) topSizer.Fit(self) + def SetValues(self, xxx): self.xxx = xxx self.origChecks = [] @@ -336,6 +349,13 @@ class PropPage(ParamPage): self.origChecks.append((param, False)) self.origControls.append((param, '', False)) + # This is called only for comment now + def OnEnter(self, evt): + if evt.GetKeyCode() == 13: + g.tree.Apply(self.xxx, g.tree.selection) + else: + evt.Skip() + ################################################################################ # Style notebook page @@ -362,6 +382,7 @@ class StylePage(ParamPage): self.SetAutoLayout(True) self.SetSizer(topSizer) topSizer.Fit(self) + # Set data for a cahced page def SetValues(self, xxx): self.xxx = xxx diff --git a/wxPython/wx/tools/XRCed/params.py b/wxPython/wx/tools/XRCed/params.py index dfe6bd6ac6..7142449f84 100644 --- a/wxPython/wx/tools/XRCed/params.py +++ b/wxPython/wx/tools/XRCed/params.py @@ -25,7 +25,10 @@ genericExStyles = [ 'wxWS_EX_PROCESS_UI_UPDATES' ] -buttonSize = (35,-1) # in dialog units, transformed to pixels in panel ctor +# Global var initialized in Panel.__init__ for button size in screen pixels +buttonSize = None +# Button size in dialog units +buttonSizeD = (35,-1) # Class that can properly disable children class PPanel(wx.Panel): @@ -33,13 +36,14 @@ class PPanel(wx.Panel): wx.Panel.__init__(self, parent, -1, name=name) self.modified = self.freeze = False def Enable(self, value): + self.enabled = value # Something strange is going on with enable so we make sure... for w in self.GetChildren(): w.Enable(value) #wx.Panel.Enable(self, value) - def SetModified(self): - self.modified = True - g.panel.SetModified(True) + def SetModified(self, state=True): + self.modified = state + if state: g.panel.SetModified(True) # Common method to set modified state def OnChange(self, evt): if self.freeze: return @@ -56,9 +60,7 @@ class ParamBinaryOr(PPanel): sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) self.button = wx.Button(self, self.ID_BUTTON_CHOICES, 'Edit...', size=buttonSize) sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL) - self.SetAutoLayout(True) self.SetSizer(sizer) - sizer.Fit(self) wx.EVT_BUTTON(self, self.ID_BUTTON_CHOICES, self.OnButtonChoices) wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange) def GetValue(self): @@ -191,9 +193,7 @@ class ParamColour(PPanel): sizer.Add(self.text, 0, wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.BOTTOM, 2) self.button = wx.Panel(self, self.ID_BUTTON, wx.DefaultPosition, wx.Size(20, 20)) sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL | wx.LEFT, 5) - self.SetAutoLayout(True) self.SetSizer(sizer) - sizer.Fit(self) self.textModified = False wx.EVT_PAINT(self.button, self.OnPaintButton) wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange) @@ -253,9 +253,7 @@ class ParamFont(PPanel): sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) self.button = wx.Button(self, self.ID_BUTTON_SELECT, 'Select...', size=buttonSize) sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL) - self.SetAutoLayout(True) self.SetSizer(sizer) - sizer.Fit(self) self.textModified = False wx.EVT_BUTTON(self, self.ID_BUTTON_SELECT, self.OnButtonSelect) wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange) @@ -320,7 +318,6 @@ class ParamFont(PPanel): dlg = wx.FontDialog(self, data) if dlg.ShowModal() == wx.ID_OK: font = dlg.GetFontData().GetChosenFont() - print font.GetEncoding() if font.GetEncoding() == wx.FONTENCODING_SYSTEM: encName = '' else: @@ -348,9 +345,7 @@ class ParamInt(PPanel): self.spin = wx.SpinCtrl(self, self.ID_SPIN_CTRL, size=(60,-1)) self.spin.SetRange(-2147483648, 2147483647) # min/max integers sizer.Add(self.spin) - self.SetAutoLayout(True) self.SetSizer(sizer) - sizer.Fit(self) wx.EVT_SPINCTRL(self, self.ID_SPIN_CTRL, self.OnChange) def GetValue(self): return str(self.spin.GetValue()) @@ -369,9 +364,7 @@ class ParamIntNN(PPanel): self.spin = wx.SpinCtrl(self, self.ID_SPIN_CTRL, size=(60,-1)) self.spin.SetRange(0, 10000) # min/max integers sizer.Add(self.spin) - self.SetAutoLayout(True) self.SetSizer(sizer) - sizer.Fit(self) wx.EVT_SPINCTRL(self, self.ID_SPIN_CTRL, self.OnChange) def GetValue(self): return str(self.spin.GetValue()) @@ -388,26 +381,23 @@ class ParamUnit(PPanel): self.ID_TEXT_CTRL = wx.NewId() self.ID_SPIN_BUTTON = wx.NewId() sizer = wx.BoxSizer(wx.HORIZONTAL) - self.spin = wx.SpinButton(self, self.ID_SPIN_BUTTON, style = wx.SP_VERTICAL, size=(-1,1)) + self.spin = wx.SpinButton(self, self.ID_SPIN_BUTTON, style = wx.SP_VERTICAL, size=(-1,0)) textW = 60 - self.spin.GetSize()[0] self.text = wx.TextCtrl(self, self.ID_TEXT_CTRL, size=(textW,-1)) self.spin.SetRange(-10000, 10000) sizer.Add(self.text, 0, wx.EXPAND) sizer.Add(self.spin, 0, wx.EXPAND) - #sizer.SetMinSize((50,-1)) - self.SetAutoLayout(True) self.SetSizer(sizer) - sizer.Fit(self) - wx.EVT_SPIN_UP(self, self.ID_SPIN_BUTTON, self.OnSpinUp) - wx.EVT_SPIN_DOWN(self, self.ID_SPIN_BUTTON, self.OnSpinDown) + self.spin.Bind(wx.EVT_SPIN_UP, self.OnSpinUp) + self.spin.Bind(wx.EVT_SPIN_DOWN, self.OnSpinDown) def GetValue(self): return self.text.GetValue() def SetValue(self, value): - self.freeze = True - if not value: value = '0' + if not value: value = '0' self.text.SetValue(value) - self.freeze = False + self.Change(0) def Change(self, x): + self.freeze = True # Check if we are working with dialog units value = self.text.GetValue() units = '' @@ -417,14 +407,19 @@ class ParamUnit(PPanel): try: intValue = int(value) + x self.spin.SetValue(intValue) - self.text.SetValue(str(intValue) + units) - self.SetModified() + if x: # 0 can be passed to update spin value only + self.text.SetValue(str(intValue) + units) + self.SetModified() except: # !!! Strange, if I use wx.LogWarning, event is re-generated - print 'incorrect unit format' + print 'ERROR: incorrect unit format' + self.freeze = False def OnSpinUp(self, evt): + self.freeze = True self.Change(1) def OnSpinDown(self, evt): + if self.freeze: return + self.freeze = True self.Change(-1) class ParamMultilineText(PPanel): @@ -437,9 +432,7 @@ class ParamMultilineText(PPanel): sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) self.button = wx.Button(self, self.ID_BUTTON_EDIT, 'Edit...', size=buttonSize) sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL) - self.SetAutoLayout(True) - self.SetSizer(sizer) - sizer.Fit(self) + self.SetSizerAndFit(sizer) wx.EVT_BUTTON(self, self.ID_BUTTON_EDIT, self.OnButtonEdit) wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange) def GetValue(self): @@ -458,18 +451,16 @@ class ParamMultilineText(PPanel): dlg.Destroy() class ParamText(PPanel): - def __init__(self, parent, name, textWidth=-1): + def __init__(self, parent, name, textWidth=-1, style=0): PPanel.__init__(self, parent, name) self.ID_TEXT_CTRL = wx.NewId() # We use sizer even here to have the same size of text control sizer = wx.BoxSizer() - self.text = wx.TextCtrl(self, self.ID_TEXT_CTRL, size=wx.Size(textWidth,-1)) + self.text = wx.TextCtrl(self, self.ID_TEXT_CTRL, size=wx.Size(textWidth,-1), style=style) if textWidth == -1: option = 1 else: option = 0 sizer.Add(self.text, option, wx.ALIGN_CENTER_VERTICAL | wx.TOP | wx.BOTTOM, 2) - self.SetAutoLayout(True) self.SetSizer(sizer) - sizer.Fit(self) wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange) def GetValue(self): return self.text.GetValue() @@ -494,6 +485,11 @@ class ParamEncoding(ParamText): def __init__(self, parent, name): ParamText.__init__(self, parent, name, 100) +class ParamComment(ParamText): + def __init__(self, parent, name): + ParamText.__init__(self, parent, name, 330 + buttonSize[0], + style=wx.TE_PROCESS_ENTER) + class ContentDialog(wx.Dialog): def __init__(self, parent, value): # Load from resource @@ -612,9 +608,7 @@ class ParamContent(PPanel): sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) self.button = wx.Button(self, self.ID_BUTTON_EDIT, 'Edit...', size=buttonSize) sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL) - self.SetAutoLayout(True) self.SetSizer(sizer) - sizer.Fit(self) self.textModified = False wx.EVT_BUTTON(self, self.ID_BUTTON_EDIT, self.OnButtonEdit) wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange) @@ -625,8 +619,7 @@ class ParamContent(PPanel): if self.textModified: # text has newer value try: return self.text.GetValue().split('|') - except SyntaxError: - wx.LogError('Syntax error in parameter value: ' + self.GetName()) + except ValueError: return [] return self.value def SetValue(self, value): @@ -648,6 +641,9 @@ class ParamContent(PPanel): self.SetModified() self.textModified = False dlg.Destroy() + def SetModified(self, state=True): + PPanel.SetModified(self, state) + self.textModified = False # CheckList content class ParamContentCheckList(ParamContent): @@ -728,8 +724,7 @@ class ParamIntList(ParamContent): if self.textModified: # text has newer value try: self.value = map(int, self.text.GetValue().split('|')) - except SyntaxError: - wx.LogError('Syntax error in parameter value: ' + self.GetName()) + except ValueError: self.value = [] dlg = IntListDialog(self, self.value) if dlg.ShowModal() == wx.ID_OK: @@ -752,9 +747,7 @@ class RadioBox(PPanel): button = wx.RadioButton(self, -1, i, size=(-1,buttonSize[1]), name=i) topSizer.Add(button, 0, wx.RIGHT, 5) wx.EVT_RADIOBUTTON(self, button.GetId(), self.OnRadioChoice) - self.SetAutoLayout(True) self.SetSizer(topSizer) - topSizer.Fit(self) def SetStringSelection(self, value): self.freeze = True for i in self.choices: @@ -812,9 +805,7 @@ class ParamFile(PPanel): sizer.Add(self.text, 0, wx.RIGHT | wx.ALIGN_CENTER_VERTICAL, 5) self.button = wx.Button(self, self.ID_BUTTON_BROWSE, 'Browse...',size=buttonSize) sizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL) - self.SetAutoLayout(True) self.SetSizer(sizer) - sizer.Fit(self) self.textModified = False wx.EVT_BUTTON(self, self.ID_BUTTON_BROWSE, self.OnButtonBrowse) wx.EVT_TEXT(self, self.ID_TEXT_CTRL, self.OnChange) @@ -941,5 +932,6 @@ paramDict = { 'fg': ParamColour, 'bg': ParamColour, 'font': ParamFont, 'enabled': ParamBool, 'focused': ParamBool, 'hidden': ParamBool, 'tooltip': ParamText, 'bitmap': ParamBitmap, 'icon': ParamBitmap, - 'encoding': ParamEncoding, 'borders': ParamUnit + 'encoding': ParamEncoding, 'borders': ParamUnit, + 'comment': ParamComment } diff --git a/wxPython/wx/tools/XRCed/tools.py b/wxPython/wx/tools/XRCed/tools.py index e0e3ac86d2..45687f850a 100644 --- a/wxPython/wx/tools/XRCed/tools.py +++ b/wxPython/wx/tools/XRCed/tools.py @@ -87,11 +87,11 @@ class Tools(wx.Panel): (ID_NEW.UNKNOWN, images.getToolUnknownBitmap())] ] + self.boxes = {} for grp in groups: self.AddGroup(grp[0]) for b in grp[1:]: self.AddButton(b[0], b[1], g.pullDownMenu.createMap[b[0]]) - self.SetAutoLayout(True) self.SetSizerAndFit(self.sizer) # Allow to be resized in vertical direction only self.SetSizeHints(self.GetSize()[0], -1) @@ -114,13 +114,19 @@ class Tools(wx.Panel): def AddGroup(self, name): # Each group is inside box - box = wx.StaticBox(self, -1, name, style=wx.WANTS_CHARS) + id = wx.NewId() + box = wx.StaticBox(self, id, '[+] '+name, style=wx.WANTS_CHARS) + box.show = True + box.name = name + box.gnum = len(self.groups) box.SetFont(g.smallerFont()) + box.Bind(wx.EVT_LEFT_DOWN, self.OnClickBox) boxSizer = wx.StaticBoxSizer(box, wx.VERTICAL) boxSizer.Add((0, 4)) + self.boxes[id] = box self.curSizer = wx.GridSizer(0, 3) boxSizer.Add(self.curSizer) - self.sizer.Add(boxSizer, 0, wx.TOP | wx.LEFT | wx.RIGHT, 4) + self.sizer.Add(boxSizer, 0, wx.TOP | wx.LEFT | wx.RIGHT | wx.EXPAND, 4) self.groups.append((box,{})) # Enable/disable group @@ -129,6 +135,12 @@ class Tools(wx.Panel): grp[0].Enable(enable) for b in grp[1].values(): b.Enable(enable) + # Show/hide group + def ShowGroup(self, gnum, show = True): + grp = self.groups[gnum] + grp[0].show = show + for b in grp[1].values(): b.Show(show) + # Enable/disable group item def EnableGroupItem(self, gnum, id, enable = True): grp = self.groups[gnum] @@ -140,6 +152,14 @@ class Tools(wx.Panel): for id in ids: grp[1][id].Enable(enable) + def OnClickBox(self, evt): + box = self.boxes[evt.GetId()] + # Collapse/restore static box, change label + self.ShowGroup(box.gnum, not box.show) + if box.show: box.SetLabel('[+] ' + box.name) + else: box.SetLabel('[-] ' + box.name) + self.Layout() + # Process key events def OnKeyDown(self, evt): if evt.GetKeyCode() == wx.WXK_CONTROL: diff --git a/wxPython/wx/tools/XRCed/tree.py b/wxPython/wx/tools/XRCed/tree.py index c08b451fd4..f384b15da5 100644 --- a/wxPython/wx/tools/XRCed/tree.py +++ b/wxPython/wx/tools/XRCed/tree.py @@ -86,10 +86,12 @@ class ID_NEW: CHOICEBOOK = wx.NewId() LISTBOOK = wx.NewId() SPLITTER_WINDOW = wx.NewId() + GRID = wx.NewId() SCROLLED_WINDOW = wx.NewId() HTML_WINDOW = wx.NewId() CALENDAR_CTRL = wx.NewId() DATE_CTRL = wx.NewId() + FILE_PICKER_CTRL = wx.NewId() GENERIC_DIR_CTRL = wx.NewId() SPIN_CTRL = wx.NewId() UNKNOWN = wx.NewId() @@ -124,6 +126,10 @@ class ID_NEW: CONTEXT_HELP_BUTTON = wx.NewId() REF = wx.NewId() + COMMENT = wx.NewId() + + CUSTOM = wx.NewId() + for i in range(99): wx.NewId() # reserve IDs for custom controls LAST = wx.NewId() @@ -193,10 +199,12 @@ class PullDownMenu: ID_NEW.CHOICEBOOK: 'wxChoicebook', ID_NEW.LISTBOOK: 'wxListbook', ID_NEW.SPLITTER_WINDOW: 'wxSplitterWindow', + ID_NEW.GRID: 'wxGrid', ID_NEW.SCROLLED_WINDOW: 'wxScrolledWindow', ID_NEW.HTML_WINDOW: 'wxHtmlWindow', ID_NEW.CALENDAR_CTRL: 'wxCalendarCtrl', ID_NEW.DATE_CTRL: 'wxDatePickerCtrl', + ID_NEW.FILE_PICKER_CTRL: 'wxFilePickerCtrl', ID_NEW.GENERIC_DIR_CTRL: 'wxGenericDirCtrl', ID_NEW.SPIN_CTRL: 'wxSpinCtrl', @@ -268,10 +276,12 @@ class PullDownMenu: (ID_NEW.SCROLL_BAR, 'ScrollBar', 'Create scroll bar'), (ID_NEW.TREE_CTRL, 'TreeCtrl', 'Create tree'), (ID_NEW.LIST_CTRL, 'ListCtrl', 'Create list'), +# (ID_NEW.GRID, 'Grid', 'Create grid'), (ID_NEW.SCROLLED_WINDOW, 'ScrolledWindow', 'Create scrolled window'), (ID_NEW.HTML_WINDOW, 'HtmlWindow', 'Create HTML window'), (ID_NEW.CALENDAR_CTRL, 'CalendarCtrl', 'Create calendar control'), (ID_NEW.DATE_CTRL, 'DatePickerCtrl', 'Create date picker control'), +# (ID_NEW.FILE_PICKER_CTRL, 'FilePickerCtrl', 'Create file picker control'), (ID_NEW.GENERIC_DIR_CTRL, 'GenericDirCtrl', 'Create generic dir control'), (ID_NEW.UNKNOWN, 'Unknown', 'Create custom control placeholder'), ], @@ -370,7 +380,13 @@ class PullDownMenu: ID_NEW.HELP_BUTTON: ('wxID_HELP', '&Help'), ID_NEW.CONTEXT_HELP_BUTTON: ('wxID_CONTEXT_HELP', '&Help'), } - + self.custom = ['custom', 'User-defined controls'] + self.customMap = {} + + def addCustom(self, klass): + n = len(self.custom)-2 + self.custom.append((ID_NEW.CUSTOM + n, klass)) + self.customMap[ID_NEW.CUSTOM + n] = klass ################################################################################ @@ -409,6 +425,7 @@ class HighLightBox: l4 = wx.Window(w, -1, wx.Point(pos.x, pos.y + size.height - 2), wx.Size(size.width, 2)) l4.SetBackgroundColour(wx.RED) self.lines = [l1, l2, l3, l4] + self.size = size # Move highlight to a new position def Replace(self, pos, size): if size.width == -1: size.width = 0 @@ -417,6 +434,7 @@ class HighLightBox: self.lines[1].SetDimensions(pos.x, pos.y, 2, size.height) self.lines[2].SetDimensions(pos.x + size.width - 2, pos.y, 2, size.height) self.lines[3].SetDimensions(pos.x, pos.y + size.height - 2, size.width, 2) + self.size = size # Remove it def Remove(self): map(wx.Window.Destroy, self.lines) @@ -428,8 +446,12 @@ class HighLightBox: class XML_Tree(wx.TreeCtrl): def __init__(self, parent, id): - wx.TreeCtrl.__init__(self, parent, id, style = wx.TR_HAS_BUTTONS | wx.TR_MULTIPLE) + wx.TreeCtrl.__init__(self, parent, id, + style = wx.TR_HAS_BUTTONS | wx.TR_MULTIPLE | wx.TR_EDIT_LABELS) self.SetBackgroundColour(wx.Colour(224, 248, 224)) + self.fontComment = wx.FFont(self.GetFont().GetPointSize(), + self.GetFont().GetFamily(), + wx.FONTFLAG_ITALIC) # Register events wx.EVT_TREE_SEL_CHANGED(self, self.GetId(), self.OnSelChanged) # One works on Linux, another on Windows @@ -440,6 +462,8 @@ class XML_Tree(wx.TreeCtrl): wx.EVT_RIGHT_DOWN(self, self.OnRightDown) wx.EVT_TREE_ITEM_EXPANDED(self, self.GetId(), self.OnItemExpandedCollapsed) wx.EVT_TREE_ITEM_COLLAPSED(self, self.GetId(), self.OnItemExpandedCollapsed) + self.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.OnBeginLabelEdit) + self.Bind(wx.EVT_TREE_END_LABEL_EDIT, self.OnEndLabelEdit) self.selection = None self.selectionChanging = False @@ -450,6 +474,7 @@ class XML_Tree(wx.TreeCtrl): # Create image list il = wx.ImageList(16, 16, True) self.rootImage = il.Add(images.getTreeRootImage().Scale(16,16).ConvertToBitmap()) + xxxComment.image = il.Add(images.getTreeCommentImage().Scale(16,16).ConvertToBitmap()) xxxObject.image = il.Add(images.getTreeDefaultImage().Scale(16,16).ConvertToBitmap()) xxxPanel.image = il.Add(images.getTreePanelImage().Scale(16,16).ConvertToBitmap()) xxxDialog.image = il.Add(images.getTreeDialogImage().Scale(16,16).ConvertToBitmap()) @@ -560,19 +585,22 @@ class XML_Tree(wx.TreeCtrl): item = self.AppendItem(itemParent, treeObj.treeName(), image=treeObj.treeImage(), data=wx.TreeItemData(xxx)) - # Different color for references - if treeObj.ref: + # Different color for comments and references + if xxx.className == 'comment': + self.SetItemTextColour(item, 'Blue') + self.SetItemFont(item, self.fontComment) + elif treeObj.ref: self.SetItemTextColour(item, 'DarkGreen') elif treeObj.hasStyle and treeObj.params.get('hidden', False): self.SetItemTextColour(item, 'Grey') # Try to find children objects if treeObj.hasChildren: - nodes = treeObj.element.childNodes[:] + nodes = treeObj.node.childNodes[:] for n in nodes: if IsObject(n): self.AddNode(item, treeObj, n) elif n.nodeType != minidom.Node.ELEMENT_NODE: - treeObj.element.removeChild(n) + treeObj.node.removeChild(n) n.unlink() # Insert new item at specific position @@ -581,23 +609,30 @@ class XML_Tree(wx.TreeCtrl): xxx = MakeXXXFromDOM(parent, elem) # If nextItem is None, we append to parent, otherwise insert before it if nextItem.IsOk(): - node = self.GetPyData(nextItem).element - parent.element.insertBefore(elem, node) + node = self.GetPyData(nextItem).node + parent.node.insertBefore(elem, node) # Inserting before is difficult, se we insert after or first child index = self.ItemIndex(nextItem) newItem = self.InsertItemBefore(itemParent, index, xxx.treeName(), image=xxx.treeImage()) self.SetPyData(newItem, xxx) else: - parent.element.appendChild(elem) + parent.node.appendChild(elem) newItem = self.AppendItem(itemParent, xxx.treeName(), image=xxx.treeImage(), data=wx.TreeItemData(xxx)) - # Different color for references - if xxx.treeObject().ref: self.SetItemTextColour(newItem, 'DarkGreen') + treeObj = xxx.treeObject() + # Different color for references and comments + if xxx.className == 'comment': + self.SetItemTextColour(newItem, 'Blue') + self.SetItemFont(newItem, self.fontComment) + elif treeObj.ref: + self.SetItemTextColour(newItem, 'DarkGreen') + elif treeObj.hasStyle and treeObj.params.get('hidden', False): + self.SetItemTextColour(newItem, 'Grey') # Add children items if xxx.hasChildren: treeObj = xxx.treeObject() - for n in treeObj.element.childNodes: + for n in treeObj.node.childNodes: if IsObject(n): self.AddNode(newItem, treeObj, n) return newItem @@ -605,13 +640,14 @@ class XML_Tree(wx.TreeCtrl): # Remove leaf of tree, return it's data object def RemoveLeaf(self, leaf): xxx = self.GetPyData(leaf) - node = xxx.element + node = xxx.node parent = node.parentNode parent.removeChild(node) self.Delete(leaf) # Reset selection object self.selection = None return node + # Find position relative to the top-level window def FindNodePos(self, item, obj=None): # Root at (0,0) @@ -631,17 +667,18 @@ class XML_Tree(wx.TreeCtrl): if g.testWin.highLight: g.testWin.highLight.Remove() break - # Find first ancestor which is a wxWindow (not a sizer) + # For sizers and notebooks we must select the first window-like parent winParent = itemParent while self.GetPyData(winParent).isSizer: winParent = self.GetItemParent(winParent) # Notebook children are layed out in a little strange way - if self.GetPyData(itemParent).treeObject().__class__ == xxxNotebook: - parentPos = wx.Point(0,0) - else: - parentPos = self.FindNodePos(winParent) - # Position (-1,-1) is really (0,0) + # wxGTK places NB panels relative to the NB parent + if wx.Platform == '__WXGTK__': + if self.GetPyData(itemParent).treeObject().__class__ == xxxNotebook: + winParent = self.GetItemParent(winParent) + parentPos = self.FindNodePos(winParent) pos = obj.GetPosition() + # Position (-1,-1) is really (0,0) if pos == (-1,-1): pos = (0,0) return parentPos + pos @@ -700,7 +737,6 @@ class XML_Tree(wx.TreeCtrl): # If some data was modified, apply changes if g.panel.IsModified(): self.Apply(xxx, oldItem) - #if conf.autoRefresh: if g.testWin: if g.testWin.highLight: g.testWin.highLight.Remove() @@ -747,16 +783,22 @@ class XML_Tree(wx.TreeCtrl): if not obj or xxx.hasStyle and xxx.params.get('hidden', False): if g.testWin.highLight: g.testWin.highLight.Remove() return - pos = self.FindNodePos(item, obj) + pos = self.FindNodePos(item, obj) size = obj.GetSize() # Highlight # Negative positions are not working quite well - if g.testWin.highLight: - g.testWin.highLight.Replace(pos, size) + hl = g.testWin.highLight + # If highlight object has the same size SetDimension does not repaint it + # so we must remove the old HL window + if hl and hl.size == size: + hl.Remove() + hl = None + if hl: + hl.Replace(pos, size) else: - g.testWin.highLight = HighLightBox(pos, size) - g.testWin.highLight.Refresh() - g.testWin.highLight.item = item + g.testWin.highLight = hl = HighLightBox(pos, size) + hl.Refresh() + hl.item = item def ShowTestWindow(self, item): xxx = self.GetPyData(item) @@ -774,7 +816,7 @@ class XML_Tree(wx.TreeCtrl): return # Show item in bold if g.testWin: # Reset old - self.Unselect() + self.UnselectAll() self.SetItemBold(g.testWin.item, False) try: wx.BeginBusyCursor() @@ -810,19 +852,6 @@ class XML_Tree(wx.TreeCtrl): testWin = g.testWin # Create a window with this resource xxx = self.GetPyData(item).treeObject() - - # If frame -# if xxx.__class__ == xxxFrame: - # Frame can't have many children, - # but it's first child possibly can... -# child = self.GetFirstChild(item)[0] -# if child.IsOk() and self.GetPyData(child).__class__ == xxxPanel: -# # Clean-up before recursive call or error -# wx.MemoryFSHandler.RemoveFile('xxx.xrc') -# wx.EndBusyCursor() -# self.CreateTestWin(child) -# return - # Close old window, remember where it was highLight = None if testWin: @@ -848,7 +877,7 @@ class XML_Tree(wx.TreeCtrl): # Save in memory FS memFile = MemoryFile('xxx.xrc') # Create memory XML file - elem = xxx.element.cloneNode(True) + elem = xxx.node.cloneNode(True) if not xxx.name: name = 'noname' else: @@ -877,6 +906,10 @@ class XML_Tree(wx.TreeCtrl): if not g.currentEncoding: xmlFlags != xrc.XRC_USE_LOCALE res = xrc.XmlResource('', xmlFlags) + xrc.XmlResource.Set(res) # set as global + # Register handlers + addHandlers() + # Same module list res.Load('memory:xxx.xrc') try: if xxx.__class__ == xxxFrame: @@ -907,7 +940,7 @@ class XML_Tree(wx.TreeCtrl): testWin.SetClientSize(testWin.GetBestSize()) testWin.Show(True) elif xxx.__class__ == xxxDialog: - testWin = g.testWin = res.LoadDialog(None, STD_NAME) + testWin = g.testWin = res.LoadDialog(g.frame, STD_NAME) testWin.panel = testWin testWin.Layout() testWin.SetPosition(pos) @@ -917,7 +950,7 @@ class XML_Tree(wx.TreeCtrl): wx.EVT_BUTTON(testWin, wx.ID_CANCEL, self.OnCloseTestWin) elif xxx.__class__ == xxxWizard: wiz = wx.wizard.PreWizard() - res.LoadOnObject(wiz, None, STD_NAME, 'wxWizard') + res.LoadOnObject(wiz, g.frame, STD_NAME, 'wxWizard') # Find first page (don't know better way) firstPage = None for w in wiz.GetChildren(): @@ -959,9 +992,11 @@ class XML_Tree(wx.TreeCtrl): testWin.toolBar = res.LoadToolBar(testWin, STD_NAME) testWin.SetToolBar(testWin.toolBar) testWin.Show(True) + # Catch some events, set highlight if testWin: testWin.item = item wx.EVT_CLOSE(testWin, self.OnCloseTestWin) + wx.EVT_SIZE(testWin, self.OnSizeTestWin) testWin.highLight = None if highLight and not self.pendingHighLight: self.HighLight(highLight) @@ -974,6 +1009,9 @@ class XML_Tree(wx.TreeCtrl): inf = sys.exc_info() wx.LogError(traceback.format_exception(inf[0], inf[1], None)[-1]) wx.LogError('Error loading resource') + # Cleanup + res.Unload('xxx.xrc') + xrc.XmlResource.Set(None) wx.MemoryFSHandler.RemoveFile('xxx.xrc') def CloseTestWindow(self): @@ -987,6 +1025,11 @@ class XML_Tree(wx.TreeCtrl): def OnCloseTestWin(self, evt): self.CloseTestWindow() + def OnSizeTestWin(self, evt): + if g.testWin.highLight: + self.HighLight(g.testWin.highLight.item) + evt.Skip() + # Return index in parent, for real window children def WindowIndex(self, item): n = 0 # index of sibling @@ -1068,6 +1111,7 @@ class XML_Tree(wx.TreeCtrl): SetMenu(m, pullDownMenu.topLevel) m.AppendSeparator() m.Append(ID_NEW.REF, 'reference...', 'Create object_ref node') + m.Append(ID_NEW.COMMENT, 'comment', 'Create comment node') else: xxx = self.GetPyData(item).treeObject() # Check parent for possible child nodes if inserting sibling @@ -1089,8 +1133,12 @@ class XML_Tree(wx.TreeCtrl): m.Enable(ID_NEW.SPACER, False) if xxx.__class__ is not xxxFrame: m.Enable(ID_NEW.MENU_BAR, False) + # Add custom controls menu + if len(pullDownMenu.custom) > 2: + SetMenu(m, [pullDownMenu.custom]) m.AppendSeparator() m.Append(ID_NEW.REF, 'reference...', 'Create object_ref node') + m.Append(ID_NEW.COMMENT, 'comment', 'Create comment node') # Select correct label for create menu if not needInsert: if self.shift: @@ -1126,11 +1174,12 @@ class XML_Tree(wx.TreeCtrl): SetMenu(m, pullDownMenu.sizers, shift=True) else: SetMenu(m, pullDownMenu.controls, shift=True) - id = wx.NewId() - menu.AppendMenu(id, 'Replace With', m) - if not m.GetMenuItemCount(): menu.Enable(id, False) - menu.Append(pullDownMenu.ID_SUBCLASS, 'Subclass...', - 'Set "subclass" property') + if xxx.isElement: + id = wx.NewId() + menu.AppendMenu(id, 'Replace With', m) + if not m.GetMenuItemCount(): menu.Enable(id, False) + menu.Append(pullDownMenu.ID_SUBCLASS, 'Subclass...', + 'Set "subclass" property') menu.AppendSeparator() # Not using standart IDs because we don't want to show shortcuts menu.Append(wx.ID_CUT, 'Cut', 'Cut to the clipboard') @@ -1165,9 +1214,25 @@ class XML_Tree(wx.TreeCtrl): # Item width may have changed # !!! Tric to update tree width (wxGTK, ??) self.SetIndent(self.GetIndent()) + elif xxx.className == 'comment': + self.SetItemText(item, xxx.treeName()) # Change tree icon for sizers if isinstance(xxx, xxxBoxSizer): self.SetItemImage(item, xxx.treeImage()) # Set global modified state g.frame.SetModified() + def OnBeginLabelEdit(self, evt): + xxx = self.GetPyData(evt.GetItem()) + if xxx.isElement: + evt.Veto() + else: + evt.Skip() + + def OnEndLabelEdit(self, evt): + xxx = self.GetPyData(evt.GetItem()) + node = xxx.node + if not xxx.isElement: + node.data = evt.GetLabel() + g.panel.SetData(xxx) + evt.Skip() diff --git a/wxPython/wx/tools/XRCed/undo.py b/wxPython/wx/tools/XRCed/undo.py index a064264b94..4b28a76c38 100644 --- a/wxPython/wx/tools/XRCed/undo.py +++ b/wxPython/wx/tools/XRCed/undo.py @@ -134,11 +134,11 @@ class UndoReplace: item = g.tree.ItemAtFullIndex(self.itemIndex) xxx = g.tree.GetPyData(item) # Replace with old element - parent = xxx.parent.element + parent = xxx.parent.node if xxx is self.xxx: # sizeritem or notebookpage - replace child - parent.replaceChild(self.xxx.child.element, xxx.child.element) + parent.replaceChild(self.xxx.child.node, xxx.child.node) else: - parent.replaceChild(self.xxx.element, xxx.element) + parent.replaceChild(self.xxx.node, xxx.node) self.xxx.parent = xxx.parent xxx = self.xxx g.tree.SetPyData(item, xxx) @@ -191,9 +191,9 @@ class UndoMove: ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \ (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \ not (parent.isSizer or isinstance(parent, xxxNotebook))): - elem.removeChild(xxx.child.element) # detach child + elem.removeChild(xxx.child.node) # detach child elem.unlink() # delete child container - elem = xxx.child.element # replace + elem = xxx.child.node # replace # This may help garbage collection xxx.child.parent = None isChildContainer = False @@ -227,9 +227,9 @@ class UndoMove: ((parent.isSizer and not isinstance(xxx, xxxSizerItem)) or \ (isinstance(parent, xxxNotebook) and not isinstance(xxx, xxxNotebookPage)) or \ not (parent.isSizer or isinstance(parent, xxxNotebook))): - elem.removeChild(xxx.child.element) # detach child + elem.removeChild(xxx.child.node) # detach child elem.unlink() # delete child container - elem = xxx.child.element # replace + elem = xxx.child.node # replace # This may help garbage collection xxx.child.parent = None isChildContainer = False diff --git a/wxPython/wx/tools/XRCed/xrced.py b/wxPython/wx/tools/XRCed/xrced.py index 92e855b9f2..9fa72fa521 100644 --- a/wxPython/wx/tools/XRCed/xrced.py +++ b/wxPython/wx/tools/XRCed/xrced.py @@ -40,9 +40,14 @@ if __name__ == '__main__': else: basePath = os.path.dirname(__file__) +# Remember system path +sys_path = sys.path + # 1 adds CMD command to Help menu debug = 0 +import xxx + g.helpText = """\
@@ -51,7 +56,7 @@ select "Append Child", and then any command.
Or just press one of the buttons on the tools palette.
Enter XML ID, change properties, create children.
To test your interface select Test command (View menu).
-Consult README file for the details. +Consult README.txt file for the details.