Mercurial > MadButterfly
annotate inkscape/firefox/MBServer.py @ 339:63aaf96209cd
* Move location of files so that we can produce XPI file from them.
* Add the produce to compile the inkscape for madbutterfly
* Add makefile to produce inkscape and madbuilder.xpi
author | wycc |
---|---|
date | Sun, 08 Mar 2009 10:05:22 +0800 |
parents | d5327265da1e |
children | 7d244a85dd68 |
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 | |
245 def setCurrentScene(self,nth): | |
246 self.current = nth | |
247 for layer in self.layer: | |
248 for s in layer.scene: | |
249 if nth >= s.start and nth <= s.end: | |
250 s.node.set("style","") | |
251 #print "Put the elemenets out" | |
252 layer.nodes = [] | |
253 | |
254 for o in s.node: | |
255 #print " ",o.tag | |
256 layer.nodes.append(o) | |
257 for o in s.node: | |
258 s.node.remove(o) | |
259 else: | |
260 s.node.set("style","display:none") | |
261 def generate(self): | |
262 newdoc = deepcopy(self.document) | |
263 root = newdoc.getroot() | |
264 has_scene = False | |
265 for n in root: | |
266 if n.tag == '{http://www.w3.org/2000/svg}metadata': | |
267 for nn in n: | |
268 if nn.tag == '{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scenes': | |
269 nn.clear() | |
270 nn.set("current", "%d" % self.current) | |
271 scenes = [] | |
272 for l in self.layer: | |
273 for s in l.scene: | |
274 id = s.node.get("id") | |
275 scene = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene') | |
276 scene.set("ref", id) | |
277 if s.start == s.end: | |
278 scene.set("start", "%d" % s.start) | |
279 else: | |
280 scene.set("start", "%d" % s.start) | |
281 scene.set("end", "%d" % s.end) | |
282 | |
283 scenes.append(scene) | |
284 for s in scenes: | |
285 nn.append(s) | |
286 has_scene = True | |
287 if has_scene == False: | |
288 scenes = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scenes') | |
289 scenes.set("current","%d" % self.current) | |
290 for l in self.layer: | |
291 for s in l.scene: | |
292 scene = etree.Element('{http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd}scene') | |
293 scene.set("ref", s.node.get("id")) | |
294 if s.start == s.end: | |
295 scene.set("start", "%d" % s.start) | |
296 else: | |
297 scene.set("start", "%d" % s.start) | |
298 scene.set("end", "%d" % s.end) | |
299 scenes.append(scene) | |
300 n.append(scenes) | |
301 if n.tag == '{http://www.w3.org/2000/svg}g': | |
302 root.remove(n) | |
303 | |
304 for l in self.layer: | |
305 # Duplicate all attribute of the layer | |
306 lnode = etree.Element("{http://www.w3.org/2000/svg}g") | |
307 for a,v in l.node.attrib.items(): | |
308 lnode.set(a,v) | |
309 for n in l.nodes: | |
310 lnode.append(n) | |
311 root.append(lnode) | |
312 for s in l.scene: | |
313 snode = etree.Element("{http://www.w3.org/2000/svg}g") | |
314 for a,v in s.node.attrib.items(): | |
315 snode.set(a,v) | |
316 for n in s.node: | |
317 snode.append(deepcopy(n)) | |
318 lnode.append(snode) | |
319 self.document = newdoc | |
320 def newCell(self,file): | |
321 img = gtk.Image() | |
322 img.set_from_file(file) | |
323 btn = gtk.EventBox() | |
324 btn.add(img) | |
325 btn.connect("button_press_event", self.cellSelect) | |
326 btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray")) | |
327 return btn | |
328 def showGrid(self): | |
329 max = 0 | |
330 for layer in self.layer: | |
331 for s in layer.scene: | |
332 if s.end > max: | |
333 max = s.end | |
334 max = 50 | |
335 | |
336 self.grid = gtk.Table(len(self.layer)+1, 50) | |
337 self.scrollwin = gtk.ScrolledWindow() | |
338 self.scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) | |
339 self.scrollwin.add_with_viewport(self.grid) | |
340 for i in range(1,max): | |
341 self.grid.attach(gtk.Label('%d'% i), i,i+1,0,1,0,0,0,0) | |
342 for i in range(1,len(self.layer)+1): | |
343 l = self.layer[i-1] | |
344 self.grid.attach(gtk.Label(l.node.get('{http://www.inkscape.org/namespaces/inkscape}label')), 0, 1, i, i+1,0,0,10,0) | |
345 for s in l.scene: | |
346 btn = self.newCell('start.png') | |
347 btn.nScene = s.start | |
348 btn.layer = l.node.get('id') | |
349 btn.nLayer = i | |
350 | |
351 self.grid.attach(btn, s.start, s.start+1, i, i+1,0,0,0,0) | |
352 for j in range(s.start+1,s.end+1): | |
353 btn = self.newCell('fill.png') | |
354 self.grid.attach(btn, j, j+1, i , i+1,0,0,0,0) | |
355 btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray")) | |
356 btn.nScene = j | |
357 btn.layer = l.node.get('id') | |
358 btn.nLayer = i | |
359 if len(l.scene) == 0: | |
360 start = 0 | |
361 else: | |
362 start = l.scene[len(l.scene)-1].end | |
363 for j in range(start,max): | |
364 btn = self.newCell('empty.png') | |
365 self.grid.attach(btn, j+1, j+2,i,i+1,0,0,0,0) | |
366 btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray")) | |
367 btn.nScene = j+1 | |
368 btn.layer = l.node.get('id') | |
369 btn.nLayer = i | |
370 self.last_cell = None | |
371 def cellSelect(self, cell, data): | |
372 if self.last_cell: | |
373 self.last_cell.modify_bg(gtk.STATE_NORMAL, self.last_cell.get_colormap().alloc_color("gray")) | |
374 | |
375 self.last_cell = cell | |
376 cell.modify_bg(gtk.STATE_NORMAL, cell.get_colormap().alloc_color("green")) | |
377 | |
378 def doEditScene(self,w): | |
379 self.setCurrentScene(self.last_cell.nScene) | |
380 self.generate() | |
381 gtk.main_quit() | |
382 | |
383 def doRemoveScene(self,w): | |
384 self.removeKeyScene() | |
385 self.grid.show_all() | |
386 self.generate() | |
387 def addButtons(self,hbox): | |
388 btn = gtk.Button('Edit') | |
389 btn.connect('clicked', self.doEditScene) | |
390 hbox.pack_start(btn) | |
391 btn = gtk.Button('Insert Key') | |
392 btn.connect('clicked',self.doInsertKeyScene) | |
393 hbox.pack_start(btn) | |
394 btn=gtk.Button('Remove Key') | |
395 btn.connect('clicked', self.doRemoveScene) | |
396 hbox.pack_start(btn) | |
397 btn=gtk.Button('Extend scene') | |
398 btn.connect('clicked', self.doExtendScene) | |
399 hbox.pack_start(btn) | |
400 def onQuit(self, event): | |
401 self.OK = False | |
402 gtk.main_quit() | |
403 def onOK(self,event): | |
404 self.OK = True | |
405 gtk.main_quit() | |
406 | |
407 def onConfirmDelete(self): | |
408 if self.scenemap == None: | |
409 vbox = gtk.VBox() | |
410 vbox.pack_start(gtk.Label('Convert the SVG into a MadButterfly SVG file. All current element will be delted')) | |
411 hbox = gtk.HBox() | |
412 self.button = gtk.Button('OK') | |
413 hbox.pack_start(self.button) | |
414 self.button.connect('clicked', self.onOK) | |
415 self.button = gtk.Button('Cancel') | |
416 hbox.pack_start(self.button) | |
417 self.button.connect("clicked", self.onQuit) | |
418 vbox.pack_start(hbox) | |
419 self.window.add(vbox) | |
420 self.window.show_all() | |
421 gtk.main() | |
422 self.window.remove(vbox) | |
423 | |
424 def start_server(self): | |
425 root = MB() | |
426 root.target = self | |
427 site = server.Site(root) | |
428 reactor.listenTCP(8080, site) | |
429 reactor.run() | |
430 | |
431 | |
432 def effect(self): | |
433 self.OK = False | |
434 self.parseScene() | |
435 self.start_server() | |
436 self.generate() | |
437 | |
438 class MB(soap.SOAPPublisher): | |
439 """ | |
440 SOAP server for inkscape extension. | |
441 """ | |
442 | |
443 def soap_PUBLISH(self): | |
444 reactor.callLater(1,self.quit) | |
445 return "OK" | |
446 def quit(self): | |
447 reactor.stop() | |
448 def soap_SCENE(self,n): | |
449 self.target.setCurrentScene(int(n)) | |
450 return "OK" | |
451 def soap_INSERTKEY(self,layer,n): | |
452 try: | |
453 layer = self.target.getLayer(layer) | |
454 self.target.insertKeyScene(layer,int(n)) | |
455 return "OK" | |
456 except: | |
457 return traceback.format_exc() | |
458 def soap_EXTENDSCENE(self,layer,n): | |
459 try: | |
460 layer = self.target.getLayer(layer) | |
461 self.target.extendScene(layer,int(n)) | |
462 return "OK" | |
463 except: | |
464 return traceback.format_exc() | |
465 def soap_DELETESCENE(self,layer,n): | |
466 try: | |
467 layer = self.target.getLayer(layer) | |
468 self.target.deleteScene(layer,int(n)) | |
469 return "OK" | |
470 except: | |
471 return traceback.format_exc() | |
472 def soap_GETDOC(self): | |
473 try: | |
474 self.target.generate() | |
475 return etree.tostring(self.target.document) | |
476 except: | |
477 return traceback.format_exc() | |
478 import os | |
339
63aaf96209cd
* Move location of files so that we can produce XPI file from them.
wycc
parents:
288
diff
changeset
|
479 os.chdir('/usr/local/share/inkscape/extensions') |
288 | 480 |
481 A = MBScene() | |
482 A.affect() | |
483 | |
484 |