ya2 · news · projects · code · about

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