def enable(self): """ plugin method """ if self._enabled is True: return self._editor = scripts.editor.getEditor() #self._camera = self._editor.getActiveMapView().getCamera() self._action_show = Action(u"Camera Editor", checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) self._createGui() self._enabled = True
def enable(self): if self._enabled is True: return self.editor = scripts.editor.getEditor() self.engine = self.editor.getEngine() self._showAction = Action(u"Object selector", checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._showAction) self.editor._tools_menu.addAction(self._showAction) events.postMapShown.connect(self.update_namespace) events.onObjectSelected.connect(self.setPreview) events.onObjectsImported.connect(self.update_namespace) self.buildGui()
def enable(self): """ Enable plugin """ if self._enabled is True: return # Fifedit plugin data self._editor = scripts.editor.getEditor() self._action_show = Action(u"LayerTool", checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) self._createGui() self.toggle() events.postMapShown.connect(self.update) events.preMapClosed.connect(self._mapClosed)
def enable(self): """ enables the plugin and connects to the editor """ if self._enabled: return self._enabled = True # Fifedit plugin data self._action_show = Action(self.getName(), checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) self.load_map_history() self.create() onOpenMapFile.connect(self.update) if self.settings['docked']: self._editor.dockWidgetTo(self.container, self.settings['dockarea'])
def enable(self): """ plugin method """ if self._enabled: return self._enabled = True self._action_show = Action(unicode(self.getName(),"utf-8"), checkable=True) scripts.gui.action.activated.connect(self.toggle_gui, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) onObjectSelected.connect(self.update) onInstancesSelected.connect(self.update) preMapClosed.connect(self.hide) postMapShown.connect(self.update) self.create_gui() self.update_gui() if self.settings['docked']: self._editor.dockWidgetTo(self.container, self.settings['dockarea'])
def enable(self): """ Enable plugin """ if self._enabled: return # Fifedit plugin data self._action_show = Action(u"LayerTool", checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) self.create() self.toggle() events.postMapShown.connect(self.update) events.preMapClosed.connect(self._mapClosed) if self.settings['docked']: self._editor.dockWidgetTo(self.container, self.settings['dockarea'])
def enable(self): """ enables the plugin and connects to the editor """ if self._enabled: return self._enabled = True # Fifedit plugin data self._action_show = Action(self.getName(), checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) postMapShown.connect(self.update) onObjectSelected.connect(self.set_object) onObjectsImported.connect(self.update_namespaces) self.create() self.toggle() if self.settings['docked']: self._editor.dockWidgetTo(self.container, self.settings['dockarea'])
def enable(self): """ plugin method """ if self._enabled is True: return self._editor = scripts.editor.getEditor() self.engine = self._editor.getEngine() self.imagemanager = self.engine.getImageManager() self._showAction = Action(unicode(self.getName(), "utf-8"), checkable=True) scripts.gui.action.activated.connect(self.toggle_gui, sender=self._showAction) self._editor._tools_menu.addAction(self._showAction) events.onInstancesSelected.connect(self.input) self._reset() self.create_gui()
def enable(self): """ plugin method overwrite """ if self._enabled: return self._editor = scripts.editor.getEditor() self._engine = self._editor.getEngine() self._action_show = Action(unicode(self.getName(), "utf-8"), checkable=True) scripts.gui.action.activated.connect(self.toggle_gui, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) events.onCellSelected.connect(self.input) events.preMapClosed.connect(self.hide) events.postMapShown.connect(self.map_shown) events.mousePressed.connect(self.mouse_pressed) self._reset() self.create() self.container.x = 0 self.container.y = 0 self.show()
def enable(self): """ plugin method """ if self._enabled is True: return self._editor = scripts.editor.getEditor() self.engine = self._editor.getEngine() self.imagemanager = self.engine.getImageManager() self._showAction = Action(unicode(self.getName(),"utf-8"), checkable=True) scripts.gui.action.activated.connect(self.toggle_gui, sender=self._showAction) self._editor._tools_menu.addAction(self._showAction) events.onInstancesSelected.connect(self.input) self._reset() self.create_gui()
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._tools_menu.addAction(self._showAction) events.postMapShown.connect(self.update_renderer) events.onMapChanged.connect(self.update_renderer) self._reset() self.create_gui()
def enable(self): """ plugin method overwrite """ if self._enabled: return self._editor = scripts.editor.getEditor() self._engine = self._editor.getEngine() self._action_show = Action(unicode(self.getName(),"utf-8"), checkable=True) scripts.gui.action.activated.connect(self.toggle_gui, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) events.onCellSelected.connect(self.input) events.preMapClosed.connect(self.hide) events.postMapShown.connect(self.map_shown) events.mousePressed.connect(self.mouse_pressed) self._reset() self.create() self.container.x = 0 self.container.y = 0 self.show()
def enable(self): if self._enabled is True: return self.editor = scripts.editor.getEditor() self.engine = self.editor.getEngine() self._show_action = Action(u"History manager", checkable=True) self._undo_action = Action(u"Undo", "gui/icons/undo.png") self._redo_action = Action(u"Redo", "gui/icons/redo.png") self._next_action = Action(u"Next branch", "gui/icons/next_branch.png") self._prev_action = Action(u"Previous branch", "gui/icons/previous_branch.png") self._show_action.helptext = u"Toggle HistoryManager" self._undo_action.helptext = u"Undo action (CTRL+Z)" self._redo_action.helptext = u"Redo action (CTRL+SHIFT+Z)" self._next_action.helptext = u"Next branch (CTRL+ALT+Z" self._prev_action.helptext = u"Previous branch (CTRL+ALT+SHIFT+Z)" scripts.gui.action.activated.connect(self.toggle, sender=self._show_action) scripts.gui.action.activated.connect(self._undo, sender=self._undo_action) scripts.gui.action.activated.connect(self._redo, sender=self._redo_action) scripts.gui.action.activated.connect(self._next, sender=self._next_action) scripts.gui.action.activated.connect(self._prev, sender=self._prev_action) self._undo_group = ActionGroup(name=u"UndoGroup") self._undo_group.addAction(self._undo_action) self._undo_group.addAction(self._redo_action) self._undo_group.addAction(self._next_action) self._undo_group.addAction(self._prev_action) self.editor._tools_menu.addAction(self._show_action) self.editor._edit_menu.insertAction(self._undo_group, 0) self.editor._edit_menu.insertSeparator(position=1) events.postMapShown.connect(self.update) undomanager.changed.connect(self.update) self.buildGui()
class HistoryManager(plugin.Plugin): def __init__(self): self.editor = None self.engine = None self._enabled = False self.undomanager = None def enable(self): if self._enabled is True: return self.editor = scripts.editor.getEditor() self.engine = self.editor.getEngine() self._show_action = Action(u"History manager", checkable=True) self._undo_action = Action(u"Undo", "gui/icons/undo.png") self._redo_action = Action(u"Redo", "gui/icons/redo.png") self._next_action = Action(u"Next branch", "gui/icons/next_branch.png") self._prev_action = Action(u"Previous branch", "gui/icons/previous_branch.png") self._show_action.helptext = u"Toggle HistoryManager" self._undo_action.helptext = u"Undo action (CTRL+Z)" self._redo_action.helptext = u"Redo action (CTRL+SHIFT+Z)" self._next_action.helptext = u"Next branch (CTRL+ALT+Z" self._prev_action.helptext = u"Previous branch (CTRL+ALT+SHIFT+Z)" scripts.gui.action.activated.connect(self.toggle, sender=self._show_action) scripts.gui.action.activated.connect(self._undo, sender=self._undo_action) scripts.gui.action.activated.connect(self._redo, sender=self._redo_action) scripts.gui.action.activated.connect(self._next, sender=self._next_action) scripts.gui.action.activated.connect(self._prev, sender=self._prev_action) self._undo_group = ActionGroup(name=u"UndoGroup") self._undo_group.addAction(self._undo_action) self._undo_group.addAction(self._redo_action) self._undo_group.addAction(self._next_action) self._undo_group.addAction(self._prev_action) self.editor._tools_menu.addAction(self._show_action) self.editor._edit_menu.insertAction(self._undo_group, 0) self.editor._edit_menu.insertSeparator(position=1) events.postMapShown.connect(self.update) undomanager.changed.connect(self.update) self.buildGui() def disable(self): if self._enabled is False: return self.gui.hide() self.removeAllChildren() events.postMapShown.disconnect(self.update) undomanager.changed.disconnect(self.update) scripts.gui.action.activated.connect(self.toggle, sender=self._show_action) scripts.gui.action.activated.disconnect(self._undo, sender=self._undo_action) scripts.gui.action.activated.disconnect(self._redo, sender=self._redo_action) scripts.gui.action.activated.disconnect(self._next, sender=self._next_action) scripts.gui.action.activated.disconnect(self._prev, sender=self._prev_action) self.editor._tools_menu.removeAction(self._show_action) self.editor._tools_menu.removeAction(self._undo_group) def isEnabled(self): return self._enabled; def getName(self): return "History manager" def buildGui(self): self.gui = Panel(title=u"History") self.scrollarea = widgets.ScrollArea(min_size=(200,300)) self.list = widgets.ListBox() self.list.capture(self._itemSelected) self.gui.addChild(self.scrollarea) self.scrollarea.addChild(self.list) self.gui.position_technique = "right:center" def _linearUndo(self, target): mapview = self.editor.getActiveMapView() if mapview is None: return undomanager = mapview.getController().getUndoManager() current_item = undomanager.current_item # Redo? item = current_item count = 0 while item is not None: if item == target: undomanager.redo(count) break count += 1 item = item.next else: # Undo? count = 0 item = current_item while item is not None: if item == target: undomanager.undo(count) break count += 1 item = item.previous else: print "HistoryManager: Didn't find target item!" # Select the current item, important to see if the undo/redo didn't work as expected self.update() def _itemSelected(self): mapview = self.editor.getActiveMapView() if mapview is None: return undomanager = mapview.getController().getUndoManager() stackitem = self.list.selected_item.item if stackitem == undomanager.current_item: return if undomanager.getBranchMode() is False: self._linearUndo(stackitem) return searchlist = [] searchlist2 = [] parent = stackitem branch = parent.next while parent is not None: if parent is undomanager.first_item or len(parent._branches) > 1: searchlist.append( (parent, branch) ) branch = parent parent = parent.parent current_item = undomanager.current_item parent = current_item branch = parent.next while parent is not None: if parent is undomanager.first_item or len(parent._branches) > 1: searchlist2.append( (parent, branch) ) branch = parent parent = parent.parent searchlist.reverse() searchlist2.reverse() # Remove duplicate entries, except the last duplicate, so we don't undo # more items than necessary sl = len(searchlist); if len(searchlist2) < sl: sl = len(searchlist2) for s in range(sl): if searchlist[s][0] != searchlist[s][0]: searchlist = searchlist[s-1:] s_item = searchlist[0][0] # Undo until we reach the first shared parent i = 0 item = current_item while item is not None: if item == s_item: undomanager.undo(i) current_item = item break i += 1 item = item.previous else: print "Nada (undo)" return # Switch branches for s_item in searchlist: if s_item[0].setBranch(s_item[1]) is False: print "Warning: HistoryManager: Switching branch failed for: ", s_item # Redo to stackitem item = current_item i = 0 while item is not None: if item == stackitem: undomanager.redo(i) break i += 1 item = item.next else: print "Nada (redo)" # Select the current item, important to see if the undo/redo didn't work as expected self.update() def recursiveUpdate(self, item, indention, parent=None, branchstr="-"): items = [] branchnr = 0 class _ListItem: def __init__(self, str, item, parent): self.str = str self.item = item self.parent = parent def __str__(self): return self.str.encode("utf-8") while item is not None: listitem = _ListItem(u" "*indention + branchstr + " " + item.object.name, item, parent) items.append(listitem) branchnr = -1 for branch in item.getBranches(): branchnr += 1 if branchnr == 0: continue items.extend(self.recursiveUpdate(branch, indention+2, listitem, str(branchnr))) if self.undomanager.getBranchMode(): if len(item._branches) > 0: item = item._branches[0] else: break else: item = item.next return items def update(self): mapview = self.editor.getActiveMapView() if mapview is None: self.list.items = [] return self.undomanager = undomanager = mapview.getController().getUndoManager() items = [] items = self.recursiveUpdate(undomanager.first_item, 0) self.list.items = items i = 0 for it in items: if it.item == undomanager.current_item: self.list.selected = i break i += 1 self.scrollarea.adaptLayout(False) def show(self): self.update() self.gui.show() self._show_action.setChecked(True) def hide(self): self.gui.setDocked(False) self.gui.hide() self._show_action.setChecked(False) def _undo(self): if self.undomanager: self.undomanager.undo() def _redo(self): if self.undomanager: self.undomanager.redo() def _next(self): if self.undomanager: self.undomanager.nextBranch() def _prev(self): if self.undomanager: self.undomanager.previousBranch() def toggle(self): if self.gui.isVisible() or self.gui.isDocked(): self.hide() else: self.show()
class LayerTool(plugin.Plugin): """ The B{LayerTool} allows to select and show / hide layers of a loaded map as well as creating new layers or edit layer properties """ # default should be pychan default, highlight can be choosen (format: r,g,b) DEFAULT_BACKGROUND_COLOR = pychan.internal.DEFAULT_STYLE['default']['base_color'] HIGHLIGHT_BACKGROUND_COLOR = pychan.internal.DEFAULT_STYLE['default']['selection_color'] # the dynamicly created widgets have the name scheme prefix + layerid LABEL_NAME_PREFIX = "select_" def __init__(self): super(LayerTool, self).__init__() # Editor instance self._editor = scripts.editor.getEditor() # Plugin variables self._enabled = False # Current mapview self._mapview = None # Toolbar button to display LayerTool self._action_show = None # GUI self._layer_wizard = None self.container = None self.wrapper = None self.remove_layer_button = None self.create_layer_button = None self.edit_layer_button = None self.default_settings = _PLUGIN_SETTINGS self.eds = self._editor._settings self.update_settings() #--- Plugin functions ---# def enable(self): """ Enable plugin """ if self._enabled: return # Fifedit plugin data self._action_show = Action(u"LayerTool", checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) self.create() self.toggle() events.postMapShown.connect(self.update) events.preMapClosed.connect(self._mapClosed) if self.settings['docked']: self._editor.dockWidgetTo(self.container, self.settings['dockarea']) def disable(self): """ Disable plugin """ if not self._enabled: return self.container.setDocked(False) self.container.hide() events.postMapShown.disconnect(self.update) events.preMapClosed.disconnect(self._mapClosed) self._editor._tools_menu.removeAction(self._action_show) def isEnabled(self): """ Returns True if plugin is enabled """ return self._enabled; def getName(self): """ Return plugin name """ return u"Layertool" #--- End plugin functions ---# def _mapClosed(self): self.update(mapview=None) def showLayerWizard(self): """ Show layer wizard """ if not self._mapview: return if self._layer_wizard: self._layer_wizard._widget.hide() self._layer_wizard = LayerDialog(self._editor.getEngine(), self._mapview.getMap(), callback=self._layerCreated) def showEditDialog(self): """ Show layerdialog for active layer """ if not self._mapview: return layer = self.getActiveLayer() if not layer: return if self._layer_wizard: self._layer_wizard._widget.hide() self._layer_wizard = LayerDialog(self._editor.getEngine(), self._mapview.getMap(), layer=layer, callback=cbwa(self.update, self._mapview)) def clear(self): """ Remove all subwrappers """ self.wrapper.removeAllChildren() def update(self, mapview): """ Update layertool with information from mapview We group one ToggleButton and one Label into a HBox, the main wrapper itself is a VBox and we also capture both the Button and the Label to listen for mouse actions @type event: object @param event: pychan mouse event """ layers = [] self._mapview = mapview if self._mapview is not None: layers = self._mapview.getMap().getLayers() self.clear() if len(layers) <= 0: if not self._mapview: layerid = "No map is open" else: layerid = "No layers" subwrapper = pychan.widgets.HBox() layerLabel = pychan.widgets.Label() layerLabel.text = unicode(layerid) layerLabel.name = LayerTool.LABEL_NAME_PREFIX + layerid subwrapper.addChild(layerLabel) self.wrapper.addChild(subwrapper) active_layer = self.getActiveLayer() if active_layer: active_layer = active_layer.getId() for layer in reversed(layers): layerid = layer.getId() subwrapper = pychan.widgets.HBox() toggleVisibleButton = pychan.widgets.ToggleButton(hexpand=False, up_image="gui/icons/is_visible.png", down_image="gui/icons/is_visible.png", hover_image="gui/icons/is_visible.png") toggleVisibleButton.name = "toggle_" + layerid if layer.areInstancesVisible(): toggleVisibleButton.toggled = True toggleVisibleButton.capture(self.toggleLayerVisibility) layerLabel = pychan.widgets.Label() layerLabel.text = unicode(layerid) layerLabel.name = LayerTool.LABEL_NAME_PREFIX + layerid layerLabel.capture(self.selectLayer,"mousePressed") if active_layer == layerid: layerLabel.background_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR layerLabel.foreground_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR layerLabel.base_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR subwrapper.addChild(toggleVisibleButton) subwrapper.addChild(layerLabel) self.wrapper.addChild(subwrapper) self.container.adaptLayout() def toggleLayerVisibility(self, event, widget): """ Callback for ToggleButtons Toggle the chosen layer visible / invisible. If the active layer is hidden, it will be deselected. @type event: object @param event: pychan mouse event @type widget: object @param widget: the pychan widget where the event occurs, transports the layer id in it's name """ layerid = widget.name[len(LayerTool.LABEL_NAME_PREFIX):] layer = self._mapview.getMap().getLayer(layerid) active_layer = self.getActiveLayer() if active_layer: active_layer = active_layer.getId() if layer.areInstancesVisible(): layer.setInstancesVisible(False) else: layer.setInstancesVisible(True) if active_layer == layerid: self.resetSelection() def getActiveLayer(self): """ Returns the active layer """ if self._mapview: return self._mapview.getController()._layer def selectLayer(self, event, widget=None, layerid=None): """ Callback for Labels We hand the layerid over to the mapeditor module to select a new active layer Additionally, we mark the active layer widget (changing base color) and reseting the previous one @type event: object @param event: pychan mouse event @type widget: object @param widget: the pychan widget where the event occurs, transports the layer id in it's name @type layerid: string @param layerid: the layer id """ if not widget and not layerid: print "No layer ID or widget passed to LayerTool.selectLayer" return if widget is not None: layerid = widget.name[len(LayerTool.LABEL_NAME_PREFIX):] self.resetSelection() widget.background_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR widget.foreground_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR widget.base_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR self._mapview.getController().selectLayer(layerid) def resetSelection(self): """ Deselects selected layer """ previous_active_layer = self.getActiveLayer() if previous_active_layer is not None: previous_layer_id = previous_active_layer.getId() previous_active_widget = self.container.findChild(name=LayerTool.LABEL_NAME_PREFIX + previous_layer_id) previous_active_widget.background_color = LayerTool.DEFAULT_BACKGROUND_COLOR previous_active_widget.foreground_color = LayerTool.DEFAULT_BACKGROUND_COLOR previous_active_widget.base_color = LayerTool.DEFAULT_BACKGROUND_COLOR previous_active_widget.text = unicode(previous_layer_id) self._mapview.getController().selectLayer(None) def removeSelectedLayer(self): """ Deletes the selected layer """ if not self._mapview: return if self._mapview.getMap().getLayerCount() <= 1: print "Can't remove the last layer" return layer = self.getActiveLayer() if not layer: return self.resetSelection() map = self._mapview.getMap() # FIFE will crash if we try to delete the layer which is in use by a camera # so we will set the camera to another layer instead for cam in map.getCameras(): if cam.getLocationRef().getMap().getId() != map.getId(): continue if cam.getLocation().getLayer().getId() != layer.getId(): continue for l in map.getLayers(): if l.getId() == layer.getId(): continue cam.getLocationRef().setLayer(l) break map.deleteLayer(layer) self.update(self._mapview) def toggle(self): """ Toggles the layertool visible / invisible and sets dock status """ if self.container.isVisible() or self.container.isDocked(): self.container.setDocked(False) self.container.hide() self._action_show.setChecked(False) else: self.container.show() self._action_show.setChecked(True) self._adjustPosition() def create(self): """ Create the basic gui container """ self.container = pychan.loadXML('gui/layertool.xml') self.wrapper = self.container.findChild(name="layers_wrapper") self.remove_layer_button = self.container.findChild(name="remove_layer_button") self.create_layer_button = self.container.findChild(name="add_layer_button") self.edit_layer_button = self.container.findChild(name="edit_layer_button") self.remove_layer_button.capture(self.removeSelectedLayer) self.remove_layer_button.capture(cbwa(self._editor.getStatusBar().showTooltip, self.remove_layer_button.helptext), 'mouseEntered') self.remove_layer_button.capture(self._editor.getStatusBar().hideTooltip, 'mouseExited') self.create_layer_button.capture(self.showLayerWizard) self.create_layer_button.capture(cbwa(self._editor.getStatusBar().showTooltip, self.create_layer_button.helptext), 'mouseEntered') self.create_layer_button.capture(self._editor.getStatusBar().hideTooltip, 'mouseExited') self.edit_layer_button.capture(self.showEditDialog) self.edit_layer_button.capture(cbwa(self._editor.getStatusBar().showTooltip, self.edit_layer_button.helptext), 'mouseEntered') self.edit_layer_button.capture(self._editor.getStatusBar().hideTooltip, 'mouseExited') self.update(None) # overwrite Panel.afterUndock self.container.afterUndock = self.on_undock self.container.afterDock = self.on_dock def on_dock(self): """ callback for dock event of B{Panel} widget """ side = self.container.dockarea.side if not side: return module = self.default_settings['module'] self.eds.set(module, 'dockarea', side) self.eds.set(module, 'docked', True) def on_undock(self): """ callback for undock event of B{Panel} widget """ self.container.hide() self.toggle() module = self.default_settings['module'] self.eds.set(module, 'dockarea', '') self.eds.set(module, 'docked', False) def _adjustPosition(self): """ Adjusts the position of the container - we don't want to let the window appear at the center of the screen. (new default position: left, beneath the tools window) """ self.container.position = (50, 200) def _layerCreated(self, layer): self.update(self._mapview) self.selectLayer(None, self.wrapper.findChild(name=LayerTool.LABEL_NAME_PREFIX + layer.getId()))
class ObjectSelector(plugin.Plugin): """The ObjectSelector class offers a gui Widget that let's you select the object you wish to use to in the editor. @param engine: fife instance @param map: fife.Map instance containing your map @param selectNotify: callback function used to tell the editor you selected an object. """ def __init__(self): self.editor = None self.engine = None self.mode = 'list' # Other mode is 'preview' self._enabled = False self.object = None self.rotation = 45 self.action = 'default' def enable(self): if self._enabled is True: return self.editor = scripts.editor.getEditor() self.engine = self.editor.getEngine() self._showAction = Action(u"Object selector", checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._showAction) self.editor._tools_menu.addAction(self._showAction) events.postMapShown.connect(self.update_namespace) events.onObjectSelected.connect(self.setPreview) events.onObjectsImported.connect(self.update_namespace) self.buildGui() def disable(self): if self._enabled is False: return self.gui.hide() self.removeAllChildren() events.postMapShown.disconnect(self.update_namespace) events.onObjectSelected.disconnect(self.setPreview) events.onObjectsImported.disconnect(self.update_namespace) self.editor._tools_menu.removeAction(self._showAction) def isEnabled(self): return self._enabled; def getName(self): return "Object selector" def buildGui(self): self.gui = pychan.loadXML('gui/objectselector.xml') # Add search field self._searchfield = self.gui.findChild(name="searchField") self._searchfield.capture(self._search) self._searchfield.capture(self._search, "keyPressed") self.gui.findChild(name="searchButton").capture(self._search) # Add the drop down with list of namespaces self.namespaces = self.gui.findChild(name="namespaceDropdown") self.namespaces.items = self.engine.getModel().getNamespaces() self.namespaces.selected = 0 # TODO: Replace with SelectionEvent, once pychan supports it self.namespaces.capture(self.update_namespace, "action") self.namespaces.capture(self.update_namespace, "mouseWheelMovedUp") self.namespaces.capture(self.update_namespace, "mouseWheelMovedDown") self.namespaces.capture(self.update_namespace, "keyReleased") self.rotations = self.gui.findChild(name="rotationDropdown") self.rotations.capture(self.update_rotations, "action") self.rotations.capture(self.update_rotations, "mouseWheelMovedUp") self.rotations.capture(self.update_rotations, "mouseWheelMovedDown") self.rotations.capture(self.update_rotations, "keyReleased") self.actions = self.gui.findChild(name="actionDropdown") self.actions.capture(self.update_actions, "action") self.actions.capture(self.update_actions, "mouseWheelMovedUp") self.actions.capture(self.update_actions, "mouseWheelMovedDown") self.actions.capture(self.update_actions, "keyReleased") # Object list self.mainScrollArea = self.gui.findChild(name="mainScrollArea") self.objects = None if self.mode == 'list': self.setTextList() else: # Assuming self.mode is 'preview' self.setImageList() # Action buttons self.gui.findChild(name="toggleModeButton").capture(self.toggleMode) self.gui.findChild(name="closeButton").capture(self.hide) # Preview area self.gui.findChild(name="previewScrollArea").background_color = self.gui.base_color self.preview = self.gui.findChild(name="previewIcon") def toggleMode(self): if self.mode == 'list': self.setImageList() self.mode = 'preview' elif self.mode == 'preview': self.setTextList() self.mode = 'list' self.update() def setImageList(self): """Sets the mainScrollArea to contain a Vbox that can be used to fill in preview Images""" if self.objects is not None: self.mainScrollArea.removeChild(self.objects) self.objects = ObjectIconList(name='list', size=(200,1000)) self.objects.base_color = self.mainScrollArea.background_color self.mainScrollArea.addChild(self.objects) def setTextList(self): """Sets the mainScrollArea to contain a List that can be used to fill in Object names/paths""" if self.objects is not None: self.mainScrollArea.removeChild(self.objects) self.objects = widgets.ListBox(name='list') self.objects.capture(self.listEntrySelected) self.mainScrollArea.addChild(self.objects) def _search(self): self.search(self._searchfield.text) def search(self, str): results = [] # Format search terms terms = [term.lower() for term in str.split()] # Search if len(terms) > 0: namespaces = self.engine.getModel().getNamespaces() for namesp in namespaces: objects = self.engine.getModel().getObjects(namesp) for obj in objects: doAppend = True for term in terms: if obj.getId().lower().find(term) < 0: doAppend = False break if doAppend: results.append(obj) else: results = None if self.mode == 'list': self.fillTextList(results) elif self.mode == 'preview': self.fillPreviewList(results) def fillTextList(self, objects=None): if objects is None: if self.namespaces.selected_item is None: return objects = self.engine.getModel().getObjects(self.namespaces.selected_item) class _ListItem: def __init__( self, name, namespace ): self.name = name self.namespace = namespace def __str__( self ): return self.name self.objects.items = [_ListItem(obj.getId(), obj.getNamespace()) for obj in objects] if not self.object: if self.namespaces.selected_item: self.objects.selected = 0 self.listEntrySelected() else: for i in range(0, len(self.objects.items)): if self.objects.items[i].name != self.object.getId(): continue if self.objects.items[i].namespace != self.object.getNamespace(): continue self.objects.selected = i break self.mainScrollArea.adaptLayout(False) scrollY = (self.objects.real_font.getHeight() + 0) * self.objects.selected self.mainScrollArea.real_widget.setVerticalScrollAmount(scrollY) def listEntrySelected(self): """This function is used as callback for the TextList.""" if self.objects.selected_item: object_id = self.objects.selected_item.name namespace = self.objects.selected_item.namespace obj = self.engine.getModel().getObject(object_id, namespace) self.objectSelected(obj) def fillPreviewList(self, objects=None): self.objects.clear() if objects is None: if self.namespaces.selected_item is None: return objects = self.engine.getModel().getObjects(self.namespaces.selected_item) for obj in objects: image = self._getImage(obj) if image is None: print 'No image available for selected object' image = "" callback = tools.callbackWithArguments(self.objectSelected, obj) icon = ObjectIcon(callback=callback, image=image, text=unicode(obj.getId())) self.objects.addChild(icon) if obj == self.object: icon.selected = True if not self.object: if len(objects) > 0: self.objectSelected(objects[0]) self.mainScrollArea.adaptLayout(False) self.mainScrollArea.real_widget.setVerticalScrollAmount(self.objects.selected_item.y) def objectSelected(self, obj): """This is used as callback function to notify the editor that a new object has been selected. @param obj: fife.Object instance""" self.setPreview(obj) events.onObjectSelected.send(sender=self, object=obj) self.gui.adaptLayout(False) # Set preview image def setPreview(self, object, forceUpdate=False): if not object: return if not forceUpdate and self.object and object == self.object: return self.object = object self.scrollToObject(object) self.preview.image = self._getImage(object) self.actions.items = self.object.getActionIds() if self.actions.selected_item is None: self.actions.selected = 0 self.rotations.items = self.object.getAction(self.actions.selected_item).get2dGfxVisual().getActionImageAngles() if self.rotations.selected_item is None: self.rotations.selected = 0 height = self.preview.image.getHeight(); if height > 200: height = 200 self.preview.parent.max_height = height def scrollToObject(self, object): # Select namespace names = self.namespaces if not names.selected_item: self.namespaces.selected = 0 if names.selected_item != object.getNamespace(): for i in range(0, len(names.items)): if names.items[i] == object.getNamespace(): self.namespaces.selected = i break self.update() def update_namespace(self): self.namespaces.items = self.engine.getModel().getNamespaces() if not self.namespaces.selected_item: self.namespaces.selected = 0 if self.mode == 'list': self.setTextList() elif self.mode == 'preview': self.setImageList() self.update() def update_rotations(self): """Called when the rotation dropdown is changed/selected""" if not self.rotations.selected_item: self.rotations.selected = 0 self.rotation = self.rotations.selected_item self.setPreview(self.object, forceUpdate=True) def update_actions(self): """Called when the action dropdown is changed/selected""" if not self.actions.selected_item: self.actions.selected = 0 self.action = self.actions.selected_item self.setPreview(self.object, forceUpdate=True) def update(self): if self.mode == 'list': self.fillTextList() elif self.mode == 'preview': self.fillPreviewList() self.gui.adaptLayout(False) def _getImage(self, obj): """ Returns an image for the given object. @param: fife.Object for which an image is to be returned @return: fife.GuiImage""" visual = None try: visual = obj.get2dGfxVisual() except: print 'Visual Selection created for type without a visual?' raise # Try to find a usable image index = visual.getStaticImageIndexByAngle(self.rotation) image = None # if no static image available, try default action if index == -1: action = obj.getAction(self.action) if action: animation_id = action.get2dGfxVisual().getAnimationIndexByAngle(self.rotation) animation = self.engine.getAnimationPool().getAnimation(animation_id) image = animation.getFrameByTimestamp(0) index = image.getPoolId() # Construct the new GuiImage that is to be returned if index != -1: image = fife.GuiImage(index, self.engine.getImagePool()) return image def show(self): self.update_namespace() self.gui.show() self._showAction.setChecked(True) def hide(self): self.gui.setDocked(False) self.gui.hide() self._showAction.setChecked(False) def toggle(self): if self.gui.isVisible() or self.gui.isDocked(): self.hide() else: self.show()
class ObjectEdit(plugin.Plugin): """ The B{ObjectEdit} module is a plugin for FIFedit and allows to edit 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 offsets, rotation, instance id - save offsets to object file - outline highlighting of the selected object - animation viewer """ 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.guidata = {} self.objectdata = {} self._help_dialog = None def _reset(self): """ 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 self._object_blocking = 0 self._instance_blocking = 0 self._static = 0 self._object_id = None self._instance_id = None self._fixed_rotation = None if self._camera is not None: self.renderer.removeAllOutlines() def enable(self): """ plugin method """ if self._enabled is True: return self._editor = scripts.editor.getEditor() self.engine = self._editor.getEngine() self.imagepool = self.engine.getImagePool() self._animationpool = self.engine.getAnimationPool() self._showAction = Action(unicode(self.getName(), "utf-8"), checkable=True) scripts.gui.action.activated.connect(self.toggle_gui, sender=self._showAction) self._editor._tools_menu.addAction(self._showAction) events.onInstancesSelected.connect(self.input) events.preMapClosed.connect(self.hide) events.preMapShown.connect(self.hide) self._reset() self.create_gui() def disable(self): """ plugin method """ if self._enabled is False: return self._reset() self.container.hide() self.removeAllChildren() events.onInstancesSelected.disconnect(self.input) events.preMapClosed.disconnect(self.hide) events.preMapShown.disconnect(self.hide) self._editor._tools_menu.removeAction(self._showAction) def isEnabled(self): """ plugin method """ return self._enabled def getName(self): """ plugin method """ return "Object editor" def _show_help(self): """ shows the help dialog """ if self._help_dialog is not None: self._help_dialog.show() return self._help_dialog = pychan.loadXML("gui/help.xml") self._help_dialog.title = u"Help (Object Editor)" self._help_dialog.mapEvents({ "closeButton": self._help_dialog.hide, }) # gimme some more space _SIZE = (320, 400) scrollarea = self._help_dialog.findChildren( __class__=pychan.widgets.ScrollArea)[0] scrollarea.size = _SIZE scrollarea.min_size = _SIZE scrollarea.max_size = _SIZE f = open('lang/help_object_edit.txt', 'r') self._help_dialog.findChild(name="helpText").text = unicode(f.read()) f.close() self._help_dialog.show() 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, '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, 'show_help': self._show_help, }) self.container.findChild(name="x_offset_up").capture( self.change_offset, "mousePressed") self.container.findChild(name="x_offset_dn").capture( self.change_offset, "mousePressed") self._gui_x_offset = self.container.findChild(name="x_offset") self._gui_x_offset.capture(self.change_offset, "mouseWheelMovedUp") self._gui_x_offset.capture(self.change_offset, "mouseWheelMovedDown") self.container.findChild(name="y_offset_up").capture( self.change_offset, "mousePressed") self.container.findChild(name="y_offset_dn").capture( self.change_offset, "mousePressed") self._gui_y_offset = self.container.findChild(name="y_offset") self._gui_y_offset.capture(self.change_offset, "mouseWheelMovedUp") self._gui_y_offset.capture(self.change_offset, "mouseWheelMovedDown") self.container.findChild(name="object_blocking_toggle").capture( self.object_blocking_toggle, "mousePressed") self.container.findChild(name="instance_blocking_toggle").capture( self.instance_blocking_toggle, "mousePressed") 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_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_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 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) """ 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 else: self._anim_data['current'] = self._anim_data['frames'] 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_data['current'] < self._anim_data['frames']: self._anim_data['current'] += 1 else: self._anim_data['current'] = 0 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 update_gui(self): """ updates the gui widgets with current instance data """ if self._instances is None: return # 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) if self._instances[0].isOverrideBlocking(): self.container.findChild( name="override_blocking_toggle")._setMarked(True) else: self.container.findChild( name="override_blocking_toggle")._setMarked(False) 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), 'instance_blocking': unicode(self._instance_blocking), 'object_blocking': unicode(self._object_blocking), 'object_static': unicode(self._static), }) if not self._animation: if self._fixed_rotation in self._avail_rotations: index = self._avail_rotations.index(self._fixed_rotation) self._gui_rotation_dropdown._setSelected(index) # else: # print "Internal FIFE rotation: ", self._instances[0].getRotation() # print "Fixed rotation (cam rot) ", self._fixed_rotation + int(abs(self._camera.getRotation())) # print "Collected rots from object ", self._avail_rotations self.container.adaptLayout(False) def toggle_gui(self): """ show / hide the gui """ if self.active is True: 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) def highlight_selected_instance(self): """ highlights selected instance """ self.renderer.removeAllOutlines() self.renderer.addOutlined(self._instances[0], WHITE["r"], WHITE["g"], WHITE["b"], OUTLINE_SIZE) def change_offset(self, event, widget): """ widget callback: change the offset of an object @type event: object @param event: FIFE mouseevent or keyevent @type widget: object @param widget: pychan widget """ if self._animation: self._editor.getStatusBar().setText( u"Offset changes of animations are not supported yet") return etype = event.getType() x = self._image.getXShift() y = self._image.getYShift() if etype == fife.MouseEvent.WHEEL_MOVED_UP or widget.name.endswith( "up"): modifier = 1 elif etype == fife.MouseEvent.WHEEL_MOVED_DOWN or widget.name.endswith( "dn"): modifier = -1 if widget.name.startswith("x"): x += modifier elif widget.name.startswith("y"): y += modifier self.set_offset(x, y) self.update_gui() def object_blocking_toggle(self, event, widget): """ widget callback: change the blocking of an instance @type event: object @param event: FIFE mouseevent or keyevent @type widget: object @param widget: pychan widget """ self.check_override_blocking() object = self._instances[0].getObject() object_id = object.getId() blocking = not object.isBlocking() object.setBlocking(blocking) instances = self._layer.getInstances() for instance in instances: object = instance.getObject() if object.getId() == object_id: instance.setBlocking(blocking) self._object_blocking = int(blocking) self._instance_blocking = int(self._instances[0].isBlocking()) self.update_gui() def instance_blocking_toggle(self, event, widget): """ widget callback: change the blocking of an instance @type event: object @param event: FIFE mouseevent or keyevent @type widget: object @param widget: pychan widget """ self.check_override_blocking() instance = self._instances[0] instance.setBlocking(not instance.isBlocking()) self._instance_blocking = int(instance.isBlocking()) self.update_gui() def check_override_blocking(self): instance = self._instances[0] marked = self.container.findChild( name="override_blocking_toggle")._isMarked() if marked: instance.setOverrideBlocking(True) else: instance.setOverrideBlocking(False) def use_user_data(self): """ - takes the users values and applies them directly to the current ._instance - 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... """ instance_id = str(self._gui_instance_id_textfield._getText()) msg = '' 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: self._instances[0].setId(instance_id) msg = unicode("Set new instance id: " + str(instance_id)) self._editor.getStatusBar().setText(msg) else: self._editor.getStatusBar().setText( u"Instance ID is already in use.") if self._animation: msg = msg + "\n" + u"Editing offset and rotation of animated instances is not supported yet" self._editor.getStatusBar().setText(msg) return xoffset = self._gui_xoffset_textfield._getText() yoffset = self._gui_yoffset_textfield._getText() # 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) 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"] == str(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 block = self.tree.getroot() block.attrib["blocking"] = str(int(self._object_blocking)) xmlcontent = ET.tostring(self.tree.getroot()) # save xml data beneath the <?fife type="object"?> definition into the object file tmp = open(file, 'w') tmp.write('<?fife type="object"?>\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]) 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) 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 """ visual = None self._avail_rotations = [] if instance is None: 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 == '': self._instance_id = 'None' if angle == -1: angle = int(instance.getRotation()) else: angle = int(angle) self._rotation = angle if object.isBlocking(): self._object_blocking = 1 if instance.isBlocking(): self._instance_blocking = 1 if object.isStatic(): self._static = 1 try: visual = object.get2dGfxVisual() except: self._editor.getStatusBar().setText( u"Fetching visual of object failed") raise self._fixed_rotation = instance.getRotation() index = visual.getStaticImageIndexByAngle(self._fixed_rotation) 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 = 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: 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: self._avail_rotations = object.getDefaultAction().get2dGfxVisual( ).getActionImageAngles() def show(self): """ show the plugin gui - and update it """ self.update_gui() self.container.show() self.container.adaptLayout(False) def hide(self): """ hide the plugin gui - and reset it """ self.container.hide() self._reset() def input(self, instances): """ if called _and_ the user wishes to edit offsets, gets instance data and show gui (we only use the top instance of the selected cell) @type instances: list @param instances: a list of instances in the selected cell """ if instances != self._instances: if self.active is True: self._reset() self._instances = instances if self._camera is None: self._camera = self._editor.getActiveMapView().getCamera() self.renderer = fife.InstanceRenderer.getInstance( self._camera) self._layer = self._editor.getActiveMapView().getController( )._layer if self._instances: self.highlight_selected_instance() self.get_instance_data() self.show() else: self.hide()
class CellView(plugin.Plugin): """ A simple plugin to control StackPos attribute of fife.Instance -> 2dGfxVisual """ def __init__(self): """ """ self._camera = None self._renderer = None self._controller = None self.__cell = None self.mode = _DEFAULT_MODE self._enabled = False self._action_show = None self.container = None self.wrapper = None self._help_dialog = None self.attrSetCallback = pychan.tools.attrSetCallback self.active = None self.previous = None # FIXME: fields should store ModelCoordinate later instead of str self.transition = { 'start' : '', 'end' : '', } def _reset(self): """ reset dynamic data """ self._instances = [] self.active = None self.previous = None self.__cell = None self._location = None if self._help_dialog: self._help_dialog.hide() if self.wrapper: self.wrapper.removeAllChildren() if self.container: self.set_mode() wdgt = self.container.findChild(name="cell_coords") wdgt.text = unicode("- : -", 'utf-8') # cleanup controller changes made by this plugin if self._controller: self._controller._single_instance = False self._controller._instance = None def _show_help(self): """ shows the help dialog """ if self._help_dialog is not None: self._help_dialog.show() return self._help_dialog = pychan.loadXML("gui/help.xml") self._help_dialog.title = u"Help (CellView)" self._help_dialog.mapEvents({ "closeButton" : self._help_dialog.hide, }) # gimme some more space _SIZE = (320,400) scrollarea = self._help_dialog.findChildren(__class__=pychan.widgets.ScrollArea)[0] scrollarea.size = _SIZE scrollarea.min_size = _SIZE scrollarea.max_size = _SIZE f = open('lang/help_cellview.txt', 'r') self._help_dialog.findChild(name="helpText").text = unicode(f.read(), 'utf-8') f.close() self._help_dialog.show() def enable(self): """ plugin method overwrite """ if self._enabled: return self._editor = scripts.editor.getEditor() self._engine = self._editor.getEngine() self._action_show = Action(unicode(self.getName(),"utf-8"), checkable=True) scripts.gui.action.activated.connect(self.toggle_gui, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) events.onCellSelected.connect(self.input) events.preMapClosed.connect(self.hide) events.postMapShown.connect(self.map_shown) events.mousePressed.connect(self.mouse_pressed) self._reset() self.create() self.container.x = 0 self.container.y = 0 self.show() def disable(self): """ plugin method """ if not self._enabled: return self._reset() self.wrapper = None self.container.setDocked(False) self.container.hide() events.onInstancesSelected.disconnect(self.input) events.preMapClosed.disconnect(self.hide) events.preMapShown.disconnect(self.map_shown) events.mousePressed.disconnect(self.mouse_pressed) self._editor._tools_menu.removeAction(self._action_show) def isEnabled(self): """ plugin method """ return self._enabled; def getName(self): """ plugin method """ return "Cell view" def create(self): """ create gui sceleton """ if self.container: return self.container = pychan.loadXML('gui/cellview.xml') self.wrapper = self.container.findChild(name="cell_instance_wrapper") btn = self.container.findChild(name="show_help") btn.capture(self._show_help, 'mousePressed') # create callbacks for section hiding for wdgt_name in _SECTION_TO_WRAPPER.keys(): wdgt = self.container.findChild(name=wdgt_name) wdgt.capture(self.cb_toggle_section, "mousePressed") # create callbacks for cell blocking policy manipulation for name in _WDGT_NAME_TO_CELL_TYPE: value = _WDGT_NAME_TO_CELL_TYPE[name] wdgt = self.container.findChild(name=name) if not wdgt: continue wdgt.capture(cbwa(self.set_cell_blocking_policy, value), "mousePressed") # create callback for setting the expert mode wdgt = self.container.findChild(name='expert_mode') wdgt.capture(self.updateMode, "mousePressed") # create callback for setting the speed multiplier wdgt = self.container.findChild(name='apply_speed_multiplier') wdgt.capture(self.set_cell_speed_multiplier, "mousePressed") # create callback for setting the default cost_multiplier wdgt = self.container.findChild(name='apply_cost_multiplier') wdgt.capture(self.set_cell_default_cost_multiplier, "mousePressed") # create callbacks for mini editor wdgt = self.container.findChild(name="mini_editor_cost_save") wdgt.capture(self.mini_editor_create_cost, "mousePressed") # hide mini editor for cost entries self.minieditor = self.container.findChild(name='cost_mini_editor') self.minieditor.hide() # create callback to control the mini editor wdgt = self.container.findChild(name='add_cost_entry') wdgt.capture(self.minieditor.show, 'mousePressed') wdgt = self.container.findChild(name="edit_current_cost_entry") wdgt.capture(self.mini_editor_edit_cost, 'mousePressed') wdgt = self.container.findChild(name="remove_current_cost_entry") wdgt.capture(self.mini_editor_remove_cost, 'mousePressed') # create fancy callbacks for mouse actions on the listbox listbox = self.container.findChild(name="cost_entries") listbox.capture(self.mini_editor_edit_cost, 'mousePressed') # transition wdgt = self.container.findChild(name="transition_start") wdgt.capture(cbwa(self.transition_set, start=1), 'mousePressed') wdgt = self.container.findChild(name="transition_end") wdgt.capture(cbwa(self.transition_set, end=1), 'mousePressed') wdgt.hide() wdgt = self.container.findChild(name="transition_create") wdgt.capture(cbwa(self.transition_set, create=1), 'mousePressed') wdgt.hide() wdgt = self.container.findChild(name="transition_immediate") wdgt.hide() self.container.hide() def transition_set(self, start=0, end=0, create=0): """ create transition data and the transition itself if we have all data @todo: - split this function up - click on ToggleButtons should focus cam on the corresponding cell - split set/unset code like that: - 1st click on button -> collect data - RMB on button -> delete data - 2nd click on button -> focus the cell with cam - we should store all transition attempts in a datastructure instead of erasing it with each update - update() should be locked if we are in the "click transition target"-mode """ if self.__cell is None: return tbtn = self.container.findChild(name="transition_end") btn = self.container.findChild(name="transition_create") chkbox = self.container.findChild(name="transition_immediate") if start: if self.transition['start']: tbtn.hide() btn.hide() chkbox.hide() self.transition['start'] = '' else: self.transition['start'] = 'put start coords here' tbtn.show() if end: if self.transition['end']: self.transition['end'] = '' btn.hide() chkbox.hide() else: self.transition['end'] = 'put end coords here' btn.show() chkbox.show() # create or destroy previous transition if create: if self.transition['start'] and self.transition['end']: wdgt = self.container.findChild(name="transition_immediate") immediate = False if wdgt.marked: immediate = True def set_mode(self, mode=_DEFAULT_MODE): """ set the mode for the plugin @type mode: str @param mode: key for the _MODES dict """ if mode in _MODES: self.mode = mode if self.mode is None: return # update 'current mode' widget lbl = self.container.findChild(name='current_mode') lbl.text = u"Current mode: " + self.mode # show / hide all sections according to the new mode # show for section in _MODES[self.mode]['show']: self.show_section(section=section) # hide for section in _MODES[self.mode]['disable']: self.hide_section(section=section) self.container.adaptLayout(True) def mini_editor_remove_cost(self): """ delete the current selected cost entry @todo: - do we need one of those annoying pop-ups here to ask "do you really want to delete this"? """ if self.__cell is None: return msg = '' listbox = self.container.findChild(name="cost_entries") if len(listbox.items) == 0: return index = listbox.selected cost_id = listbox.items[index] cache = self.__cell.getLayer().getCellCache() print cost_id print cache.getCellCosts(self.__cell) try: cache.removeCellFromCost(str(cost_id), self.__cell) print cache.getCellCosts(self.__cell) except: msg = self.getName() + "Plugin: Error! Couldn't remove cost from cell" else: msg = self.getName() + "Plugin: Success! Cost was removed from cell" self.update() if msg == '': self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) def mini_editor_edit_cost(self, event=None, widget=None): """ edit the given current selected cost entry by reading the values into the mini editor & show it We also check if RMB was pressed on the listbox and return otherwise @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ if self.__cell is None: return if widget is not None: if widget.name == 'cost_entries' and event.getButton() != fife.MouseEvent.RIGHT: return wdgt_id = self.container.findChild(name="mini_editor_cost_id") wdgt_val = self.container.findChild(name="mini_editor_cost_value") listbox = self.container.findChild(name="cost_entries") index = listbox.selected if len(listbox.items) == 0: return cost_id = listbox.items[index] cost_val = self.__cell.getLayer().getCellCache().getCost(cost_id) wdgt_id.text = unicode(cost_id, 'utf-8') wdgt_val.text = unicode(str(cost_val), 'utf-8') self.minieditor.show() def mini_editor_create_cost(self, event=None, widget=None): """ read out data from the mini editor and apply it if possible @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ if event is None and widget is None: return if widget is None: return if self.__cell is None: return msg = '' wdgt_id = self.container.findChild(name="mini_editor_cost_id") wdgt_val = self.container.findChild(name="mini_editor_cost_value") cost_id = wdgt_id.text cost_value = wdgt_val.text try: cost_value = float(cost_value) except: msg = self.getName() + "Plugin: new cost value has to be a float" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) else: cache = self.__cell.getLayer().getCellCache() cache.registerCost(str(cost_id), cost_value) cache.addCellToCost(str(cost_id), self.__cell) msg = self.getName() + "Plugin: Success! New cost id and value saved to cell" self.update() if msg: self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) def set_cell_default_cost_multiplier(self): """ set the default cost multiplier of the current selected cell """ if self.__cell is None: msg = self.getName() + "Plugin: no cell selected, aborting update of default cost multiplier" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) return if not hasattr(self.__cell, 'setCostMultiplier'): msg = self.getName() + "Plugin: wrong fife version, cell lacks method 'setCostMultiplier'" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) return msg = '' wdgt = self.container.findChild(name="default_cost_multiplier") default_cost_multiplier = wdgt.text try: default_cost_multiplier = float(default_cost_multiplier) except: msg = self.getName() + "Plugin: wrong value type for default cost multiplier, must be float" else: try: self.__cell.setCostMultiplier(default_cost_multiplier) except: msg = self.getName() + "Plugin: something went wrong - couldn't set default cost multiplier for current cell" else: msg = self.getName() + "Plugin: Success! Set new default cost multiplier for current cell to %s" % default_cost_multiplier if msg: self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) def set_cell_speed_multiplier(self): """ set the current user input for the cell's speed multiplier """ if self.__cell is None: msg = self.getName() + "Plugin: no cell selected, aborting update of speed multiplier" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) return if not hasattr(self.__cell, 'setSpeedMultiplier'): msg = self.getName() + "Plugin: wrong fife version, cell lacks method 'setSpeedMultiplier'" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) return msg = '' wdgt = self.container.findChild(name="speed_multiplier") speed_multiplier = wdgt.text try: speed_multiplier = float(speed_multiplier) except: msg = self.getName() + "Plugin: wrong value type for speed multiplier, must be float" else: try: self.__cell.setSpeedMultiplier(speed_multiplier) except: msg = self.getName() + "Plugin: something went wrong - couldn't set speed multiplier for current cell" else: msg = self.getName() + "Plugin: Success! Set new speed multiplier for current cell to %s" % speed_multiplier if msg: self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) def set_cell_blocking_policy(self, value, widget=None): """ set the current cell to the next available blocking policy @type value: int @param value: integer code for cell blocking type @type widget: pychan.Widget @param widget: widget which calls this method """ if not self.__cell: msg = self.getName() + "Plugin: no cell selected, aborting update of blocking policy" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) return if not hasattr(self.__cell, 'setCellType'): msg = self.getName() + "Plugin: wrong fife version, cell lacks method 'setCellType'" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) return self.__cell.setCellType(value) msg = self.getName() + "Plugin: set cell blocking policy to %s" % value self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) def cb_toggle_section(self, event, widget): """ widget callback - toggles a section wrapper connected to the given widget @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ if widget.name not in _SECTION_TO_WRAPPER: return section_wrapper_name = _SECTION_TO_WRAPPER[widget.name] self.toggle_section(section_wrapper_name) def toggle_section(self, section_wrapper_name=''): """ flip between show/hide of a section wrapper @type section_wrapper_name: str @param section_wrapper_name: widget name of a section wrapper """ section_wrapper = self.container.findChild(name=section_wrapper_name) if section_wrapper.isVisible(): self.hide_section(widget=section_wrapper) else: self.show_section(widget=section_wrapper) self.container.adaptLayout(True) def hide_section(self, widget=None, section=None): """ hides a section - hiding is always possible (not restricted by the current mode of this plugin FIXME: - decide if we need section here (e.g. to set the users last choice of the layout of the mode - might be nice if FIFedit allows to save plugin data and restore the users last choices in a new FIFedit session) @type widget: pychan.Widget @param widget: section wrapper @param section: str @param section: section type which should be hidden """ if widget is None and section is not None: section_wrapper_name = _SECTION_TO_WRAPPER[section] widget = self.container.findChild(name=section_wrapper_name) # if section is None and widget is not None: # if widget.name in _WRAPPER_TO_SECTION: # section = _WRAPPER_TO_SECTION[widget.name] # else: # return if widget is None and section is None: return widget.hide() def show_section(self, widget=None, section=None): """ @type widget: pychan.Widget @param widget: section wrapper @param section: str @param section: section type which should be hidden """ if widget is None and section is not None: section_wrapper_name = _SECTION_TO_WRAPPER[section] widget = self.container.findChild(name=section_wrapper_name) if section is None and widget is not None: if widget.name in _WRAPPER_TO_SECTION: section = _WRAPPER_TO_SECTION[widget.name] else: return if widget is None and section is None: return if section in _MODES[self.mode]['disable']: # give feedback to the user msg = self.getName() + "Plugin: section cannot be shown due to mode restrictions" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) else: widget.show() def toggle_gui(self): """ toggle visibility of main container """ if self.container.isVisible(): self.hide() else: self.show() def hide(self): """ hides the main container """ self.container.hide() self._action_show.setChecked(False) def show(self): """ shows the main container """ self.container.show() self._action_show.setChecked(True) def map_shown(self): """ callback for editor signal: postMapShown """ mapview = self._editor.getActiveMapView() self._controller = mapview.getController() self.set_mode() self.show() def mouse_pressed(self, event): """ callback for editor signal: mousePressed """ if event.getButton() == fife.MouseEvent.RIGHT: self._reset() def increase_cell_stackpos(self, event, widget): """ callback for widget; increase cell stack pos @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ index = widget.name print "Implement increase of cell_stackpos" def decrease_cell_stackpos(self, event, widget): """ callback for widget; decrease cell stack pos @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ index = widget.name print "Implement decrease of cell_stackpos" def increase_stackpos(self, event, widget): """ callback for btn1; increases stackpos @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ index = widget.name instance = self.get_instance(index) if not instance: return sp = instance.get2dGfxVisual().getStackPosition() if sp < _MAX_STACKPOS: sp += 1 instance.get2dGfxVisual().setStackPosition(sp) self.update() def decrease_stackpos(self, event, widget): """ callback for btn1; decreases stackpos @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ index = widget.name instance = self.get_instance(index) if not instance: return sp = instance.get2dGfxVisual().getStackPosition() if sp > _MIN_STACKPOS: sp -= 1 instance.get2dGfxVisual().setStackPosition(sp) self.update() def get_instance(self, index=None): """ turn list index into instance @type index: int @param index: list index to access instance """ instance = None try: instance = self._instances[index] except IndexError: print "index %s not in self._instances" % index return instance def select(self, event, widget): """ callback for selected subwrapper @todo: - FIFedit needs a flag to either only fetch single instances or all instances on a cell, otherwise this plugin can´t work as it should (selecting a particular instance and edit it) @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ index = int(widget.name) instance = self.get_instance(index) if self.active: wdgt = self.wrapper.findChild(name=self.active) if wdgt: wdgt.base_color = _WRAPPER_COLOR self.previous = self.active self.active = index widget.base_color = _WRAPPER_COLOR_SELECTED # interesting part - reset editor selection and dump our instance into it self._controller.deselectSelection() self._controller._selection.append(instance.getLocation()) self._controller._single_instance = True self._controller._instance = instance fife.CellSelectionRenderer.getInstance(self._controller._camera).selectLocation(instance.getLocation()) def hover_enter_subwrapper(self, event, widget): """ callback for on mouse enter events on subwrapper """ widget.base_color = _WRAPPER_COLOR_HOVER instance = self.get_instance(widget.name) if instance: self._renderer.removeAllOutlines() args = ( instance, _OUTLINE_COLOR[0], _OUTLINE_COLOR[1], _OUTLINE_COLOR[2], _OUTLINE_SIZE ) self._renderer.addOutlined(*args) def hover_exit_subrwapper(self, event, widget): """ callback for on mouse exit events on subwrapper """ if widget.name != self.active: widget.base_color = _WRAPPER_COLOR else: widget.base_color = _WRAPPER_COLOR_SELECTED self._renderer.removeAllOutlines() def update(self): """ redraws dynamic widgets; interprets self._instances """ if not self._location and not self.__cell: return if self.__cell: coords = self.__cell.getLayerCoordinates() else: coords = self._location.getLayerCoordinates() x, y = round(coords.x, 2), round(coords.y, 2) wdgt = self.container.findChild(name="cell_coords") wdgt.text = unicode(str(x) + " : " + str(y), 'utf-8') if self.__cell: cache = self.__cell.getLayer().getCellCache() if hasattr(self.__cell, 'getCellType'): cell_type = self.__cell.getCellType() if cell_type in _CELL_TYPE_TO_WDGT_NAME: wdgt_name = _CELL_TYPE_TO_WDGT_NAME[cell_type] wdgt = self.container.findChild(name=wdgt_name) wdgt.toggled = 1 if hasattr(self.__cell, 'getSpeedMultiplier'): speed_multiplier = self.__cell.getSpeedMultiplier() wdgt = self.container.findChild(name="speed_multiplier") wdgt.text = unicode(str(speed_multiplier), 'utf-8') if hasattr(self.__cell, 'getCostMultiplier'): default_cost_multiplier = self.__cell.getCostMultiplier() wdgt = self.container.findChild(name="default_cost_multiplier") wdgt.text = unicode(str(default_cost_multiplier), 'utf-8') if hasattr(cache, 'getCosts'): self.minieditor.hide() costs = cache.getCellCosts(self.__cell) listbox = self.container.findChild(name="cost_entries") listbox.items = costs if costs: listbox.selected = 0 wdgt = self.container.findChild(name="transition_end") wdgt.hide() wdgt = self.container.findChild(name="transition_create") wdgt.hide() wdgt = self.container.findChild(name="transition_immediate") wdgt.hide() # rebuild the gui list of all instances on the current cell self.wrapper.removeAllChildren() for index, instance in enumerate(self._instances): fife_object_id = instance.getObject().getId() subwrapper = pychan.widgets.VBox(padding=2) subwrapper.name= index subwrapper.base_color = _WRAPPER_COLOR subwrapper.size = subwrapper.min_size = subwrapper.max_size = _SUBWRAPPER_SIZE subwrapper.capture(self.hover_enter_subwrapper, "mouseEntered") subwrapper.capture(self.hover_exit_subrwapper, "mouseExited") subwrapper.capture(self.select, "mousePressed") # object id label1 = pychan.widgets.Label() label1.text = unicode(fife_object_id, 'utf-8') label1.size = label1.min_size = label1.max_size = _LABEL1_SIZE subwrapper.addChild(label1) data = { 'index' : index, 'stack_pos' : instance.get2dGfxVisual().getStackPosition(), 'stack_pos_name' : 'Stack pos', 'inc_callback' : self.increase_stackpos, 'dec_callback' : self.decrease_stackpos, } stackpos_edit_wdgt = StackposEditWidget(data) subwrapper.addChild(stackpos_edit_wdgt.widget) data['stack_pos'] = instance.getCellStackPosition() data['stack_pos_name'] = 'Cell stack pos' data['inc_callback'] = self.increase_cell_stackpos data['dec_callback'] = self.decrease_cell_stackpos stackpos_edit_wdgt = StackposEditWidget(data) subwrapper.addChild(stackpos_edit_wdgt.widget) subwrapper.adaptLayout() self.wrapper.addChild(subwrapper) self.wrapper.adaptLayout() self.container.adaptLayout(True) def input(self, locations): """ receiver for onCellSelected we filter given instances, to not let the user dump instances from different cells here """ self._reset() if not locations: return self._camera = self._editor.getActiveMapView().getCamera() self._renderer = fife.InstanceRenderer.getInstance(self._camera) self._instances = [] self._location = locations[0] layer = self._location.getLayer() fcoords = self._location.getLayerCoordinates() # decide wether we allow cell manipulation or not # no cell cache, no cell manipulation cellcache = layer.getCellCache() if cellcache is None: self.__cell = None self.set_mode('cell_view') # get instances from layer self._instances = layer.getInstancesAt(self._location) else: self.__cell = cellcache.getCell(fcoords) if self.__cell is None: self.__cell = None self.set_mode('cell_view') # get instances from layer self._instances = layer.getInstancesAt(self._location) else: wdgt = self.container.findChild(name="expert_mode") if wdgt.marked: self.set_mode('cell_edit_expert') else: self.set_mode('cell_edit') # get instances from cell self._instances = self.__cell.getInstances() self.update() def updateMode(self): if self.__cell is None: self.set_mode('cell_view') else: wdgt = self.container.findChild(name="expert_mode") if not wdgt.marked: self.set_mode('cell_edit_expert') else: self.set_mode('cell_edit') self.update()
class CameraEdit(plugin.Plugin): def __init__(self): self._enabled = False # Camera instance self._camera = None # Editor instance self._editor = None # Toolbar button to display Camera Editor self._action_show = None # GUI self._container = None self._ok_button = None self._cancel_button = None def enable(self): """ plugin method """ if self._enabled is True: return self._editor = scripts.editor.getEditor() #self._camera = self._editor.getActiveMapView().getCamera() self._action_show = Action(u"Camera Editor", checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) self._createGui() self._enabled = True def disable(self): """ plugin method """ if self._enabled is False: return self._container.setDocked(False) self._container.hide() self._editor._tools_menu.removeAction(self._action_show) self._enabled = False def isEnabled(self): """ plugin method """ return self._enabled; def getName(self): """ plugin method """ return "Camera Editor" def toggle(self): """ Toggles the cameratool visible / invisible and sets dock status """ if self._container.isVisible() or self._container.isDocked(): self._container.setDocked(False) self._container.hide() self._action_show.setChecked(False) else: self._container.show() self.loadSettings() self._action_show.setChecked(True) self._adjustPosition() def saveSettings(self): engine = self._editor.getEngine() id = self._container.collectData('idBox') if id == '': print 'Please enter a camera id.' return try: map = engine.getModel().getMap(str(self._container.collectData('mapBox'))) except fife.Exception: print 'Cannot find the specified map id.' return try: layer = map.getLayer(str(self._container.collectData('layerBox'))) except fife.Exception: print 'Cannot find the specified layer id.' return try: vals = self._container.collectData('viewBox').split(',') if len(vals) != 4: raise ValueError viewport = fife.Rect(*[int(c) for c in vals]) except ValueError: print 'Please enter 4 comma (,) delimited values for viewport x,y,width,height.' return try: refh = int(self._container.collectData('refhBox')) refw = int(self._container.collectData('refwBox')) except ValueError: print 'Please enter positive integer values for reference width and height.' return try: rot = int(self._container.collectData('rotBox')) tilt = int(self._container.collectData('tiltBox')) except ValueError: print 'Please enter positive integer values for rotation and tilt.' return self._camera = self._editor.getActiveMapView().getCamera() self._camera.setId(str(id)) self._camera.getLocation().setLayer(layer) self._camera.setViewPort(viewport) self._camera.setCellImageDimensions(refw, refh) self._camera.setRotation(rot) self._camera.setTilt(tilt) self.toggle() def loadSettings(self): if self._editor.getActiveMapView() is None: return else: self._camera = self._editor.getActiveMapView().getCamera() map = self._editor.getActiveMapView().getMap().getId() self._container.findChild(name="mapBox").text = unicode(str(map)) layer = self._camera.getLocation().getLayer().getId() self._container.findChild(name="layerBox").text = unicode(layer) vp = self._camera.getViewPort() viewport_str = unicode(str(vp.x) + "," + str(vp.y) + "," + str(vp.w) + "," + str(vp.h)) self._container.findChild(name="viewBox").text = viewport_str ref = self._camera.getCellImageDimensions() refw_str = unicode(str(ref.x)) refh_str = unicode(str(ref.y)) self._container.findChild(name="refhBox").text = refh_str self._container.findChild(name="refwBox").text = refw_str self._container.findChild(name="idBox").text = unicode(str(self._camera.getId())) self._container.findChild(name="rotBox").text = unicode(str(int(self._camera.getRotation()))) self._container.findChild(name="tiltBox").text = unicode(str(int(self._camera.getTilt()))) def _createGui(self): """ Create the basic gui container """ self._container = pychan.loadXML('gui/cameradialog.xml') self._ok_button = self._container.findChild(name="okButton") self._cancel_button = self._container.findChild(name="cancelButton") self._ok_button.capture(self.saveSettings) self._ok_button.capture(cbwa(self._editor.getStatusBar().showTooltip, unicode("Save changes to the camera")), 'mouseEntered') self._ok_button.capture(self._editor.getStatusBar().hideTooltip, 'mouseExited') self._cancel_button.capture(self.toggle) self._cancel_button.capture(cbwa(self._editor.getStatusBar().showTooltip, unicode("Discard any changes to the camera")), 'mouseEntered') self._cancel_button.capture(self._editor.getStatusBar().hideTooltip, 'mouseExited') def _adjustPosition(self): """ Adjusts the position of the container - we don't want to let the window appear at the center of the screen. (new default position: left, beneath the tools window) """ self._container.position = (50, 200)
class CellView(plugin.Plugin): """ A simple plugin to control StackPos attribute of fife.Instance -> 2dGfxVisual """ def __init__(self): """ """ self._camera = None self._renderer = None self._controller = None self.__cell = None self.mode = _DEFAULT_MODE self._enabled = False self._action_show = None self.container = None self.wrapper = None self._help_dialog = None self.attrSetCallback = pychan.tools.attrSetCallback self.active = None self.previous = None # FIXME: fields should store ModelCoordinate later instead of str self.transition = { 'start': '', 'end': '', } def _reset(self): """ reset dynamic data """ self._instances = [] self.active = None self.previous = None self.__cell = None self._location = None if self._help_dialog: self._help_dialog.hide() if self.wrapper: self.wrapper.removeAllChildren() if self.container: self.set_mode() wdgt = self.container.findChild(name="cell_coords") wdgt.text = unicode("- : -", 'utf-8') # cleanup controller changes made by this plugin if self._controller: self._controller._single_instance = False self._controller._instance = None def _show_help(self): """ shows the help dialog """ if self._help_dialog is not None: self._help_dialog.show() return self._help_dialog = pychan.loadXML("gui/help.xml") self._help_dialog.title = u"Help (CellView)" self._help_dialog.mapEvents({ "closeButton": self._help_dialog.hide, }) # gimme some more space _SIZE = (320, 400) scrollarea = self._help_dialog.findChildren( __class__=pychan.widgets.ScrollArea)[0] scrollarea.size = _SIZE scrollarea.min_size = _SIZE scrollarea.max_size = _SIZE f = open('lang/help_cellview.txt', 'r') self._help_dialog.findChild(name="helpText").text = unicode( f.read(), 'utf-8') f.close() self._help_dialog.show() def enable(self): """ plugin method overwrite """ if self._enabled: return self._editor = scripts.editor.getEditor() self._engine = self._editor.getEngine() self._action_show = Action(unicode(self.getName(), "utf-8"), checkable=True) scripts.gui.action.activated.connect(self.toggle_gui, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) events.onCellSelected.connect(self.input) events.preMapClosed.connect(self.hide) events.postMapShown.connect(self.map_shown) events.mousePressed.connect(self.mouse_pressed) self._reset() self.create() self.container.x = 0 self.container.y = 0 self.show() def disable(self): """ plugin method """ if not self._enabled: return self._reset() self.wrapper = None self.container.setDocked(False) self.container.hide() events.onInstancesSelected.disconnect(self.input) events.preMapClosed.disconnect(self.hide) events.preMapShown.disconnect(self.map_shown) events.mousePressed.disconnect(self.mouse_pressed) self._editor._tools_menu.removeAction(self._action_show) def isEnabled(self): """ plugin method """ return self._enabled def getName(self): """ plugin method """ return "Cell view" def create(self): """ create gui sceleton """ if self.container: return self.container = pychan.loadXML('gui/cellview.xml') self.wrapper = self.container.findChild(name="cell_instance_wrapper") btn = self.container.findChild(name="show_help") btn.capture(self._show_help, 'mousePressed') # create callbacks for section hiding for wdgt_name in _SECTION_TO_WRAPPER.keys(): wdgt = self.container.findChild(name=wdgt_name) wdgt.capture(self.cb_toggle_section, "mousePressed") # create callbacks for cell blocking policy manipulation for name in _WDGT_NAME_TO_CELL_TYPE: value = _WDGT_NAME_TO_CELL_TYPE[name] wdgt = self.container.findChild(name=name) if not wdgt: continue wdgt.capture(cbwa(self.set_cell_blocking_policy, value), "mousePressed") # create callback for setting the expert mode wdgt = self.container.findChild(name='expert_mode') wdgt.capture(self.updateMode, "mousePressed") # create callback for setting the speed multiplier wdgt = self.container.findChild(name='apply_speed_multiplier') wdgt.capture(self.set_cell_speed_multiplier, "mousePressed") # create callback for setting the default cost_multiplier wdgt = self.container.findChild(name='apply_cost_multiplier') wdgt.capture(self.set_cell_default_cost_multiplier, "mousePressed") # create callbacks for mini editor wdgt = self.container.findChild(name="mini_editor_cost_save") wdgt.capture(self.mini_editor_create_cost, "mousePressed") # hide mini editor for cost entries self.minieditor = self.container.findChild(name='cost_mini_editor') self.minieditor.hide() # create callback to control the mini editor wdgt = self.container.findChild(name='add_cost_entry') wdgt.capture(self.minieditor.show, 'mousePressed') wdgt = self.container.findChild(name="edit_current_cost_entry") wdgt.capture(self.mini_editor_edit_cost, 'mousePressed') wdgt = self.container.findChild(name="remove_current_cost_entry") wdgt.capture(self.mini_editor_remove_cost, 'mousePressed') # create fancy callbacks for mouse actions on the listbox listbox = self.container.findChild(name="cost_entries") listbox.capture(self.mini_editor_edit_cost, 'mousePressed') # transition wdgt = self.container.findChild(name="transition_start") wdgt.capture(cbwa(self.transition_set, start=1), 'mousePressed') wdgt = self.container.findChild(name="transition_end") wdgt.capture(cbwa(self.transition_set, end=1), 'mousePressed') wdgt.hide() wdgt = self.container.findChild(name="transition_create") wdgt.capture(cbwa(self.transition_set, create=1), 'mousePressed') wdgt.hide() wdgt = self.container.findChild(name="transition_immediate") wdgt.hide() self.container.hide() def transition_set(self, start=0, end=0, create=0): """ create transition data and the transition itself if we have all data @todo: - split this function up - click on ToggleButtons should focus cam on the corresponding cell - split set/unset code like that: - 1st click on button -> collect data - RMB on button -> delete data - 2nd click on button -> focus the cell with cam - we should store all transition attempts in a datastructure instead of erasing it with each update - update() should be locked if we are in the "click transition target"-mode """ if self.__cell is None: return tbtn = self.container.findChild(name="transition_end") btn = self.container.findChild(name="transition_create") chkbox = self.container.findChild(name="transition_immediate") if start: if self.transition['start']: tbtn.hide() btn.hide() chkbox.hide() self.transition['start'] = '' else: self.transition['start'] = 'put start coords here' tbtn.show() if end: if self.transition['end']: self.transition['end'] = '' btn.hide() chkbox.hide() else: self.transition['end'] = 'put end coords here' btn.show() chkbox.show() # create or destroy previous transition if create: if self.transition['start'] and self.transition['end']: wdgt = self.container.findChild(name="transition_immediate") immediate = False if wdgt.marked: immediate = True def set_mode(self, mode=_DEFAULT_MODE): """ set the mode for the plugin @type mode: str @param mode: key for the _MODES dict """ if mode in _MODES: self.mode = mode if self.mode is None: return # update 'current mode' widget lbl = self.container.findChild(name='current_mode') lbl.text = u"Current mode: " + self.mode # show / hide all sections according to the new mode # show for section in _MODES[self.mode]['show']: self.show_section(section=section) # hide for section in _MODES[self.mode]['disable']: self.hide_section(section=section) self.container.adaptLayout(True) def mini_editor_remove_cost(self): """ delete the current selected cost entry @todo: - do we need one of those annoying pop-ups here to ask "do you really want to delete this"? """ if self.__cell is None: return msg = '' listbox = self.container.findChild(name="cost_entries") if len(listbox.items) == 0: return index = listbox.selected cost_id = listbox.items[index] cache = self.__cell.getLayer().getCellCache() print cost_id print cache.getCellCosts(self.__cell) try: cache.removeCellFromCost(str(cost_id), self.__cell) print cache.getCellCosts(self.__cell) except: msg = self.getName( ) + "Plugin: Error! Couldn't remove cost from cell" else: msg = self.getName( ) + "Plugin: Success! Cost was removed from cell" self.update() if msg == '': self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) def mini_editor_edit_cost(self, event=None, widget=None): """ edit the given current selected cost entry by reading the values into the mini editor & show it We also check if RMB was pressed on the listbox and return otherwise @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ if self.__cell is None: return if widget is not None: if widget.name == 'cost_entries' and event.getButton( ) != fife.MouseEvent.RIGHT: return wdgt_id = self.container.findChild(name="mini_editor_cost_id") wdgt_val = self.container.findChild(name="mini_editor_cost_value") listbox = self.container.findChild(name="cost_entries") index = listbox.selected if len(listbox.items) == 0: return cost_id = listbox.items[index] cost_val = self.__cell.getLayer().getCellCache().getCost(cost_id) wdgt_id.text = unicode(cost_id, 'utf-8') wdgt_val.text = unicode(str(cost_val), 'utf-8') self.minieditor.show() def mini_editor_create_cost(self, event=None, widget=None): """ read out data from the mini editor and apply it if possible @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ if event is None and widget is None: return if widget is None: return if self.__cell is None: return msg = '' wdgt_id = self.container.findChild(name="mini_editor_cost_id") wdgt_val = self.container.findChild(name="mini_editor_cost_value") cost_id = wdgt_id.text cost_value = wdgt_val.text try: cost_value = float(cost_value) except: msg = self.getName() + "Plugin: new cost value has to be a float" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) else: cache = self.__cell.getLayer().getCellCache() cache.registerCost(str(cost_id), cost_value) cache.addCellToCost(str(cost_id), self.__cell) msg = self.getName( ) + "Plugin: Success! New cost id and value saved to cell" self.update() if msg: self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) def set_cell_default_cost_multiplier(self): """ set the default cost multiplier of the current selected cell """ if self.__cell is None: msg = self.getName( ) + "Plugin: no cell selected, aborting update of default cost multiplier" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) return if not hasattr(self.__cell, 'setCostMultiplier'): msg = self.getName( ) + "Plugin: wrong fife version, cell lacks method 'setCostMultiplier'" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) return msg = '' wdgt = self.container.findChild(name="default_cost_multiplier") default_cost_multiplier = wdgt.text try: default_cost_multiplier = float(default_cost_multiplier) except: msg = self.getName( ) + "Plugin: wrong value type for default cost multiplier, must be float" else: try: self.__cell.setCostMultiplier(default_cost_multiplier) except: msg = self.getName( ) + "Plugin: something went wrong - couldn't set default cost multiplier for current cell" else: msg = self.getName( ) + "Plugin: Success! Set new default cost multiplier for current cell to %s" % default_cost_multiplier if msg: self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) def set_cell_speed_multiplier(self): """ set the current user input for the cell's speed multiplier """ if self.__cell is None: msg = self.getName( ) + "Plugin: no cell selected, aborting update of speed multiplier" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) return if not hasattr(self.__cell, 'setSpeedMultiplier'): msg = self.getName( ) + "Plugin: wrong fife version, cell lacks method 'setSpeedMultiplier'" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) return msg = '' wdgt = self.container.findChild(name="speed_multiplier") speed_multiplier = wdgt.text try: speed_multiplier = float(speed_multiplier) except: msg = self.getName( ) + "Plugin: wrong value type for speed multiplier, must be float" else: try: self.__cell.setSpeedMultiplier(speed_multiplier) except: msg = self.getName( ) + "Plugin: something went wrong - couldn't set speed multiplier for current cell" else: msg = self.getName( ) + "Plugin: Success! Set new speed multiplier for current cell to %s" % speed_multiplier if msg: self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) def set_cell_blocking_policy(self, value, widget=None): """ set the current cell to the next available blocking policy @type value: int @param value: integer code for cell blocking type @type widget: pychan.Widget @param widget: widget which calls this method """ if not self.__cell: msg = self.getName( ) + "Plugin: no cell selected, aborting update of blocking policy" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) return if not hasattr(self.__cell, 'setCellType'): msg = self.getName( ) + "Plugin: wrong fife version, cell lacks method 'setCellType'" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) return self.__cell.setCellType(value) msg = self.getName() + "Plugin: set cell blocking policy to %s" % value self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) def cb_toggle_section(self, event, widget): """ widget callback - toggles a section wrapper connected to the given widget @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ if widget.name not in _SECTION_TO_WRAPPER: return section_wrapper_name = _SECTION_TO_WRAPPER[widget.name] self.toggle_section(section_wrapper_name) def toggle_section(self, section_wrapper_name=''): """ flip between show/hide of a section wrapper @type section_wrapper_name: str @param section_wrapper_name: widget name of a section wrapper """ section_wrapper = self.container.findChild(name=section_wrapper_name) if section_wrapper.isVisible(): self.hide_section(widget=section_wrapper) else: self.show_section(widget=section_wrapper) self.container.adaptLayout(True) def hide_section(self, widget=None, section=None): """ hides a section - hiding is always possible (not restricted by the current mode of this plugin FIXME: - decide if we need section here (e.g. to set the users last choice of the layout of the mode - might be nice if FIFedit allows to save plugin data and restore the users last choices in a new FIFedit session) @type widget: pychan.Widget @param widget: section wrapper @param section: str @param section: section type which should be hidden """ if widget is None and section is not None: section_wrapper_name = _SECTION_TO_WRAPPER[section] widget = self.container.findChild(name=section_wrapper_name) # if section is None and widget is not None: # if widget.name in _WRAPPER_TO_SECTION: # section = _WRAPPER_TO_SECTION[widget.name] # else: # return if widget is None and section is None: return widget.hide() def show_section(self, widget=None, section=None): """ @type widget: pychan.Widget @param widget: section wrapper @param section: str @param section: section type which should be hidden """ if widget is None and section is not None: section_wrapper_name = _SECTION_TO_WRAPPER[section] widget = self.container.findChild(name=section_wrapper_name) if section is None and widget is not None: if widget.name in _WRAPPER_TO_SECTION: section = _WRAPPER_TO_SECTION[widget.name] else: return if widget is None and section is None: return if section in _MODES[self.mode]['disable']: # give feedback to the user msg = self.getName( ) + "Plugin: section cannot be shown due to mode restrictions" self._editor.getStatusBar().setText(unicode(msg, 'utf-8')) else: widget.show() def toggle_gui(self): """ toggle visibility of main container """ if self.container.isVisible(): self.hide() else: self.show() def hide(self): """ hides the main container """ self.container.hide() self._action_show.setChecked(False) def show(self): """ shows the main container """ self.container.show() self._action_show.setChecked(True) def map_shown(self): """ callback for editor signal: postMapShown """ mapview = self._editor.getActiveMapView() self._controller = mapview.getController() self.set_mode() self.show() def mouse_pressed(self, event): """ callback for editor signal: mousePressed """ if event.getButton() == fife.MouseEvent.RIGHT: self._reset() def increase_cell_stackpos(self, event, widget): """ callback for widget; increase cell stack pos @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ index = widget.name print "Implement increase of cell_stackpos" def decrease_cell_stackpos(self, event, widget): """ callback for widget; decrease cell stack pos @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ index = widget.name print "Implement decrease of cell_stackpos" def increase_stackpos(self, event, widget): """ callback for btn1; increases stackpos @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ index = widget.name instance = self.get_instance(index) if not instance: return sp = instance.get2dGfxVisual().getStackPosition() if sp < _MAX_STACKPOS: sp += 1 instance.get2dGfxVisual().setStackPosition(sp) self.update() def decrease_stackpos(self, event, widget): """ callback for btn1; decreases stackpos @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ index = widget.name instance = self.get_instance(index) if not instance: return sp = instance.get2dGfxVisual().getStackPosition() if sp > _MIN_STACKPOS: sp -= 1 instance.get2dGfxVisual().setStackPosition(sp) self.update() def get_instance(self, index=None): """ turn list index into instance @type index: int @param index: list index to access instance """ instance = None try: instance = self._instances[index] except IndexError: print "index %s not in self._instances" % index return instance def select(self, event, widget): """ callback for selected subwrapper @todo: - FIFedit needs a flag to either only fetch single instances or all instances on a cell, otherwise this plugin can´t work as it should (selecting a particular instance and edit it) @type widget: pychan.Widget @param widget: widget which triggered an event @type event: pychan.Event @type event: event caused by an widget """ index = int(widget.name) instance = self.get_instance(index) if self.active: wdgt = self.wrapper.findChild(name=self.active) if wdgt: wdgt.base_color = _WRAPPER_COLOR self.previous = self.active self.active = index widget.base_color = _WRAPPER_COLOR_SELECTED # interesting part - reset editor selection and dump our instance into it self._controller.deselectSelection() self._controller._selection.append(instance.getLocation()) self._controller._single_instance = True self._controller._instance = instance fife.CellSelectionRenderer.getInstance( self._controller._camera).selectLocation(instance.getLocation()) def hover_enter_subwrapper(self, event, widget): """ callback for on mouse enter events on subwrapper """ widget.base_color = _WRAPPER_COLOR_HOVER instance = self.get_instance(widget.name) if instance: self._renderer.removeAllOutlines() args = (instance, _OUTLINE_COLOR[0], _OUTLINE_COLOR[1], _OUTLINE_COLOR[2], _OUTLINE_SIZE) self._renderer.addOutlined(*args) def hover_exit_subrwapper(self, event, widget): """ callback for on mouse exit events on subwrapper """ if widget.name != self.active: widget.base_color = _WRAPPER_COLOR else: widget.base_color = _WRAPPER_COLOR_SELECTED self._renderer.removeAllOutlines() def update(self): """ redraws dynamic widgets; interprets self._instances """ if not self._location and not self.__cell: return if self.__cell: coords = self.__cell.getLayerCoordinates() else: coords = self._location.getLayerCoordinates() x, y = round(coords.x, 2), round(coords.y, 2) wdgt = self.container.findChild(name="cell_coords") wdgt.text = unicode(str(x) + " : " + str(y), 'utf-8') if self.__cell: cache = self.__cell.getLayer().getCellCache() if hasattr(self.__cell, 'getCellType'): cell_type = self.__cell.getCellType() if cell_type in _CELL_TYPE_TO_WDGT_NAME: wdgt_name = _CELL_TYPE_TO_WDGT_NAME[cell_type] wdgt = self.container.findChild(name=wdgt_name) wdgt.toggled = 1 if hasattr(self.__cell, 'getSpeedMultiplier'): speed_multiplier = self.__cell.getSpeedMultiplier() wdgt = self.container.findChild(name="speed_multiplier") wdgt.text = unicode(str(speed_multiplier), 'utf-8') if hasattr(self.__cell, 'getCostMultiplier'): default_cost_multiplier = self.__cell.getCostMultiplier() wdgt = self.container.findChild(name="default_cost_multiplier") wdgt.text = unicode(str(default_cost_multiplier), 'utf-8') if hasattr(cache, 'getCosts'): self.minieditor.hide() costs = cache.getCellCosts(self.__cell) listbox = self.container.findChild(name="cost_entries") listbox.items = costs if costs: listbox.selected = 0 wdgt = self.container.findChild(name="transition_end") wdgt.hide() wdgt = self.container.findChild(name="transition_create") wdgt.hide() wdgt = self.container.findChild(name="transition_immediate") wdgt.hide() # rebuild the gui list of all instances on the current cell self.wrapper.removeAllChildren() for index, instance in enumerate(self._instances): fife_object_id = instance.getObject().getId() subwrapper = pychan.widgets.VBox(padding=2) subwrapper.name = index subwrapper.base_color = _WRAPPER_COLOR subwrapper.size = subwrapper.min_size = subwrapper.max_size = _SUBWRAPPER_SIZE subwrapper.capture(self.hover_enter_subwrapper, "mouseEntered") subwrapper.capture(self.hover_exit_subrwapper, "mouseExited") subwrapper.capture(self.select, "mousePressed") # object id label1 = pychan.widgets.Label() label1.text = unicode(fife_object_id, 'utf-8') label1.size = label1.min_size = label1.max_size = _LABEL1_SIZE subwrapper.addChild(label1) data = { 'index': index, 'stack_pos': instance.get2dGfxVisual().getStackPosition(), 'stack_pos_name': 'Stack pos', 'inc_callback': self.increase_stackpos, 'dec_callback': self.decrease_stackpos, } stackpos_edit_wdgt = StackposEditWidget(data) subwrapper.addChild(stackpos_edit_wdgt.widget) data['stack_pos'] = instance.getCellStackPosition() data['stack_pos_name'] = 'Cell stack pos' data['inc_callback'] = self.increase_cell_stackpos data['dec_callback'] = self.decrease_cell_stackpos stackpos_edit_wdgt = StackposEditWidget(data) subwrapper.addChild(stackpos_edit_wdgt.widget) subwrapper.adaptLayout() self.wrapper.addChild(subwrapper) self.wrapper.adaptLayout() self.container.adaptLayout(True) def input(self, locations): """ receiver for onCellSelected we filter given instances, to not let the user dump instances from different cells here """ self._reset() if not locations: return self._camera = self._editor.getActiveMapView().getCamera() self._renderer = fife.InstanceRenderer.getInstance(self._camera) self._instances = [] self._location = locations[0] layer = self._location.getLayer() fcoords = self._location.getLayerCoordinates() # decide wether we allow cell manipulation or not # no cell cache, no cell manipulation cellcache = layer.getCellCache() if cellcache is None: self.__cell = None self.set_mode('cell_view') # get instances from layer self._instances = layer.getInstancesAt(self._location) else: self.__cell = cellcache.getCell(fcoords) if self.__cell is None: self.__cell = None self.set_mode('cell_view') # get instances from layer self._instances = layer.getInstancesAt(self._location) else: wdgt = self.container.findChild(name="expert_mode") if wdgt.marked: self.set_mode('cell_edit_expert') else: self.set_mode('cell_edit') # get instances from cell self._instances = self.__cell.getInstances() self.update() def updateMode(self): if self.__cell is None: self.set_mode('cell_view') else: wdgt = self.container.findChild(name="expert_mode") if not wdgt.marked: self.set_mode('cell_edit_expert') else: self.set_mode('cell_edit') self.update()
class ObjectSelector(plugin.Plugin): """The ObjectSelector class offers a gui Widget that let's you select the object you wish to use to in the editor. @param engine: fife instance @param map: fife.Map instance containing your map @param selectNotify: callback function used to tell the editor you selected an object. """ def __init__(self): self.editor = None self.engine = None self.mode = 'list' # Other mode is 'preview' self._enabled = False self.object = None def enable(self): if self._enabled is True: return self.editor = scripts.editor.getEditor() self.engine = self.editor.getEngine() self._showAction = Action(u"Object selector", checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._showAction) self.editor._tools_menu.addAction(self._showAction) events.postMapShown.connect(self.update_namespace) events.onObjectSelected.connect(self.setPreview) events.onObjectsImported.connect(self.update_namespace) self.buildGui() def disable(self): if self._enabled is False: return self.gui.hide() self.removeAllChildren() events.postMapShown.disconnect(self.update_namespace) events.onObjectSelected.disconnect(self.setPreview) events.onObjectsImported.disconnect(self.update_namespace) self.editor._tools_menu.removeAction(self._showAction) def isEnabled(self): return self._enabled; def getName(self): return "Object selector" def buildGui(self): self.gui = pychan.loadXML('gui/objectselector.xml') # Add search field self._searchfield = self.gui.findChild(name="searchField") self._searchfield.capture(self._search) self._searchfield.capture(self._search, "keyPressed") self.gui.findChild(name="searchButton").capture(self._search) # Add the drop down with list of namespaces self.namespaces = self.gui.findChild(name="namespaceDropdown") self.namespaces.items = self.engine.getModel().getNamespaces() self.namespaces.selected = 0 # TODO: Replace with SelectionEvent, once pychan supports it self.namespaces.capture(self.update_namespace, "action") self.namespaces.capture(self.update_namespace, "mouseWheelMovedUp") self.namespaces.capture(self.update_namespace, "mouseWheelMovedDown") self.namespaces.capture(self.update_namespace, "keyReleased") # Object list self.mainScrollArea = self.gui.findChild(name="mainScrollArea") self.objects = None if self.mode == 'list': self.setTextList() else: # Assuming self.mode is 'preview' self.setImageList() # Action buttons self.gui.findChild(name="toggleModeButton").capture(self.toggleMode) self.gui.findChild(name="closeButton").capture(self.hide) # Preview area self.gui.findChild(name="previewScrollArea").background_color = self.gui.base_color self.preview = self.gui.findChild(name="previewIcon") def toggleMode(self): if self.mode == 'list': self.setImageList() self.mode = 'preview' elif self.mode == 'preview': self.setTextList() self.mode = 'list' self.update() def setImageList(self): """Sets the mainScrollArea to contain a Vbox that can be used to fill in preview Images""" if self.objects is not None: self.mainScrollArea.removeChild(self.objects) self.objects = ObjectIconList(name='list', size=(200,1000)) self.objects.base_color = self.mainScrollArea.background_color self.mainScrollArea.addChild(self.objects) def setTextList(self): """Sets the mainScrollArea to contain a List that can be used to fill in Object names/paths""" if self.objects is not None: self.mainScrollArea.removeChild(self.objects) self.objects = widgets.ListBox(name='list') self.objects.capture(self.listEntrySelected) self.mainScrollArea.addChild(self.objects) def _search(self): self.search(self._searchfield.text) def search(self, str): results = [] # Format search terms terms = [term.lower() for term in str.split()] # Search if len(terms) > 0: namespaces = self.engine.getModel().getNamespaces() for namesp in namespaces: objects = self.engine.getModel().getObjects(namesp) for obj in objects: doAppend = True for term in terms: if obj.getId().lower().find(term) < 0: doAppend = False break if doAppend: results.append(obj) else: results = None if self.mode == 'list': self.fillTextList(results) elif self.mode == 'preview': self.fillPreviewList(results) def fillTextList(self, objects=None): if objects is None: if self.namespaces.selected_item is None: return objects = self.engine.getModel().getObjects(self.namespaces.selected_item) class _ListItem: def __init__( self, name, namespace ): self.name = name self.namespace = namespace def __str__( self ): return self.name self.objects.items = [_ListItem(obj.getId(), obj.getNamespace()) for obj in objects] if not self.object: if self.namespaces.selected_item: self.objects.selected = 0 self.listEntrySelected() else: for i in range(0, len(self.objects.items)): if self.objects.items[i].name != self.object.getId(): continue if self.objects.items[i].namespace != self.object.getNamespace(): continue self.objects.selected = i break scrollY = (self.objects.real_font.getHeight() + 0) * self.objects.selected self.mainScrollArea.real_widget.setVerticalScrollAmount(scrollY) def listEntrySelected(self): """This function is used as callback for the TextList.""" if self.objects.selected_item: object_id = self.objects.selected_item.name namespace = self.objects.selected_item.namespace obj = self.engine.getModel().getObject(object_id, namespace) self.objectSelected(obj) def fillPreviewList(self, objects=None): self.objects.clear() if objects is None: if self.namespaces.selected_item is None: return objects = self.engine.getModel().getObjects(self.namespaces.selected_item) for obj in objects: image = self._getImage(obj) if image is None: print 'No image available for selected object' image = "" callback = tools.callbackWithArguments(self.objectSelected, obj) icon = ObjectIcon(callback=callback, image=image, text=unicode(obj.getId())) self.objects.addChild(icon) if obj == self.object: icon.selected = True if not self.object: if len(objects) > 0: self.objectSelected(objects[0]) self.mainScrollArea.real_widget.setVerticalScrollAmount(self.objects.selected_item.y) self.objects.adaptLayout(False) def objectSelected(self, obj): """This is used as callback function to notify the editor that a new object has been selected. @param obj: fife.Object instance""" events.onObjectSelected.send(sender=self, object=obj) # Set preview image def setPreview(self, object, sender=None): if not object: return if self.object and object == self.object: return self.object = object # We do not want to autoscroll the list when the user manually # selects an object from the object selector if sender is not self: self.scrollToObject(object) self.preview.image = self._getImage(object) height = self.preview.image.getHeight(); if height > 200: height = 200 self.preview.parent.max_height = height self.gui.adaptLayout() def scrollToObject(self, object): # Select namespace names = self.namespaces if not names.selected_item: self.namespaces.selected = 0 if names.selected_item != object.getNamespace(): for i in range(0, len(names.items)): if names.items[i] == object.getNamespace(): self.namespaces.selected = i break self.update() def update_namespace(self): self.namespaces.items = self.engine.getModel().getNamespaces() if not self.namespaces.selected_item: self.namespaces.selected = 0 if self.mode == 'list': self.setTextList() elif self.mode == 'preview': self.setImageList() self.update() def update(self): if self.mode == 'list': self.fillTextList() elif self.mode == 'preview': self.fillPreviewList() self.gui.adaptLayout() def _getImage(self, obj): """ Returns an image for the given object. @param: fife.Object for which an image is to be returned @return: fife.GuiImage""" visual = None try: visual = obj.get2dGfxVisual() except: print 'Visual Selection created for type without a visual?' raise # Try to find a usable image index = visual.getStaticImageIndexByAngle(0) image = None # if no static image available, try default action if index == -1: action = obj.getDefaultAction() if action: animation_id = action.get2dGfxVisual().getAnimationIndexByAngle(0) animation = self.engine.getAnimationPool().getAnimation(animation_id) image = animation.getFrameByTimestamp(0) index = image.getPoolId() # Construct the new GuiImage that is to be returned if index != -1: image = fife.GuiImage(index, self.engine.getImagePool()) return image def show(self): self.update_namespace() self.gui.show() self._showAction.setChecked(True) def hide(self): self.gui.setDocked(False) self.gui.hide() self._showAction.setChecked(False) def toggle(self): if self.gui.isVisible() or self.gui.isDocked(): self.hide() else: self.show()
class ObjectSelector(plugin.Plugin): """ The B{ObjectSelector} plugin offers a gui that let you browse the loaded namespaces and their associated objects. It can be used in text- and image-mode. Text mode provides a preview image of the current selected object. @todo: - we need some sort of caching to prevent pychan from resizing all the object images over and over again - image aspect ratio is still broken - I guess my resize() function is junk (actually, I bet it is) - current selection of the user is overwritten on new updates """ ORIENTATION = { "Horizontal": 0, "Vertical": 1, } def __init__(self): super(ObjectSelector, self).__init__() # editor instance self._editor = scripts.editor.getEditor() self._engine = self._editor.getEngine() # plugin variables self._enabled = False self.last_dockarea = None self._action_show = None self._mode = _MODE_IMAGE self._object = None # @todo: we should store all the selection data here self._current_selection = { 'object': None, 'object_id': None, 'object_namespace': None, 'namespace': None, } # gui vars self.container = None self.default_x, self.default_y = _POSITION w, h = self._engine.getSettings().getScreenWidth( ), self._engine.getSettings().getScreenHeight() self._panel_size = int(w * 0.25) / 2 self.max_x = int(w * 0.85) self.max_y = int(h * 0.7) if self.max_y < _MAX_PREVIEW_WRAPPER_SIZE[1]: self.max_y = _MAX_PREVIEW_WRAPPER_SIZE[ 1] + 20 # compensate for scrollbar self._orientation = ObjectSelector.ORIENTATION['Vertical'] self._default_orientation = ObjectSelector.ORIENTATION['Vertical'] self.wrappers = { ObjectSelector.ORIENTATION['Vertical']: { 'wrapper': None, 'image_mode_wrapper': None, 'text_mode_wrapper': None, }, ObjectSelector.ORIENTATION['Horizontal']: { 'wrapper': None, 'image_mode_wrapper': None, 'text_mode_wrapper': None, }, } # setting variables self.default_settings = _PLUGIN_SETTINGS self.eds = self._editor._settings self.update_settings() def enable(self): """ enables the plugin and connects to the editor """ if self._enabled: return self._enabled = True # Fifedit plugin data self._action_show = Action(self.getName(), checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) postMapShown.connect(self.update) onObjectSelected.connect(self.set_object) onObjectsImported.connect(self.update_namespaces) self.create() self.toggle() if self.settings['docked']: self._editor.dockWidgetTo(self.container, self.settings['dockarea']) def disable(self): """ disables the plugin and connects to the editor """ if self._enabled: return self._enabled = False postMapShown.disconnect(self.update_namespaces) onObjectSelected.disconnect(self.set_object) onObjectsImported.disconnect(self.update_namespaces) def set_orientation(self, orientation=None, key=None): if key is not None: if key not in ObjectSelector.ORIENTATION: return orientation = ObjectSelector.ORIENTATION[key] if orientation is None: return if orientation == ObjectSelector.ORIENTATION['Vertical']: self._orientation = ObjectSelector.ORIENTATION['Vertical'] self._max_size = (self._panel_size, self.max_y) else: self._orientation = ObjectSelector.ORIENTATION['Horizontal'] self._max_size = (self.max_x, self._panel_size) self._orientation = orientation self.update_orientation() def get_orientation(self): return self._orientation orientation = property(get_orientation, set_orientation) def update_orientation(self): """ change widget orientation """ self.container.removeAllChildren() wrapper = self.wrappers[self.orientation]['wrapper'] self.apply_mode() self.container.addChild(wrapper) self.container.max_size = self.container.min_size = self._max_size self.container.adaptLayout(True) self.map_callbacks() self.update_namespaces() def set_mode(self, mode): """ set new mode @type mode: int @param mode: int id of the mode, either 0 (text mode) or 1 (image mode) """ if mode not in _MODES: return self._mode = mode self.apply_mode() def toggle_mode(self): """ callback for button to toggle mode """ self.set_mode(int(not self._mode)) self.map_callbacks() self.update_namespaces() def apply_mode(self): """ set the gui into the current active mode @note: - text mode: list item is used - image mode: V/HBox with Icon childs is used """ wrapper = self.wrappers[self.orientation]['wrapper'] vert_img_wrapper = self.wrappers[1]['image_mode_wrapper'] vert_text_wrapper = self.wrappers[1]['text_mode_wrapper'] hor_img_wrapper = self.wrappers[0]['image_mode_wrapper'] hor_text_wrapper = self.wrappers[0]['text_mode_wrapper'] if self._mode == _MODE_TEXT: if self.orientation == ObjectSelector.ORIENTATION['Horizontal']: vert_img_wrapper.hide() vert_text_wrapper.hide() hor_img_wrapper.hide() hor_text_wrapper.show() elif self.orientation == ObjectSelector.ORIENTATION['Vertical']: vert_img_wrapper.hide() vert_text_wrapper.show() hor_img_wrapper.hide() hor_text_wrapper.hide() elif self._mode == _MODE_IMAGE: if self.orientation == ObjectSelector.ORIENTATION['Horizontal']: vert_img_wrapper.hide() vert_text_wrapper.hide() hor_img_wrapper.show() hor_text_wrapper.hide() elif self.orientation == ObjectSelector.ORIENTATION['Vertical']: vert_img_wrapper.show() vert_text_wrapper.hide() hor_img_wrapper.hide() hor_text_wrapper.hide() def mouse_clicked(self, event): if self.container.isDocked(): return if event.getButton() == fife.MouseEvent.RIGHT: self.set_orientation(orientation=int(not self.get_orientation())) event.consume() def create(self): """ creates the gui sceleton """ if self.container is not None: return self.container = pychan.loadXML('gui/objectselector.xml') self.container.position_technique = 'explicit' self.container.position = _POSITION self.container.name = self.getName() self.container.set_orientation = self.set_orientation self.container.capture(self.mouse_clicked, "mouseClicked") vert_wrapper = self.container.findChild(name='vertical_wrapper') hor_wrapper = self.container.findChild(name='horizontal_wrapper') self.wrappers[1]['wrapper'] = vert_wrapper self.wrappers[1]['image_mode_wrapper'] = vert_wrapper.findChild( name="image_mode_wrapper") self.wrappers[1]['text_mode_wrapper'] = vert_wrapper.findChild( name="text_mode_wrapper") self.wrappers[1]['image_mode_wrapper'].hide() self.wrappers[1]['text_mode_wrapper'].hide() self.wrappers[0]['wrapper'] = hor_wrapper self.wrappers[0]['image_mode_wrapper'] = hor_wrapper.findChild( name="image_mode_wrapper") self.wrappers[0]['text_mode_wrapper'] = hor_wrapper.findChild( name="text_mode_wrapper") self.wrappers[0]['image_mode_wrapper'].hide() self.wrappers[0]['text_mode_wrapper'].hide() self.container.removeChild(vert_wrapper) self.container.removeChild(hor_wrapper) self.set_orientation(orientation=self._orientation) self.container.afterUndock = self.on_undock self.container.afterDock = self.on_dock def map_callbacks(self): """ captures events for the main widgets """ btn = self.container.findChild(name="toggle_mode") btn.capture(self.toggle_mode) self.namespace_list = self.container.findChild(name="namespace_list") self.namespace_list.capture(self.namespace_id_selected, "action") self.namespace_list.capture(self.namespace_id_selected, "mouseWheelMovedUp") self.namespace_list.capture(self.namespace_id_selected, "mouseWheelMovedDown") self.search_field = self.container.findChild(name="search_field") self.search_field.capture(self._search) self.search_field.capture(self._search, "keyPressed") self.container.findChild(name="search_button").capture(self._search) if self._mode == _MODE_TEXT: subwrapper = self.wrappers[self.orientation]['text_mode_wrapper'] self.preview_icon = subwrapper.findChild(name="preview_icon") self.object_list = subwrapper.findChild(name="object_list") self.object_list.capture(self.object_id_selected, "action") self.object_list.capture(self.object_id_selected, "mouseWheelMovedUp") self.object_list.capture(self.object_id_selected, "mouseWheelMovedDown") elif self._mode == _MODE_IMAGE: subwrapper = self.wrappers[self.orientation]['image_mode_wrapper'] if self.orientation == ObjectSelector.ORIENTATION['Horizontal']: self.object_list = subwrapper.findChild( __class__=pychan.widgets.HBox, name="object_list") elif self.orientation == ObjectSelector.ORIENTATION['Vertical']: self.object_list = subwrapper.findChild( __class__=pychan.widgets.VBox, name="object_list") def set_preview(self): """ set the preview icon @note: - only text mode shows a preview icon """ if self._mode == _MODE_IMAGE: return if self._object is None: return image = self._get_image(object=self._object) if image is None: return w, h = image.getWidth(), image.getHeight() w, h = resize(w, h) self.preview_icon.image = image self.preview_icon.size = self.preview_icon.max_size = (w, h) parent = self.preview_icon.parent x, y = parent.size self.preview_icon.position = (int(x / 2 - w / 2), int(y / 2 - h / 2)) def update_namespaces(self, namespaces=None): """ fetchs the available namespaces """ if namespaces is None: namespaces = self._engine.getModel().getNamespaces() a = set(self.namespace_list.items) b = set(namespaces) if self.namespace_list.items == list(namespaces): return self.namespace_list.items = a.union(b) else: self.namespace_list.items = namespaces self.namespace_list.items.sort() if namespaces: self.namespace_list.selected = 0 ns = namespaces[0] self.update_objects(namespace=ns) self.container.adaptLayout(True) def update_objects(self, namespace=None, objects=None): """ fetch the available objects for the selected namespace @type objects: list @param objects: list of fife.Object instances @type namespace: str @param namespace: namespace of the object """ if namespace is None and objects is None: return if objects is None and namespace is not None: objects = self._engine.getModel().getObjects(namespace) if objects is None: return if self._mode == _MODE_TEXT: object_list = [ ListItem(object.getId(), object.getNamespace()) for object in objects ] self.object_list.items = object_list elif self._mode == _MODE_IMAGE: self.object_list.removeAllChildren() object_list = [ ObjectIcon(object.getId(), object.getNamespace(), self._get_image(object=object)) for object in objects ] for index, object_icon in enumerate(object_list): object_icon.capture(object_icon._mouse_pressed, "mousePressed") object_icon.index = index object_icon.callback = self.object_id_selected self.object_list.addChild(object_icon) self.object_list.selected = 0 self.object_list.items = object_list self.container.adaptLayout(True) if object_list: self.object_list.selected = 0 self._current_object_id = object_list[0].object_id self.object_id_selected() def namespace_id_selected(self): """ callback for the namespace list """ index = self.namespace_list.selected if index >= 0: ns = self.namespace_list.items[index] self.update_objects(namespace=ns) def object_id_selected(self): """ callback for the object list """ index = self.object_list.selected if index >= 0: object_id = self.object_list.items[index].object_id namespace = self.object_list.items[index].namespace object = self._engine.getModel().getObject(object_id, namespace) self.object_selected(object) onObjectSelected.send(sender=self, object=object) def object_selected(self, object): """ plugin event on selecting a new object @type object: fife.Object @param object: selected object instance """ self.set_object(object=object) self.set_preview() def set_object(self, sender=None, object=None): """ set new active object for this plugin and notify the editor @note: the editor will create an instance of this object on the map once the player uses the insert command @type object: fife.Object @param object: selected object instance """ if sender == self: return self._object = object def on_dock(self): """ callback for dock event of B{Panel} widget """ side = self.container.dockarea.side if not side: return module = self.default_settings['module'] self.eds.set(module, 'dockarea', side) self.eds.set(module, 'docked', True) def on_undock(self): """ callback for undock event of B{Panel} widget """ self.set_mode(self._mode) self.set_orientation(orientation=self._default_orientation) self.container.hide() self.toggle() module = self.default_settings['module'] self.eds.set(module, 'dockarea', '') self.eds.set(module, 'docked', False) def toggle(self): """ shows / hides the gui """ if self.container.isVisible(): self.last_dockarea = self.container.dockarea self.container.hide() self._action_show.setChecked(False) else: if not self.container.isDocked(): self.container.show() self.container.x = self.default_x self.container.y = self.default_y else: self.container.setDocked(True) self.dockWidgetTo(self.container, self.last_dockarea) self._action_show.setChecked(True) def isEnabled(self): """ returns plugin status """ return self._enabled def getName(self): """ returns the plugin name as unicode string """ return u"Object selector" def getAuthor(self): return "FIFE" def getDescription(self): return "" def getLicense(self): return "" def getVersion(self): return "0.1" def _get_image(self, object_data=None, object=None): """ returns an image for the given object data @type object: fife.Object @param object: object instance @type object_data: ListItem @param object_data: wrapper class containing obj id and namespace @rtype result: fife.GuiImage @return result: gui image of the visual of the given object @return: fife.GuiImage """ if object_data is None and object is None: return if object_data is not None: object_id = object_data.object_id namespace = object_data.namespace object = self._engine.getModel().getObject(object_id, namespace) if object is None: return visual = object.get2dGfxVisual() result = None imageptr = None # try to find a usable image index = visual.getStaticImageIndexByAngle(0) # if no static image available, try default action if index == -1: action = object.getDefaultAction() if action: animation = action.get2dGfxVisual().getAnimationByAngle(0) imageptr = animation.getFrameByTimestamp(0) else: # static image found use the index to get the image from the image manager imageptr = self._engine.getImageManager().get(index) if imageptr is not None: result = fife.GuiImage(imageptr) return result def _search(self): """ callback for search field """ self.search_namespace(self.search_field.text) def search_namespace(self, text): """ search for the matching namespaces while the user is typing @type text: string @param text: user input """ results = [] # Format search terms terms = [term.lower() for term in text.split()] # Search if len(terms) > 0: namespaces = self._engine.getModel().getNamespaces() for namesp in namespaces: objects = self._engine.getModel().getObjects(namesp) for obj in objects: doAppend = True for term in terms: if obj.getId().lower().find(term) < 0: doAppend = False break if doAppend: results.append(obj) else: results = None self.update_objects(objects=results) def update(self): """ callback for postMapShown event - update plugin """ self.set_mode(self._mode) self.update_namespaces()
class ObjectSelector(plugin.Plugin): """ The B{ObjectSelector} plugin offers a gui that let you browse the loaded namespaces and their associated objects. It can be used in text- and image-mode. Text mode provides a preview image of the current selected object. @todo: - we need some sort of caching to prevent pychan from resizing all the object images over and over again - image aspect ratio is still broken - I guess my resize() function is junk (actually, I bet it is) - current selection of the user is overwritten on new updates """ ORIENTATION = { "Horizontal" : 0, "Vertical" : 1, } def __init__(self): super(ObjectSelector, self).__init__() # editor instance self._editor = scripts.editor.getEditor() self._engine = self._editor.getEngine() # plugin variables self._enabled = False self.last_dockarea = None self._action_show = None self._mode = _MODE_IMAGE self._object = None # @todo: we should store all the selection data here self._current_selection = { 'object' : None, 'object_id' : None, 'object_namespace' : None, 'namespace' : None, } # gui vars self.container = None self.default_x, self.default_y = _POSITION w,h = self._engine.getSettings().getScreenWidth(), self._engine.getSettings().getScreenHeight() self._panel_size = int(w * 0.25) / 2 self.max_x = int(w * 0.85) self.max_y = int(h * 0.7) if self.max_y < _MAX_PREVIEW_WRAPPER_SIZE[1]: self.max_y = _MAX_PREVIEW_WRAPPER_SIZE[1] + 20 # compensate for scrollbar self._orientation = ObjectSelector.ORIENTATION['Vertical'] self._default_orientation = ObjectSelector.ORIENTATION['Vertical'] self.wrappers = { ObjectSelector.ORIENTATION['Vertical'] : { 'wrapper' : None, 'image_mode_wrapper' : None, 'text_mode_wrapper' : None, }, ObjectSelector.ORIENTATION['Horizontal'] : { 'wrapper' : None, 'image_mode_wrapper' : None, 'text_mode_wrapper' : None, }, } # setting variables self.default_settings = _PLUGIN_SETTINGS self.eds = self._editor._settings self.update_settings() def enable(self): """ enables the plugin and connects to the editor """ if self._enabled: return self._enabled = True # Fifedit plugin data self._action_show = Action(self.getName(), checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) postMapShown.connect(self.update) onObjectSelected.connect(self.set_object) onObjectsImported.connect(self.update_namespaces) self.create() self.toggle() if self.settings['docked']: self._editor.dockWidgetTo(self.container, self.settings['dockarea']) def disable(self): """ disables the plugin and connects to the editor """ if self._enabled: return self._enabled = False postMapShown.disconnect(self.update_namespaces) onObjectSelected.disconnect(self.set_object) onObjectsImported.disconnect(self.update_namespaces) def set_orientation(self, orientation=None, key=None): if key is not None: if key not in ObjectSelector.ORIENTATION: return orientation = ObjectSelector.ORIENTATION[key] if orientation is None: return if orientation == ObjectSelector.ORIENTATION['Vertical']: self._orientation = ObjectSelector.ORIENTATION['Vertical'] self._max_size = (self._panel_size, self.max_y) else: self._orientation = ObjectSelector.ORIENTATION['Horizontal'] self._max_size = (self.max_x, self._panel_size) self._orientation = orientation self.update_orientation() def get_orientation(self): return self._orientation orientation = property(get_orientation, set_orientation) def update_orientation(self): """ change widget orientation """ self.container.removeAllChildren() wrapper = self.wrappers[self.orientation]['wrapper'] self.apply_mode() self.container.addChild(wrapper) self.container.max_size = self.container.min_size = self._max_size self.container.adaptLayout(True) self.map_callbacks() self.update_namespaces() def set_mode(self, mode): """ set new mode @type mode: int @param mode: int id of the mode, either 0 (text mode) or 1 (image mode) """ if mode not in _MODES: return self._mode = mode self.apply_mode() def toggle_mode(self): """ callback for button to toggle mode """ self.set_mode(int(not self._mode)) self.map_callbacks() self.update_namespaces() def apply_mode(self): """ set the gui into the current active mode @note: - text mode: list item is used - image mode: V/HBox with Icon childs is used """ wrapper = self.wrappers[self.orientation]['wrapper'] vert_img_wrapper = self.wrappers[1]['image_mode_wrapper'] vert_text_wrapper = self.wrappers[1]['text_mode_wrapper'] hor_img_wrapper = self.wrappers[0]['image_mode_wrapper'] hor_text_wrapper = self.wrappers[0]['text_mode_wrapper'] if self._mode == _MODE_TEXT: if self.orientation == ObjectSelector.ORIENTATION['Horizontal']: vert_img_wrapper.hide() vert_text_wrapper.hide() hor_img_wrapper.hide() hor_text_wrapper.show() elif self.orientation == ObjectSelector.ORIENTATION['Vertical']: vert_img_wrapper.hide() vert_text_wrapper.show() hor_img_wrapper.hide() hor_text_wrapper.hide() elif self._mode == _MODE_IMAGE: if self.orientation == ObjectSelector.ORIENTATION['Horizontal']: vert_img_wrapper.hide() vert_text_wrapper.hide() hor_img_wrapper.show() hor_text_wrapper.hide() elif self.orientation == ObjectSelector.ORIENTATION['Vertical']: vert_img_wrapper.show() vert_text_wrapper.hide() hor_img_wrapper.hide() hor_text_wrapper.hide() def mouse_clicked(self, event): if self.container.isDocked(): return if event.getButton() == fife.MouseEvent.RIGHT: self.set_orientation(orientation=int(not self.get_orientation())) event.consume() def create(self): """ creates the gui sceleton """ if self.container is not None: return self.container = pychan.loadXML('gui/objectselector.xml') self.container.position_technique = 'explicit' self.container.position = _POSITION self.container.name = self.getName() self.container.set_orientation = self.set_orientation self.container.capture(self.mouse_clicked, "mouseClicked") vert_wrapper = self.container.findChild(name='vertical_wrapper') hor_wrapper = self.container.findChild(name='horizontal_wrapper') self.wrappers[1]['wrapper'] = vert_wrapper self.wrappers[1]['image_mode_wrapper'] = vert_wrapper.findChild(name="image_mode_wrapper") self.wrappers[1]['text_mode_wrapper'] = vert_wrapper.findChild(name="text_mode_wrapper") self.wrappers[1]['image_mode_wrapper'].hide() self.wrappers[1]['text_mode_wrapper'].hide() self.wrappers[0]['wrapper'] = hor_wrapper self.wrappers[0]['image_mode_wrapper'] = hor_wrapper.findChild(name="image_mode_wrapper") self.wrappers[0]['text_mode_wrapper'] = hor_wrapper.findChild(name="text_mode_wrapper") self.wrappers[0]['image_mode_wrapper'].hide() self.wrappers[0]['text_mode_wrapper'].hide() self.container.removeChild(vert_wrapper) self.container.removeChild(hor_wrapper) self.set_orientation(orientation=self._orientation) self.container.afterUndock = self.on_undock self.container.afterDock = self.on_dock def map_callbacks(self): """ captures events for the main widgets """ btn = self.container.findChild(name="toggle_mode") btn.capture(self.toggle_mode) self.namespace_list = self.container.findChild(name="namespace_list") self.namespace_list.capture(self.namespace_id_selected, "action") self.namespace_list.capture(self.namespace_id_selected, "mouseWheelMovedUp") self.namespace_list.capture(self.namespace_id_selected, "mouseWheelMovedDown") self.search_field = self.container.findChild(name="search_field") self.search_field.capture(self._search) self.search_field.capture(self._search, "keyPressed") self.container.findChild(name="search_button").capture(self._search) if self._mode == _MODE_TEXT: subwrapper = self.wrappers[self.orientation]['text_mode_wrapper'] self.preview_icon = subwrapper.findChild(name="preview_icon") self.object_list = subwrapper.findChild(name="object_list") self.object_list.capture(self.object_id_selected, "action") self.object_list.capture(self.object_id_selected, "mouseWheelMovedUp") self.object_list.capture(self.object_id_selected, "mouseWheelMovedDown") elif self._mode == _MODE_IMAGE: subwrapper = self.wrappers[self.orientation]['image_mode_wrapper'] if self.orientation == ObjectSelector.ORIENTATION['Horizontal']: self.object_list = subwrapper.findChild(__class__=pychan.widgets.HBox, name="object_list") elif self.orientation == ObjectSelector.ORIENTATION['Vertical']: self.object_list = subwrapper.findChild(__class__=pychan.widgets.VBox, name="object_list") def set_preview(self): """ set the preview icon @note: - only text mode shows a preview icon """ if self._mode == _MODE_IMAGE: return if self._object is None: return image = self._get_image(object=self._object) if image is None: return w, h = image.getWidth(), image.getHeight() w, h = resize(w, h) self.preview_icon.image = image self.preview_icon.size = self.preview_icon.max_size = (w, h) parent = self.preview_icon.parent x, y = parent.size self.preview_icon.position = (int(x / 2 - w / 2), int(y / 2 - h / 2)) def update_namespaces(self, namespaces=None): """ fetchs the available namespaces """ if namespaces is None: namespaces = self._engine.getModel().getNamespaces() a = set(self.namespace_list.items) b = set(namespaces) if self.namespace_list.items == list(namespaces): return self.namespace_list.items = a.union(b) else: self.namespace_list.items = namespaces self.namespace_list.items.sort() if namespaces: self.namespace_list.selected = 0 ns = namespaces[0] self.update_objects(namespace=ns) self.container.adaptLayout(True) def update_objects(self, namespace=None, objects=None): """ fetch the available objects for the selected namespace @type objects: list @param objects: list of fife.Object instances @type namespace: str @param namespace: namespace of the object """ if namespace is None and objects is None: return if objects is None and namespace is not None: objects = self._engine.getModel().getObjects(namespace) if objects is None: return if self._mode == _MODE_TEXT: object_list = [ListItem(object.getId(), object.getNamespace()) for object in objects] self.object_list.items = object_list elif self._mode == _MODE_IMAGE: self.object_list.removeAllChildren() object_list = [ObjectIcon(object.getId(), object.getNamespace(), self._get_image(object=object)) for object in objects] for index, object_icon in enumerate(object_list): object_icon.capture(object_icon._mouse_pressed, "mousePressed") object_icon.index = index object_icon.callback = self.object_id_selected self.object_list.addChild(object_icon) self.object_list.selected = 0 self.object_list.items = object_list self.container.adaptLayout(True) if object_list: self.object_list.selected = 0 self._current_object_id = object_list[0].object_id self.object_id_selected() def namespace_id_selected(self): """ callback for the namespace list """ index = self.namespace_list.selected if index >= 0: ns = self.namespace_list.items[index] self.update_objects(namespace=ns) def object_id_selected(self): """ callback for the object list """ index = self.object_list.selected if index >= 0: object_id = self.object_list.items[index].object_id namespace = self.object_list.items[index].namespace object = self._engine.getModel().getObject(object_id, namespace) self.object_selected(object) onObjectSelected.send(sender=self, object=object) def object_selected(self, object): """ plugin event on selecting a new object @type object: fife.Object @param object: selected object instance """ self.set_object(object=object) self.set_preview() def set_object(self, sender=None, object=None): """ set new active object for this plugin and notify the editor @note: the editor will create an instance of this object on the map once the player uses the insert command @type object: fife.Object @param object: selected object instance """ if sender == self: return self._object = object def on_dock(self): """ callback for dock event of B{Panel} widget """ side = self.container.dockarea.side if not side: return module = self.default_settings['module'] self.eds.set(module, 'dockarea', side) self.eds.set(module, 'docked', True) def on_undock(self): """ callback for undock event of B{Panel} widget """ self.set_mode(self._mode) self.set_orientation(orientation=self._default_orientation) self.container.hide() self.toggle() module = self.default_settings['module'] self.eds.set(module, 'dockarea', '') self.eds.set(module, 'docked', False) def toggle(self): """ shows / hides the gui """ if self.container.isVisible(): self.last_dockarea = self.container.dockarea self.container.hide() self._action_show.setChecked(False) else: if not self.container.isDocked(): self.container.show() self.container.x = self.default_x self.container.y = self.default_y else: self.container.setDocked(True) self.dockWidgetTo(self.container, self.last_dockarea) self._action_show.setChecked(True) def isEnabled(self): """ returns plugin status """ return self._enabled def getName(self): """ returns the plugin name as unicode string """ return u"Object selector" def getAuthor(self): return "FIFE" def getDescription(self): return "" def getLicense(self): return "" def getVersion(self): return "0.1" def _get_image(self, object_data=None, object=None): """ returns an image for the given object data @type object: fife.Object @param object: object instance @type object_data: ListItem @param object_data: wrapper class containing obj id and namespace @rtype result: fife.GuiImage @return result: gui image of the visual of the given object @return: fife.GuiImage """ if object_data is None and object is None: return if object_data is not None: object_id = object_data.object_id namespace = object_data.namespace object = self._engine.getModel().getObject(object_id, namespace) if object is None: return visual = object.get2dGfxVisual() result = None imageptr = None # try to find a usable image index = visual.getStaticImageIndexByAngle(0) # if no static image available, try default action if index == -1: action = object.getDefaultAction() if action: animation = action.get2dGfxVisual().getAnimationByAngle(0) imageptr = animation.getFrameByTimestamp(0) else: # static image found use the index to get the image from the image manager imageptr = self._engine.getImageManager().get(index) if imageptr is not None: result = fife.GuiImage(imageptr) return result def _search(self): """ callback for search field """ self.search_namespace(self.search_field.text) def search_namespace(self, text): """ search for the matching namespaces while the user is typing @type text: string @param text: user input """ results = [] # Format search terms terms = [term.lower() for term in text.split()] # Search if len(terms) > 0: namespaces = self._engine.getModel().getNamespaces() for namesp in namespaces: objects = self._engine.getModel().getObjects(namesp) for obj in objects: doAppend = True for term in terms: if obj.getId().lower().find(term) < 0: doAppend = False break if doAppend: results.append(obj) else: results = None self.update_objects(objects=results) def update(self): """ callback for postMapShown event - update plugin """ self.set_mode(self._mode) self.update_namespaces()
class LightEdit(plugin.Plugin): """ The B{LightEdit} module is a plugin for FIFedit and allows to use Lighting current features: - click instance to add SimpleLight, LightImage, LightAnimation - outline highlighting of the selected object - changeing all SimpleLigh values and Image, Animation source """ def __init__(self): self.active = False self._camera = None self._layer = None self._enabled = False self._light = {} self._color = {} self._color.update(DEFAULT_GLOBAL_LIGHT) random.seed() def _reset(self): """ resets all dynamic vars, but leaves out static ones (e.g. camera, layer) """ self._instances = None self._light["stencil"] = -1 self._light["alpha"] = 0.0 self._light["src"] = -1 self._light["dst"] = -1 self._light["intensity"] = 0 self._light["red"] = 0 self._light["green"] = 0 self._light["blue"] = 0 self._light["radius"] = 0 self._light["subdivisions"] = 32 self._light["xstretch"] = 1 self._light["ystretch"] = 1 self._light["image"] = "" self._light["animation"] = "" self._simple_l = False self._image_l = False self._animation_l = False self._global_l = False if self._camera is not None: self.renderer.removeAllOutlines() self._widgets["group"].text = unicode(str("")) self._widgets["image"].text = unicode(str("")) self._widgets["animation"].text = unicode(str("")) def enable(self): """ plugin method """ if self._enabled is True: return self._editor = scripts.editor.getEditor() self.engine = self._editor.getEngine() self.imagepool = self.engine.getImagePool() self._animationpool = self.engine.getAnimationPool() self._showAction = Action(unicode(self.getName(), "utf-8"), checkable=True) scripts.gui.action.activated.connect(self.toggle_gui, sender=self._showAction) self._editor._tools_menu.addAction(self._showAction) events.onInstancesSelected.connect(self.input) self._reset() self.create_gui() def disable(self): """ plugin method """ if self._enabled is False: return self._reset() self.container.hide() self.removeAllChildren() events.onInstancesSelected.disconnect(self.input) self._editor._toolsMenu.removeAction(self._showAction) def isEnabled(self): """ plugin method """ return self._enabled def getName(self): """ plugin method """ return "Light editor" def create_gui(self): """ - creates the gui skeleton by loading the xml file FIXME: - move all dynamic widgets to dict """ self.container = pychan.loadXML('gui/lightedit.xml') self.container.mapEvents({ "reset": self.reset_light, "use": self.use_light, "simple_but": self.toggle_simple_gui, "image_but": self.toggle_image_gui, "animation_but": self.toggle_animation_gui, "global_but": self.toggle_global_gui, "selec_image": self.change_image, "selec_animation": self.change_animation, "stencil_up": cbwa(self.change_light, value=1, option="stencil"), "stencil_dn": cbwa(self.change_light, value=-1, option="stencil"), "stencil/mouseWheelMovedUp": cbwa(self.change_light, value=10, option="stencil"), "stencil/mouseWheelMovedDown": cbwa(self.change_light, value=-10, option="stencil"), "alpha_up": cbwa(self.change_light, value=0.01, option="alpha"), "alpha_dn": cbwa(self.change_light, value=-0.01, option="alpha"), "alpha/mouseWheelMovedUp": cbwa(self.change_light, value=0.1, option="alpha"), "alpha/mouseWheelMovedDown": cbwa(self.change_light, value=-0.1, option="alpha"), "intensity_up": cbwa(self.change_light, value=1, option="intensity"), "intensity_dn": cbwa(self.change_light, value=-1, option="intensity"), "intensity/mouseWheelMovedUp": cbwa(self.change_light, value=10, option="intensity"), "intensity/mouseWheelMovedDown": cbwa(self.change_light, value=-10, option="intensity"), "radius_up": cbwa(self.change_light, value=1, option="radius"), "radius_dn": cbwa(self.change_light, value=-1, option="radius"), "radius/mouseWheelMovedUp": cbwa(self.change_light, value=10, option="radius"), "radius/mouseWheelMovedDown": cbwa(self.change_light, value=-10, option="radius"), "subdivisions_up": cbwa(self.change_light, value=1, option="subdivisions"), "subdivisions_dn": cbwa(self.change_light, value=-1, option="subdivisions"), "subdivisions/mouseWheelMovedUp": cbwa(self.change_light, value=1, option="subdivisions"), "subdivisions/mouseWheelMovedDown": cbwa(self.change_light, value=-1, option="subdivisions"), "xstretch_up": cbwa(self.change_light, value=0.01, option="xstretch"), "xstretch_dn": cbwa(self.change_light, value=-0.01, option="xstretch"), "xstretch/mouseWheelMovedUp": cbwa(self.change_light, value=0.1, option="xstretch"), "xstretch/mouseWheelMovedDown": cbwa(self.change_light, value=-0.1, option="xstretch"), "ystretch_up": cbwa(self.change_light, value=0.01, option="ystretch"), "ystretch_dn": cbwa(self.change_light, value=-0.01, option="ystretch"), "ystretch/mouseWheelMovedUp": cbwa(self.change_light, value=0.1, option="ystretch"), "ystretch/mouseWheelMovedDown": cbwa(self.change_light, value=-0.1, option="ystretch"), "red_up": cbwa(self.change_light, value=1, option="red"), "red_dn": cbwa(self.change_light, value=-1, option="red"), "red/mouseWheelMovedUp": cbwa(self.change_light, value=10, option="red"), "red/mouseWheelMovedDown": cbwa(self.change_light, value=-10, option="red"), "green_up": cbwa(self.change_light, value=1, option="green"), "green_dn": cbwa(self.change_light, value=-1, option="green"), "green/mouseWheelMovedUp": cbwa(self.change_light, value=10, option="green"), "green/mouseWheelMovedDown": cbwa(self.change_light, value=-10, option="green"), "blue_up": cbwa(self.change_light, value=1, option="blue"), "blue_dn": cbwa(self.change_light, value=-1, option="blue"), "blue/mouseWheelMovedUp": cbwa(self.change_light, value=10, option="blue"), "blue/mouseWheelMovedDown": cbwa(self.change_light, value=-10, option="blue"), "src_up": cbwa(self.change_light, value=1, option="src"), "src_dn": cbwa(self.change_light, value=-1, option="src"), "src/mouseWheelMovedUp": cbwa(self.change_light, value=1, option="src"), "src/mouseWheelMovedDown": cbwa(self.change_light, value=-1, option="src"), "dst_up": cbwa(self.change_light, value=1, option="dst"), "dst_dn": cbwa(self.change_light, value=-1, option="dst"), "dst/mouseWheelMovedUp": cbwa(self.change_light, value=1, option="dst"), "dst/mouseWheelMovedDown": cbwa(self.change_light, value=-1, option="dst"), "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.1, r=True), "value_R/mouseWheelMovedDown": cbwa(self.decrease_color, step=0.1, 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.1, g=True), "value_G/mouseWheelMovedDown": cbwa(self.decrease_color, step=0.1, 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.1, b=True), "value_B/mouseWheelMovedDown": cbwa(self.decrease_color, step=0.1, 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.1, a=True), "value_A/mouseWheelMovedDown": cbwa(self.decrease_color, step=0.1, a=True), }) self._widgets = { "group": self.container.findChild(name="group"), "ins_id": self.container.findChild(name="ins_id"), "obj_id": self.container.findChild(name="obj_id"), "stencil": self.container.findChild(name="stencil"), "alpha": self.container.findChild(name="alpha"), "intensity": self.container.findChild(name="intensity"), "red": self.container.findChild(name="red"), "green": self.container.findChild(name="green"), "blue": self.container.findChild(name="blue"), "radius": self.container.findChild(name="radius"), "subdivisions": self.container.findChild(name="subdivisions"), "xstretch": self.container.findChild(name="xstretch"), "ystretch": self.container.findChild(name="ystretch"), "src": self.container.findChild(name="src"), "dst": self.container.findChild(name="dst"), "image": self.container.findChild(name="image"), "animation": self.container.findChild(name="animation"), "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"), } self._gui_simple_panel_wrapper = self.container.findChild( name="simple_panel_wrapper") self._gui_simple_panel = self._gui_simple_panel_wrapper.findChild( name="simple_panel") self._gui_image_panel_wrapper = self.container.findChild( name="image_panel_wrapper") self._gui_image_panel = self._gui_image_panel_wrapper.findChild( name="image_panel") self._gui_animation_panel_wrapper = self.container.findChild( name="animation_panel_wrapper") self._gui_animation_panel = self._gui_animation_panel_wrapper.findChild( name="animation_panel") self._gui_global_panel_wrapper = self.container.findChild( name="global_panel_wrapper") self._gui_global_panel = self._gui_global_panel_wrapper.findChild( name="global_panel") def update_gui(self): """ updates the gui """ self._widgets["ins_id"].text = unicode(str(self._instances[0].getId())) self._widgets["obj_id"].text = unicode( str(self._instances[0].getObject().getId())) self._widgets["stencil"].text = unicode(str(self._light["stencil"])) self._widgets["alpha"].text = unicode(str(self._light["alpha"])) self._widgets["src"].text = unicode(str(self._light["src"])) self._widgets["dst"].text = unicode(str(self._light["dst"])) self._widgets["intensity"].text = unicode(str( self._light["intensity"])) self._widgets["red"].text = unicode(str(self._light["red"])) self._widgets["green"].text = unicode(str(self._light["green"])) self._widgets["blue"].text = unicode(str(self._light["blue"])) self._widgets["radius"].text = unicode(str(self._light["radius"])) self._widgets["subdivisions"].text = unicode( str(self._light["subdivisions"])) self._widgets["xstretch"].text = unicode(str(self._light["xstretch"])) self._widgets["ystretch"].text = unicode(str(self._light["ystretch"])) 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"])) if self._simple_l: if not self._gui_simple_panel_wrapper.findChild( name="simple_panel"): self._gui_simple_panel_wrapper.addChild(self._gui_simple_panel) else: if self._gui_simple_panel_wrapper.findChild(name="simple_panel"): self._gui_simple_panel_wrapper.removeChild( self._gui_simple_panel) if self._image_l: if not self._gui_image_panel_wrapper.findChild(name="image_panel"): self._gui_image_panel_wrapper.addChild(self._gui_image_panel) else: if self._gui_image_panel_wrapper.findChild(name="image_panel"): self._gui_image_panel_wrapper.removeChild( self._gui_image_panel) if self._animation_l: if not self._gui_animation_panel_wrapper.findChild( name="animation_panel"): self._gui_animation_panel_wrapper.addChild( self._gui_animation_panel) else: if self._gui_animation_panel_wrapper.findChild( name="animation_panel"): self._gui_animation_panel_wrapper.removeChild( self._gui_animation_panel) if self._global_l: if not self._gui_global_panel_wrapper.findChild( name="global_panel"): self._gui_global_panel_wrapper.addChild(self._gui_global_panel) else: if self._gui_global_panel_wrapper.findChild(name="global_panel"): self._gui_global_panel_wrapper.removeChild( self._gui_global_panel) self.container.adaptLayout(False) def toggle_gui(self): """ show / hide the gui """ if self.active is True: 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) def toggle_simple_gui(self): if self._simple_l: self._simple_l = False else: self._simple_l = True self._image_l = False self._animation_l = False self.update_gui() def toggle_image_gui(self): if self._image_l: self._image_l = False else: self._simple_l = False self._image_l = True self._animation_l = False self.update_gui() def toggle_animation_gui(self): if self._animation_l: self._animation_l = False else: self._simple_l = False self._image_l = False self._animation_l = True self.update_gui() def toggle_global_gui(self): if self._global_l: self._global_l = False else: self._global_l = True self.update_gui() def init_data(self): color = self._camera.getLightingColor() self._color["R"] = color[0] self._color["G"] = color[1] self._color["B"] = color[2] self._color["A"] = color[3] groups = self.lightrenderer.getGroups() for group in groups: infos = self.lightrenderer.getLightInfo(group) for info in infos: node = info.getNode() if node.getInstance() is None: continue if node.getInstance().getId() == self._instances[0].getId(): self._widgets["group"].text = unicode(str(group)) self._light["stencil"] = info.getStencil() self._light["alpha"] = info.getAlpha() self._light["src"] = info.getSrcBlend() self._light["dst"] = info.getDstBlend() if str(info.getName()) == "simple": self._light["red"] = info.getColor()[0] self._light["green"] = info.getColor()[1] self._light["blue"] = info.getColor()[2] self._light["intensity"] = info.getColor()[3] self._light["radius"] = info.getRadius() self._light["subdivisions"] = info.getSubdivisions() self._light["xstretch"] = info.getXStretch() self._light["ystretch"] = info.getYStretch() self.toggle_simple_gui() elif str(info.getName()) == "image": if info.getId() == -1: continue img = self.imagepool.getImage(info.getId()) name = img.getResourceFile() self._widgets["image"].text = unicode(str(name)) self._light["image"] = info.getId() self.toggle_image_gui() elif str(info.getName()) == "animation": if info.getId() == -1: continue ani = self._animationpool.getAnimation(info.getId()) count = 0 newstr = '' image = ani.getFrame(ani.getActionFrame()) fname = image.getResourceFile() strings = ([str(s) for s in fname.split('/')]) leng = len(strings) - 1 while count < leng: newstr = str(newstr + strings[count] + '/') count += 1 self._widgets["animation"].text = unicode( str(newstr + 'animation.xml')) self._light["animation"] = info.getId() self.toggle_animation_gui() def change_image(self): file = self._editor.getObject().getResourceFile() tree = ET.parse(file) img_lst = tree.findall("image") for image in img_lst: source = image.get('source') path = file.split('/') path.pop() path.append(str(source)) self._widgets["image"].text = unicode(str('/'.join(path))) break def change_animation(self): file = self._editor.getObject().getResourceFile() tree = ET.parse(file) ani_lst = tree.findall("animation") if not ani_lst: act_lst = tree.findall("action") if not act_lst: return for act in act_lst: ani_lst = act.findall("animation") if ani_lst: break for animation in ani_lst: source = animation.get('source') path = file.split('/') path.pop() path.append(str(source)) self._widgets["animation"].text = unicode(str('/'.join(path))) break def reset_light(self): self._light["stencil"] = -1 self._light["alpha"] = 0.0 self._light["src"] = -1 self._light["dst"] = -1 self._light["intensity"] = 0 self._light["red"] = 0 self._light["green"] = 0 self._light["blue"] = 0 self._light["radius"] = 0 self._light["subdivisions"] = 32 self._light["xstretch"] = 1 self._light["ystretch"] = 1 self._light["image"] = "" self._light["animation"] = "" self.lightrenderer.removeAll(str(self._widgets["group"]._getText())) self._widgets["group"].text = unicode(str("")) self._widgets["image"].text = unicode(str("")) self._widgets["animation"].text = unicode(str("")) self.update_gui() def use_light(self): if not self._instances[0]: return counter = 1 if self._widgets["ins_id"]._getText() == "": objid = self._instances[0].getObject().getId() insid = str(objid + str(counter)) while bool(self._layer.getInstance(insid)): counter = int(counter + 1) insid = str(objid + str(counter)) self._instances[0].setId(insid) if self._light["stencil"] is not -1 and self._light["alpha"] is not 0.0: self.stencil_test() if self._simple_l: self.simple_light() if self._image_l: self.image_light() if self._animation_l: self.animation_light() def highlight_selected_instance(self): """ highlights selected instance """ self.renderer.removeAllOutlines() self.renderer.addOutlined(self._instances[0], WHITE["r"], WHITE["g"], WHITE["b"], OUTLINE_SIZE) def change_light(self, value=0.01, option=None): self._light[option] = self._light[option] + value if self._light[option] + value < -1 and (option == "src" or option == "dst" or option == "stencil"): self._light[option] = -1 if self._light[ option] + value < 0 and option != "src" and option != "dst" and option != "stencil": self._light[option] = 0 if self._light[option] + value > 7 and (option == "src" or option == "dst"): self._light[option] = 7 if self._light[option] + value > 255 and ( option == "intensity" or option == "red" or option == "green" or option == "blue" or option == "stencil"): self._light[option] = 255 if self._light[option] + value > 1 and option == "alpha": self._light[option] = 1.0 self.update_gui() def stencil_test(self): self.lightrenderer.addStencilTest( str(self._widgets["group"]._getText()), self._light["stencil"], self._light["alpha"]) def simple_light(self): if not self._instances[0]: return self.lightrenderer.removeAll(str(self._widgets["group"]._getText())) node = fife.LightRendererNode(self._instances[0]) self.lightrenderer.addSimpleLight( str(self._widgets["group"]._getText()), node, self._light["intensity"], self._light["radius"], self._light["subdivisions"], self._light["xstretch"], self._light["ystretch"], self._light["red"], self._light["green"], self._light["blue"], self._light["src"], self._light["dst"], ) def image_light(self): if not self._instances[0]: return self.lightrenderer.removeAll(str(self._widgets["group"]._getText())) image = str(self._widgets["image"]._getText()) if image == "": return img_id = self.imagepool.addResourceFromFile(image) self._light["image"] = int(img_id) node = fife.LightRendererNode(self._instances[0]) self.lightrenderer.addImage( str(self._widgets["group"]._getText()), node, self._light["image"], self._light["src"], self._light["dst"], ) def animation_light(self): if not self._instances[0]: return self.lightrenderer.removeAll(str(self._widgets["group"]._getText())) animation = str(self._widgets["animation"]._getText()) if animation == "": return rloc = fife.ResourceLocation(animation) ani_id = self._animationpool.addResourceFromLocation(rloc) self._light["animation"] = int(ani_id) node = fife.LightRendererNode(self._instances[0]) self.lightrenderer.addAnimation( str(self._widgets["group"]._getText()), node, self._light["animation"], self._light["src"], self._light["dst"], ) def reset_global_light(self): """ reset global light to default values (1.0) """ 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: if self._color["R"] + step > 1.0: self._color["R"] = 1.0 else: self._color["R"] += step if g: if self._color["G"] + step > 1.0: self._color["G"] = 1.0 else: self._color["G"] += step if b: if self._color["B"] + step > 1.0: self._color["B"] = 1.0 else: self._color["B"] += step if a: if self._color["A"] + step > 1.0: self._color["A"] = 1.0 else: 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: if self._color["R"] - step < 0.0: self._color["R"] = 0.0 else: self._color["R"] -= step if g: if self._color["G"] - step < 0.0: self._color["G"] = 0.0 else: self._color["G"] -= step if b: if self._color["B"] - step < 0.0: self._color["B"] = 0.0 else: self._color["B"] -= step if a: if self._color["A"] - step < 0.0: self._color["A"] = 0.0 else: self._color["A"] -= step self.update_gui() self.set_global_light() def random_color(self): """ generate random values for color channels """ self._color["R"] = random.uniform(0, 1) self._color["G"] = random.uniform(0, 1) self._color["B"] = random.uniform(0, 1) self._color["A"] = random.uniform(0, 1) self.update_gui() self.set_global_light() def set_global_light(self): """ update the global light with the current set colors """ self._camera.setLightingColor(self._color["R"], self._color["G"], self._color["B"], self._color["A"]) def input(self, instances): if instances != self._instances: if self.active is True: self._reset() self._instances = instances if self._camera is None: self._camera = self._editor.getActiveMapView().getCamera() self.renderer = fife.InstanceRenderer.getInstance( self._camera) self.lightrenderer = fife.LightRenderer.getInstance( self._camera) self._layer = self._editor.getActiveMapView().getController( )._layer if self._instances != (): self.init_data() self.highlight_selected_instance() self.update_gui() self.container.show() else: self._reset() self.container.hide() self.container.adaptLayout(False)
class LayerTool(plugin.Plugin): """ The B{LayerTool} allows to select and show / hide layers of a loaded map as well as creating new layers or edit layer properties """ # default should be pychan default, highlight can be choosen (format: r,g,b) DEFAULT_BACKGROUND_COLOR = pychan.internal.DEFAULT_STYLE['default'][ 'base_color'] HIGHLIGHT_BACKGROUND_COLOR = pychan.internal.DEFAULT_STYLE['default'][ 'selection_color'] # the dynamicly created widgets have the name scheme prefix + layerid LABEL_NAME_PREFIX = "select_" def __init__(self): super(LayerTool, self).__init__() # Editor instance self._editor = scripts.editor.getEditor() # Plugin variables self._enabled = False # Current mapview self._mapview = None # Toolbar button to display LayerTool self._action_show = None # GUI self._layer_wizard = None self.container = None self.wrapper = None self.remove_layer_button = None self.create_layer_button = None self.edit_layer_button = None self.default_settings = _PLUGIN_SETTINGS self.eds = self._editor._settings self.update_settings() #--- Plugin functions ---# def enable(self): """ Enable plugin """ if self._enabled: return # Fifedit plugin data self._action_show = Action(u"LayerTool", checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) self.create() self.toggle() events.postMapShown.connect(self.update) events.preMapClosed.connect(self._mapClosed) if self.settings['docked']: self._editor.dockWidgetTo(self.container, self.settings['dockarea']) def disable(self): """ Disable plugin """ if not self._enabled: return self.container.setDocked(False) self.container.hide() events.postMapShown.disconnect(self.update) events.preMapClosed.disconnect(self._mapClosed) self._editor._tools_menu.removeAction(self._action_show) def isEnabled(self): """ Returns True if plugin is enabled """ return self._enabled def getName(self): """ Return plugin name """ return u"Layertool" #--- End plugin functions ---# def _mapClosed(self): self.update(mapview=None) def showLayerWizard(self): """ Show layer wizard """ if not self._mapview: return if self._layer_wizard: self._layer_wizard._widget.hide() self._layer_wizard = LayerDialog(self._editor.getEngine(), self._mapview.getMap(), callback=self._layerCreated) def showEditDialog(self): """ Show layerdialog for active layer """ if not self._mapview: return layer = self.getActiveLayer() if not layer: return if self._layer_wizard: self._layer_wizard._widget.hide() self._layer_wizard = LayerDialog(self._editor.getEngine(), self._mapview.getMap(), layer=layer, callback=cbwa(self.update, self._mapview)) def clear(self): """ Remove all subwrappers """ self.wrapper.removeAllChildren() def update(self, mapview): """ Update layertool with information from mapview We group one ToggleButton and one Label into a HBox, the main wrapper itself is a VBox and we also capture both the Button and the Label to listen for mouse actions @type event: object @param event: pychan mouse event """ layers = [] self._mapview = mapview if self._mapview is not None: layers = self._mapview.getMap().getLayers() self.clear() if len(layers) <= 0: if not self._mapview: layerid = "No map is open" else: layerid = "No layers" subwrapper = pychan.widgets.HBox() layerLabel = pychan.widgets.Label() layerLabel.text = unicode(layerid) layerLabel.name = LayerTool.LABEL_NAME_PREFIX + layerid subwrapper.addChild(layerLabel) self.wrapper.addChild(subwrapper) active_layer = self.getActiveLayer() if active_layer: active_layer = active_layer.getId() for layer in reversed(layers): layerid = layer.getId() subwrapper = pychan.widgets.HBox() toggleVisibleButton = pychan.widgets.ToggleButton( hexpand=False, up_image="gui/icons/is_visible.png", down_image="gui/icons/is_visible.png", hover_image="gui/icons/is_visible.png") toggleVisibleButton.name = "toggle_" + layerid if layer.areInstancesVisible(): toggleVisibleButton.toggled = True toggleVisibleButton.capture(self.toggleLayerVisibility) layerLabel = pychan.widgets.Label() layerLabel.text = unicode(layerid) layerLabel.name = LayerTool.LABEL_NAME_PREFIX + layerid layerLabel.capture(self.selectLayer, "mousePressed") if active_layer == layerid: layerLabel.background_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR layerLabel.foreground_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR layerLabel.base_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR subwrapper.addChild(toggleVisibleButton) subwrapper.addChild(layerLabel) self.wrapper.addChild(subwrapper) self.container.adaptLayout() def toggleLayerVisibility(self, event, widget): """ Callback for ToggleButtons Toggle the chosen layer visible / invisible. If the active layer is hidden, it will be deselected. @type event: object @param event: pychan mouse event @type widget: object @param widget: the pychan widget where the event occurs, transports the layer id in it's name """ layerid = widget.name[len(LayerTool.LABEL_NAME_PREFIX):] layer = self._mapview.getMap().getLayer(layerid) active_layer = self.getActiveLayer() if active_layer: active_layer = active_layer.getId() if layer.areInstancesVisible(): layer.setInstancesVisible(False) else: layer.setInstancesVisible(True) if active_layer == layerid: self.resetSelection() def getActiveLayer(self): """ Returns the active layer """ if self._mapview: return self._mapview.getController()._layer def selectLayer(self, event, widget=None, layerid=None): """ Callback for Labels We hand the layerid over to the mapeditor module to select a new active layer Additionally, we mark the active layer widget (changing base color) and reseting the previous one @type event: object @param event: pychan mouse event @type widget: object @param widget: the pychan widget where the event occurs, transports the layer id in it's name @type layerid: string @param layerid: the layer id """ if not widget and not layerid: print "No layer ID or widget passed to LayerTool.selectLayer" return if widget is not None: layerid = widget.name[len(LayerTool.LABEL_NAME_PREFIX):] self.resetSelection() widget.background_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR widget.foreground_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR widget.base_color = LayerTool.HIGHLIGHT_BACKGROUND_COLOR self._mapview.getController().selectLayer(layerid) def resetSelection(self): """ Deselects selected layer """ previous_active_layer = self.getActiveLayer() if previous_active_layer is not None: previous_layer_id = previous_active_layer.getId() previous_active_widget = self.container.findChild( name=LayerTool.LABEL_NAME_PREFIX + previous_layer_id) previous_active_widget.background_color = LayerTool.DEFAULT_BACKGROUND_COLOR previous_active_widget.foreground_color = LayerTool.DEFAULT_BACKGROUND_COLOR previous_active_widget.base_color = LayerTool.DEFAULT_BACKGROUND_COLOR previous_active_widget.text = unicode(previous_layer_id) self._mapview.getController().selectLayer(None) def removeSelectedLayer(self): """ Deletes the selected layer """ if not self._mapview: return if self._mapview.getMap().getLayerCount() <= 1: print "Can't remove the last layer" return layer = self.getActiveLayer() if not layer: return self.resetSelection() map = self._mapview.getMap() # FIFE will crash if we try to delete the layer which is in use by a camera # so we will set the camera to another layer instead for cam in map.getCameras(): if cam.getLocationRef().getMap().getId() != map.getId(): continue if cam.getLocation().getLayer().getId() != layer.getId(): continue for l in map.getLayers(): if l.getId() == layer.getId(): continue cam.getLocationRef().setLayer(l) break map.deleteLayer(layer) self.update(self._mapview) def toggle(self): """ Toggles the layertool visible / invisible and sets dock status """ if self.container.isVisible() or self.container.isDocked(): self.container.setDocked(False) self.container.hide() self._action_show.setChecked(False) else: self.container.show() self._action_show.setChecked(True) self._adjustPosition() def create(self): """ Create the basic gui container """ self.container = pychan.loadXML('gui/layertool.xml') self.wrapper = self.container.findChild(name="layers_wrapper") self.remove_layer_button = self.container.findChild( name="remove_layer_button") self.create_layer_button = self.container.findChild( name="add_layer_button") self.edit_layer_button = self.container.findChild( name="edit_layer_button") self.remove_layer_button.capture(self.removeSelectedLayer) self.remove_layer_button.capture( cbwa(self._editor.getStatusBar().showTooltip, self.remove_layer_button.helptext), 'mouseEntered') self.remove_layer_button.capture( self._editor.getStatusBar().hideTooltip, 'mouseExited') self.create_layer_button.capture(self.showLayerWizard) self.create_layer_button.capture( cbwa(self._editor.getStatusBar().showTooltip, self.create_layer_button.helptext), 'mouseEntered') self.create_layer_button.capture( self._editor.getStatusBar().hideTooltip, 'mouseExited') self.edit_layer_button.capture(self.showEditDialog) self.edit_layer_button.capture( cbwa(self._editor.getStatusBar().showTooltip, self.edit_layer_button.helptext), 'mouseEntered') self.edit_layer_button.capture(self._editor.getStatusBar().hideTooltip, 'mouseExited') self.update(None) # overwrite Panel.afterUndock self.container.afterUndock = self.on_undock self.container.afterDock = self.on_dock def on_dock(self): """ callback for dock event of B{Panel} widget """ side = self.container.dockarea.side if not side: return module = self.default_settings['module'] self.eds.set(module, 'dockarea', side) self.eds.set(module, 'docked', True) def on_undock(self): """ callback for undock event of B{Panel} widget """ self.container.hide() self.toggle() module = self.default_settings['module'] self.eds.set(module, 'dockarea', '') self.eds.set(module, 'docked', False) def _adjustPosition(self): """ Adjusts the position of the container - we don't want to let the window appear at the center of the screen. (new default position: left, beneath the tools window) """ self.container.position = (50, 200) def _layerCreated(self, layer): self.update(self._mapview) self.selectLayer( None, self.wrapper.findChild(name=LayerTool.LABEL_NAME_PREFIX + layer.getId()))
class RegionTool(plugin.Plugin): """ The B{RegionTool} allows to select and show / hide regions of a loaded map as well as creating new regions or edit region properties """ # default should be pychan default, highlight can be choosen (format: r,g,b) DEFAULT_BACKGROUND_COLOR = pychan.internal.DEFAULT_STYLE['default']['base_color'] HIGHLIGHT_BACKGROUND_COLOR = pychan.internal.DEFAULT_STYLE['default']['selection_color'] # the dynamicly created widgets have the name scheme prefix + regionid LABEL_NAME_PREFIX = "select_" def __init__(self): super(RegionTool, self).__init__() # Editor instance self._editor = scripts.editor.getEditor() self.regions = {} self.selected_region = None # Plugin variables self._enabled = False # Current mapview self._mapview = None # Toolbar button to display RegionTool self._action_show = None # GUI self._region_wizard = None self.container = None self.wrapper = None self.remove_region_button = None self.create_region_button = None self.edit_region_button = None self.default_settings = _PLUGIN_SETTINGS self.eds = self._editor._settings self.update_settings() self.renderer = None self.region_layer = None #--- Plugin functions ---# def enable(self): """ Enable plugin """ if self._enabled: return # Fifedit plugin data self._action_show = Action(u"RegionTool", checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) self.create() self.toggle() postMapShown.connect(self.onNewMap) preMapClosed.connect(self._mapClosed) postSave.connect(self.save) if self.settings['docked']: self._editor.dockWidgetTo(self.container, self.settings['dockarea']) def disable(self): """ Disable plugin """ if not self._enabled: return self.container.setDocked(False) self.container.hide() postMapShown.disconnect(self.update) preMapClosed.disconnect(self._mapClosed) self._editor._tools_menu.removeAction(self._action_show) def isEnabled(self): """ Returns True if plugin is enabled """ return self._enabled; def getName(self): """ Return plugin name """ return u"Regiontool" #--- End plugin functions ---# def _mapClosed(self): self.onNewMap(mapview=None) def showRegionWizard(self): """ Show region wizard """ if not self._mapview: return if self._region_wizard: self._region_wizard._widget.hide() self._region_wizard = RegionDialog(self._editor.getEngine(), self.regions, callback=self._regionCreated) def showEditDialog(self): """ Show regiondialog for active region """ if not self._mapview: return if not self.selected_region: return if self._region_wizard: self._region_wizard._widget.hide() callback = lambda region: self._regionEdited(self.selected_region, region) self._region_wizard = RegionDialog(self._editor.getEngine(), self.regions, region=self.selected_region, callback=callback ) def clear_region_list(self): """ Remove all subwrappers """ self.wrapper.removeAllChildren() def onNewMap(self, mapview): """ Update regiontool with information from mapview @type event: scripts.MapView @param event: the view of the new map """ self._mapview = mapview self.regions = {} layer_list = [] if not mapview is None: self.renderer = fife.GenericRenderer.getInstance( self._mapview.getCamera()) self.renderer.setEnabled(True) layers = self._mapview.getMap().getLayers() for layer in reversed(layers): layer_list.append(layer.getId()) try: filename = mapview.getMap().getFilename() filename = "%s_regions.yaml" % os.path.splitext(filename)[0] regions_file = file(filename, "r") for name, region_data in yaml.load(regions_file).iteritems(): x_pos = region_data[0] y_pos = region_data[1] width = region_data[2] height = region_data[3] rect = fife.DoubleRect(x_pos, y_pos, width, height) region = Region(name, rect) self.regions[name] = region except (RuntimeError, IOError): pass self.select_layer_drop_down.setInitialData(layer_list) size = [self.container.size[0], 15] self.select_layer_drop_down.min_size = size self.select_layer_drop_down.size = size self.select_layer_drop_down.selected = 0 self.update_region_layer() self.update() def update_region_layer(self): """Updates the layer the regions are drawn on""" if self._mapview is None: return layer_id = self.select_layer_drop_down.selected_item self.region_layer = self._mapview.getMap().getLayer(layer_id) self.renderer.addActiveLayer(self.region_layer) self.update() def update(self): """ Update regiontool We group one ToggleButton and one Label into a HBox, the main wrapper itself is a VBox and we also capture both the Button and the Label to listen for mouse actions """ self.clear_region_list() if len(self.regions) <= 0: if not self._mapview: regionid = "No map is open" else: regionid = "No regions" subwrapper = pychan.widgets.HBox() regionLabel = pychan.widgets.Label() regionLabel.text = unicode(regionid) regionLabel.name = RegionTool.LABEL_NAME_PREFIX + regionid subwrapper.addChild(regionLabel) self.wrapper.addChild(subwrapper) if self._mapview: self.renderer.removeAll("region") for name, region in self.regions.iteritems(): rect = region.rect region_dict = [] point1 = fife.ExactModelCoordinate(rect.x, rect.y) loc1 = fife.Location(self.region_layer) loc1.setExactLayerCoordinates(point1) node1 = fife.RendererNode(loc1) region_dict.append(node1) point2 = fife.ExactModelCoordinate(rect.x, rect.y + rect.h) loc2 = fife.Location(self.region_layer) loc2.setExactLayerCoordinates(point2) node2 = fife.RendererNode(loc2) region_dict.append(node2) point3 = fife.ExactModelCoordinate(rect.x + rect.w, rect.y + rect.h) loc3 = fife.Location(self.region_layer) loc3.setExactLayerCoordinates(point3) node3 = fife.RendererNode(loc3) region_dict.append(node3) point4 = fife.ExactModelCoordinate(rect.x + rect.w, rect.y) loc4 = fife.Location(self.region_layer) loc4.setExactLayerCoordinates(point4) node4 = fife.RendererNode(loc4) region_dict.append(node4) color = [255, 0, 0, 127] if name == self.selected_region: color[3] = 255 self.renderer.addQuad("region", region_dict[0], region_dict[1], region_dict[2], region_dict[3], *color) font = get_manager().getDefaultFont() self.renderer.addText("region", region_dict[0], font, name) for region in self.regions.itervalues(): regionid = region.name subwrapper = pychan.widgets.HBox() regionLabel = pychan.widgets.Label() regionLabel.text = unicode(regionid) regionLabel.name = RegionTool.LABEL_NAME_PREFIX + regionid regionLabel.capture(self.selectRegion, "mousePressed") subwrapper.addChild(regionLabel) self.wrapper.addChild(subwrapper) self.container.adaptLayout() def selectRegion(self, event, widget=None, regionid=None): """ Callback for Labels We hand the regionid over to the mapeditor module to select a new active region Additionally, we mark the active region widget (changing base color) and reseting the previous one @type event: object @param event: pychan mouse event @type widget: object @param widget: the pychan widget where the event occurs, transports the region id in it's name @type regionid: string @param regionid: the region id """ if not widget and not regionid: print "No region ID or widget passed to RegionTool.selectRegion" return if widget is not None: regionid = widget.name[len(RegionTool.LABEL_NAME_PREFIX):] self.selected_region = regionid self.update() def resetSelection(self): """ Deselects selected region """ self.selected_region = None self.update() def removeSelectedRegion(self): """ Deletes the selected region """ if self.regions.has_key(self.selected_region): del self.regions[self.selected_region] self.resetSelection() def toggle(self): """ Toggles the regiontool visible / invisible and sets dock status """ if self.container.isVisible() or self.container.isDocked(): self.container.setDocked(False) self.container.hide() self._action_show.setChecked(False) else: self.container.show() self._action_show.setChecked(True) self._adjustPosition() def create(self): """ Create the basic gui container """ self.container = pychan.loadXML('gui/regiontool.xml') self.wrapper = self.container.findChild(name="regions_wrapper") self.remove_region_button = self.container.findChild(name="remove_region_button") self.create_region_button = self.container.findChild(name="add_region_button") self.edit_region_button = self.container.findChild(name="edit_region_button") self.remove_region_button.capture(self.removeSelectedRegion) self.remove_region_button.capture(cbwa(self._editor.getStatusBar().showTooltip, self.remove_region_button.helptext), 'mouseEntered') self.remove_region_button.capture(self._editor.getStatusBar().hideTooltip, 'mouseExited') self.create_region_button.capture(self.showRegionWizard) self.create_region_button.capture(cbwa(self._editor.getStatusBar().showTooltip, self.create_region_button.helptext), 'mouseEntered') self.create_region_button.capture(self._editor.getStatusBar().hideTooltip, 'mouseExited') self.edit_region_button.capture(self.showEditDialog) self.edit_region_button.capture(cbwa(self._editor.getStatusBar().showTooltip, self.edit_region_button.helptext), 'mouseEntered') self.edit_region_button.capture(self._editor.getStatusBar().hideTooltip, 'mouseExited') self.select_layer_drop_down = self.container.findChild(name="layer_select_drop_down") self.select_layer_drop_down.capture(self.update_region_layer) self.onNewMap(None) # overwrite Panel.afterUndock self.container.afterUndock = self.on_undock self.container.afterDock = self.on_dock def on_dock(self): """ callback for dock event of B{Panel} widget """ side = self.container.dockarea.side if not side: return module = self.default_settings['module'] self.eds.set(module, 'dockarea', side) self.eds.set(module, 'docked', True) def on_undock(self): """ callback for undock event of B{Panel} widget """ self.container.hide() self.toggle() module = self.default_settings['module'] self.eds.set(module, 'dockarea', '') self.eds.set(module, 'docked', False) def _adjustPosition(self): """ Adjusts the position of the container - we don't want to let the window appear at the center of the screen. (new default position: left, beneath the tools window) """ self.container.position = (50, 200) def _regionEdited(self, old_region, region): del self.regions[old_region] self._regionCreated(region) def _regionCreated(self, region): self.regions[region.name] = region self.update() def save(self, mapview): """Save the regions to a file""" filename = mapview.getMap().getFilename() filename = "%s_regions.yaml" % os.path.splitext(filename)[0] regions_file = file(filename, "w") yaml.dump(self.regions, regions_file)
class CameraEdit(plugin.Plugin): def __init__(self): self._enabled = False # Camera instance self._camera = None # Editor instance self._editor = None # Toolbar button to display Camera Editor self._action_show = None # GUI self._container = None self._ok_button = None self._cancel_button = None def enable(self): """ plugin method """ if self._enabled is True: return self._editor = scripts.editor.getEditor() #self._camera = self._editor.getActiveMapView().getCamera() self._action_show = Action(u"Camera Editor", checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) self._createGui() self._enabled = True def disable(self): """ plugin method """ if self._enabled is False: return self._container.setDocked(False) self._container.hide() self._editor._tools_menu.removeAction(self._action_show) self._enabled = False def isEnabled(self): """ plugin method """ return self._enabled def getName(self): """ plugin method """ return "Camera Editor" def toggle(self): """ Toggles the cameratool visible / invisible and sets dock status """ if self._container.isVisible() or self._container.isDocked(): self._container.setDocked(False) self._container.hide() self._action_show.setChecked(False) else: self._container.show() self.loadSettings() self._action_show.setChecked(True) self._adjustPosition() def saveSettings(self): engine = self._editor.getEngine() id = self._container.collectData('idBox') if id == '': print 'Please enter a camera id.' return try: map = engine.getModel().getMap( str(self._container.collectData('mapBox'))) except fife.Exception: print 'Cannot find the specified map id.' return try: layer = map.getLayer(str(self._container.collectData('layerBox'))) except fife.Exception: print 'Cannot find the specified layer id.' return try: vals = self._container.collectData('viewBox').split(',') if len(vals) != 4: raise ValueError viewport = fife.Rect(*[int(c) for c in vals]) except ValueError: print 'Please enter 4 comma (,) delimited values for viewport x,y,width,height.' return try: refh = int(self._container.collectData('refhBox')) refw = int(self._container.collectData('refwBox')) if refh <= 0 or refw <= 0: raise ValueError except ValueError: print 'Please enter positive integer values for reference width and height.' return try: rot = int(self._container.collectData('rotBox')) tilt = int(self._container.collectData('tiltBox')) except ValueError: print 'Please enter positive integer values for rotation and tilt.' return self._camera = self._editor.getActiveMapView().getCamera() self._camera.setId(str(id)) self._camera.getLocation().setLayer(layer) self._camera.setViewPort(viewport) self._camera.setCellImageDimensions(refw, refh) self._camera.setRotation(rot) self._camera.setTilt(tilt) ztoy = int(self._container.collectData('ztoyNBox')) if ztoy is not 0 and ztoy is not self._camera.getOriginalZToY(): self._camera.setZToY(ztoy) self.toggle() def loadSettings(self): if self._editor.getActiveMapView() is None: return else: self._camera = self._editor.getActiveMapView().getCamera() map = self._editor.getActiveMapView().getMap().getId() self._container.findChild(name="mapBox").text = unicode(str(map)) layer = self._camera.getLocation().getLayer().getId() self._container.findChild(name="layerBox").text = unicode(layer) vp = self._camera.getViewPort() viewport_str = unicode( str(vp.x) + "," + str(vp.y) + "," + str(vp.w) + "," + str(vp.h)) self._container.findChild(name="viewBox").text = viewport_str ref = self._camera.getCellImageDimensions() refw_str = unicode(str(ref.x)) refh_str = unicode(str(ref.y)) self._container.findChild(name="refhBox").text = refh_str self._container.findChild(name="refwBox").text = refw_str self._container.findChild(name="idBox").text = unicode( str(self._camera.getId())) self._container.findChild(name="rotBox").text = unicode( str(int(self._camera.getRotation()))) self._container.findChild(name="tiltBox").text = unicode( str(int(self._camera.getTilt()))) self._container.findChild(name="ztoyOBox").text = unicode( str(float(self._camera.getOriginalZToY()))) self._container.findChild(name="ztoyNBox").text = unicode( str(float(self._camera.getZToY()))) def _createGui(self): """ Create the basic gui container """ self._container = pychan.loadXML('gui/cameradialog.xml') self._ok_button = self._container.findChild(name="okButton") self._cancel_button = self._container.findChild(name="cancelButton") self._ok_button.capture(self.saveSettings) self._ok_button.capture( cbwa(self._editor.getStatusBar().showTooltip, unicode("Save changes to the camera")), 'mouseEntered') self._ok_button.capture(self._editor.getStatusBar().hideTooltip, 'mouseExited') self._cancel_button.capture(self.toggle) self._cancel_button.capture( cbwa(self._editor.getStatusBar().showTooltip, unicode("Discard any changes to the camera")), 'mouseEntered') self._cancel_button.capture(self._editor.getStatusBar().hideTooltip, 'mouseExited') def _adjustPosition(self): """ Adjusts the position of the container - we don't want to let the window appear at the center of the screen. (new default position: left, beneath the tools window) """ self._container.position = (50, 200)
class ObjectEdit(plugin.Plugin): """ The B{ObjectEdit} module is a plugin for FIFedit and allows to edit attributes of a selected object fife.Objects can be selected via the B{ObjectSelector}. fife.Instances are instances of fife.Objects - so clicking on a "map object" is actually not selecting an object. Not sure how to handle that - for now this Plugin only reacts on selections in the ObjectSelector There is an InstanceEdit plugin yet to be written which allows the manipulation of instance data. """ def __init__(self): super(ObjectEdit, self).__init__() self._editor = scripts.editor.getEditor() self.engine = self._editor.getEngine() self.xml_saver = XMLObjectSaver(self.engine) self.default_x, self.default_y = _POSITION self._enabled = False self._showAction = None self._help_dialog = None self.default_settings = _PLUGIN_SETTINGS self.eds = self._editor._settings self.update_settings() self.reset() def reset(self): """ reset major ivars """ self.current_angle = None self.current_action = None self._object = None self._instance = None def enable(self): """ plugin method """ if self._enabled: return self._enabled = True self._action_show = Action(unicode(self.getName(), "utf-8"), checkable=True) scripts.gui.action.activated.connect(self.toggle_gui, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) onObjectSelected.connect(self.update) onInstancesSelected.connect(self.update) preMapClosed.connect(self.hide) postMapShown.connect(self.update) self.create_gui() self.update_gui() if self.settings['docked']: self._editor.dockWidgetTo(self.container, self.settings['dockarea']) def disable(self): """ plugin method """ if not self._enabled: return self._enabled = False self.container.hide() self.reset() onObjectSelected.disconnect(self.update) onInstancesSelected.disconnect(self.update) preMapClosed.disconnect(self.hide) postMapShown.disconnect(self.update) self._editor._tools_menu.removeAction(self._action_show) def isEnabled(self): """ plugin method """ return self._enabled def getName(self): """ plugin method """ return "Object editor" def _show_help(self): """ shows the help dialog """ if self._help_dialog is not None: self._help_dialog.show() return self._help_dialog = pychan.loadXML("gui/help.xml") self._help_dialog.title = u"Help (Object Editor)" self._help_dialog.mapEvents({ "closeButton": self._help_dialog.hide, }) # gimme some more space _SIZE = (320, 400) scrollarea = self._help_dialog.findChildren( __class__=pychan.widgets.ScrollArea)[0] scrollarea.size = _SIZE scrollarea.min_size = _SIZE scrollarea.max_size = _SIZE f = open('lang/help_object_edit.txt', 'r') self._help_dialog.findChild(name="helpText").text = unicode(f.read()) f.close() self._help_dialog.show() def create_gui(self): """ - creates the gui skeleton by loading the xml file - finds some important childs and saves their widget in the object @todo: - move all dynamic widgets to dict """ self.container = pychan.loadXML('gui/objectedit.xml') self.container.position_technique = 'explicit' self.container.position = _POSITION self.container.mapEvents({ 'change_data': self.save, 'show_help': self._show_help, }) self.container.findChild(name="x_offset_up").capture( self.change_offset, "mousePressed") self.container.findChild(name="x_offset_dn").capture( self.change_offset, "mousePressed") self.x_offset = self.container.findChild(name="x_offset") self.x_offset.capture(self.change_offset, "mouseWheelMovedUp") self.x_offset.capture(self.change_offset, "mouseWheelMovedDown") self.container.findChild(name="y_offset_up").capture( self.change_offset, "mousePressed") self.container.findChild(name="y_offset_dn").capture( self.change_offset, "mousePressed") self.y_offset = self.container.findChild(name="y_offset") self.y_offset.capture(self.change_offset, "mouseWheelMovedUp") self.y_offset.capture(self.change_offset, "mouseWheelMovedDown") self.container.findChild(name="object_blocking_toggle").capture( self.object_blocking_toggle, "mousePressed") self.rotations_listbox = self.container.findChild( name="select_rotations") self.rotations_listbox.capture(self.select_rotation, "mouseWheelMovedUp") self.rotations_listbox.capture(self.select_rotation, "mouseWheelMovedDown") self.rotations_listbox.capture(self.select_rotation, "action") self.xoffset_textfield = self.container.findChild(name="x_offset") self.yoffset_textfield = self.container.findChild(name="y_offset") self.actions_wrapper = self.container.findChild(name="actions_wrapper") self.rotations_wrapper = self.container.findChild( name="rotations_wrapper") self.actions_listbox = self.container.findChild(name="select_actions") self.actions_listbox.capture(self.select_action, "mouseWheelMovedUp") self.actions_listbox.capture(self.select_action, "mouseWheelMovedDown") self.actions_listbox.capture(self.select_action, "action") def get_image(self, rotations=None): """ try to get the current image of the object @rtype image: fife.Image @return image: image of the current angle of the current object """ if self._object is None: return image = None if rotations is None: rotations = self.get_rotations() if rotations: if self.current_angle is not None and self.current_angle in rotations: angle = self.current_angle else: angle = rotations[0] visual = self._object.get2dGfxVisual() index = visual.getStaticImageIndexByAngle(angle) if index == -1: action = self._object.getDefaultAction() if action: animation = action.get2dGfxVisual().getAnimationByAngle( angle) image = animation.getFrameByTimestamp(0) else: image = self.engine.getImageManager().get(index) return image def get_rotations(self): """ get either the static rotations or those of the action (if the object has one) """ rotations = [] visual = self._object.get2dGfxVisual() rotations = visual.getStaticImageAngles() if not rotations and self._object.getDefaultAction(): rotations = self._object.getDefaultAction().get2dGfxVisual( ).getActionImageAngles() return rotations def update_gui(self): """ updates the gui widgets with current object data """ x_offset = _DEFAULT_ENTRY y_offset = _DEFAULT_ENTRY rotations = [] actions = [] namespace = _DEFAULT_ENTRY blocking = bool(_DEFAULT_ENTRY) static = _DEFAULT_ENTRY _id = _DEFAULT_ENTRY cost_id = _DEFAULT_ENTRY cost = _DEFAULT_ENTRY cellstack_pos = _DEFAULT_ENTRY if self._object is not None: actions = list(self._object.getActionIds()) rotations = self.get_rotations() image = self.get_image(rotations=rotations) if image is not None: x_offset = unicode(str(image.getXShift()), 'utf-8') y_offset = unicode(str(image.getYShift()), 'utf-8') namespace = unicode(self._object.getNamespace(), 'utf-8') blocking = self._object.isBlocking() static = unicode(str(int(self._object.isStatic())), 'utf-8') _id = unicode(self._object.getId(), 'utf-8') if hasattr(self._object, 'getCostId'): cost_id = unicode(self._object.getCostId(), 'utf-8') if hasattr(self._object, 'getCost'): cost = unicode(str(self._object.getCost()), 'utf-8') if hasattr(self._object, 'getCellStackPosition'): cellstack_pos = unicode( str(self._object.getCellStackPosition()), 'utf-8') self.container.distributeInitialData({ 'object_id': u"\t" + _id, 'x_offset': x_offset, 'y_offset': y_offset, 'object_namespace': u"\t" + namespace, 'object_static': static, 'cost_id': cost_id, 'cost_value': cost, 'object_cellstack_pos': cellstack_pos, }) wdgt = self.container.findChild(name="object_blocking_toggle") wdgt.marked = blocking self.rotations_listbox.items = rotations if rotations: if self.current_angle in rotations: index = rotations.index(self.current_angle) else: index = 0 self.rotations_listbox.selected = index self.rotations_wrapper.show() else: self.rotations_wrapper.hide() self.actions_listbox.items = actions if actions: if self.current_action in actions: index = actions.index(self.current_action) else: index = 0 self.actions_listbox.selected = index self.actions_wrapper.show() else: self.actions_wrapper.hide() if not self.container.isDocked(): self.container.adaptLayout(True) def toggle_gui(self): """ show / hide the gui """ if self.container.isVisible(): self.last_dockarea = self.container.dockarea self.container.hide() self._action_show.setChecked(False) else: if not self.container.isDocked(): self.container.show() self.container.x = self.default_x self.container.y = self.default_y else: self.container.setDocked(True) self.dockWidgetTo(self.container, self.last_dockarea) self._action_show.setChecked(True) def change_offset(self, event, widget): """ widget callback: change the offset of an object @type event: object @param event: FIFE mouseevent or keyevent @type widget: object @param widget: pychan widget """ if self._object is None: return etype = event.getType() image = self.get_image() if image is None: return x = image.getXShift() y = image.getYShift() if etype == fife.MouseEvent.WHEEL_MOVED_UP or widget.name.endswith( "up"): modifier = 1 elif etype == fife.MouseEvent.WHEEL_MOVED_DOWN or widget.name.endswith( "dn"): modifier = -1 if widget.name.startswith("x"): x += modifier elif widget.name.startswith("y"): y += modifier self.set_offset(x, y, image=image) self.update_gui() def object_blocking_toggle(self, event, widget): """ widget callback: change the blocking of an instance @type event: object @param event: FIFE mouseevent or keyevent @type widget: object @param widget: pychan widget """ if self._object is None: return blocking = widget.marked self._object.setBlocking(bool(blocking)) self.update_gui() def save(self): """ saves the current object to its xml file @note: - saves only object data and static image data - no animation data or atlas data is saved """ if self._object is None: return self.xml_saver.save(self._object) self._editor.getStatusBar().setText( u"Saving of object data successful: %s" % self._object.getId()) def select_action(self): """ let an instance act and set the action of the current object """ if self._object is None: return action = str(self.actions_listbox.selected_item) self.current_action = action # @todo: compat layer - trunk/ doesn't have this method exposed # to python yet (cell pathfinding branch has) # @todo: remove this check later if hasattr(self._object, 'setDefaultAction'): self._object.setDefaultAction(action) if self._instance is not None and action is not None: f_loc = self._instance.getFacingLocation() self._instance.actOnce(action, f_loc) def select_rotation(self): """ rotate an instance due to selected angle """ if self._object is None: return angle = self.eval_rotation() self.current_angle = angle if self._instance is not None and angle is not None: self._instance.setRotation(int(angle)) self.update_gui() def eval_rotation(self): """ prepare rotation from gui and apply it to the current selected instance """ selected = self.rotations_listbox.selected_item if selected is None: return selected angle = int(selected) if angle == 360: angle = 0 return angle def set_offset(self, x=None, y=None, image=None): """ set x/y offset of current selected instance """ if self._object is None: return if self._object.isStatic(): if image is None: image = self.get_image() if image is None: return if x is not None: image.setXShift(x) if y is not None: image.setYShift(y) else: self.set_animation_offset(x, y) def set_animation_offset(self, x, y): """ apply the offset to all frames of the default action """ if self.current_action is not None: action = self._object.getAction(self.current_action) else: action = self._object.getDefaultAction() if not action: return if self.current_angle is not None: angle = self.current_angle else: angle = 0 animation = action.get2dGfxVisual().getAnimationByAngle(angle) if not animation: return for index in range(animation.getFrameCount()): image = animation.getFrame(index) image.setXShift(x) image.setYShift(y) def show(self): """ show the plugin gui """ self.container.show() self.container.adaptLayout(False) def hide(self): """ hide the plugin gui - and reset it """ self.container.hide() self.reset() def update(self, object=None, instances=[]): """ called by the editor onObjectSelected or onInstancesSelected (we only use the top instance of the selected cell) @type instances: list @param instances: a list of instances in the selected cell """ self.reset() if object is None and not instances: self._object = None self._instance = None self.update_gui() return if instances: self._instance = instances[0] object = instances[0].getObject() action = object.getDefaultAction() if action: self.current_action = action.getId() self._object = object self.update_gui()
class ObjectEdit(plugin.Plugin): """ The B{ObjectEdit} module is a plugin for FIFedit and allows to edit 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 offsets, rotation, instance id - save offsets to object file - outline highlighting of the selected object - animation viewer """ def __init__(self): self.active = False self._camera = None self._layer = None self._anim_timer = None self._enabled = False self.imageManager = None self.guidata = {} self.objectdata = {} self._help_dialog = None def _reset(self): """ 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 self._object_blocking = 0 self._instance_blocking = 0 self._static = 0 self._object_id = None self._instance_id = None self._fixed_rotation = None if self._camera is not None: self.renderer.removeAllOutlines() def enable(self): """ plugin method """ if self._enabled is True: return self._editor = scripts.editor.getEditor() self.engine = self._editor.getEngine() self.imageManager = self.engine.getImageManager() self._showAction = Action(unicode(self.getName(),"utf-8"), checkable=True) scripts.gui.action.activated.connect(self.toggle_gui, sender=self._showAction) self._editor._tools_menu.addAction(self._showAction) events.onInstancesSelected.connect(self.input) events.preMapClosed.connect(self.hide) events.preMapShown.connect(self.hide) self._reset() self.create_gui() def disable(self): """ plugin method """ if self._enabled is False: return self._reset() self.container.hide() self.removeAllChildren() events.onInstancesSelected.disconnect(self.input) events.preMapClosed.disconnect(self.hide) events.preMapShown.disconnect(self.hide) self._editor._tools_menu.removeAction(self._showAction) def isEnabled(self): """ plugin method """ return self._enabled; def getName(self): """ plugin method """ return "Object editor" def _show_help(self): """ shows the help dialog """ if self._help_dialog is not None: self._help_dialog.show() return self._help_dialog = pychan.loadXML("gui/help.xml") self._help_dialog.title = u"Help (Object Editor)" self._help_dialog.mapEvents({ "closeButton" : self._help_dialog.hide, }) # gimme some more space _SIZE = (320,400) scrollarea = self._help_dialog.findChildren(__class__=pychan.widgets.ScrollArea)[0] scrollarea.size = _SIZE scrollarea.min_size = _SIZE scrollarea.max_size = _SIZE f = open('lang/help_object_edit.txt', 'r') self._help_dialog.findChild(name="helpText").text = unicode(f.read()) f.close() self._help_dialog.show() 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, '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, 'show_help' : self._show_help, }) self.container.findChild(name="x_offset_up").capture(self.change_offset, "mousePressed") self.container.findChild(name="x_offset_dn").capture(self.change_offset, "mousePressed") self._gui_x_offset = self.container.findChild(name="x_offset") self._gui_x_offset.capture(self.change_offset, "mouseWheelMovedUp") self._gui_x_offset.capture(self.change_offset, "mouseWheelMovedDown") self.container.findChild(name="y_offset_up").capture(self.change_offset, "mousePressed") self.container.findChild(name="y_offset_dn").capture(self.change_offset, "mousePressed") self._gui_y_offset = self.container.findChild(name="y_offset") self._gui_y_offset.capture(self.change_offset, "mouseWheelMovedUp") self._gui_y_offset.capture(self.change_offset, "mouseWheelMovedDown") self.container.findChild(name="object_blocking_toggle").capture(self.object_blocking_toggle, "mousePressed") self.container.findChild(name="instance_blocking_toggle").capture(self.instance_blocking_toggle, "mousePressed") 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_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_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 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) """ 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 else: self._anim_data['current'] = self._anim_data['frames'] 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_data['current'] < self._anim_data['frames']: self._anim_data['current'] += 1 else: self._anim_data['current'] = 0 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 update_gui(self): """ updates the gui widgets with current instance data """ if self._instances is None: return # 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.getName() 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 ) if self._instances[0].isOverrideBlocking(): self.container.findChild(name="override_blocking_toggle")._setMarked(True) else: self.container.findChild(name="override_blocking_toggle")._setMarked(False) 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 ), 'instance_blocking' : unicode( self._instance_blocking ), 'object_blocking' : unicode( self._object_blocking ), 'object_static' : unicode( self._static ), }) if not self._animation: if self._fixed_rotation in self._avail_rotations: index = self._avail_rotations.index( self._fixed_rotation ) self._gui_rotation_dropdown._setSelected(index) # else: # print "Internal FIFE rotation: ", self._instances[0].getRotation() # print "Fixed rotation (cam rot) ", self._fixed_rotation + int(abs(self._camera.getRotation())) # print "Collected rots from object ", self._avail_rotations self.container.adaptLayout(False) def toggle_gui(self): """ show / hide the gui """ if self.active is True: 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) def highlight_selected_instance(self): """ highlights selected instance """ self.renderer.removeAllOutlines() self.renderer.addOutlined(self._instances[0], WHITE["r"], WHITE["g"], WHITE["b"], OUTLINE_SIZE) def change_offset(self, event, widget): """ widget callback: change the offset of an object @type event: object @param event: FIFE mouseevent or keyevent @type widget: object @param widget: pychan widget """ if self._animation: self._editor.getStatusBar().setText(u"Offset changes of animations are not supported yet") return etype = event.getType() x = self._image.getXShift() y = self._image.getYShift() if etype == fife.MouseEvent.WHEEL_MOVED_UP or widget.name.endswith("up"): modifier = 1 elif etype == fife.MouseEvent.WHEEL_MOVED_DOWN or widget.name.endswith("dn"): modifier = -1 if widget.name.startswith("x"): x += modifier elif widget.name.startswith("y"): y += modifier self.set_offset(x, y) self.update_gui() def object_blocking_toggle(self, event, widget): """ widget callback: change the blocking of an instance @type event: object @param event: FIFE mouseevent or keyevent @type widget: object @param widget: pychan widget """ self.check_override_blocking() object = self._instances[0].getObject() object_id = object.getId() blocking = not object.isBlocking() object.setBlocking(blocking) instances = self._layer.getInstances() for instance in instances: object = instance.getObject() if object.getId() == object_id: instance.setBlocking(blocking) self._object_blocking = int(blocking) self._instance_blocking = int(self._instances[0].isBlocking()) self.update_gui() def instance_blocking_toggle(self, event, widget): """ widget callback: change the blocking of an instance @type event: object @param event: FIFE mouseevent or keyevent @type widget: object @param widget: pychan widget """ self.check_override_blocking() instance = self._instances[0] instance.setBlocking(not instance.isBlocking()) self._instance_blocking = int(instance.isBlocking()) self.update_gui() def check_override_blocking(self): instance = self._instances[0] marked = self.container.findChild(name="override_blocking_toggle")._isMarked() if marked: instance.setOverrideBlocking(True) else: instance.setOverrideBlocking(False) def use_user_data(self): """ - takes the users values and applies them directly to the current ._instance - 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... """ instance_id = str(self._gui_instance_id_textfield._getText()) msg = '' 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: self._instances[0].setId(instance_id) msg = unicode("Set new instance id: " + str(instance_id)) self._editor.getStatusBar().setText(msg) else: self._editor.getStatusBar().setText(u"Instance ID is already in use.") if self._animation: msg = msg + "\n" + u"Editing offset and rotation of animated instances is not supported yet" self._editor.getStatusBar().setText(msg) return xoffset = self._gui_xoffset_textfield._getText() yoffset = self._gui_yoffset_textfield._getText() # 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.getFilename() self.tree = ET.parse(file) 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"] == str(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 block = self.tree.getroot() block.attrib["blocking"] = str(int(self._object_blocking)) xmlcontent = ET.tostring(self.tree.getroot()) # save xml data beneath the <?fife type="object"?> definition into the object file tmp = open(file, 'w') tmp.write('<?fife type="object"?>\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] ) 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 = action.get2dGfxVisual().getAnimationByAngle(self._fixed_rotation) animation_id = animation.getFifeId() 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.getFrameCount() 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 """ visual = None self._avail_rotations = [] if instance is None: 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 == '': self._instance_id = 'None' if angle == -1: angle = int(instance.getRotation()) else: angle = int(angle) self._rotation = angle if object.isBlocking(): self._object_blocking = 1 if instance.isBlocking(): self._instance_blocking = 1 if object.isStatic(): self._static = 1 try: visual = object.get2dGfxVisual() except: self._editor.getStatusBar().setText(u"Fetching visual of object failed") raise self._fixed_rotation = instance.getRotation() index = visual.getStaticImageIndexByAngle(self._fixed_rotation) 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 = 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.imageManager.get(index) if not self._animation: 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: self._avail_rotations = object.getDefaultAction().get2dGfxVisual().getActionImageAngles() def show(self): """ show the plugin gui - and update it """ self.update_gui() self.container.show() self.container.adaptLayout(False) def hide(self): """ hide the plugin gui - and reset it """ self.container.hide() self._reset() def input(self, instances): """ if called _and_ the user wishes to edit offsets, gets instance data and show gui (we only use the top instance of the selected cell) @type instances: list @param instances: a list of instances in the selected cell """ if instances != self._instances: if self.active is True: self._reset() self._instances = instances if self._camera is None: self._camera = self._editor.getActiveMapView().getCamera() self.renderer = fife.InstanceRenderer.getInstance(self._camera) self._layer = self._editor.getActiveMapView().getController()._layer if self._instances: self.highlight_selected_instance() self.get_instance_data() self.show() else: self.hide()
class LightEdit(plugin.Plugin): """ The B{LightEdit} module is a plugin for FIFedit and allows to use Lighting current features: - click instance to add SimpleLight, LightImage, LightAnimation - outline highlighting of the selected object - changeing all SimpleLigh values and Image, Animation source """ def __init__(self): self.active = False self._camera = None self._layer = None self._enabled = False self._light = {} self._color = {} self._color.update(DEFAULT_GLOBAL_LIGHT) random.seed() def _reset(self): """ resets all dynamic vars, but leaves out static ones (e.g. camera, layer) """ self._instances = None self._light["stencil"] = -1 self._light["src"] = -1 self._light["dst"] = -1 self._light["intensity"] = 0 self._light["red"] = 0 self._light["green"] = 0 self._light["blue"] = 0 self._light["radius"] = 0 self._light["subdivisions"] = 32 self._light["xstretch"] = 1 self._light["ystretch"] = 1 self._light["image"] = None self._light["animation"] = None self._simple_l = False self._image_l = False self._animation_l = False self._global_l = False if self._camera is not None: self.renderer.removeAllOutlines() self._widgets["group"].text = unicode(str("")) self._widgets["image"].text = unicode(str("")) self._widgets["animation"].text = unicode(str("")) def enable(self): """ plugin method """ if self._enabled is True: return self._editor = scripts.editor.getEditor() self.engine = self._editor.getEngine() self.imagemanager = self.engine.getImageManager() self._showAction = Action(unicode(self.getName(),"utf-8"), checkable=True) scripts.gui.action.activated.connect(self.toggle_gui, sender=self._showAction) self._editor._tools_menu.addAction(self._showAction) events.onInstancesSelected.connect(self.input) self._reset() self.create_gui() def disable(self): """ plugin method """ if self._enabled is False: return self._reset() self.container.hide() self.removeAllChildren() events.onInstancesSelected.disconnect(self.input) self._editor._toolsMenu.removeAction(self._showAction) def isEnabled(self): """ plugin method """ return self._enabled; def getName(self): """ plugin method """ return "Light editor" def create_gui(self): """ - creates the gui skeleton by loading the xml file FIXME: - move all dynamic widgets to dict """ self.container = pychan.loadXML('gui/lightedit.xml') self.container.mapEvents({ "reset" : self.reset_light, "use" : self.use_light, "simple_but" : self.toggle_simple_gui, "image_but" : self.toggle_image_gui, "animation_but" : self.toggle_animation_gui, "global_but" : self.toggle_global_gui, "selec_image" : self.change_image, "selec_animation" : self.change_animation, "stencil_up" : cbwa(self.change_light, value=1, option="stencil"), "stencil_dn" : cbwa(self.change_light, value=-1, option="stencil"), "stencil/mouseWheelMovedUp" : cbwa(self.change_light, value=10, option="stencil"), "stencil/mouseWheelMovedDown" : cbwa(self.change_light, value=-10, option="stencil"), "intensity_up" : cbwa(self.change_light, value=1, option="intensity"), "intensity_dn" : cbwa(self.change_light, value=-1, option="intensity"), "intensity/mouseWheelMovedUp" : cbwa(self.change_light, value=10, option="intensity"), "intensity/mouseWheelMovedDown" : cbwa(self.change_light, value=-10, option="intensity"), "radius_up" : cbwa(self.change_light, value= 1, option="radius"), "radius_dn" : cbwa(self.change_light, value=-1, option="radius"), "radius/mouseWheelMovedUp" : cbwa(self.change_light, value= 10, option="radius"), "radius/mouseWheelMovedDown" : cbwa(self.change_light, value=-10, option="radius"), "subdivisions_up" : cbwa(self.change_light, value= 1, option="subdivisions"), "subdivisions_dn" : cbwa(self.change_light, value=-1, option="subdivisions"), "subdivisions/mouseWheelMovedUp" : cbwa(self.change_light, value= 1, option="subdivisions"), "subdivisions/mouseWheelMovedDown" : cbwa(self.change_light, value=-1, option="subdivisions"), "xstretch_up" : cbwa(self.change_light, value= 0.01, option="xstretch"), "xstretch_dn" : cbwa(self.change_light, value=-0.01, option="xstretch"), "xstretch/mouseWheelMovedUp" : cbwa(self.change_light, value= 0.1, option="xstretch"), "xstretch/mouseWheelMovedDown" : cbwa(self.change_light, value=-0.1, option="xstretch"), "ystretch_up" : cbwa(self.change_light, value= 0.01, option="ystretch"), "ystretch_dn" : cbwa(self.change_light, value=-0.01, option="ystretch"), "ystretch/mouseWheelMovedUp" : cbwa(self.change_light, value= 0.1, option="ystretch"), "ystretch/mouseWheelMovedDown" : cbwa(self.change_light, value=-0.1, option="ystretch"), "red_up" : cbwa(self.change_light, value= 1, option="red"), "red_dn" : cbwa(self.change_light, value=-1, option="red"), "red/mouseWheelMovedUp" : cbwa(self.change_light, value= 10, option="red"), "red/mouseWheelMovedDown" : cbwa(self.change_light, value=-10, option="red"), "green_up" : cbwa(self.change_light, value= 1, option="green"), "green_dn" : cbwa(self.change_light, value=-1, option="green"), "green/mouseWheelMovedUp" : cbwa(self.change_light, value= 10, option="green"), "green/mouseWheelMovedDown" : cbwa(self.change_light, value=-10, option="green"), "blue_up" : cbwa(self.change_light, value= 1, option="blue"), "blue_dn" : cbwa(self.change_light, value=-1, option="blue"), "blue/mouseWheelMovedUp" : cbwa(self.change_light, value= 10, option="blue"), "blue/mouseWheelMovedDown" : cbwa(self.change_light, value=-10, option="blue"), "src_up" : cbwa(self.change_light, value= 1, option="src"), "src_dn" : cbwa(self.change_light, value=-1, option="src"), "src/mouseWheelMovedUp" : cbwa(self.change_light, value= 1, option="src"), "src/mouseWheelMovedDown" : cbwa(self.change_light, value=-1, option="src"), "dst_up" : cbwa(self.change_light, value= 1, option="dst"), "dst_dn" : cbwa(self.change_light, value=-1, option="dst"), "dst/mouseWheelMovedUp" : cbwa(self.change_light, value= 1, option="dst"), "dst/mouseWheelMovedDown" : cbwa(self.change_light, value=-1, option="dst"), "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.1, r=True), "value_R/mouseWheelMovedDown" : cbwa(self.decrease_color, step=0.1, 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.1, g=True), "value_G/mouseWheelMovedDown" : cbwa(self.decrease_color, step=0.1, 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.1, b=True), "value_B/mouseWheelMovedDown" : cbwa(self.decrease_color, step=0.1, b=True) }) self._widgets = { "group" : self.container.findChild(name="group"), "ins_id" : self.container.findChild(name="ins_id"), "obj_id" : self.container.findChild(name="obj_id"), "stencil" : self.container.findChild(name="stencil"), "intensity" : self.container.findChild(name="intensity"), "red" : self.container.findChild(name="red"), "green" : self.container.findChild(name="green"), "blue" : self.container.findChild(name="blue"), "radius" : self.container.findChild(name="radius"), "subdivisions" : self.container.findChild(name="subdivisions"), "xstretch" : self.container.findChild(name="xstretch"), "ystretch" : self.container.findChild(name="ystretch"), "src" : self.container.findChild(name="src"), "dst" : self.container.findChild(name="dst"), "image" : self.container.findChild(name="image"), "animation" : self.container.findChild(name="animation"), "value_R" : self.container.findChild(name="value_R"), "value_G" : self.container.findChild(name="value_G"), "value_B" : self.container.findChild(name="value_B") } self._gui_simple_panel_wrapper = self.container.findChild(name="simple_panel_wrapper") self._gui_simple_panel = self._gui_simple_panel_wrapper.findChild(name="simple_panel") self._gui_image_panel_wrapper = self.container.findChild(name="image_panel_wrapper") self._gui_image_panel = self._gui_image_panel_wrapper.findChild(name="image_panel") self._gui_animation_panel_wrapper = self.container.findChild(name="animation_panel_wrapper") self._gui_animation_panel = self._gui_animation_panel_wrapper.findChild(name="animation_panel") self._gui_global_panel_wrapper = self.container.findChild(name="global_panel_wrapper") self._gui_global_panel = self._gui_global_panel_wrapper.findChild(name="global_panel") def update_gui(self): """ updates the gui """ self._widgets["ins_id"].text = unicode(str(self._instances[0].getId())) self._widgets["obj_id"].text = unicode(str(self._instances[0].getObject().getId())) self._widgets["stencil"].text = unicode(str(self._light["stencil"])) self._widgets["src"].text = unicode(str(self._light["src"])) self._widgets["dst"].text = unicode(str(self._light["dst"])) self._widgets["intensity"].text = unicode(str(self._light["intensity"])) self._widgets["red"].text = unicode(str(self._light["red"])) self._widgets["green"].text = unicode(str(self._light["green"])) self._widgets["blue"].text = unicode(str(self._light["blue"])) self._widgets["radius"].text = unicode(str(self._light["radius"])) self._widgets["subdivisions"].text = unicode(str(self._light["subdivisions"])) self._widgets["xstretch"].text = unicode(str(self._light["xstretch"])) self._widgets["ystretch"].text = unicode(str(self._light["ystretch"])) 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"])) if self._simple_l: if not self._gui_simple_panel_wrapper.findChild(name="simple_panel"): self._gui_simple_panel_wrapper.addChild(self._gui_simple_panel) else: if self._gui_simple_panel_wrapper.findChild(name="simple_panel"): self._gui_simple_panel_wrapper.removeChild(self._gui_simple_panel) if self._image_l: if not self._gui_image_panel_wrapper.findChild(name="image_panel"): self._gui_image_panel_wrapper.addChild(self._gui_image_panel) else: if self._gui_image_panel_wrapper.findChild(name="image_panel"): self._gui_image_panel_wrapper.removeChild(self._gui_image_panel) if self._animation_l: if not self._gui_animation_panel_wrapper.findChild(name="animation_panel"): self._gui_animation_panel_wrapper.addChild(self._gui_animation_panel) else: if self._gui_animation_panel_wrapper.findChild(name="animation_panel"): self._gui_animation_panel_wrapper.removeChild(self._gui_animation_panel) if self._global_l: if not self._gui_global_panel_wrapper.findChild(name="global_panel"): self._gui_global_panel_wrapper.addChild(self._gui_global_panel) else: if self._gui_global_panel_wrapper.findChild(name="global_panel"): self._gui_global_panel_wrapper.removeChild(self._gui_global_panel) self.container.adaptLayout(False) def toggle_gui(self): """ show / hide the gui """ if self.active is True: 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) def toggle_simple_gui(self): if self._simple_l: self._simple_l = False else: self._simple_l = True self._image_l = False self._animation_l = False self.update_gui() def toggle_image_gui(self): if self._image_l: self._image_l = False else: self._simple_l = False self._image_l = True self._animation_l = False self.update_gui() def toggle_animation_gui(self): if self._animation_l: self._animation_l = False else: self._simple_l = False self._image_l = False self._animation_l = True self.update_gui() def toggle_global_gui(self): if self._global_l: self._global_l = False else: self._global_l = True self.update_gui() def init_data(self): color = self._camera.getLightingColor() self._color["R"] = color[0] self._color["G"] = color[1] self._color["B"] = color[2] groups = self.lightrenderer.getGroups() for group in groups: infos = self.lightrenderer.getLightInfo(group) for info in infos: node = info.getNode() if node.getInstance() is None: continue if node.getInstance().getId() == self._instances[0].getId(): self._widgets["group"].text = unicode(str(group)) self._light["stencil"] = info.getStencil() self._light["src"] = info.getSrcBlend() self._light["dst"] = info.getDstBlend() if str(info.getName()) == "simple": self._light["red"] = info.getColor()[0] self._light["green"] = info.getColor()[1] self._light["blue"] = info.getColor()[2] self._light["intensity"] = info.getColor()[3] self._light["radius"] = info.getRadius() self._light["subdivisions"] = info.getSubdivisions() self._light["xstretch"] = info.getXStretch() self._light["ystretch"] = info.getYStretch() self.toggle_simple_gui() elif str(info.getName()) == "image": if info.getImage() is None: continue img = info.getImage() name = img.getName() self._widgets["image"].text = unicode(str(name)) self._light["image"] = image self.toggle_image_gui() elif str(info.getName()) == "animation": if info.getAnimation() is None: continue ani = info.getAnimation(); count = 0 newstr = '' image = self.engine.getImageManager().get(ani.getFrame(ani.getActionFrame())) fname = image.getName() strings = ([str(s) for s in fname.split('/')]) leng = len(strings) -1 while count < leng: newstr = str(newstr + strings[count] + '/') count += 1 self._widgets["animation"].text = unicode(str(newstr + 'animation.xml')) self._light["animation"] = ani self.toggle_animation_gui() def change_image(self): file = self._editor.getObject().getResourceFile() tree = ET.parse(file) img_lst = tree.findall("image") for image in img_lst: source = image.get('source') path = file.split('/') path.pop() path.append(str(source)) self._widgets["image"].text = unicode(str('/'.join(path))) break def change_animation(self): file = self._editor.getObject().getResourceFile() tree = ET.parse(file) ani_lst = tree.findall("animation") if not ani_lst: act_lst = tree.findall("action") if not act_lst: return for act in act_lst: ani_lst = act.findall("animation") if ani_lst: break for animation in ani_lst: source = animation.get('source') path = file.split('/') path.pop() path.append(str(source)) self._widgets["animation"].text = unicode(str('/'.join(path))) break def reset_light(self): self._light["stencil"] = -1 self._light["src"] = -1 self._light["dst"] = -1 self._light["intensity"] = 0 self._light["red"] = 0 self._light["green"] = 0 self._light["blue"] = 0 self._light["radius"] = 0 self._light["subdivisions"] = 32 self._light["xstretch"] = 1 self._light["ystretch"] = 1 self._light["image"] = None self._light["animation"] = None self.lightrenderer.removeAll(str(self._widgets["group"]._getText())) self._widgets["group"].text = unicode(str("")) self._widgets["image"].text = unicode(str("")) self._widgets["animation"].text = unicode(str("")) self.update_gui() def use_light(self): if not self._instances[0]: return counter = 1 if self._widgets["ins_id"]._getText() == "": objid = self._instances[0].getObject().getId() insid = str(objid + str(counter)) while bool(self._layer.getInstance(insid)): counter = int(counter+1) insid = str(objid + str(counter)) self._instances[0].setId(insid) if self._light["stencil"] is not -1 : self.stencil_test() if self._simple_l: self.simple_light() if self._image_l: self.image_light() if self._animation_l: self.animation_light() def highlight_selected_instance(self): """ highlights selected instance """ self.renderer.removeAllOutlines() self.renderer.addOutlined(self._instances[0], WHITE["r"], WHITE["g"], WHITE["b"], OUTLINE_SIZE) def change_light(self, value=0.01, option=None): self._light[option] = self._light[option] + value if self._light[option]+ value < -1 and (option == "src" or option == "dst" or option == "stencil"): self._light[option] = -1 if self._light[option]+ value < 0 and option != "src" and option != "dst" and option != "stencil": self._light[option] = 0 if self._light[option]+ value > 7 and (option == "src" or option == "dst"): self._light[option] = 7 if self._light[option]+ value > 255 and (option == "intensity" or option == "red" or option == "green" or option == "blue" or option == "stencil"): self._light[option] = 255 self.update_gui() def stencil_test(self): self.lightrenderer.addStencilTest(str(self._widgets["group"]._getText()), self._light["stencil"]) def simple_light(self): if not self._instances[0]: return self.lightrenderer.removeAll(str(self._widgets["group"]._getText())) node = fife.RendererNode(self._instances[0]) self.lightrenderer.addSimpleLight(str(self._widgets["group"]._getText()), node, self._light["intensity"], self._light["radius"], self._light["subdivisions"], self._light["xstretch"], self._light["ystretch"], self._light["red"], self._light["green"], self._light["blue"], self._light["src"], self._light["dst"],) def image_light(self): if not self._instances[0]: return self.lightrenderer.removeAll(str(self._widgets["group"]._getText())) image = str(self._widgets["image"]._getText()) if image == "": return img = self.engine.getImageManager().load(image) self._light["image"] = img node = fife.RendererNode(self._instances[0]) self.lightrenderer.addImage(str(self._widgets["group"]._getText()), node, self._light["image"], self._light["src"], self._light["dst"],) def animation_light(self): if not self._instances[0]: return self.lightrenderer.removeAll(str(self._widgets["group"]._getText())) animation = str(self._widgets["animation"]._getText()) if animation == "": return rloc = animation ani = loadXMLAnimation(self.engine, rloc) self._light["animation"] = ani node = fife.RendererNode(self._instances[0]) self.lightrenderer.addAnimation(str(self._widgets["group"]._getText()), node, self._light["animation"], self._light["src"], self._light["dst"],) def reset_global_light(self): """ reset global light to default values (1.0) """ 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 """ if r: if self._color["R"] + step > 1.0: self._color["R"] = 1.0 else: self._color["R"] += step if g: if self._color["G"] + step > 1.0: self._color["G"] = 1.0 else: self._color["G"] += step if b: if self._color["B"] + step > 1.0: self._color["B"] = 1.0 else: self._color["B"] += 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 """ if r: if self._color["R"] - step < 0.0: self._color["R"] = 0.0 else: self._color["R"] -= step if g: if self._color["G"] - step < 0.0: self._color["G"] = 0.0 else: self._color["G"] -= step if b: if self._color["B"] - step < 0.0: self._color["B"] = 0.0 else: self._color["B"] -= step self.update_gui() self.set_global_light() def random_color(self): """ generate random values for color channels """ self._color["R"] = random.uniform(0,1) self._color["G"] = random.uniform(0,1) self._color["B"] = random.uniform(0,1) self.update_gui() self.set_global_light() def set_global_light(self): """ update the global light with the current set colors """ self._camera.setLightingColor(self._color["R"], self._color["G"], self._color["B"]) def input(self, instances): if instances != self._instances: if self.active is True: self._reset() self._instances = instances if self._camera is None: self._camera = self._editor.getActiveMapView().getCamera() self.renderer = fife.InstanceRenderer.getInstance(self._camera) self.lightrenderer = fife.LightRenderer.getInstance(self._camera) self._layer = self._editor.getActiveMapView().getController()._layer if self._instances != (): self.init_data() self.highlight_selected_instance() self.update_gui() self.container.show() else: self._reset() self.container.hide() self.container.adaptLayout(False)
class MapFileHistory(plugin.Plugin): """ The B{MapFileHistory} uses the fife_settings module to store the last used mapfiles and provides the means to both display them and load them """ def __init__(self): super(MapFileHistory, self).__init__() # editor instance self._editor = scripts.editor.getEditor() # Plugin variables self._enabled = False self._action_show = None self.history = [] self.names = [] # gui vars self.container = None self.default_x, self.default_y = _POSITION self.default_settings = _PLUGIN_SETTINGS self.eds = self._editor._settings self.update_settings() def enable(self): """ enables the plugin and connects to the editor """ if self._enabled: return self._enabled = True # Fifedit plugin data self._action_show = Action(self.getName(), checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) self.load_map_history() self.create() onOpenMapFile.connect(self.update) if self.settings['docked']: self._editor.dockWidgetTo(self.container, self.settings['dockarea']) def disable(self): """ deactivates plugin """ if not self._enabled: return self._enabled = False onOpenMapFile.disconnect(self.update) self._editor._tools_menu.removeAction(self._action_show) def isEnabled(self): return self._enabled def getName(self): return u"Mapfile history" #--- These are not so important ---# def getAuthor(self): return "Zero-Projekt" def getDescription(self): return "" def getLicense(self): return "" def getVersion(self): return "0.1" def load_map(self, event=None, widget=None): """ load the the selected map """ index = widget.selected path = self.history[index] # make sure the mapfile exists, otherwise delete the entry if not self._editor.engine.getVFS().exists(path): self.delete_entry(path) self.update_gui() return self._editor.openFile(path) def load_map_history(self): """ loads the mapfile history from settings file """ for i in range(_HISTORY_LEN): entry = _ITEM_PREFIX+str(i) item = self.eds.get(_MODULE, entry) self.add_entry(item) def add_entry(self, path, save=False): """ adds an entry to the history @type path: str @param path: path to map file @type save: bool @param save: flag to either save entry to settings file or not """ if not path: return if path in self.history: return cur_len = len(self.history) parts = path.split(os.sep) name = parts[-1] if cur_len >= _HISTORY_LEN: self.history[0] = path self.names[0] = name elif cur_len < _HISTORY_LEN: self.history.append(path) self.names.append(name) if save: index = self.history.index(path) self.eds.set(_MODULE, _ITEM_PREFIX+str(index), path) def delete_entry(self, path): """ delete an (outdated) entry from the history @type path: str @param path: path to map file """ if path not in self.history: return index = self.history.index(path) del self.history[index] del self.names[index] self.eds.set(_MODULE, _ITEM_PREFIX+str(index), '') def create(self): """ creates the gui """ if self.container is not None: return self.container = Panel(title=self.getName()) self.container.position_technique = 'explicit' self.container.position = _POSITION self.container.min_size = _MIN_SIZE self.container.name = _MODULE self.lst_box = pychan.widgets.ListBox() self.lst_box.items = self.names self.lst_box.capture(self.load_map) self.container.addChild(self.lst_box) # overwrite Panel.afterUndock self.container.afterUndock = self.on_undock self.container.afterDock = self.on_dock def on_dock(self): """ callback for dock event of B{Panel} widget """ side = self.container.dockarea.side if not side: return module = self.default_settings['module'] self.eds.set(module, 'dockarea', side) self.eds.set(module, 'docked', True) def on_undock(self): """ callback for undock event of B{Panel} widget """ self.container.hide() self.toggle() module = self.default_settings['module'] self.eds.set(module, 'dockarea', '') self.eds.set(module, 'docked', False) def toggle(self): """ shows / hides the gui """ if self.container.isVisible(): self.last_dockarea = self.container.dockarea self.container.hide() self._action_show.setChecked(False) else: if not self.container.isDocked(): self.container.show() self.container.x = self.default_x self.container.y = self.default_y else: self.container.setDocked(True) self.dockWidgetTo(self.container, self.last_dockarea) self._action_show.setChecked(True) def update_gui(self): """ refresh the listbox and update the container layout """ self.lst_box.items = self.names self.container.adaptLayout() def update(self, path): """ updates the history with a new mapfile """ self.add_entry(path, save=True) self.update_gui()
class RegionTool(plugin.Plugin): """ The B{RegionTool} allows to select and show / hide regions of a loaded map as well as creating new regions or edit region properties """ # default should be pychan default, highlight can be choosen (format: r,g,b) DEFAULT_BACKGROUND_COLOR = pychan.internal.DEFAULT_STYLE['default'][ 'base_color'] HIGHLIGHT_BACKGROUND_COLOR = pychan.internal.DEFAULT_STYLE['default'][ 'selection_color'] # the dynamicly created widgets have the name scheme prefix + regionid LABEL_NAME_PREFIX = "select_" def __init__(self): super(RegionTool, self).__init__() # Editor instance self._editor = scripts.editor.getEditor() self.regions = {} self.selected_region = None # Plugin variables self._enabled = False # Current mapview self._mapview = None # Toolbar button to display RegionTool self._action_show = None # GUI self._region_wizard = None self.container = None self.wrapper = None self.remove_region_button = None self.create_region_button = None self.edit_region_button = None self.default_settings = _PLUGIN_SETTINGS self.eds = self._editor._settings self.update_settings() self.renderer = None self.region_layer = None #--- Plugin functions ---# def enable(self): """ Enable plugin """ if self._enabled: return # Fifedit plugin data self._action_show = Action(u"RegionTool", checkable=True) scripts.gui.action.activated.connect(self.toggle, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) self.create() self.toggle() postMapShown.connect(self.onNewMap) preMapClosed.connect(self._mapClosed) postSave.connect(self.save) if self.settings['docked']: self._editor.dockWidgetTo(self.container, self.settings['dockarea']) def disable(self): """ Disable plugin """ if not self._enabled: return self.container.setDocked(False) self.container.hide() postMapShown.disconnect(self.update) preMapClosed.disconnect(self._mapClosed) self._editor._tools_menu.removeAction(self._action_show) def isEnabled(self): """ Returns True if plugin is enabled """ return self._enabled def getName(self): """ Return plugin name """ return u"Regiontool" #--- End plugin functions ---# def _mapClosed(self): self.onNewMap(mapview=None) def showRegionWizard(self): """ Show region wizard """ if not self._mapview: return if self._region_wizard: self._region_wizard._widget.hide() self._region_wizard = RegionDialog(self._editor.getEngine(), self.regions, callback=self._regionCreated) def showEditDialog(self): """ Show regiondialog for active region """ if not self._mapview: return if not self.selected_region: return if self._region_wizard: self._region_wizard._widget.hide() callback = lambda region: self._regionEdited(self.selected_region, region) self._region_wizard = RegionDialog(self._editor.getEngine(), self.regions, region=self.selected_region, callback=callback) def clear_region_list(self): """ Remove all subwrappers """ self.wrapper.removeAllChildren() def onNewMap(self, mapview): """ Update regiontool with information from mapview @type event: scripts.MapView @param event: the view of the new map """ self._mapview = mapview self.regions = {} layer_list = [] if not mapview is None: self.renderer = fife.GenericRenderer.getInstance( self._mapview.getCamera()) self.renderer.setEnabled(True) layers = self._mapview.getMap().getLayers() for layer in reversed(layers): layer_list.append(layer.getId()) try: filename = mapview.getMap().getFilename() filename = "%s_regions.yaml" % os.path.splitext(filename)[0] regions_file = open(filename, "r") for name, region_data in yaml.load(regions_file).iteritems(): x_pos = region_data[0] y_pos = region_data[1] width = region_data[2] height = region_data[3] rect = fife.DoubleRect(x_pos, y_pos, width, height) region = Region(name, rect) self.regions[name] = region except (RuntimeError, IOError): pass self.select_layer_drop_down.setInitialData(layer_list) size = [self.container.size[0], 15] self.select_layer_drop_down.min_size = size self.select_layer_drop_down.size = size self.select_layer_drop_down.selected = 0 self.update_region_layer() self.update() def update_region_layer(self): """Updates the layer the regions are drawn on""" if self._mapview is None: return layer_id = self.select_layer_drop_down.selected_item self.region_layer = self._mapview.getMap().getLayer(layer_id) self.renderer.addActiveLayer(self.region_layer) self.update() def update(self): """ Update regiontool We group one ToggleButton and one Label into a HBox, the main wrapper itself is a VBox and we also capture both the Button and the Label to listen for mouse actions """ self.clear_region_list() if len(self.regions) <= 0: if not self._mapview: regionid = "No map is open" else: regionid = "No regions" subwrapper = pychan.widgets.HBox() regionLabel = pychan.widgets.Label() regionLabel.text = unicode(regionid) regionLabel.name = RegionTool.LABEL_NAME_PREFIX + regionid subwrapper.addChild(regionLabel) self.wrapper.addChild(subwrapper) if self._mapview: self.renderer.removeAll("region") for name, region in self.regions.iteritems(): rect = region.rect region_dict = [] point1 = fife.ExactModelCoordinate(rect.x, rect.y) loc1 = fife.Location(self.region_layer) loc1.setExactLayerCoordinates(point1) node1 = fife.RendererNode(loc1) region_dict.append(node1) point2 = fife.ExactModelCoordinate(rect.x, rect.y + rect.h) loc2 = fife.Location(self.region_layer) loc2.setExactLayerCoordinates(point2) node2 = fife.RendererNode(loc2) region_dict.append(node2) point3 = fife.ExactModelCoordinate(rect.x + rect.w, rect.y + rect.h) loc3 = fife.Location(self.region_layer) loc3.setExactLayerCoordinates(point3) node3 = fife.RendererNode(loc3) region_dict.append(node3) point4 = fife.ExactModelCoordinate(rect.x + rect.w, rect.y) loc4 = fife.Location(self.region_layer) loc4.setExactLayerCoordinates(point4) node4 = fife.RendererNode(loc4) region_dict.append(node4) color = [255, 0, 0, 127] if name == self.selected_region: color[3] = 255 self.renderer.addQuad("region", region_dict[0], region_dict[1], region_dict[2], region_dict[3], *color) font = get_manager().getDefaultFont() self.renderer.addText("region", region_dict[0], font, name) for region in self.regions.itervalues(): regionid = region.name subwrapper = pychan.widgets.HBox() regionLabel = pychan.widgets.Label() regionLabel.text = unicode(regionid) regionLabel.name = RegionTool.LABEL_NAME_PREFIX + regionid regionLabel.capture(self.selectRegion, "mousePressed") subwrapper.addChild(regionLabel) self.wrapper.addChild(subwrapper) self.container.adaptLayout() def selectRegion(self, event, widget=None, regionid=None): """ Callback for Labels We hand the regionid over to the mapeditor module to select a new active region Additionally, we mark the active region widget (changing base color) and reseting the previous one @type event: object @param event: pychan mouse event @type widget: object @param widget: the pychan widget where the event occurs, transports the region id in it's name @type regionid: string @param regionid: the region id """ if not widget and not regionid: print "No region ID or widget passed to RegionTool.selectRegion" return if widget is not None: regionid = widget.name[len(RegionTool.LABEL_NAME_PREFIX):] self.selected_region = regionid self.update() def resetSelection(self): """ Deselects selected region """ self.selected_region = None self.update() def removeSelectedRegion(self): """ Deletes the selected region """ if self.regions.has_key(self.selected_region): del self.regions[self.selected_region] self.resetSelection() def toggle(self): """ Toggles the regiontool visible / invisible and sets dock status """ if self.container.isVisible() or self.container.isDocked(): self.container.setDocked(False) self.container.hide() self._action_show.setChecked(False) else: self.container.show() self._action_show.setChecked(True) self._adjustPosition() def create(self): """ Create the basic gui container """ self.container = pychan.loadXML('gui/regiontool.xml') self.wrapper = self.container.findChild(name="regions_wrapper") self.remove_region_button = self.container.findChild( name="remove_region_button") self.create_region_button = self.container.findChild( name="add_region_button") self.edit_region_button = self.container.findChild( name="edit_region_button") self.remove_region_button.capture(self.removeSelectedRegion) self.remove_region_button.capture( cbwa(self._editor.getStatusBar().showTooltip, self.remove_region_button.helptext), 'mouseEntered') self.remove_region_button.capture( self._editor.getStatusBar().hideTooltip, 'mouseExited') self.create_region_button.capture(self.showRegionWizard) self.create_region_button.capture( cbwa(self._editor.getStatusBar().showTooltip, self.create_region_button.helptext), 'mouseEntered') self.create_region_button.capture( self._editor.getStatusBar().hideTooltip, 'mouseExited') self.edit_region_button.capture(self.showEditDialog) self.edit_region_button.capture( cbwa(self._editor.getStatusBar().showTooltip, self.edit_region_button.helptext), 'mouseEntered') self.edit_region_button.capture( self._editor.getStatusBar().hideTooltip, 'mouseExited') self.select_layer_drop_down = self.container.findChild( name="layer_select_drop_down") self.select_layer_drop_down.capture(self.update_region_layer) self.onNewMap(None) # overwrite Panel.afterUndock self.container.afterUndock = self.on_undock self.container.afterDock = self.on_dock def on_dock(self): """ callback for dock event of B{Panel} widget """ side = self.container.dockarea.side if not side: return module = self.default_settings['module'] self.eds.set(module, 'dockarea', side) self.eds.set(module, 'docked', True) def on_undock(self): """ callback for undock event of B{Panel} widget """ self.container.hide() self.toggle() module = self.default_settings['module'] self.eds.set(module, 'dockarea', '') self.eds.set(module, 'docked', False) def _adjustPosition(self): """ Adjusts the position of the container - we don't want to let the window appear at the center of the screen. (new default position: left, beneath the tools window) """ self.container.position = (50, 200) def _regionEdited(self, old_region, region): del self.regions[old_region] self._regionCreated(region) def _regionCreated(self, region): self.regions[region.name] = region self.update() def save(self, mapview): """Save the regions to a file""" filename = mapview.getMap().getFilename() filename = "%s_regions.yaml" % os.path.splitext(filename)[0] regions_file = open(filename, "w") yaml.dump(self.regions, regions_file)
class ObjectEdit(plugin.Plugin): """ The B{ObjectEdit} module is a plugin for FIFedit and allows to edit 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 offsets, rotation, instance id - save offsets to object file - outline highlighting of the selected object - 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.guidata = {} self.objectdata = {} def _reset(self): """ 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 self._blocking = 0 self._static = 0 self._object_id = None self._instance_id = None self._fixed_rotation = None if self._camera is not None: self.renderer.removeAllOutlines() def enable(self): """ plugin method """ if self._enabled is True: return self._editor = scripts.editor.getEditor() self.engine = self._editor.getEngine() self.imagepool = self.engine.getImagePool() self._animationpool = self.engine.getAnimationPool() self._showAction = Action(unicode(self.getName(),"utf-8"), checkable=True) scripts.gui.action.activated.connect(self.toggle_gui, sender=self._showAction) self._editor._tools_menu.addAction(self._showAction) events.onInstancesSelected.connect(self.input) self._reset() self.create_gui() def disable(self): """ plugin method """ if self._enabled is False: return self._reset() self.container.hide() self.removeAllChildren() events.onInstancesSelected.disconnect(self.input) self._editor._tools_menu.removeAction(self._showAction) def isEnabled(self): """ plugin method """ return self._enabled; def getName(self): """ 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({ '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_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_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 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) """ 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 """ # 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 ), }) if not self._animation: if self._fixed_rotation in self._avail_rotations: index = self._avail_rotations.index( self._fixed_rotation ) self._gui_rotation_dropdown._setSelected(index) else: print "Internal FIFE rotation: ", self._instances[0].getRotation() print "Fixed rotation (cam rot) ", self._fixed_rotation + int(abs(self._camera.getRotation())) print "Collected rots from object ", self._avail_rotations self.container.adaptLayout(False) def toggle_gui(self): """ show / hide the gui """ if self.active is True: 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) def highlight_selected_instance(self): """ 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): """ - 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): """ - takes the users values and applies them directly to the current ._instance - 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: self._instances[0].setId(instance_id) print "Set new instance id: ", instance_id else: print "Instance ID is already in use." # 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) 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 <?fife type="object"?> definition into the object file tmp = open(file, 'w') tmp.write('<?fife type="object"?>\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] ) 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) 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 FIXME: 1.) we need to fix the instance rotation / rotation issue """ visual = None self._avail_rotations = [] if instance is None: 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 == '': self._instance_id = 'None' if angle == -1: angle = int(instance.getRotation()) else: angle = int(angle) self._rotation = angle if object.isBlocking(): self._blocking = 1 if object.isStatic(): self._static = 1 try: visual = object.get2dGfxVisual() except: print 'Fetching visual of object - failed. :/' raise # 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.getRotation() ) ) self._fixed_rotation = instance.getRotation() # self._fixed_rotation = visual.getClosestMatchingAngle(self._fixed_rotation) index = visual.getStaticImageIndexByAngle(self._fixed_rotation) 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 = 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: rotations = visual.getStaticImageAngles() for angle in rotations: # angle += int(abs( self._camera.getRotation() )) 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] # 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 user wishes to edit offsets, gets instance data and show gui """ if instances != self._instances: if self.active is True: self._reset() self._instances = instances if self._camera is None: self._camera = self._editor.getActiveMapView().getCamera() self.renderer = fife.InstanceRenderer.getInstance(self._camera) self._layer = self._editor.getActiveMapView().getController()._layer if self._instances != (): self.highlight_selected_instance() self.get_instance_data() self.update_gui() self.container.show() else: self._reset() self.container.hide() self.container.adaptLayout(False)
class ObjectEdit(plugin.Plugin): """ The B{ObjectEdit} module is a plugin for FIFedit and allows to edit attributes of a selected object fife.Objects can be selected via the B{ObjectSelector}. fife.Instances are instances of fife.Objects - so clicking on a "map object" is actually not selecting an object. Not sure how to handle that - for now this Plugin only reacts on selections in the ObjectSelector There is an InstanceEdit plugin yet to be written which allows the manipulation of instance data. """ def __init__(self): super(ObjectEdit, self).__init__() self._editor = scripts.editor.getEditor() self.engine = self._editor.getEngine() self.xml_saver = XMLObjectSaver(self.engine) self.default_x, self.default_y = _POSITION self._enabled = False self._showAction = None self._help_dialog = None self.default_settings = _PLUGIN_SETTINGS self.eds = self._editor._settings self.update_settings() self.reset() def reset(self): """ reset major ivars """ self.current_angle = None self.current_action = None self._object = None self._instance = None def enable(self): """ plugin method """ if self._enabled: return self._enabled = True self._action_show = Action(unicode(self.getName(),"utf-8"), checkable=True) scripts.gui.action.activated.connect(self.toggle_gui, sender=self._action_show) self._editor._tools_menu.addAction(self._action_show) onObjectSelected.connect(self.update) onInstancesSelected.connect(self.update) preMapClosed.connect(self.hide) postMapShown.connect(self.update) self.create_gui() self.update_gui() if self.settings['docked']: self._editor.dockWidgetTo(self.container, self.settings['dockarea']) def disable(self): """ plugin method """ if not self._enabled: return self._enabled = False self.container.hide() self.reset() onObjectSelected.disconnect(self.update) onInstancesSelected.disconnect(self.update) preMapClosed.disconnect(self.hide) postMapShown.disconnect(self.update) self._editor._tools_menu.removeAction(self._action_show) def isEnabled(self): """ plugin method """ return self._enabled; def getName(self): """ plugin method """ return "Object editor" def _show_help(self): """ shows the help dialog """ if self._help_dialog is not None: self._help_dialog.show() return self._help_dialog = pychan.loadXML("gui/help.xml") self._help_dialog.title = u"Help (Object Editor)" self._help_dialog.mapEvents({ "closeButton" : self._help_dialog.hide, }) # gimme some more space _SIZE = (320,400) scrollarea = self._help_dialog.findChildren(__class__=pychan.widgets.ScrollArea)[0] scrollarea.size = _SIZE scrollarea.min_size = _SIZE scrollarea.max_size = _SIZE f = open('lang/help_object_edit.txt', 'r') self._help_dialog.findChild(name="helpText").text = unicode(f.read()) f.close() self._help_dialog.show() def create_gui(self): """ - creates the gui skeleton by loading the xml file - finds some important childs and saves their widget in the object @todo: - move all dynamic widgets to dict """ self.container = pychan.loadXML('gui/objectedit.xml') self.container.position_technique = 'explicit' self.container.position = _POSITION self.container.mapEvents({ 'change_data' : self.save, 'show_help' : self._show_help, }) self.container.findChild(name="x_offset_up").capture(self.change_offset, "mousePressed") self.container.findChild(name="x_offset_dn").capture(self.change_offset, "mousePressed") self.x_offset = self.container.findChild(name="x_offset") self.x_offset.capture(self.change_offset, "mouseWheelMovedUp") self.x_offset.capture(self.change_offset, "mouseWheelMovedDown") self.container.findChild(name="y_offset_up").capture(self.change_offset, "mousePressed") self.container.findChild(name="y_offset_dn").capture(self.change_offset, "mousePressed") self.y_offset = self.container.findChild(name="y_offset") self.y_offset.capture(self.change_offset, "mouseWheelMovedUp") self.y_offset.capture(self.change_offset, "mouseWheelMovedDown") self.container.findChild(name="object_blocking_toggle").capture(self.object_blocking_toggle, "mousePressed") self.rotations_listbox = self.container.findChild(name="select_rotations") self.rotations_listbox.capture(self.select_rotation,"mouseWheelMovedUp") self.rotations_listbox.capture(self.select_rotation,"mouseWheelMovedDown") self.rotations_listbox.capture(self.select_rotation,"action") self.xoffset_textfield = self.container.findChild(name="x_offset") self.yoffset_textfield = self.container.findChild(name="y_offset") self.actions_wrapper = self.container.findChild(name="actions_wrapper") self.rotations_wrapper = self.container.findChild(name="rotations_wrapper") self.actions_listbox = self.container.findChild(name="select_actions") self.actions_listbox.capture(self.select_action,"mouseWheelMovedUp") self.actions_listbox.capture(self.select_action,"mouseWheelMovedDown") self.actions_listbox.capture(self.select_action,"action") def get_image(self, rotations=None): """ try to get the current image of the object @rtype image: fife.Image @return image: image of the current angle of the current object """ if self._object is None: return image = None if rotations is None: rotations = self.get_rotations() if rotations: if self.current_angle is not None and self.current_angle in rotations: angle = self.current_angle else: angle = rotations[0] visual = self._object.get2dGfxVisual() index = visual.getStaticImageIndexByAngle(angle) if index == -1: action = self._object.getDefaultAction() if action: animation = action.get2dGfxVisual().getAnimationByAngle(angle) image = animation.getFrameByTimestamp(0) else: image = self.engine.getImageManager().get(index) return image def get_rotations(self): """ get either the static rotations or those of the action (if the object has one) """ rotations = [] visual = self._object.get2dGfxVisual() rotations = visual.getStaticImageAngles() if not rotations and self._object.getDefaultAction(): rotations = self._object.getDefaultAction().get2dGfxVisual().getActionImageAngles() return rotations def update_gui(self): """ updates the gui widgets with current object data """ x_offset = _DEFAULT_ENTRY y_offset = _DEFAULT_ENTRY rotations = [] actions = [] namespace = _DEFAULT_ENTRY blocking = bool(_DEFAULT_ENTRY) static = _DEFAULT_ENTRY _id = _DEFAULT_ENTRY cost_id = _DEFAULT_ENTRY cost = _DEFAULT_ENTRY cellstack_pos = _DEFAULT_ENTRY if self._object is not None: actions = list(self._object.getActionIds()) rotations = self.get_rotations() image = self.get_image(rotations=rotations) if image is not None: x_offset = unicode(str(image.getXShift()), 'utf-8') y_offset = unicode(str(image.getYShift()), 'utf-8') namespace = unicode(self._object.getNamespace(), 'utf-8') blocking = self._object.isBlocking() static = unicode(str(int(self._object.isStatic())), 'utf-8') _id = unicode(self._object.getId(), 'utf-8') if hasattr(self._object, 'getCostId'): cost_id = unicode(self._object.getCostId(), 'utf-8') if hasattr(self._object, 'getCost'): cost = unicode(str(self._object.getCost()), 'utf-8') if hasattr(self._object, 'getCellStackPosition'): cellstack_pos = unicode(str(self._object.getCellStackPosition()), 'utf-8') self.container.distributeInitialData({ 'object_id' : u"\t" + _id, 'x_offset' : x_offset, 'y_offset' : y_offset, 'object_namespace' : u"\t" + namespace, 'object_static' : static, 'cost_id' : cost_id, 'cost_value' : cost, 'object_cellstack_pos' : cellstack_pos, }) wdgt = self.container.findChild(name="object_blocking_toggle") wdgt.marked = blocking self.rotations_listbox.items = rotations if rotations: if self.current_angle in rotations: index = rotations.index(self.current_angle) else: index = 0 self.rotations_listbox.selected = index self.rotations_wrapper.show() else: self.rotations_wrapper.hide() self.actions_listbox.items = actions if actions: if self.current_action in actions: index = actions.index(self.current_action) else: index = 0 self.actions_listbox.selected = index self.actions_wrapper.show() else: self.actions_wrapper.hide() if not self.container.isDocked(): self.container.adaptLayout(True) def toggle_gui(self): """ show / hide the gui """ if self.container.isVisible(): self.last_dockarea = self.container.dockarea self.container.hide() self._action_show.setChecked(False) else: if not self.container.isDocked(): self.container.show() self.container.x = self.default_x self.container.y = self.default_y else: self.container.setDocked(True) self.dockWidgetTo(self.container, self.last_dockarea) self._action_show.setChecked(True) def change_offset(self, event, widget): """ widget callback: change the offset of an object @type event: object @param event: FIFE mouseevent or keyevent @type widget: object @param widget: pychan widget """ if self._object is None: return etype = event.getType() image = self.get_image() if image is None: return x = image.getXShift() y = image.getYShift() if etype == fife.MouseEvent.WHEEL_MOVED_UP or widget.name.endswith("up"): modifier = 1 elif etype == fife.MouseEvent.WHEEL_MOVED_DOWN or widget.name.endswith("dn"): modifier = -1 if widget.name.startswith("x"): x += modifier elif widget.name.startswith("y"): y += modifier self.set_offset(x, y, image=image) self.update_gui() def object_blocking_toggle(self, event, widget): """ widget callback: change the blocking of an instance @type event: object @param event: FIFE mouseevent or keyevent @type widget: object @param widget: pychan widget """ if self._object is None: return blocking = widget.marked self._object.setBlocking(bool(blocking)) self.update_gui() def save(self): """ saves the current object to its xml file @note: - saves only object data and static image data - no animation data or atlas data is saved """ if self._object is None: return self.xml_saver.save(self._object) self._editor.getStatusBar().setText(u"Saving of object data successful: %s" % self._object.getId()) def select_action(self): """ let an instance act and set the action of the current object """ if self._object is None: return action = str(self.actions_listbox.selected_item) self.current_action = action # @todo: compat layer - trunk/ doesn't have this method exposed # to python yet (cell pathfinding branch has) # @todo: remove this check later if hasattr(self._object, 'setDefaultAction'): self._object.setDefaultAction(action) if self._instance is not None and action is not None: f_loc = self._instance.getFacingLocation() self._instance.actOnce(action, f_loc) def select_rotation(self): """ rotate an instance due to selected angle """ if self._object is None: return angle = self.eval_rotation() self.current_angle = angle if self._instance is not None and angle is not None: self._instance.setRotation(int(angle)) self.update_gui() def eval_rotation(self): """ prepare rotation from gui and apply it to the current selected instance """ selected = self.rotations_listbox.selected_item if selected is None: return selected angle = int(selected) if angle == 360: angle = 0 return angle def set_offset(self, x=None, y=None, image=None): """ set x/y offset of current selected instance """ if self._object is None: return if self._object.isStatic(): if image is None: image = self.get_image() if image is None: return if x is not None: image.setXShift(x) if y is not None: image.setYShift(y) else: self.set_animation_offset(x, y) def set_animation_offset(self, x, y): """ apply the offset to all frames of the default action """ if self.current_action is not None: action = self._object.getAction(self.current_action) else: action = self._object.getDefaultAction() if not action: return if self.current_angle is not None: angle = self.current_angle else: angle = 0 animation = action.get2dGfxVisual().getAnimationByAngle(angle) if not animation: return for index in range(animation.getFrameCount()): image = animation.getFrame(index) image.setXShift(x) image.setYShift(y) def show(self): """ show the plugin gui """ self.container.show() self.container.adaptLayout(False) def hide(self): """ hide the plugin gui - and reset it """ self.container.hide() self.reset() def update(self, object=None, instances=[]): """ called by the editor onObjectSelected or onInstancesSelected (we only use the top instance of the selected cell) @type instances: list @param instances: a list of instances in the selected cell """ self.reset() if object is None and not instances: self._object = None self._instance = None self.update_gui() return if instances: self._instance = instances[0] object = instances[0].getObject() action = object.getDefaultAction() if action: self.current_action = action.getId() self._object = object self.update_gui()
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._tools_menu.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._tools_menu.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"] )