Commit | Line | Data |
---|---|---|
9199c6aa FC |
1 | from dataclasses import dataclass |
2 | from panda3d.core import TextNode | |
3 | from direct.gui.OnscreenText import OnscreenText | |
4 | from direct.gui.DirectGui import DirectButton, DirectOptionMenu, DirectSlider, DirectCheckButton | |
5 | from direct.gui.DirectGuiGlobals import FLAT | |
6 | from ya2.utils.audio import AudioTools | |
7 | from ya2.utils.gfx import DirectGuiMixin, GfxTools | |
8 | from ya2.utils.gui.gui import GuiTools | |
9 | ||
10 | ||
11 | class DirectOptionMenuTestable(DirectOptionMenu): | |
12 | ||
13 | def __init__(self, parent=None, **kw): | |
14 | DirectOptionMenu.__init__(self, parent, **kw) | |
15 | self.initialiseoptions(DirectOptionMenuTestable) | |
16 | ||
17 | def showPopupMenu(self, event=None): | |
18 | #super().showPopupMenu(event) # it does not work with mixins | |
19 | DirectOptionMenu.showPopupMenu(self, event) | |
20 | self._show_cb([self.component(c) for c in self.components()]) | |
21 | ||
22 | ||
23 | @dataclass | |
9f095a28 | 24 | class BaseArgs: |
9199c6aa FC |
25 | id: ... = '' |
26 | text: ... = None | |
27 | pos: ... = None | |
28 | scale: ... = None | |
29 | wordwrap: ... = None | |
30 | texture: ... = None | |
31 | text_scale: ... = None | |
32 | font: ... = None | |
33 | color: ... = None | |
34 | ||
35 | def to_p3d_args(self): | |
36 | d = {} | |
37 | d['text'] = self.text | |
38 | d['pos'] = self.pos or (0, 1, 0) | |
39 | d['scale'] = self.scale or .12 | |
40 | d['font'] = self.font or GuiTools.load_font('assets/fonts/Hanken-Book.ttf') | |
41 | d['fg'] = self.color or (.9, .9, .9, 1) | |
42 | return d | |
43 | ||
44 | ||
45 | @dataclass | |
9f095a28 | 46 | class ButtonArgs(BaseArgs): |
9199c6aa FC |
47 | command: ... = None |
48 | command_args: ... = None | |
49 | size: ... = None | |
50 | text_color: ... = None | |
51 | relief: ... = None | |
52 | rollover_sound: ... = None | |
53 | click_sound: ... = None | |
54 | ||
55 | def to_p3d_args(self): | |
56 | d = super().to_p3d_args() | |
57 | d['frameSize'] = self.size or (-4.8, 4.8, -.6, 1.2) | |
58 | d['command'] = self.command | |
59 | d['extraArgs'] = self.command_args or [] | |
60 | d['text_fg'] = self.text_color or d.pop('fg') | |
61 | if 'fg' in d: del d['fg'] | |
62 | d['text_font'] = self.font or d.pop('font') | |
63 | d['frameColor'] = self.color or (.4, .4, .4, .14) | |
64 | d['relief'] = self.relief or FLAT | |
65 | d['rolloverSound'] = self.rollover_sound or AudioTools.load_sfx('assets/audio/sfx/rollover.ogg') | |
66 | d['clickSound'] = self.click_sound or AudioTools.load_sfx('assets/audio/sfx/click.ogg') | |
67 | d['pos'] = (self.pos[0], 1, self.pos[1]) if len(self.pos) == 2 else self.pos | |
68 | d['text_wordwrap'] = self.wordwrap | |
69 | d['frameTexture'] = self.texture | |
70 | d['text_scale'] = self.text_scale or 1 | |
71 | return d | |
72 | ||
73 | def __build_gui_args(self): | |
74 | base = { | |
75 | 'scale': .12, | |
76 | 'text_font': GuiTools.load_font('assets/fonts/Hanken-Book.ttf'), | |
77 | 'text_fg': (.9, .9, .9, 1), | |
78 | 'relief': FLAT, | |
79 | 'frameColor': (.4, .4, .4, .14), | |
80 | 'rolloverSound': AudioTools.load_sfx('assets/audio/sfx/rollover.ogg'), | |
81 | 'clickSound': AudioTools.load_sfx('assets/audio/sfx/click.ogg')} | |
82 | button = {'size': (-4.8, 4.8, -.6, 1.2)} | base | |
83 | return button | |
84 | ||
85 | ||
86 | @dataclass | |
9f095a28 | 87 | class SliderArgs(ButtonArgs): |
9199c6aa FC |
88 | range: ... = None |
89 | scale: ... = None | |
90 | value: ... = None | |
91 | ||
92 | def to_p3d_args(self): | |
93 | d = super().to_p3d_args() | |
94 | d['range'] = self.range or (0, 1) | |
95 | d['thumb_frameColor'] = (.4, .4, .4, .4) | |
96 | d['thumb_scale'] = 1.6 | |
97 | d['thumb_relief'] = d['relief'] | |
98 | d['scale'] = self.scale or .4 | |
99 | d['value'] = self.value or 0 | |
100 | del d['rolloverSound'] | |
101 | del d['clickSound'] | |
102 | del d['frameSize'] | |
103 | return d | |
104 | ||
105 | ||
106 | @dataclass | |
9f095a28 | 107 | class OptionMenuArgs(ButtonArgs): |
9199c6aa FC |
108 | items: ... = None |
109 | initial_item: ... = None | |
110 | item_color: ... = None | |
111 | popup_color: ... = None | |
112 | item_relief: ... = None | |
113 | item_text_font: ... = None | |
114 | item_text_fg: ... = None | |
115 | highlight_color: ... = None | |
116 | text_align: ... = None | |
117 | ||
118 | def to_p3d_args(self): | |
119 | d = super().to_p3d_args() | |
120 | d['items'] = self.items | |
121 | d['initialitem'] = self.initial_item | |
122 | d['item_frameColor'] = d['frameColor'] | |
123 | d['popupMarker_frameColor'] = d['frameColor'] | |
124 | d['popupMarker_relief'] = d['relief'] | |
125 | d['item_relief'] = d['relief'] | |
126 | d['item_text_font'] = d['text_font'] | |
127 | d['item_text_fg'] = d['text_fg'] | |
128 | d['textMayChange'] = 1 | |
129 | h = d['frameColor'] | |
130 | h = (h[0] + .2, h[1] + .2, h[2] + .2, h[3] + .2) | |
131 | d['highlightColor'] = self.highlight_color or h | |
132 | d['text_align'] = TextNode.A_center | |
133 | d['frameSize'] = (f:=d['frameSize'])[0], f[1] - .56, f[2], f[3] | |
134 | return d | |
135 | ||
136 | ||
137 | @dataclass | |
9f095a28 | 138 | class CheckButtonArgs(ButtonArgs): |
9199c6aa FC |
139 | value: ... = None |
140 | ||
141 | def to_p3d_args(self): | |
142 | d = super().to_p3d_args() | |
143 | h = d['frameColor'] | |
144 | h = (h[0] + .2, h[1] + .2, h[2] + .2, h[3] + .2) | |
145 | d['indicator_frameColor'] = h | |
146 | d['indicator_relief'] = d['relief'] | |
147 | d['indicatorValue'] = self.value or 0 | |
148 | return d | |
149 | ||
150 | ||
151 | @dataclass | |
9f095a28 | 152 | class TextArgs(BaseArgs): |
9199c6aa FC |
153 | align: ... = None |
154 | ||
155 | def to_p3d_args(self): | |
156 | d = super().to_p3d_args() | |
157 | if self.align: | |
158 | a = {'left': TextNode.A_left, | |
159 | 'right': TextNode.A_right, | |
160 | 'center': TextNode.A_center}[self.align] | |
161 | d['align'] = a | |
162 | return d | |
163 | ||
164 | ||
165 | class BasePage: | |
166 | ||
167 | def __init__(self, page_info): | |
168 | self.__widgets = [] | |
169 | self._page_info = page_info | |
170 | for k in list(self._page_info.test_positions.keys()): | |
171 | del self._page_info.test_positions[k] | |
172 | self._build_widgets() | |
173 | ||
174 | def _add_text(self, text_info): | |
175 | t = OnscreenText( | |
176 | **text_info.to_p3d_args()) | |
177 | self.__widgets += [t] | |
178 | return t | |
179 | ||
180 | def _add_button(self, button_args, vertically_centered=False): | |
181 | b = DirectButton(**button_args.to_p3d_args()) | |
182 | b.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {}) | |
183 | self._page_info.test_positions[button_args.id] = b.pos_pixel() | |
184 | self.__widgets += [b] | |
185 | if vertically_centered: | |
186 | for j in range(4): | |
187 | tnode = b.component('text%s' % j).textNode | |
188 | height = - tnode.getLineHeight() / 2 | |
189 | height += (tnode.get_height() - tnode.get_line_height()) / 2 | |
190 | b.component('text%s' % j).set_pos(0, 0, height) | |
191 | return b | |
192 | ||
193 | def _add_check_button(self, button_args): | |
194 | b = DirectCheckButton(**button_args.to_p3d_args()) | |
195 | b.__class__ = type('DirectCheckButtonMixed', (DirectCheckButton, DirectGuiMixin), {}) | |
196 | self.__widgets += [b] | |
197 | self._page_info.test_positions[button_args.id] = b.pos_pixel() | |
198 | return b | |
199 | ||
200 | def _add_option_menu(self, option_args, cb): | |
201 | o = DirectOptionMenuTestable(**option_args.to_p3d_args()) | |
202 | o.__class__ = type('DirectOptionMenuMixed', (DirectOptionMenu, DirectGuiMixin), {}) | |
203 | o._show_cb = cb | |
204 | o.popupMenu['frameColor'] = option_args.to_p3d_args()['frameColor'] | |
205 | o.popupMenu['relief'] = option_args.to_p3d_args()['relief'] | |
206 | self.__widgets += [o] | |
207 | self._page_info.test_positions[option_args.id] = o.pos_pixel() | |
208 | return o | |
209 | ||
210 | def _add_slider(self, slider_args): | |
211 | s = DirectSlider(**slider_args.to_p3d_args()) | |
212 | s.__class__ = type('DirectSliderMixed', (DirectSlider, DirectGuiMixin), {}) | |
213 | self._page_info.test_positions['volume'] = s.pos_pixel() | |
214 | np_left = GfxTools.build_empty_node('left_slider') | |
215 | np_left.set_pos(s.get_net_transform().get_pos()) | |
216 | np_left.set_x(np_left.get_x() - s.get_scale()[0]) | |
217 | lpos = np_left.pos_as_widget() # try with pos2d_pixel and remove pos_as_widget if ok | |
218 | self.__widgets += [s] | |
219 | self._page_info.test_positions['volume_0'] = lpos | |
220 | return s | |
221 | ||
222 | def _set_page(self, page_name): | |
223 | self._page_info.set_page(page_name) | |
224 | self.destroy() | |
225 | ||
226 | def on_back(self): | |
227 | self._set_page('main') | |
228 | ||
229 | def _rearrange_buttons_width(self): | |
230 | max_width = 0 | |
231 | for w in self.__widgets: | |
232 | t = w.component('text0') | |
233 | ul = t.textNode.get_upper_left_3d() | |
234 | lr = t.textNode.get_lower_right_3d() | |
235 | max_width = max(lr[0] - ul[0], max_width) | |
236 | for w in self.__widgets: | |
237 | m_w = max_width / 2 + .8 | |
238 | w['frameSize'] = -m_w, m_w, w['frameSize'][2], w['frameSize'][3] | |
239 | ||
240 | def destroy(self): | |
241 | for w in self.__widgets: w.destroy() | |
242 | self._page_info = None | |
243 | self.__widgets = [] |