233
|
1 #!/usr/bin/python
|
|
2 import inkex
|
|
3 import pygtk
|
|
4 import gtk
|
|
5 from copy import deepcopy
|
|
6 from lxml import etree
|
|
7 import random
|
|
8
|
|
9 # In the inkscape, the top layer group are treated as layer. The Mad butter fly add another structure under the layer as frame. It means that each layer can has multiple frame.
|
|
10 # Like the layer, the frames are represented by special groups. All groups directly under a layer will be treated as frames. However, a group may be spanned for more than one
|
|
11 # frame. For example
|
|
12 # <g id="layer1">
|
|
13 # <g id="g1234" scene="1">
|
|
14 # </g>
|
|
15 # <g id="g1235" scene="2-7">
|
|
16 # </g>
|
|
17 # <g id="g1236">
|
|
18 # </g>
|
|
19 # </g>
|
|
20 # This will stand for 7 scenes. Scene 1 and scene 2 are key scenes. 3,4,5,6,7 are filled scenes.In the above example, g1234 and g1236 are in the scene 1. g1235 and g1236 are in
|
|
21 # scene 2-7
|
|
22 #
|
|
23 # In the inkscape extention, we will provide an grid for users to select the current scene or change the scene structure. Users are allowed to
|
|
24 # Insert a new key scene
|
|
25 # Delete a key scene
|
|
26 # Insert a filled scene
|
|
27 # Delete a filled scene
|
|
28 # Select a scene for edit.
|
|
29 #
|
|
30 # When user select a scene to edit, we will hide all scenes which is not in the selected scene. For example, if we select scene 4, g1234 will be hidden and g1235 and g1236 will
|
|
31 # be displayed.
|
|
32
|
|
33
|
|
34
|
|
35 # Algorithm:
|
|
36 #
|
|
37 # We will parse the first two level of the SVG DOM. collect a table of layer and scene.
|
|
38 # 1. Collect the layer table which will be displayed as the first column of the grid.
|
|
39 # 2. Get the maximum scene number. This will decide the size of the grid.
|
|
40 # 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
|
|
41 # range specified by scene field. The function IsSceneDefined(scene) can be used for this purpose.
|
|
42 # 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
|
|
43 # 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
|
|
44 # "8-10".
|
|
45 # 5. If this scene are filled screne, we will split the existing scene into two scenes with the same content.
|
|
46
|
|
47 class Layer:
|
|
48 def __init__(self,node):
|
|
49 self.scene = []
|
|
50 self.node = node
|
|
51 class Scene:
|
|
52 def __init__(self, node, start,end):
|
|
53 self.node = node
|
|
54 self.start = int(start)
|
|
55 self.end = int(end)
|
|
56
|
|
57
|
|
58 class MBScene(inkex.Effect):
|
|
59 def confirm(self,msg):
|
|
60 vbox = gtk.VBox()
|
|
61 vbox.pack_start(gtk.Label(msg))
|
|
62 self.button = gtk.Button('OK')
|
|
63 vbox.pack_start(self.button)
|
|
64 self.button.connect("clicked", self.onQuit)
|
|
65 self.window.add(vbox)
|
|
66 def dumpattr(self,n):
|
|
67 s = ""
|
|
68 for a,v in n.attrib.items():
|
|
69 s = s + ("%s=%s" % (a,v))
|
|
70 return s
|
|
71
|
|
72 def dump(self,node,l=0):
|
|
73 print " " * l*2,"<", node.tag, self.dumpattr(node),">"
|
|
74 for n in node:
|
|
75 self.dump(n,l+1)
|
|
76 print " " * l * 2,"/>"
|
|
77
|
|
78 def parseScene(self):
|
|
79 self.layer = []
|
|
80 for layer in self.document.getroot():
|
|
81 if layer.tag == '{http://www.w3.org/2000/svg}g':
|
|
82 #print layer.attrib.get("id")
|
|
83 lyobj = Layer(layer)
|
|
84 self.layer.append(lyobj)
|
|
85 for scene in layer:
|
|
86 if scene.tag == '{http://www.w3.org/2000/svg}g':
|
|
87 range = scene.attrib.get("scene").split('-')
|
|
88 if len(range) == 1:
|
|
89 #print " scene %d" % int(range[0])
|
|
90 lyobj.scene.append(Scene(scene,range[0],range[0]))
|
|
91 elif len(range) == 2:
|
|
92 #print " scene%d-%d" % (int(range[0]),int(range[1]))
|
|
93 lyobj.scene.append(Scene(scene,range[0],range[1]))
|
|
94 self.collectID()
|
|
95 #self.dumpID()
|
|
96 def collectID(self):
|
|
97 self.ID = {}
|
|
98 root = self.document.getroot()
|
|
99 for n in root:
|
|
100 self.collectID_recursive(n)
|
|
101 def collectID_recursive(self,node):
|
|
102 self.ID[node.get("id")] = 1
|
|
103 for n in node:
|
|
104 self.collectID_recursive(n)
|
|
105 def newID(self):
|
|
106 while True:
|
|
107 n = 's%d' % int(random.random()*10000)
|
|
108 #print "try %s" % n
|
|
109 if self.ID.has_key(n) == False:
|
|
110 return n
|
|
111 def dumpID(self):
|
|
112 for a,v in self.ID.items():
|
|
113 print a
|
|
114
|
|
115
|
|
116 def getLayer(self, layer):
|
|
117 for l in self.layer:
|
|
118 if l.node.attrib.get("id") == layer:
|
|
119 return l
|
|
120 return None
|
|
121
|
|
122
|
|
123 def insertKeyScene(self):
|
|
124 """
|
|
125 Insert a new key scene into the stage. If the nth is always a key scene, we will return without changing anything.
|
|
126 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
|
|
127 append a new scene.
|
|
128
|
|
129 """
|
|
130 nth = self.last_cell.nScene
|
|
131 layer = self.getLayer(self.last_cell.layer)
|
|
132 x = self.last_cell.nScene
|
|
133 y = self.last_cell.nLayer
|
|
134 if layer == None: return
|
|
135 for i in range(0,len(layer.scene)):
|
|
136 s = layer.scene[i]
|
|
137 if nth >= s.start and nth <= s.end:
|
|
138 if nth == s.start: return
|
|
139 newscene = Scene(deepcopy(s.node),nth,s.end)
|
|
140 newscene.node.set("id", self.newID())
|
|
141 layer.scene.insert(i+1,newscene)
|
|
142 layer.scene[i].end = nth-1
|
|
143 btn = self.newCell('start.png')
|
|
144 btn.nScene = nth
|
|
145 btn.layer = layer
|
|
146 btn.nLayer = y
|
|
147 self.grid.remove(self.last_cell)
|
|
148 self.grid.attach(btn, x,x+1,y,y+1,0,0,0,0)
|
|
149 return
|
|
150 if len(layer.scene) > 0:
|
|
151 last = layer.scene[len(layer.scene)-1]
|
|
152 for x in range(last.end+1, nth):
|
|
153 btn = self.newCell('fill.png')
|
|
154 btn.nScene = x
|
|
155 btn.layer = layer
|
|
156 btn.nLayer = y
|
|
157 self.grid.attach(btn, x, x+1, y , y+1,0,0,0,0)
|
|
158 last.end = nth-1
|
|
159 newscene = Scene(deepcopy(s.node),nth,nth)
|
|
160 newscene.node.set("id",self.newID())
|
|
161 layer.scene.append(newscene)
|
|
162 btn = self.newCell('start.png')
|
|
163 x = self.last_cell.nScene
|
|
164 y = self.last_cell.nLayer
|
|
165 btn.nScene = nth
|
|
166 btn.layer = layer
|
|
167 btn.nLayer = y
|
|
168 self.grid.attach(btn, x, x+1, y, y+1,0,0,0,0)
|
|
169
|
|
170
|
|
171 def removeKeyScene(self):
|
|
172 nth = self.last_cell.nScene
|
|
173 layer = self.getLayer(self.last_cell.layer)
|
|
174 x = self.last_cell.nScene
|
|
175 y = self.last_cell.nLayer
|
|
176 # We can not remove the key scene at the first scene
|
|
177 if nth == 1: return
|
|
178 for i in range(0,len(layer.scene)):
|
|
179 s = layer.scene[i]
|
|
180 if nth == s.start:
|
|
181 layer.scene[i-1].end = s.end
|
|
182 layer.scene.remove(s)
|
|
183 btn = self.newCell('fill.png')
|
|
184 btn.nScene = nth
|
|
185 btn.layer = layer
|
|
186 btn.nLayer = y
|
|
187 self.grid.attach(btn, x,x+1,y,y+1,0,0,0,0)
|
|
188 return
|
|
189
|
|
190 def extendScene(self,layer,nth):
|
|
191 layer = self.getLayer(layer)
|
|
192 if layer == None: return
|
|
193 for i in range(0,len(layer.scene)-1):
|
|
194 s = layer.scene[i]
|
|
195 if nth >= layer.scene[i].start and nth < layer.scene[i+1].start:
|
|
196 layer.scene[i].end = nth
|
|
197 if len(layer.scene) > 0:
|
|
198 layer.scene[len(layer.scene)-1].end = nth
|
|
199 def setCurrentScene(self,nth):
|
|
200 for layer in self.layer:
|
|
201 for s in layer.scene:
|
|
202 if nth >= s.start and nth <= s.end:
|
|
203 s.node.set("style","")
|
|
204 else:
|
|
205 s.node.set("style","display:none")
|
|
206 def generate(self):
|
|
207 newdoc = deepcopy(self.document)
|
|
208 root = newdoc.getroot()
|
|
209 for n in root:
|
|
210 if n.tag == '{http://www.w3.org/2000/svg}g':
|
|
211 root.remove(n)
|
|
212
|
|
213 for l in self.layer:
|
|
214 # Duplicate all attribute of the layer
|
|
215 lnode = etree.Element("{http://www.w3.org/2000/svg}g")
|
|
216 for a,v in l.node.attrib.items():
|
|
217 lnode.set(a,v)
|
|
218 root.append(lnode)
|
|
219 for s in l.scene:
|
|
220 snode = etree.Element("{http://www.w3.org/2000/svg}g")
|
|
221 for a,v in s.node.attrib.items():
|
|
222 snode.set(a,v)
|
|
223 if s.start == s.end:
|
|
224 snode.set("scene", "%d" % s.start)
|
|
225 else:
|
|
226 snode.set("scene","%d-%d" % (s.start,s.end))
|
|
227 for n in s.node:
|
|
228 snode.append(deepcopy(n))
|
|
229 lnode.append(snode)
|
|
230 self.document = newdoc
|
|
231 def newCell(self,file):
|
|
232 img = gtk.Image()
|
|
233 img.set_from_file(file)
|
|
234 btn = gtk.EventBox()
|
|
235 btn.add(img)
|
|
236 btn.connect("button_press_event", self.cellSelect)
|
|
237 btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray"))
|
|
238 return btn
|
|
239 def showGrid(self):
|
|
240 max = 0
|
|
241 for layer in self.layer:
|
|
242 for s in layer.scene:
|
|
243 if s.end > max:
|
|
244 max = s.end
|
|
245 max = 50
|
|
246
|
|
247 self.grid = gtk.Table(len(self.layer)+1, 50)
|
|
248 self.scrollwin = gtk.ScrolledWindow()
|
|
249 self.scrollwin.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC)
|
|
250 self.scrollwin.add_with_viewport(self.grid)
|
|
251 for i in range(1,max):
|
|
252 self.grid.attach(gtk.Label('%d'% i), i,i+1,0,1,0,0,0,0)
|
|
253 for i in range(1,len(self.layer)+1):
|
|
254 l = self.layer[i-1]
|
|
255 self.grid.attach(gtk.Label(l.node.get('id')), 0, 1, i, i+1,0,0,10,0)
|
|
256 for s in l.scene:
|
|
257 btn = self.newCell('start.png')
|
|
258 btn.nScene = s.start
|
|
259 btn.layer = l.node.get('id')
|
|
260 btn.nLayer = i
|
|
261
|
|
262 self.grid.attach(btn, s.start, s.start+1, i, i+1,0,0,0,0)
|
|
263 for j in range(s.start+1,s.end+1):
|
|
264 btn = self.newCell('fill.png')
|
|
265 self.grid.attach(btn, j, j+1, i , i+1,0,0,0,0)
|
|
266 btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray"))
|
|
267 btn.nScene = j
|
|
268 btn.layer = l.node.get('id')
|
|
269 btn.nLayer = i
|
|
270 if len(l.scene) == 0:
|
|
271 start = 0
|
|
272 else:
|
|
273 start = l.scene[len(l.scene)-1].end
|
|
274 for j in range(start,max):
|
|
275 btn = self.newCell('empty.png')
|
|
276 self.grid.attach(btn, j+1, j+2,i,i+1,0,0,0,0)
|
|
277 btn.modify_bg(gtk.STATE_NORMAL, btn.get_colormap().alloc_color("gray"))
|
|
278 btn.nScene = j+1
|
|
279 btn.layer = l.node.get('id')
|
|
280 btn.nLayer = i
|
|
281 self.last_cell = None
|
|
282 def cellSelect(self, cell, data):
|
|
283 if self.last_cell:
|
|
284 self.last_cell.modify_bg(gtk.STATE_NORMAL, self.last_cell.get_colormap().alloc_color("gray"))
|
|
285
|
|
286 self.last_cell = cell
|
|
287 cell.modify_bg(gtk.STATE_NORMAL, cell.get_colormap().alloc_color("green"))
|
|
288
|
|
289 def doEditScene(self,w):
|
|
290 self.setCurrentScene(self.last_cell.nScene)
|
|
291 self.generate()
|
|
292 gtk.main_quit()
|
|
293 def doInsertKeyScene(self,w):
|
|
294 self.insertKeyScene()
|
|
295 self.grid.show_all()
|
|
296 self.generate()
|
|
297
|
|
298 def doRemoveScene(self,w):
|
|
299 self.removeKeyScene()
|
|
300 self.grid.show_all()
|
|
301 self.generate()
|
|
302 def addButtons(self,hbox):
|
|
303 btn = gtk.Button('Edit')
|
|
304 btn.connect('clicked', self.doEditScene)
|
|
305 hbox.pack_start(btn)
|
|
306 btn = gtk.Button('Insert Key')
|
|
307 btn.connect('clicked',self.doInsertKeyScene)
|
|
308 hbox.pack_start(btn)
|
|
309 btn=gtk.Button('Remove Key')
|
|
310 btn.connect('clicked', self.doRemoveScene)
|
|
311 hbox.pack_start(btn)
|
|
312 def effect(self):
|
|
313 self.parseScene()
|
|
314 self.showGrid()
|
|
315 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
|
|
316 self.window.connect("destroy", gtk.main_quit)
|
|
317 self.window.set_position(gtk.WIN_POS_MOUSE)
|
|
318 vbox = gtk.VBox()
|
|
319 self.window.add(vbox)
|
|
320 vbox.add(self.scrollwin)
|
|
321 self.vbox = vbox
|
|
322 hbox=gtk.HBox()
|
|
323 self.addButtons(hbox)
|
|
324 vbox.add(hbox)
|
|
325 self.window.set_size_request(600,200)
|
|
326 self.window.show_all()
|
|
327 gtk.main()
|
|
328
|
|
329
|
|
330
|
|
331
|
|
332
|
|
333 A = MBScene()
|
|
334 A.affect()
|
|
335
|
|
336
|