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