Mercurial > MadButterfly
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 |