Mercurial > MadButterfly
comparison pyink/MBScene.py @ 1189:9cf183faf89f
Maintaining scene group ID to scene node mapping in MBScene_dom_monitor
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Sat, 01 Jan 2011 19:52:28 +0800 |
parents | 45e3a9273af2 |
children | a4df892fb4e5 |
comparison
equal
deleted
inserted
replaced
1188:45e3a9273af2 | 1189:9cf183faf89f |
---|---|
159 class MBScene_dom_monitor(object): | 159 class MBScene_dom_monitor(object): |
160 def __init__(self, *args, **kws): | 160 def __init__(self, *args, **kws): |
161 super(MBScene_dom_monitor, self).__init__() | 161 super(MBScene_dom_monitor, self).__init__() |
162 | 162 |
163 self._id2node = {} # map ID to the node in the DOM tree. | 163 self._id2node = {} # map ID to the node in the DOM tree. |
164 self._group2scene = {} # map ID of a group to associated scene node. | |
164 pass | 165 pass |
165 | 166 |
166 def _start_monitor(self): | 167 def _start_monitor(self): |
167 self._collect_node_ids() | 168 self._collect_node_ids() |
168 | 169 |
174 | 175 |
175 def _on_insert_node(self, node): | 176 def _on_insert_node(self, node): |
176 try: | 177 try: |
177 node_id = node.getAttribute('id') | 178 node_id = node.getAttribute('id') |
178 except: | 179 except: |
179 return | 180 pass |
180 self._id2node[node_id] = node | 181 else: |
182 if node_id not in self._id2node: | |
183 self._id2node[node_id] = node | |
184 pass | |
185 pass | |
186 | |
187 if node.name() == 'ns0:scene': | |
188 try: | |
189 ref = node.getAttribute('ref') | |
190 except: | |
191 pass | |
192 else: | |
193 print 'scene %s' % (ref) | |
194 if ref not in self._group2scene: | |
195 self._group2scene[ref] = node | |
196 pass | |
197 pass | |
198 pass | |
181 pass | 199 pass |
182 | 200 |
183 def _on_remove_node(self, node): | 201 def _on_remove_node(self, node): |
184 try: | 202 try: |
185 node_id = node.getAttribute('id') | 203 node_id = node.getAttribute('id') |
186 except: | 204 except: |
205 pass | |
206 else: | |
207 if node_id not in self._id2node: | |
208 raise ValueError, \ | |
209 'remove a node that is never known (%s)' % (node_id) | |
210 del self._id2node[node_id] | |
211 pass | |
212 | |
213 if node.name() == 'ns0:scene': | |
214 try: | |
215 ref = node.getAttribute('ref') | |
216 except: | |
217 pass | |
218 else: | |
219 del self._group2scene[ref] | |
220 pass | |
221 pass | |
222 pass | |
223 | |
224 def _on_attr_modified(self, node, name, old_value, new_value): | |
225 print 'chg attr %s' % (name) | |
226 if name == 'id' and old_value != new_value: | |
227 if old_value and (old_value not in self._id2node): | |
228 raise ValueError, \ | |
229 'old ID value of passed node is valid one (%s)' % \ | |
230 (old_value) | |
231 if (new_value in self._id2node): | |
232 raise ValueError, \ | |
233 'new ID value of passed node is valid one (%s)' % \ | |
234 (new_value) | |
235 | |
236 if old_value: | |
237 del self._id2node[old_value] | |
238 pass | |
239 self._id2node[new_value] = node | |
240 pass | |
241 elif name == 'ref' and node.name() == 'ns0:scene': | |
242 print 'change ref %s' % (new_value) | |
243 if old_value == new_value: | |
244 return | |
245 if old_value: | |
246 node = self._group2scene[old_value] # use old node. Binding | |
247 # may generate a new | |
248 # wrapper. | |
249 del self._group2scene[old_value] | |
250 pass | |
251 if new_value: | |
252 self._group2scene[new_value] = node | |
253 pass | |
187 return | 254 return |
188 if node_id not in self._id2node: | |
189 raise ValueError, \ | |
190 'remove a node that is never known (%s)' % (node_id) | |
191 del self._id2node[node_id] | |
192 pass | |
193 | |
194 def _on_attr_modified(self, node, name, old_value, new_value): | |
195 if name != 'id' or old_value == new_value: | |
196 return | |
197 | |
198 if old_value and (old_value not in self._id2node): | |
199 raise ValueError, \ | |
200 'old ID value of passed node is valid one (%s)' % (old_value) | |
201 if (new_value in self._id2node): | |
202 raise ValueError, \ | |
203 'new ID value of passed node is valid one (%s)' % (new_value) | |
204 | |
205 if old_value: | |
206 del self._id2node[old_value] | |
207 pass | |
208 self._id2node[new_value] = node | |
209 pass | 255 pass |
210 | 256 |
211 def _collect_node_ids(self): | 257 def _collect_node_ids(self): |
212 self._id2node = {} | 258 self._id2node = {} |
213 root = self._root | 259 root = self._root |
229 pass | 275 pass |
230 | 276 |
231 def get_node(self, node_id): | 277 def get_node(self, node_id): |
232 return self._id2node[node_id] | 278 return self._id2node[node_id] |
233 | 279 |
280 def get_scene(self, group_id): | |
281 print 'get_scene %s' % (group_id) | |
282 return self._group2scene[group_id] | |
283 | |
234 def new_id(self): | 284 def new_id(self): |
235 while True: | 285 while True: |
236 candidate = 's%d' % int(random.random()*100000) | 286 candidate = 's%d' % int(random.random()*100000) |
237 if candidate not in self._id2node: | 287 if candidate not in self._id2node: |
238 return candidate | 288 return candidate |
251 def handle_doc_root(self, doc, root): | 301 def handle_doc_root(self, doc, root): |
252 self._doc = doc | 302 self._doc = doc |
253 self._root = root | 303 self._root = root |
254 | 304 |
255 self._start_monitor() # start MBScene_dom_monitor | 305 self._start_monitor() # start MBScene_dom_monitor |
306 self._init_metadata() | |
256 pass | 307 pass |
257 | 308 |
258 def dumpattr(self, n): | 309 def dumpattr(self, n): |
259 s = "" | 310 s = "" |
260 for a,v in n.attrib.items(): | 311 for a,v in n.attrib.items(): |
267 for n in node: | 318 for n in node: |
268 self.dump(n, l+1) | 319 self.dump(n, l+1) |
269 pass | 320 pass |
270 print " " * l * 2,"/>" | 321 print " " * l * 2,"/>" |
271 pass | 322 pass |
323 | |
324 def _parse_one_scene(self, scene): | |
325 assert scene.name() == 'ns0:scene' | |
326 | |
327 start = int(scene.getAttribute("start")) | |
328 try: | |
329 end = int(scene.getAttribute("end")) | |
330 except: | |
331 end = start | |
332 pass | |
333 | |
334 try: | |
335 scene_type = scene.getAttribute('type') | |
336 if scene_type == None: | |
337 scene_type = 'normal' | |
338 pass | |
339 except: | |
340 scene_type = 'normal' | |
341 pass | |
342 | |
343 return start, end, scene_type | |
272 | 344 |
273 def _parse_one_scenes(self, scenes): | 345 def _parse_one_scenes(self, scenes): |
274 self.scenemap = {} | 346 self.scenemap = {} |
275 try: | 347 try: |
276 cur = int(n.getAttribute("current")) | 348 cur = int(n.getAttribute("current")) |
280 self.current = cur | 352 self.current = cur |
281 | 353 |
282 for scene in scenes.childList(): | 354 for scene in scenes.childList(): |
283 if scene.name() != 'ns0:scene': | 355 if scene.name() != 'ns0:scene': |
284 continue | 356 continue |
285 | 357 |
286 try: | 358 try: |
287 start = int(scene.getAttribute("start")) | 359 start, end, scene_type = self._parse_one_scene(scene) |
288 except: | 360 except: |
289 traceback.print_exc() | |
290 continue | 361 continue |
291 try: | |
292 end = int(scene.getAttribute("end")) | |
293 except: | |
294 end = start | |
295 pass | |
296 | 362 |
297 if end > self.maxframe: | 363 if end > self.maxframe: |
298 self.maxframe = end | 364 self.maxframe = end |
299 pass | 365 pass |
300 try: | 366 |
301 scene_type = scene.getAttribute('type') | |
302 if scene_type == None: | |
303 scene_type = 'normal' | |
304 pass | |
305 except: | |
306 traceback.print_exc() | |
307 scene_type = 'normal' | |
308 pass | |
309 link = scene.getAttribute("ref") | 367 link = scene.getAttribute("ref") |
310 self.scenemap[link] = (int(start), int(end), scene_type) | 368 self.scenemap[link] = (start, end, scene_type) |
311 if cur >= start and cur <= end: | 369 if cur >= start and cur <= end: |
312 self.currentscene = link | 370 self.currentscene = link |
313 pass | 371 pass |
314 pass | 372 pass |
315 pass | 373 pass |
316 | 374 |
317 def parseMetadata(self, node): | 375 def _init_metadata(self): |
376 for node in self._root.childList(): | |
377 if node.name() == 'svg:metadata': | |
378 break | |
379 pass | |
380 else: | |
381 raise RuntimeError, \ | |
382 'can not find <svg:metadata> node in the document' | |
383 | |
318 for n in node.childList(): | 384 for n in node.childList(): |
319 if n.name() == 'ns0:scenes': | 385 if n.name() == 'ns0:scenes': |
320 self._parse_one_scenes(n) | |
321 break | 386 break |
322 pass | 387 pass |
323 else: | 388 else: |
324 ns = "http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd" | 389 ns = "http://madbutterfly.sourceforge.net/DTD/madbutterfly.dtd" |
325 self._root.setAttribute("xmlns:ns0", ns) | 390 self._root.setAttribute("xmlns:ns0", ns) |
326 scenes = self._doc.createElement("ns0:scenes") | 391 scenes = self._doc.createElement("ns0:scenes") |
327 node.appendChild(scenes) | 392 node.appendChild(scenes) |
328 pass | 393 pass |
329 pass | 394 pass |
330 | 395 |
331 def insertKeyScene(self, line, frame): | 396 def insertKeyScene(self, line, frame): |
332 """ | 397 """ |
333 Insert a new key scene into the stage. If the nth is always a | 398 Insert a new key scene into the stage. If the nth is always a |
334 key scene, we will return without changing anything. If the | 399 key scene, we will return without changing anything. If the |
335 nth is a filled scene, we will break the original scene into | 400 nth is a filled scene, we will break the original scene into |
336 two parts. If the nth is out of any scene, we will append a | 401 two parts. If the nth is out of any scene, we will append a |
337 new scene. | 402 new scene. |
338 | 403 |
339 """ | 404 """ |
340 rdoc = self._doc | 405 rdoc = self._doc |
341 ns = rdoc.createElement("svg:g") | 406 scene_group = rdoc.createElement("svg:g") |
342 found = False | 407 found = False |
343 for node in line.node.childList(): | 408 for node in line.node.childList(): |
344 try: | 409 try: |
345 label = node.getAttribute("inkscape:label") | 410 label = node.getAttribute("inkscape:label") |
346 except: | 411 except: |
348 if label == "dup": | 413 if label == "dup": |
349 #FIXME: The duplication here is not perfect. We should | 414 #FIXME: The duplication here is not perfect. We should |
350 # get the element inside the group and apply the | 415 # get the element inside the group and apply the |
351 # transformation matrix to it directly. | 416 # transformation matrix to it directly. |
352 for n in node.childList(): | 417 for n in node.childList(): |
353 ns.appendChild(n.duplicate(self._doc)) | 418 scene_group.appendChild(n.duplicate(self._doc)) |
354 found = True | 419 found = True |
355 node.setAttribute("style","display:none") | 420 node.setAttribute("style","display:none") |
356 break | 421 break |
357 pass | 422 pass |
358 pass | 423 pass |
362 txt.setAttribute("x","0") | 427 txt.setAttribute("x","0") |
363 txt.setAttribute("y","0") | 428 txt.setAttribute("y","0") |
364 txt.setAttribute("width","100") | 429 txt.setAttribute("width","100") |
365 txt.setAttribute("height","100") | 430 txt.setAttribute("height","100") |
366 txt.setAttribute("style","fill:#ff00") | 431 txt.setAttribute("style","fill:#ff00") |
367 ns.appendChild(txt) | 432 scene_group.appendChild(txt) |
368 | 433 |
369 gid = line.node.getAttribute('inkscape:label')+self.new_id() | 434 gid = line.node.getAttribute('inkscape:label')+self.new_id() |
370 ns.setAttribute("id",gid) | 435 scene_group.setAttribute("id",gid) |
371 ns.setAttribute("inkscape:groupmode","layer") | 436 scene_group.setAttribute("inkscape:groupmode","layer") |
372 line.node.appendChild(ns) | 437 line.node.appendChild(scene_group) |
373 line.add_keyframe(frame, ns) | 438 line.add_keyframe(frame, scene_group) |
374 self.update_scenes_of_dom() | 439 self.update_scenes_of_dom() |
375 pass | 440 pass |
376 | 441 |
377 def add_scene_on_dom(self, frameline, scenes_node): | 442 def add_scene_on_dom(self, frameline, scenes_node): |
378 doc = self._doc | 443 doc = self._doc |
385 scenes_node.appendChild(scene_node) | 450 scenes_node.appendChild(scene_node) |
386 scene_node.setAttribute("start", str(start_idx + 1)) | 451 scene_node.setAttribute("start", str(start_idx + 1)) |
387 if start_idx != stop_idx: | 452 if start_idx != stop_idx: |
388 scene_node.setAttribute("end", str(stop_idx + 1)) | 453 scene_node.setAttribute("end", str(stop_idx + 1)) |
389 pass | 454 pass |
390 scene_node.setAttribute("ref", ref.attribute("id")) | 455 scene_node.setAttribute("ref", ref.getAttribute("id")) |
391 scene_node.setAttribute("type", tween_type_name) | 456 scene_node.setAttribute("type", tween_type_name) |
392 pass | 457 pass |
393 pass | 458 pass |
394 | 459 |
395 def update_scenes_of_dom(self): | 460 def update_scenes_of_dom(self): |
417 In this function, we will collect all items for the current | 482 In this function, we will collect all items for the current |
418 scene and then relocate them back to the appropriate scene | 483 scene and then relocate them back to the appropriate scene |
419 object. | 484 object. |
420 """ | 485 """ |
421 self.layers = [] | 486 self.layers = [] |
422 self.scenemap = None | |
423 doc = self._root | 487 doc = self._root |
424 | 488 |
425 # TODO: Remove following code sicne this function is for parsing. | 489 # TODO: Remove following code sicne this function is for parsing. |
426 # Why do this here? | 490 # Why do this here? |
427 addEventListener(doc,'DOMNodeInserted',self.updateUI,None) | 491 addEventListener(doc,'DOMNodeInserted',self.updateUI,None) |
435 self.width = 640 | 499 self.width = 640 |
436 self.height=480 | 500 self.height=480 |
437 pass | 501 pass |
438 | 502 |
439 for node in doc.childList(): | 503 for node in doc.childList(): |
440 print node.name() | 504 if node.name() == 'svg:g': |
441 if node.name() == 'svg:metadata': | |
442 self.parseMetadata(node) | |
443 pass | |
444 elif node.name() == 'svg:g': | |
445 oldscene = None | 505 oldscene = None |
446 lyobj = Layer(node) | 506 lyobj = Layer(node) |
447 self.layers.append(lyobj) | 507 self.layers.append(lyobj) |
448 lyobj.current_scene = [] | 508 lyobj.current_scene = [] |
449 for scene in node.childList(): | 509 for scene in node.childList(): |
458 except: | 518 except: |
459 pass | 519 pass |
460 | 520 |
461 try: | 521 try: |
462 scene_id = scene.getAttribute('id') | 522 scene_id = scene.getAttribute('id') |
463 start, stop, tween_type = self.scenemap[scene_id] | 523 scene = self.get_scene(scene_id) |
524 start, stop, tween_type = \ | |
525 self._parse_one_scene(scene) | |
464 except: | 526 except: |
465 lyobj.current_scene.append(scene) | 527 lyobj.current_scene.append(scene) |
466 continue | 528 continue |
467 | 529 |
468 lyobj.scenes.append(Scene(scene, start, stop, | 530 lyobj.scenes.append(Scene(scene, start, stop, |
496 | 558 |
497 self.desktop = desktop | 559 self.desktop = desktop |
498 self.window = win | 560 self.window = win |
499 self.layers = [] | 561 self.layers = [] |
500 self.layers.append(Layer(None)) | 562 self.layers.append(Layer(None)) |
501 self.scenemap = None | |
502 self.top = None | 563 self.top = None |
503 self.last_update = None | 564 self.last_update = None |
504 pybInkscape.inkscape.connect('change_selection', self.show_selection) | 565 pybInkscape.inkscape.connect('change_selection', self.show_selection) |
505 self.last_select = None | 566 self.last_select = None |
506 self.lockui=False | 567 self._lockui=False |
507 self.tween=None | 568 self.tween=None |
508 self.document = None | 569 self.document = None |
509 self.root = root | 570 self.root = root |
510 self.framerate=12 | 571 self.framerate=12 |
511 self.maxframe=0 | 572 self.maxframe=0 |
769 | 830 |
770 def onCellClick(self, line, frame, but): | 831 def onCellClick(self, line, frame, but): |
771 self.last_line = line | 832 self.last_line = line |
772 self.last_frame = frame | 833 self.last_frame = frame |
773 self.last_line.active_frame(frame) | 834 self.last_line.active_frame(frame) |
774 self.lockui = True | 835 self._lockui = True |
775 self.doEditScene(None) | 836 self.doEditScene(None) |
776 self.lockui = False | 837 self._lockui = False |
777 pass | 838 pass |
778 | 839 |
779 def _remove_active_frame(self,widget,event): | 840 def _remove_active_frame(self,widget,event): |
780 """ | 841 """ |
781 Hide all hover frames. This is a hack. We should use the lost focus event | 842 Hide all hover frames. This is a hack. We should use the lost focus event |
937 self.setCurrentScene(self.last_frame+1) | 998 self.setCurrentScene(self.last_frame+1) |
938 self.selectSceneObject(self.last_line, self.last_frame) | 999 self.selectSceneObject(self.last_line, self.last_frame) |
939 pass | 1000 pass |
940 | 1001 |
941 def doInsertKeyScene(self,w): | 1002 def doInsertKeyScene(self,w): |
942 self.lockui=True | 1003 self._lockui=True |
943 self.insertKeyScene(self.last_line, self.last_frame) | 1004 self.insertKeyScene(self.last_line, self.last_frame) |
944 self.selectSceneObject(self.last_line, self.last_frame) | 1005 self.selectSceneObject(self.last_line, self.last_frame) |
945 self.lockui=False | 1006 self._lockui=False |
946 # self.grid.show_all() | 1007 # self.grid.show_all() |
947 return | 1008 return |
948 | 1009 |
949 def doDuplicateKeyScene(self,w): | 1010 def doDuplicateKeyScene(self,w): |
950 self.lockui = True | 1011 self._lockui = True |
951 self.duplicateKeyScene() | 1012 self.duplicateKeyScene() |
952 self.lockui = False | 1013 self._lockui = False |
953 | 1014 |
954 def doRemoveScene(self,w): | 1015 def doRemoveScene(self,w): |
955 self.lockui = True | 1016 self._lockui = True |
956 self.removeKeyScene() | 1017 self.removeKeyScene() |
957 self.lockui = False | 1018 self._lockui = False |
958 return | 1019 return |
959 | 1020 |
960 | 1021 |
961 def doExtendScene(self,w): | 1022 def doExtendScene(self,w): |
962 self.lockui = True | 1023 self._lockui = True |
963 self.extendScene() | 1024 self.extendScene() |
964 self.lockui = False | 1025 self._lockui = False |
965 #self.grid.show_all() | 1026 #self.grid.show_all() |
966 pass | 1027 pass |
967 | 1028 |
968 def changeObjectLabel(self,w): | 1029 def changeObjectLabel(self,w): |
969 o = self.desktop.selection.list()[0] | 1030 o = self.desktop.selection.list()[0] |
982 """ | 1043 """ |
983 Execute the current animation till the last frame. | 1044 Execute the current animation till the last frame. |
984 """ | 1045 """ |
985 if self.btnRun.get_label() == "Run": | 1046 if self.btnRun.get_label() == "Run": |
986 self.btnRun.set_label("Stop") | 1047 self.btnRun.set_label("Stop") |
987 self.lockui = True | 1048 self._lockui = True |
988 self.last_update = glib.timeout_add(1000/self.framerate,self.doRunNext) | 1049 self.last_update = glib.timeout_add(1000/self.framerate,self.doRunNext) |
989 else: | 1050 else: |
990 self.btnRun.set_label("Run") | 1051 self.btnRun.set_label("Run") |
991 glib.source_remove(self.last_update) | 1052 glib.source_remove(self.last_update) |
992 self.lockui = False | 1053 self._lockui = False |
993 pass | 1054 pass |
994 | 1055 |
995 def doRunNext(self): | 1056 def doRunNext(self): |
996 if self.current >= self.maxframe: | 1057 if self.current >= self.maxframe: |
997 self.current = 0 | 1058 self.current = 0 |
1001 traceback.print_exc() | 1062 traceback.print_exc() |
1002 raise | 1063 raise |
1003 self.last_update = glib.timeout_add(1000/self.framerate,self.doRunNext) | 1064 self.last_update = glib.timeout_add(1000/self.framerate,self.doRunNext) |
1004 | 1065 |
1005 def doInsertScene(self,w): | 1066 def doInsertScene(self,w): |
1006 self.lockui=True | 1067 self._lockui=True |
1007 self.last_line.insert_frame(self.last_frame) | 1068 self.last_line.insert_frame(self.last_frame) |
1008 self.update_scenes_of_dom() | 1069 self.update_scenes_of_dom() |
1009 self.lockui=False | 1070 self._lockui=False |
1010 | 1071 |
1011 def doRemoveScene(self,w): | 1072 def doRemoveScene(self,w): |
1012 self.lockui=True | 1073 self._lockui=True |
1013 self.last_line.remove_frame(self.last_frame) | 1074 self.last_line.remove_frame(self.last_frame) |
1014 self.update_scenes_of_dom() | 1075 self.update_scenes_of_dom() |
1015 self.lockui=False | 1076 self._lockui=False |
1016 | 1077 |
1017 def addButtons(self,hbox): | 1078 def addButtons(self,hbox): |
1018 btn = gtk.Button('Insert Key') | 1079 btn = gtk.Button('Insert Key') |
1019 btn.connect('clicked',self.doInsertKeyScene) | 1080 btn.connect('clicked',self.doInsertKeyScene) |
1020 hbox.pack_start(btn,expand=False,fill=False) | 1081 hbox.pack_start(btn,expand=False,fill=False) |
1096 self.OK = True | 1157 self.OK = True |
1097 gtk.main_quit() | 1158 gtk.main_quit() |
1098 pass | 1159 pass |
1099 | 1160 |
1100 def updateUI(self,node=None,arg=None): | 1161 def updateUI(self,node=None,arg=None): |
1101 if self.lockui: return | 1162 if self._lockui: return |
1102 | 1163 |
1103 if self.last_update!= None: | 1164 if self.last_update!= None: |
1104 glib.source_remove(self.last_update) | 1165 glib.source_remove(self.last_update) |
1105 self.last_update = glib.timeout_add(300,self._updateUI) | 1166 self.last_update = glib.timeout_add(300,self._updateUI) |
1106 | 1167 |
1107 pass | 1168 pass |
1108 | 1169 |
1109 def _updateUI(self,node=None,arg=None): | 1170 def _updateUI(self,node=None,arg=None): |
1171 self._lockui = True | |
1110 self.parseScene() | 1172 self.parseScene() |
1111 self._create_framelines() | 1173 self._create_framelines() |
1112 self._update_framelines() | 1174 self._update_framelines() |
1175 self._lockui = False | |
1113 pass | 1176 pass |
1114 | 1177 |
1115 def show(self): | 1178 def show(self): |
1116 self.OK = True | 1179 self.OK = True |
1117 if not self.root: | 1180 if not self.root: |