ya2 · news · projects · code · about

housekeeping: ya2.utils.gui
[pmachines.git] / pmachines / editor / inspector.py
CommitLineData
ee65fee0 1from collections import namedtuple
3466af49 2from logging import info
c48bfe58 3from panda3d.core import Texture, TextNode, LPoint3f
ee65fee0 4from direct.gui.OnscreenImage import OnscreenImage
2aeb9f68 5from direct.gui.DirectGui import DirectButton, DirectFrame, DirectEntry, DirectOptionMenu, OkDialog
ee65fee0
FC
6from direct.gui.DirectGuiGlobals import FLAT, NORMAL
7from direct.gui.OnscreenText import OnscreenText
8from direct.showbase.DirectObject import DirectObject
9f095a28 9from pmachines.items.item import FixedStrategy, StillStrategy
2aeb9f68
FC
10from pmachines.items.box import HitStrategy
11from pmachines.items.domino import DownStrategy, UpStrategy
c617fd93 12from pmachines.editor.augmented_frame import AugmentedDirectFrame
9199c6aa 13from ya2.utils.gui.base_page import DirectOptionMenuTestable
a810a9ed 14from ya2.utils.gfx import DirectGuiMixin
ee65fee0
FC
15
16
17class Inspector(DirectObject):
18
fd2a4e5d 19 def __init__(self, item, all_items, pos_mgr, strategy_items):
ee65fee0
FC
20 super().__init__()
21 self.__item = item
2aeb9f68 22 self.__all_items = all_items
3466af49 23 self.__pos_mgr = pos_mgr
ee65fee0
FC
24 self._font = base.loader.load_font(
25 'assets/fonts/Hanken-Book.ttf')
26 self._font.clear()
27 self._font.set_pixels_per_unit(60)
28 self._font.set_minfilter(Texture.FTLinearMipmapLinear)
29 self._font.set_outline((0, 0, 0, 1), .8, .2)
30 self._common = {
31 'scale': .046,
32 'text_font': self._font,
33 'text_fg': (.9, .9, .9, 1),
34 'relief': FLAT,
35 'frameColor': (.4, .4, .4, .14),
36 'rolloverSound': loader.load_sfx(
37 'assets/audio/sfx/rollover.ogg'),
38 'clickSound': loader.load_sfx(
39 'assets/audio/sfx/click.ogg')}
a810a9ed 40 tooltip_args = self._common['text_font'], self._common['scale'], self._common['text_fg']
2aeb9f68 41 w, h = .8, 1.04
c617fd93 42 self._frm = AugmentedDirectFrame(frameColor=(.4, .4, .4, .06),
c48bfe58
FC
43 frameSize=(0, w, -h, 0),
44 parent=base.a2dTopRight,
45 pos=(-w, 0, 0),
c617fd93 46 delta_drag=LPoint3f(-w, 0, -h),
3466af49
FC
47 collapse_pos=(w - .06, 1, -h + .06),
48 pos_mgr=pos_mgr,
49 frame_name='inspector')
ee65fee0
FC
50 self.__z = -.08
51 p = self.__item._np.get_pos()
52 r = self.__item._np.get_r()
53 s = self.__item._np.get_scale()[0]
54 m = self.__item._mass
55 restitution = self.__item._restitution
56 f = self.__item._friction
2aeb9f68
FC
57 _id = ''
58 if 'id' in self.__item.json:
59 _id = self.__item.json['id']
60 _strategy = ''
61 if 'strategy' in self.__item.json:
62 _strategy = self.__item.json['strategy']
63 _strategy_args = ''
64 if 'strategy_args' in self.__item.json:
7ab60451 65 _strategy_args = ' '.join(map(str, self.__item.json['strategy_args']))
3466af49
FC
66 t, pos_entry = self.__add_row('position', _('position'), f'{round(p.x, 3)} {round(p.z, 3)}', self.on_edit_position, _('position (e.g. 0.1 2.3 4.5)'))
67 t, rot_entry = self.__add_row('roll', _('roll'), f'{round(r, 3)}', self.on_edit_roll, _('roll (e.g. 90)'))
68 t, scale_entry = self.__add_row('scale', _('scale'), f'{round(s, 3)}', self.on_edit_scale, _('scale (e.g. 1.2)'))
69 t, mass_entry = self.__add_row('mass', _('mass'), f'{round(m, 3)}', self.on_edit_mass, _('mass (default 1; 0 if fixed)'))
70 t, restitution_entry = self.__add_row('restitution', _('restitution'), f'{round(restitution, 3)}', self.on_edit_restitution, _('restitution (default 0.5)'))
71 t, friction_entry = self.__add_row('friction', _('friction'), f'{round(f, 3)}', self.on_edit_friction, _('friction (default 0.5)'))
72 t, id_entry = self.__add_row('id', _('id'), _id, self.on_edit_id, _('id of the item (for the strategies)'))
fd2a4e5d
FC
73 # item_modules = glob('pmachines/items/*.py')
74 # item_modules = [basename(i)[:-3] for i in item_modules]
75 # strategy_items = ['']
76 # for item_module in item_modules:
77 # mod_name = 'pmachines.items.' + item_module
78 # for member in import_module(mod_name).__dict__.values():
79 # if isclass(member) and issubclass(member, ItemStrategy) and \
80 # member != ItemStrategy:
81 # strategy_items = list(set(strategy_items + [member.__name__]))
82 strategy_names = [s.__name__ for s in strategy_items]
83 t, strategy_entry = self.__add_row_option(_('strategy'), _strategy, strategy_names, self.on_edit_strategy, _('the strategy of the item'))
3466af49
FC
84
85 def strategy_set(comps):
fd2a4e5d 86 strategy_labels = [f'inspector_strategy_{i.lower()}' for i in strategy_names]
3466af49
FC
87 for i in strategy_labels:
88 if i in self.__pos_mgr:
89 del self.__pos_mgr[i]
90 for l, b in zip(strategy_labels, comps):
91 b.__class__ = type('DirectFrameMixed', (DirectFrame, DirectGuiMixin), {})
92 p = b.pos_pixel()
93 self.__pos_mgr[l] = (p[0] + 5, p[1])
94 strategy_entry._show_cb = strategy_set
95 p = strategy_entry.pos_pixel()
96 self.__pos_mgr['editor_inspector_strategy'] = (p[0] + 5, p[1])
97
98 t, strategy_args_entry = self.__add_row('strategy_args', _('strategy_args'), _strategy_args, self.on_edit_strategy_args, _('the arguments of the strategy'))
2aeb9f68 99 fields = ['position', 'roll', 'scale', 'mass', 'restitution', 'friction', 'id', 'strategy', 'strategy_args']
ee65fee0 100 Entries = namedtuple('Entries', fields)
2aeb9f68 101 self.__entries = Entries(pos_entry, rot_entry, scale_entry, mass_entry, restitution_entry, friction_entry, id_entry, strategy_entry, strategy_args_entry)
ee65fee0
FC
102 def load_images_btn(path, col):
103 colors = {
104 'gray': [
105 (.6, .6, .6, 1), # ready
106 (1, 1, 1, 1), # press
107 (.8, .8, .8, 1), # rollover
108 (.4, .4, .4, .4)],
109 'green': [
110 (.1, .68, .1, 1),
111 (.1, 1, .1, 1),
112 (.1, .84, .1, 1),
113 (.4, .1, .1, .4)]}[col]
114 return [self.__load_img_btn(path, col) for col in colors]
115 fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
a810a9ed 116 b = DirectButton(
ee65fee0
FC
117 image=load_images_btn('exitRight', 'gray'), scale=.05,
118 pos=(.06, 1, -h + .06),
119 parent=self._frm, command=self.destroy, state=NORMAL, relief=FLAT,
120 frameColor=fcols[0],
121 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
122 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
a810a9ed 123 b.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {})
3466af49 124 pos_mgr['editor_inspector_close'] = b.pos_pixel()
a810a9ed 125 b.set_tooltip(_('Close'), *tooltip_args)
ee65fee0 126 self.accept('item-rototranslated', self.__on_item_rototranslated)
a810a9ed 127 b = DirectButton(
2aeb9f68
FC
128 image=load_images_btn('trashcan', 'gray'), scale=.05,
129 pos=(.18, 1, -h + .06),
130 parent=self._frm, command=self.__delete_item, state=NORMAL, relief=FLAT,
131 frameColor=fcols[0],
132 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
133 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
a810a9ed 134 b.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {})
3466af49 135 pos_mgr['editor_inspector_delete'] = b.pos_pixel()
a810a9ed 136 b.set_tooltip(_('Delete the item'), *tooltip_args)
ee65fee0 137
3466af49 138 def __add_row(self, id_, label, text, callback, tooltip):
ee65fee0 139 tw = 10
a810a9ed 140 tooltip_args = self._common['text_font'], self._common['scale'], self._common['text_fg']
ee65fee0
FC
141 t = OnscreenText(
142 label,
143 pos=(.03, self.__z), parent=self._frm,
144 font=self._common['text_font'],
145 scale=self._common['scale'],
146 fg=self._common['text_fg'],
147 wordwrap=20, align=TextNode.ALeft)
148 e = DirectEntry(
149 scale=self._common['scale'],
150 pos=(.30, 1, self.__z),
151 entryFont=self._font,
152 width=tw,
153 cursorKeys=True,
154 frameColor=self._common['frameColor'],
155 initialText=text,
156 parent=self._frm,
157 text_fg=self._common['text_fg'],
158 command=callback)
a810a9ed
FC
159 e.__class__ = type('DirectEntryMixed', (DirectEntry, DirectGuiMixin), {})
160 e.set_tooltip(tooltip, *tooltip_args)
3466af49 161 self.__pos_mgr[f'editor_inspector_{id_}'] = e.pos_pixel()
ee65fee0
FC
162 self.__z -= .1
163 return t, e
164
3466af49 165 def __add_row_option(self, label, text, items, callback, tooltip):
a810a9ed 166 tooltip_args = self._common['text_font'], self._common['scale'], self._common['text_fg']
2aeb9f68
FC
167 t = OnscreenText(
168 label,
169 pos=(.03, self.__z), parent=self._frm,
170 font=self._common['text_font'],
171 scale=self._common['scale'],
172 fg=self._common['text_fg'],
173 wordwrap=20, align=TextNode.ALeft)
3466af49 174 e = DirectOptionMenuTestable(
2aeb9f68
FC
175 scale=self._common['scale'],
176 initialitem=text,
177 pos=(.30, 1, self.__z),
3466af49 178 items=items,
2aeb9f68
FC
179 parent=self._frm,
180 command=callback,
181 state=NORMAL,
182 relief=FLAT,
183 item_relief=FLAT,
184 frameColor=self._common['frameColor'],
185 item_frameColor=self._common['frameColor'],
186 popupMenu_frameColor=self._common['frameColor'],
187 popupMarker_frameColor=self._common['frameColor'],
188 text_font=self._font,
189 text_fg=self._common['text_fg'],
190 highlightColor=(.9, .9, .9, .9),
191 item_text_font=self._font,
192 item_text_fg=self._common['text_fg'],
193 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
194 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
a810a9ed
FC
195 e.__class__ = type('DirectOptionMenuMixed', (DirectOptionMenu, DirectGuiMixin), {})
196 e.set_tooltip(tooltip, *tooltip_args)
2aeb9f68
FC
197 self.__z -= .1
198 return t, e
199
ee65fee0
FC
200 def __load_img_btn(self, path, col):
201 img = OnscreenImage('assets/images/buttons/%s.dds' % path)
202 img.set_transparency(True)
203 img.set_color(col)
204 img.detach_node()
205 return img
206
207 def __on_item_rototranslated(self, np):
208 pos = np.get_pos()
209 r = np.get_r()
210 self.__entries.position.set('%s %s' % (str(round(pos.x, 3)), str(round(pos.z, 3))))
211 self.__entries.roll.set('%s' % str(round(r, 3)))
2aeb9f68
FC
212 self.__item.json['position'] = list(pos)
213 self.__item.json['roll'] = round(r, 3)
214
215 def __delete_item(self):
216 messenger.send('editor-inspector-delete', [self.__item])
217 self.destroy()
ee65fee0
FC
218
219 @property
220 def item(self):
221 return self.__item
222
223 def on_edit_position(self, txt):
224 x, z = map(float, txt.split())
225 self.__item.position = [x, 0, z]
226
227 def on_edit_roll(self, txt):
228 self.__item.roll = float(txt)
229
230 def on_edit_scale(self, txt):
231 self.__item.scale = float(txt)
232
233 def on_edit_mass(self, txt):
234 self.__item.mass = float(txt)
235
236 def on_edit_restitution(self, txt):
237 self.__item.restitution = float(txt)
238
239 def on_edit_friction(self, txt):
240 self.__item.friction = float(txt)
241
2aeb9f68
FC
242 def on_edit_id(self, txt):
243 self.__item.id = txt
244
245 def on_edit_strategy(self, txt):
246 if not txt:
247 self.__entries.strategy_args.set('')
248 return
249 name2class = {
250 'StillStrategy': StillStrategy,
251 'UpStrategy': UpStrategy,
252 'HitStrategy': HitStrategy,
253 'DownStrategy': DownStrategy,
254 'FixedStrategy': FixedStrategy}
255 class_ = name2class[txt]
256 args = []
257 error = False
258 if txt == 'StillStrategy':
259 args += [self.__item._np]
260 if txt in ['UpStrategy', 'DownStrategy']:
261 args += [self.__item._np]
262 try:
263 args += [float(self.__entries.strategy_args.get())]
264 except ValueError:
265 error = True
266 if txt == 'HitStrategy':
267 for item in self.__all_items:
268 if item.id == self.__entries.strategy_args.get():
269 args += [item]
270 args += [self.__item.node]
271 args += [self.__item._world]
272 if not error:
273 self.__item.strategy = class_(*args)
274 self.__item.strategy_json = txt
275 else:
276 self.__show_error_popup()
277
278 def on_edit_strategy_args(self, txt):
279 self.__item.strategy_args_json = txt
280
281 def __show_error_popup(self):
282 self.__dialog = OkDialog(dialogName='Strategy args errors',
283 text=_('There are errors in the strategy args.'),
284 command=self.__actually_close)
285 self.__dialog['frameColor'] = (.4, .4, .4, .14)
286 self.__dialog['relief'] = FLAT
287 self.__dialog.component('text0')['fg'] = (.9, .9, .9, 1)
288 self.__dialog.component('text0')['font'] = self._font
289 for b in self.__dialog.buttonList:
290 b['frameColor'] = (.4, .4, .4, .14)
291 b.component('text0')['fg'] = (.9, .9, .9, 1)
292 b.component('text0')['font'] = self._font
293 b.component('text1')['fg'] = (.9, .1, .1, 1)
294 b.component('text1')['font'] = self._font
295 b.component('text2')['fg'] = (.9, .9, .1, 1)
296 b.component('text2')['font'] = self._font
297
298 def __actually_close(self, arg):
299 self.__entries.strategy.set('')
300 self.__entries.strategy_args.set('')
301 self.__dialog.cleanup()
302
ee65fee0
FC
303 def destroy(self):
304 self._frm.destroy()
305 self.ignore('item-rototranslated')
306 messenger.send('editor-inspector-destroy')
3133e30f
FC
307
308
309class PixelSpaceInspector(DirectObject):
310
311 def __init__(self, item, all_items):
3466af49 312 info('PixelSpaceInspector')
3133e30f
FC
313 super().__init__()
314 self.__item = item
315 self.__all_items = all_items
316 self._font = base.loader.load_font(
317 'assets/fonts/Hanken-Book.ttf')
318 self._font.clear()
319 self._font.set_pixels_per_unit(60)
320 self._font.set_minfilter(Texture.FTLinearMipmapLinear)
321 self._font.set_outline((0, 0, 0, 1), .8, .2)
322 self._common = {
323 'scale': .046,
324 'text_font': self._font,
325 'text_fg': (.9, .9, .9, 1),
326 'relief': FLAT,
327 'frameColor': (.4, .4, .4, .14),
328 'rolloverSound': loader.load_sfx(
329 'assets/audio/sfx/rollover.ogg'),
330 'clickSound': loader.load_sfx(
331 'assets/audio/sfx/click.ogg')}
332 w, h = .8, .36
333 self._frm = DirectFrame(frameColor=(.4, .4, .4, .06),
334 frameSize=(0, w, -h, 0),
335 parent=base.a2dTopRight,
336 pos=(-w, 0, 0))
337 self.__z = -.08
338 p = self.__item._np.get_pos()
339 _id = ''
340 if 'id' in self.__item.json:
341 _id = self.__item.json['id']
342 t, pos_entry = self.__add_row(_('position'), f'{round(p.x, 3)}, {round(p.z, 3)}', self.on_edit_position)
343 t, id_entry = self.__add_row(_('id'), _id, self.on_edit_id)
344 fields = ['position', 'id']
345 Entries = namedtuple('Entries', fields)
346 self.__entries = Entries(pos_entry, id_entry)
347 def load_images_btn(path, col):
348 colors = {
349 'gray': [
350 (.6, .6, .6, 1), # ready
351 (1, 1, 1, 1), # press
352 (.8, .8, .8, 1), # rollover
353 (.4, .4, .4, .4)],
354 'green': [
355 (.1, .68, .1, 1),
356 (.1, 1, .1, 1),
357 (.1, .84, .1, 1),
358 (.4, .1, .1, .4)]}[col]
359 return [self.__load_img_btn(path, col) for col in colors]
360 fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
361 DirectButton(
362 image=load_images_btn('exitRight', 'gray'), scale=.05,
363 pos=(.06, 1, -h + .06),
364 parent=self._frm, command=self.destroy, state=NORMAL, relief=FLAT,
365 frameColor=fcols[0],
366 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
367 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
368 self.accept('item-rototranslated', self.__on_item_rototranslated)
369 DirectButton(
370 image=load_images_btn('trashcan', 'gray'), scale=.05,
371 pos=(.18, 1, -h + .06),
372 parent=self._frm, command=self.__delete_item, state=NORMAL, relief=FLAT,
373 frameColor=fcols[0],
374 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
375 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
376
377 def __add_row(self, label, text, callback):
378 tw = 10
379 t = OnscreenText(
380 label,
381 pos=(.03, self.__z), parent=self._frm,
382 font=self._common['text_font'],
383 scale=self._common['scale'],
384 fg=self._common['text_fg'],
385 wordwrap=20, align=TextNode.ALeft)
386 e = DirectEntry(
387 scale=self._common['scale'],
388 pos=(.30, 1, self.__z),
389 entryFont=self._font,
390 width=tw,
391 cursorKeys=True,
392 frameColor=self._common['frameColor'],
393 initialText=text,
394 parent=self._frm,
395 text_fg=self._common['text_fg'],
396 command=callback)
397 self.__z -= .1
398 return t, e
399
400 def __load_img_btn(self, path, col):
401 img = OnscreenImage('assets/images/buttons/%s.dds' % path)
402 img.set_transparency(True)
403 img.set_color(col)
404 img.detach_node()
405 return img
406
407 def __on_item_rototranslated(self, np):
bf77b5d5 408 pos = np.pos2d_pixel()
3133e30f
FC
409 self.__entries.position.set('%s %s' % (str(round(pos[0], 3)), str(round(pos[1], 3))))
410 self.__item.json['position'] = list(pos)
411
412 def __delete_item(self):
413 messenger.send('editor-inspector-delete', [self.__item])
414 self.destroy()
415
416 @property
417 def item(self):
418 return self.__item
419
420 def on_edit_position(self, txt):
421 x, z = map(float, txt.split())
422 self.__item.position = [x, 0, z]
423
424 def on_edit_id(self, txt):
425 self.__item.id = txt
426
427 def __actually_close(self, arg):
428 self.__entries.strategy.set('')
429 self.__entries.strategy_args.set('')
430 self.__dialog.cleanup()
431
432 def destroy(self):
433 self._frm.destroy()
434 self.ignore('item-rototranslated')
435 messenger.send('editor-inspector-destroy')
436
437
438class WorldSpaceInspector(DirectObject):
439
3466af49
FC
440 def __init__(self, item, all_items, pos_mgr):
441 info('WorldSpaceInspector')
3133e30f
FC
442 super().__init__()
443 self.__item = item
444 self.__all_items = all_items
3466af49 445 self.__pos_mgr = pos_mgr
3133e30f
FC
446 self._font = base.loader.load_font(
447 'assets/fonts/Hanken-Book.ttf')
448 self._font.clear()
449 self._font.set_pixels_per_unit(60)
450 self._font.set_minfilter(Texture.FTLinearMipmapLinear)
451 self._font.set_outline((0, 0, 0, 1), .8, .2)
452 self._common = {
453 'scale': .046,
454 'text_font': self._font,
455 'text_fg': (.9, .9, .9, 1),
456 'relief': FLAT,
457 'frameColor': (.4, .4, .4, .14),
458 'rolloverSound': loader.load_sfx(
459 'assets/audio/sfx/rollover.ogg'),
460 'clickSound': loader.load_sfx(
461 'assets/audio/sfx/click.ogg')}
3466af49 462 tooltip_args = self._common['text_font'], self._common['scale'], self._common['text_fg']
3133e30f
FC
463 w, h = .8, .36
464 self._frm = DirectFrame(frameColor=(.4, .4, .4, .06),
465 frameSize=(0, w, -h, 0),
466 parent=base.a2dTopRight,
467 pos=(-w, 0, 0))
468 self.__z = -.08
469 p = self.__item._np.get_pos()
470 _id = ''
471 if 'id' in self.__item.json:
472 _id = self.__item.json['id']
3466af49
FC
473 t, pos_entry = self.__add_row('position', _('position'), f'{round(p.x, 3)} {round(p.z, 3)}', self.on_edit_position, _('position (e.g. 0.1 2.3 4.5)'))
474 t, id_entry = self.__add_row('id', _('id'), _id, self.on_edit_id, _('id of the item (for the strategies)'))
3133e30f
FC
475 fields = ['position', 'id']
476 Entries = namedtuple('Entries', fields)
477 self.__entries = Entries(pos_entry, id_entry)
478 def load_images_btn(path, col):
479 colors = {
480 'gray': [
481 (.6, .6, .6, 1), # ready
482 (1, 1, 1, 1), # press
483 (.8, .8, .8, 1), # rollover
484 (.4, .4, .4, .4)],
485 'green': [
486 (.1, .68, .1, 1),
487 (.1, 1, .1, 1),
488 (.1, .84, .1, 1),
489 (.4, .1, .1, .4)]}[col]
490 return [self.__load_img_btn(path, col) for col in colors]
491 fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
3466af49 492 b = DirectButton(
3133e30f
FC
493 image=load_images_btn('exitRight', 'gray'), scale=.05,
494 pos=(.06, 1, -h + .06),
495 parent=self._frm, command=self.destroy, state=NORMAL, relief=FLAT,
496 frameColor=fcols[0],
497 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
498 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
3466af49
FC
499 b.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {})
500 pos_mgr['editor_inspector_test_close'] = b.pos_pixel()
501 b.set_tooltip(_('Close'), *tooltip_args)
3133e30f 502 self.accept('item-rototranslated', self.__on_item_rototranslated)
3466af49 503 b = DirectButton(
3133e30f
FC
504 image=load_images_btn('trashcan', 'gray'), scale=.05,
505 pos=(.18, 1, -h + .06),
506 parent=self._frm, command=self.__delete_item, state=NORMAL, relief=FLAT,
507 frameColor=fcols[0],
508 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
509 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
3466af49
FC
510 b.__class__ = type('DirectButtonMixed', (DirectButton, DirectGuiMixin), {})
511 pos_mgr['editor_inspector_test_delete'] = b.pos_pixel()
512 b.set_tooltip(_('Delete the item'), *tooltip_args)
3133e30f 513
3466af49 514 def __add_row(self, id_, label, text, callback, tooltip):
3133e30f 515 tw = 10
3466af49 516 tooltip_args = self._common['text_font'], self._common['scale'], self._common['text_fg']
3133e30f
FC
517 t = OnscreenText(
518 label,
519 pos=(.03, self.__z), parent=self._frm,
520 font=self._common['text_font'],
521 scale=self._common['scale'],
522 fg=self._common['text_fg'],
523 wordwrap=20, align=TextNode.ALeft)
524 e = DirectEntry(
525 scale=self._common['scale'],
526 pos=(.30, 1, self.__z),
527 entryFont=self._font,
528 width=tw,
529 cursorKeys=True,
530 frameColor=self._common['frameColor'],
531 initialText=text,
532 parent=self._frm,
533 text_fg=self._common['text_fg'],
534 command=callback)
3466af49
FC
535 e.__class__ = type('DirectEntryMixed', (DirectEntry, DirectGuiMixin), {})
536 e.set_tooltip(tooltip, *tooltip_args)
537 self.__pos_mgr[f'editor_inspector_test_{id_}'] = e.pos_pixel()
3133e30f
FC
538 self.__z -= .1
539 return t, e
540
541 def __load_img_btn(self, path, col):
542 img = OnscreenImage('assets/images/buttons/%s.dds' % path)
543 img.set_transparency(True)
544 img.set_color(col)
545 img.detach_node()
546 return img
547
548 def __on_item_rototranslated(self, np):
549 pos = np.get_pos()
550 self.__entries.position.set('%s %s' % (str(round(pos.x, 3)), str(round(pos.z, 3))))
551 self.__item.json['position'] = list(pos)
552
553 def __delete_item(self):
554 messenger.send('editor-inspector-delete', [self.__item])
555 self.destroy()
556
557 @property
558 def item(self):
559 return self.__item
560
561 def on_edit_position(self, txt):
562 x, z = map(float, txt.split())
563 self.__item.position = [x, 0, z]
564
565 def on_edit_id(self, txt):
566 self.__item.id = txt
567
568 def __actually_close(self, arg):
569 self.__entries.strategy.set('')
570 self.__entries.strategy_args.set('')
571 self.__dialog.cleanup()
572
573 def destroy(self):
574 self._frm.destroy()
575 self.ignore('item-rototranslated')
576 messenger.send('editor-inspector-destroy')