comparison pyink/MBScene.py @ 941:9ba94c577a6f

Add scene editor. This vewrsion can only switch scene. It can not change the scene yet.
author wycc
date Sun, 14 Nov 2010 23:09:02 +0800
parents
children 82321f404b5f
comparison
equal deleted inserted replaced
934:5dedeedf0408 941:9ba94c577a6f
1 #!/usr/bin/python
2 import pygtk
3 import gtk
4 from copy import deepcopy
5 from lxml import etree
6 import random
7 import traceback
8
9 # Please refer to http://www.assembla.com/wiki/show/MadButterfly/Inkscape_extention for the designed document.
10
11
12 # Algorithm:
13 #
14 # We will parse the first two level of the SVG DOM. collect a table of layer and scene.
15 # 1. Collect the layer table which will be displayed as the first column of the grid.
16 # 2. Get the maximum scene number. This will decide the size of the grid.
17 # 3. When F6 is pressed, we will check if this scene has been defined. This can be done by scan all second level group and check if the current scene number is within the
18 # range specified by scene field. The function IsSceneDefined(scene) can be used for this purpose.
19 # 4. If this is a new scene, we will append a new group which duplication the content of the last scene in the same group. The scene field will contain the number from the
20 # last scene number of the last scene to the current scenen number. For example, if the last scene is from 4-7 and the new scene is 10, we will set the scene field as
21 # "8-10".
22 # 5. If this scene are filled screne, we will split the existing scene into two scenes with the same content.
23
24 class Layer:
25 def __init__(self,node):
26 self.scene = []
27 self.node = node
28 self.nodes=[]
29 class Scene:
30 def __init__(self, node, start,end):
31 self.node = node
32 self.start = int(start)
33 self.end = int(end)
34
35
36 class MBScene():
37 def __init__(self,desktop,win):
38 self.desktop = desktop
39 self.window = win
40 self.layer = []
41 self.layer.append(Layer(None))
42 self.scenemap = None
43
44 def confirm(self,msg):
45 vbox = gtk.VBox()
46 vbox.pack_start(gtk.Label(msg))
47 self.button = gtk.Button('OK')
48 vbox.pack_start(self.button)
49 self.button.connect("clicked", self.onQuit)
50 self.window.add(vbox)
51 def dumpattr(self,n):
52 s = ""
53 for a,v in n.attrib.items():
54 s = s + ("%s=%s" % (a,v))
55 return s
56
57 def dump(self,node,l=0):
58 print " " * l*2,"<", node.tag, self.dumpattr(node),">"
59 for n in node:
60 self.dump(n,l+1)
61 print " " * l * 2,"/>"
62 def parseMetadata(self,node):
63 self.current = 1
64 for n in node.childList():
65 if n.repr.name() == 'ns0:scenes':
66 self.scenemap={}
67 cur = int(n.repr.attribute("current"))
68 self.current = cur
69
70 for s in n.childList():
71 print '--->',s.repr.name()
72 if s.repr.name() == 'ns0:scene':
73 try:
74 start = int(s.repr.attribute("start"))
75 except:
76 traceback.print_exc()
77 continue
78 try:
79 end = s.repr.attribute("end")
80 if end == None:
81 end = start
82 except:
83 end = start
84 link = s.repr.attribute("ref")
85 self.scenemap[link] = [int(start),int(end)]
86 print "scene %d to %d" % (self.scenemap[link][0],self.scenemap[link][1])
87 if cur >= start and cur <= end:
88 self.currentscene = link
89
90 pass
91 pass
92 pass
93 pass
94
95
96 def parseScene(self):
97 """
98 In this function, we will collect all items for the current scene and then relocate them back to the appropriate scene object.
99 """
100 self.layer = []
101 self.scenemap = None
102 doc = self.desktop.doc().root()
103
104 for node in doc.childList():
105 if node.repr.name() == 'svg:metadata':
106 self.parseMetadata(node)
107 elif node.repr.name() == 'svg:g':
108 oldscene = None
109 #print layer.attrib.get("id")
110 lyobj = Layer(node)
111 self.layer.append(lyobj)
112 lyobj.current_scene = []
113 for scene in node.childList():
114 if scene.repr.name() == 'svg:g':
115 try:
116 scmap = self.scenemap[scene.getId()]
117 if scmap == None:
118 lyobj.current_scene.append(scene)
119 continue
120 if self.current <= scmap[1] and self.current >= scmap[0]:
121 oldscene = scene
122 except:
123 lyobj.current_scene.append(scene)
124 continue
125
126 lyobj.scene.append(Scene(scene,scmap[0],scmap[1]))
127 else:
128 lyobj.current_scene.append(scene)
129 pass
130
131 if oldscene != None:
132 # Put the objects back to the current scene
133 #for o in lyobj.current_scene:
134 #print o.tag
135 #oldscene.append(o)
136 pass
137 pass
138 pass
139
140 self.collectID()
141 self.dumpID()
142 def collectID(self):
143 self.ID = {}
144 root = self.desktop.doc().root()
145 for n in root.childList():
146 self.collectID_recursive(n)
147 def collectID_recursive(self,node):
148 self.ID[node.getId()] = 1
149 for n in node.childList():
150 self.collectID_recursive(n)
151 def newID(self):
152 while True:
153 n = 's%d' % int(random.random()*10000)
154 #print "try %s" % n
155 if self.ID.has_key(n) == False:
156 return n
157 def dumpID(self):
158 for a,v in self.ID.items():
159 print a
160
161
162 def getLayer(self, layer):
163 for l in self.layer:
164 if l.node.getId() == layer:
165 return l
166 return None
167
168
169 def insertKeyScene(self):
170 """
171 Insert a new key scene into the stage. If the nth is always a key scene, we will return without changing anything.
172 If the nth is a filled scene, we will break the original scene into two parts. If the nth is out of any scene, we will
173 append a new scene.
174
175 """
176 nth = self.last_cell.nScene
177 layer = self.getLayer(self.last_cell.layer)
178 x = self.last_cell.nScene
179 y = self.last_cell.nLayer
180 if layer == None: return
181 for i in range(0,len(layer.scene)):
182 s = layer.scene[i]
183 if nth >= s.start and nth <= s.end:
184 if nth == s.start: return
185 newscene = Scene(DuplicateNode(s.node),nth,s.end)
186 newscene.node.setId(self.newID())
187 layer.scene.insert(i+1,newscene)
188 layer.scene[i].end = nth-1
189 btn = self.newCell('start.png')
190 btn.nScene = nth
191 btn.layer = layer
192 btn.nLayer = y
193 self.grid.remove(self.last_cell)
194 self.grid.attach(btn, x,x+1,y,y+1,0,0,0,0)
195 return
196 if len(layer.scene) > 0:
197 last = nth
198 lastscene = None
199 for s in layer.scene:
200 if s.end < nth and last < s.end:
201 last = s.end
202 lastscene = s
203 for x in range(last+1, nth):
204 btn = self.newCell('fill.png')
205 btn.nScene = x
206 btn.layer = layer.node.getId()
207 btn.nLayer = y
208 self.grid.attach(btn, x, x+1, y , y+1,0,0,0,0)
209 if lastscene == None:
210 node = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene')
211 node.setId(self.newID())
212 newscene = Scene(node,nth,nth)
213 else:
214 lastscene.end = nth-1
215 newscene = Scene(DuplicateNode(lastscene.node),nth,nth)
216 newscene.node.setId(self.newID())
217 layer.scene.append(newscene)
218 btn = self.newCell('start.png')
219 x = self.last_cell.nScene
220 y = self.last_cell.nLayer
221 btn.nScene = nth
222 btn.layer = layer.node.getId()
223 btn.nLayer = y
224 self.grid.attach(btn, x, x+1, y, y+1,0,0,0,0)
225 else:
226 # This is the first scene in the layer
227 node = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene')
228 node.repr.setId(self.newID())
229 newscene = Scene(node,nth,nth)
230 layer.scene.append(newscene)
231 btn = self.newCell('start.png')
232 btn.nScene = nth
233 btn.layer = layer.node.getId()
234 btn.nLayer = y
235 self.grid.attach(btn, x, x+1, y, y+1,0,0,0,0)
236
237
238
239
240 def removeKeyScene(self):
241 nth = self.last_cell.nScene
242 try:
243 layer = self.getLayer(self.last_cell.layer)
244 except:
245 return
246 x = self.last_cell.nScene
247 y = self.last_cell.nLayer
248 for i in range(0,len(layer.scene)):
249 s = layer.scene[i]
250 if nth == s.start:
251 if i == 0:
252 for j in range(s.start,s.end+1):
253 btn = self.newCell('empty.png')
254 btn.nScene = nth
255 btn.layer = layer
256 btn.nLayer = y
257 self.grid.attach(btn, j,j+1,y,y+1,0,0,0,0)
258 layer.scene.remove(s)
259 else:
260 if s.start == layer.scene[i-1].end+1:
261 # If the start of the delete scene segment is the end of the last scene segmenet, convert all scenes in the deleted
262 # scene segmenet to the last one
263 layer.scene[i-1].end = s.end
264 layer.scene.remove(s)
265 btn = self.newCell('fill.png')
266
267 btn.nScene = nth
268 btn.layer = layer
269 btn.nLayer = y
270 self.grid.attach(btn, x,x+1,y,y+1,0,0,0,0)
271 else:
272 # Convert all scenes into empty cell
273 layer.scene.remove(s)
274 for j in range(s.start,s.end+1):
275 btn = self.newCell('empty.png')
276 btn.nScene = nth
277 btn.layer = layer
278 btn.nLayer = y
279 self.grid.attach(btn, j,j+1,y,y+1,0,0,0,0)
280
281
282 return
283
284 def extendScene(self):
285 nth = self.last_cell.nScene
286 try:
287 layer = self.getLayer(self.last_cell.layer)
288 except:
289 traceback.print_exc()
290 return
291 x = self.last_cell.nScene
292 y = self.last_cell.nLayer
293 if layer == None: return
294
295 for i in range(0,len(layer.scene)-1):
296 s = layer.scene[i]
297 if nth >= layer.scene[i].start and nth <= layer.scene[i].end:
298 return
299
300 for i in range(0,len(layer.scene)-1):
301 s = layer.scene[i]
302 if nth >= layer.scene[i].start and nth < layer.scene[i+1].start:
303 for j in range(layer.scene[i].end+1, nth+1):
304 btn = self.newCell('fill.png')
305 btn.nScene = nth
306 btn.nLayer = y
307 btn.layer = self.last_cell.layer
308 self.grid.attach(btn, j,j+1,y,y+1,0,0,0,0)
309 layer.scene[i].end = nth
310 return
311 if len(layer.scene) > 0 and nth > layer.scene[len(layer.scene)-1].end:
312 for j in range(layer.scene[len(layer.scene)-1].end+1, nth+1):
313 btn = self.newCell('fill.png')
314 btn.nScene = nth
315 btn.nLayer = y
316 btn.layer = self.last_cell.layer
317 self.grid.attach(btn, j,j+1,y,y+1,0,0,0,0)
318 layer.scene[len(layer.scene)-1].end = nth
319 def setCurrentScene(self,nth):
320 self.current = nth
321 for layer in self.layer:
322 for s in layer.scene:
323 if nth >= s.start and nth <= s.end:
324 s.node.repr.setAttribute("style","",True)
325 #print "Put the elemenets out"
326 layer.nodes = []
327
328 #for o in s.node:
329 #print " ",o.tag
330 # layer.nodes.append(o)
331 #for o in s.node:
332 # s.node.remove(o)
333 else:
334 s.node.repr.setAttribute("style","display:none",True)
335 def generate(self):
336 newdoc = deepcopy(self.document)
337 root = newdoc.getroot()
338 has_scene = False
339 for n in root:
340 if n.tag == '{http://www.w3.org/2000/svg}metadata':
341 for nn in n:
342 if nn.tag == '{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scenes':
343 nn.clear()
344 nn.set("current", "%d" % self.current)
345 scenes = []
346 for l in self.layer:
347 for s in l.scene:
348 id = s.node.get("id")
349 scene = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene')
350 scene.set("ref", id)
351 if s.start == s.end:
352 scene.set("start", "%d" % s.start)
353 else:
354 scene.set("start", "%d" % s.start)
355 scene.set("end", "%d" % s.end)
356
357 scenes.append(scene)
358 for s in scenes:
359 nn.append(s)
360 has_scene = True
361 if has_scene == False:
362 scenes = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scenes')
363 scenes.set("current","%d" % self.current)
364 for l in self.layer:
365 for s in l.scene:
366 scene = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene')
367 scene.set("ref", s.node.get("id"))
368 if s.start == s.end:
369 scene.set("start", "%d" % s.start)
370 else:
371 scene.set("start", "%d" % s.start)
372 scene.set("end", "%d" % s.end)
373 scenes.append(scene)
374 n.append(scenes)
375 if n.tag == '{http://www.w3.org/2000/svg}g':
376 root.remove(n)
377
378 for l in self.layer:
379 # Duplicate all attribute of the layer
380 lnode = etree.Element("{http://www.w3.org/2000/svg}g")
381 for a,v in l.node.attrib.items():
382 lnode.set(a,v)
383 for n in l.nodes:
384 lnode.append(n)
385 root.append(lnode)
386 for s in l.scene:
387 snode = etree.Element("{http://www.w3.org/2000/svg}g")
388 for a,v in s.node.attrib.items():
389 snode.set(a,v)
390 for n in s.node:
391 snode.append(deepcopy(n))
392 lnode.append(snode)
393 self.document = newdoc
394 def newCell(self,file):
395 img = gtk.Image()
396 img.set_from_file(file)
397 btn = gtk.EventBox()
398 btn.add(img)
399 btn.connect("button_press_event", self.cellSelect)
400 btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray"))
401 return btn
402 def showGrid(self):
403 max = 0
404 for layer in self.layer:
405 for s in layer.scene:
406 if s.end > max:
407 max = s.end
408 max = 50
409
410 self.grid = gtk.Table(len(self.layer)+1, 50)
411 self.scrollwin = gtk.ScrolledWindow()
412 self.scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
413 self.scrollwin.add_with_viewport(self.grid)
414 for i in range(1,max):
415 self.grid.attach(gtk.Label('%d'% i), i,i+1,0,1,0,0,0,0)
416 for i in range(1,len(self.layer)+1):
417 print "Layer", i
418 l = self.layer[i-1]
419 #self.grid.attach(gtk.Label(l.node.get('{http://www.inkscape.org/namespaces/inkscape}label')), 0, 1, i, i+1,0,0,10,0)
420 for s in l.scene:
421 btn = self.newCell('start.png')
422 btn.nScene = s.start
423 btn.layer = l.node.getId()
424 btn.nLayer = i
425
426 self.grid.attach(btn, s.start, s.start+1, i, i+1,0,0,0,0)
427 for j in range(s.start+1,s.end+1):
428 btn = self.newCell('fill.png')
429 self.grid.attach(btn, j, j+1, i , i+1,0,0,0,0)
430 btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray"))
431 btn.nScene = j
432 btn.layer = l.node.getId()
433 btn.nLayer = i
434 if len(l.scene) == 0:
435 start = 0
436 else:
437 start = l.scene[len(l.scene)-1].end
438 for j in range(start,max):
439 btn = self.newCell('empty.png')
440 self.grid.attach(btn, j+1, j+2,i,i+1,0,0,0,0)
441 btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray"))
442 btn.nScene = j+1
443 btn.layer = l.node.getId()
444 btn.nLayer = i
445 self.last_cell = None
446 def cellSelect(self, cell, data):
447 if self.last_cell:
448 self.last_cell.modify_bg(gtk.STATE_NORMAL, self.last_cell.get_colormap().alloc_color("gray"))
449
450 self.last_cell = cell
451 cell.modify_bg(gtk.STATE_NORMAL, cell.get_colormap().alloc_color("green"))
452
453 def doEditScene(self,w):
454 self.setCurrentScene(self.last_cell.nScene)
455 def doInsertKeyScene(self,w):
456 return
457 self.insertKeyScene()
458 self.grid.show_all()
459
460 def doRemoveScene(self,w):
461 return
462 self.removeKeyScene()
463 self.grid.show_all()
464 self.generate()
465 def doExtendScene(self,w):
466 self.extendScene()
467 self.grid.show_all()
468 def addButtons(self,hbox):
469 btn = gtk.Button('Edit')
470 btn.connect('clicked', self.doEditScene)
471 hbox.pack_start(btn)
472 btn = gtk.Button('Insert Key')
473 btn.connect('clicked',self.doInsertKeyScene)
474 hbox.pack_start(btn)
475 btn=gtk.Button('Remove Key')
476 btn.connect('clicked', self.doRemoveScene)
477 hbox.pack_start(btn)
478 btn=gtk.Button('Extend scene')
479 btn.connect('clicked', self.doExtendScene)
480 hbox.pack_start(btn)
481 def onQuit(self, event):
482 self.OK = False
483 gtk.main_quit()
484 def onOK(self,event):
485 self.OK = True
486 gtk.main_quit()
487
488 def onConfirmDelete(self):
489 if self.scenemap == None:
490 vbox = gtk.VBox()
491 vbox.pack_start(gtk.Label('Convert the SVG into a MadButterfly SVG file. All current element will be delted'))
492 hbox = gtk.HBox()
493 self.button = gtk.Button('OK')
494 hbox.pack_start(self.button)
495 self.button.connect('clicked', self.onOK)
496 self.button = gtk.Button('Cancel')
497 hbox.pack_start(self.button)
498 self.button.connect("clicked", self.onQuit)
499 vbox.pack_start(hbox)
500 self.window.add(vbox)
501 self.window.show_all()
502 gtk.main()
503 self.window.remove(vbox)
504
505
506 def show(self):
507 self.OK = True
508 self.parseScene()
509 self.showGrid()
510 #self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
511 #self.window.connect("destroy", gtk.main_quit)
512 #self.window.set_position(gtk.WIN_POS_MOUSE)
513 if self.scenemap == None:
514 self.onConfirmDelete()
515 if self.OK:
516 vbox = gtk.VBox()
517 self.window.add(vbox)
518 vbox.add(self.scrollwin)
519 self.vbox = vbox
520 hbox=gtk.HBox()
521 self.addButtons(hbox)
522 vbox.add(hbox)
523 else:
524 return
525
526 self.window.set_size_request(600,200)
527
528 self.window.show_all()
529
530