--- /dev/null
+from copy import deepcopy
+from json import dumps
+import hashlib
+from panda3d.core import Texture, TextNode
+from direct.gui.OnscreenImage import OnscreenImage
+from direct.gui.DirectGui import DirectButton, DirectFrame, DirectEntry, YesNoDialog
+from direct.gui.DirectGuiGlobals import FLAT, NORMAL
+from direct.gui.OnscreenText import OnscreenText
+
+
+class SceneEditor:
+
+ def __init__(self, json, json_name):
+ self.__json = json
+ self.__json_name = json_name
+ self._font = base.loader.load_font(
+ 'assets/fonts/Hanken-Book.ttf')
+ self._font.clear()
+ self._font.set_pixels_per_unit(60)
+ self._font.set_minfilter(Texture.FTLinearMipmapLinear)
+ self._font.set_outline((0, 0, 0, 1), .8, .2)
+ self._common = {
+ 'scale': .046,
+ 'text_font': self._font,
+ 'text_fg': (.9, .9, .9, 1),
+ 'relief': FLAT,
+ 'frameColor': (.4, .4, .4, .14),
+ 'rolloverSound': loader.load_sfx(
+ 'assets/audio/sfx/rollover.ogg'),
+ 'clickSound': loader.load_sfx(
+ 'assets/audio/sfx/click.ogg')}
+ w, h, tw, l = 1.8, .9, 30, .36
+ self._frm = DirectFrame(frameColor=(.4, .4, .4, .06),
+ frameSize=(0, w, 0, h),
+ parent=base.a2dBottomCenter,
+ pos=(-w/2, 0, 0))
+ OnscreenText(
+ _('Name'), pos=(l - .03, h - .1), parent=self._frm,
+ font=self._common['text_font'],
+ scale=self._common['scale'],
+ fg=self._common['text_fg'],
+ align=TextNode.A_right)
+ self.__name_entry = DirectEntry(
+ scale=self._common['scale'],
+ pos=(l, 1, h - .1),
+ entryFont=self._font,
+ width=tw,
+ frameColor=self._common['frameColor'],
+ initialText=json['name'],
+ parent=self._frm,
+ text_fg=self._common['text_fg'])
+ OnscreenText(
+ _('Description'), pos=(l - .03, h - .2), parent=self._frm,
+ font=self._common['text_font'],
+ scale=self._common['scale'],
+ fg=self._common['text_fg'],
+ align=TextNode.A_right)
+ def add_line_break(txt, entry):
+ curpos = entry.node().getCursorPosition()
+ entry.set(txt[:curpos]+ "\n" + txt[curpos:])
+ entry.node().setCursorPosition(curpos+1)
+ entry['focus']=1
+ self.__instructions_entry = DirectEntry(
+ scale=self._common['scale'],
+ pos=(l, 1, h - .2),
+ entryFont=self._font,
+ width=tw,
+ numLines=12,
+ cursorKeys=True,
+ frameColor=self._common['frameColor'],
+ initialText=json['instructions'].replace('\\n', '\n'),
+ parent=self._frm,
+ text_fg=self._common['text_fg'])
+ self.__instructions_entry['command'] = add_line_break
+ self.__instructions_entry['extraArgs'] = [self.__instructions_entry]
+ def load_images_btn(path, col):
+ colors = {
+ 'gray': [
+ (.6, .6, .6, 1), # ready
+ (1, 1, 1, 1), # press
+ (.8, .8, .8, 1), # rollover
+ (.4, .4, .4, .4)],
+ 'green': [
+ (.1, .68, .1, 1),
+ (.1, 1, .1, 1),
+ (.1, .84, .1, 1),
+ (.4, .1, .1, .4)]}[col]
+ return [self.__load_img_btn(path, col) for col in colors]
+ fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
+ btn = DirectButton(
+ image=load_images_btn('exitRight', 'gray'), scale=.05,
+ pos=(.06, 1, .06),
+ parent=self._frm, command=self.__on_close, state=NORMAL, relief=FLAT,
+ frameColor=fcols[0],
+ rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
+ clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
+ btn = DirectButton(
+ image=load_images_btn('save', 'gray'), scale=.05,
+ pos=(.06, 1, .18),
+ parent=self._frm, command=self.__on_save, state=NORMAL, relief=FLAT,
+ frameColor=fcols[0],
+ rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
+ clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
+
+ def __on_close(self):
+ self.__json['name'] = self.__name_entry.get()
+ self.__json['instructions'] = self.__instructions_entry.get()
+ if self.__compute_hash() == self.__json['version']:
+ self._frm.destroy()
+ else:
+ self.__dialog = YesNoDialog(dialogName='Unsaved changes',
+ text=_('You have unsaved changes. Really quit?'),
+ command=self.__actually_close)
+
+ def __actually_close(self, arg):
+ if arg:
+ self._frm.destroy()
+ self.__dialog.cleanup()
+
+ def __on_save(self):
+ self.__json['name'] = self.__name_entry.get()
+ self.__json['instructions'] = self.__instructions_entry.get()
+ self.__json['version'] = self.__compute_hash()
+ with open('assets/scenes/%s.json' % self.__json_name, 'w') as f:
+ f.write(dumps(self.__json, indent=2, sort_keys=True))
+
+ def __load_img_btn(self, path, col):
+ img = OnscreenImage('assets/images/buttons/%s.dds' % path)
+ img.set_transparency(True)
+ img.set_color(col)
+ img.detach_node()
+ return img
+
+ def __compute_hash(self):
+ new_dict = deepcopy(self.__json)
+ del new_dict['version']
+ new_dict_str = str(dumps(new_dict, indent=2, sort_keys=True))
+ h = hashlib.new('sha256')
+ h.update(new_dict_str.encode())
+ return h.hexdigest()[:12]