Beispiel #1
0
	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)
Beispiel #4
0
	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'])
Beispiel #5
0
	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'])
Beispiel #6
0
    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'])
Beispiel #7
0
    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()
Beispiel #9
0
	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
Beispiel #10
0
    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()
Beispiel #11
0
	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()
Beispiel #12
0
	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'])
Beispiel #13
0
	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'])		
Beispiel #14
0
	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'])
Beispiel #15
0
	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()
Beispiel #16
0
	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()
Beispiel #17
0
	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()
Beispiel #18
0
	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 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()
Beispiel #20
0
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()
Beispiel #21
0
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()
Beispiel #23
0
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()
Beispiel #24
0
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()
Beispiel #25
0
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)
Beispiel #26
0
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()
Beispiel #27
0
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()
Beispiel #28
0
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()
Beispiel #29
0
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()
Beispiel #30
0
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()
Beispiel #31
0
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)
Beispiel #32
0
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()))
Beispiel #33
0
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()
Beispiel #36
0
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()
Beispiel #37
0
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)						
Beispiel #38
0
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()		
Beispiel #39
0
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)
Beispiel #40
0
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)						
Beispiel #41
0
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()
Beispiel #42
0
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"]
		)