b44506ad9c6cfe981a9f0abaa2db2648cc17cc70
1 from os
.path
import exists
2 from os
import makedirs
4 from importlib
import import_module
5 from inspect
import isclass
6 from panda3d
.core
import AmbientLight
, DirectionalLight
, Point3
, Texture
, \
7 TextPropertiesManager
, TextNode
, Spotlight
, PerspectiveLens
, BitMask32
8 from panda3d
.bullet
import BulletPlaneShape
, BulletGhostNode
9 from direct
.gui
.OnscreenImage
import OnscreenImage
10 from direct
.gui
.OnscreenText
import OnscreenText
11 from direct
.gui
.DirectGui
import DirectButton
, DirectFrame
12 from direct
.gui
.DirectGuiGlobals
import FLAT
, DISABLED
, NORMAL
13 from direct
.showbase
.DirectObject
import DirectObject
14 from game
.items
.background
import Background
15 from game
.sidepanel
import SidePanel
16 from lib
.engine
.gui
.cursor
import MouseCursor
17 from lib
.lib
.p3d
.gfx
import P3dGfxMgr
20 class Scene(DirectObject
):
22 def __init__(self
, world
, exit_cb
, auto_close_instr
, dbg_items
, reload_cb
):
25 self
._exit
_cb
= exit_cb
26 self
._dbg
_items
= dbg_items
27 self
._reload
_cb
= reload_cb
29 self
._cursor
= MouseCursor(
30 'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
35 self
._set
_mouse
_plane
()
40 self
._item
_active
= None
43 self
.__restore
_state
()
45 self
._set
_instructions
()
46 self
._bg
= Background()
47 self
._side
_panel
= SidePanel(world
, self
._mouse
_plane
_node
, (-5, 4), (-3, 1), 1, self
.items
)
48 self
._scene
_tsk
= taskMgr
.add(self
.on_frame
, 'on_frame')
60 def screenshot(self
, task
=None):
61 tex
= Texture('screenshot')
62 buffer = base
.win
.make_texture_buffer('screenshot', 512, 512, tex
, True )
63 cam
= base
.make_camera(buffer)
64 cam
.reparent_to(render
)
65 cam
.node().get_lens().set_fov(base
.camLens
.get_fov())
66 cam
.set_pos(0, -20, 0)
73 use_emission_maps
=False,
74 use_occlusion_maps
=True,
77 base
.graphicsEngine
.renderFrame()
78 base
.graphicsEngine
.renderFrame()
79 fname
= self
.__class
__.__name
__
80 if not exists('assets/images/scenes'):
81 makedirs('assets/images/scenes')
82 buffer.save_screenshot('assets/images/scenes/%s.png' % fname
)
84 # frameTexture=buffer.get_texture(), relief=FLAT,
85 # frameSize=(-.2, .2, -.2, .2))
86 return buffer.get_texture()
88 def current_bottom(self
):
90 for item
in self
.items
:
92 curr_bottom
= min(curr_bottom
, item
.get_bottom())
96 [itm
.destroy() for itm
in self
.items
]
100 self
._command
_idx
= 0
101 if hasattr(self
, '_success_txt'):
102 self
._success
_txt
.destroy()
103 del self
._success
_txt
104 self
.__right
_btn
['state'] = NORMAL
110 self
._unset
_mouse
_plane
()
111 [itm
.destroy() for itm
in self
.items
]
113 self
._side
_panel
.destroy()
114 self
._cursor
.destroy()
115 taskMgr
.remove(self
._scene
_tsk
)
116 if hasattr(self
, '_success_txt'):
117 self
._success
_txt
.destroy()
119 def _set_camera(self
):
120 base
.camera
.set_pos(0, -20, 0)
121 base
.camera
.look_at(0, 0, 0)
123 def __load_img_btn(self
, path
, col
):
124 img
= OnscreenImage('assets/images/buttons/%s.dds' % path
)
125 img
.set_transparency(True)
131 def load_images_btn(path
, col
):
134 (.6, .6, .6, 1), # ready
135 (1, 1, 1, 1), # press
136 (.8, .8, .8, 1), # rollover
142 (.4, .1, .1, .4)]}[col
]
143 return [self
.__load
_img
_btn
(path
, col
) for col
in colors
]
144 abl
, abr
= base
.a2dBottomLeft
, base
.a2dBottomRight
146 ('home', self
.on_home
, NORMAL
, abl
, 'gray'),
147 ('information', self
._set
_instructions
, NORMAL
, abl
, 'gray'),
148 ('right', self
.on_play
, NORMAL
, abr
, 'green'),
149 ('next', self
.on_next
, DISABLED
, abr
, 'gray'),
150 ('previous', self
.on_prev
, DISABLED
, abr
, 'gray'),
151 ('rewind', self
.reset
, NORMAL
, abr
, 'gray')]
154 for binfo
in btn_info
:
155 imgs
= load_images_btn(binfo
[0], binfo
[4])
156 if binfo
[3] == base
.a2dBottomLeft
:
160 sign
, num
= -1, num_r
162 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
164 image
=imgs
, scale
=.05, pos
=(sign
* (.06 + .11 * num
), 1, .06),
165 parent
=binfo
[3], command
=binfo
[1], state
=binfo
[2], relief
=FLAT
,
166 frameColor
=fcols
[0] if binfo
[2] == NORMAL
else fcols
[1],
167 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
168 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
169 btn
.set_transparency(True)
171 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
, self
.__next
_btn
, \
172 self
.__prev
_btn
, self
.__rewind
_btn
= btns
174 self
._info
_txt
= OnscreenText(
175 '', parent
=base
.a2dTopRight
, scale
=0.04,
176 pos
=(-.03, -.06), fg
=(.9, .9, .9, 1), align
=TextNode
.A_right
)
178 def _unset_gui(self
):
180 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
181 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
182 [btn
.destroy() for btn
in btns
]
184 self
._info
_txt
.destroy()
186 def _set_spotlight(self
, name
, pos
, look_at
, color
, shadows
=False):
187 light
= Spotlight(name
)
189 light
.setLens(PerspectiveLens())
190 light_np
= render
.attach_new_node(light
)
191 light_np
.set_pos(pos
)
192 light_np
.look_at(look_at
)
193 light
.set_color(color
)
194 render
.set_light(light_np
)
197 def _set_lights(self
):
198 alight
= AmbientLight('alight') # for ao
199 alight
.set_color((.15, .15, .15, 1))
200 self
._alnp
= render
.attach_new_node(alight
)
201 render
.set_light(self
._alnp
)
202 self
._key
_light
= self
._set
_spotlight
(
203 'key light', (-5, -80, 5), (0, 0, 0), (2.8, 2.8, 2.8, 1))
204 self
._shadow
_light
= self
._set
_spotlight
(
205 'key light', (-5, -80, 5), (0, 0, 0), (.58, .58, .58, 1), True)
206 self
._shadow
_light
.node().set_shadow_caster(True, 2048, 2048)
207 self
._shadow
_light
.node().get_lens().set_film_size(2048, 2048)
208 self
._shadow
_light
.node().get_lens().set_near_far(1, 256)
209 self
._shadow
_light
.node().set_camera_mask(BitMask32(0x01))
211 def _unset_lights(self
):
212 for light
in [self
._alnp
, self
._key
_light
, self
._shadow
_light
]:
213 render
.clear_light(light
)
216 def _set_input(self
):
217 self
.accept('mouse1', self
.on_click_l
)
218 self
.accept('mouse1-up', self
.on_release
)
219 self
.accept('mouse3', self
.on_click_r
)
220 self
.accept('mouse3-up', self
.on_release
)
222 def _unset_input(self
):
223 for evt
in ['mouse1', 'mouse1-up', 'mouse3', 'mouse3-up']:
226 def _set_mouse_plane(self
):
227 shape
= BulletPlaneShape((0, -1, 0), 0)
228 #self._mouse_plane_node = BulletRigidBodyNode('mouse plane')
229 self
._mouse
_plane
_node
= BulletGhostNode('mouse plane')
230 self
._mouse
_plane
_node
.addShape(shape
)
231 #np = render.attachNewNode(self._mouse_plane_node)
232 #self._world.attachRigidBody(self._mouse_plane_node)
233 self
._world
.attach_ghost(self
._mouse
_plane
_node
)
235 def _unset_mouse_plane(self
):
236 self
._world
.remove_ghost(self
._mouse
_plane
_node
)
239 if not base
.mouseWatcherNode
.has_mouse(): return []
240 p_from
, p_to
= P3dGfxMgr
.world_from_to(base
.mouseWatcherNode
.get_mouse())
241 return self
._world
.ray_test_all(p_from
, p_to
).get_hits()
243 def _update_info(self
, item
):
246 txt
= '%.3f %.3f\n%.3f°' % (
247 item
._np
.get_x(), item
._np
.get_z(), item
._np
.get_r())
248 self
._info
_txt
['text'] = txt
250 def _on_click(self
, method
):
253 for hit
in self
._get
_hits
():
254 if hit
.get_node() == self
._mouse
_plane
_node
:
255 pos
= hit
.get_hit_pos()
256 for hit
in self
._get
_hits
():
257 for item
in [i
for i
in self
.items
if hit
.get_node() == i
.node
and i
.interactable
]:
258 if not self
._item
_active
:
259 self
._item
_active
= item
260 getattr(item
, method
)(pos
)
261 img
= 'move' if method
== 'on_click_l' else 'rotate'
262 if not (img
== 'rotate' and not item
._instantiated
):
263 self
._cursor
.set_image('assets/images/buttons/%s.dds' % img
)
265 def on_click_l(self
):
266 self
._on
_click
('on_click_l')
268 def on_click_r(self
):
269 self
._on
_click
('on_click_r')
271 def on_release(self
):
272 if self
._item
_active
and not self
._item
_active
._first
_command
:
273 self
._commands
= self
._commands
[:self
._command
_idx
]
274 self
._commands
+= [self
._item
_active
]
275 self
._command
_idx
+= 1
276 self
.__prev
_btn
['state'] = NORMAL
277 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
278 self
.__prev
_btn
['frameColor'] = fcols
[0]
279 if self
._item
_active
._command
_idx
== len(self
._item
_active
._commands
) - 1:
280 self
.__next
_btn
['state'] = DISABLED
281 self
.__next
_btn
['frameColor'] = fcols
[1]
282 self
._item
_active
= None
283 [item
.on_release() for item
in self
.items
]
284 self
._cursor
.set_image('assets/images/buttons/arrowUpLeft.dds')
287 for item
in self
.items
:
288 item
.repos_done
= False
289 self
.items
= sorted(self
.items
, key
=lambda itm
: itm
.__class
__.__name
__)
290 [item
.on_aspect_ratio_changed() for item
in self
.items
]
291 self
._side
_panel
.update(self
.items
)
292 max_x
= -float('inf')
293 for item
in self
.items
:
294 if not item
._instantiated
:
295 max_x
= max(item
._np
.get_x(), max_x
)
296 for item
in self
.items
:
297 if not item
._instantiated
:
300 def on_aspect_ratio_changed(self
):
303 def _win_condition(self
):
306 def _fail_condition(self
):
307 return all(itm
.fail_condition() for itm
in self
.items
) and not self
._paused
and self
._state
== 'playing'
309 def on_frame(self
, task
):
310 hits
= self
._get
_hits
()
312 for hit
in self
._get
_hits
():
313 if hit
.get_node() == self
._mouse
_plane
_node
:
314 pos
= hit
.get_hit_pos()
315 hit_nodes
= [hit
.get_node() for hit
in hits
]
316 if self
._item
_active
:
317 items_hit
= [self
._item
_active
]
319 items_hit
= [itm
for itm
in self
.items
if itm
.node
in hit_nodes
]
320 items_no_hit
= [itm
for itm
in self
.items
if itm
not in items_hit
]
321 [itm
.on_mouse_on() for itm
in items_hit
]
322 [itm
.on_mouse_off() for itm
in items_no_hit
]
323 if pos
and self
._item
_active
:
324 self
._item
_active
.on_mouse_move(pos
)
326 self
._update
_info
(items_hit
[0] if items_hit
else None)
327 if self
._win
_condition
():
329 elif self
._state
== 'playing' and self
._fail
_condition
():
331 if any(itm
._overlapping
for itm
in self
.items
):
332 self
._cursor
.cursor_img
.img
.set_color(.9, .1, .1, 1)
334 self
._cursor
.cursor_img
.img
.set_color(.9, .9, .9, 1)
337 def cb_inst(self
, item
):
341 self
._state
= 'playing'
342 self
.__prev
_btn
['state'] = DISABLED
343 self
.__next
_btn
['state'] = DISABLED
344 self
.__right
_btn
['state'] = DISABLED
345 [itm
.play() for itm
in self
.items
]
348 self
._commands
[self
._command
_idx
].redo()
349 self
._command
_idx
+= 1
350 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
351 self
.__prev
_btn
['state'] = NORMAL
352 self
.__prev
_btn
['frameColor'] = fcols
[0]
353 more_commands
= self
._command
_idx
< len(self
._commands
)
354 self
.__next
_btn
['state'] = NORMAL
if more_commands
else DISABLED
355 self
.__next
_btn
['frameColor'] = fcols
[0] if more_commands
else fcols
[1]
358 self
._command
_idx
-= 1
359 self
._commands
[self
._command
_idx
].undo()
360 fcols
= (.4, .4, .4, .14), (.3, .3, .3, .05)
361 self
.__next
_btn
['state'] = NORMAL
362 self
.__next
_btn
['frameColor'] = fcols
[0]
363 self
.__prev
_btn
['state'] = NORMAL
if self
._command
_idx
else DISABLED
364 self
.__prev
_btn
['frameColor'] = fcols
[0] if self
._command
_idx
else fcols
[1]
369 def _set_instructions(self
):
372 mgr
= TextPropertiesManager
.get_global_ptr()
373 for name
in ['mouse_l', 'mouse_r']:
374 graphic
= OnscreenImage('assets/images/buttons/%s.dds' % name
)
375 graphic
.set_scale(.5)
376 graphic
.get_texture().set_minfilter(Texture
.FTLinearMipmapLinear
)
377 graphic
.get_texture().set_anisotropic_degree(2)
378 mgr
.set_graphic(name
, graphic
)
380 graphic
.set_transparency(True)
381 graphic
.detach_node()
382 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
383 frameSize
=(-.6, .6, -.3, .3))
384 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
386 font
.set_pixels_per_unit(60)
387 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
388 font
.set_outline((0, 0, 0, 1), .8, .2)
389 self
._txt
= OnscreenText(
390 self
._instr
_txt
(), parent
=frm
, font
=font
, scale
=0.06,
391 fg
=(.9, .9, .9, 1), align
=TextNode
.A_left
)
392 u_l
= self
._txt
.textNode
.get_upper_left_3d()
393 l_r
= self
._txt
.textNode
.get_lower_right_3d()
394 w
, h
= l_r
[0] - u_l
[0], u_l
[2] - l_r
[2]
397 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
398 z
+= (btn_scale
+ 2 * mar
) / 2
399 self
._txt
['pos'] = -w
/ 2, z
400 u_l
= self
._txt
.textNode
.get_upper_left_3d()
401 l_r
= self
._txt
.textNode
.get_lower_right_3d()
402 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
403 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
404 frm
['frameSize'] = fsz
406 (.6, .6, .6, 1), # ready
407 (1, 1, 1, 1), # press
408 (.8, .8, .8, 1), # rollover
410 imgs
= [self
.__load
_img
_btn
('exitRight', col
) for col
in colors
]
412 image
=imgs
, scale
=btn_scale
,
413 pos
=(l_r
[0] - btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
414 parent
=frm
, command
=self
.__on
_close
_instructions
, extraArgs
=[frm
],
415 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
416 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
417 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
418 btn
.set_transparency(True)
421 loader
.load_sfx('assets/audio/sfx/success.ogg').play()
424 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
425 frameSize
=(-.6, .6, -.3, .3))
426 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
428 font
.set_pixels_per_unit(60)
429 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
430 font
.set_outline((0, 0, 0, 1), .8, .2)
431 self
._txt
= OnscreenText(
434 font
=font
, scale
=0.2,
436 u_l
= self
._txt
.textNode
.get_upper_left_3d()
437 l_r
= self
._txt
.textNode
.get_lower_right_3d()
438 w
, h
= l_r
[0] - u_l
[0], u_l
[2] - l_r
[2]
441 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
442 z
+= (btn_scale
+ 2 * mar
) / 2
443 self
._txt
['pos'] = 0, z
444 u_l
= self
._txt
.textNode
.get_upper_left_3d()
445 l_r
= self
._txt
.textNode
.get_lower_right_3d()
446 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
447 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
448 frm
['frameSize'] = fsz
450 (.6, .6, .6, 1), # ready
451 (1, 1, 1, 1), # press
452 (.8, .8, .8, 1), # rollover
454 imgs
= [self
.__load
_img
_btn
('home', col
) for col
in colors
]
456 image
=imgs
, scale
=btn_scale
,
457 pos
=(-2.8 * btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
458 parent
=frm
, command
=self
._on
_end
_home
, extraArgs
=[frm
],
459 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
460 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
461 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
462 btn
.set_transparency(True)
463 imgs
= [self
.__load
_img
_btn
('rewind', col
) for col
in colors
]
465 image
=imgs
, scale
=btn_scale
,
466 pos
=(0, 1, l_r
[2] - mar
- btn_scale
),
467 parent
=frm
, command
=self
._on
_restart
, 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)
473 for _file
in glob('game/scenes/*.py'):
474 _fn
= _file
.replace('.py', '').replace('/', '.')
475 for member
in import_module(_fn
).__dict
__.values():
476 if isclass(member
) and issubclass(member
, Scene
) and \
479 scenes
= sorted(scenes
, key
=lambda elm
: elm
.sorting
)
480 enabled
= scenes
.index(self
.__class
__) < len(scenes
) - 1
482 next_scene
= scenes
[scenes
.index(self
.__class
__) + 1]
485 imgs
= [self
.__load
_img
_btn
('right', col
) for col
in colors
]
487 image
=imgs
, scale
=btn_scale
,
488 pos
=(2.8 * btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
489 parent
=frm
, command
=self
._on
_next
_scene
,
490 extraArgs
=[frm
, next_scene
], relief
=FLAT
,
491 frameColor
=(.6, .6, .6, .08),
492 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
493 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
494 btn
['state'] = NORMAL
if enabled
else DISABLED
495 btn
.set_transparency(True)
498 loader
.load_sfx('assets/audio/sfx/success.ogg').play()
501 frm
= DirectFrame(frameColor
=(.4, .4, .4, .06),
502 frameSize
=(-.6, .6, -.3, .3))
503 font
= base
.loader
.load_font('assets/fonts/Hanken-Book.ttf')
505 font
.set_pixels_per_unit(60)
506 font
.set_minfilter(Texture
.FTLinearMipmapLinear
)
507 font
.set_outline((0, 0, 0, 1), .8, .2)
508 self
._txt
= OnscreenText(
509 _('You have failed!'),
511 font
=font
, scale
=0.2,
513 u_l
= self
._txt
.textNode
.get_upper_left_3d()
514 l_r
= self
._txt
.textNode
.get_lower_right_3d()
515 w
, h
= l_r
[0] - u_l
[0], u_l
[2] - l_r
[2]
518 z
= h
/ 2 - font
.get_line_height() * self
._txt
['scale'][1]
519 z
+= (btn_scale
+ 2 * mar
) / 2
520 self
._txt
['pos'] = 0, z
521 u_l
= self
._txt
.textNode
.get_upper_left_3d()
522 l_r
= self
._txt
.textNode
.get_lower_right_3d()
523 c_l_r
= l_r
[0], l_r
[1], l_r
[2] - 2 * mar
- btn_scale
524 fsz
= u_l
[0] - mar
, l_r
[0] + mar
, c_l_r
[2] - mar
, u_l
[2] + mar
525 frm
['frameSize'] = fsz
527 (.6, .6, .6, 1), # ready
528 (1, 1, 1, 1), # press
529 (.8, .8, .8, 1), # rollover
531 imgs
= [self
.__load
_img
_btn
('home', col
) for col
in colors
]
533 image
=imgs
, scale
=btn_scale
,
534 pos
=(-2.8 * btn_scale
, 1, l_r
[2] - mar
- btn_scale
),
535 parent
=frm
, command
=self
._on
_end
_home
, extraArgs
=[frm
],
536 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
537 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
538 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
539 btn
.set_transparency(True)
540 imgs
= [self
.__load
_img
_btn
('rewind', col
) for col
in colors
]
542 image
=imgs
, scale
=btn_scale
,
543 pos
=(0, 1, l_r
[2] - mar
- btn_scale
),
544 parent
=frm
, command
=self
._on
_restart
, extraArgs
=[frm
],
545 relief
=FLAT
, frameColor
=(.6, .6, .6, .08),
546 rolloverSound
=loader
.load_sfx('assets/audio/sfx/rollover.ogg'),
547 clickSound
=loader
.load_sfx('assets/audio/sfx/click.ogg'))
548 btn
.set_transparency(True)
550 def _on_restart(self
, frm
):
551 self
.__on
_close
_instructions
(frm
)
554 def _on_end_home(self
, frm
):
555 self
.__on
_close
_instructions
(frm
)
558 def _on_next_scene(self
, frm
, scene
):
559 self
.__on
_close
_instructions
(frm
)
560 self
._reload
_cb
(scene
)
562 def __store_state(self
):
564 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
565 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
566 self
.__btn
_state
= [btn
['state'] for btn
in btns
]
568 btn
['state'] = DISABLED
569 [itm
.store_state() for itm
in self
.items
]
571 def __restore_state(self
):
573 self
.__home
_btn
, self
.__info
_btn
, self
.__right
_btn
,
574 self
.__next
_btn
, self
.__prev
_btn
, self
.__rewind
_btn
]
575 for btn
, state
in zip(btns
, self
.__btn
_state
):
577 [itm
.restore_state() for itm
in self
.items
]
580 def __on_close_instructions(self
, frm
):
582 self
.__restore
_state
()