1912797485ae08ae15fdab5460d2bab4fabfb4cf
1 from inspect
import getmro
2 from ya2
.lib
.gui
import Btn
, Slider
, CheckBtn
, OptionMenu
, Entry
3 from ya2
.engine
.vec
import Vec2
4 from ya2
.engine
.gui
.gui
import left
, right
, up
, down
5 from ya2
.gameobject
import GameObject
, GuiColleague
, EventColleague
6 from ya2
.engine
.gui
.imgbtn
import ImgBtn
9 class PageGui(GuiColleague
):
11 def __init__(self
, mediator
, menu_props
, players
=[0]):
12 GuiColleague
.__init
__(self
, mediator
)
13 self
.enable_tsk
= None
15 self
.menu_props
= menu_props
16 self
.players
= players
21 for player
in players
:
23 self
.__next
_wdg
((-.1, -1), player
, Vec2(-3.6, 1))]
24 if self
.curr_wdgs
[-1]:
25 self
.curr_wdgs
[-1].on_wdg_enter(None, player
)
27 def build(self
, back_btn
=True, exit_behav
=False):
28 if back_btn
: self
.__build
_back
_btn
(exit_behav
)
31 self
.transition_enter()
34 def add_widgets(self
, widgets
): self
.widgets
+= widgets
36 def on_arrow(self
, direction
, player
):
37 if not self
.curr_wdgs
[player
]: return
38 if self
.curr_wdgs
[player
].__class
__.__name
__ == 'P3dEntryWidget' and \
39 self
.curr_wdgs
[player
].focused
: return
40 processed_cmd
= self
.curr_wdgs
[player
].on_arrow(direction
)
41 # e.g. up/down in a combobox or left/right in a slider
42 if processed_cmd
: return
43 next_wdg
= self
.__next
_wdg
(direction
, player
)
44 if not next_wdg
: return
45 self
.focus(next_wdg
, player
)
47 def on_enter(self
, player
):
48 if not self
.curr_wdgs
[player
]: return
49 arg
= player
if len(self
.players
) > 1 else None
50 if self
.curr_wdgs
[player
].on_enter(arg
): self
.enable([player
])
51 # wdg.on_enter returns True when it is an option widget
55 is_btn
= lambda wdg
: Btn
in getmro(wdg
.__class
__)
56 return [wdg
for wdg
in self
.widgets
if is_btn(wdg
)]
58 def focus(self
, wdg
, player
):
59 self
.curr_wdgs
[player
].on_wdg_exit(None, player
)
60 self
.curr_wdgs
[player
] = wdg
61 self
.curr_wdgs
[player
].on_wdg_enter(None, player
)
63 def __direction_dot_dwg(self
, wdg
, direction
, player
, start
=None):
64 if start
: start_pos
= start
65 else: start_pos
= self
.curr_wdgs
[player
].pos
66 return (wdg
.pos
- start_pos
).normalized
.dot(direction
)
68 def __next_weight(self
, wdg
, direction
, player
, start
=None):
69 if start
: start_pos
= start
70 else: start_pos
= self
.curr_wdgs
[player
].global_pos
71 dot
= self
.__direction
_dot
_dwg
(wdg
, direction
, player
, start
)
72 if direction
in [(-1, 0), (1, 0)]:
73 proj_dist
= abs(wdg
.global_pos
.x
- start_pos
.x
)
74 else: proj_dist
= abs(wdg
.global_pos
.y
- start_pos
.y
)
75 weights
= [.5, .5] if direction
in [left
, right
] else [.1, .9]
76 return weights
[0] * (dot
* dot
) + weights
[1] * (1 - proj_dist
)
78 def __next_wdg(self
, direction
, player
, start
=None):
80 iclss
= [Btn
, CheckBtn
, Slider
, OptionMenu
, ImgBtn
, Entry
]
81 inter
= lambda wdg
: any(pcl
in iclss
for pcl
in getmro(wdg
.__class
__))
82 allwdgs
= [wdg
for wdg
in self
.widgets
if inter(wdg
)]
83 wdgs
= list(filter(lambda wdg
: wdg
.is_enabled
, allwdgs
))
84 if player
< len(self
.curr_wdgs
) and self
.curr_wdgs
[player
] \
85 and self
.curr_wdgs
[player
] in wdgs
:
86 # the last check for this case: multiple players appear on the
87 # same button, one player clicks it, another moves from it
88 wdgs
.remove(self
.curr_wdgs
[player
])
89 mth
= self
.__direction
_dot
_dwg
90 in_direction
= lambda wdg
: mth(wdg
, direction
, player
, start
) > .1
91 dirwdgs
= list(filter(in_direction
, wdgs
))
92 if not dirwdgs
: return None
93 nextweight
= lambda wdg
: \
94 self
.__next
_weight
(wdg
, direction
, player
, start
)
95 return max(dirwdgs
, key
=nextweight
)
97 def _set_widgets(self
):
98 list(map(lambda wdg
: wdg
.set_widget(), self
.widgets
))
100 def _set_entries(self
):
101 for wdg
in self
.widgets
:
102 if wdg
.__class
__.__name
__ == 'P3dEntryWidget':
103 wdg
.attach(self
.on_entry_enter
)
104 wdg
.attach(self
.on_entry_exit
)
106 def on_entry_enter(self
):
107 if self
.menu_props
: # i.e. not destroyed
108 self
.disable_navigation(self
.players
)
110 def on_entry_exit(self
):
111 if self
.menu_props
: # i.e. not destroyed
112 self
.enable_navigation(self
.players
)
114 def transition_enter(self
):
116 list(map(lambda wdg
: wdg
.set_enter_transition(), self
.widgets
))
117 self
.enable(self
.players
)
119 def translate(self
): list(map(lambda wdg
: wdg
.translate(), self
.widgets
))
121 def enable_navigation(self
, players
):
122 if self
.enable_tsk
: self
.eng
.rm_do_later(self
.enable_tsk
)
123 self
.enable_tsk
= self
.eng
.do_later(
124 .01, self
.enable_navigation_aux
, [players
])
126 def update_navigation(self
):
127 self
.disable_navigation(self
.players
)
128 self
.enable_navigation(self
.players
)
130 def enable_navigation_aux(self
, players
):
132 for player
in players
:
133 nav
= self
.menu_props
.nav
.navinfo_lst
[player
]
135 (self
.eng
.lib
.remap_str(nav
.left
), self
.on_arrow
,
137 (self
.eng
.lib
.remap_str(nav
.right
), self
.on_arrow
,
139 (self
.eng
.lib
.remap_str(nav
.up
), self
.on_arrow
, [up
, player
]),
140 (self
.eng
.lib
.remap_str(nav
.down
), self
.on_arrow
,
142 (self
.eng
.lib
.remap_str(nav
.fire
), self
.on_enter
, [player
])]
143 def append_up(evt
): return evt
+ ('' if evt
.endswith('-up') else '-up')
144 evts
= [(append_up(evt
[0]), evt
[1], evt
[2]) for evt
in evts
]
146 list(map(lambda args
: self
.mediator
.event
.accept(*args
), evts
))
147 self
.eng
.joystick_mgr
.bind_keyboard(navs
)
148 if self
.eng
.cfg
.dev_cfg
.menu_joypad
and self
._back
_btn
:
149 self
.mediator
.event
.accept('joypad0-face_b-up', self
.__back
_wrapper
)
151 def __back_wrapper(self
):
152 if not self
.eng
.joystick_mgr
.is_recording
: self
._back
_btn
['command']()
154 def disable_navigation(self
, players
):
156 self
.enable_tsk
= self
.eng
.rm_do_later(self
.enable_tsk
)
157 for player
in players
:
158 nav
= self
.menu_props
.nav
.navinfo_lst
[player
]
159 # evts = [nav.left, nav.right, nav.up, nav.down, nav.fire]
161 self
.eng
.lib
.remap_str(nav
.left
),
162 self
.eng
.lib
.remap_str(nav
.right
),
163 self
.eng
.lib
.remap_str(nav
.up
),
164 self
.eng
.lib
.remap_str(nav
.down
),
165 self
.eng
.lib
.remap_str(nav
.fire
)]
166 def append_up(evt
): return evt
+ ('' if evt
.endswith('-up') else '-up')
167 evts
= [append_up(evt
) for evt
in evts
]
168 self
.eng
.joystick_mgr
.unbind_keyboard()
169 list(map(self
.mediator
.event
.ignore
, evts
))
170 self
.mediator
.event
.ignore('joypad0-face_b-up')
172 def enable(self
, players
):
173 self
.enable_navigation(players
)
174 list(map(lambda wdg
: wdg
.enable(), self
.widgets
))
176 def disable(self
, players
):
178 self
.enable_tsk
= self
.eng
.rm_do_later(self
.enable_tsk
)
179 self
.disable_navigation(players
)
180 list(map(lambda wdg
: wdg
.disable(), self
.widgets
))
182 def transition_exit(self
, destroy
=True):
183 list(map(lambda wdg
: wdg
.set_exit_transition(destroy
), self
.widgets
))
184 self
.disable(self
.players
)
186 def __build_back_btn(self
, exit_behav
):
187 tra_src
= 'Quit' if exit_behav
else 'Back'
188 tra_tra
= _('Quit') if exit_behav
else _('Back')
189 callback
= self
._on
_quit
if exit_behav
else self
._on
_back
190 btn
= Btn(text
='', pos
=(0, -.85), cmd
=callback
,
191 tra_src
=tra_src
, tra_tra
=tra_tra
, **self
.menu_props
.btn_args
)
192 self
.widgets
+= [btn
]
195 def _on_back(self
, player
=0):
196 self
.notify('on_back', self
.__class
__.__name
__)
198 def _on_quit(self
): self
.notify('on_quit', self
.__class
__.__name
__)
201 visible_widgets
= [wdg
for wdg
in self
.widgets
if wdg
.was_visible
]
202 list(map(lambda wdg
: wdg
.show(), visible_widgets
))
203 self
.transition_enter()
206 for wdg
in self
.widgets
: wdg
.was_visible
= not wdg
.hidden
207 self
.transition_exit(False)
208 self
.notify('on_hide')
211 self
.transition_exit()
212 self
.menu_props
= None
215 class PageEvent(EventColleague
):
217 def on_back(self
): pass
219 def on_quit(self
): pass
224 def show(self
): return self
.gui
.show()
225 def hide(self
): return self
.gui
.hide()
226 def enable(self
, players
): return self
.gui
.enable(players
)
227 def disable(self
, players
): return self
.gui
.disable(players
)
229 def enable_navigation(self
, players
):
230 return self
.gui
.enable_navigation(players
)
232 def disable_navigation(self
, players
):
233 return self
.gui
.disable_navigation(players
)
235 def attach_obs(self
, obs_meth
, sort
=10, rename
='', args
=None):
236 return self
.gui
.attach(obs_meth
, sort
, rename
, args
or [])
238 def detach_obs(self
, obs_meth
, lambda_call
=None):
239 return self
.gui
.detach(obs_meth
, lambda_call
)
242 class Page(GameObject
, PageFacade
):
245 event_cls
= PageEvent
247 def __init__(self
, menu_props
, players
=[0]):
248 PageFacade
.__init
__(self
)
249 self
.menu_props
= menu_props
250 self
.players
= players
251 GameObject
.__init
__(self
)
254 list(map(self
.gui
.attach
, [self
.on_hide
, self
.on_back
, self
.on_quit
]))
256 def _build_event(self
):
257 self
.event
= self
.event_cls(self
)
259 def _build_gui(self
):
260 self
.gui
= self
.gui_cls(self
, self
.menu_props
, self
.players
)
262 def on_hide(self
): self
.event
.ignoreAll()
264 def on_back(self
, cls_name
, args
=None): self
.event
.on_back() # unused arg
266 def on_quit(self
, cls_name
): self
.event
.on_quit() # unused arg
271 bases
= [basecls
for basecls
in Page
.__bases
__
272 if basecls
!= PageFacade
]
273 for cls
in bases
: cls
.destroy(self
)