ya2 · news · projects · code · about

fixes for building
[pmachines.git] / pmachines / editor / start_items.py
1 from collections import namedtuple
2 from glob import glob
3 from importlib import import_module
4 from os.path import basename
5 from inspect import isclass
6 from panda3d.core import Texture, TextNode, LPoint3f
7 from direct.gui.OnscreenImage import OnscreenImage
8 from direct.gui.DirectGui import DirectButton, DirectEntry, DirectOptionMenu, OkDialog, DirectFrame
9 from direct.gui.DirectGuiGlobals import FLAT, NORMAL
10 from direct.gui.OnscreenText import OnscreenText
11 from direct.showbase.DirectObject import DirectObject
12 from ya2.utils.gfx import DirectGuiMixin
13 from pmachines.items.item import Item, ItemStrategy
14 from pmachines.editor.augmented_frame import AugmentedDirectFrame
15 from ya2.utils.gui.base_page import DirectOptionMenuTestable
16
17
18 class StartItems(DirectObject):
19
20 def __init__(self, json_items, pos_mgr, item_classes, strategy_items):
21 super().__init__()
22 self.__items = json_items
23 self.__json = self.__items[0]
24 self.__pos_mgr = pos_mgr
25 self._font = base.loader.load_font(
26 'assets/fonts/Hanken-Book.ttf')
27 self._font.clear()
28 self._font.set_pixels_per_unit(60)
29 self._font.set_minfilter(Texture.FTLinearMipmapLinear)
30 self._font.set_outline((0, 0, 0, 1), .8, .2)
31 self._common = {
32 'scale': .046,
33 'text_font': self._font,
34 'text_fg': (.9, .9, .9, 1),
35 'relief': FLAT,
36 'frameColor': (.4, .4, .4, .14),
37 'rolloverSound': loader.load_sfx(
38 'assets/audio/sfx/rollover.ogg'),
39 'clickSound': loader.load_sfx(
40 'assets/audio/sfx/click.ogg')}
41 tooltip_args = self._common['text_font'], self._common['scale'], self._common['text_fg']
42 w, h = .8, 1.04
43 self._frm = AugmentedDirectFrame(frameColor=(.4, .4, .4, .06),
44 frameSize=(0, w, -h, 0),
45 parent=base.a2dTopLeft,
46 pos=(0, 0, 0),
47 delta_drag=LPoint3f(w, 0, -h),
48 collapse_pos=(w - .06, 1, -h + .06),
49 pos_mgr=pos_mgr,
50 frame_name='start')
51 self.__z = -.08
52 # item_modules = glob('pmachines/items/*.py')
53 # item_modules = [basename(i)[:-3] for i in item_modules]
54 # new_items = ['']
55 # for item_module in item_modules:
56 # mod_name = 'pmachines.items.' + item_module
57 # for member in import_module(mod_name).__dict__.values():
58 # if isclass(member) and issubclass(member, Item) and \
59 # member != Item:
60 # new_items = list(set(new_items + [member.__name__]))
61 item_names = [i.__name__ for i in item_classes]
62 t, item_class_entry = self.__add_row_option(_('class'), '', item_names, self.on_edit_class, _('class of the item'))
63
64 def item_class_set(comps):
65 class_labels = [f'start_class_{i.lower()}' for i in item_names]
66 for i in class_labels:
67 if i in self.__pos_mgr:
68 del self.__pos_mgr[i]
69 for l, b in zip(class_labels, comps):
70 b.__class__ = type('DirectFrameMixed', (DirectFrame, DirectGuiMixin), {})
71 p = b.pos_pixel()
72 self.__pos_mgr[l] = (p[0] + 5, p[1])
73 item_class_entry._show_cb = item_class_set
74 self.__pos_mgr['editor_start_class'] = item_class_entry.pos_pixel()
75
76 t, count_entry = self.__add_row('count', _('count'), '', self.on_edit_count, _('number of the items'))
77 t, scale_entry = self.__add_row('scale', _('scale'), '', self.on_edit_scale, _('scale (e.g. 1.2)'))
78 t, mass_entry = self.__add_row('mass', _('mass'), '', self.on_edit_mass, _('mass (default 1)'))
79 t, restitution_entry = self.__add_row('restitution', _('restitution'), '', self.on_edit_restitution, _('restitution (default 0.5)'))
80 t, friction_entry = self.__add_row('friction', _('friction'), '', self.on_edit_friction, _('friction (default 0.5)'))
81 t, id_entry = self.__add_row('id', _('id'), '', self.on_edit_id, _('id'))
82 # strategy_items = ['']
83 # for item_module in item_modules:
84 # mod_name = 'pmachines.items.' + item_module
85 # for member in import_module(mod_name).__dict__.values():
86 # if isclass(member) and issubclass(member, ItemStrategy) and \
87 # member != ItemStrategy:
88 # strategy_items = list(set(strategy_items + [member.__name__]))
89 strategy_names = [s.__name__ for s in strategy_items]
90 t, strategy_entry = self.__add_row_option(_('strategy'), '', strategy_names, self.on_edit_strategy, _('the strategy of the item'))
91
92 def strategy_set(comps):
93 strategy_labels = [f'start_strategy_{i.lower()}' for i in strategy_names]
94 for i in strategy_labels:
95 if i in self.__pos_mgr:
96 del self.__pos_mgr[i]
97 for l, b in zip(strategy_labels, comps):
98 b.__class__ = type('DirectFrameMixed', (DirectFrame, DirectGuiMixin), {})
99 p = b.pos_pixel()
100 self.__pos_mgr[l] = (p[0] + 5, p[1])
101 strategy_entry._show_cb = strategy_set
102 p = strategy_entry.pos_pixel()
103 self.__pos_mgr['editor_start_strategy'] = (p[0] + 5, p[1])
104
105 t, strategy_args_entry = self.__add_row('strategy_args', _('strategy_args'), '', self.on_edit_strategy_args, _('the arguments of the strategy'))
106 fields = ['scale', 'mass', 'restitution', 'friction', 'id', 'strategy', 'strategy_args', 'item_class', 'count']
107 Entries = namedtuple('Entries', fields)
108 self.__entries = Entries(scale_entry, mass_entry, restitution_entry, friction_entry, id_entry, strategy_entry, strategy_args_entry, item_class_entry, count_entry)
109 self.__set(self.__json)
110 def load_images_btn(path, col):
111 colors = {
112 'gray': [
113 (.6, .6, .6, 1), # ready
114 (1, 1, 1, 1), # press
115 (.8, .8, .8, 1), # rollover
116 (.4, .4, .4, .4)],
117 'green': [
118 (.1, .68, .1, 1),
119 (.1, 1, .1, 1),
120 (.1, .84, .1, 1),
121 (.4, .1, .1, .4)]}[col]
122 return [self.__load_img_btn(path, col) for col in colors]
123 fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
124 b = DirectButton(
125 image=load_images_btn('exitRight', 'gray'), scale=.05,
126 pos=(.54, 1, -h + .06),
127 parent=self._frm, command=self.destroy, state=NORMAL, relief=FLAT,
128 frameColor=fcols[0],
129 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
130 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
131 b.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {})
132 pos_mgr['editor_start_close'] = b.pos_pixel()
133 b.set_tooltip(_('Close'), *tooltip_args)
134 b = DirectButton(
135 image=load_images_btn('save', 'gray'), scale=.05,
136 pos=(.42, 1, -h + .06),
137 parent=self._frm, command=self.__save, state=NORMAL, relief=FLAT,
138 frameColor=fcols[0],
139 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
140 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
141 b.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {})
142 pos_mgr['editor_start_save'] = b.pos_pixel()
143 b.set_tooltip(_('Save'), *tooltip_args)
144 b = DirectButton(
145 image=load_images_btn('trashcan', 'gray'), scale=.05,
146 pos=(.3, 1, -h + .06),
147 parent=self._frm, command=self.__delete_item, state=NORMAL, relief=FLAT,
148 frameColor=fcols[0],
149 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
150 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
151 b.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {})
152 pos_mgr['editor_start_delete'] = b.pos_pixel()
153 b.set_tooltip(_('Delete'), *tooltip_args)
154 b = DirectButton(
155 image=load_images_btn('plus', 'gray'), scale=.05,
156 pos=(.06, 1, -h + .06),
157 parent=self._frm, command=self.__new_item, state=NORMAL, relief=FLAT,
158 frameColor=fcols[0],
159 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
160 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
161 b.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {})
162 pos_mgr['editor_start_new'] = b.pos_pixel()
163 b.set_tooltip(_('New'), *tooltip_args)
164 b = DirectButton(
165 image=load_images_btn('right', 'gray'), scale=.05,
166 pos=(.18, 1, -h + .06),
167 parent=self._frm, command=self.__next_item, state=NORMAL, relief=FLAT,
168 frameColor=fcols[0],
169 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
170 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
171 b.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {})
172 pos_mgr['editor_start_next'] = b.pos_pixel()
173 b.set_tooltip(_('Next'), *tooltip_args)
174
175 def __add_row(self, id_, label, text, callback, tooltip):
176 tw = 10
177 tooltip_args = self._common['text_font'], self._common['scale'], self._common['text_fg']
178 t = OnscreenText(
179 label,
180 pos=(.03, self.__z), parent=self._frm,
181 font=self._common['text_font'],
182 scale=self._common['scale'],
183 fg=self._common['text_fg'],
184 wordwrap=20, align=TextNode.ALeft)
185 e = DirectEntry(
186 scale=self._common['scale'],
187 pos=(.30, 1, self.__z),
188 entryFont=self._font,
189 width=tw,
190 cursorKeys=True,
191 frameColor=self._common['frameColor'],
192 initialText=text,
193 parent=self._frm,
194 text_fg=self._common['text_fg'],
195 command=callback)
196 e.__class__ = type('DirectEntryMixed', (DirectEntry, DirectGuiMixin), {})
197 e.set_tooltip(tooltip, *tooltip_args)
198 self.__pos_mgr[f'editor_start_{id_}'] = e.pos_pixel()
199 self.__z -= .1
200 return t, e
201
202 def __add_row_option(self, label, text, items, callback, tooltip):
203 tooltip_args = self._common['text_font'], self._common['scale'], self._common['text_fg']
204 t = OnscreenText(
205 label,
206 pos=(.03, self.__z), parent=self._frm,
207 font=self._common['text_font'],
208 scale=self._common['scale'],
209 fg=self._common['text_fg'],
210 wordwrap=20, align=TextNode.ALeft)
211 e = DirectOptionMenuTestable(
212 scale=self._common['scale'],
213 initialitem=text,
214 pos=(.30, 1, self.__z),
215 items=items,
216 parent=self._frm,
217 command=callback,
218 state=NORMAL,
219 relief=FLAT,
220 item_relief=FLAT,
221 frameColor=self._common['frameColor'],
222 item_frameColor=self._common['frameColor'],
223 popupMenu_frameColor=self._common['frameColor'],
224 popupMarker_frameColor=self._common['frameColor'],
225 text_font=self._font,
226 text_fg=self._common['text_fg'],
227 highlightColor=(.9, .9, .9, .9),
228 item_text_font=self._font,
229 item_text_fg=self._common['text_fg'],
230 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
231 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
232 e.__class__ = type('DirectOptionMenuMixed', (DirectOptionMenu, DirectGuiMixin), {})
233 e.set_tooltip(tooltip, *tooltip_args)
234 self.__z -= .1
235 return t, e
236
237 def __load_img_btn(self, path, col):
238 img = OnscreenImage('assets/images/buttons/%s.dds' % path)
239 img.set_transparency(True)
240 img.set_color(col)
241 img.detach_node()
242 return img
243
244 def on_edit_scale(self, txt):
245 if txt:
246 self.__json['model_scale'] = float(txt)
247 else:
248 del self.__json['model_scale']
249
250 def on_edit_mass(self, txt):
251 if txt:
252 self.__json['mass'] = float(txt)
253 else:
254 del self.__json['mass']
255
256 def on_edit_restitution(self, txt):
257 if txt:
258 self.__json['restitution'] = float(txt)
259 else:
260 del self.__json['restitution']
261
262 def on_edit_friction(self, txt):
263 if txt:
264 self.__json['friction'] = float(txt)
265 else:
266 del self.__json['friction']
267
268 def on_edit_id(self, txt):
269 if txt:
270 self.__json['id'] = txt
271 else:
272 del self.__json['id']
273
274 def on_edit_strategy(self, txt):
275 if txt:
276 self.__json['strategy'] = txt
277 self.__entries.strategy_args.set('')
278
279 def on_edit_strategy_args(self, txt):
280 if txt:
281 self.__json['strategy_args'] = txt
282 else:
283 del self.__json['strategy_args']
284
285 def on_edit_class(self, txt):
286 if txt:
287 self.__json['class'] = txt
288
289 def on_edit_count(self, txt):
290 if txt:
291 self.__json['count'] = int(txt)
292 else:
293 del self.__json['count']
294
295 def __new_item(self):
296 curr_index = self.__items.index(self.__json)
297 self.__json = {}
298 curr_index = (curr_index + 1) % len(self.__items)
299 self.__items.insert(curr_index, self.__json)
300 self.__set(self.__json)
301 import pprint
302 pprint.pprint(self.__items)
303
304 def __next_item(self):
305 curr_index = self.__items.index(self.__json)
306 self.__json = self.__items[(curr_index + 1) % len(self.__items)]
307 self.__set(self.__json)
308 import pprint
309 pprint.pprint(self.__items)
310
311 def __delete_item(self):
312 curr_index = self.__items.index(self.__json)
313 if curr_index == len(self.__items): curr_index = 0
314 self.__items.remove(self.__json)
315 if not self.__items:
316 self.__items = [{}]
317 self.__json = self.__items[curr_index]
318 self.__set(self.__json)
319 import pprint
320 pprint.pprint(self.__items)
321
322 def __set(self, json):
323 if 'model_scale' in json:
324 self.__entries.scale.set(str(json['model_scale']))
325 else:
326 self.__entries.scale.set('')
327 if 'mass' in json:
328 self.__entries.mass.set(str(json['mass']))
329 else:
330 self.__entries.mass.set('')
331 if 'restitution' in json:
332 self.__entries.restitution.set(str(json['restitution']))
333 else:
334 self.__entries.restitution.set('')
335 if 'friction' in json:
336 self.__entries.friction.set(str(json['friction']))
337 else:
338 self.__entries.friction.set('')
339 if 'id' in json:
340 self.__entries.id.set(str(json['id']))
341 else:
342 self.__entries.id.set('')
343 if 'strategy' in json:
344 self.__entries.strategy.set(str(json['strategy']))
345 else:
346 self.__entries.strategy.set('')
347 if 'strategy_args' in json:
348 self.__entries.strategy_args.set(str(json['strategy_args']))
349 else:
350 self.__entries.strategy_args.set('')
351 if 'class' in json:
352 self.__entries.item_class.set(str(json['class']))
353 else:
354 self.__entries.item_class.set('')
355 if 'count' in json:
356 self.__entries.count.set(str(json['count']))
357 else:
358 self.__entries.count.set('')
359 import pprint
360 pprint.pprint(self.__items)
361
362 def __save(self):
363 messenger.send('editor-start-items-save', [self.__items])
364
365 def __show_error_popup(self):
366 self.__dialog = OkDialog(dialogName='Strategy args errors',
367 text=_('There are errors in the strategy args.'),
368 command=self.__actually_close)
369 self.__dialog['frameColor'] = (.4, .4, .4, .14)
370 self.__dialog['relief'] = FLAT
371 self.__dialog.component('text0')['fg'] = (.9, .9, .9, 1)
372 self.__dialog.component('text0')['font'] = self._font
373 for b in self.__dialog.buttonList:
374 b['frameColor'] = (.4, .4, .4, .14)
375 b.component('text0')['fg'] = (.9, .9, .9, 1)
376 b.component('text0')['font'] = self._font
377 b.component('text1')['fg'] = (.9, .1, .1, 1)
378 b.component('text1')['font'] = self._font
379 b.component('text2')['fg'] = (.9, .9, .1, 1)
380 b.component('text2')['font'] = self._font
381
382 def __actually_close(self, arg):
383 self.__entries.strategy.set('')
384 self.__entries.strategy_args.set('')
385 self.__dialog.cleanup()
386
387 def destroy(self):
388 self._frm.destroy()
389 messenger.send('editor-start-items-destroy')