ya2 · news · projects · code · about

housekeeping: ya2.utils.gui
[pmachines.git] / pmachines / gui / options_page.py
1 from logging import info, debug
2 from panda3d.core import WindowProperties, LVector2i
3 from direct.showbase.DirectObject import DirectObject
4 from direct.gui.DirectGui import DirectFrame
5 from ya2.utils.gfx import DirectGuiMixin, pos_pixel
6 from ya2.utils.audio import AudioTools
7 from ya2.utils.gui.base_page import BasePage, OptionMenuInfo, TextInfo, SliderInfo, CheckButtonInfo, ButtonInfo
8
9
10 class OptionsPage(BasePage, DirectObject):
11
12 def __init__(self, page_info, option_file, set_language, gfx_pipeline):
13 DirectObject.__init__(self)
14 self.__option_file = option_file
15 self.__set_language = set_language
16 self.__gfx_pipeline = gfx_pipeline
17 self.__enforced_resolution = ''
18 super().__init__(page_info)
19
20 def _build_widgets(self):
21 self.__build_language()
22 self.__build_volume()
23 self.__build_fullscreen()
24 self.__build_resolution()
25 self.__build_aa()
26 self.__build_shadows()
27 self.__build_back()
28
29 def __build_language(self):
30 self._lang_funcs = [lambda: _('English'), lambda: _('Italian')]
31 items = [fnc() for fnc in self._lang_funcs]
32 inititem = {
33 'en': _('English'),
34 'it': _('Italian')
35 }[self.__option_file['settings']['language']]
36
37 def lang_cb(comps):
38 for element in ['english', 'italian']:
39 if element in self._page_info.test_positions:
40 del self._page_info.test_positions[element]
41 for lng, btn in zip(['english', 'italian'], comps):
42 btn.__class__ = type('DirectFrameMixed', (DirectFrame, DirectGuiMixin), {})
43 pos = btn.pos_pixel()
44 self._page_info.test_positions[lng] = (pos[0] + 5, pos[1])
45 language_menu = OptionMenuInfo(
46 id='languages',
47 text=_('Language'),
48 items=items,
49 initial_item=inititem,
50 pos=(0, .8),
51 command=self.on_language)
52 self._add_option_menu(language_menu, lang_cb)
53
54 def __build_volume(self):
55 t = TextInfo(
56 text=_('Volume'),
57 pos=(-.56, .55),
58 align='left')
59 self._add_text(t)
60 s = SliderInfo(
61 pos=(.3, 1, .57),
62 value=self.__option_file['settings']['volume'],
63 scale=(.28, 1, .5),
64 command=self.on_volume)
65 self._slider = self._add_slider(s)
66
67 def __build_fullscreen(self):
68 c = CheckButtonInfo(
69 id='fullscreen',
70 text=_('Fullscreen'),
71 pos=(0, .3),
72 command=self.on_fullscreen,
73 value=self.__option_file['settings']['fullscreen'])
74 self._add_check_button(c)
75
76 def __build_resolution(self):
77 res = self.__option_file['settings']['resolution']
78 d_i = base.pipe.get_display_information()
79 def _res(idx):
80 return d_i.get_display_mode_width(idx), \
81 d_i.get_display_mode_height(idx)
82 resolutions = [
83 _res(idx) for idx in range(d_i.get_total_display_modes())]
84 resolutions = list(set(resolutions))
85 resolutions = sorted(resolutions)
86 resolutions = [(str(_res[0]), str(_res[1])) for _res in resolutions]
87 resolutions = ['x'.join(_res) for _res in resolutions]
88 if not res:
89 res = resolutions[-1]
90 def res_cb(comps):
91 for element in ['res_1440x900', 'res_1360x768']:
92 if element in self._page_info.test_positions:
93 del self._page_info.test_positions[element]
94 for tgt_res in ['1440x900', '1360x768']:
95 for btn in comps:
96 if btn['text'] == tgt_res:
97 pos = pos_pixel(btn)
98 self._page_info.test_positions['res_' + tgt_res] = (pos[0] + 5, pos[1])
99 r = OptionMenuInfo(
100 id='resolutions',
101 text=_('Resolution'),
102 items=resolutions,
103 initial_item=res,
104 pos=(0, .05),
105 command=self.on_resolution)
106 o = self._add_option_menu(r, res_cb)
107 pos_res = o.pos_pixel()
108 self._page_info.test_positions['res_1440x900'] = [pos_res[0] + 320, pos_res[1] + 75]
109 self._page_info.test_positions['res_1360x768'] = [pos_res[0] + 430, pos_res[1] -285]
110
111 def __build_aa(self):
112 c = CheckButtonInfo(
113 id='aa',
114 text=_('Antialiasing'),
115 pos=(0, -.2),
116 command=self.on_aa,
117 value=self.__option_file['settings']['antialiasing'])
118 self._add_check_button(c)
119
120 def __build_shadows(self):
121 c = CheckButtonInfo(
122 id='shadows',
123 text=_('Shadows'),
124 pos=(0, -.45),
125 command=self.on_shadows,
126 value=self.__option_file['settings']['shadows'])
127 self._add_check_button(c)
128
129 def __build_back(self):
130 back_button = ButtonInfo(
131 id='back',
132 text=_('Back'),
133 pos=(0, -.8),
134 command=self._set_page,
135 command_args=['main'])
136 self._add_button(back_button)
137 self.accept('enforce_resolution', self.enforce_resolution)
138
139 def enforce_resolution(self, resolution):
140 self.__enforced_resolution = resolution
141 info('enforced resolution: ' + resolution)
142
143 def on_language(self, arg):
144 lang_code = {
145 _('English'): 'en_EN',
146 _('Italian'): 'it_IT'}[arg]
147 self.__set_language(lang_code)
148 self.__option_file['settings']['language'] = lang_code[:2]
149 self.__option_file.store()
150 self._set_page('options')
151
152 def on_volume(self):
153 self.__option_file['settings']['volume'] = self._slider['value']
154 AudioTools.set_volume(self._slider['value'])
155
156 def on_fullscreen(self, arg):
157 props = WindowProperties()
158 props.set_fullscreen(arg)
159 if not self._page_info.running_functional_tests:
160 base.win.request_properties(props)
161 # if we actually switch to fullscreen during the tests then
162 # exwm inside qemu can't restore the correct resolution
163 # i may re-enable this if/when i run the tests onto a
164 # physical machine
165 self.__option_file['settings']['fullscreen'] = int(arg)
166 self.__option_file.store()
167
168 def on_resolution(self, arg):
169 info('on resolution: %s (%s)' % (arg, self.__enforced_resolution))
170 arg = self.__enforced_resolution or arg
171 info('set resolution: %s' % arg)
172 props = WindowProperties()
173 props.set_size(LVector2i(*[int(_res) for _res in arg.split('x')]))
174 base.win.request_properties(props)
175 self.__option_file['settings']['resolution'] = arg
176 self.__option_file.store()
177
178 def on_aa(self, arg):
179 self.__gfx_pipeline.msaa_samples = 4 if arg else 1
180 debug(f'msaa: {self.__gfx_pipeline.msaa_samples}')
181 self.__option_file['settings']['antialiasing'] = int(arg)
182 self.__option_file.store()
183
184 def on_shadows(self, arg):
185 self.__gfx_pipeline.enable_shadows = int(arg)
186 debug(f'shadows: {self.__gfx_pipeline.enable_shadows}')
187 self.__option_file['settings']['shadows'] = int(arg)
188 self.__option_file.store()
189
190 def on_back(self):
191 self.__option_file.store()
192 super().on_back()
193
194 def destroy(self):
195 super().destroy()
196 self.ignore('enforce_resolution')