Mercurial > fife-parpg
comparison clients/editor/plugins/ObjectEdit.py @ 307:22253b2c9b14
- added LightEdit editor plugin (needs light branch to work; deactivated if lighting renderer is not available)
- added animation viewer to ObjectEdit
- several bugfixes for ObjectEdit plugin
FEATURES:
- ObjectEdit
- viewing and rotating animated instances (rotations are hardcoded for now, FIFE needs to expose available angles to python in order to make animation rotation work for every client)
- LightEdit
- test global light values
author | chewie@33b003aa-7bff-0310-803a-e67f0ece8222 |
---|---|
date | Tue, 11 Aug 2009 15:32:54 +0000 |
parents | 07709bffab8f |
children | af0b233e246f |
comparison
equal
deleted
inserted
replaced
306:6177cdf72489 | 307:22253b2c9b14 |
---|---|
1 #!/usr/bin/env python | |
1 # coding: utf-8 | 2 # coding: utf-8 |
2 # ################################################### | 3 # ################################################### |
3 # Copyright (C) 2008 The Zero-Projekt team | 4 # Copyright (C) 2008 The Zero-Projekt team |
4 # http://zero-projekt.net | 5 # http://zero-projekt.net |
5 # info@zero-projekt.net | 6 # info@zero-projekt.net |
26 import fife | 27 import fife |
27 import pychan | 28 import pychan |
28 import pychan.widgets as widgets | 29 import pychan.widgets as widgets |
29 from pychan.tools import callbackWithArguments as cbwa | 30 from pychan.tools import callbackWithArguments as cbwa |
30 | 31 |
32 from fife_timer import Timer | |
33 | |
31 import scripts | 34 import scripts |
32 import scripts.plugin as plugin | 35 import scripts.plugin as plugin |
33 from scripts.events import * | 36 from scripts.events import * |
34 from scripts.gui.action import Action | 37 from scripts.gui.action import Action |
35 | 38 |
39 | |
40 import os | |
41 try: | |
42 import xml.etree.cElementTree as ET | |
43 except: | |
44 import xml.etree.ElementTree as ET | |
45 | |
36 import math | 46 import math |
47 | |
48 WHITE = { | |
49 "r" : 205, | |
50 "g" : 205, | |
51 "b" : 205 | |
52 } | |
53 OUTLINE_SIZE = 1 | |
37 | 54 |
38 class ObjectEdit(plugin.Plugin): | 55 class ObjectEdit(plugin.Plugin): |
39 """ The B{ObjectEdit} module is a plugin for FIFedit and allows to edit | 56 """ The B{ObjectEdit} module is a plugin for FIFedit and allows to edit |
40 attributes of an selected instance - like instance id or rotation | 57 attributes of an selected instance - like offset, instance id or rotation |
41 (namespaces and object id editing is excluded) | 58 (namespaces and object id editing is excluded) |
42 | 59 |
43 current features: | 60 current features: |
44 - click instance and get all known data | 61 - click instance and get all known data |
45 - edit rotation, instance id | 62 - edit offsets, rotation, instance id |
63 - save offsets to object file | |
46 - outline highlighting of the selected object | 64 - outline highlighting of the selected object |
47 | 65 - animation viewer |
48 missing features: | 66 |
49 - blocking flag (flag doesn't work yet from FIFE side) | 67 FIXME: |
50 - static flag (flag doesn't work yet from FIFE side) | 68 - add static and blocking flag to save routine |
51 - object saving | 69 - fix animation rotation (FIFE has no method yet to export all |
52 - a lot of bug fixing concerning the rotation | 70 angles of an animation to python) |
53 - the module should be able to use the editors global undo history | |
54 """ | 71 """ |
55 def __init__(self): | 72 def __init__(self): |
56 self.active = False | 73 self.active = False |
57 self._camera = None | 74 self._camera = None |
58 self._layer = None | 75 self._layer = None |
76 self._anim_timer = None | |
59 | 77 |
60 self._enabled = False | 78 self._enabled = False |
61 | 79 |
62 self.imagepool = None | 80 self.imagepool = None |
63 self.animationpool = None | 81 self._animationpool = None |
64 | 82 |
65 self.guidata = {} | 83 self.guidata = {} |
66 self.objectdata = {} | 84 self.objectdata = {} |
67 | 85 |
68 def _reset(self): | 86 def _reset(self): |
69 """ | 87 """ |
70 resets all dynamic vars, but leaves out static ones (e.g. camera, layer) | 88 resets all dynamic vars, but leaves out static ones (e.g. camera, layer) |
71 | 89 |
72 """ | 90 """ |
91 if self._anim_timer: | |
92 self._anim_timer.stop() | |
93 # reset the ToggleButton | |
94 if self._gui_anim_playback._isToggled(): | |
95 self._gui_anim_playback._setToggled(0) | |
96 self._anim_timer = None | |
97 | |
98 self._object = None | |
73 self._instances = None | 99 self._instances = None |
74 self._image = None | 100 self._image = None |
101 self._image_default_x_offset = None | |
102 self._image_default_y_offset = None | |
75 self._animation = False | 103 self._animation = False |
104 self._anim_data = {} | |
76 self._rotation = None | 105 self._rotation = None |
77 self._avail_rotations = [] | 106 self._avail_rotations = [] |
78 self._namespace = None | 107 self._namespace = None |
79 self._blocking = 0 | 108 self._blocking = 0 |
80 self._static = 0 | 109 self._static = 0 |
81 self._object_id = None | 110 self._object_id = None |
82 self._instance_id = None | 111 self._instance_id = None |
83 self._fixed_rotation = None | 112 self._fixed_rotation = None |
84 | 113 |
85 if self._camera is not None: | 114 if self._camera is not None: |
86 self.renderer.removeAllOutlines() | 115 self.renderer.removeAllOutlines() |
87 | |
88 | 116 |
89 def enable(self): | 117 def enable(self): |
118 """ plugin method """ | |
90 if self._enabled is True: | 119 if self._enabled is True: |
91 return | 120 return |
92 | 121 |
93 self._editor = scripts.editor.getEditor() | 122 self._editor = scripts.editor.getEditor() |
94 self.engine = self._editor.getEngine() | 123 self.engine = self._editor.getEngine() |
95 | 124 |
96 self.imagepool = self.engine.getImagePool() | 125 self.imagepool = self.engine.getImagePool() |
97 self.animationpool = self.engine.getAnimationPool() | 126 self._animationpool = self.engine.getAnimationPool() |
98 | 127 |
99 self._showAction = Action(u"Object editor", checkable=True) | 128 self._showAction = Action(unicode(self.getName(),"utf-8"), checkable=True) |
100 scripts.gui.action.activated.connect(self.toggle_gui, sender=self._showAction) | 129 scripts.gui.action.activated.connect(self.toggle_gui, sender=self._showAction) |
101 | 130 |
102 self._editor._toolsMenu.addAction(self._showAction) | 131 self._editor._toolsMenu.addAction(self._showAction) |
103 | 132 |
104 events.onInstancesSelected.connect(self.input) | 133 events.onInstancesSelected.connect(self.input) |
105 | 134 |
106 self._reset() | 135 self._reset() |
107 self.create_gui() | 136 self.create_gui() |
108 | 137 |
109 def disable(self): | 138 def disable(self): |
139 """ plugin method """ | |
110 if self._enabled is False: | 140 if self._enabled is False: |
111 return | 141 return |
112 | 142 |
113 self._reset() | 143 self._reset() |
114 self.container.hide() | 144 self.container.hide() |
117 events.onInstancesSelected.disconnect(self.input) | 147 events.onInstancesSelected.disconnect(self.input) |
118 | 148 |
119 self._editor._toolsMenu.removeAction(self._showAction) | 149 self._editor._toolsMenu.removeAction(self._showAction) |
120 | 150 |
121 def isEnabled(self): | 151 def isEnabled(self): |
152 """ plugin method """ | |
122 return self._enabled; | 153 return self._enabled; |
123 | 154 |
124 def getName(self): | 155 def getName(self): |
125 return "Object editor" | 156 """ plugin method """ |
157 return "Object editor v2" | |
126 | 158 |
127 def create_gui(self): | 159 def create_gui(self): |
128 """ | 160 """ |
129 - creates the gui skeleton by loading the xml file | 161 - creates the gui skeleton by loading the xml file |
130 - finds some important childs and saves their widget in the object | 162 - finds some important childs and saves their widget in the object |
163 | |
164 FIXME: | |
165 - move all dynamic widgets to dict | |
131 """ | 166 """ |
132 self.container = pychan.loadXML('gui/objectedit.xml') | 167 self.container = pychan.loadXML('gui/objectedit.xml') |
133 self.container.mapEvents({ | 168 self.container.mapEvents({ |
134 'use_data' : self.use_user_data, | 169 'x_offset_up' : cbwa(self.change_offset_x, 1), |
135 | 170 'x_offset_dn' : cbwa(self.change_offset_x, -1), |
171 | |
172 'y_offset_up' : cbwa(self.change_offset_y, 1), | |
173 'y_offset_dn' : cbwa(self.change_offset_y, -1), | |
174 | |
175 'use_data' : self.use_user_data, | |
176 'change_data' : self.save_user_data, | |
177 | |
178 'anim_left' : self.previous_anim_frame, | |
179 'anim_right' : self.next_anim_frame, | |
180 'anim_start_pos' : self.anim_start_frame, | |
181 'anim_end_pos' : self.anim_end_frame, | |
136 }) | 182 }) |
137 | 183 |
138 self._gui_anim_panel_wrapper = self.container.findChild(name="animation_panel_wrapper") | 184 self._gui_anim_panel_wrapper = self.container.findChild(name="animation_panel_wrapper") |
139 self._gui_anim_panel = self._gui_anim_panel_wrapper.findChild(name="animation_panel") | 185 self._gui_anim_panel = self._gui_anim_panel_wrapper.findChild(name="animation_panel") |
140 | 186 |
141 self._gui_anim_panel_wrapper.removeChild(self._gui_anim_panel) | |
142 | |
143 self._gui_rotation_dropdown = self.container.findChild(name="select_rotations") | 187 self._gui_rotation_dropdown = self.container.findChild(name="select_rotations") |
144 | 188 self._gui_rotation_dropdown.capture(self.gui_rotate_instance,"mouseWheelMovedUp") |
189 self._gui_rotation_dropdown.capture(self.gui_rotate_instance,"mouseWheelMovedDown") | |
190 self._gui_rotation_dropdown.capture(self.gui_rotate_instance,"action") | |
191 | |
192 self._gui_anim_actions_dropdown = self._gui_anim_panel_wrapper.findChild(name="select_actions") | |
193 self._gui_anim_actions_dropdown.capture(self.eval_gui_anim_action,"mouseWheelMovedUp") | |
194 self._gui_anim_actions_dropdown.capture(self.eval_gui_anim_action,"mouseWheelMovedDown") | |
195 self._gui_anim_actions_dropdown.capture(self.eval_gui_anim_action,"action") | |
196 | |
197 self._gui_anim_playback = self._gui_anim_panel_wrapper.findChild(name="anim_playback") | |
198 self._gui_anim_playback.capture(self.anim_playback, "mousePressed") | |
199 self._gui_anim_loop = self._gui_anim_panel_wrapper.findChild(name="anim_loop") | |
200 | |
201 self._gui_current_frame = self._gui_anim_panel_wrapper.findChild(name="anim_current_frame") | |
202 self._gui_current_frame.capture(self.previous_anim_frame,"mouseWheelMovedUp") | |
203 self._gui_current_frame.capture(self.next_anim_frame,"mouseWheelMovedDown") | |
204 | |
205 self._gui_xoffset_textfield = self.container.findChild(name="x_offset") | |
206 self._gui_yoffset_textfield = self.container.findChild(name="y_offset") | |
207 | |
145 self._gui_instance_id_textfield = self.container.findChild(name="instance_id") | 208 self._gui_instance_id_textfield = self.container.findChild(name="instance_id") |
146 | 209 |
147 def _get_gui_size(self): | 210 def anim_playback(self, widget): |
148 """ | 211 """ start / stop playback of an animation due to status of a gui ToggleButton |
149 gets the current size of the gui window and calculates new position | 212 Sets also two ivars of timer object (active & loop) |
150 (atm top right corner) | 213 """ |
151 """ | 214 if widget._isToggled(): |
152 size = self.container.size | 215 self._anim_timer.stop() |
153 self.position = ((pychan.internal.screen_width() - 50 - size[0]), 50) | 216 self._anim_timer.active = False |
154 | 217 else: |
218 frame_delay = self._anim_data['obj'].getFrameDuration(self._anim_data['current']) | |
219 self._anim_timer = Timer(delay=frame_delay,callback=self.next_anim_frame) | |
220 self._anim_timer.active = True | |
221 self._anim_timer.loop = self._gui_anim_loop._isMarked() | |
222 self._anim_timer.start() | |
223 | |
224 def previous_anim_frame(self): | |
225 """ show previous anim frame """ | |
226 if self._anim_data['current'] > 0: | |
227 self._anim_data['current'] -= 1 | |
228 self.update_gui() | |
229 | |
230 def next_anim_frame(self): | |
231 """ show next anim frame and reset animation frame to 0 if playback looping is active""" | |
232 if self._anim_timer.loop and (self._anim_data['current'] == self._anim_data['frames']): | |
233 self._anim_data['current'] = 0 | |
234 | |
235 if self._anim_data['current'] < self._anim_data['frames']: | |
236 self._anim_data['current'] += 1 | |
237 self.update_gui() | |
238 | |
239 def anim_start_frame(self): | |
240 """ set start frame of animation """ | |
241 self._anim_data['current'] = 0 | |
242 self.update_gui() | |
243 | |
244 def anim_end_frame(self): | |
245 """ set end frame of animation """ | |
246 self._anim_data['current'] = self._anim_data['frames'] | |
247 self.update_gui() | |
248 | |
249 def set_default_offset(self, axis): | |
250 """ set default image offset for given axis """ | |
251 if axis == 'x': | |
252 self.set_offset(x=self._image_default_x_offset) | |
253 elif axis == 'y': | |
254 self.set_offset(y=self._image_default_y_offset) | |
255 | |
155 def update_gui(self): | 256 def update_gui(self): |
156 """ | 257 """ |
157 updates the gui widgets with current instance data | 258 updates the gui widgets with current instance data |
158 | 259 |
159 FIXME: | 260 """ |
160 - drop animation support or turn it into something useful | 261 # show the image we retrieved from an animated object |
161 """ | 262 if self._animation: |
162 #if self._animation is False: | 263 if not self._gui_anim_panel_wrapper.findChild(name="animation_panel"): |
163 #try: | 264 self._gui_anim_panel_wrapper.addChild(self._gui_anim_panel) |
164 #self._gui_anim_panel_wrapper.removeChild(self._gui_anim_panel) | 265 |
165 #except: | 266 # get current selected image and update the icon widget |
166 #pass | 267 dur = 0 |
167 #elif self._animation is True: | 268 for i in range(self._anim_data['frames']): |
168 #try: | 269 dur += self._anim_data['obj'].getFrameDuration(i) |
169 #self._gui_anim_panel_wrapper.resizeToContent() | 270 |
170 #self._gui_anim_panel_wrapper.addChild(self._gui_anim_panel) | 271 # set new duration for the playback timer |
171 #self._gui_anim_panel_wrapper.resizeToContent() | 272 if self._anim_timer: |
172 #except: | 273 frame_delay = self._anim_data['obj'].getFrameDuration(self._anim_data['current']) |
173 #pass | 274 |
174 | 275 if i == self._anim_data['current']: |
276 # set new duration for the playback timer | |
277 if self._anim_timer and self._anim_timer.active: | |
278 self._anim_timer.setPeriod(self._anim_data['obj'].getFrameDuration(self._anim_data['current'])) | |
279 break | |
280 | |
281 image = self._anim_data['obj'].getFrameByTimestamp(dur) | |
282 self.container.findChild(name="animTest").image = image.getResourceFile() | |
283 self.container.findChild(name="animTest").size= (250,250) | |
284 self.container.findChild(name="animTest").min_size= (250,250) | |
285 | |
286 self.container.distributeInitialData({ | |
287 'anim_current_frame' : unicode(str(self._anim_data['current'])), | |
288 'anim_rotation' : unicode(str(self._anim_data['obj'].getDirection())), | |
289 }) | |
290 | |
291 else: | |
292 if self._gui_anim_panel_wrapper.findChild(name="animation_panel"): | |
293 self._gui_anim_panel_wrapper.removeChild(self._gui_anim_panel) | |
294 | |
295 if self._image is not None: | |
296 x_offset = unicode( self._image.getXShift() ) | |
297 y_offset = unicode( self._image.getYShift() ) | |
298 else: | |
299 x_offset = unicode( 0 ) | |
300 y_offset = unicode( 0 ) | |
301 | |
175 self.container.distributeInitialData({ | 302 self.container.distributeInitialData({ |
176 'select_rotations' : self._avail_rotations, | 303 'select_rotations' : self._avail_rotations, |
177 'instance_id' : unicode( self._instances[0].getId() ), | 304 'instance_id' : unicode( self._instances[0].getId() ), |
178 'object_id' : unicode( self._object_id ), | 305 'object_id' : unicode( self._object_id ), |
306 'x_offset' : x_offset, | |
307 'y_offset' : y_offset, | |
179 'instance_rotation' : unicode( self._instances[0].getRotation() ), | 308 'instance_rotation' : unicode( self._instances[0].getRotation() ), |
180 'object_namespace' : unicode( self._namespace ), | 309 'object_namespace' : unicode( self._namespace ), |
181 'object_blocking' : unicode( self._blocking ), | 310 'object_blocking' : unicode( self._blocking ), |
182 'object_static' : unicode( self._static ), | 311 'object_static' : unicode( self._static ), |
183 }) | 312 }) |
184 try: | 313 |
185 print self._avail_rotations | 314 if not self._animation: |
186 print self._fixed_rotation | 315 index = self._avail_rotations.index( self._fixed_rotation ) |
187 index = self._avail_rotations.index( str(self._fixed_rotation) ) | |
188 self._gui_rotation_dropdown._setSelected(index) | 316 self._gui_rotation_dropdown._setSelected(index) |
189 except: | 317 |
190 # pass | 318 self.container.adaptLayout() |
191 print "Angle (", self._fixed_rotation, ") not supported by this instance" | |
192 self.container.adaptLayout() | |
193 | 319 |
194 def toggle_gui(self): | 320 def toggle_gui(self): |
195 """ | 321 """ |
196 show / hide the gui | 322 show / hide the gui |
197 """ | 323 """ |
204 else: | 330 else: |
205 self.active = True | 331 self.active = True |
206 self._showAction.setChecked(True) | 332 self._showAction.setChecked(True) |
207 | 333 |
208 def highlight_selected_instance(self): | 334 def highlight_selected_instance(self): |
209 """ | 335 """ highlights selected instance """ |
210 just highlights selected instance | |
211 """ | |
212 self.renderer.removeAllOutlines() | 336 self.renderer.removeAllOutlines() |
213 self.renderer.addOutlined(self._instances[0], 205, 205, 205, 1) | 337 self.renderer.addOutlined(self._instances[0], WHITE["r"], WHITE["g"], WHITE["b"], OUTLINE_SIZE) |
338 | |
339 def change_offset_x(self, value=1): | |
340 """ | |
341 - callback for changing x offset | |
342 - changes x offset of current instance (image) | |
343 - updates gui | |
344 | |
345 @type value: int | |
346 @param value: the modifier for the x offset | |
347 """ | |
348 if self._animation: | |
349 print "Offset changes of animations are not supported yet" | |
350 return | |
351 | |
352 if self._image is not None: | |
353 self._image.setXShift(self._image.getXShift() + value) | |
354 self.update_gui() | |
355 | |
356 def change_offset_y(self, value=1): | |
357 """ | |
358 - callback for changing y offset | |
359 - changes y offset of current instance (image) | |
360 - updates gui | |
361 | |
362 @type value: int | |
363 @param value: the modifier for the y offset | |
364 """ | |
365 if self._animation: | |
366 print "Offset changes of animations are not supported yet" | |
367 return | |
368 | |
369 if self._image is not None: | |
370 self._image.setYShift(self._image.getYShift() + value) | |
371 self.update_gui() | |
214 | 372 |
215 def use_user_data(self): | 373 def use_user_data(self): |
216 """ | 374 """ |
217 - takes the users values and applies them directly to the current ._instance | 375 - takes the users values and applies them directly to the current ._instance |
218 - writes current data record | 376 - writes current data record |
219 - writes previous data record | 377 - writes previous data record |
220 - updates gui | 378 - updates gui |
221 """ | 379 |
380 FIXME: | |
381 - parse user data in case user think strings are considered to be integer offset values... | |
382 """ | |
383 if self._animation: | |
384 print "Editing animated instances is not supported yet" | |
385 return | |
386 | |
387 xoffset = self._gui_xoffset_textfield._getText() | |
388 yoffset = self._gui_yoffset_textfield._getText() | |
389 | |
222 instance_id = str(self._gui_instance_id_textfield._getText()) | 390 instance_id = str(self._gui_instance_id_textfield._getText()) |
391 | |
392 if instance_id == "": | |
393 instance_id = "None" | |
394 | |
223 if instance_id is not None and instance_id is not "None": | 395 if instance_id is not None and instance_id is not "None": |
224 existing_instances = self._editor.getActiveMapView().getController()._layer.getInstances(instance_id) | 396 existing_instances = self._editor.getActiveMapView().getController()._layer.getInstances(instance_id) |
225 if len(existing_instances) <= 0: | 397 if len(existing_instances) <= 0: |
226 self._instances[0].setId(instance_id) | 398 self._instances[0].setId(instance_id) |
227 print "Set new instance id: ", instance_id | 399 print "Set new instance id: ", instance_id |
228 else: | 400 else: |
229 print "Instance ID is already in use." | 401 print "Instance ID is already in use." |
230 | 402 |
231 # workaround - dropdown list only has 2 entries, but sends 3 -> pychan bug? | 403 # update rotation |
232 if len(self._avail_rotations) < self._gui_rotation_dropdown._getSelected(): | 404 angle = self.eval_gui_rotation() |
233 index = len(self._avail_rotations) | 405 self.set_rotation(angle) |
234 else: | 406 |
235 index = self._gui_rotation_dropdown._getSelected() | 407 # update offsets |
236 | 408 self.set_offset(int(xoffset), int(yoffset)) |
237 # strange, but this helps to rotate the image correctly to the value the user selected | 409 |
410 self.update_gui() | |
411 | |
412 def save_user_data(self): | |
413 """ saves the current object to its xml file | |
414 | |
415 NOTE: | |
416 - animations can't be saved for now | |
417 | |
418 FIXME: | |
419 - add missing object attributes to saving routine | |
420 """ | |
421 if self._object is None: | |
422 return | |
423 if self._animation: | |
424 return | |
425 | |
426 file = self._object.getResourceFile() | |
427 self.tree = ET.parse(file) | |
428 | |
429 img_lst = self.tree.findall("image") | |
430 | |
431 # apply changes to the XML structure due to current user settings in the gui | |
432 for img_tag in img_lst: | |
433 if img_tag.attrib["direction"] == self._avail_rotations[self._gui_rotation_dropdown._getSelected()]: | |
434 img_tag.attrib["x_offset"] = self._gui_xoffset_textfield._getText() | |
435 img_tag.attrib["y_offset"] = self._gui_yoffset_textfield._getText() | |
436 break | |
437 | |
438 xmlcontent = ET.tostring(self.tree.getroot()) | |
439 | |
440 # save xml data beneath the <?fife type="object"?> definition into the object file | |
441 tmp = open(file, 'w') | |
442 tmp.write('<?fife type="object"?>\n') | |
443 tmp.write(xmlcontent + "\n") | |
444 tmp.close() | |
445 | |
446 def gui_rotate_instance(self): | |
447 """ rotate an instance due to selected angle """ | |
448 angle = self.eval_gui_rotation() | |
449 self.set_rotation(angle) | |
450 | |
451 def eval_gui_rotation(self): | |
452 """ prepare rotation from gui and apply it to the current selected instance """ | |
453 index = self._gui_rotation_dropdown._getSelected() | |
238 angle = int( self._avail_rotations[index] ) | 454 angle = int( self._avail_rotations[index] ) |
239 angle = int(angle - abs( self._camera.getTilt() ) ) | 455 |
240 if angle == 360: | 456 if angle == 360: |
241 angle = 0 | 457 angle = 0 |
242 | 458 |
459 return angle | |
460 | |
461 def eval_gui_anim_action(self): | |
462 """ check the selected action of an animation and update the gui accordingly """ | |
463 if not self._anim_data['actions']: return | |
464 | |
465 index = self._gui_anim_actions_dropdown._getSelected() | |
466 action = self._anim_data['actions'][index] | |
467 | |
468 self.update_anim_data(action) | |
469 self.update_gui() | |
470 | |
471 def set_rotation(self, angle): | |
472 """ set the rotation of the current instance """ | |
473 # print "...setting instance rotation from %s to %s" % (self._rotation, angle) | |
243 self._instances[0].setRotation(angle) | 474 self._instances[0].setRotation(angle) |
244 self.get_instance_data(None, None, angle) | 475 self.get_instance_data(None, None, angle) |
245 | 476 self.update_gui() |
246 self.update_gui() | 477 # print "...new internal FIFE rotation ", int(self._instances[0].getRotation()) |
478 | |
479 def set_offset(self, x=None, y=None): | |
480 """ set x/y offset of current selected instance """ | |
481 if x is not None: | |
482 self._image.setXShift(x) | |
483 if y is not None: | |
484 self._image.setYShift(y) | |
485 | |
486 def update_anim_data(self, action=None): | |
487 """ update animation data for the current selected instance from FIFE's data structure | |
488 | |
489 @type animation FIFE animation | |
490 @return animation current selected animation | |
491 """ | |
492 if action: | |
493 animation_id = action.get2dGfxVisual().getAnimationIndexByAngle(self._fixed_rotation) | |
494 animation = self._animationpool.getAnimation(animation_id) | |
495 | |
496 action_ids = [] | |
497 actions = [] | |
498 | |
499 try: | |
500 action_ids = self._object.getActionIds() | |
501 for id in action_ids: | |
502 actions.append(self._object.getAction(id)) | |
503 except: | |
504 pass | |
505 | |
506 self._anim_data = {} | |
507 self._anim_data['obj'] = animation | |
508 self._anim_data['id'] = animation_id | |
509 self._anim_data['frames'] = animation.getNumFrames() | |
510 self._anim_data['current'] = 0 | |
511 self._anim_data['actions'] = actions | |
512 self._anim_data['action_ids'] = action_ids | |
513 self._anim_data['default_action'] = self._object.getDefaultAction() | |
514 self._anim_data['action'] = action | |
515 | |
516 return animation | |
247 | 517 |
248 def get_instance_data(self, timestamp=None, frame=None, angle=-1, instance=None): | 518 def get_instance_data(self, timestamp=None, frame=None, angle=-1, instance=None): |
249 """ | 519 """ |
250 - grabs all available data from both object and instance | 520 - grabs all available data from both object and instance |
251 - checks if we already hold a record (namespace + object id) | 521 |
252 | |
253 FIXME: | 522 FIXME: |
254 1.) we need to fix the instance rotation / rotation issue | 523 1.) we need to fix the instance rotation / rotation issue |
255 2.) use correct instance rotations to store data for _each_ available rotation | |
256 3.) move record code out of this method | |
257 """ | 524 """ |
258 visual = None | 525 visual = None |
259 self._avail_rotations = [] | 526 self._avail_rotations = [] |
260 | 527 |
261 if instance is None: | 528 if instance is None: |
262 instance = self._instances[0] | 529 instance = self._instances[0] |
263 | 530 |
264 object = instance.getObject() | 531 object = instance.getObject() |
532 self._object = object | |
265 self._namespace = object.getNamespace() | 533 self._namespace = object.getNamespace() |
266 self._object_id = object.getId() | 534 self._object_id = object.getId() |
267 | 535 |
268 self._instance_id = instance.getId() | 536 self._instance_id = instance.getId() |
269 | 537 |
270 if self._instance_id == '': | 538 if self._instance_id == '': |
271 self._instance_id = 'None' | 539 self._instance_id = 'None' |
272 | 540 |
287 visual = object.get2dGfxVisual() | 555 visual = object.get2dGfxVisual() |
288 except: | 556 except: |
289 print 'Fetching visual of object - failed. :/' | 557 print 'Fetching visual of object - failed. :/' |
290 raise | 558 raise |
291 | 559 |
292 # print "Camera Tilt: ", self._camera.getTilt() | 560 # print "Camera tilt: ", self._camera.getTilt() |
293 # print "Camera Rotation: ", self._camera.getRotation() | 561 # print "Camera rotation: ", self._camera.getRotation() |
562 # print "Instance rotation: ", instance.getRotation() | |
294 | 563 |
295 self._fixed_rotation = int(instance.getRotation() + abs( self._camera.getTilt() ) ) | 564 self._fixed_rotation = int(instance.getRotation() + abs( self._camera.getTilt() ) ) |
296 self._fixed_rotation = visual.getClosestMatchingAngle(self._fixed_rotation) | 565 self._fixed_rotation = instance.getRotation() |
566 # self._fixed_rotation = visual.getClosestMatchingAngle(self._fixed_rotation) | |
297 | 567 |
298 index = visual.getStaticImageIndexByAngle(self._fixed_rotation) | 568 index = visual.getStaticImageIndexByAngle(self._fixed_rotation) |
299 | 569 |
300 if index == -1: | 570 if index is -1: |
301 # object is an animation | 571 # object is an animation |
302 self._animation = True | 572 self._animation = True |
573 self._image = None | |
574 | |
303 # no static image available, try default action | 575 # no static image available, try default action |
304 action = object.getDefaultAction() | 576 action = object.getDefaultAction() |
577 | |
305 if action: | 578 if action: |
306 animation_id = action.get2dGfxVisual().getAnimationIndexByAngle(self._fixed_rotation) | 579 animation = self.update_anim_data(action) |
307 animation = self.animationpool.getAnimation(animation_id) | 580 |
308 # if timestamp is None and frame is not None: | 581 # update gui |
309 # self._image = animation.getFrame(frame) | 582 if animation: |
310 # elif timestamp is not None and frame is None: | 583 self._gui_anim_actions_dropdown._setItems(self._anim_data['action_ids']) |
311 # self._image = animation.getFrameByTimestamp(timestamp) | 584 self._gui_anim_actions_dropdown._setSelected(0) |
312 # else: | 585 |
313 self._image = animation.getFrameByTimestamp(0) | 586 if timestamp is None and frame is not None: |
314 index = self._image.getPoolId() | 587 self._image = animation.getFrame(frame) |
315 elif index != -1: | 588 elif timestamp is not None and frame is None: |
589 self._image = animation.getFrameByTimestamp(timestamp) | |
590 else: | |
591 self._image = animation.getFrameByTimestamp(0) | |
592 elif index is not -1: | |
316 # object is a static image | 593 # object is a static image |
317 self._animation = False | 594 self._animation = False |
318 self._image = self.imagepool.getImage(index) | 595 self._image = self.imagepool.getImage(index) |
319 | 596 |
320 if not self._animation: | 597 if not self._animation: |
321 rotation_tuple = visual.getStaticImageAngles() | 598 rotations = visual.getStaticImageAngles() |
322 for angle in rotation_tuple: | 599 for angle in rotations: |
323 self._avail_rotations.append( str(angle) ) | 600 self._avail_rotations.append(angle) |
324 | 601 |
325 | 602 self._image_default_x_offset = self._image.getXShift() |
326 # FIXME: see l. 40 | 603 self._image_default_y_offset = self._image.getYShift() |
327 self._editor.getActiveMapView().getController()._objectedit_rotations = self._avail_rotations | 604 else: |
328 # end FIXME | 605 # these doesn't work correctly |
329 | 606 # rotations = [0,60,120,180,240,300] |
607 | |
608 # testbench to get valid angles | |
609 # angle = 0 | |
610 # rotations = [] | |
611 # while angle != 360: | |
612 # angle += 10 | |
613 # rotations.append(angle) | |
614 | |
615 # estimated angles (for hex!) to make things work - use testbench to test | |
616 # various angles and note down the working ones (watch instance | |
617 # rotation and the animation rotations shown in the gui; valid | |
618 # angles are given once the rotations are in sync | |
619 self._avail_rotations = [9,69,139,169,249,319] | |
620 | |
330 def input(self, instances): | 621 def input(self, instances): |
331 """ | 622 """ |
332 if called _and_ the objectedit is active, | 623 if called _and_ the user wishes to edit offsets, |
333 gets instance data and show gui | 624 gets instance data and show gui |
334 | 625 |
335 (see run.py, pump() ) | |
336 """ | 626 """ |
337 if instances != self._instances: | 627 if instances != self._instances: |
338 if self.active is True: | 628 if self.active is True: |
339 self._reset() | 629 self._reset() |
340 self._instances = instances | 630 self._instances = instances |
349 self.highlight_selected_instance() | 639 self.highlight_selected_instance() |
350 self.get_instance_data() | 640 self.get_instance_data() |
351 self.update_gui() | 641 self.update_gui() |
352 self.container.adaptLayout() | 642 self.container.adaptLayout() |
353 self.container.show() | 643 self.container.show() |
354 self._get_gui_size() | |
355 self.container._setPosition(self.position) | |
356 else: | 644 else: |
357 self._reset() | 645 self._reset() |
358 self.container.hide() | 646 self.container.hide() |
647 | |
648 self.container.adaptLayout() |