Mercurial > MadButterfly
comparison pyink/domview_ui.py @ 1243:d5f70928e9f1
Move MBScene_domview_ui and MBScene_domview to separated modules.
- domview.py is where MBScene_domview and MBScene_domview_monitor are.
- domview_ui.py is where MBScene_domview_ui and MBScene_frameline_stack are.
- keep modules small to make better collaberation.
author | Thinker K.F. Li <thinker@codemud.net> |
---|---|
date | Mon, 10 Jan 2011 16:32:16 +0800 |
parents | |
children | b241f9768833 |
comparison
equal
deleted
inserted
replaced
1242:1b1eb8f9a866 | 1243:d5f70928e9f1 |
---|---|
1 import gtk | |
2 from tween import TweenObject | |
3 from frameline import frameline, frameruler | |
4 from domview import MBScene_domview | |
5 | |
6 | |
7 ## \brief Maintain a stack of frameline UI component. | |
8 # | |
9 # Every layer is assocated with a frameline. Framelines are showed/stacked in | |
10 # virtical. Framelines of lower layers are placed at lower position on the | |
11 # screen. This class provide a set of API to access framelines with layer and | |
12 # frame index number. You access/set content of frameline by specifing layer | |
13 # index and frame index. | |
14 # | |
15 class MBScene_frameline_stack(object): | |
16 _frameline_tween_types = (frameline.TWEEN_TYPE_NONE, | |
17 frameline.TWEEN_TYPE_SHAPE) | |
18 _num_frames_of_line = 100 | |
19 | |
20 _framelines = None | |
21 | |
22 def __init__(self, *args, **kws): | |
23 super(MBScene_frameline_stack, self).__init__(*args, **kws) | |
24 | |
25 self._last_mouse_over_frameline = None | |
26 self._last_active_frameline = None | |
27 self._active_frame_callback = None | |
28 pass | |
29 | |
30 def _change_hover_frameline(self, widget, event): | |
31 """ | |
32 Hide all hover frames. This is a hack. We should use the lost focus | |
33 event instead in the future to reduce the overhead. | |
34 """ | |
35 if self._last_mouse_over_frameline and \ | |
36 widget != self._last_mouse_over_frameline: | |
37 self._last_mouse_over_frameline.mouse_leave() | |
38 pass | |
39 self._last_mouse_over_frameline = widget | |
40 pass | |
41 | |
42 ## \brief Switch to new active frameline. | |
43 # | |
44 # Hide active frame mark for the active frame of old active frameline. It | |
45 # always shows at most one active frame mark. When a frame is activated, | |
46 # all active frame mark of other frameline should be hidden. | |
47 # | |
48 def _active_frameline(self, frameline): | |
49 last = self._last_active_frameline | |
50 | |
51 if last and last != frameline: | |
52 last.deactive() | |
53 pass | |
54 | |
55 self._last_active_frameline = frameline | |
56 pass | |
57 | |
58 ## \brief Called for changing of active frame. | |
59 # | |
60 # This handle deactive previous frameline that owns an active frame when a | |
61 # frame in another frameline is activated. | |
62 # | |
63 def _change_active_frame(self, frameline, frame_idx, button): | |
64 frameline.active_frame(frame_idx) | |
65 self._active_frameline(frameline) | |
66 | |
67 if self._active_frame_callback: | |
68 layer_idx = frameline.layer_idx | |
69 self._active_frame_callback(layer_idx, frame_idx) | |
70 pass | |
71 pass | |
72 | |
73 ## \brief Add a frameline into the frameline box for the given layer. | |
74 # | |
75 def _add_frameline(self, layer_idx): | |
76 if layer_idx > len(self._framelines): | |
77 raise ValueError, 'layer number should be a consequence' | |
78 | |
79 vbox = self._frameline_vbox | |
80 | |
81 line = frameline(self._num_frames_of_line) | |
82 line.set_size_request(self._num_frames_of_line * 10, 20) | |
83 | |
84 hbox = gtk.HBox() | |
85 label = gtk.Label('') | |
86 label.set_size_request(100,0) | |
87 hbox.pack_start(label,expand=False, fill=True) | |
88 hbox.pack_start(line) | |
89 vbox.pack_start(hbox, False) | |
90 | |
91 # Put later one on the top of earier one, but after the ruler. | |
92 position = len(self._framelines) - layer_idx + 1 | |
93 vbox.reorder_child(hbox, position) | |
94 | |
95 self._framelines[layer_idx: layer_idx] = [line] | |
96 | |
97 for idx in range(layer_idx, len(self._framelines)): | |
98 self._framelines[idx].layer_idx = idx | |
99 pass | |
100 | |
101 line.label = label | |
102 line.connect('motion-notify-event', self._change_hover_frameline) | |
103 line.connect(frameline.FRAME_BUT_PRESS, self._change_active_frame) | |
104 pass | |
105 | |
106 ## \brief Remove the given frameline from the frameline box. | |
107 # | |
108 def _remove_frameline(self, layer_idx): | |
109 vbox = self._frameline_vbox | |
110 line = self._framelines[layer_idx] | |
111 | |
112 hbox = line.parent | |
113 vbox.remove(hbox) | |
114 del self._framelines[layer_idx] | |
115 | |
116 for idx in range(layer_idx, len(self._framelines)): | |
117 self._framelines[idx].layer_idx = idx | |
118 pass | |
119 pass | |
120 | |
121 def _init_framelines(self): | |
122 self._framelines = [] | |
123 | |
124 box = gtk.ScrolledWindow() | |
125 self._frameline_box = box | |
126 box.set_policy(gtk.POLICY_AUTOMATIC, gtk.POLICY_AUTOMATIC) | |
127 box.set_size_request(-1, 150) | |
128 vbox = gtk.VBox() | |
129 self._frameline_vbox = vbox | |
130 box.add_with_viewport(vbox) | |
131 | |
132 nframes = self._num_frames_of_line | |
133 | |
134 # | |
135 # Set up a ruler | |
136 # | |
137 ruler = frameruler(nframes) | |
138 ruler.set_size_request(nframes * 10, 20) | |
139 ruler.show() | |
140 hbox = gtk.HBox() | |
141 label=gtk.Label('') | |
142 label.set_size_request(100,0) | |
143 hbox.pack_start(label,expand=False,fill=True) | |
144 hbox.pack_start(ruler) | |
145 vbox.pack_start(hbox, False) | |
146 pass | |
147 | |
148 ## \brief Show framelines on the screen. | |
149 # | |
150 # When a frameline was inserted or removed, it would not be showed | |
151 # immediately. This function is used to notify toolkit to update the | |
152 # screen and drawing framelines. | |
153 def _show_framelines(self): | |
154 self._frameline_vbox.show_all() | |
155 pass | |
156 | |
157 ## \brief Make given frame as current active frame. | |
158 # | |
159 def active_frame(self, layer_idx, frame_idx): | |
160 frameline = self._framelines[layer_idx] | |
161 self._active_frameline(frameline) | |
162 frameline.active_frame(frame_idx) | |
163 pass | |
164 | |
165 ## \brief Get layer and frame index of current active frame. | |
166 # | |
167 # \return (-1, -1) for no active, (layer_idx, frame_idx) for current | |
168 # active. | |
169 def get_active_layer_frame(self): | |
170 if self._last_active_frameline: | |
171 layer_idx = self._last_active_frameline.layer_idx | |
172 frame_idx = self._last_active_frameline.get_active_frame() | |
173 if frame_idx != -1: | |
174 return layer_idx, frame_idx | |
175 pass | |
176 return -1, -1 | |
177 | |
178 ## \brief Get information of the key frame at left-side. | |
179 # | |
180 # The key frame, returned, is at the place of the give frame or its | |
181 # left-side. | |
182 def get_left_key_tween(self, layer_idx, frame_idx): | |
183 frameline = self._framelines[layer_idx] | |
184 start, end, fl_tween_type = frameline.get_frame_block_floor(frame_idx) | |
185 tween_type = self._frameline_tween_types.index(fl_tween_type) | |
186 return start, end, tween_type | |
187 | |
188 ## \brief Return information of a key frame and its tweening. | |
189 # | |
190 # This method return the key frame that the given frame is, or is in its | |
191 # tween. | |
192 # | |
193 # \return (start, end, tween_type) | |
194 def get_key_tween(self, layer_idx, frame_idx): | |
195 frameline = self._framelines[layer_idx] | |
196 start, end, fl_tween_type = frameline.get_frame_block(frame_idx) | |
197 | |
198 tween_type = self._frameline_tween_types.index(fl_tween_type) | |
199 return start, end, tween_type | |
200 | |
201 def get_all_key_tween_of_layer(self, layer_idx): | |
202 frameline = self._framelines[layer_idx] | |
203 info = frameline.get_frame_blocks() | |
204 tweens = [(tween[0], tween[1], | |
205 self._frameline_tween_types.index(tween[2])) | |
206 for tween in info] | |
207 return tweens | |
208 | |
209 ## \brief Tweening key frame to a give size | |
210 # | |
211 # The tween can be changed by tweening it again. | |
212 def tween(self, layer_idx, key_frame_idx, tween_len, | |
213 tween_type=TweenObject.TWEEN_TYPE_NORMAL): | |
214 assert tween_len > 0 | |
215 frameline = self._framelines[layer_idx] | |
216 right_frame_idx = key_frame_idx + tween_len - 1 | |
217 fl_tween_type = self._frameline_tween_types[tween_type] | |
218 | |
219 start, end, old_fl_tween_type = \ | |
220 frameline.get_frame_block(key_frame_idx) | |
221 if start != key_frame_idx: | |
222 ValueError, 'invalid key frame (%d)' % (key_frame_idx) | |
223 if start < end: | |
224 frameline.unmark_keyframe(end) | |
225 pass | |
226 frameline.mark_keyframe(right_frame_idx) | |
227 frameline.tween(start, fl_tween_type) | |
228 pass | |
229 | |
230 ## \brief Unmark a key frame. | |
231 # | |
232 # Once a key frame was unmark, the associated tween was also removed | |
233 # totally. | |
234 # | |
235 def unmark_keyframe(self, layer_idx, frame_idx): | |
236 frameline = self._framelines[layer_idx] | |
237 start, end, fl_tween_type = frameline.get_frame_block(frame_idx) | |
238 if start != frame_idx: | |
239 raise ValueError, 'no such key (%d, %d)' % (layer_idx, frame_idx) | |
240 | |
241 frameline.unmark_keyframe(frame_idx) | |
242 if start < end: | |
243 frameline.unmark_keyframe(end) | |
244 pass | |
245 pass | |
246 | |
247 ## \brief Makr a key frame. | |
248 # | |
249 # Make a frame as a key frame. | |
250 # | |
251 def mark_keyframe(self, layer_idx, frame_idx): | |
252 frameline = self._framelines[layer_idx] | |
253 frameline.mark_keyframe(frame_idx) | |
254 pass | |
255 | |
256 ## \brief Get data associated with the given key frame. | |
257 # | |
258 # The given frame index must be exactly a key frame. | |
259 # | |
260 def get_keyframe_data(self, layer_idx, frame_idx): | |
261 frameline = self._framelines[layer_idx] | |
262 data = frameline.get_frame_data(frame_idx) | |
263 return data | |
264 | |
265 ## \brief Set/associate data with the given key frame. | |
266 # | |
267 def set_keyframe_data(self, layer_idx, frame_idx, data): | |
268 frameline = self._framelines[layer_idx] | |
269 frameline.set_frame_data(frame_idx, data) | |
270 pass | |
271 | |
272 ## \brief Insert frames before specified frame. | |
273 # | |
274 # Specified frame and frames after it are shift right for \ref num | |
275 # positions to make a space for new frames. | |
276 # | |
277 def insert_frames(self, layer_idx, frame_idx, num): | |
278 assert num > 0 | |
279 assert frame_idx >= 0 | |
280 frameline = self._framelines[layer_idx] | |
281 for i in range(num): | |
282 frameline.add_frame(frame_idx) | |
283 pass | |
284 pass | |
285 | |
286 ## \brief Remove a number of frames from the frameline. | |
287 # | |
288 # All key frames and associated tween info covered by removing range would | |
289 # be removed. | |
290 # | |
291 def rm_frames(self, layer_idx, frame_idx, num): | |
292 assert num > 0 | |
293 assert frame_idx >= 0 | |
294 | |
295 frameline = self._framelines[layer_idx] | |
296 | |
297 # | |
298 # Remove right key frame of last tween which left one will be removed. | |
299 # | |
300 last_rm = frame_idx + num - 1 # last removed frame | |
301 try: | |
302 start, end, tween_type = frameline.get_frame_block(last_rm) | |
303 except ValueError: # last removed frame is not in any tween | |
304 pass | |
305 else: | |
306 if start >= frame_idx and end > last_rm: | |
307 # Left key frame of the tween was removed, but not right one. | |
308 frameline.untween(start) | |
309 frameline.unmark_keyframe(end) | |
310 pass | |
311 pass | |
312 | |
313 # | |
314 # Remove left key of the tween that right key frame is in removing | |
315 # range. | |
316 # | |
317 try: | |
318 start, end, tween_type = frameline.get_frame_block(frame_idx) | |
319 except ValueError: | |
320 pass | |
321 else: | |
322 if start < frame_idx and end <= last_rm: | |
323 # right key frame is in removing range but left one. | |
324 frameline.untween(start) | |
325 frameline.unmark_keyframe(start) | |
326 frameline.unmark_keyframe(end) | |
327 pass | |
328 pass | |
329 | |
330 for i in range(num): | |
331 frameline.rm_frame(frame_idx) | |
332 pass | |
333 pass | |
334 | |
335 ## \brief Set label for a layer. | |
336 # | |
337 def set_layer_label(self, layer_idx, txt): | |
338 frameline = self._framelines[layer_idx] | |
339 frameline.label.set_text(txt) | |
340 pass | |
341 | |
342 ## \brief Register a callback for active frame event. | |
343 # | |
344 # The callback would be called when a frame is activated. | |
345 # | |
346 def register_active_frame_callback(self, cb): | |
347 self._active_frame_callback = cb | |
348 pass | |
349 pass | |
350 | |
351 ## \brief Bridge of DOM-tree to syncrhonize data-model and UI. | |
352 # | |
353 # This class is a wrapper | |
354 class MBScene_domview_ui(object): | |
355 _tween_type_names = ('normal', 'scale') | |
356 | |
357 def __init__(self): | |
358 super(MBScene_domview_ui, self).__init__() | |
359 self._fl_stack = MBScene_frameline_stack() | |
360 self._dom = MBScene_domview() | |
361 pass | |
362 | |
363 ## \brief Update content of a frameline from scenes of respective layer. | |
364 # | |
365 def _update_frameline_content(self, layer_idx): | |
366 fl_stack = self._fl_stack | |
367 scene_nodes = self._dom.get_all_scene_node_of_layer(layer_idx) | |
368 for scene_node in scene_nodes: | |
369 start, end, tween_name = self._dom._parse_one_scene(scene_node) | |
370 | |
371 fl_stack.mark_keyframe(layer_idx, start) | |
372 fl_stack.set_keyframe_data(layer_idx, start, scene_node) | |
373 if start != end: | |
374 tween_type = self._tween_type_names.index(tween_name) | |
375 tween_len = end - start + 1 | |
376 fl_stack.tween(layer_idx, start, tween_len, tween_type) | |
377 pass | |
378 pass | |
379 pass | |
380 | |
381 ## \brief Add a frameline for every found layer. | |
382 # | |
383 # This method is called to create a frameline for every layer found when | |
384 # loading a document. | |
385 # | |
386 def _add_frameline_for_every_layer(self): | |
387 for layer_idx in range(self._dom.get_layer_num()): | |
388 layer_group_node = self._dom.get_layer_group(layer_idx) | |
389 label = layer_group_node.getAttribute('inkscape:label') | |
390 | |
391 self._fl_stack._add_frameline(layer_idx) | |
392 self._fl_stack.set_layer_label(layer_idx, label) | |
393 | |
394 self._update_frameline_content(layer_idx) | |
395 pass | |
396 pass | |
397 | |
398 ## \brief This method is called to handle a new document. | |
399 # | |
400 def handle_doc_root(self, doc, root): | |
401 self._dom.handle_doc_root(doc, root) | |
402 self._fl_stack._init_framelines() | |
403 self._add_frameline_for_every_layer() | |
404 self._fl_stack._show_framelines() | |
405 pass | |
406 | |
407 ## \brief Mark given frame as a key frame. | |
408 # | |
409 def mark_key(self, layer_idx, key_idx): | |
410 scene_group = self._dom.add_scene_group(layer_idx) | |
411 scene_group_id = scene_group.getAttribute('id') | |
412 | |
413 scene_node = self._dom.add_scene_node(key_idx, key_idx) | |
414 self._dom.chg_scene_node(scene_node, ref=scene_group_id) | |
415 | |
416 self._fl_stack.mark_keyframe(layer_idx, key_idx) | |
417 self._fl_stack.set_keyframe_data(layer_idx, key_idx, scene_node) | |
418 pass | |
419 | |
420 ## \brief Tweening a key frame. | |
421 # | |
422 # To tween a key spanning several frames at right-side. | |
423 # The tween of a key frame can be changed by tweening it again. | |
424 # | |
425 def tween(self, layer_idx, key_frame_idx, tween_len, | |
426 tween_type=TweenObject.TWEEN_TYPE_NORMAL): | |
427 self._fl_stack.tween(layer_idx, key_frame_idx, tween_len, tween_type) | |
428 | |
429 end_frame_idx = key_frame_idx + tween_len - 1 | |
430 scene_node = self._fl_stack.get_keyframe_data(layer_idx, key_frame_idx) | |
431 tween_name = self._tween_type_names[tween_type] | |
432 self._dom.chg_scene_node(scene_node, end=end_frame_idx, | |
433 tween_type=tween_name) | |
434 pass | |
435 | |
436 ## \brief Change tween info of a key frame | |
437 # | |
438 def chg_tween(self, layer_idx, key_frame_idx, | |
439 tween_len=None, tween_type=None): | |
440 scene_node = self._fl_stack.get_keyframe_data(layer_idx, key_frame_idx) | |
441 start, end, old_tween_type = \ | |
442 self._fl_stack.get_key_tween(layer_idx, key_frame_idx) | |
443 | |
444 if tween_len is not None: | |
445 end = start + tween_len - 1 | |
446 self._dom.chg_scene_node(scene_node, end=end) | |
447 pass | |
448 if tween_type is not None: | |
449 tween_name = self._tween_type_names[tween_type] | |
450 self._dom.chg_scene_node(scene_node, tween_type=tween_name) | |
451 pass | |
452 | |
453 if tween_type is None: | |
454 tween_type = old_tween_type | |
455 pass | |
456 | |
457 tween_len = end - start + 1 | |
458 self._fl_stack.tween(layer_idx, start, tween_len, tween_type) | |
459 pass | |
460 | |
461 ## \brief Unmark a frame from a key frame. | |
462 # | |
463 def unmark_key(self, layer_idx, key_frame_idx): | |
464 scene_node = self._fl_stack.get_keyframe_data(layer_idx, key_frame_idx) | |
465 self._dom.rm_scene_node_n_group(scene_node) | |
466 | |
467 self._fl_stack.unmark_keyframe(layer_idx, key_frame_idx) | |
468 pass | |
469 | |
470 ## \brief Insert frames at specified position. | |
471 # | |
472 # All frame at and after given position will shift right. | |
473 # | |
474 def insert_frames(self, layer_idx, frame_idx, num): | |
475 self._fl_stack.insert_frames(layer_idx, frame_idx, num) | |
476 self._dom.insert_frames(layer_idx, frame_idx, num) | |
477 pass | |
478 | |
479 ## \brief Insert frames at specified position. | |
480 # | |
481 # All frame at and after given position will shift left, except nearest | |
482 # \ref num frames are removed. | |
483 # | |
484 def rm_frames(self, layer_idx, frame_idx, num): | |
485 self._fl_stack.insert_frames(layer_idx, frame_idx, num) | |
486 self._dom.rm_frames(layer_idx, frame_idx, num) | |
487 pass | |
488 | |
489 ## \brief Insert a layer at given position. | |
490 # | |
491 # Original layer \ref layer_idx and later ones would be shifted to make a | |
492 # space for the new layer. | |
493 # | |
494 def insert_layer(self, layer_idx): | |
495 self._dom.insert_layer(layer_idx) | |
496 self._fl_stack._add_frameline(layer_idx) | |
497 self._fl_stack._show_framelines() | |
498 pass | |
499 | |
500 ## \brief Remove given layer. | |
501 # | |
502 def rm_layer(self, layer_idx): | |
503 self._dom.rm_layer(layer_idx) | |
504 self._fl_stack._remove_frameline(layer_idx) | |
505 self._fl_stack._show_framelines() | |
506 pass | |
507 | |
508 def set_active_layer_frame(self, layer_idx, frame_idx): | |
509 self._fl_stack.active_frame(layer_idx, frame_idx) | |
510 pass | |
511 | |
512 ## \bref Return current active frame and its layer. | |
513 # | |
514 # \return (layer_idx, frame_idx) of active frame, or (-1, -1) when no | |
515 # active one. | |
516 def get_active_layer_frame(self): | |
517 layer_idx, frame_idx = self._fl_stack.get_active_layer_frame() | |
518 return layer_idx, frame_idx | |
519 | |
520 def get_layer_num(self): | |
521 return self._dom.get_layer_num() | |
522 | |
523 ## \brief Return associated group node for a key frame. | |
524 # | |
525 # The given frame index must be exactly a key frame. | |
526 # | |
527 def get_key_group(self, layer_idx, frame_idx): | |
528 scene_node = self._fl_stack.get_keyframe_data(layer_idx, frame_idx) | |
529 scene_group_id = scene_node.getAttribute('ref') | |
530 scene_group_node = self._dom.get_node(scene_group_id) | |
531 return scene_group_node | |
532 | |
533 ## \brief Find an associated key frame and tween info for a group ID. | |
534 # | |
535 def find_key_from_group(self, scene_group_id): | |
536 layer_idx, scene_node = \ | |
537 self._dom.find_layer_n_scene_of_node(scene_group_id) | |
538 start, end, tween_name = self._dom._parse_one_scene(scene_node) | |
539 tween_type = self._tween_type_names.index(tween_name) | |
540 return layer_idx, (start, end, tween_type) | |
541 | |
542 ## \brief Return key and tween info for given frame index. | |
543 # | |
544 # The return key is at given frame, or its tween covers given frame. | |
545 # | |
546 def get_key(self, layer_idx, frame_idx): | |
547 start, end, tween_type = \ | |
548 self._fl_stack.get_key_tween(layer_idx, frame_idx) | |
549 return start, end, tween_type | |
550 | |
551 def get_left_key(self, layer_idx, frame_idx): | |
552 start, end, tween_type = \ | |
553 self._fl_stack.get_left_key_tween(layer_idx, frame_idx) | |
554 return start, end, tween_type | |
555 | |
556 ## \brief Return information of key frames in the given layer. | |
557 # | |
558 def get_layer_keys(self, layer_idx): | |
559 key_tweens = self._fl_stack.get_all_key_tween_of_layer(layer_idx) | |
560 return key_tweens | |
561 | |
562 ## \brief Return widget showing frames and layers. | |
563 # | |
564 def get_frame_ui_widget(self): | |
565 return self._fl_stack._frameline_box | |
566 | |
567 ## \brief Register a callback for activating a frame event. | |
568 # | |
569 # The callback function is called when a frame is activated. | |
570 # | |
571 def register_active_frame_callback(self, cb): | |
572 self._fl_stack.register_active_frame_callback(cb) | |
573 pass | |
574 | |
575 ## \brief Get duplicate group of a layer. | |
576 # | |
577 def get_layer_dup_group(self, layer_idx): | |
578 data = self._dom.get_layer_data(layer_idx) | |
579 if not data: | |
580 data = dict() | |
581 self._dom.set_layer_data(layer_idx, data) | |
582 pass | |
583 | |
584 dup_group = None | |
585 if data.has_key('dup_group_id'): | |
586 try: | |
587 dup_group = self._dom.get_node(data['dup_group_id']) | |
588 except KeyError: | |
589 pass | |
590 pass | |
591 | |
592 if not dup_group: | |
593 # Search dup group from children of the layer group | |
594 layer_group = self._dom.get_layer_group(layer_idx) | |
595 for child in layer_group.childList(): | |
596 try: | |
597 label = child.getAttribute('inkscape:label') | |
598 except: | |
599 pass | |
600 else: | |
601 if label == 'dup': | |
602 data['dup_group_id'] = child | |
603 return child | |
604 pass | |
605 pass | |
606 | |
607 # Or create a new dup group for the layer | |
608 dup_group = self._dom.create_layer_dup_group(layer_idx) | |
609 data['dup_group_id'] = dup_group.getAttribute('id') | |
610 pass | |
611 | |
612 return dup_group | |
613 | |
614 def get_max_frame(self): | |
615 max_frame = self._dom.get_max_frame() | |
616 return max_frame | |
617 pass | |
618 |