ya2 · news · projects · code · about

fix: building of screenshots
[pmachines.git] / pmachines / scene.py
... / ...
CommitLineData
1from os.path import exists
2from glob import glob
3from importlib import import_module
4from inspect import isclass
5from panda3d.core import AmbientLight, DirectionalLight, Point3, Texture, \
6 TextPropertiesManager, TextNode, Spotlight, PerspectiveLens, BitMask32
7from panda3d.bullet import BulletPlaneShape, BulletGhostNode
8from direct.gui.OnscreenImage import OnscreenImage
9from direct.gui.OnscreenText import OnscreenText
10from direct.gui.DirectGui import DirectButton, DirectFrame
11from direct.gui.DirectGuiGlobals import FLAT, DISABLED, NORMAL
12from direct.showbase.DirectObject import DirectObject
13from pmachines.items.background import Background
14from pmachines.sidepanel import SidePanel
15from lib.engine.gui.cursor import MouseCursor
16from lib.lib.p3d.gfx import P3dGfxMgr
17
18
19class Scene(DirectObject):
20
21 def __init__(self, world, exit_cb, auto_close_instr, dbg_items, reload_cb):
22 super().__init__()
23 self._world = world
24 self._exit_cb = exit_cb
25 self._dbg_items = dbg_items
26 self._reload_cb = reload_cb
27 self._set_camera()
28 self._cursor = MouseCursor(
29 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
30 (.01, .01))
31 self._set_gui()
32 self._set_lights()
33 self._set_input()
34 self._set_mouse_plane()
35 self.items = []
36 self.reset()
37 self._state = 'init'
38 self._paused = False
39 self._item_active = None
40 if auto_close_instr:
41 self.__store_state()
42 self.__restore_state()
43 else:
44 self._set_instructions()
45 self._bg = Background()
46 self._side_panel = SidePanel(world, self._mouse_plane_node, (-5, 4), (-3, 1), 1, self.items)
47 self._scene_tsk = taskMgr.add(self.on_frame, 'on_frame')
48
49 @staticmethod
50 def name():
51 return ''
52
53 def _instr_txt(self):
54 return ''
55
56 def _set_items(self):
57 self.items = []
58
59 def screenshot(self, task=None):
60 tex = Texture('screenshot')
61 buffer = base.win.make_texture_buffer('screenshot', 512, 512, tex, True )
62 cam = base.make_camera(buffer)
63 cam.reparent_to(render)
64 cam.node().get_lens().set_fov(base.camLens.get_fov())
65 cam.set_pos(0, -20, 0)
66 cam.look_at(0, 0, 0)
67 import simplepbr
68 simplepbr.init(
69 window=buffer,
70 camera_node=cam,
71 use_normal_maps=True,
72 use_emission_maps=False,
73 use_occlusion_maps=True,
74 msaa_samples=4,
75 enable_shadows=True)
76 base.graphicsEngine.renderFrame()
77 base.graphicsEngine.renderFrame()
78 fname = self.__class__.__name__
79 if not exists('assets/images/scenes'):
80 makedirs('assets/images/scenes')
81 buffer.save_screenshot('assets/images/scenes/%s.png' % fname)
82 # img = DirectButton(
83 # frameTexture=buffer.get_texture(), relief=FLAT,
84 # frameSize=(-.2, .2, -.2, .2))
85 return buffer.get_texture()
86
87 def current_bottom(self):
88 curr_bottom = 1
89 for item in self.items:
90 if item.repos_done:
91 curr_bottom = min(curr_bottom, item.get_bottom())
92 return curr_bottom
93
94 def reset(self):
95 [itm.destroy() for itm in self.items]
96 self._set_items()
97 self._state = 'init'
98 self._commands = []
99 self._command_idx = 0
100 if hasattr(self, '_success_txt'):
101 self._success_txt.destroy()
102 del self._success_txt
103 self.__right_btn['state'] = NORMAL
104
105 def destroy(self):
106 self._unset_gui()
107 self._unset_lights()
108 self._unset_input()
109 self._unset_mouse_plane()
110 [itm.destroy() for itm in self.items]
111 self._bg.destroy()
112 self._side_panel.destroy()
113 self._cursor.destroy()
114 taskMgr.remove(self._scene_tsk)
115 if hasattr(self, '_success_txt'):
116 self._success_txt.destroy()
117
118 def _set_camera(self):
119 base.camera.set_pos(0, -20, 0)
120 base.camera.look_at(0, 0, 0)
121
122 def __load_img_btn(self, path, col):
123 img = OnscreenImage('assets/images/buttons/%s.dds' % path)
124 img.set_transparency(True)
125 img.set_color(col)
126 img.detach_node()
127 return img
128
129 def _set_gui(self):
130 def load_images_btn(path, col):
131 colors = {
132 'gray': [
133 (.6, .6, .6, 1), # ready
134 (1, 1, 1, 1), # press
135 (.8, .8, .8, 1), # rollover
136 (.4, .4, .4, .4)],
137 'green': [
138 (.1, .68, .1, 1),
139 (.1, 1, .1, 1),
140 (.1, .84, .1, 1),
141 (.4, .1, .1, .4)]}[col]
142 return [self.__load_img_btn(path, col) for col in colors]
143 abl, abr = base.a2dBottomLeft, base.a2dBottomRight
144 btn_info = [
145 ('home', self.on_home, NORMAL, abl, 'gray'),
146 ('information', self._set_instructions, NORMAL, abl, 'gray'),
147 ('right', self.on_play, NORMAL, abr, 'green'),
148 ('next', self.on_next, DISABLED, abr, 'gray'),
149 ('previous', self.on_prev, DISABLED, abr, 'gray'),
150 ('rewind', self.reset, NORMAL, abr, 'gray')]
151 num_l = num_r = 0
152 btns = []
153 for binfo in btn_info:
154 imgs = load_images_btn(binfo[0], binfo[4])
155 if binfo[3] == base.a2dBottomLeft:
156 sign, num = 1, num_l
157 num_l += 1
158 else:
159 sign, num = -1, num_r
160 num_r += 1
161 fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
162 btn = DirectButton(
163 image=imgs, scale=.05, pos=(sign * (.06 + .11 * num), 1, .06),
164 parent=binfo[3], command=binfo[1], state=binfo[2], relief=FLAT,
165 frameColor=fcols[0] if binfo[2] == NORMAL else fcols[1],
166 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
167 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
168 btn.set_transparency(True)
169 btns += [btn]
170 self.__home_btn, self.__info_btn, self.__right_btn, self.__next_btn, \
171 self.__prev_btn, self.__rewind_btn = btns
172 if self._dbg_items:
173 self._info_txt = OnscreenText(
174 '', parent=base.a2dTopRight, scale=0.04,
175 pos=(-.03, -.06), fg=(.9, .9, .9, 1), align=TextNode.A_right)
176
177 def _unset_gui(self):
178 btns = [
179 self.__home_btn, self.__info_btn, self.__right_btn,
180 self.__next_btn, self.__prev_btn, self.__rewind_btn]
181 [btn.destroy() for btn in btns]
182 if self._dbg_items:
183 self._info_txt.destroy()
184
185 def _set_spotlight(self, name, pos, look_at, color, shadows=False):
186 light = Spotlight(name)
187 if shadows:
188 light.setLens(PerspectiveLens())
189 light_np = render.attach_new_node(light)
190 light_np.set_pos(pos)
191 light_np.look_at(look_at)
192 light.set_color(color)
193 render.set_light(light_np)
194 return light_np
195
196 def _set_lights(self):
197 alight = AmbientLight('alight') # for ao
198 alight.set_color((.15, .15, .15, 1))
199 self._alnp = render.attach_new_node(alight)
200 render.set_light(self._alnp)
201 self._key_light = self._set_spotlight(
202 'key light', (-5, -80, 5), (0, 0, 0), (2.8, 2.8, 2.8, 1))
203 self._shadow_light = self._set_spotlight(
204 'key light', (-5, -80, 5), (0, 0, 0), (.58, .58, .58, 1), True)
205 self._shadow_light.node().set_shadow_caster(True, 2048, 2048)
206 self._shadow_light.node().get_lens().set_film_size(2048, 2048)
207 self._shadow_light.node().get_lens().set_near_far(1, 256)
208 self._shadow_light.node().set_camera_mask(BitMask32(0x01))
209
210 def _unset_lights(self):
211 for light in [self._alnp, self._key_light, self._shadow_light]:
212 render.clear_light(light)
213 light.remove_node()
214
215 def _set_input(self):
216 self.accept('mouse1', self.on_click_l)
217 self.accept('mouse1-up', self.on_release)
218 self.accept('mouse3', self.on_click_r)
219 self.accept('mouse3-up', self.on_release)
220
221 def _unset_input(self):
222 for evt in ['mouse1', 'mouse1-up', 'mouse3', 'mouse3-up']:
223 self.ignore(evt)
224
225 def _set_mouse_plane(self):
226 shape = BulletPlaneShape((0, -1, 0), 0)
227 #self._mouse_plane_node = BulletRigidBodyNode('mouse plane')
228 self._mouse_plane_node = BulletGhostNode('mouse plane')
229 self._mouse_plane_node.addShape(shape)
230 #np = render.attachNewNode(self._mouse_plane_node)
231 #self._world.attachRigidBody(self._mouse_plane_node)
232 self._world.attach_ghost(self._mouse_plane_node)
233
234 def _unset_mouse_plane(self):
235 self._world.remove_ghost(self._mouse_plane_node)
236
237 def _get_hits(self):
238 if not base.mouseWatcherNode.has_mouse(): return []
239 p_from, p_to = P3dGfxMgr.world_from_to(base.mouseWatcherNode.get_mouse())
240 return self._world.ray_test_all(p_from, p_to).get_hits()
241
242 def _update_info(self, item):
243 txt = ''
244 if item:
245 txt = '%.3f %.3f\n%.3f°' % (
246 item._np.get_x(), item._np.get_z(), item._np.get_r())
247 self._info_txt['text'] = txt
248
249 def _on_click(self, method):
250 if self._paused:
251 return
252 for hit in self._get_hits():
253 if hit.get_node() == self._mouse_plane_node:
254 pos = hit.get_hit_pos()
255 for hit in self._get_hits():
256 for item in [i for i in self.items if hit.get_node() == i.node and i.interactable]:
257 if not self._item_active:
258 self._item_active = item
259 getattr(item, method)(pos)
260 img = 'move' if method == 'on_click_l' else 'rotate'
261 if not (img == 'rotate' and not item._instantiated):
262 self._cursor.set_image('assets/images/buttons/%s.dds' % img)
263
264 def on_click_l(self):
265 self._on_click('on_click_l')
266
267 def on_click_r(self):
268 self._on_click('on_click_r')
269
270 def on_release(self):
271 if self._item_active and not self._item_active._first_command:
272 self._commands = self._commands[:self._command_idx]
273 self._commands += [self._item_active]
274 self._command_idx += 1
275 self.__prev_btn['state'] = NORMAL
276 fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
277 self.__prev_btn['frameColor'] = fcols[0]
278 if self._item_active._command_idx == len(self._item_active._commands) - 1:
279 self.__next_btn['state'] = DISABLED
280 self.__next_btn['frameColor'] = fcols[1]
281 self._item_active = None
282 [item.on_release() for item in self.items]
283 self._cursor.set_image('assets/images/buttons/arrowUpLeft.dds')
284
285 def repos(self):
286 for item in self.items:
287 item.repos_done = False
288 self.items = sorted(self.items, key=lambda itm: itm.__class__.__name__)
289 [item.on_aspect_ratio_changed() for item in self.items]
290 self._side_panel.update(self.items)
291 max_x = -float('inf')
292 for item in self.items:
293 if not item._instantiated:
294 max_x = max(item._np.get_x(), max_x)
295 for item in self.items:
296 if not item._instantiated:
297 item.repos_x(max_x)
298
299 def on_aspect_ratio_changed(self):
300 self.repos()
301
302 def _win_condition(self):
303 pass
304
305 def _fail_condition(self):
306 return all(itm.fail_condition() for itm in self.items) and not self._paused and self._state == 'playing'
307
308 def on_frame(self, task):
309 hits = self._get_hits()
310 pos = None
311 for hit in self._get_hits():
312 if hit.get_node() == self._mouse_plane_node:
313 pos = hit.get_hit_pos()
314 hit_nodes = [hit.get_node() for hit in hits]
315 if self._item_active:
316 items_hit = [self._item_active]
317 else:
318 items_hit = [itm for itm in self.items if itm.node in hit_nodes]
319 items_no_hit = [itm for itm in self.items if itm not in items_hit]
320 [itm.on_mouse_on() for itm in items_hit]
321 [itm.on_mouse_off() for itm in items_no_hit]
322 if pos and self._item_active:
323 self._item_active.on_mouse_move(pos)
324 if self._dbg_items:
325 self._update_info(items_hit[0] if items_hit else None)
326 if self._win_condition():
327 self._set_win()
328 elif self._state == 'playing' and self._fail_condition():
329 self._set_fail()
330 if any(itm._overlapping for itm in self.items):
331 self._cursor.cursor_img.img.set_color(.9, .1, .1, 1)
332 else:
333 self._cursor.cursor_img.img.set_color(.9, .9, .9, 1)
334 return task.cont
335
336 def cb_inst(self, item):
337 self.items += [item]
338
339 def on_play(self):
340 self._state = 'playing'
341 self.__prev_btn['state'] = DISABLED
342 self.__next_btn['state'] = DISABLED
343 self.__right_btn['state'] = DISABLED
344 [itm.play() for itm in self.items]
345
346 def on_next(self):
347 self._commands[self._command_idx].redo()
348 self._command_idx += 1
349 fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
350 self.__prev_btn['state'] = NORMAL
351 self.__prev_btn['frameColor'] = fcols[0]
352 more_commands = self._command_idx < len(self._commands)
353 self.__next_btn['state'] = NORMAL if more_commands else DISABLED
354 self.__next_btn['frameColor'] = fcols[0] if more_commands else fcols[1]
355
356 def on_prev(self):
357 self._command_idx -= 1
358 self._commands[self._command_idx].undo()
359 fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
360 self.__next_btn['state'] = NORMAL
361 self.__next_btn['frameColor'] = fcols[0]
362 self.__prev_btn['state'] = NORMAL if self._command_idx else DISABLED
363 self.__prev_btn['frameColor'] = fcols[0] if self._command_idx else fcols[1]
364
365 def on_home(self):
366 self._exit_cb()
367
368 def _set_instructions(self):
369 self._paused = True
370 self.__store_state()
371 mgr = TextPropertiesManager.get_global_ptr()
372 for name in ['mouse_l', 'mouse_r']:
373 graphic = OnscreenImage('assets/images/buttons/%s.dds' % name)
374 graphic.set_scale(.5)
375 graphic.get_texture().set_minfilter(Texture.FTLinearMipmapLinear)
376 graphic.get_texture().set_anisotropic_degree(2)
377 mgr.set_graphic(name, graphic)
378 graphic.set_z(-.2)
379 graphic.set_transparency(True)
380 graphic.detach_node()
381 frm = DirectFrame(frameColor=(.4, .4, .4, .06),
382 frameSize=(-.6, .6, -.3, .3))
383 font = base.loader.load_font('assets/fonts/Hanken-Book.ttf')
384 font.clear()
385 font.set_pixels_per_unit(60)
386 font.set_minfilter(Texture.FTLinearMipmapLinear)
387 font.set_outline((0, 0, 0, 1), .8, .2)
388 self._txt = OnscreenText(
389 self._instr_txt(), parent=frm, font=font, scale=0.06,
390 fg=(.9, .9, .9, 1), align=TextNode.A_left)
391 u_l = self._txt.textNode.get_upper_left_3d()
392 l_r = self._txt.textNode.get_lower_right_3d()
393 w, h = l_r[0] - u_l[0], u_l[2] - l_r[2]
394 btn_scale = .05
395 mar = .06 # margin
396 z = h / 2 - font.get_line_height() * self._txt['scale'][1]
397 z += (btn_scale + 2 * mar) / 2
398 self._txt['pos'] = -w / 2, z
399 u_l = self._txt.textNode.get_upper_left_3d()
400 l_r = self._txt.textNode.get_lower_right_3d()
401 c_l_r = l_r[0], l_r[1], l_r[2] - 2 * mar - btn_scale
402 fsz = u_l[0] - mar, l_r[0] + mar, c_l_r[2] - mar, u_l[2] + mar
403 frm['frameSize'] = fsz
404 colors = [
405 (.6, .6, .6, 1), # ready
406 (1, 1, 1, 1), # press
407 (.8, .8, .8, 1), # rollover
408 (.4, .4, .4, .4)]
409 imgs = [self.__load_img_btn('exitRight', col) for col in colors]
410 btn = DirectButton(
411 image=imgs, scale=btn_scale,
412 pos=(l_r[0] - btn_scale, 1, l_r[2] - mar - btn_scale),
413 parent=frm, command=self.__on_close_instructions, extraArgs=[frm],
414 relief=FLAT, frameColor=(.6, .6, .6, .08),
415 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
416 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
417 btn.set_transparency(True)
418
419 def _set_win(self):
420 loader.load_sfx('assets/audio/sfx/success.ogg').play()
421 self._paused = True
422 self.__store_state()
423 frm = DirectFrame(frameColor=(.4, .4, .4, .06),
424 frameSize=(-.6, .6, -.3, .3))
425 font = base.loader.load_font('assets/fonts/Hanken-Book.ttf')
426 font.clear()
427 font.set_pixels_per_unit(60)
428 font.set_minfilter(Texture.FTLinearMipmapLinear)
429 font.set_outline((0, 0, 0, 1), .8, .2)
430 self._txt = OnscreenText(
431 _('You win!'),
432 parent=frm,
433 font=font, scale=0.2,
434 fg=(.9, .9, .9, 1))
435 u_l = self._txt.textNode.get_upper_left_3d()
436 l_r = self._txt.textNode.get_lower_right_3d()
437 w, h = l_r[0] - u_l[0], u_l[2] - l_r[2]
438 btn_scale = .05
439 mar = .06 # margin
440 z = h / 2 - font.get_line_height() * self._txt['scale'][1]
441 z += (btn_scale + 2 * mar) / 2
442 self._txt['pos'] = 0, z
443 u_l = self._txt.textNode.get_upper_left_3d()
444 l_r = self._txt.textNode.get_lower_right_3d()
445 c_l_r = l_r[0], l_r[1], l_r[2] - 2 * mar - btn_scale
446 fsz = u_l[0] - mar, l_r[0] + mar, c_l_r[2] - mar, u_l[2] + mar
447 frm['frameSize'] = fsz
448 colors = [
449 (.6, .6, .6, 1), # ready
450 (1, 1, 1, 1), # press
451 (.8, .8, .8, 1), # rollover
452 (.4, .4, .4, .4)]
453 imgs = [self.__load_img_btn('home', col) for col in colors]
454 btn = DirectButton(
455 image=imgs, scale=btn_scale,
456 pos=(-2.8 * btn_scale, 1, l_r[2] - mar - btn_scale),
457 parent=frm, command=self._on_end_home, extraArgs=[frm],
458 relief=FLAT, frameColor=(.6, .6, .6, .08),
459 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
460 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
461 btn.set_transparency(True)
462 imgs = [self.__load_img_btn('rewind', col) for col in colors]
463 btn = DirectButton(
464 image=imgs, scale=btn_scale,
465 pos=(0, 1, l_r[2] - mar - btn_scale),
466 parent=frm, command=self._on_restart, extraArgs=[frm],
467 relief=FLAT, frameColor=(.6, .6, .6, .08),
468 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
469 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
470 btn.set_transparency(True)
471 scenes = []
472 for _file in glob('pmachines/scenes/*.py'):
473 _fn = _file.replace('.py', '').replace('/', '.')
474 for member in import_module(_fn).__dict__.values():
475 if isclass(member) and issubclass(member, Scene) and \
476 member != Scene:
477 scenes += [member]
478 scenes = sorted(scenes, key=lambda elm: elm.sorting)
479 enabled = scenes.index(self.__class__) < len(scenes) - 1
480 if enabled:
481 next_scene = scenes[scenes.index(self.__class__) + 1]
482 else:
483 next_scene = None
484 imgs = [self.__load_img_btn('right', col) for col in colors]
485 btn = DirectButton(
486 image=imgs, scale=btn_scale,
487 pos=(2.8 * btn_scale, 1, l_r[2] - mar - btn_scale),
488 parent=frm, command=self._on_next_scene,
489 extraArgs=[frm, next_scene], relief=FLAT,
490 frameColor=(.6, .6, .6, .08),
491 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
492 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
493 btn['state'] = NORMAL if enabled else DISABLED
494 btn.set_transparency(True)
495
496 def _set_fail(self):
497 loader.load_sfx('assets/audio/sfx/success.ogg').play()
498 self._paused = True
499 self.__store_state()
500 frm = DirectFrame(frameColor=(.4, .4, .4, .06),
501 frameSize=(-.6, .6, -.3, .3))
502 font = base.loader.load_font('assets/fonts/Hanken-Book.ttf')
503 font.clear()
504 font.set_pixels_per_unit(60)
505 font.set_minfilter(Texture.FTLinearMipmapLinear)
506 font.set_outline((0, 0, 0, 1), .8, .2)
507 self._txt = OnscreenText(
508 _('You have failed!'),
509 parent=frm,
510 font=font, scale=0.2,
511 fg=(.9, .9, .9, 1))
512 u_l = self._txt.textNode.get_upper_left_3d()
513 l_r = self._txt.textNode.get_lower_right_3d()
514 w, h = l_r[0] - u_l[0], u_l[2] - l_r[2]
515 btn_scale = .05
516 mar = .06 # margin
517 z = h / 2 - font.get_line_height() * self._txt['scale'][1]
518 z += (btn_scale + 2 * mar) / 2
519 self._txt['pos'] = 0, z
520 u_l = self._txt.textNode.get_upper_left_3d()
521 l_r = self._txt.textNode.get_lower_right_3d()
522 c_l_r = l_r[0], l_r[1], l_r[2] - 2 * mar - btn_scale
523 fsz = u_l[0] - mar, l_r[0] + mar, c_l_r[2] - mar, u_l[2] + mar
524 frm['frameSize'] = fsz
525 colors = [
526 (.6, .6, .6, 1), # ready
527 (1, 1, 1, 1), # press
528 (.8, .8, .8, 1), # rollover
529 (.4, .4, .4, .4)]
530 imgs = [self.__load_img_btn('home', col) for col in colors]
531 btn = DirectButton(
532 image=imgs, scale=btn_scale,
533 pos=(-2.8 * btn_scale, 1, l_r[2] - mar - btn_scale),
534 parent=frm, command=self._on_end_home, extraArgs=[frm],
535 relief=FLAT, frameColor=(.6, .6, .6, .08),
536 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
537 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
538 btn.set_transparency(True)
539 imgs = [self.__load_img_btn('rewind', col) for col in colors]
540 btn = DirectButton(
541 image=imgs, scale=btn_scale,
542 pos=(0, 1, l_r[2] - mar - btn_scale),
543 parent=frm, command=self._on_restart, extraArgs=[frm],
544 relief=FLAT, frameColor=(.6, .6, .6, .08),
545 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
546 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
547 btn.set_transparency(True)
548
549 def _on_restart(self, frm):
550 self.__on_close_instructions(frm)
551 self.reset()
552
553 def _on_end_home(self, frm):
554 self.__on_close_instructions(frm)
555 self.on_home()
556
557 def _on_next_scene(self, frm, scene):
558 self.__on_close_instructions(frm)
559 self._reload_cb(scene)
560
561 def __store_state(self):
562 btns = [
563 self.__home_btn, self.__info_btn, self.__right_btn,
564 self.__next_btn, self.__prev_btn, self.__rewind_btn]
565 self.__btn_state = [btn['state'] for btn in btns]
566 for btn in btns:
567 btn['state'] = DISABLED
568 [itm.store_state() for itm in self.items]
569
570 def __restore_state(self):
571 btns = [
572 self.__home_btn, self.__info_btn, self.__right_btn,
573 self.__next_btn, self.__prev_btn, self.__rewind_btn]
574 for btn, state in zip(btns, self.__btn_state):
575 btn['state'] = state
576 [itm.restore_state() for itm in self.items]
577 self._paused = False
578
579 def __on_close_instructions(self, frm):
580 frm.remove_node()
581 self.__restore_state()