2 # Purpose: XRC editor, main module
3 # Author: Roman Rolinsky <rolinsky@mema.ucl.ac.be>
7 from wxPython
.wx
import *
8 from wxPython
.xrc
import *
9 from wxPython
.html
import *
10 from xml
.dom
import minidom
19 # Return code from wxGetOsVersion
22 if wxGetOsVersion()[0] == wxGTK
:
23 labelFont
= wxFont(12, wxDEFAULT
, wxNORMAL
, wxBOLD
)
24 modernFont
= wxFont(12, wxMODERN
, wxNORMAL
, wxNORMAL
)
26 labelFont
= wxFont(10, wxDEFAULT
, wxNORMAL
, wxBOLD
)
27 modernFont
= wxFont(10, wxMODERN
, wxNORMAL
, wxNORMAL
)
37 testWinPos
= wxDefaultPosition
39 # 1 adds CMD command to Help menu
43 <HTML><H2>Welcome to XRCed!</H2><H3><font color="green">DON'T PANIC :)</font></H3>
44 To start select tree root, then popup menu with your right mouse button,
45 select "Append Child", and then any command.<P>
46 Enter XML ID, change properties, create children.<P>
47 To test your interface select Test command (View menu).<P>
48 Consult README file for the details.</HTML>
51 defaultIDs
= {xxxPanel
:'PANEL', xxxDialog
:'DIALOG', xxxFrame
:'FRAME',
52 xxxMenuBar
:'MENUBAR', xxxMenu
:'MENU', xxxToolBar
:'TOOLBAR'}
54 # Set menu to list items.
55 # Each menu command is a tuple (id, label, help)
56 # submenus are lists [id, label, help, submenu]
57 # and separators are any other type
60 if type(l
) == types
.TupleType
:
62 elif type(l
) == types
.ListType
:
64 SetMenu(subMenu
, l
[2:])
65 m
.AppendMenu(wxNewId(), l
[0], subMenu
, l
[1])
69 ################################################################################
71 # Properties panel containing notebook
72 class Panel(wxNotebook
):
73 def __init__(self
, parent
, id = -1):
74 wxNotebook
.__init
__(self
, parent
, id, style
=wxNB_BOTTOM
)
75 sys
.modules
['params'].panel
= self
76 # List of child windows
78 # Create scrolled windows for pages
79 self
.page1
= wxScrolledWindow(self
, -1)
81 sizer
.Add(wxBoxSizer()) # dummy sizer
82 self
.page1
.SetAutoLayout(true
)
83 self
.page1
.SetSizer(sizer
)
84 self
.AddPage(self
.page1
, 'Properties')
86 self
.page2
= wxScrolledWindow(self
, -1)
88 sizer
.Add(wxBoxSizer()) # dummy sizer
89 self
.page2
.SetAutoLayout(true
)
90 self
.page2
.SetSizer(sizer
)
91 # Cache for already used panels
92 self
.pageCache
= {} # cached property panels
93 self
.stylePageCache
= {} # cached style panels
94 # Dummy parent window for cache pages
95 self
.cacheParent
= wxFrame(None, -1, 'non visible')
96 # Delete child windows and recreate page sizer
97 def ResetPage(self
, page
):
98 topSizer
= page
.GetSizer()
99 sizer
= topSizer
.GetChildren()[0].GetSizer()
100 for w
in page
.GetChildren():
101 sizer
.RemoveWindow(w
)
102 if isinstance(w
, ParamPage
):
103 # With SetParent, we wouldn't need this
104 w
.Reparent(self
.cacheParent
)
107 topSizer
.RemoveSizer(sizer
)
109 sizer
= wxBoxSizer(wxVERTICAL
)
110 # Special case - resize html window
112 topSizer
.Add(sizer
, 1, wxEXPAND
)
114 topSizer
.Add(sizer
, 0, wxALL
, 5)
116 def SetData(self
, xxx
):
119 # Set cached or new page
120 # Remove current objects and sizer
121 sizer
= self
.ResetPage(self
.page1
)
122 if not xxx
or (not xxx
.allParams
and not xxx
.hasName
):
124 sizer
.Add(wxStaticText(self
.page1
, -1, 'This item has no properties.'))
125 else: # nothing selected
126 # If first time, show some help
128 html
= wxHtmlWindow(self
.page1
, -1, wxDefaultPosition
,
129 wxDefaultSize
, wxSUNKEN_BORDER
)
130 html
.SetPage(helpText
)
131 sizer
.Add(html
, 1, wxEXPAND
)
134 sizer
.Add(wxStaticText(self
.page1
, -1, 'Select a tree item.'))
136 SetCurrentXXX(xxx
.treeObject())
138 page
= self
.pageCache
[xxx
.__class
__]
139 page
.Reparent(self
.page1
)
141 page
= PropPage(self
.page1
, xxx
.className
, xxx
)
142 self
.pageCache
[xxx
.__class
__] = page
144 self
.pages
.append(page
)
145 sizer
.Add(page
, 1, wxEXPAND
)
147 # Special label for child objects - they may have different GUI
148 cacheID
= (xxx
.child
.__class
__, xxx
.__class
__)
150 page
= self
.pageCache
[cacheID
]
151 page
.Reparent(self
.page1
)
153 page
= PropPage(self
.page1
, xxx
.child
.className
, xxx
.child
)
154 self
.pageCache
[cacheID
] = page
155 page
.SetValues(xxx
.child
)
156 self
.pages
.append(page
)
157 sizer
.Add(page
, 0, wxEXPAND | wxTOP
, 5)
159 size
= self
.page1
.GetSizer().GetMinSize()
160 self
.page1
.SetScrollbars(1, 1, size
.x
, size
.y
, 0, 0, true
)
163 # Create if does not exist
164 if xxx
and xxx
.treeObject().hasStyle
:
165 xxx
= xxx
.treeObject()
166 # Simplest case: set data if class is the same
167 sizer
= self
.ResetPage(self
.page2
)
169 page
= self
.stylePageCache
[xxx
.__class
__]
170 page
.Reparent(self
.page2
)
172 page
= StylePage(self
.page2
, xxx
.className
+ ' style', xxx
)
173 self
.stylePageCache
[xxx
.__class
__] = page
175 self
.pages
.append(page
)
176 sizer
.Add(page
, 0, wxEXPAND
)
177 # Add page if not exists
178 if not self
.GetPageCount() == 2:
179 self
.AddPage(self
.page2
, 'Style')
181 size
= self
.page2
.GetSizer().GetMinSize()
182 self
.page2
.SetScrollbars(1, 1, size
.x
, size
.y
, 0, 0, true
)
184 # Remove page if exists
185 if self
.GetPageCount() == 2:
189 # Check if some parameter on some page has changed
190 def IsModified(self
):
192 if p
.IsModified(): return true
194 # Reset changed state
195 def SetModified(self
, value
):
196 for p
in self
.pages
: p
.SetModified(value
)
198 for p
in self
.pages
: p
.Apply()
200 ################################################################################
202 # General class for notebook pages
203 class ParamPage(wxPanel
):
204 def __init__(self
, parent
, xxx
):
205 wxPanel
.__init
__(self
, parent
, -1)
207 # Register event handlers
208 for id in paramIDs
.values():
209 EVT_CHECKBOX(self
, id, self
.OnCheckParams
)
210 self
.modified
= false
212 self
.controls
= {} # save python objects
213 self
.controlName
= None
214 def OnCheckParams(self
, evt
):
216 param
= evt
.GetEventObject().GetName()
217 w
= self
.controls
[param
]
218 objElem
= xxx
.element
220 # Ad new text node in order of allParams
221 w
.SetValue('') # set empty (default) value
222 w
.SetModified() # mark as changed
223 elem
= tree
.dom
.createElement(param
)
224 # Some classes are special
226 xxx
.params
[param
] = xxxParamFont(xxx
.element
, elem
)
228 xxx
.params
[param
] = xxxParam(elem
)
229 # Find place to put new element: first present element after param
231 paramStyles
= xxx
.allParams
+ xxx
.styles
232 for p
in paramStyles
[paramStyles
.index(param
) + 1:]:
233 # Content params don't have same type
234 if xxx
.params
.has_key(p
) and p
!= 'content':
238 nextTextElem
= xxx
.params
[p
].node
239 objElem
.insertBefore(elem
, nextTextElem
)
241 objElem
.appendChild(elem
)
244 xxx
.params
[param
].remove()
245 del xxx
.params
[param
]
247 w
.modified
= false
# mark as not changed
249 self
.SetModified(true
)
250 w
.Enable(evt
.IsChecked())
251 # If some parameter has changed
252 def IsModified(self
):
254 def SetModified(self
, value
):
255 self
.modified
= value
259 # if xxx.undo: xxx.undo.unlink()
260 # xxx.undo = xxx.element.cloneNode(false)
262 name
= self
.controlName
.GetValue()
265 xxx
.element
.setAttribute('name', name
)
266 for param
, w
in self
.controls
.items():
268 paramObj
= xxx
.params
[param
]
270 if param
in xxx
.specials
:
271 xxx
.setSpecial(param
, value
)
273 paramObj
.update(value
)
275 ################################################################################
277 # Panel for displaying properties
278 class PropPage(ParamPage
):
279 def __init__(self
, parent
, label
, xxx
):
280 ParamPage
.__init
__(self
, parent
, xxx
)
281 box
= wxStaticBox(self
, -1, label
)
282 box
.SetFont(labelFont
)
283 topSizer
= wxStaticBoxSizer(box
, wxVERTICAL
)
284 sizer
= wxFlexGridSizer(len(xxx
.allParams
), 2, 1, 1)
286 label
= wxStaticText(self
, -1, 'XML ID:', size
=(100,-1))
287 control
= ParamText(self
, name
='XML_name')
288 sizer
.AddMany([ (label
, 0, wxALIGN_CENTER_VERTICAL
),
289 (control
, 0, wxALIGN_CENTER_VERTICAL
) ])
290 self
.controlName
= control
291 for param
in xxx
.allParams
:
292 present
= param
in xxx
.params
293 if param
in xxx
.required
:
294 label
= wxStaticText(self
, paramIDs
[param
], param
+ ':',
295 size
= (100,-1), name
= param
)
297 # Notebook has one very loooooong parameter
298 if param
== 'usenotebooksizer': sParam
= 'usesizer:'
299 else: sParam
= param
+ ':'
300 label
= wxCheckBox(self
, paramIDs
[param
], sParam
,
301 size
= (100,-1), name
= param
)
302 self
.checks
[param
] = label
304 typeClass
= xxx
.paramDict
[param
]
308 typeClass
= paramDict
[param
]
311 typeClass
= ParamText
312 control
= typeClass(self
, param
)
313 control
.Enable(present
)
314 sizer
.AddMany([ (label
, 0, wxALIGN_CENTER_VERTICAL
),
315 (control
, 0, wxALIGN_CENTER_VERTICAL
) ])
316 self
.controls
[param
] = control
317 topSizer
.Add(sizer
, 1, wxALL | wxEXPAND
, 3)
318 self
.SetAutoLayout(true
)
319 self
.SetSizer(topSizer
)
321 def SetValues(self
, xxx
):
323 # Set values, checkboxes to false, disable defaults
325 self
.controlName
.SetValue(xxx
.name
)
326 for param
in xxx
.allParams
:
327 w
= self
.controls
[param
]
330 value
= xxx
.params
[param
].value()
333 if not param
in xxx
.required
:
334 self
.checks
[param
].SetValue(true
)
336 self
.checks
[param
].SetValue(false
)
339 self
.SetModified(false
)
341 ################################################################################
343 # Style notebook page
344 class StylePage(ParamPage
):
345 def __init__(self
, parent
, label
, xxx
):
346 ParamPage
.__init
__(self
, parent
, xxx
)
347 box
= wxStaticBox(self
, -1, label
)
348 box
.SetFont(labelFont
)
349 topSizer
= wxStaticBoxSizer(box
, wxVERTICAL
)
350 sizer
= wxFlexGridSizer(len(xxx
.styles
), 2, 1, 1)
351 for param
in xxx
.styles
:
352 present
= param
in xxx
.params
.keys()
353 check
= wxCheckBox(self
, paramIDs
[param
],
354 param
+ ':', size
= (100,-1), name
= param
)
355 check
.SetValue(present
)
356 control
= paramDict
[param
](self
, name
= param
)
357 control
.Enable(present
)
358 sizer
.AddMany([ (check
, 0, wxALIGN_CENTER_VERTICAL
),
359 (control
, 0, wxALIGN_CENTER_VERTICAL
) ])
360 self
.checks
[param
] = check
361 self
.controls
[param
] = control
362 topSizer
.Add(sizer
, 1, wxALL | wxEXPAND
, 3)
363 self
.SetAutoLayout(true
)
364 self
.SetSizer(topSizer
)
366 # Set data for a cahced page
367 def SetValues(self
, xxx
):
369 for param
in xxx
.styles
:
370 present
= param
in xxx
.params
.keys()
371 check
= self
.checks
[param
]
372 check
.SetValue(present
)
373 control
= self
.controls
[param
]
375 control
.SetValue(xxx
.params
[param
].value())
378 control
.Enable(present
)
379 self
.SetModified(false
)
381 ################################################################################
384 def __init__(self
, pos
, size
):
386 l1
= wxWindow(w
, -1, pos
, wxSize(size
.x
, 2))
387 l1
.SetBackgroundColour(wxRED
)
388 l2
= wxWindow(w
, -1, pos
, wxSize(2, size
.y
))
389 l2
.SetBackgroundColour(wxRED
)
390 l3
= wxWindow(w
, -1, wxPoint(pos
.x
+ size
.x
- 2, pos
.y
), wxSize(2, size
.y
))
391 l3
.SetBackgroundColour(wxRED
)
392 l4
= wxWindow(w
, -1, wxPoint(pos
.x
, pos
.y
+ size
.y
- 2), wxSize(size
.x
, 2))
393 l4
.SetBackgroundColour(wxRED
)
394 self
.lines
= [l1
, l2
, l3
, l4
]
395 # Move highlight to a new position
396 def Replace(self
, pos
, size
):
397 self
.lines
[0].SetDimensions(pos
.x
, pos
.y
, size
.x
, 2, wxSIZE_ALLOW_MINUS_ONE
)
398 self
.lines
[1].SetDimensions(pos
.x
, pos
.y
, 2, size
.y
, wxSIZE_ALLOW_MINUS_ONE
)
399 self
.lines
[2].SetDimensions(pos
.x
+ size
.x
- 2, pos
.y
, 2, size
.y
,
400 wxSIZE_ALLOW_MINUS_ONE
)
401 self
.lines
[3].SetDimensions(pos
.x
, pos
.y
+ size
.y
- 2, size
.x
, 2,
402 wxSIZE_ALLOW_MINUS_ONE
)
405 map(wxWindow
.Destroy
, self
.lines
)
406 testWin
.highLight
= None
408 ################################################################################
411 def __init__(self
, name
):
414 def write(self
, data
):
415 self
.buffer += data
.encode()
417 wxMemoryFSHandler_AddFile(self
.name
, self
.buffer)
419 class XML_Tree(wxTreeCtrl
):
420 def __init__(self
, parent
, id):
421 wxTreeCtrl
.__init
__(self
, parent
, id, style
= wxTR_HAS_BUTTONS
)
422 self
.SetBackgroundColour(wxColour(224, 248, 224))
423 EVT_TREE_SEL_CHANGED(self
, self
.GetId(), self
.OnSelChanged
)
424 # One works on Linux, another on Windows
425 if wxGetOsVersion()[1] == 1:
426 EVT_TREE_ITEM_ACTIVATED(self
, self
.GetId(), self
.OnItemActivated
)
428 EVT_LEFT_DCLICK(self
, self
.OnDClick
)
429 EVT_RIGHT_DOWN(self
, self
.OnRightDown
)
431 self
.needUpdate
= false
432 self
.pendingHighLight
= None
433 self
.ctrl
= self
.shift
= false
436 il
= wxImageList(16, 16, true
)
437 self
.rootImage
= il
.AddIcon(wxIconFromXPMData(images
.getTreeRootData()))
438 xxxObject
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeDefaultData()))
439 xxxPanel
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreePanelData()))
440 xxxDialog
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeDialogData()))
441 xxxFrame
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeFrameData()))
442 xxxMenuBar
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeMenuBarData()))
443 xxxToolBar
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeToolBarData()))
444 xxxMenu
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeMenuData()))
445 xxxSizer
.imageH
= il
.AddIcon(wxIconFromXPMData(images
.getTreeSizerHData()))
446 xxxSizer
.imageV
= il
.AddIcon(wxIconFromXPMData(images
.getTreeSizerVData()))
447 xxxStaticBoxSizer
.imageH
= il
.AddIcon(wxIconFromXPMData(images
.getTreeStaticBoxSizerHData()))
448 xxxStaticBoxSizer
.imageV
= il
.AddIcon(wxIconFromXPMData(images
.getTreeStaticBoxSizerVData()))
449 xxxGridSizer
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeSizerGridData()))
450 xxxFlexGridSizer
.image
= il
.AddIcon(wxIconFromXPMData(images
.getTreeSizerFlexGridData()))
452 self
.SetImageList(il
)
455 self
.selection
= None
456 wxTreeCtrl
.Unselect(self
)
458 def ExpandAll(self
, item
):
459 if self
.ItemHasChildren(item
):
461 i
, cookie
= self
.GetFirstChild(item
, 0)
465 i
, cookie
= self
.GetNextChild(item
, cookie
)
468 def CollapseAll(self
, item
):
469 if self
.ItemHasChildren(item
):
470 i
, cookie
= self
.GetFirstChild(item
, 0)
474 i
, cookie
= self
.GetNextChild(item
, cookie
)
481 self
.DeleteAllItems()
482 # Add minimal structure
483 if self
.dom
: self
.dom
.unlink()
484 self
.dom
= minidom
.Document()
485 self
.dummyNode
= self
.dom
.createComment('dummy node')
487 self
.mainNode
= self
.dom
.createElement('resource')
488 self
.dom
.appendChild(self
.mainNode
)
489 xxx
= xxxMainNode(None, self
.mainNode
)
490 self
.root
= self
.AddRoot('XML tree', self
.rootImage
, data
=wxTreeItemData(xxx
))
491 self
.SetItemHasChildren(self
.root
)
492 self
.Expand(self
.root
)
495 # Clear old data and set new
496 def SetData(self
, dom
):
497 self
.DeleteAllItems()
498 # Add minimal structure
499 if self
.dom
: self
.dom
.unlink()
501 self
.dummyNode
= self
.dom
.createComment('dummy node')
502 # Find 'resource' child, add it's children
503 self
.mainNode
= dom
.getElementsByTagName('resource')[0]
504 xxx
= xxxMainNode(None, self
.mainNode
)
505 self
.root
= self
.AddRoot('XML tree', self
.rootImage
, data
=wxTreeItemData(xxx
))
506 self
.SetItemHasChildren(self
.root
)
507 nodes
= self
.mainNode
.childNodes
[:]
510 self
.AddNode(self
.root
, None, node
)
512 self
.mainNode
.removeChild(node
)
514 self
.Expand(self
.root
)
517 # Add tree item for given parent item if node is DOM element node with
518 # 'object' tag. xxxParent is parent xxx object
519 def AddNode(self
, itemParent
, xxxParent
, node
):
520 # Set item data to current node
522 xxx
= MakeXXXFromDOM(xxxParent
, node
)
524 print 'ERROR: MakeXXXFromDom(%s, %s)' % (xxxParent
, node
)
527 treeObj
= xxx
.treeObject()
529 item
= self
.AppendItem(itemParent
, treeObj
.treeName(),
530 image
=treeObj
.treeImage(),
531 data
=wxTreeItemData(xxx
))
532 # Try to find children objects
533 if treeObj
.hasChildren
:
534 nodes
= treeObj
.element
.childNodes
[:]
537 self
.AddNode(item
, treeObj
, n
)
538 elif n
.nodeType
!= minidom
.Node
.ELEMENT_NODE
:
539 treeObj
.element
.removeChild(n
)
541 # Remove leaf of tree, return it's data object
542 def RemoveLeaf(self
, leaf
):
543 xxx
= self
.GetPyData(leaf
)
545 parent
= node
.parentNode
546 parent
.removeChild(node
)
548 # Reset selection object
549 self
.selection
= None
551 # Find position relative to the top-level window
552 def FindNodePos(self
, item
):
554 if item
== testWin
.item
: return wxPoint(0, 0)
555 itemParent
= self
.GetItemParent(item
)
557 obj
= self
.FindNodeObject(item
)
558 if self
.GetPyData(itemParent
).treeObject().__class
__ == xxxNotebook
:
559 notebook
= self
.FindNodeObject(itemParent
)
561 for i
in range(notebook
.GetPageCount()):
562 if notebook
.GetPage(i
) == obj
:
563 if notebook
.GetSelection() != i
: notebook
.SetSelection(i
)
565 # Find first ancestor which is a wxWindow (not a sizer)
566 winParent
= itemParent
567 while self
.GetPyData(winParent
).isSizer
:
568 winParent
= self
.GetItemParent(winParent
)
569 parentPos
= self
.FindNodePos(winParent
)
570 # Position (-1,-1) is really (0,0)
571 pos
= obj
.GetPosition()
572 if pos
== (-1,-1): pos
= (0,0)
573 return parentPos
+ pos
574 # Find window (or sizer) corresponding to a tree item.
575 def FindNodeObject(self
, item
):
576 if item
== testWin
.item
: return testWin
.panel
577 itemParent
= self
.GetItemParent(item
)
578 # If top-level, return testWin (or panel if wxFrame)
579 xxx
= self
.GetPyData(item
).treeObject()
580 parentWin
= self
.FindNodeObject(itemParent
)
581 # Top-level sizer? return window's sizer
582 if xxx
.isSizer
and isinstance(parentWin
, wxWindowPtr
):
583 return parentWin
.GetSizer()
584 # Otherwise get parent's object and it's child
585 n
= 0 # index of sibling
586 prev
= self
.GetPrevSibling(item
)
588 prev
= self
.GetPrevSibling(prev
)
590 child
= parentWin
.GetChildren()[n
]
591 # Return window or sizer for sizer items
592 if child
.GetClassName() == 'wxSizerItem':
593 if child
.IsWindow(): child
= child
.GetWindow()
594 elif child
.IsSizer():
595 child
= child
.GetSizer()
596 # Test for notebook sizers
597 if isinstance(child
, wxNotebookSizerPtr
):
598 child
= child
.GetNotebook()
600 def OnSelChanged(self
, evt
):
602 # !!! problem with wxGTK - GetOldItem is Ok if nothing selected
603 #oldItem = evt.GetOldItem()
605 oldItem
= self
.selection
607 xxx
= self
.GetPyData(oldItem
)
608 # If some data was modified, apply changes
609 if panel
.IsModified():
610 self
.Apply(xxx
, oldItem
)
611 #if conf.autoRefresh:
612 if testWin
and not tree
.IsHighlatable(oldItem
):
613 if testWin
.highLight
:
614 testWin
.highLight
.Remove()
615 self
.needUpdate
= true
616 status
= 'Changes were applied'
617 frame
.SetStatusText(status
)
619 self
.selection
= evt
.GetItem()
620 if not self
.selection
.IsOk():
621 self
.selection
= None
623 xxx
= self
.GetPyData(self
.selection
)
627 panel
.SetModified(false
)
628 # Hightlighting is done in OnIdle
629 tree
.pendingHighLight
= self
.selection
630 # Check if item is in testWin subtree
631 def IsHighlatable(self
, item
):
632 if item
== testWin
.item
: return false
633 while item
!= self
.root
:
634 item
= self
.GetItemParent(item
)
635 if item
== testWin
.item
: return true
637 # Highlight selected item
638 def HighLight(self
, item
):
639 self
.pendingHighLight
= None
640 if not testWin
or self
.GetPyData(testWin
.item
).className \
641 not in ['wxDialog', 'wxPanel', 'wxFrame']:
643 # Top-level does not have highlight
644 if item
== testWin
.item
or item
== tree
.root
:
645 if testWin
.highLight
: testWin
.highLight
.Remove()
647 # If a control from another window is selected, remove highlight
648 if not self
.IsHighlatable(item
):
649 if testWin
.highLight
: testWin
.highLight
.Remove()
651 # Get window/sizer object
652 obj
, pos
= self
.FindNodeObject(item
), self
.FindNodePos(item
)
655 # Nagative positions are not working wuite well
656 if testWin
.highLight
:
657 testWin
.highLight
.Replace(pos
, size
)
659 testWin
.highLight
= HightLightBox(pos
, size
)
660 testWin
.highLight
.item
= item
661 def ShowTestWindow(self
, item
):
663 xxx
= self
.GetPyData(item
)
664 if panel
.IsModified():
665 self
.Apply(xxx
, item
) # apply changes
666 treeObj
= xxx
.treeObject()
667 if treeObj
.className
not in ['wxFrame', 'wxPanel', 'wxDialog',
668 'wxMenuBar', 'wxToolBar']:
669 wxLogMessage('No view for this element (yet)')
672 wxLogError("Can't display a noname element!")
676 self
.SetItemBold(testWin
.item
, false
)
677 self
.SetItemBold(item
)
678 self
.CreateTestWin(item
)
679 # Double-click on Linux
680 def OnItemActivated(self
, evt
):
681 if evt
.GetItem() != self
.root
:
682 self
.ShowTestWindow(evt
.GetItem())
683 # Double-click on Windows
684 def OnDClick(self
, evt
):
685 item
, flags
= self
.HitTest(evt
.GetPosition())
686 if flags
in [wxTREE_HITTEST_ONITEMBUTTON
, wxTREE_HITTEST_ONITEMLABEL
]:
687 if item
!= self
.root
: self
.ShowTestWindow(item
)
690 # (re)create test window
691 def CreateTestWin(self
, item
):
694 # Create a window with this resource
695 xxx
= self
.GetPyData(item
).treeObject()
696 # Close old window, remember where it was
699 pos
= testWin
.GetPosition()
700 if item
== testWin
.item
:
701 # Remember highlight if same top-level window
702 if testWin
.highLight
:
703 highLight
= testWin
.highLight
.item
704 # !!! if 0 is removed, refresh is broken (notebook not deleted?)
705 if xxx
.className
== 'wxPanel':
706 if testWin
.highLight
:
707 testWin
.pendingHighLight
= highLight
708 testWin
.highLight
.Remove()
709 testWin
.panel
.Destroy()
720 memFile
= MemoryFile('xxx.xrc')
721 # Create partial XML file - faster for big files
723 dom
= minidom
.Document()
724 mainNode
= dom
.createElement('resource')
725 dom
.appendChild(mainNode
)
727 # Remove temporarily from old parent
729 parent
= elem
.parentNode
730 next
= elem
.nextSibling
731 parent
.replaceChild(self
.dummyNode
, elem
)
732 # Append to new DOM, write it
733 mainNode
.appendChild(elem
)
734 dom
.writexml(memFile
)
736 mainNode
.removeChild(elem
)
738 parent
.replaceChild(elem
, self
.dummyNode
)
739 memFile
.close() # write to wxMemoryFS
740 res
= wxXmlResource('')
741 res
.Load('memory:xxx.xrc')
742 if xxx
.className
== 'wxFrame':
744 testWin
= wxPreFrame()
745 res
.LoadFrame(testWin
, frame
, xxx
.name
)
747 testWin
.CreateStatusBar()
748 testWin
.panel
= testWin
749 testWin
.SetPosition(pos
)
751 elif xxx
.className
== 'wxPanel':
754 testWin
= wxFrame(frame
, -1, 'Panel: ' + xxx
.name
, pos
=pos
)
755 testWin
.panel
= res
.LoadPanel(testWin
, xxx
.name
)
756 testWin
.SetClientSize(testWin
.panel
.GetSize())
758 elif xxx
.className
== 'wxDialog':
760 testWin
= res
.LoadDialog(None, xxx
.name
)
761 testWin
.panel
= testWin
763 testWin
.SetPosition(pos
)
765 elif xxx
.className
== 'wxMenuBar':
766 testWin
= wxFrame(frame
, -1, 'MenuBar: ' + xxx
.name
, pos
=pos
)
768 # Set status bar to display help
769 testWin
.CreateStatusBar()
770 testWin
.menuBar
= res
.LoadMenuBar(xxx
.name
)
771 testWin
.SetMenuBar(testWin
.menuBar
)
773 elif xxx
.className
== 'wxToolBar':
774 testWin
= wxFrame(frame
, -1, 'ToolBar: ' + xxx
.name
, pos
=pos
)
776 # Set status bar to display help
777 testWin
.CreateStatusBar()
778 testWin
.toolBar
= res
.LoadToolBar(testWin
, xxx
.name
)
779 testWin
.SetToolBar(testWin
.toolBar
)
781 wxMemoryFSHandler_RemoveFile('xxx.xrc')
783 EVT_CLOSE(testWin
, self
.OnCloseTestWin
)
784 EVT_BUTTON(testWin
, wxID_OK
, self
.OnCloseTestWin
)
785 EVT_BUTTON(testWin
, wxID_CANCEL
, self
.OnCloseTestWin
)
786 testWin
.highLight
= None
787 if highLight
and not tree
.pendingHighLight
:
788 self
.HighLight(highLight
)
791 def OnCloseTestWin(self
, evt
):
792 global testWin
, testWinPos
793 self
.SetItemBold(testWin
.item
, false
)
794 testWinPos
= testWin
.GetPosition()
798 # Return item index in parent
799 def ItemIndex(self
, parent
, item
):
801 it
, cookie
= self
.GetFirstChild(parent
, 0)
804 it
, cookie
= self
.GetNextChild(parent
, cookie
)
807 # True if next item should be inserted after current (vs. appended to it)
808 def NeedInsert(self
, item
):
809 xxx
= self
.GetPyData(item
)
810 if item
== self
.root
: return false
# root item
811 if xxx
.hasChildren
and not self
.GetChildrenCount(item
, false
):
813 return not (self
.IsExpanded(item
) and self
.GetChildrenCount(item
, false
))
816 def OnRightDown(self
, evt
):
818 pt
= evt
.GetPosition();
819 item
, flags
= self
.HitTest(pt
)
820 if item
.Ok() and flags
& wxTREE_HITTEST_ONITEM
:
821 self
.SelectItem(item
)
826 item
= self
.selection
828 menu
.Append(pullDownMenu
.ID_EXPAND
, 'Expand', 'Expand tree')
829 menu
.Append(pullDownMenu
.ID_COLLAPSE
, 'Collapse', 'Collapse tree')
831 self
.ctrl
= evt
.ControlDown() # save Ctrl state
832 self
.shift
= evt
.ShiftDown() # and Shift too
833 m
= wxMenu() # create menu
837 needInsert
= self
.NeedInsert(item
)
838 if item
== self
.root
or needInsert
and self
.GetItemParent(item
) == self
.root
:
839 m
.Append(pullDownMenu
.ID_NEW_PANEL
, 'Panel', 'Create panel')
840 m
.Append(pullDownMenu
.ID_NEW_DIALOG
, 'Dialog', 'Create dialog')
841 m
.Append(pullDownMenu
.ID_NEW_FRAME
, 'Frame', 'Create frame')
843 m
.Append(pullDownMenu
.ID_NEW_TOOL_BAR
, 'ToolBar', 'Create toolbar')
844 m
.Append(pullDownMenu
.ID_NEW_MENU_BAR
, 'MenuBar', 'Create menubar')
845 m
.Append(pullDownMenu
.ID_NEW_MENU
, 'Menu', 'Create menu')
847 xxx
= self
.GetPyData(item
).treeObject()
848 # Check parent for possible child nodes if inserting sibling
849 if needInsert
: xxx
= xxx
.parent
850 if xxx
.__class
__ == xxxMenuBar
:
851 m
.Append(pullDownMenu
.ID_NEW_MENU
, 'Menu', 'Create menu')
852 elif xxx
.__class
__ in [xxxToolBar
, xxxTool
] or \
853 xxx
.__class
__ == xxxSeparator
and xxx
.parent
.__class
__ == xxxToolBar
:
854 SetMenu(m
, pullDownMenu
.toolBarControls
)
855 elif xxx
.__class
__ in [xxxMenu
, xxxMenuItem
]:
856 SetMenu(m
, pullDownMenu
.menuControls
)
858 SetMenu(m
, pullDownMenu
.controls
)
859 if xxx
.__class
__ == xxxNotebook
:
860 m
.Enable(m
.FindItem('sizer'), false
)
861 elif not (xxx
.isSizer
or xxx
.parent
and xxx
.parent
.isSizer
):
862 m
.Enable(pullDownMenu
.ID_NEW_SPACER
, false
)
863 # Select correct label for create menu
866 menu
.AppendMenu(wxNewId(), 'Insert Child', m
,
867 'Create child object as the first child')
869 menu
.AppendMenu(wxNewId(), 'Append Child', m
,
870 'Create child object as the last child')
873 menu
.AppendMenu(wxNewId(), 'Create Sibling', m
,
874 'Create sibling before selected object')
876 menu
.AppendMenu(wxNewId(), 'Create Sibling', m
,
877 'Create sibling after selected object')
878 menu
.AppendSeparator()
879 # Not using standart IDs because we don't want to show shortcuts
880 menu
.Append(wxID_CUT
, 'Cut', 'Cut to the clipboard')
881 menu
.Append(wxID_COPY
, 'Copy', 'Copy to the clipboard')
882 if self
.ctrl
and item
!= tree
.root
:
883 menu
.Append(pullDownMenu
.ID_PASTE_SIBLING
, 'Paste Sibling',
884 'Paste from the clipboard as a sibling')
886 menu
.Append(wxID_PASTE
, 'Paste', 'Paste from the clipboard')
887 menu
.Append(pullDownMenu
.ID_DELETE
,
888 'Delete', 'Delete object')
889 if self
.ItemHasChildren(item
):
890 menu
.AppendSeparator()
891 menu
.Append(pullDownMenu
.ID_EXPAND
, 'Expand', 'Expand subtree')
892 menu
.Append(pullDownMenu
.ID_COLLAPSE
, 'Collapse', 'Collapse subtree')
893 self
.PopupMenu(menu
, evt
.GetPosition())
897 def Apply(self
, xxx
, item
):
900 xxx
= xxx
.treeObject()
901 if xxx
.hasName
and self
.GetItemText(item
) != xxx
.name
:
902 self
.SetItemText(item
, xxx
.treeName())
903 # Change tree icon for sizers
904 if isinstance(xxx
, xxxBoxSizer
):
905 self
.SetItemImage(item
, xxx
.treeImage())
906 # Set global modified state
907 frame
.modified
= true
910 ID_NEW_PANEL
= wxNewId()
911 ID_NEW_DIALOG
= wxNewId()
912 ID_NEW_FRAME
= wxNewId()
913 ID_NEW_TOOL_BAR
= wxNewId()
914 ID_NEW_TOOL
= wxNewId()
915 ID_NEW_MENU_BAR
= wxNewId()
916 ID_NEW_MENU
= wxNewId()
918 ID_NEW_STATIC_TEXT
= wxNewId()
919 ID_NEW_TEXT_CTRL
= wxNewId()
921 ID_NEW_BUTTON
= wxNewId()
922 ID_NEW_BITMAP_BUTTON
= wxNewId()
923 ID_NEW_RADIO_BUTTON
= wxNewId()
924 ID_NEW_SPIN_BUTTON
= wxNewId()
926 ID_NEW_STATIC_BOX
= wxNewId()
927 ID_NEW_CHECK_BOX
= wxNewId()
928 ID_NEW_RADIO_BOX
= wxNewId()
929 ID_NEW_COMBO_BOX
= wxNewId()
930 ID_NEW_LIST_BOX
= wxNewId()
932 ID_NEW_STATIC_LINE
= wxNewId()
933 ID_NEW_STATIC_BITMAP
= wxNewId()
934 ID_NEW_CHOICE
= wxNewId()
935 ID_NEW_SLIDER
= wxNewId()
936 ID_NEW_GAUGE
= wxNewId()
937 ID_NEW_SCROLL_BAR
= wxNewId()
938 ID_NEW_TREE_CTRL
= wxNewId()
939 ID_NEW_LIST_CTRL
= wxNewId()
940 ID_NEW_CHECK_LIST
= wxNewId()
941 ID_NEW_NOTEBOOK
= wxNewId()
942 ID_NEW_HTML_WINDOW
= wxNewId()
943 ID_NEW_CALENDAR
= wxNewId()
945 ID_NEW_BOX_SIZER
= wxNewId()
946 ID_NEW_STATIC_BOX_SIZER
= wxNewId()
947 ID_NEW_GRID_SIZER
= wxNewId()
948 ID_NEW_FLEX_GRID_SIZER
= wxNewId()
949 ID_NEW_SPACER
= wxNewId()
950 ID_NEW_TOOL_BAR
= wxNewId()
951 ID_NEW_TOOL
= wxNewId()
952 ID_NEW_MENU
= wxNewId()
953 ID_NEW_MENU_ITEM
= wxNewId()
954 ID_NEW_SEPARATOR
= wxNewId()
955 ID_NEW_LAST
= wxNewId()
956 ID_EXPAND
= wxNewId()
957 ID_COLLAPSE
= wxNewId()
958 ID_PASTE_SIBLING
= wxNewId()
960 def __init__(self
, parent
):
961 self
.ID_DELETE
= parent
.ID_DELETE
962 EVT_MENU_RANGE(parent
, self
.ID_NEW_PANEL
,
963 self
.ID_NEW_LAST
, parent
.OnCreate
)
964 EVT_MENU(parent
, self
.ID_COLLAPSE
, parent
.OnCollapse
)
965 EVT_MENU(parent
, self
.ID_EXPAND
, parent
.OnExpand
)
966 EVT_MENU(parent
, self
.ID_PASTE_SIBLING
, parent
.OnPaste
)
967 # We connect to tree, but process in frame
968 EVT_MENU_HIGHLIGHT_ALL(tree
, parent
.OnPullDownHighlight
)
970 ################################################################################
972 # ScrolledMessageDialog - modified from wxPython lib to set fixed-width font
973 class ScrolledMessageDialog(wxDialog
):
974 def __init__(self
, parent
, msg
, caption
, pos
= wxDefaultPosition
, size
= (500,300)):
975 from wxPython
.lib
.layoutf
import Layoutf
976 wxDialog
.__init
__(self
, parent
, -1, caption
, pos
, size
)
977 text
= wxTextCtrl(self
, -1, msg
, wxDefaultPosition
,
978 wxDefaultSize
, wxTE_MULTILINE | wxTE_READONLY
)
979 text
.SetFont(modernFont
)
980 dc
= wxWindowDC(text
)
981 w
, h
= dc
.GetTextExtent(' ')
982 ok
= wxButton(self
, wxID_OK
, "OK")
983 text
.SetConstraints(Layoutf('t=t5#1;b=t5#2;l=l5#1;r=r5#1', (self
,ok
)))
984 text
.SetSize((w
* 80 + 30, h
* 40))
985 ok
.SetConstraints(Layoutf('b=b5#1;x%w50#1;w!80;h!25', (self
,)))
986 self
.SetAutoLayout(TRUE
)
988 self
.CenterOnScreen(wxBOTH
)
990 ################################################################################
992 class Frame(wxFrame
):
993 def __init__(self
, pos
, size
):
996 wxFrame
.__init
__(self
, None, -1, '', pos
, size
)
997 self
.CreateStatusBar()
998 icon
= wxIcon(os
.path
.join(sys
.path
[0], 'xrced.ico'), wxBITMAP_TYPE_ICO
)
1003 self
.panelX
= self
.panelY
= -1
1004 self
.panelWidth
= 300
1005 self
.panelHeight
= 200
1011 menuBar
= wxMenuBar()
1014 menu
.Append(wxID_NEW
, '&New\tCtrl-N', 'New file')
1015 menu
.Append(wxID_OPEN
, '&Open...\tCtrl-O', 'Open XRC file')
1016 menu
.Append(wxID_SAVE
, '&Save\tCtrl-S', 'Save XRC file')
1017 menu
.Append(wxID_SAVEAS
, 'Save &As...', 'Save XRC file under different name')
1018 menu
.AppendSeparator()
1019 menu
.Append(wxID_EXIT
, '&Quit\tCtrl-Q', 'Exit application')
1020 menuBar
.Append(menu
, '&File')
1023 menu
.Append(wxID_UNDO
, '&Undo\tCtrl-Z', 'Undo')
1024 menu
.Append(wxID_REDO
, '&Redo\tCtrl-Y', 'Redo')
1025 menu
.AppendSeparator()
1026 menu
.Append(wxID_CUT
, 'Cut\tCtrl-X', 'Cut to the clipboard')
1027 menu
.Append(wxID_COPY
, '&Copy\tCtrl-C', 'Copy to the clipboard')
1028 menu
.Append(wxID_PASTE
, '&Paste\tCtrl-V', 'Paste from the clipboard')
1029 self
.ID_DELETE
= wxNewId()
1030 menu
.Append(self
.ID_DELETE
, '&Delete\tCtrl-D', 'Delete object')
1031 menuBar
.Append(menu
, '&Edit')
1034 self
.ID_EMBED_PANEL
= wxNewId()
1035 menu
.Append(self
.ID_EMBED_PANEL
, '&Embed Panel',
1036 'Toggle embedding properties panel in the main window', true
)
1037 menu
.Check(self
.ID_EMBED_PANEL
, conf
.embedPanel
)
1038 menu
.AppendSeparator()
1039 self
.ID_TEST
= wxNewId()
1040 menu
.Append(self
.ID_TEST
, '&Test\tF5', 'Test window')
1041 self
.ID_REFRESH
= wxNewId()
1042 menu
.Append(self
.ID_REFRESH
, '&Refresh\tCtrl-R', 'Refresh test window')
1043 self
.ID_AUTO_REFRESH
= wxNewId()
1044 menu
.Append(self
.ID_AUTO_REFRESH
, '&Auto-refresh\tCtrl-A',
1045 'Toggle auto-refresh mode', true
)
1046 menu
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
1047 menuBar
.Append(menu
, '&View')
1050 menu
.Append(wxID_ABOUT
, '&About...', 'About XCRed')
1051 self
.ID_README
= wxNewId()
1052 menu
.Append(self
.ID_README
, '&Readme...', 'View the README file')
1054 self
.ID_DEBUG_CMD
= wxNewId()
1055 menu
.Append(self
.ID_DEBUG_CMD
, 'CMD', 'Python command line')
1056 EVT_MENU(self
, self
.ID_DEBUG_CMD
, self
.OnDebugCMD
)
1057 menuBar
.Append(menu
, '&Help')
1059 self
.menuBar
= menuBar
1060 self
.SetMenuBar(menuBar
)
1063 tb
= self
.CreateToolBar(wxTB_HORIZONTAL | wxNO_BORDER | wxTB_FLAT
)
1064 tb
.SetToolBitmapSize((24, 23))
1065 tb
.AddSimpleTool(wxID_NEW
, images
.getNewBitmap(), 'New', 'New file')
1066 tb
.AddSimpleTool(wxID_OPEN
, images
.getOpenBitmap(), 'Open', 'Open file')
1067 tb
.AddSimpleTool(wxID_SAVE
, images
.getSaveBitmap(), 'Save', 'Save file')
1068 tb
.AddControl(wxStaticLine(tb
, -1, size
=(-1,23), style
=wxLI_VERTICAL
))
1069 tb
.AddSimpleTool(wxID_CUT
, images
.getCutBitmap(), 'Cut', 'Cut')
1070 tb
.AddSimpleTool(wxID_COPY
, images
.getCopyBitmap(), 'Copy', 'Copy')
1071 tb
.AddSimpleTool(wxID_PASTE
, images
.getPasteBitmap(), 'Paste', 'Paste')
1072 tb
.AddControl(wxStaticLine(tb
, -1, size
=(-1,23), style
=wxLI_VERTICAL
))
1073 tb
.AddSimpleTool(self
.ID_TEST
, images
.getTestBitmap(), 'Test', 'Test window')
1074 tb
.AddSimpleTool(self
.ID_REFRESH
, images
.getRefreshBitmap(),
1075 'Refresh', 'Refresh view')
1076 tb
.AddSimpleTool(self
.ID_AUTO_REFRESH
, images
.getAutoRefreshBitmap(),
1077 'Auto-refresh', 'Toggle auto-refresh mode', true
)
1078 if wxGetOsVersion()[1] == 1:
1079 tb
.AddSeparator() # otherwise auto-refresh sticks in status line
1080 tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
1085 EVT_MENU(self
, wxID_NEW
, self
.OnNew
)
1086 EVT_MENU(self
, wxID_OPEN
, self
.OnOpen
)
1087 EVT_MENU(self
, wxID_SAVE
, self
.OnSaveOrSaveAs
)
1088 EVT_MENU(self
, wxID_SAVEAS
, self
.OnSaveOrSaveAs
)
1089 EVT_MENU(self
, wxID_EXIT
, self
.OnExit
)
1091 EVT_MENU(self
, wxID_UNDO
, self
.OnUndo
)
1092 EVT_MENU(self
, wxID_REDO
, self
.OnRedo
)
1093 EVT_MENU(self
, wxID_CUT
, self
.OnCut
)
1094 EVT_MENU(self
, wxID_COPY
, self
.OnCopy
)
1095 EVT_MENU(self
, wxID_PASTE
, self
.OnPaste
)
1096 EVT_MENU(self
, self
.ID_DELETE
, self
.OnDelete
)
1098 EVT_MENU(self
, self
.ID_EMBED_PANEL
, self
.OnEmbedPanel
)
1099 EVT_MENU(self
, self
.ID_TEST
, self
.OnTest
)
1100 EVT_MENU(self
, self
.ID_REFRESH
, self
.OnRefresh
)
1101 EVT_MENU(self
, self
.ID_AUTO_REFRESH
, self
.OnAutoRefresh
)
1103 EVT_MENU(self
, wxID_ABOUT
, self
.OnAbout
)
1104 EVT_MENU(self
, self
.ID_README
, self
.OnReadme
)
1107 EVT_UPDATE_UI(self
, wxID_CUT
, self
.OnUpdateUI
)
1108 EVT_UPDATE_UI(self
, wxID_COPY
, self
.OnUpdateUI
)
1109 EVT_UPDATE_UI(self
, wxID_PASTE
, self
.OnUpdateUI
)
1110 EVT_UPDATE_UI(self
, self
.ID_DELETE
, self
.OnUpdateUI
)
1111 EVT_UPDATE_UI(self
, self
.ID_TEST
, self
.OnUpdateUI
)
1112 EVT_UPDATE_UI(self
, self
.ID_REFRESH
, self
.OnUpdateUI
)
1115 sizer
= wxBoxSizer(wxVERTICAL
)
1116 sizer
.Add(wxStaticLine(self
, -1), 0, wxEXPAND
)
1117 splitter
= wxSplitterWindow(self
, -1, style
=wxSP_3DSASH
)
1118 self
.splitter
= splitter
1119 splitter
.SetMinimumPaneSize(100)
1122 tree
= XML_Tree(splitter
, -1)
1123 sys
.modules
['xxx'].tree
= tree
1124 # !!! frame styles are broken
1125 # Miniframe for not embedded mode
1126 miniFrame
= wxFrame(self
, -1, 'Properties Panel',
1127 (conf
.panelX
, conf
.panelY
),
1128 (conf
.panelWidth
, conf
.panelHeight
))
1129 self
.miniFrame
= miniFrame
1130 sizer2
= wxBoxSizer()
1131 miniFrame
.SetAutoLayout(true
)
1132 miniFrame
.SetSizer(sizer2
)
1133 EVT_CLOSE(self
.miniFrame
, self
.OnCloseMiniFrame
)
1134 # Create panel for parameters
1137 panel
= Panel(splitter
)
1138 # Set plitter windows
1139 splitter
.SplitVertically(tree
, panel
, conf
.sashPos
)
1141 panel
= Panel(miniFrame
)
1142 sizer2
.Add(panel
, 1, wxEXPAND
)
1143 miniFrame
.Show(true
)
1144 splitter
.Initialize(tree
)
1145 sizer
.Add(splitter
, 1, wxEXPAND
)
1146 self
.SetAutoLayout(true
)
1147 self
.SetSizer(sizer
)
1149 # Init pull-down menu data
1151 pullDownMenu
= PullDownMenu(self
)
1152 # Mapping from IDs to element names
1154 pullDownMenu
.ID_NEW_PANEL
: 'wxPanel',
1155 pullDownMenu
.ID_NEW_DIALOG
: 'wxDialog',
1156 pullDownMenu
.ID_NEW_FRAME
: 'wxFrame',
1157 pullDownMenu
.ID_NEW_TOOL_BAR
: 'wxToolBar',
1158 pullDownMenu
.ID_NEW_TOOL
: 'tool',
1159 pullDownMenu
.ID_NEW_MENU_BAR
: 'wxMenuBar',
1160 pullDownMenu
.ID_NEW_MENU
: 'wxMenu',
1161 pullDownMenu
.ID_NEW_MENU_ITEM
: 'wxMenuItem',
1162 pullDownMenu
.ID_NEW_SEPARATOR
: 'separator',
1164 pullDownMenu
.ID_NEW_STATIC_TEXT
: 'wxStaticText',
1165 pullDownMenu
.ID_NEW_TEXT_CTRL
: 'wxTextCtrl',
1167 pullDownMenu
.ID_NEW_BUTTON
: 'wxButton',
1168 pullDownMenu
.ID_NEW_BITMAP_BUTTON
: 'wxBitmapButton',
1169 pullDownMenu
.ID_NEW_RADIO_BUTTON
: 'wxRadioButton',
1170 pullDownMenu
.ID_NEW_SPIN_BUTTON
: 'wxSpinButton',
1172 pullDownMenu
.ID_NEW_STATIC_BOX
: 'wxStaticBox',
1173 pullDownMenu
.ID_NEW_CHECK_BOX
: 'wxCheckBox',
1174 pullDownMenu
.ID_NEW_RADIO_BOX
: 'wxRadioBox',
1175 pullDownMenu
.ID_NEW_COMBO_BOX
: 'wxComboBox',
1176 pullDownMenu
.ID_NEW_LIST_BOX
: 'wxListBox',
1178 pullDownMenu
.ID_NEW_STATIC_LINE
: 'wxStaticLine',
1179 pullDownMenu
.ID_NEW_STATIC_BITMAP
: 'wxStaticBitmap',
1180 pullDownMenu
.ID_NEW_CHOICE
: 'wxChoice',
1181 pullDownMenu
.ID_NEW_SLIDER
: 'wxSlider',
1182 pullDownMenu
.ID_NEW_GAUGE
: 'wxGauge',
1183 pullDownMenu
.ID_NEW_SCROLL_BAR
: 'wxScrollBar',
1184 pullDownMenu
.ID_NEW_TREE_CTRL
: 'wxTreeCtrl',
1185 pullDownMenu
.ID_NEW_LIST_CTRL
: 'wxListCtrl',
1186 pullDownMenu
.ID_NEW_CHECK_LIST
: 'wxCheckList',
1187 pullDownMenu
.ID_NEW_NOTEBOOK
: 'wxNotebook',
1188 pullDownMenu
.ID_NEW_HTML_WINDOW
: 'wxHtmlWindow',
1189 pullDownMenu
.ID_NEW_CALENDAR
: 'wxCalendar',
1191 pullDownMenu
.ID_NEW_BOX_SIZER
: 'wxBoxSizer',
1192 pullDownMenu
.ID_NEW_STATIC_BOX_SIZER
: 'wxStaticBoxSizer',
1193 pullDownMenu
.ID_NEW_GRID_SIZER
: 'wxGridSizer',
1194 pullDownMenu
.ID_NEW_FLEX_GRID_SIZER
: 'wxFlexGridSizer',
1195 pullDownMenu
.ID_NEW_SPACER
: 'spacer',
1197 pullDownMenu
.controls
= [
1198 ['control', 'Various controls',
1199 (pullDownMenu
.ID_NEW_STATIC_TEXT
, 'Label', 'Create static label'),
1200 (pullDownMenu
.ID_NEW_STATIC_LINE
, 'Line', 'Create static line'),
1201 (pullDownMenu
.ID_NEW_TEXT_CTRL
, 'TextBox', 'Create text box control'),
1202 (pullDownMenu
.ID_NEW_CHOICE
, 'Choice', 'Create choice control'),
1203 (pullDownMenu
.ID_NEW_SLIDER
, 'Slider', 'Create slider control'),
1204 (pullDownMenu
.ID_NEW_GAUGE
, 'Gauge', 'Create gauge control'),
1205 (pullDownMenu
.ID_NEW_SCROLL_BAR
, 'ScrollBar', 'Create scroll bar'),
1206 (pullDownMenu
.ID_NEW_TREE_CTRL
, 'TreeCtrl', 'Create tree control'),
1207 (pullDownMenu
.ID_NEW_LIST_CTRL
, 'ListCtrl', 'Create list control'),
1208 (pullDownMenu
.ID_NEW_HTML_WINDOW
, 'HtmlWindow', 'Create HTML window'),
1209 (pullDownMenu
.ID_NEW_CALENDAR
, 'Calendar', 'Create calendar control'),
1210 (pullDownMenu
.ID_NEW_PANEL
, 'Panel', 'Create panel'),
1211 (pullDownMenu
.ID_NEW_NOTEBOOK
, 'Notebook', 'Create notebook control'),
1213 ['button', 'Buttons',
1214 (pullDownMenu
.ID_NEW_BUTTON
, 'Button', 'Create button'),
1215 (pullDownMenu
.ID_NEW_BITMAP_BUTTON
, 'BitmapButton', 'Create bitmap button'),
1216 (pullDownMenu
.ID_NEW_RADIO_BUTTON
, 'RadioButton', 'Create radio button'),
1217 (pullDownMenu
.ID_NEW_SPIN_BUTTON
, 'SpinButton', 'Create spin button'),
1220 (pullDownMenu
.ID_NEW_STATIC_BOX
, 'StaticBox', 'Create static box'),
1221 (pullDownMenu
.ID_NEW_CHECK_BOX
, 'CheckBox', 'Create check box'),
1222 (pullDownMenu
.ID_NEW_RADIO_BOX
, 'RadioBox', 'Create radio box'),
1223 (pullDownMenu
.ID_NEW_COMBO_BOX
, 'ComboBox', 'Create combo box'),
1224 (pullDownMenu
.ID_NEW_LIST_BOX
, 'ListBox', 'Create list box'),
1225 (pullDownMenu
.ID_NEW_CHECK_LIST
, 'CheckListBox',
1226 'Create check list control'),
1229 (pullDownMenu
.ID_NEW_BOX_SIZER
, 'BoxSizer', 'Create box sizer'),
1230 (pullDownMenu
.ID_NEW_STATIC_BOX_SIZER
, 'StaticBoxSizer',
1231 'Create static box sizer'),
1232 (pullDownMenu
.ID_NEW_GRID_SIZER
, 'GridSizer', 'Create grid sizer'),
1233 (pullDownMenu
.ID_NEW_FLEX_GRID_SIZER
, 'FlexGridSizer',
1234 'Create flexgrid sizer'),
1235 (pullDownMenu
.ID_NEW_SPACER
, 'Spacer', 'Create spacer'),
1238 pullDownMenu
.menuControls
= [
1239 (pullDownMenu
.ID_NEW_MENU
, 'Menu', 'Create menu'),
1240 (pullDownMenu
.ID_NEW_MENU_ITEM
, 'MenuItem', 'Create menu item'),
1241 (pullDownMenu
.ID_NEW_SEPARATOR
, 'Separator', 'Create separator'),
1243 pullDownMenu
.toolBarControls
= [
1244 (pullDownMenu
.ID_NEW_TOOL
, 'Tool', 'Create tool'),
1245 (pullDownMenu
.ID_NEW_SEPARATOR
, 'Separator', 'Create separator'),
1246 ['control', 'Various controls',
1247 (pullDownMenu
.ID_NEW_STATIC_TEXT
, 'Label', 'Create static label'),
1248 (pullDownMenu
.ID_NEW_STATIC_LINE
, 'Line', 'Create static line'),
1249 (pullDownMenu
.ID_NEW_TEXT_CTRL
, 'TextBox', 'Create text box control'),
1250 (pullDownMenu
.ID_NEW_CHOICE
, 'Choice', 'Create choice control'),
1251 (pullDownMenu
.ID_NEW_SLIDER
, 'Slider', 'Create slider control'),
1252 (pullDownMenu
.ID_NEW_GAUGE
, 'Gauge', 'Create gauge control'),
1253 (pullDownMenu
.ID_NEW_SCROLL_BAR
, 'ScrollBar', 'Create scroll bar'),
1254 (pullDownMenu
.ID_NEW_LIST_CTRL
, 'ListCtrl', 'Create list control'),
1256 ['button', 'Buttons',
1257 (pullDownMenu
.ID_NEW_BUTTON
, 'Button', 'Create button'),
1258 (pullDownMenu
.ID_NEW_BITMAP_BUTTON
, 'BitmapButton', 'Create bitmap button'),
1259 (pullDownMenu
.ID_NEW_RADIO_BUTTON
, 'RadioButton', 'Create radio button'),
1260 (pullDownMenu
.ID_NEW_SPIN_BUTTON
, 'SpinButton', 'Create spin button'),
1263 (pullDownMenu
.ID_NEW_STATIC_BOX
, 'StaticBox', 'Create static box'),
1264 (pullDownMenu
.ID_NEW_CHECK_BOX
, 'CheckBox', 'Create check box'),
1265 (pullDownMenu
.ID_NEW_RADIO_BOX
, 'RadioBox', 'Create radio box'),
1266 (pullDownMenu
.ID_NEW_COMBO_BOX
, 'ComboBox', 'Create combo box'),
1267 (pullDownMenu
.ID_NEW_LIST_BOX
, 'ListBox', 'Create list box'),
1268 (pullDownMenu
.ID_NEW_CHECK_LIST
, 'CheckListBox',
1269 'Create check list control'),
1277 EVT_IDLE(self
, self
.OnIdle
)
1278 EVT_CLOSE(self
, self
.OnCloseWindow
)
1280 def OnNew(self
, evt
):
1283 def OnOpen(self
, evt
):
1284 if not self
.AskSave(): return
1285 dlg
= wxFileDialog(self
, 'Open', os
.path
.dirname(self
.dataFile
),
1286 '', '*.xrc', wxOPEN | wxCHANGE_DIR
)
1287 if dlg
.ShowModal() == wxID_OK
:
1288 path
= dlg
.GetPath()
1289 self
.SetStatusText('Loading...')
1294 self
.SetStatusText('Data loaded')
1296 self
.SetStatusText('Failed')
1301 def OnSaveOrSaveAs(self
, evt
):
1302 if evt
.GetId() == wxID_SAVEAS
or not self
.dataFile
:
1303 if self
.dataFile
: defaultName
= ''
1304 else: defaultName
= 'UNTITLED.xrc'
1305 dlg
= wxFileDialog(self
, 'Save As', os
.path
.dirname(self
.dataFile
),
1306 defaultName
, '*.xrc',
1307 wxSAVE | wxOVERWRITE_PROMPT | wxCHANGE_DIR
)
1308 if dlg
.ShowModal() == wxID_OK
:
1309 path
= dlg
.GetPath()
1315 path
= self
.dataFile
1316 self
.SetStatusText('Saving...')
1321 self
.dataFile
= path
1322 self
.SetStatusText('Data saved')
1324 self
.SetStatusText('Failed')
1327 def OnExit(self
, evt
):
1330 def OnUndo(self
, evt
):
1331 print '*** being implemented'
1333 print self
.lastOp
, self
.undo
1334 if self
.lastOp
== 'DELETE':
1335 parent
, prev
, elem
= self
.undo
1337 xxx
= MakeXXXFromDOM(tree
.GetPyData(parent
).treeObject(), elem
)
1338 item
= tree
.InsertItem( parent
, prev
, xxx
.treeObject().className
,
1339 data
=wxTreeItemData(xxx
) )
1341 def OnRedo(self
, evt
):
1342 print '*** being implemented'
1344 def OnCut(self
, evt
):
1345 selected
= tree
.selection
1346 if not selected
: return # key pressed event
1349 self
.undo
= [tree
.GetItemParent(selected
), tree
.GetPrevSibling(selected
)]
1353 # If deleting top-level item, delete testWin
1354 if selected
== testWin
.item
:
1358 # Remove highlight, update testWin
1359 if not tree
.IsHighlatable(selected
):
1360 if testWin
.highLight
: testWin
.highLight
.Remove()
1361 tree
.needUpdate
= true
1362 self
.clipboard
= tree
.RemoveLeaf(selected
)
1363 tree
.pendingHighLight
= None
1366 self
.modified
= true
1367 self
.SetStatusText('Removed to clipboard')
1369 def OnCopy(self
, evt
):
1370 selected
= tree
.selection
1371 if not selected
: return # key pressed event
1372 xxx
= tree
.GetPyData(selected
)
1373 self
.clipboard
= xxx
.element
.cloneNode(true
)
1374 self
.SetStatusText('Copied')
1376 def OnPaste(self
, evt
):
1377 selected
= tree
.selection
1378 if not selected
: return # key pressed event
1379 # For pasting with Ctrl pressed
1380 if evt
.GetId() == pullDownMenu
.ID_PASTE_SIBLING
: appendChild
= false
1381 else: appendChild
= not tree
.NeedInsert(selected
)
1382 xxx
= tree
.GetPyData(selected
)
1384 # If has next item, insert, else append to parent
1385 nextItem
= tree
.GetNextSibling(selected
)
1387 # Insert before nextItem
1388 parentLeaf
= tree
.GetItemParent(selected
)
1389 else: # last child: change selected to parent
1391 selected
= tree
.GetItemParent(selected
)
1392 # Expanded container (must have children)
1393 elif tree
.IsExpanded(selected
) and tree
.GetChildrenCount(selected
, false
):
1395 nextItem
= tree
.GetFirstChild(selected
, 0)[0]
1396 parentLeaf
= selected
1397 # Parent should be tree element or None
1399 parent
= tree
.GetPyData(selected
)
1401 parent
= tree
.GetPyData(parentLeaf
)
1402 if parent
.hasChild
: parent
= parent
.child
1404 # Create a copy of clipboard element
1405 elem
= self
.clipboard
.cloneNode(true
)
1406 # Tempopary xxx object to test things
1407 xxx
= MakeXXXFromDOM(parent
, elem
)
1409 # Check compatibility
1412 x
= xxx
.treeObject()
1413 if x
.__class
__ in [xxxDialog
, xxxFrame
, xxxMenuBar
, xxxToolBar
]:
1414 if parent
.__class
__ != xxxMainNode
: error
= true
1415 elif x
.__class
__ == xxxPanel
and parent
.__class
__ == xxxMainNode
:
1417 elif x
.__class
__ == xxxSpacer
:
1418 if not parent
.isSizer
: error
= true
1419 elif x
.__class
__ == xxxSeparator
:
1420 if not parent
.__class
__ in [xxxMenu
, xxxToolBar
]: error
= true
1421 elif x
.__class
__ == xxxTool
:
1422 if parent
.__class
__ != xxxToolBar
: error
= true
1423 elif x
.__class
__ == xxxMenuItem
:
1424 if not parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error
= true
1425 elif x
.isSizer
and parent
.__class
__ == xxxNotebook
: error
= true
1426 else: # normal controls can be almost anywhere
1427 if parent
.__class
__ == xxxMainNode
or \
1428 parent
.__class
__ in [xxxMenuBar
, xxxMenu
]: error
= true
1430 if parent
.__class
__ == xxxMainNode
: parentClass
= 'root'
1431 else: parentClass
= parent
.className
1432 wxLogError('Incompatible parent/child: parent is %s, child is %s!' %
1433 (parentClass
, x
.className
))
1436 # Check parent and child relationships.
1437 # If parent is sizer or notebook, child is of wrong class or
1438 # parent is normal window, child is child container then detach child.
1439 isChildContainer
= isinstance(xxx
, xxxChildContainer
)
1440 if isChildContainer
and \
1441 ((parent
.isSizer
and not isinstance(xxx
, xxxSizerItem
)) or \
1442 (isinstance(parent
, xxxNotebook
) and not isinstance(xxx
, xxxNotebookPage
)) or \
1443 not (parent
.isSizer
or isinstance(parent
, xxxNotebook
))):
1444 elem
.removeChild(xxx
.child
.element
) # detach child
1445 elem
.unlink() # delete child container
1446 elem
= xxx
.child
.element
# replace
1447 # This may help garbage collection
1448 xxx
.child
.parent
= None
1449 isChildContainer
= false
1450 # Parent is sizer or notebook, child is not child container
1451 if parent
.isSizer
and not isChildContainer
and not isinstance(xxx
, xxxSpacer
):
1452 # Create sizer item element
1453 sizerItemElem
= MakeEmptyDOM('sizeritem')
1454 sizerItemElem
.appendChild(elem
)
1455 elem
= sizerItemElem
1456 elif isinstance(parent
, xxxNotebook
) and not isChildContainer
:
1457 pageElem
= MakeEmptyDOM('notebookpage')
1458 pageElem
.appendChild(elem
)
1460 xxx
= MakeXXXFromDOM(parent
, elem
)
1461 # Figure out if we must append a new child or sibling
1463 parent
.element
.appendChild(elem
)
1464 newItem
= tree
.AppendItem(selected
, xxx
.treeName(), image
=xxx
.treeImage(),
1465 data
=wxTreeItemData(xxx
))
1467 node
= tree
.GetPyData(nextItem
).element
1468 parent
.element
.insertBefore(elem
, node
)
1469 # Inserting before is difficult, se we insert after or first child
1470 index
= tree
.ItemIndex(parentLeaf
, nextItem
)
1471 newItem
= tree
.InsertItemBefore(parentLeaf
, index
,
1472 xxx
.treeName(), image
=xxx
.treeImage())
1473 tree
.SetPyData(newItem
, xxx
)
1474 # newItem = tree.InsertItem(parentLeaf, selected, xxx.treeName(),
1475 # image=xxx.treeImage(), data=wxTreeItemData(xxx))
1476 # Add children items
1478 treeObj
= xxx
.treeObject()
1479 for n
in treeObj
.element
.childNodes
:
1481 tree
.AddNode(newItem
, treeObj
, n
)
1482 # Scroll to show new item
1483 tree
.EnsureVisible(newItem
)
1484 tree
.SelectItem(newItem
)
1485 if not tree
.IsVisible(newItem
):
1486 tree
.ScrollTo(newItem
)
1489 if testWin
and tree
.IsHighlatable(newItem
):
1490 if conf
.autoRefresh
:
1491 tree
.needUpdate
= true
1492 tree
.pendingHighLight
= newItem
1494 tree
.pendingHighLight
= None
1495 self
.modified
= true
1496 self
.SetStatusText('Pasted')
1498 def OnDelete(self
, evt
):
1499 selected
= tree
.selection
1500 if not selected
: return # key pressed event
1502 self
.lastOp
= 'DELETE'
1503 self
.undo
= [tree
.GetItemParent(selected
), tree
.GetPrevSibling(selected
)]
1507 # If deleting top-level item, delete testWin
1508 if selected
== testWin
.item
:
1512 # Remove highlight, update testWin
1513 if not tree
.IsHighlatable(selected
):
1514 if testWin
.highLight
: testWin
.highLight
.Remove()
1515 tree
.needUpdate
= true
1516 xnode
= tree
.RemoveLeaf(selected
)
1517 # !!! cloneNode is broken, or something is wrong
1518 # self.undo.append(xnode.cloneNode(true))
1520 tree
.pendingHighLight
= None
1523 self
.modified
= true
1524 self
.SetStatusText('Deleted')
1526 def OnEmbedPanel(self
, evt
):
1527 conf
.embedPanel
= evt
.IsChecked()
1529 # Remember last dimentions
1530 self
.panelWidth
, self
.panelHeight
= panel
.GetSize()
1531 panel
.Reparent(self
.splitter
)
1532 self
.miniFrame
.GetSizer().RemoveWindow(panel
)
1533 self
.splitter
.SplitVertically(tree
, panel
, self
.sashPos
)
1534 self
.miniFrame
.Show(false
)
1536 self
.sashPos
= self
.splitter
.GetSashPosition()
1537 self
.splitter
.Unsplit(panel
)
1538 sizer
= self
.miniFrame
.GetSizer()
1539 panel
.Reparent(self
.miniFrame
)
1541 sizer
.Add(panel
, 1, wxEXPAND
)
1542 self
.miniFrame
.Show(true
)
1543 self
.miniFrame
.SetSize((self
.panelWidth
, self
.panelHeight
))
1545 def OnTest(self
, evt
):
1546 if not tree
.selection
: return # key pressed event
1547 tree
.ShowTestWindow(tree
.selection
)
1549 def OnRefresh(self
, evt
):
1550 # If modified, apply first
1551 selection
= tree
.selection
1553 xxx
= tree
.GetPyData(selection
)
1554 if xxx
and panel
.IsModified():
1555 tree
.Apply(xxx
, selection
)
1558 tree
.CreateTestWin(testWin
.item
)
1559 tree
.needUpdate
= false
1561 def OnAutoRefresh(self
, evt
):
1562 conf
.autoRefresh
= evt
.IsChecked()
1563 self
.menuBar
.Check(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
1564 self
.tb
.ToggleTool(self
.ID_AUTO_REFRESH
, conf
.autoRefresh
)
1566 def OnAbout(self
, evt
):
1567 str = '%s %s\n\nRoman Rolinsky <rolinsky@mema.ucl.ac.be>' % \
1569 dlg
= wxMessageDialog(self
, str, 'About ' + progname
, wxOK | wxCENTRE
)
1573 def OnReadme(self
, evt
):
1574 text
= open(os
.path
.join(sys
.path
[0], 'README'), 'r').read()
1575 dlg
= ScrolledMessageDialog(self
, text
, "XRCed README")
1580 # Simple emulation of python command line
1581 def OnDebugCMD(self
, evt
):
1585 exec raw_input('C:\> ')
1590 (etype
, value
, tb
) =sys
.exc_info()
1591 tblist
=traceback
.extract_tb(tb
)[1:]
1592 msg
=string
.join(traceback
.format_exception_only(etype
, value
)
1593 +traceback
.format_list(tblist
))
1596 def OnCreate(self
, evt
):
1597 selected
= tree
.selection
1598 if tree
.ctrl
: appendChild
= false
1599 else: appendChild
= not tree
.NeedInsert(selected
)
1600 xxx
= tree
.GetPyData(selected
)
1604 # If has previous item, insert after it, else append to parent
1606 parentLeaf
= tree
.GetItemParent(selected
)
1608 # If has next item, insert, else append to parent
1609 nextItem
= tree
.GetNextSibling(selected
)
1611 # Insert before nextItem
1612 parentLeaf
= tree
.GetItemParent(selected
)
1613 else: # last child: change selected to parent
1615 selected
= tree
.GetItemParent(selected
)
1616 # Expanded container (must have children)
1617 elif tree
.shift
and tree
.IsExpanded(selected
) \
1618 and tree
.GetChildrenCount(selected
, false
):
1620 nextItem
= tree
.GetFirstChild(selected
, 0)[0]
1621 parentLeaf
= selected
1622 # Parent should be tree element or None
1624 parent
= tree
.GetPyData(selected
)
1626 parent
= tree
.GetPyData(parentLeaf
)
1627 if parent
.hasChild
: parent
= parent
.child
1630 className
= self
.createMap
[evt
.GetId()]
1631 xxx
= MakeEmptyXXX(parent
, className
)
1633 # Set default name for top-level windows
1634 if parent
.__class
__ == xxxMainNode
:
1635 cl
= xxx
.treeObject().__class
__
1636 frame
.maxIDs
[cl
] += 1
1637 xxx
.treeObject().name
= '%s%d' % (defaultIDs
[cl
], frame
.maxIDs
[cl
])
1638 xxx
.treeObject().element
.setAttribute('name', xxx
.treeObject().name
)
1640 # Figure out if we must append a new child or sibling
1643 # Insert newline for debug purposes
1644 parent
.element
.appendChild(elem
)
1645 newItem
= tree
.AppendItem(selected
, xxx
.treeName(), image
=xxx
.treeImage(),
1646 data
=wxTreeItemData(xxx
))
1648 node
= tree
.GetPyData(nextItem
).element
1649 parent
.element
.insertBefore(elem
, node
)
1650 # !!! There is a different behavious on Win and GTK
1651 # !!! On Win InsertItem(parent, parent, ...) inserts at the end.
1652 index
= tree
.ItemIndex(parentLeaf
, nextItem
)
1653 newItem
= tree
.InsertItemBefore(parentLeaf
, index
,
1654 xxx
.treeName(), image
=xxx
.treeImage())
1655 # data=wxTreeItemData(xxx)) # does not work
1656 tree
.SetPyData(newItem
, xxx
)
1657 # newItem = tree.InsertItem(parentLeaf, selected,
1658 # xxx.treeName(), image=xxx.treeImage(),
1659 # data=wxTreeItemData(xxx))
1660 tree
.EnsureVisible(newItem
)
1661 tree
.SelectItem(newItem
)
1662 if not tree
.IsVisible(newItem
):
1663 tree
.ScrollTo(newItem
)
1666 if testWin
and tree
.IsHighlatable(newItem
):
1667 if conf
.autoRefresh
:
1668 tree
.needUpdate
= true
1669 tree
.pendingHighLight
= newItem
1671 tree
.pendingHighLight
= None
1673 # Expand/collapse subtree
1674 def OnExpand(self
, evt
):
1675 if tree
.selection
: tree
.ExpandAll(tree
.selection
)
1676 else: tree
.ExpandAll(tree
.root
)
1677 def OnCollapse(self
, evt
):
1678 if tree
.selection
: tree
.CollapseAll(tree
.selection
)
1679 else: tree
.CollapseAll(tree
.root
)
1681 def OnPullDownHighlight(self
, evt
):
1682 menuId
= evt
.GetMenuId()
1684 menu
= evt
.GetEventObject()
1685 help = menu
.GetHelpString(menuId
)
1686 self
.SetStatusText(help)
1688 self
.SetStatusText('')
1690 def OnUpdateUI(self
, evt
):
1691 if evt
.GetId() in [wxID_CUT
, wxID_COPY
, self
.ID_DELETE
]:
1692 evt
.Enable(tree
.selection
!= tree
.root
)
1693 elif evt
.GetId() == wxID_PASTE
:
1694 evt
.Enable((self
.clipboard
and tree
.selection
) != None)
1695 elif evt
.GetId() == self
.ID_TEST
:
1696 evt
.Enable(tree
.selection
!= tree
.root
)
1697 elif evt
.GetId() == self
.ID_REFRESH
:
1698 evt
.Enable(testWin
!= None)
1700 def OnIdle(self
, evt
):
1701 if self
.inIdle
: return # Recursive call protection
1704 if conf
.autoRefresh
:
1706 self
.SetStatusText('Refreshing test window...')
1708 tree
.CreateTestWin(testWin
.item
)
1710 self
.SetStatusText('')
1711 tree
.needUpdate
= false
1712 elif tree
.pendingHighLight
:
1713 tree
.HighLight(tree
.pendingHighLight
)
1718 # We don't let close panel window
1719 def OnCloseMiniFrame(self
, evt
):
1722 def OnCloseWindow(self
, evt
):
1723 if not self
.AskSave(): return
1724 if testWin
: testWin
.Destroy()
1725 # Destroy cached windows
1726 panel
.cacheParent
.Destroy()
1727 # for w in panel.styleCache.values(): w.Destroy()
1728 if not panel
.GetPageCount() == 2:
1729 panel
.page2
.Destroy()
1730 conf
.x
, conf
.y
= self
.GetPosition()
1731 conf
.width
, conf
.height
= self
.GetSize()
1733 conf
.sashPos
= self
.splitter
.GetSashPosition()
1734 conf
.panelWidth
, conf
.panelHeight
= self
.panelWidth
, self
.panelHeight
1736 conf
.sashPos
= self
.sashPos
1737 conf
.panelX
, conf
.panelY
= self
.miniFrame
.GetPosition()
1738 conf
.panelWidth
, conf
.panelHeight
= self
.miniFrame
.GetSize()
1743 self
.clipboard
= None
1744 self
.modified
= false
1745 panel
.SetModified(false
)
1752 self
.SetTitle(progname
)
1753 # Numbers for new controls
1755 self
.maxIDs
[xxxPanel
] = self
.maxIDs
[xxxDialog
] = self
.maxIDs
[xxxFrame
] = \
1756 self
.maxIDs
[xxxMenuBar
] = self
.maxIDs
[xxxMenu
] = self
.maxIDs
[xxxToolBar
] = 0
1758 def Open(self
, path
):
1759 # Try to read the file
1764 dom
= minidom
.parse(path
)
1766 self
.dataFile
= path
1767 self
.SetTitle(progname
+ ': ' + os
.path
.basename(path
))
1769 wxLogError('Error reading file: %s' % path
)
1772 def Indent(self
, node
, indent
= 0):
1773 # Copy child list because it will change soon
1774 children
= node
.childNodes
[:]
1775 # Main node doesn't need to be indented
1777 text
= self
.domCopy
.createTextNode('\n' + ' ' * indent
)
1778 node
.parentNode
.insertBefore(text
, node
)
1780 # Append newline after last child, except for text nodes
1781 if children
[-1].nodeType
== minidom
.Node
.ELEMENT_NODE
:
1782 text
= self
.domCopy
.createTextNode('\n' + ' ' * indent
)
1783 node
.appendChild(text
)
1784 # Indent children which are elements
1786 if n
.nodeType
== minidom
.Node
.ELEMENT_NODE
:
1787 self
.Indent(n
, indent
+ 2)
1789 def Save(self
, path
):
1792 self
.OnRefresh(wxCommandEvent())
1794 # Make temporary copy
1795 self
.domCopy
= domCopy
= tree
.dom
.cloneNode(true
)
1796 self
.Indent(domCopy
.getElementsByTagName('resource')[0])
1801 self
.modified
= false
1802 panel
.SetModified(false
)
1804 wxLogError('Error writing file: %s' % path
)
1808 if not (self
.modified
or panel
.IsModified()): return true
1809 flags
= wxICON_EXCLAMATION | wxYES_NO | wxCANCEL | wxCENTRE
1810 dlg
= wxMessageDialog( self
, 'File is modified. Save before exit?',
1811 'Save before too late?', flags
)
1812 say
= dlg
.ShowModal()
1815 self
.OnSaveOrSaveAs(wxCommandEvent(wxID_SAVE
))
1816 # If save was successful, modified flag is unset
1817 if not self
.modified
: return true
1818 elif say
== wxID_NO
:
1819 self
.modified
= false
1820 panel
.SetModified(false
)
1824 ################################################################################
1827 print >> sys
.stderr
, 'usage: xrced [-dvh] [file]'
1831 global debug
, verbose
1832 # Process comand-line
1834 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'dvh')
1835 except getopt
.GetoptError
:
1836 print >> sys
.stderr
, 'Unknown option'
1846 print 'XRCed version', version
1849 self
.SetAppName('xrced')
1852 conf
= wxConfig(style
= wxCONFIG_USE_LOCAL_FILE
)
1853 conf
.autoRefresh
= conf
.ReadInt('autorefresh', true
)
1854 pos
= conf
.ReadInt('x', -1), conf
.ReadInt('y', -1)
1855 size
= conf
.ReadInt('width', 800), conf
.ReadInt('height', 600)
1856 conf
.embedPanel
= conf
.ReadInt('embedPanel', true
)
1857 conf
.sashPos
= conf
.ReadInt('sashPos', 200)
1858 if not conf
.embedPanel
:
1859 conf
.panelX
= conf
.ReadInt('panelX', -1)
1860 conf
.panelY
= conf
.ReadInt('panelY', -1)
1862 conf
.panelX
= conf
.panelY
= -1
1863 conf
.panelWidth
= conf
.ReadInt('panelWidth', 200)
1864 conf
.panelHeight
= conf
.ReadInt('panelHeight', 200)
1865 conf
.panic
= not conf
.HasEntry('nopanic')
1867 wxFileSystem_AddHandler(wxMemoryFSHandler())
1868 wxInitAllImageHandlers()
1870 frame
= Frame(pos
, size
)
1872 # Load resources from XRC file (!!! should be transformed to .py later?)
1873 sys
.modules
['params'].frame
= frame
1874 frame
.res
= wxXmlResource('')
1875 frame
.res
.Load(os
.path
.join(sys
.path
[0], 'xrced.xrc'))
1877 # Load file after showing
1880 frame
.open = frame
.Open(args
[0])
1886 wc
= wxConfigBase_Get()
1887 wc
.WriteInt('autorefresh', conf
.autoRefresh
)
1888 wc
.WriteInt('x', conf
.x
)
1889 wc
.WriteInt('y', conf
.y
)
1890 wc
.WriteInt('width', conf
.width
)
1891 wc
.WriteInt('height', conf
.height
)
1892 wc
.WriteInt('embedPanel', conf
.embedPanel
)
1893 if not conf
.embedPanel
:
1894 wc
.WriteInt('panelX', conf
.panelX
)
1895 wc
.WriteInt('panelY', conf
.panelY
)
1896 wc
.WriteInt('sashPos', conf
.sashPos
)
1897 wc
.WriteInt('panelWidth', conf
.panelWidth
)
1898 wc
.WriteInt('panelHeight', conf
.panelHeight
)
1899 wc
.WriteInt('nopanic', 1)
1907 if __name__
== '__main__':