ya2 · news · projects · code · about

inspector
[pmachines.git] / pmachines / editor / scene.py
CommitLineData
d3a2e50a
FC
1from copy import deepcopy
2from json import dumps
3import hashlib
4from panda3d.core import Texture, TextNode
5from direct.gui.OnscreenImage import OnscreenImage
6from direct.gui.DirectGui import DirectButton, DirectFrame, DirectEntry, YesNoDialog
7from direct.gui.DirectGuiGlobals import FLAT, NORMAL
8from direct.gui.OnscreenText import OnscreenText
ee65fee0 9from direct.showbase.DirectObject import DirectObject
012cf969 10from pmachines.editor.scene_list import SceneList
ee65fee0 11from pmachines.editor.inspector import Inspector
d3a2e50a
FC
12
13
ee65fee0 14class SceneEditor(DirectObject):
d3a2e50a
FC
15
16 def __init__(self, json, json_name):
ee65fee0 17 super().__init__()
d3a2e50a
FC
18 self.__json = json
19 self.__json_name = json_name
ee65fee0 20 self.__inspector = None
d3a2e50a
FC
21 self._font = base.loader.load_font(
22 'assets/fonts/Hanken-Book.ttf')
23 self._font.clear()
24 self._font.set_pixels_per_unit(60)
25 self._font.set_minfilter(Texture.FTLinearMipmapLinear)
26 self._font.set_outline((0, 0, 0, 1), .8, .2)
27 self._common = {
28 'scale': .046,
29 'text_font': self._font,
30 'text_fg': (.9, .9, .9, 1),
31 'relief': FLAT,
32 'frameColor': (.4, .4, .4, .14),
33 'rolloverSound': loader.load_sfx(
34 'assets/audio/sfx/rollover.ogg'),
35 'clickSound': loader.load_sfx(
36 'assets/audio/sfx/click.ogg')}
37 w, h, tw, l = 1.8, .9, 30, .36
38 self._frm = DirectFrame(frameColor=(.4, .4, .4, .06),
39 frameSize=(0, w, 0, h),
40 parent=base.a2dBottomCenter,
41 pos=(-w/2, 0, 0))
42 OnscreenText(
43 _('Name'), pos=(l - .03, h - .1), parent=self._frm,
44 font=self._common['text_font'],
45 scale=self._common['scale'],
46 fg=self._common['text_fg'],
47 align=TextNode.A_right)
48 self.__name_entry = DirectEntry(
49 scale=self._common['scale'],
50 pos=(l, 1, h - .1),
51 entryFont=self._font,
52 width=tw,
53 frameColor=self._common['frameColor'],
54 initialText=json['name'],
55 parent=self._frm,
56 text_fg=self._common['text_fg'])
57 OnscreenText(
58 _('Description'), pos=(l - .03, h - .2), parent=self._frm,
59 font=self._common['text_font'],
60 scale=self._common['scale'],
61 fg=self._common['text_fg'],
62 align=TextNode.A_right)
63 def add_line_break(txt, entry):
64 curpos = entry.node().getCursorPosition()
65 entry.set(txt[:curpos]+ "\n" + txt[curpos:])
66 entry.node().setCursorPosition(curpos+1)
67 entry['focus']=1
68 self.__instructions_entry = DirectEntry(
69 scale=self._common['scale'],
70 pos=(l, 1, h - .2),
71 entryFont=self._font,
72 width=tw,
73 numLines=12,
74 cursorKeys=True,
75 frameColor=self._common['frameColor'],
76 initialText=json['instructions'].replace('\\n', '\n'),
77 parent=self._frm,
78 text_fg=self._common['text_fg'])
79 self.__instructions_entry['command'] = add_line_break
80 self.__instructions_entry['extraArgs'] = [self.__instructions_entry]
81 def load_images_btn(path, col):
82 colors = {
83 'gray': [
84 (.6, .6, .6, 1), # ready
85 (1, 1, 1, 1), # press
86 (.8, .8, .8, 1), # rollover
87 (.4, .4, .4, .4)],
88 'green': [
89 (.1, .68, .1, 1),
90 (.1, 1, .1, 1),
91 (.1, .84, .1, 1),
92 (.4, .1, .1, .4)]}[col]
93 return [self.__load_img_btn(path, col) for col in colors]
94 fcols = (.4, .4, .4, .14), (.3, .3, .3, .05)
012cf969 95 DirectButton(
d3a2e50a
FC
96 image=load_images_btn('exitRight', 'gray'), scale=.05,
97 pos=(.06, 1, .06),
98 parent=self._frm, command=self.__on_close, state=NORMAL, relief=FLAT,
99 frameColor=fcols[0],
100 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
101 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
012cf969 102 DirectButton(
d3a2e50a
FC
103 image=load_images_btn('save', 'gray'), scale=.05,
104 pos=(.06, 1, .18),
105 parent=self._frm, command=self.__on_save, state=NORMAL, relief=FLAT,
106 frameColor=fcols[0],
107 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
108 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
012cf969
FC
109 DirectButton(
110 image=load_images_btn('menuList', 'gray'), scale=.05,
111 pos=(.06, 1, .30),
112 parent=self._frm, command=self.__on_scene_list, state=NORMAL, relief=FLAT,
113 frameColor=fcols[0],
114 rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
115 clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
ee65fee0
FC
116 messenger.send('editor-start')
117 self.accept('editor-item-click-l', self.__on_item_click_l)
118 self.accept('editor-inspector-destroy', self.__on_inspector_destroy)
d3a2e50a
FC
119
120 def __on_close(self):
121 self.__json['name'] = self.__name_entry.get()
122 self.__json['instructions'] = self.__instructions_entry.get()
123 if self.__compute_hash() == self.__json['version']:
124 self._frm.destroy()
125 else:
126 self.__dialog = YesNoDialog(dialogName='Unsaved changes',
127 text=_('You have unsaved changes. Really quit?'),
128 command=self.__actually_close)
012cf969
FC
129 self.__dialog['frameColor'] = (.4, .4, .4, .14)
130 self.__dialog['relief'] = FLAT
131 self.__dialog.component('text0')['fg'] = (.9, .9, .9, 1)
132 self.__dialog.component('text0')['font'] = self._font
133 for b in self.__dialog.buttonList:
134 b['frameColor'] = (.4, .4, .4, .14)
135 b.component('text0')['fg'] = (.9, .9, .9, 1)
136 b.component('text0')['font'] = self._font
137 b.component('text1')['fg'] = (.9, .1, .1, 1)
138 b.component('text1')['font'] = self._font
139 b.component('text2')['fg'] = (.9, .9, .1, 1)
140 b.component('text2')['font'] = self._font
d3a2e50a
FC
141
142 def __actually_close(self, arg):
143 if arg:
144 self._frm.destroy()
ee65fee0 145 messenger.send('editor-stop')
d3a2e50a
FC
146 self.__dialog.cleanup()
147
148 def __on_save(self):
149 self.__json['name'] = self.__name_entry.get()
150 self.__json['instructions'] = self.__instructions_entry.get()
151 self.__json['version'] = self.__compute_hash()
152 with open('assets/scenes/%s.json' % self.__json_name, 'w') as f:
153 f.write(dumps(self.__json, indent=2, sort_keys=True))
154
012cf969
FC
155 def __on_scene_list(self):
156 SceneList()
157
d3a2e50a
FC
158 def __load_img_btn(self, path, col):
159 img = OnscreenImage('assets/images/buttons/%s.dds' % path)
160 img.set_transparency(True)
161 img.set_color(col)
162 img.detach_node()
163 return img
164
165 def __compute_hash(self):
166 new_dict = deepcopy(self.__json)
167 del new_dict['version']
168 new_dict_str = str(dumps(new_dict, indent=2, sort_keys=True))
169 h = hashlib.new('sha256')
170 h.update(new_dict_str.encode())
171 return h.hexdigest()[:12]
ee65fee0
FC
172
173 def __on_item_click_l(self, item):
174 if self.__inspector and self.__inspector.item == item: return
175 if self.__inspector:
176 self.__inspector.destroy()
177 self.__inspector = Inspector(item)
178
179 def __on_inspector_destroy(self):
180 self.__inspector = None