9d4861daa00256d03326bccc03a4859487824d81
1 from os
.path
import exists
2 from os
import makedirs
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 game
.items
.background
import Background
16 from game
.sidepanel
import SidePanel
17 from lib
.engine
.gui
.cursor
import MouseCursor
18 from lib
.lib
.p3d
.gfx
import P3dGfxMgr
21 class Scene(DirectObject
):
23 def __init__(self
, world
, exit_cb
, auto_close_instr
, dbg_items
, reload_cb
, scenes
):
26 self
._exit
_cb
= exit_cb
27 self
._dbg
_items
= dbg_items
28 self
._reload
_cb
= reload_cb
30 self
._enforce
_res
= ''
31 self
.accept('enforce_res', self
.enforce_res
)
33 self
._cursor
= MouseCursor(
34 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
39 self
._set
_mouse
_plane
()
44 self
._item
_active
= None
47 self
.__restore
_state
()
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')
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)
77 use_emission_maps
=False,
78 use_occlusion_maps
=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
)
88 # frameTexture=buffer.get_texture(), relief=FLAT,
89 # frameSize=(-.2, .2, -.2, .2))
90 return buffer.get_texture()
92 def current_bottom(self
):
94 for item
in self
.items
:
96 curr_bottom
= min(curr_bottom
, item
.get_bottom())
100 [itm
.destroy() for itm
in self
.items
]
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
110 def enforce_res(self
, val
):
111 self
._enforce
_res
= val
112 info('enforce res: ' + val
)
115 self
.ignore('enforce_res')
119 self
._unset
_mouse
_plane
()
120 [itm
.destroy() for itm
in self
.items
]
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()
128 def _set_camera(self
):
129 base
.camera
.set_pos(0, -20, 0)
130 base
.camera
.look_at(0, 0, 0)
132 def __load_img_btn(self
, path
, col
):
133 img
= OnscreenImage('assets/images/buttons/%s.dds' % path
)
134 img
.set_transparency(True)
140 def load_images_btn(path
, col
):
143 (.6, .6, .6, 1), # ready
144 (1, 1, 1, 1), # press
145 (.8, .8, .8, 1), # rollover
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
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')]
163 for binfo
in btn_info
:
164 imgs
= load_images_btn(binfo
[0], binfo
[4])
165 if binfo
[3] == base
.a2dBottomLeft
:
169 sign
, num
= -1, num_r
171 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
173 image
=imgs
, scale
=.05, pos
=(sign
* (.06 + .11 * num
), 1, .06),
174 parent
=binfo
[3], command
=binfo
[1], state
=binfo
[2], relief
=FLAT
,
175 frameColor
=fcols
[0] if binfo
[2] == NORMAL
else fcols
[1],
176 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
177 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
178 btn
.set_transparency(True)
180 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
, self
.__next
_btn
, \
181 self
.__prev
_btn
, self
.__rewind
_btn
= btns
183 self
._info
_txt
= OnscreenText(
184 '', parent
=base
.a2dTopRight
, scale
=0.04,
185 pos
=(-.03, -.06), fg
=(.9, .9, .9, 1), align
=TextNode
.A_right
)
187 def _unset_gui(self
):
189 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
190 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
191 [btn
.destroy() for btn
in btns
]
193 self
._info
_txt
.destroy()
195 def _set_spotlight(self
, name
, pos
, look_at
, color
, shadows
=False):
196 light
= Spotlight(name
)
198 light
.setLens(PerspectiveLens())
199 light_np
= render
.attach_new_node(light
)
200 light_np
.set_pos(pos
)
201 light_np
.look_at(look_at
)
202 light
.set_color(color
)
203 render
.set_light(light_np
)
206 def _set_lights(self
):
207 alight
= AmbientLight('alight') # for ao
208 alight
.set_color((.15, .15, .15, 1))
209 self
._alnp
= render
.attach_new_node(alight
)
210 render
.set_light(self
._alnp
)
211 self
._key
_light
= self
._set
_spotlight
(
212 'key light', (-5, -80, 5), (0, 0, 0), (2.8, 2.8, 2.8, 1))
213 self
._shadow
_light
= self
._set
_spotlight
(
214 'key light', (-5, -80, 5), (0, 0, 0), (.58, .58, .58, 1), True)
215 self
._shadow
_light
.node().set_shadow_caster(True, 2048, 2048)
216 self
._shadow
_light
.node().get_lens().set_film_size(2048, 2048)
217 self
._shadow
_light
.node().get_lens().set_near_far(1, 256)
218 self
._shadow
_light
.node().set_camera_mask(BitMask32(0x01))
220 def _unset_lights(self
):
221 for light
in [self
._alnp
, self
._key
_light
, self
._shadow
_light
]:
222 render
.clear_light(light
)
225 def _set_input(self
):
226 self
.accept('mouse1', self
.on_click_l
)
227 self
.accept('mouse1-up', self
.on_release
)
228 self
.accept('mouse3', self
.on_click_r
)
229 self
.accept('mouse3-up', self
.on_release
)
231 def _unset_input(self
):
232 for evt
in ['mouse1', 'mouse1-up', 'mouse3', 'mouse3-up']:
235 def _set_mouse_plane(self
):
236 shape
= BulletPlaneShape((0, -1, 0), 0)
237 #self._mouse_plane_node = BulletRigidBodyNode('mouse plane')
238 self
._mouse
_plane
_node
= BulletGhostNode('mouse plane')
239 self
._mouse
_plane
_node
.addShape(shape
)
240 #np = render.attachNewNode(self._mouse_plane_node)
241 #self._world.attachRigidBody(self._mouse_plane_node)
242 self
._world
.attach_ghost(self
._mouse
_plane
_node
)
244 def _unset_mouse_plane(self
):
245 self
._world
.remove_ghost(self
._mouse
_plane
_node
)
248 if not base
.mouseWatcherNode
.has_mouse(): return []
249 p_from
, p_to
= P3dGfxMgr
.world_from_to(base
.mouseWatcherNode
.get_mouse())
250 return self
._world
.ray_test_all(p_from
, p_to
).get_hits()
252 def _update_info(self
, item
):
255 txt
= '%.3f %.3f\n%.3f°' % (
256 item
._np
.get_x(), item
._np
.get_z(), item
._np
.get_r())
257 self
._info
_txt
['text'] = txt
259 def _on_click(self
, method
):
262 for hit
in self
._get
_hits
():
263 if hit
.get_node() == self
._mouse
_plane
_node
:
264 pos
= hit
.get_hit_pos()
265 for hit
in self
._get
_hits
():
266 for item
in [i
for i
in self
.items
if hit
.get_node() == i
.node
and i
.interactable
]:
267 if not self
._item
_active
:
268 self
._item
_active
= item
269 getattr(item
, method
)(pos
)
270 img
= 'move' if method
== 'on_click_l' else 'rotate'
271 if not (img
== 'rotate' and not item
._instantiated
):
272 self
._cursor
.set_image('assets/images/buttons/%s.dds' % img
)
274 def on_click_l(self
):
275 self
._on
_click
('on_click_l')
277 def on_click_r(self
):
278 self
._on
_click
('on_click_r')
280 def on_release(self
):
281 if self
._item
_active
and not self
._item
_active
._first
_command
:
282 self
._commands
= self
._commands
[:self
._command
_idx
]
283 self
._commands
+= [self
._item
_active
]
284 self
._command
_idx
+= 1
285 self
.__prev
_btn
['state'] = NORMAL
286 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
287 self
.__prev
_btn
['frameColor'] = fcols
[0]
288 if self
._item
_active
._command
_idx
== len(self
._item
_active
._commands
) - 1:
289 self
.__next
_btn
['state'] = DISABLED
290 self
.__next
_btn
['frameColor'] = fcols
[1]
291 self
._item
_active
= None
292 [item
.on_release() for item
in self
.items
]
293 self
._cursor
.set_image('assets/images/buttons/arrowUpLeft.dds')
296 for item
in self
.items
:
297 item
.repos_done
= False
298 self
.items
= sorted(self
.items
, key
=lambda itm
: itm
.__class
__.__name
__)
299 [item
.on_aspect_ratio_changed() for item
in self
.items
]
300 self
._side
_panel
.update(self
.items
)
301 max_x
= -float('inf')
302 for item
in self
.items
:
303 if not item
._instantiated
:
304 max_x
= max(item
._np
.get_x(), max_x
)
305 for item
in self
.items
:
306 if not item
._instantiated
:
309 def on_aspect_ratio_changed(self
):
312 def _win_condition(self
):
315 def _fail_condition(self
):
316 return all(itm
.fail_condition() for itm
in self
.items
) and not self
._paused
and self
._state
== 'playing'
318 def on_frame(self
, task
):
319 hits
= self
._get
_hits
()
321 for hit
in self
._get
_hits
():
322 if hit
.get_node() == self
._mouse
_plane
_node
:
323 pos
= hit
.get_hit_pos()
324 hit_nodes
= [hit
.get_node() for hit
in hits
]
325 if self
._item
_active
:
326 items_hit
= [self
._item
_active
]
328 items_hit
= [itm
for itm
in self
.items
if itm
.node
in hit_nodes
]
329 items_no_hit
= [itm
for itm
in self
.items
if itm
not in items_hit
]
330 [itm
.on_mouse_on() for itm
in items_hit
]
331 [itm
.on_mouse_off() for itm
in items_no_hit
]
332 if pos
and self
._item
_active
:
333 self
._item
_active
.on_mouse_move(pos
)
335 self
._update
_info
(items_hit
[0] if items_hit
else None)
336 if self
._win
_condition
():
337 self
._set
_fail
() if self
._enforce
_res
== 'fail' else self
._set
_win
()
338 elif self
._state
== 'playing' and self
._fail
_condition
():
339 self
._set
_win
() if self
._enforce
_res
== 'win' else self
._set
_fail
()
340 if any(itm
._overlapping
for itm
in self
.items
):
341 self
._cursor
.cursor_img
.img
.set_color(.9, .1, .1, 1)
343 self
._cursor
.cursor_img
.img
.set_color(.9, .9, .9, 1)
346 def cb_inst(self
, item
):
350 self
._state
= 'playing'
351 self
.__prev
_btn
['state'] = DISABLED
352 self
.__next
_btn
['state'] = DISABLED
353 self
.__right
_btn
['state'] = DISABLED
354 [itm
.play() for itm
in self
.items
]
357 self
._commands
[self
._command
_idx
].redo()
358 self
._command
_idx
+= 1
359 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
360 self
.__prev
_btn
['state'] = NORMAL
361 self
.__prev
_btn
['frameColor'] = fcols
[0]
362 more_commands
= self
._command
_idx
< len(self
._commands
)
363 self
.__next
_btn
['state'] = NORMAL
if more_commands
else DISABLED
364 self
.__next
_btn
['frameColor'] = fcols
[0] if more_commands
else fcols
[1]
367 self
._command
_idx
-= 1
368 self
._commands
[self
._command
_idx
].undo()
369 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
370 self
.__next
_btn
['state'] = NORMAL
371 self
.__next
_btn
['frameColor'] = fcols
[0]
372 self
.__prev
_btn
['state'] = NORMAL
if self
._command
_idx
else DISABLED
373 self
.__prev
_btn
['frameColor'] = fcols
[0] if self
._command
_idx
else fcols
[1]
378 def _set_instructions(self
):
381 mgr
= TextPropertiesManager
.get_global_ptr()
382 for name
in ['mouse_l', 'mouse_r']:
383 graphic
= OnscreenImage('assets/images/buttons/%s.dds' % name
)
384 graphic
.set_scale(.5)
385 graphic
.get_texture().set_minfilter(Texture
.FTLinearMipmapLinear
)
386 graphic
.get_texture().set_anisotropic_degree(2)
387 mgr
.set_graphic(name
, graphic
)
389 graphic
.set_transparency(True)
390 graphic
.detach_node()
391 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
392 frameSize
=(-.6, .6, -.3, .3))
393 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
395 font
.set_pixels_per_unit(60)
396 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
397 font
.set_outline((0, 0, 0, 1), .8, .2)
398 self
._txt
= OnscreenText(
399 self
._instr
_txt
(), parent
=frm
, font
=font
, scale
=0.06,
400 fg
=(.9, .9, .9, 1), align
=TextNode
.A_left
)
401 u_l
= self
._txt
.textNode
.get_upper_left_3d()
402 l_r
= self
._txt
.textNode
.get_lower_right_3d()
403 w
, h
= l_r
[0] - u_l
[0], u_l
[2] - l_r
[2]
406 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
407 z
+= (btn_scale
+ 2 * mar
) / 2
408 self
._txt
['pos'] = -w
/ 2, z
409 u_l
= self
._txt
.textNode
.get_upper_left_3d()
410 l_r
= self
._txt
.textNode
.get_lower_right_3d()
411 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
412 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
413 frm
['frameSize'] = fsz
415 (.6, .6, .6, 1), # ready
416 (1, 1, 1, 1), # press
417 (.8, .8, .8, 1), # rollover
419 imgs
= [self
.__load
_img
_btn
('exitRight', col
) for col
in colors
]
421 image
=imgs
, scale
=btn_scale
,
422 pos
=(l_r
[0] - btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
423 parent
=frm
, command
=self
.__on
_close
_instructions
, extraArgs
=[frm
],
424 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
425 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
426 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
427 btn
.set_transparency(True)
430 loader
.load_sfx('assets/audio/sfx/success.ogg').play()
433 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
434 frameSize
=(-.6, .6, -.3, .3))
435 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
437 font
.set_pixels_per_unit(60)
438 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
439 font
.set_outline((0, 0, 0, 1), .8, .2)
440 self
._txt
= OnscreenText(
443 font
=font
, scale
=0.2,
445 u_l
= self
._txt
.textNode
.get_upper_left_3d()
446 l_r
= self
._txt
.textNode
.get_lower_right_3d()
447 w
, h
= l_r
[0] - u_l
[0], u_l
[2] - l_r
[2]
450 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
451 z
+= (btn_scale
+ 2 * mar
) / 2
452 self
._txt
['pos'] = 0, z
453 u_l
= self
._txt
.textNode
.get_upper_left_3d()
454 l_r
= self
._txt
.textNode
.get_lower_right_3d()
455 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
456 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
457 frm
['frameSize'] = fsz
459 (.6, .6, .6, 1), # ready
460 (1, 1, 1, 1), # press
461 (.8, .8, .8, 1), # rollover
463 imgs
= [self
.__load
_img
_btn
('home', col
) for col
in colors
]
465 image
=imgs
, scale
=btn_scale
,
466 pos
=(-2.8 * btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
467 parent
=frm
, command
=self
._on
_end
_home
, extraArgs
=[frm
],
468 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
469 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
470 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
471 btn
.set_transparency(True)
472 imgs
= [self
.__load
_img
_btn
('rewind', col
) for col
in colors
]
474 image
=imgs
, scale
=btn_scale
,
475 pos
=(0, 1, l_r
[2] - mar
- btn_scale
),
476 parent
=frm
, command
=self
._on
_restart
, extraArgs
=[frm
],
477 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
478 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
479 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
480 btn
.set_transparency(True)
481 enabled
= self
._scenes
.index(self
.__class
__) < len(self
._scenes
) - 1
483 next_scene
= self
._scenes
[self
._scenes
.index(self
.__class
__) + 1]
486 imgs
= [self
.__load
_img
_btn
('right', col
) for col
in colors
]
488 image
=imgs
, scale
=btn_scale
,
489 pos
=(2.8 * btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
490 parent
=frm
, command
=self
._on
_next
_scene
,
491 extraArgs
=[frm
, next_scene
], relief
=FLAT
,
492 frameColor
=(.6, .6, .6, .08),
493 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
494 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
495 btn
['state'] = NORMAL
if enabled
else DISABLED
496 btn
.set_transparency(True)
499 loader
.load_sfx('assets/audio/sfx/success.ogg').play()
502 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
503 frameSize
=(-.6, .6, -.3, .3))
504 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
506 font
.set_pixels_per_unit(60)
507 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
508 font
.set_outline((0, 0, 0, 1), .8, .2)
509 self
._txt
= OnscreenText(
510 _('You have failed!'),
512 font
=font
, scale
=0.2,
514 u_l
= self
._txt
.textNode
.get_upper_left_3d()
515 l_r
= self
._txt
.textNode
.get_lower_right_3d()
516 w
, h
= l_r
[0] - u_l
[0], u_l
[2] - l_r
[2]
519 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
520 z
+= (btn_scale
+ 2 * mar
) / 2
521 self
._txt
['pos'] = 0, z
522 u_l
= self
._txt
.textNode
.get_upper_left_3d()
523 l_r
= self
._txt
.textNode
.get_lower_right_3d()
524 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
525 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
526 frm
['frameSize'] = fsz
528 (.6, .6, .6, 1), # ready
529 (1, 1, 1, 1), # press
530 (.8, .8, .8, 1), # rollover
532 imgs
= [self
.__load
_img
_btn
('home', col
) for col
in colors
]
534 image
=imgs
, scale
=btn_scale
,
535 pos
=(-2.8 * btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
536 parent
=frm
, command
=self
._on
_end
_home
, extraArgs
=[frm
],
537 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
538 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
539 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
540 btn
.set_transparency(True)
541 imgs
= [self
.__load
_img
_btn
('rewind', col
) for col
in colors
]
543 image
=imgs
, scale
=btn_scale
,
544 pos
=(0, 1, l_r
[2] - mar
- btn_scale
),
545 parent
=frm
, command
=self
._on
_restart
, extraArgs
=[frm
],
546 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
547 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
548 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
549 btn
.set_transparency(True)
551 def _on_restart(self
, frm
):
552 self
.__on
_close
_instructions
(frm
)
555 def _on_end_home(self
, frm
):
556 self
.__on
_close
_instructions
(frm
)
559 def _on_next_scene(self
, frm
, scene
):
560 self
.__on
_close
_instructions
(frm
)
561 self
._reload
_cb
(scene
)
563 def __store_state(self
):
565 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
566 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
567 self
.__btn
_state
= [btn
['state'] for btn
in btns
]
569 btn
['state'] = DISABLED
570 [itm
.store_state() for itm
in self
.items
]
572 def __restore_state(self
):
574 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
575 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
576 for btn
, state
in zip(btns
, self
.__btn
_state
):
578 [itm
.restore_state() for itm
in self
.items
]
581 def __on_close_instructions(self
, frm
):
583 self
.__restore
_state
()