# HG changeset patch
# User chewie@33b003aa-7bff-0310-803a-e67f0ece8222
# Date 1250004774 0
# Node ID 22253b2c9b14714bb289331fad3604372e9fe551
# Parent 6177cdf7248968431e335dfeca40a35e2f8ecdc7
- 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
diff -r 6177cdf72489 -r 22253b2c9b14 clients/editor/gui/lightedit.xml
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/clients/editor/gui/lightedit.xml Tue Aug 11 15:32:54 2009 +0000
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff -r 6177cdf72489 -r 22253b2c9b14 clients/editor/gui/objectedit.xml
--- a/clients/editor/gui/objectedit.xml Sat Aug 08 14:24:35 2009 +0000
+++ b/clients/editor/gui/objectedit.xml Tue Aug 11 15:32:54 2009 +0000
@@ -1,9 +1,9 @@
-
-
+
-
-
-
+
+
+
+
@@ -16,28 +16,56 @@
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+
+
+
+
+
+
+
+
-
+
+
+
@@ -45,11 +73,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
diff -r 6177cdf72489 -r 22253b2c9b14 clients/editor/plugins/LightEdit.py
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/clients/editor/plugins/LightEdit.py Tue Aug 11 15:32:54 2009 +0000
@@ -0,0 +1,292 @@
+#!/usr/bin/env python
+# coding: utf-8
+# ###################################################
+# Copyright (C) 2008 The Zero-Projekt team
+# http://zero-projekt.net
+# info@zero-projekt.net
+# This file is part of Zero "Was vom Morgen blieb"
+#
+# The Zero-Projekt codebase is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the
+# Free Software Foundation, Inc.,
+# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+# ###################################################
+
+""" a tool for FIFEdit to test global light """
+
+import fife
+import pychan
+import pychan.widgets as widgets
+from pychan.tools import callbackWithArguments as cbwa
+
+from fife_timer import Timer
+
+import scripts
+import scripts.plugin as plugin
+from scripts.events import *
+from scripts.gui.action import Action
+
+import random
+
+DEFAULT_GLOBAL_LIGHT = {
+ "R" : 1.0,
+ "G" : 1.0,
+ "B" : 1.0,
+ "A" : 1.0,
+}
+DEFAULT_LIGHT_ID = "LightEdit"
+
+class LightEdit(plugin.Plugin):
+ """ The B{LightEdit} module is a plugin for FIFedit and allows to change the
+ global light value
+
+ FEATURES:
+ - enable FIFE lighting renderer
+ - generate random light values
+ - test lightsetups by manipulating the color channels
+ - reset to default
+ """
+ def __init__(self):
+ self.active = False
+
+ self._renderer = None
+ self._camera = None
+ self._enabled = False
+ self._light = False
+
+ self.map_loaded = False
+
+ self._color = {}
+ self._color.update(DEFAULT_GLOBAL_LIGHT)
+
+ random.seed()
+
+ if "LightRenderer" in dir(fife):
+ self._renderer_available = True
+ else:
+ self._renderer_available = False
+
+ def _reset(self):
+ """ resets all dynamic vars """
+ pass
+
+ def enable(self):
+ """ plugin method """
+ if not self._renderer_available:
+ self._enabled = False
+ return
+ if self._enabled is True:
+ return
+
+ self._editor = scripts.editor.getEditor()
+ self.engine = self._editor.getEngine()
+
+ self._showAction = Action(unicode(self.getName(),"utf-8"), checkable=True)
+ scripts.gui.action.activated.connect(self.toggle_gui, sender=self._showAction)
+
+ self._editor._toolsMenu.addAction(self._showAction)
+
+ events.postMapShown.connect(self.update_renderer)
+ events.onMapChanged.connect(self.update_renderer)
+
+ self._reset()
+ self.create_gui()
+
+ def disable(self):
+ """ plugin method """
+ if self._enabled is False:
+ return
+
+ self._reset()
+ self.container.hide()
+ self.removeAllChildren()
+
+ self._editor._toolsMenu.removeAction(self._showAction)
+
+ events.postMapShown.disconnect(self.update_renderer)
+ events.onMapChanged.disconnect(self.update_renderer)
+
+ def isEnabled(self):
+ """ plugin method """
+ return self._enabled;
+
+ def getName(self):
+ """ plugin method """
+ return "Light editor"
+
+ def create_gui(self):
+ """ create gui container and setup callbacks """
+ self.container = pychan.loadXML('gui/lightedit.xml')
+ self.container.mapEvents({
+ "enable_global_light" : self.toggle_light,
+ "random_global_light" : self.random_color,
+ "reset_global_light" : self.reset_global_light,
+
+ "increase_R" : cbwa(self.increase_color, r=True),
+ "decrease_R" : cbwa(self.decrease_color, r=True),
+ "value_R/mouseWheelMovedUp" : cbwa(self.increase_color, step=0.2, r=True),
+ "value_R/mouseWheelMovedDown" : cbwa(self.decrease_color, step=0.2, r=True),
+
+ "increase_G" : cbwa(self.increase_color, g=True),
+ "decrease_G" : cbwa(self.decrease_color, g=True),
+ "value_G/mouseWheelMovedUp" : cbwa(self.increase_color, step=0.2, g=True),
+ "value_G/mouseWheelMovedDown" : cbwa(self.decrease_color, step=0.2, g=True),
+
+ "increase_B" : cbwa(self.increase_color, b=True),
+ "decrease_B" : cbwa(self.decrease_color, b=True),
+ "value_B/mouseWheelMovedUp" : cbwa(self.increase_color, step=0.2, b=True),
+ "value_B/mouseWheelMovedDown" : cbwa(self.decrease_color, step=0.2, b=True),
+
+ "increase_A" : cbwa(self.increase_color, a=True),
+ "decrease_A" : cbwa(self.decrease_color, a=True),
+ "value_A/mouseWheelMovedUp" : cbwa(self.increase_color, step=0.2, a=True),
+ "value_A/mouseWheelMovedDown" : cbwa(self.decrease_color, step=0.2, a=True),
+ })
+ self._widgets = {
+ "enable_global_light" : self.container.findChild(name="enable_global_light"),
+ "random_global_light" : self.container.findChild(name="random_global_light"),
+ "reset_global_light" : self.container.findChild(name="reset_global_light"),
+
+ "value_R" : self.container.findChild(name="value_R"),
+ "value_G" : self.container.findChild(name="value_G"),
+ "value_B" : self.container.findChild(name="value_B"),
+ "value_A" : self.container.findChild(name="value_A"),
+ }
+
+ def toggle_gui(self):
+ """ show / hide the gui """
+ if self.active:
+ self.active = False
+ if self.container.isVisible() or self.container.isDocked():
+ self.container.setDocked(False)
+ self.container.hide()
+ self._showAction.setChecked(False)
+ else:
+ self.active = True
+ self._showAction.setChecked(True)
+ self.container.show()
+
+ def toggle_light(self):
+ """ toggle light on / off """
+ if not self._renderer:
+ self._widgets['enable_global_light']._setToggled(False)
+ return
+
+ if self._light:
+ self._light = False
+ self.reset_global_light()
+ self._renderer.setEnabled(False)
+ else:
+ self._light = True
+ self._renderer.setEnabled(True)
+
+ def update_renderer(self):
+ """ sets current camera and renderer
+ bound to FIFedit core (updated on map change)
+ """
+ self._camera = self._editor.getActiveMapView().getCamera()
+ self._renderer = fife.LightRenderer.getInstance(self._camera)
+
+ def update_gui(self):
+ """ update gui widgets according to plugin data """
+ self._widgets["value_R"].text = unicode(str(self._color["R"]))
+ self._widgets["value_G"].text = unicode(str(self._color["G"]))
+ self._widgets["value_B"].text = unicode(str(self._color["B"]))
+ self._widgets["value_A"].text = unicode(str(self._color["A"]))
+
+ def reset_global_light(self):
+ """ reset global light to default values (1.0) """
+ if not self._renderer: return
+
+ self._color.update(DEFAULT_GLOBAL_LIGHT)
+ self.update_gui()
+ self.set_global_light()
+
+ def increase_color(self, step=0.1, r=None, g=None, b=None, a=None):
+ """ increase a given color value by step value
+
+ @type step float
+ @param step the step for changing the color channel
+ @type r bool
+ @param r flag to alter red color value
+ @type g bool
+ @param g flag to alter green color value
+ @type b bool
+ @param b flag to alter blue color value
+ @type a bool
+ @type a flag to alter alpha channel value (no effect atm)
+ """
+ if r:
+ self._color["R"] += step
+ if g:
+ self._color["G"] += step
+ if b:
+ self._color["B"] += step
+ if a:
+ self._color["A"] += step
+
+ self.update_gui()
+ self.set_global_light()
+
+ def decrease_color(self, step=0.1, r=None, g=None, b=None, a=None):
+ """ decrease a given color value by step value
+
+ @type step float
+ @param step the step for changing the color channel
+ @type r bool
+ @param r flag to alter red color value
+ @type g bool
+ @param g flag to alter green color value
+ @type b bool
+ @param b flag to alter blue color value
+ @type a bool
+ @type a flag to alter alpha channel value (no effect atm)
+ """
+ if r:
+ self._color["R"] -= step
+ if g:
+ self._color["G"] -= step
+ if b:
+ self._color["B"] -= step
+ if a:
+ self._color["A"] -= step
+
+ self.update_gui()
+ self.set_global_light()
+
+ def random_color(self):
+ """ generate random values for color channels """
+ if not self._renderer: return
+
+ self._color["R"] = random.uniform(0,2)
+ self._color["G"] = random.uniform(0,2)
+ self._color["B"] = random.uniform(0,2)
+ self._color["A"] = random.uniform(0,2)
+
+ self.update_gui()
+ self.set_global_light()
+
+ def set_global_light(self):
+ """ update the global light with the current set colors """
+ if not self._renderer: return
+
+ self._renderer.removeAll(DEFAULT_LIGHT_ID)
+ self._renderer.setglobalLight(
+ DEFAULT_LIGHT_ID,
+ 1,
+ self._color["R"],
+ self._color["G"],
+ self._color["B"],
+ self._color["A"]
+ )
+
diff -r 6177cdf72489 -r 22253b2c9b14 clients/editor/plugins/ObjectEdit.py
--- a/clients/editor/plugins/ObjectEdit.py Sat Aug 08 14:24:35 2009 +0000
+++ b/clients/editor/plugins/ObjectEdit.py Tue Aug 11 15:32:54 2009 +0000
@@ -1,3 +1,4 @@
+#!/usr/bin/env python
# coding: utf-8
# ###################################################
# Copyright (C) 2008 The Zero-Projekt team
@@ -28,39 +29,56 @@
import pychan.widgets as widgets
from pychan.tools import callbackWithArguments as cbwa
+from fife_timer import Timer
+
import scripts
import scripts.plugin as plugin
from scripts.events import *
from scripts.gui.action import Action
+
+import os
+try:
+ import xml.etree.cElementTree as ET
+except:
+ import xml.etree.ElementTree as ET
+
import math
+WHITE = {
+ "r" : 205,
+ "g" : 205,
+ "b" : 205
+}
+OUTLINE_SIZE = 1
+
class ObjectEdit(plugin.Plugin):
""" The B{ObjectEdit} module is a plugin for FIFedit and allows to edit
- attributes of an selected instance - like instance id or rotation
+ attributes of an selected instance - like offset, instance id or rotation
(namespaces and object id editing is excluded)
current features:
- click instance and get all known data
- - edit rotation, instance id
+ - edit offsets, rotation, instance id
+ - save offsets to object file
- outline highlighting of the selected object
-
- missing features:
- - blocking flag (flag doesn't work yet from FIFE side)
- - static flag (flag doesn't work yet from FIFE side)
- - object saving
- - a lot of bug fixing concerning the rotation
- - the module should be able to use the editors global undo history
+ - animation viewer
+
+ FIXME:
+ - add static and blocking flag to save routine
+ - fix animation rotation (FIFE has no method yet to export all
+ angles of an animation to python)
"""
def __init__(self):
self.active = False
self._camera = None
self._layer = None
+ self._anim_timer = None
self._enabled = False
self.imagepool = None
- self.animationpool = None
+ self._animationpool = None
self.guidata = {}
self.objectdata = {}
@@ -70,9 +88,20 @@
resets all dynamic vars, but leaves out static ones (e.g. camera, layer)
"""
+ if self._anim_timer:
+ self._anim_timer.stop()
+ # reset the ToggleButton
+ if self._gui_anim_playback._isToggled():
+ self._gui_anim_playback._setToggled(0)
+ self._anim_timer = None
+
+ self._object = None
self._instances = None
self._image = None
+ self._image_default_x_offset = None
+ self._image_default_y_offset = None
self._animation = False
+ self._anim_data = {}
self._rotation = None
self._avail_rotations = []
self._namespace = None
@@ -83,10 +112,10 @@
self._fixed_rotation = None
if self._camera is not None:
- self.renderer.removeAllOutlines()
-
+ self.renderer.removeAllOutlines()
def enable(self):
+ """ plugin method """
if self._enabled is True:
return
@@ -94,9 +123,9 @@
self.engine = self._editor.getEngine()
self.imagepool = self.engine.getImagePool()
- self.animationpool = self.engine.getAnimationPool()
+ self._animationpool = self.engine.getAnimationPool()
- self._showAction = Action(u"Object editor", checkable=True)
+ self._showAction = Action(unicode(self.getName(),"utf-8"), checkable=True)
scripts.gui.action.activated.connect(self.toggle_gui, sender=self._showAction)
self._editor._toolsMenu.addAction(self._showAction)
@@ -107,6 +136,7 @@
self.create_gui()
def disable(self):
+ """ plugin method """
if self._enabled is False:
return
@@ -119,77 +149,173 @@
self._editor._toolsMenu.removeAction(self._showAction)
def isEnabled(self):
+ """ plugin method """
return self._enabled;
def getName(self):
- return "Object editor"
+ """ plugin method """
+ return "Object editor v2"
def create_gui(self):
"""
- creates the gui skeleton by loading the xml file
- finds some important childs and saves their widget in the object
+
+ FIXME:
+ - move all dynamic widgets to dict
"""
self.container = pychan.loadXML('gui/objectedit.xml')
self.container.mapEvents({
- 'use_data' : self.use_user_data,
+ 'x_offset_up' : cbwa(self.change_offset_x, 1),
+ 'x_offset_dn' : cbwa(self.change_offset_x, -1),
+
+ 'y_offset_up' : cbwa(self.change_offset_y, 1),
+ 'y_offset_dn' : cbwa(self.change_offset_y, -1),
+ 'use_data' : self.use_user_data,
+ 'change_data' : self.save_user_data,
+
+ 'anim_left' : self.previous_anim_frame,
+ 'anim_right' : self.next_anim_frame,
+ 'anim_start_pos' : self.anim_start_frame,
+ 'anim_end_pos' : self.anim_end_frame,
})
self._gui_anim_panel_wrapper = self.container.findChild(name="animation_panel_wrapper")
self._gui_anim_panel = self._gui_anim_panel_wrapper.findChild(name="animation_panel")
- self._gui_anim_panel_wrapper.removeChild(self._gui_anim_panel)
+ self._gui_rotation_dropdown = self.container.findChild(name="select_rotations")
+ self._gui_rotation_dropdown.capture(self.gui_rotate_instance,"mouseWheelMovedUp")
+ self._gui_rotation_dropdown.capture(self.gui_rotate_instance,"mouseWheelMovedDown")
+ self._gui_rotation_dropdown.capture(self.gui_rotate_instance,"action")
+
+ self._gui_anim_actions_dropdown = self._gui_anim_panel_wrapper.findChild(name="select_actions")
+ self._gui_anim_actions_dropdown.capture(self.eval_gui_anim_action,"mouseWheelMovedUp")
+ self._gui_anim_actions_dropdown.capture(self.eval_gui_anim_action,"mouseWheelMovedDown")
+ self._gui_anim_actions_dropdown.capture(self.eval_gui_anim_action,"action")
+
+ self._gui_anim_playback = self._gui_anim_panel_wrapper.findChild(name="anim_playback")
+ self._gui_anim_playback.capture(self.anim_playback, "mousePressed")
+ self._gui_anim_loop = self._gui_anim_panel_wrapper.findChild(name="anim_loop")
- self._gui_rotation_dropdown = self.container.findChild(name="select_rotations")
-
+ self._gui_current_frame = self._gui_anim_panel_wrapper.findChild(name="anim_current_frame")
+ self._gui_current_frame.capture(self.previous_anim_frame,"mouseWheelMovedUp")
+ self._gui_current_frame.capture(self.next_anim_frame,"mouseWheelMovedDown")
+
+ self._gui_xoffset_textfield = self.container.findChild(name="x_offset")
+ self._gui_yoffset_textfield = self.container.findChild(name="y_offset")
+
self._gui_instance_id_textfield = self.container.findChild(name="instance_id")
- def _get_gui_size(self):
+ def anim_playback(self, widget):
+ """ start / stop playback of an animation due to status of a gui ToggleButton
+ Sets also two ivars of timer object (active & loop)
"""
- gets the current size of the gui window and calculates new position
- (atm top right corner)
- """
- size = self.container.size
- self.position = ((pychan.internal.screen_width() - 50 - size[0]), 50)
+ if widget._isToggled():
+ self._anim_timer.stop()
+ self._anim_timer.active = False
+ else:
+ frame_delay = self._anim_data['obj'].getFrameDuration(self._anim_data['current'])
+ self._anim_timer = Timer(delay=frame_delay,callback=self.next_anim_frame)
+ self._anim_timer.active = True
+ self._anim_timer.loop = self._gui_anim_loop._isMarked()
+ self._anim_timer.start()
+
+ def previous_anim_frame(self):
+ """ show previous anim frame """
+ if self._anim_data['current'] > 0:
+ self._anim_data['current'] -= 1
+ self.update_gui()
+
+ def next_anim_frame(self):
+ """ show next anim frame and reset animation frame to 0 if playback looping is active"""
+ if self._anim_timer.loop and (self._anim_data['current'] == self._anim_data['frames']):
+ self._anim_data['current'] = 0
+ if self._anim_data['current'] < self._anim_data['frames']:
+ self._anim_data['current'] += 1
+ self.update_gui()
+
+ def anim_start_frame(self):
+ """ set start frame of animation """
+ self._anim_data['current'] = 0
+ self.update_gui()
+
+ def anim_end_frame(self):
+ """ set end frame of animation """
+ self._anim_data['current'] = self._anim_data['frames']
+ self.update_gui()
+
+ def set_default_offset(self, axis):
+ """ set default image offset for given axis """
+ if axis == 'x':
+ self.set_offset(x=self._image_default_x_offset)
+ elif axis == 'y':
+ self.set_offset(y=self._image_default_y_offset)
+
def update_gui(self):
"""
updates the gui widgets with current instance data
- FIXME:
- - drop animation support or turn it into something useful
"""
- #if self._animation is False:
- #try:
- #self._gui_anim_panel_wrapper.removeChild(self._gui_anim_panel)
- #except:
- #pass
- #elif self._animation is True:
- #try:
- #self._gui_anim_panel_wrapper.resizeToContent()
- #self._gui_anim_panel_wrapper.addChild(self._gui_anim_panel)
- #self._gui_anim_panel_wrapper.resizeToContent()
- #except:
- #pass
+ # show the image we retrieved from an animated object
+ if self._animation:
+ if not self._gui_anim_panel_wrapper.findChild(name="animation_panel"):
+ self._gui_anim_panel_wrapper.addChild(self._gui_anim_panel)
+ # get current selected image and update the icon widget
+ dur = 0
+ for i in range(self._anim_data['frames']):
+ dur += self._anim_data['obj'].getFrameDuration(i)
+
+ # set new duration for the playback timer
+ if self._anim_timer:
+ frame_delay = self._anim_data['obj'].getFrameDuration(self._anim_data['current'])
+
+ if i == self._anim_data['current']:
+ # set new duration for the playback timer
+ if self._anim_timer and self._anim_timer.active:
+ self._anim_timer.setPeriod(self._anim_data['obj'].getFrameDuration(self._anim_data['current']))
+ break
+
+ image = self._anim_data['obj'].getFrameByTimestamp(dur)
+ self.container.findChild(name="animTest").image = image.getResourceFile()
+ self.container.findChild(name="animTest").size= (250,250)
+ self.container.findChild(name="animTest").min_size= (250,250)
+
+ self.container.distributeInitialData({
+ 'anim_current_frame' : unicode(str(self._anim_data['current'])),
+ 'anim_rotation' : unicode(str(self._anim_data['obj'].getDirection())),
+ })
+
+ else:
+ if self._gui_anim_panel_wrapper.findChild(name="animation_panel"):
+ self._gui_anim_panel_wrapper.removeChild(self._gui_anim_panel)
+
+ if self._image is not None:
+ x_offset = unicode( self._image.getXShift() )
+ y_offset = unicode( self._image.getYShift() )
+ else:
+ x_offset = unicode( 0 )
+ y_offset = unicode( 0 )
+
self.container.distributeInitialData({
'select_rotations' : self._avail_rotations,
'instance_id' : unicode( self._instances[0].getId() ),
'object_id' : unicode( self._object_id ),
+ 'x_offset' : x_offset,
+ 'y_offset' : y_offset,
'instance_rotation' : unicode( self._instances[0].getRotation() ),
'object_namespace' : unicode( self._namespace ),
'object_blocking' : unicode( self._blocking ),
'object_static' : unicode( self._static ),
})
- try:
- print self._avail_rotations
- print self._fixed_rotation
- index = self._avail_rotations.index( str(self._fixed_rotation) )
+
+ if not self._animation:
+ index = self._avail_rotations.index( self._fixed_rotation )
self._gui_rotation_dropdown._setSelected(index)
- except:
-# pass
- print "Angle (", self._fixed_rotation, ") not supported by this instance"
- self.container.adaptLayout()
+
+ self.container.adaptLayout()
def toggle_gui(self):
"""
@@ -206,11 +332,43 @@
self._showAction.setChecked(True)
def highlight_selected_instance(self):
- """
- just highlights selected instance
+ """ highlights selected instance """
+ self.renderer.removeAllOutlines()
+ self.renderer.addOutlined(self._instances[0], WHITE["r"], WHITE["g"], WHITE["b"], OUTLINE_SIZE)
+
+ def change_offset_x(self, value=1):
"""
- self.renderer.removeAllOutlines()
- self.renderer.addOutlined(self._instances[0], 205, 205, 205, 1)
+ - callback for changing x offset
+ - changes x offset of current instance (image)
+ - updates gui
+
+ @type value: int
+ @param value: the modifier for the x offset
+ """
+ if self._animation:
+ print "Offset changes of animations are not supported yet"
+ return
+
+ if self._image is not None:
+ self._image.setXShift(self._image.getXShift() + value)
+ self.update_gui()
+
+ def change_offset_y(self, value=1):
+ """
+ - callback for changing y offset
+ - changes y offset of current instance (image)
+ - updates gui
+
+ @type value: int
+ @param value: the modifier for the y offset
+ """
+ if self._animation:
+ print "Offset changes of animations are not supported yet"
+ return
+
+ if self._image is not None:
+ self._image.setYShift(self._image.getYShift() + value)
+ self.update_gui()
def use_user_data(self):
"""
@@ -218,8 +376,22 @@
- writes current data record
- writes previous data record
- updates gui
- """
+
+ FIXME:
+ - parse user data in case user think strings are considered to be integer offset values...
+ """
+ if self._animation:
+ print "Editing animated instances is not supported yet"
+ return
+
+ xoffset = self._gui_xoffset_textfield._getText()
+ yoffset = self._gui_yoffset_textfield._getText()
+
instance_id = str(self._gui_instance_id_textfield._getText())
+
+ if instance_id == "":
+ instance_id = "None"
+
if instance_id is not None and instance_id is not "None":
existing_instances = self._editor.getActiveMapView().getController()._layer.getInstances(instance_id)
if len(existing_instances) <= 0:
@@ -228,32 +400,127 @@
else:
print "Instance ID is already in use."
- # workaround - dropdown list only has 2 entries, but sends 3 -> pychan bug?
- if len(self._avail_rotations) < self._gui_rotation_dropdown._getSelected():
- index = len(self._avail_rotations)
- else:
- index = self._gui_rotation_dropdown._getSelected()
+ # update rotation
+ angle = self.eval_gui_rotation()
+ self.set_rotation(angle)
+
+ # update offsets
+ self.set_offset(int(xoffset), int(yoffset))
+
+ self.update_gui()
+
+ def save_user_data(self):
+ """ saves the current object to its xml file
+
+ NOTE:
+ - animations can't be saved for now
+
+ FIXME:
+ - add missing object attributes to saving routine
+ """
+ if self._object is None:
+ return
+ if self._animation:
+ return
+
+ file = self._object.getResourceFile()
+ self.tree = ET.parse(file)
- # strange, but this helps to rotate the image correctly to the value the user selected
+ img_lst = self.tree.findall("image")
+
+ # apply changes to the XML structure due to current user settings in the gui
+ for img_tag in img_lst:
+ if img_tag.attrib["direction"] == self._avail_rotations[self._gui_rotation_dropdown._getSelected()]:
+ img_tag.attrib["x_offset"] = self._gui_xoffset_textfield._getText()
+ img_tag.attrib["y_offset"] = self._gui_yoffset_textfield._getText()
+ break
+
+ xmlcontent = ET.tostring(self.tree.getroot())
+
+ # save xml data beneath the definition into the object file
+ tmp = open(file, 'w')
+ tmp.write('\n')
+ tmp.write(xmlcontent + "\n")
+ tmp.close()
+
+ def gui_rotate_instance(self):
+ """ rotate an instance due to selected angle """
+ angle = self.eval_gui_rotation()
+ self.set_rotation(angle)
+
+ def eval_gui_rotation(self):
+ """ prepare rotation from gui and apply it to the current selected instance """
+ index = self._gui_rotation_dropdown._getSelected()
angle = int( self._avail_rotations[index] )
- angle = int(angle - abs( self._camera.getTilt() ) )
+
if angle == 360:
angle = 0
+
+ return angle
+ def eval_gui_anim_action(self):
+ """ check the selected action of an animation and update the gui accordingly """
+ if not self._anim_data['actions']: return
+
+ index = self._gui_anim_actions_dropdown._getSelected()
+ action = self._anim_data['actions'][index]
+
+ self.update_anim_data(action)
+ self.update_gui()
+
+ def set_rotation(self, angle):
+ """ set the rotation of the current instance """
+# print "...setting instance rotation from %s to %s" % (self._rotation, angle)
self._instances[0].setRotation(angle)
self.get_instance_data(None, None, angle)
+ self.update_gui()
+# print "...new internal FIFE rotation ", int(self._instances[0].getRotation())
+
+ def set_offset(self, x=None, y=None):
+ """ set x/y offset of current selected instance """
+ if x is not None:
+ self._image.setXShift(x)
+ if y is not None:
+ self._image.setYShift(y)
+
+ def update_anim_data(self, action=None):
+ """ update animation data for the current selected instance from FIFE's data structure
+
+ @type animation FIFE animation
+ @return animation current selected animation
+ """
+ if action:
+ animation_id = action.get2dGfxVisual().getAnimationIndexByAngle(self._fixed_rotation)
+ animation = self._animationpool.getAnimation(animation_id)
- self.update_gui()
+ action_ids = []
+ actions = []
+
+ try:
+ action_ids = self._object.getActionIds()
+ for id in action_ids:
+ actions.append(self._object.getAction(id))
+ except:
+ pass
+
+ self._anim_data = {}
+ self._anim_data['obj'] = animation
+ self._anim_data['id'] = animation_id
+ self._anim_data['frames'] = animation.getNumFrames()
+ self._anim_data['current'] = 0
+ self._anim_data['actions'] = actions
+ self._anim_data['action_ids'] = action_ids
+ self._anim_data['default_action'] = self._object.getDefaultAction()
+ self._anim_data['action'] = action
+
+ return animation
def get_instance_data(self, timestamp=None, frame=None, angle=-1, instance=None):
"""
- grabs all available data from both object and instance
- - checks if we already hold a record (namespace + object id)
-
+
FIXME:
1.) we need to fix the instance rotation / rotation issue
- 2.) use correct instance rotations to store data for _each_ available rotation
- 3.) move record code out of this method
"""
visual = None
self._avail_rotations = []
@@ -262,9 +529,10 @@
instance = self._instances[0]
object = instance.getObject()
+ self._object = object
self._namespace = object.getNamespace()
self._object_id = object.getId()
-
+
self._instance_id = instance.getId()
if self._instance_id == '':
@@ -289,50 +557,72 @@
print 'Fetching visual of object - failed. :/'
raise
-# print "Camera Tilt: ", self._camera.getTilt()
-# print "Camera Rotation: ", self._camera.getRotation()
+# print "Camera tilt: ", self._camera.getTilt()
+# print "Camera rotation: ", self._camera.getRotation()
+# print "Instance rotation: ", instance.getRotation()
self._fixed_rotation = int(instance.getRotation() + abs( self._camera.getTilt() ) )
- self._fixed_rotation = visual.getClosestMatchingAngle(self._fixed_rotation)
+ self._fixed_rotation = instance.getRotation()
+# self._fixed_rotation = visual.getClosestMatchingAngle(self._fixed_rotation)
index = visual.getStaticImageIndexByAngle(self._fixed_rotation)
- if index == -1:
+ if index is -1:
# object is an animation
self._animation = True
+ self._image = None
+
# no static image available, try default action
action = object.getDefaultAction()
+
if action:
- animation_id = action.get2dGfxVisual().getAnimationIndexByAngle(self._fixed_rotation)
- animation = self.animationpool.getAnimation(animation_id)
-# if timestamp is None and frame is not None:
-# self._image = animation.getFrame(frame)
-# elif timestamp is not None and frame is None:
-# self._image = animation.getFrameByTimestamp(timestamp)
-# else:
- self._image = animation.getFrameByTimestamp(0)
- index = self._image.getPoolId()
- elif index != -1:
+ animation = self.update_anim_data(action)
+
+ # update gui
+ if animation:
+ self._gui_anim_actions_dropdown._setItems(self._anim_data['action_ids'])
+ self._gui_anim_actions_dropdown._setSelected(0)
+
+ if timestamp is None and frame is not None:
+ self._image = animation.getFrame(frame)
+ elif timestamp is not None and frame is None:
+ self._image = animation.getFrameByTimestamp(timestamp)
+ else:
+ self._image = animation.getFrameByTimestamp(0)
+ elif index is not -1:
# object is a static image
self._animation = False
self._image = self.imagepool.getImage(index)
if not self._animation:
- rotation_tuple = visual.getStaticImageAngles()
- for angle in rotation_tuple:
- self._avail_rotations.append( str(angle) )
-
+ rotations = visual.getStaticImageAngles()
+ for angle in rotations:
+ self._avail_rotations.append(angle)
+
+ self._image_default_x_offset = self._image.getXShift()
+ self._image_default_y_offset = self._image.getYShift()
+ else:
+ # these doesn't work correctly
+# rotations = [0,60,120,180,240,300]
-# FIXME: see l. 40
- self._editor.getActiveMapView().getController()._objectedit_rotations = self._avail_rotations
-# end FIXME
-
+ # testbench to get valid angles
+# angle = 0
+# rotations = []
+# while angle != 360:
+# angle += 10
+# rotations.append(angle)
+
+ # estimated angles (for hex!) to make things work - use testbench to test
+ # various angles and note down the working ones (watch instance
+ # rotation and the animation rotations shown in the gui; valid
+ # angles are given once the rotations are in sync
+ self._avail_rotations = [9,69,139,169,249,319]
+
def input(self, instances):
"""
- if called _and_ the objectedit is active,
+ if called _and_ the user wishes to edit offsets,
gets instance data and show gui
- (see run.py, pump() )
"""
if instances != self._instances:
if self.active is True:
@@ -351,8 +641,8 @@
self.update_gui()
self.container.adaptLayout()
self.container.show()
- self._get_gui_size()
- self.container._setPosition(self.position)
else:
self._reset()
self.container.hide()
+
+ self.container.adaptLayout()