Mercurial > MadButterfly
annotate inkscape/firefox/MBServer.py @ 1535:9aff42a7e2b9 tip
Fix issue of add/remove a frame at a scene before all key frames of a layer.
When you added or removed a frame at a scene before all key frames of
a layer, frameline was not updated correctly. It seems nothing
happened, but domview is updated. This changeset fix this issue by
correcting logic for boundary case.
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Fri, 30 Sep 2011 22:07:28 +0800 |
parents | 29145d2affdb |
children |
rev | line source |
---|---|
288 | 1 #!/usr/bin/python |
2 import inkex | |
3 import pygtk | |
4 import gtk | |
5 from copy import deepcopy | |
6 from lxml import etree | |
7 from twisted.web import server, resource,soap | |
8 from twisted.internet import reactor | |
9 import traceback | |
10 | |
11 import random | |
12 | |
13 # Please refer to http://www.assembla.com/wiki/show/MadButterfly/Inkscape_extention for the designed document. | |
14 | |
15 | |
16 # Algorithm: | |
17 # | |
18 # We will parse the first two level of the SVG DOM. collect a table of layer and scene. | |
19 # 1. Collect the layer table which will be displayed as the first column of the grid. | |
20 # 2. Get the maximum scene number. This will decide the size of the grid. | |
21 # 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 | |
22 # range specified by scene field. The function IsSceneDefined(scene) can be used for this purpose. | |
23 # 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 | |
24 # 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 | |
25 # "8-10". | |
26 # 5. If this scene are filled screne, we will split the existing scene into two scenes with the same content. | |
27 | |
28 class Layer: | |
29 def __init__(self,node): | |
30 self.scene = [] | |
31 self.node = node | |
32 self.nodes=[] | |
33 class Scene: | |
34 def __init__(self, node, start,end): | |
35 self.node = node | |
36 self.start = int(start) | |
37 self.end = int(end) | |
38 | |
39 | |
40 class MBScene(inkex.Effect): | |
41 def confirm(self,msg): | |
42 vbox = gtk.VBox() | |
43 vbox.pack_start(gtk.Label(msg)) | |
44 self.button = gtk.Button('OK') | |
45 vbox.pack_start(self.button) | |
46 self.button.connect("clicked", self.onQuit) | |
47 self.window.add(vbox) | |
48 def dumpattr(self,n): | |
49 s = "" | |
50 for a,v in n.attrib.items(): | |
51 s = s + ("%s=%s" % (a,v)) | |
52 return s | |
53 | |
54 def dump(self,node,l=0): | |
55 print " " * l*2,"<", node.tag, self.dumpattr(node),">" | |
56 for n in node: | |
57 self.dump(n,l+1) | |
58 print " " * l * 2,"/>" | |
59 def parseMetadata(self,node): | |
60 self.current = 1 | |
61 for n in node: | |
62 if n.tag == '{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scenes': | |
63 self.scenemap={} | |
64 cur = int(n.get("current")) | |
65 self.current = cur | |
66 | |
67 for s in n: | |
68 if s.tag == '{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene': | |
69 try: | |
70 start = int(s.get("start")) | |
71 except: | |
72 continue | |
73 try: | |
74 end = s.get("end") | |
75 if end == None: | |
76 end = start | |
77 except: | |
78 end = start | |
79 link = s.get("ref") | |
80 self.scenemap[link] = [int(start),int(end)] | |
81 if cur >= start and cur <= end: | |
82 self.currentscene = link | |
83 | |
84 pass | |
85 pass | |
86 pass | |
87 pass | |
88 | |
89 | |
90 def parseScene(self): | |
91 """ | |
92 In this function, we will collect all items for the current scene and then relocate them back to the appropriate scene object. | |
93 """ | |
94 self.layer = [] | |
95 self.scenemap = None | |
96 for node in self.document.getroot(): | |
97 if node.tag == '{http://www.w3.org/2000/svg}metadata': | |
98 self.parseMetadata(node) | |
99 elif node.tag == '{http://www.w3.org/2000/svg}g': | |
100 oldscene = None | |
101 #print layer.attrib.get("id") | |
102 lyobj = Layer(node) | |
103 self.layer.append(lyobj) | |
104 lyobj.current_scene = [] | |
105 for scene in node: | |
106 if scene.tag == '{http://www.w3.org/2000/svg}g': | |
107 try: | |
108 scmap = self.scenemap[scene.get("id")] | |
109 if scmap == None: | |
110 lyobj.current_scene.append(scene) | |
111 continue | |
112 if self.current <= scmap[1] and self.current >= scmap[0]: | |
113 oldscene = scene | |
114 except: | |
115 lyobj.current_scene.append(scene) | |
116 continue | |
117 | |
118 lyobj.scene.append(Scene(scene,scmap[0],scmap[1])) | |
119 else: | |
120 lyobj.current_scene.append(scene) | |
121 pass | |
122 pass | |
123 | |
124 if oldscene != None: | |
125 # Put the objects back to the current scene | |
126 for o in lyobj.current_scene: | |
127 #print o.tag | |
128 oldscene.append(o) | |
129 pass | |
130 pass | |
131 pass | |
132 pass | |
133 | |
134 self.collectID() | |
135 #self.dumpID() | |
136 def collectID(self): | |
137 self.ID = {} | |
138 root = self.document.getroot() | |
139 for n in root: | |
140 self.collectID_recursive(n) | |
141 def collectID_recursive(self,node): | |
142 self.ID[node.get("id")] = 1 | |
143 for n in node: | |
144 self.collectID_recursive(n) | |
145 def newID(self): | |
146 while True: | |
147 n = 's%d' % int(random.random()*10000) | |
148 #print "try %s" % n | |
149 if self.ID.has_key(n) == False: | |
150 return n | |
151 def dumpID(self): | |
152 for a,v in self.ID.items(): | |
153 print a | |
154 | |
155 | |
156 def getLayer(self, layer): | |
157 for l in self.layer: | |
158 if l.node.attrib.get("id") == layer: | |
159 return l | |
160 return None | |
161 | |
162 | |
163 def insertKeyScene(self,layer,nth): | |
164 """ | |
165 Insert a new key scene into the stage. If the nth is always a key scene, we will return without changing anything. | |
166 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 | |
167 append a new scene. | |
168 | |
169 """ | |
170 if layer == None: return | |
171 | |
172 # Check if the nth is in the middle of any scene | |
173 for i in range(0,len(layer.scene)): | |
174 s = layer.scene[i] | |
175 if nth >= s.start and nth <= s.end: | |
176 if nth == s.start: return | |
177 newscene = Scene(deepcopy(s.node),nth,s.end) | |
178 newscene.node.set("id", self.newID()) | |
179 layer.scene.insert(i+1,newscene) | |
180 layer.scene[i].end = nth-1 | |
181 return | |
182 if len(layer.scene) > 0: | |
183 # extend the last scene befor eit automatically | |
184 last = nth | |
185 lastscene = None | |
186 # Find the last scene before it | |
187 for s in layer.scene: | |
188 if s.end < nth and last < s.end: | |
189 last = s.end | |
190 lastscene = s | |
191 if lastscene == None: | |
192 node = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene') | |
193 node.set("id", self.newID()) | |
194 newscene = Scene(node,nth,nth) | |
195 else: | |
196 lastscene.end = nth-1 | |
197 newscene = Scene(deepcopy(lastscene.node),nth,nth) | |
198 newscene.node.set("id",self.newID()) | |
199 layer.scene.append(newscene) | |
200 else: | |
201 # This is the first scene in the layer | |
202 node = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene') | |
203 node.set("id", self.newID()) | |
204 newscene = Scene(node,nth,nth) | |
205 layer.scene.append(newscene) | |
206 | |
207 | |
208 def deleteScene(self,layer,nth): | |
209 for i in range(0,len(layer.scene)): | |
210 s = layer.scene[i] | |
211 if nth == s.start: | |
212 if i == 0: | |
213 layer.scene.remove(s) | |
214 else: | |
215 if s.start == layer.scene[i-1].end+1: | |
216 # If the start of the delete scene segment is the end of the last scene segmenet, convert all scenes in the deleted | |
217 # scene segmenet to the last one | |
218 layer.scene[i-1].end = s.end | |
219 layer.scene.remove(s) | |
220 else: | |
221 # Convert all scenes into empty cell | |
222 layer.scene.remove(s) | |
223 | |
224 return | |
225 pass | |
226 pass | |
227 | |
228 | |
229 def extendScene(self,layer,nth): | |
230 if layer == None: return | |
231 | |
232 for i in range(0,len(layer.scene)-1): | |
233 s = layer.scene[i] | |
234 if nth >= layer.scene[i].start and nth <= layer.scene[i].end: | |
235 return | |
236 | |
237 for i in range(0,len(layer.scene)-1): | |
238 s = layer.scene[i] | |
239 if nth >= layer.scene[i].start and nth < layer.scene[i+1].start: | |
240 layer.scene[i].end = nth | |
241 return | |
242 if len(layer.scene) > 0 and nth > layer.scene[len(layer.scene)-1].end: | |
243 layer.scene[len(layer.scene)-1].end = nth | |
244 | |
381 | 245 def findNodeById(self,root,id): |
246 for n in root: | |
247 if n.attrib.get('id') == id: | |
248 return n | |
249 nn = self.findNodeById(n,id) | |
250 if nn is not None: | |
251 return nn | |
252 return None | |
253 def changeSymbol(self,id,newname): | |
254 node = self.findNodeById(self.document.getroot(),id) | |
255 if node is not None: | |
256 node.set('mbname',newname); | |
257 | |
258 | |
288 | 259 def setCurrentScene(self,nth): |
260 self.current = nth | |
261 for layer in self.layer: | |
262 for s in layer.scene: | |
263 if nth >= s.start and nth <= s.end: | |
264 s.node.set("style","") | |
265 #print "Put the elemenets out" | |
266 layer.nodes = [] | |
267 | |
268 for o in s.node: | |
269 #print " ",o.tag | |
270 layer.nodes.append(o) | |
271 for o in s.node: | |
272 s.node.remove(o) | |
273 else: | |
274 s.node.set("style","display:none") | |
275 def generate(self): | |
276 newdoc = deepcopy(self.document) | |
277 root = newdoc.getroot() | |
278 has_scene = False | |
279 for n in root: | |
280 if n.tag == '{http://www.w3.org/2000/svg}metadata': | |
281 for nn in n: | |
282 if nn.tag == '{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scenes': | |
283 nn.clear() | |
284 nn.set("current", "%d" % self.current) | |
285 scenes = [] | |
286 for l in self.layer: | |
287 for s in l.scene: | |
288 id = s.node.get("id") | |
289 scene = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene') | |
290 scene.set("ref", id) | |
291 if s.start == s.end: | |
292 scene.set("start", "%d" % s.start) | |
293 else: | |
294 scene.set("start", "%d" % s.start) | |
295 scene.set("end", "%d" % s.end) | |
296 | |
297 scenes.append(scene) | |
298 for s in scenes: | |
299 nn.append(s) | |
300 has_scene = True | |
301 if has_scene == False: | |
302 scenes = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scenes') | |
303 scenes.set("current","%d" % self.current) | |
304 for l in self.layer: | |
305 for s in l.scene: | |
306 scene = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene') | |
307 scene.set("ref", s.node.get("id")) | |
308 if s.start == s.end: | |
309 scene.set("start", "%d" % s.start) | |
310 else: | |
311 scene.set("start", "%d" % s.start) | |
312 scene.set("end", "%d" % s.end) | |
313 scenes.append(scene) | |
314 n.append(scenes) | |
315 if n.tag == '{http://www.w3.org/2000/svg}g': | |
316 root.remove(n) | |
317 | |
318 for l in self.layer: | |
319 # Duplicate all attribute of the layer | |
320 lnode = etree.Element("{http://www.w3.org/2000/svg}g") | |
321 for a,v in l.node.attrib.items(): | |
322 lnode.set(a,v) | |
323 for n in l.nodes: | |
324 lnode.append(n) | |
325 root.append(lnode) | |
326 for s in l.scene: | |
327 snode = etree.Element("{http://www.w3.org/2000/svg}g") | |
328 for a,v in s.node.attrib.items(): | |
329 snode.set(a,v) | |
330 for n in s.node: | |
331 snode.append(deepcopy(n)) | |
332 lnode.append(snode) | |
333 self.document = newdoc | |
334 def newCell(self,file): | |
335 img = gtk.Image() | |
336 img.set_from_file(file) | |
337 btn = gtk.EventBox() | |
338 btn.add(img) | |
339 btn.connect("button_press_event", self.cellSelect) | |
340 btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray")) | |
341 return btn | |
342 def showGrid(self): | |
343 max = 0 | |
344 for layer in self.layer: | |
345 for s in layer.scene: | |
346 if s.end > max: | |
347 max = s.end | |
348 max = 50 | |
349 | |
350 self.grid = gtk.Table(len(self.layer)+1, 50) | |
351 self.scrollwin = gtk.ScrolledWindow() | |
352 self.scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) | |
353 self.scrollwin.add_with_viewport(self.grid) | |
354 for i in range(1,max): | |
355 self.grid.attach(gtk.Label('%d'% i), i,i+1,0,1,0,0,0,0) | |
356 for i in range(1,len(self.layer)+1): | |
357 l = self.layer[i-1] | |
358 self.grid.attach(gtk.Label(l.node.get('{http://www.inkscape.org/namespaces/inkscape}label')), 0, 1, i, i+1,0,0,10,0) | |
359 for s in l.scene: | |
360 btn = self.newCell('start.png') | |
361 btn.nScene = s.start | |
362 btn.layer = l.node.get('id') | |
363 btn.nLayer = i | |
364 | |
365 self.grid.attach(btn, s.start, s.start+1, i, i+1,0,0,0,0) | |
366 for j in range(s.start+1,s.end+1): | |
367 btn = self.newCell('fill.png') | |
368 self.grid.attach(btn, j, j+1, i , i+1,0,0,0,0) | |
369 btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray")) | |
370 btn.nScene = j | |
371 btn.layer = l.node.get('id') | |
372 btn.nLayer = i | |
373 if len(l.scene) == 0: | |
374 start = 0 | |
375 else: | |
376 start = l.scene[len(l.scene)-1].end | |
377 for j in range(start,max): | |
378 btn = self.newCell('empty.png') | |
379 self.grid.attach(btn, j+1, j+2,i,i+1,0,0,0,0) | |
380 btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray")) | |
381 btn.nScene = j+1 | |
382 btn.layer = l.node.get('id') | |
383 btn.nLayer = i | |
384 self.last_cell = None | |
385 def cellSelect(self, cell, data): | |
386 if self.last_cell: | |
387 self.last_cell.modify_bg(gtk.STATE_NORMAL, self.last_cell.get_colormap().alloc_color("gray")) | |
388 | |
389 self.last_cell = cell | |
390 cell.modify_bg(gtk.STATE_NORMAL, cell.get_colormap().alloc_color("green")) | |
391 | |
392 def doEditScene(self,w): | |
393 self.setCurrentScene(self.last_cell.nScene) | |
394 self.generate() | |
395 gtk.main_quit() | |
396 | |
397 def doRemoveScene(self,w): | |
398 self.removeKeyScene() | |
399 self.grid.show_all() | |
400 self.generate() | |
401 def addButtons(self,hbox): | |
402 btn = gtk.Button('Edit') | |
403 btn.connect('clicked', self.doEditScene) | |
404 hbox.pack_start(btn) | |
405 btn = gtk.Button('Insert Key') | |
406 btn.connect('clicked',self.doInsertKeyScene) | |
407 hbox.pack_start(btn) | |
408 btn=gtk.Button('Remove Key') | |
409 btn.connect('clicked', self.doRemoveScene) | |
410 hbox.pack_start(btn) | |
411 btn=gtk.Button('Extend scene') | |
412 btn.connect('clicked', self.doExtendScene) | |
413 hbox.pack_start(btn) | |
414 def onQuit(self, event): | |
415 self.OK = False | |
416 gtk.main_quit() | |
417 def onOK(self,event): | |
418 self.OK = True | |
419 gtk.main_quit() | |
420 | |
421 def onConfirmDelete(self): | |
422 if self.scenemap == None: | |
423 vbox = gtk.VBox() | |
424 vbox.pack_start(gtk.Label('Convert the SVG into a MadButterfly SVG file. All current element will be delted')) | |
425 hbox = gtk.HBox() | |
426 self.button = gtk.Button('OK') | |
427 hbox.pack_start(self.button) | |
428 self.button.connect('clicked', self.onOK) | |
429 self.button = gtk.Button('Cancel') | |
430 hbox.pack_start(self.button) | |
431 self.button.connect("clicked", self.onQuit) | |
432 vbox.pack_start(hbox) | |
433 self.window.add(vbox) | |
434 self.window.show_all() | |
435 gtk.main() | |
436 self.window.remove(vbox) | |
437 | |
438 def start_server(self): | |
439 root = MB() | |
440 root.target = self | |
441 site = server.Site(root) | |
442 reactor.listenTCP(8080, site) | |
443 reactor.run() | |
444 | |
445 | |
446 def effect(self): | |
447 self.OK = False | |
448 self.parseScene() | |
449 self.start_server() | |
450 self.generate() | |
451 | |
452 class MB(soap.SOAPPublisher): | |
453 """ | |
454 SOAP server for inkscape extension. | |
455 """ | |
456 | |
457 def soap_PUBLISH(self): | |
458 reactor.callLater(1,self.quit) | |
459 return "OK" | |
460 def quit(self): | |
461 reactor.stop() | |
462 def soap_SCENE(self,n): | |
463 self.target.setCurrentScene(int(n)) | |
464 return "OK" | |
465 def soap_INSERTKEY(self,layer,n): | |
466 try: | |
467 layer = self.target.getLayer(layer) | |
468 self.target.insertKeyScene(layer,int(n)) | |
469 return "OK" | |
470 except: | |
471 return traceback.format_exc() | |
472 def soap_EXTENDSCENE(self,layer,n): | |
473 try: | |
474 layer = self.target.getLayer(layer) | |
475 self.target.extendScene(layer,int(n)) | |
476 return "OK" | |
477 except: | |
478 return traceback.format_exc() | |
479 def soap_DELETESCENE(self,layer,n): | |
480 try: | |
481 layer = self.target.getLayer(layer) | |
482 self.target.deleteScene(layer,int(n)) | |
483 return "OK" | |
484 except: | |
485 return traceback.format_exc() | |
486 def soap_GETDOC(self): | |
487 try: | |
488 self.target.generate() | |
376
7d244a85dd68
Change the screen layout to make it more like an usual IDE.
wycc
parents:
339
diff
changeset
|
489 newdoc = deepcopy(self.target.document) |
7d244a85dd68
Change the screen layout to make it more like an usual IDE.
wycc
parents:
339
diff
changeset
|
490 root = newdoc.getroot() |
7d244a85dd68
Change the screen layout to make it more like an usual IDE.
wycc
parents:
339
diff
changeset
|
491 for id,node in self.target.selected.iteritems(): |
7d244a85dd68
Change the screen layout to make it more like an usual IDE.
wycc
parents:
339
diff
changeset
|
492 select = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}select') |
7d244a85dd68
Change the screen layout to make it more like an usual IDE.
wycc
parents:
339
diff
changeset
|
493 select.set('ref', id) |
7d244a85dd68
Change the screen layout to make it more like an usual IDE.
wycc
parents:
339
diff
changeset
|
494 root.append(select) |
7d244a85dd68
Change the screen layout to make it more like an usual IDE.
wycc
parents:
339
diff
changeset
|
495 return etree.tostring(newdoc) |
288 | 496 except: |
497 return traceback.format_exc() | |
381 | 498 def soap_CHANGESYMBOL(self,id,newname): |
499 try: | |
500 self.target.changeSymbol(id,newname) | |
501 return "OK" | |
502 except: | |
503 return traceback.format_exc() | |
288 | 504 import os |
339
63aaf96209cd
* Move location of files so that we can produce XPI file from them.
wycc
parents:
288
diff
changeset
|
505 os.chdir('/usr/local/share/inkscape/extensions') |
288 | 506 |
507 A = MBScene() | |
508 A.affect() | |
509 | |
510 |