changeset 418:70ba57cd9d18

Documented, commented, cleaned and updated mapeditor.py to match new python coding guidelines.
author cheesesucker@33b003aa-7bff-0310-803a-e67f0ece8222
date Sat, 06 Feb 2010 18:50:36 +0000
parents 14e8087cde2c
children 6dace911ac2d
files tools/editor/scripts/gui/mapeditor.py
diffstat 1 files changed, 183 insertions(+), 129 deletions(-) [+]
line wrap: on
line diff
--- a/tools/editor/scripts/gui/mapeditor.py	Wed Feb 03 20:04:39 2010 +0000
+++ b/tools/editor/scripts/gui/mapeditor.py	Sat Feb 06 18:50:36 2010 +0000
@@ -21,14 +21,27 @@
 #  51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 # ####################################################################
 
-# MapEditor is a plugin for Fifedit. It allows for selection and visual editing of maps.
+"""
+Visual Map Editor
+=================
+
+The map editor provides the user with an interface for editing
+maps visually.
 
-import math, os, time
+To edit a map through code, use MapController.
+
+"""
+
+import math
+import os
+import time
 from datetime import date
 
 from fife import fife
 from fife.extensions import pychan
 import fife.extensions.pychan.widgets as widgets
+from fife.extensions import fife_utils
+
 import scripts
 import scripts.events as events
 import action
@@ -36,48 +49,75 @@
 from menubar import Menu, MenuBar
 from action import Action, ActionGroup
 from scripts.mapcontroller import MapController
-from fife.extensions import fife_utils
-
-states = (u'SELECTING', u'INSERTING', u'REMOVING', u'MOVING', u'OBJECTPICKER')
-for s in states:
-	globals()[s] = s
-NOT_INITIALIZED = -9999999
 
 class MapEditor:
-	def __init__(self):	
+	""" This class provides a basic user interface for map editing. It allows the user
+		to visually edit a map.
+	"""
+	
+	# Editor states
+	SELECTING		= u"Selecting"
+	INSERTING		= u"Inserting"
+	REMOVING		= u"Removing"
+	MOVING			= u"Moving"
+	OBJECTPICKER	= u"Objectpicking"
+	
+	def __init__(self):
+		""" Set up all variables and call some initial functions """
 		self._ignoreToggles = False # A hack to avoid infinite recursion when toggling a button
 		self._controller = None
-		self._mode = SELECTING
+		self._mode = MapEditor.SELECTING
+		self._debug = False # TODO: We should have a central system for activating debug messages
 		
+		# GUI
 		self._editor = scripts.editor.getEditor()
 		self._eventlistener = self._editor.getEventListener()
 		self._statusbar = self._editor.getStatusBar()
 		self._toolbar = self._editor.getToolBar()
-		self._object = None
-		self._startDragPos = None
-		self._lastDragPos = None
-		self._lastDragPosExact = None
-		
 		self._toolbox = self._editor.getToolbox()
 		
-		self._initToolbuttons()
+		# Currently selected object type
+		self._object = None
+		
+		# Variables used for moving instances
+		self._last_drag_pos = None
+		self._last_drag_pos_exact = None
+		
+		self._selected_instances = []
 		
+		self._undogroup = False
+		
+		# Variables for scrolling the map
+		self._dragx = 0
+		self._dragy = 0
+		self._scrollX = 0
+		self._scrollY = 0
+		
+		self._initToolboxButtons()
 		self._toolbox.show()
-		self._instances = []
 		
 		events.postMapShown.connect(self._mapChanged)
 		events.preMapClosed.connect(self._mapClosed)
 		events.onObjectSelected.connect(self.setObject)
-		self._undogroup = False
+		
+	def setObject(self, object):
+		""" Set the object type to be paint onto map """
+		self._object = object
 		
-		self._scrollX = 0
-		self._scrollY = 0
+	def setController(self, controller):
+		""" Set the controller to use. """
+		if self._controller is not None:
+			self._clear()
+			
+		self._controller = controller
+
+		if self._controller is not None:
+			self._init()
 		
 	def _init(self):
-		self._dragx = NOT_INITIALIZED
-		self._dragy = NOT_INITIALIZED
-		
-		self._setMode(SELECTING)
+		""" Sets up the mapeditor to work with the selected controller """
+		self._debug = self._controller.debug
+		self._setMode(MapEditor.SELECTING)
 		
 		self._initToolbarbuttons()
 		
@@ -95,6 +135,7 @@
 		events.onPump.connect(self.pump)
 		
 	def _clear(self):
+		""" Remove any functionality set up by _init """
 		self._clearToolbarButtons()
 		
 		events.keyPressed.disconnect(self.keyPressed)
@@ -111,37 +152,47 @@
 		events.onPump.disconnect(self.pump)
 		
 	def _mapChanged(self, sender, mapview):
+		""" Called when a new map is selected. 
+			Sets the mapeditor to control the mapcontroller in the new map 
+		"""
 		self.setController(mapview.getController())
 		
 	def _mapClosed(self, sender, mapview):
-		self.setController(None)
+		""" Called when a map is closed. """
+		if mapview.getMap().getId() == self._controller.getMap().getId():
+			self.setController(None)
 		
-	def _setCursor(self):
+	def _updateCursor(self):
+		""" Updates the cursor to reflect the mode of the editor """
 		engine = self._editor.getEngine()
 		cursor = engine.getCursor()
 		
 		id = -1
-		if self._mode == SELECTING:
+		if self._mode == MapEditor.SELECTING:
 			id = engine.getImagePool().addResourceFromFile("gui/icons/select_instance.png")
 			image = engine.getImagePool().getImage(id)
 			image.setXShift(-7)
 			image.setYShift(-7)
-		elif self._mode == INSERTING:
+			
+		elif self._mode == MapEditor.INSERTING:
 			id = engine.getImagePool().addResourceFromFile("gui/icons/add_instance.png")
 			image = engine.getImagePool().getImage(id)
 			image.setXShift(-2)
 			image.setYShift(-20)
-		elif self._mode == REMOVING:
+			
+		elif self._mode == MapEditor.REMOVING:
 			id = engine.getImagePool().addResourceFromFile("gui/icons/erase_instance.png")
 			image = engine.getImagePool().getImage(id)
 			image.setXShift(-2)
 			image.setYShift(-19)
-		elif self._mode == MOVING:
+			
+		elif self._mode == MapEditor.MOVING:
 			id = engine.getImagePool().addResourceFromFile("gui/icons/move_instance.png")
 			image = engine.getImagePool().getImage(id)
 			image.setXShift(-11)
 			image.setYShift(-11)
-		elif self._mode == OBJECTPICKER:
+			
+		elif self._mode == MapEditor.OBJECTPICKER:
 			id = engine.getImagePool().addResourceFromFile("gui/icons/objectpicker.png")
 			image = engine.getImagePool().getImage(id)
 			image.setXShift(-0)
@@ -153,22 +204,13 @@
 			cursor.set(fife.CURSOR_IMAGE, id)
 			
 	def _resetCursor(self):
+		""" Reset the cursor to the standard native one """
 		cursor = self._editor.getEngine().getCursor()
 		cursor.set(fife.CURSOR_NATIVE, fife.NC_ARROW)
 		
-	def setObject(self, object):
-		self._object = object
+	def _initToolboxButtons(self):
+		""" Sets up and connects buttons related to the toolbox """
 		
-	def setController(self, controller):
-		if self._controller is not None:
-			self._clear()
-
-		if controller is not None:
-			self._init()
-			
-		self._controller = controller
-		
-	def _initToolbuttons(self):
 		self._selectAction = Action(text=u"Select", icon="gui/icons/select_instance.png", checkable=True)
 		self._drawAction = Action(text=u"Draw", icon="gui/icons/add_instance.png", checkable=True)
 		self._removeAction = Action(text=u"Remove", icon="gui/icons/erase_instance.png", checkable=True)
@@ -194,13 +236,14 @@
 		self._toolgroup.addAction(self._removeAction)
 		self._toolgroup.addAction(self._objectpickerAction)
 		
-		
 		self._toolbox.addAction(self._toolgroup)
 		self._toolbox.adaptLayout()
 		
 		self._editor._edit_menu.addAction(self._toolgroup)
 		
 	def _initToolbarbuttons(self):
+		""" Sets up and connects buttons related to the toolbar """
+	
 		rotateLeftAction = Action(text=u"Rotate counterclockwise", icon="gui/icons/rotate_countercw.png")
 		rotateRightAction = Action(text=u"Rotate clockwise", icon="gui/icons/rotate_clockwise.png")
 		zoomInAction = Action(text=u"Zoom in", icon="gui/icons/zoom_in.png")
@@ -215,12 +258,12 @@
 		zoomResetAction.helptext = u"Reset zoom to default level"
 		screenshotAction.helptext = u"Take screenshot   (F7)"
 		
-		action.activated.connect(self.rotateCounterClockwise, sender=rotateLeftAction)
-		action.activated.connect(self.rotateClockwise, sender=rotateRightAction)
-		action.activated.connect(self.zoomIn, sender=zoomInAction)
-		action.activated.connect(self.zoomOut, sender=zoomOutAction)
-		action.activated.connect(self.resetZoom, sender=zoomResetAction)
-		action.activated.connect(self.captureScreen, sender=screenshotAction)
+		action.activated.connect(self._rotateCounterClockwise, sender=rotateLeftAction)
+		action.activated.connect(self._rotateClockwise, sender=rotateRightAction)
+		action.activated.connect(self._zoomIn, sender=zoomInAction)
+		action.activated.connect(self._zoomOut, sender=zoomOutAction)
+		action.activated.connect(self._resetZoom, sender=zoomResetAction)
+		action.activated.connect(self._captureScreen, sender=screenshotAction)
 	
 		self._viewGroup = ActionGroup(name=u"View group")
 		self._viewGroup.addAction(rotateLeftAction)
@@ -234,52 +277,84 @@
 		self._toolbar.adaptLayout()
 		
 	def _clearToolbarButtons(self):
+		""" Remove toolbar buttons """
 		self._toolbar.removeAction(self._viewGroup)
 		self._toolbar.adaptLayout()
 		self._viewGroup = None
 		
-		
 	def _setMode(self, mode):
-		if (mode == INSERTING) and (not self._object):
+		""" Set the editor mode """
+		if (mode == MapEditor.INSERTING) and (not self._object):
 			self._statusbar.setText(u'Please select object first')
 			mode = self._mode
 
 		self._ignoreToggles = True
 		# Update toolbox buttons
-		if (mode == INSERTING):
+		if (mode == MapEditor.INSERTING):
 			self._drawAction.setChecked(True)
-		elif mode == REMOVING:
+		elif mode == MapEditor.REMOVING:
 			self._removeAction.setChecked(True)
-		elif mode == MOVING:
+		elif mode == MapEditor.MOVING:
 			self._moveAction.setChecked(True)
-		elif mode == OBJECTPICKER:
+		elif mode == MapEditor.OBJECTPICKER:
 			self._objectpickerAction.setChecked(True)
 		else:
 			self._selectAction.setChecked(True)
 		self._ignoreToggles = False
 
 		self._mode = mode
-		print "Entered mode " + mode
-		self._statusbar.setText(mode.replace('_', ' ').capitalize())
-		self._setCursor()
+		if self._debug: print "Entered mode " + mode
+		self._statusbar.setText(mode)
+		self._updateCursor()
+		
+	def _zoomIn(self, zoom=1.10):
+		self._controller.setZoom(self._controller.getZoom()*zoom)
+		
+	def _zoomOut(self, zoom=1.10):
+		self._controller.setZoom(self._controller.getZoom()/zoom)
+		
+	def _resetZoom(self):
+		""" Resets zoom level to 1:1 """
+		self._controller.setZoom(1)
+		
+	def _rotateCounterClockwise(self):
+		""" Rotates map counterclockwise """
+		self._controller.rotateCounterClockwise()
+		
+	def _rotateClockwise(self):
+		""" Rotates map clockwise """
+		self._controller.rotateClockwise()
+		
+	def _captureScreen(self):
+		""" Saves a screenshot to the users data directory """
+		userDir = fife_utils.getUserDataDirectory("fife", "editor")
+		t = userDir+"/screenshots"
+		if not os.path.isdir(t):
+			os.makedirs(t)
+		t += "/screen-%s-%s.png" % (date.today().strftime('%Y-%m-%d'),
+									time.strftime('%H-%M-%S'))
+		
+		self._editor.getEngine().getRenderBackend().captureScreen(t)
+		print "Saved screenshot to:", t		
 		
 	def _buttonToggled(self, sender, toggled):
+		""" Called when a button controlling the editor mode was activated """
 		if self._controller is None: return
 		if self._ignoreToggles is True: return
 	
-		mode = SELECTING
+		mode = MapEditor.SELECTING
 		
 		if toggled:
 			if sender == self._selectAction:
-				mode = SELECTING
+				mode = MapEditor.SELECTING
 			elif sender == self._moveAction:
-				mode = MOVING
+				mode = MapEditor.MOVING
 			elif sender == self._drawAction:
-				mode = INSERTING
+				mode = MapEditor.INSERTING
 			elif sender == self._removeAction:
-				mode = REMOVING
+				mode = MapEditor.REMOVING
 			elif sender == self._objectpickerAction:
-				mode = OBJECTPICKER
+				mode = MapEditor.OBJECTPICKER
 
 		self._setMode(mode)
 		
@@ -288,7 +363,7 @@
 			return
 			
 		if not self._controller._layer:
-			if self._controller.debug: print 'No layers active. Cancelling map action'
+			if self._debug: print 'No layers active. Cancelling map action'
 			return
 
 		realCoords = self._getRealCoords(sender, event)
@@ -301,7 +376,7 @@
 			if event.getButton() == fife.MouseEvent.RIGHT:
 				self._controller.deselectSelection()
 				
-			if self._mode == SELECTING:
+			if self._mode == MapEditor.SELECTING:
 				if event.getButton() == fife.MouseEvent.LEFT:
 					if self._eventlistener.shiftPressed:
 						self._controller.deselectCell(realCoords[0], realCoords[1])
@@ -313,7 +388,7 @@
 				elif event.getButton() == fife.MouseEvent.RIGHT:
 					self._controller.deselectSelection()
 					
-			elif self._mode == INSERTING:
+			elif self._mode == MapEditor.INSERTING:
 				if event.getButton() == fife.MouseEvent.LEFT:
 					self._controller.deselectSelection()
 					self._controller.selectCell(realCoords[0], realCoords[1])
@@ -326,7 +401,7 @@
 					self._controller.selectCell(realCoords[0], realCoords[1])
 					self._controller.placeInstance(position, self._object)
 				
-			elif self._mode == REMOVING:
+			elif self._mode == MapEditor.REMOVING:
 				if event.getButton() == fife.MouseEvent.LEFT:
 					self._controller.deselectSelection()
 					self._controller.selectCell(realCoords[0], realCoords[1])
@@ -335,27 +410,27 @@
 					
 					self._controller.removeInstances(self._controller.getInstancesFromSelection())
 				
-			elif self._mode == MOVING:
+			elif self._mode == MapEditor.MOVING:
 				if event.getButton() == fife.MouseEvent.LEFT:
 				
 					position = self._controller._camera.toMapCoordinates(fife.ScreenPoint(realCoords[0], realCoords[1]), False)
 
-					self._lastDragPos = self._controller._layer.getCellGrid().toLayerCoordinates(position)
-					self._lastDragPosExact = self._controller._layer.getCellGrid().toExactLayerCoordinates(position)
+					self._last_drag_pos = self._controller._layer.getCellGrid().toLayerCoordinates(position)
+					self._last_drag_pos_exact = self._controller._layer.getCellGrid().toExactLayerCoordinates(position)
 	
 					for loc in self._controller._selection:
-						if loc.getLayerCoordinates() == self._lastDragPos:
+						if loc.getLayerCoordinates() == self._last_drag_pos:
 							break
 					else:
 						self._controller.deselectSelection()
 						self._controller.selectCell(realCoords[0], realCoords[1])
 						
-					self._instances = self._controller.getInstancesFromSelection()
+					self._selected_instances = self._controller.getInstancesFromSelection()
 					
 					self._controller.getUndoManager().startGroup("Moved instances")
 					self._undogroup = True
 					
-			elif self._mode == OBJECTPICKER:
+			elif self._mode == MapEditor.OBJECTPICKER:
 				position = self._controller._camera.toMapCoordinates(fife.ScreenPoint(realCoords[0], realCoords[1]), False)
 				exact = self._controller._layer.getCellGrid().toExactLayerCoordinates(position)
 				instances = self._controller.getInstancesFromPosition(exact)
@@ -369,7 +444,7 @@
 			return
 			
 		if not self._controller._layer:
-			if self._controller.debug: print 'No layers active. Cancelling map action'
+			if self._debug: print 'No layers active. Cancelling map action'
 			return
 			
 		realCoords = self._getRealCoords(sender, event)
@@ -377,49 +452,51 @@
 		if event.getButton() == fife.MouseEvent.MIDDLE:
 			self._scrollX = (self._dragx-realCoords[0])/10.0
 			self._scrollY = (self._dragy-realCoords[1])/10.0
+			
 		else:
-			if self._mode != SELECTING:
+			if self._mode != MapEditor.SELECTING:
 				self._controller.deselectSelection()
 				
-			if self._mode == SELECTING:
+			if self._mode == MapEditor.SELECTING:
 				if event.getButton() == fife.MouseEvent.LEFT:
 					if self._eventlistener.shiftPressed:
 						self._controller.deselectCell(realCoords[0], realCoords[1])
 					else:
 						self._controller.selectCell(realCoords[0], realCoords[1])
 					
-			elif self._mode == INSERTING:
+			elif self._mode == MapEditor.INSERTING:
 				position = self._controller._camera.toMapCoordinates(fife.ScreenPoint(realCoords[0], realCoords[1]), False)
 				position = self._controller._layer.getCellGrid().toLayerCoordinates(position)
 				
 				self._controller.selectCell(realCoords[0], realCoords[1])
 				self._controller.placeInstance(position, self._object)
 				
-			elif self._mode == REMOVING:
+			elif self._mode == MapEditor.REMOVING:
 				self._controller.selectCell(realCoords[0], realCoords[1])
 				self._controller.removeInstances(self._controller.getInstancesFromSelection())
 				
-			elif self._mode == MOVING:
+			elif self._mode == MapEditor.MOVING:
 				position = self._controller._camera.toMapCoordinates(fife.ScreenPoint(realCoords[0], realCoords[1]), False)
 				
 				positionExact = self._controller._layer.getCellGrid().toExactLayerCoordinates(position)
 				position = self._controller._layer.getCellGrid().toLayerCoordinates(position)
 				
 				if self._eventlistener.shiftPressed:
-					self._controller.moveInstances(self._instances, positionExact-self._lastDragPosExact, True)
+					self._controller.moveInstances(self._selected_instances, positionExact-self._last_drag_pos_exact, True)
 				else:
-					self._controller.moveInstances(self._instances, position-self._lastDragPos, False)
-				self._lastDragPos = position
-				self._lastDragPosExact = positionExact
+					self._controller.moveInstances(self._selected_instances, position-self._last_drag_pos, False)
+				self._last_drag_pos = position
+				self._last_drag_pos_exact = positionExact
 				
 				# Update selection
 				self._controller.deselectSelection()
 				
-				for i in self._instances:
+				for i in self._selected_instances:
 					pos = i.getLocation().getMapCoordinates()
 					pos = self._controller._camera.toScreenCoordinates(pos)
 					self._controller.selectCell(pos.x, pos.y)
-			elif self._mode == OBJECTPICKER:
+					
+			elif self._mode == MapEditor.OBJECTPICKER:
 				pass
 
 	def mouseReleased(self, sender, event):
@@ -427,10 +504,10 @@
 			return
 			
 		if not self._controller._layer:
-			if self._controller.debug: print 'No layers active. Cancelling map action'
+			if self._debug: print 'No layers active. Cancelling map action'
 			return
 			
-		if self._mode == SELECTING or self._mode == MOVING:
+		if self._mode == MapEditor.SELECTING or self._mode == MapEditor.MOVING:
 			instances = self._controller.getInstancesFromSelection()
 			if len(instances) > 0:
 				events.onInstancesSelected.send(sender=self, instances=instances)
@@ -445,27 +522,27 @@
 			self._controller.getUndoManager().endGroup()
 			self._undogroup = False
 
-		self._dragx = NOT_INITIALIZED
-		self._dragy = NOT_INITIALIZED
-
 	def mouseMoved(self, sender, event):
 		pass
 		
 	def mouseEntered(self, sender, event):
-		self._setCursor()
+		# Mouse has entered map area. Set cursor to reflect current mode
+		self._updateCursor()
 		
 	def mouseExited(self, sender, event):
+		# Mouse has exited the map area. Set the cursor to native arrow
 		self._resetCursor()
 				
 	def mouseWheelMovedUp(self, event):
+		# Zoom in
 		if self._eventlistener.controlPressed and self._controller._camera:
 			self._controller._camera.setZoom(self._controller._camera.getZoom() * 1.10)
 
 	def mouseWheelMovedDown(self, event):
+		# Zoom out
 		if self._eventlistener.controlPressed and self._controller._camera:
 			self._controller._camera.setZoom(self._controller._camera.getZoom() / 1.10)
 
-
 	def keyPressed(self, event):
 		keyval = event.getKey().getValue()
 		keystr = event.getKey().getAsString().lower()
@@ -489,25 +566,25 @@
 			self.captureScreen()
 			
 		elif keystr == "s":
-			self._setMode(SELECTING)
+			self._setMode(MapEditor.SELECTING)
 			
 		elif keystr == "i":
-			if self._mode != INSERTING:
+			if self._mode != MapEditor.INSERTING:
 				self._setMode(INSERTING)
 			else:
-				self._setMode(SELECTING)
+				self._setMode(MapEditor.SELECTING)
 			
 		elif keystr == "r":
-			if self._mode != REMOVING:
-				self._setMode(REMOVING)
+			if self._mode != MapEditor.REMOVING:
+				self._setMode(MapEditor.REMOVING)
 			else:
-				self._setMode(SELECTING)
+				self._setMode(MapEditor.SELECTING)
 
 		elif keystr == 'm':
-			if self._mode != MOVING:
-				self._setMode(MOVING)
+			if self._mode != MapEditor.MOVING:
+				self._setMode(MapEditor.MOVING)
 			else:
-				self._setMode(SELECTING)
+				self._setMode(MapEditor.SELECTING)
 
 		elif keystr == 't':
 			gridrenderer = self._controller._camera.getRenderer('GridRenderer')
@@ -534,22 +611,8 @@
 	def keyReleased(self, event):		
 		pass
 		
-	def zoomIn(self, zoom=1.10):
-		self._controller.setZoom(self._controller.getZoom()*zoom)
-		
-	def zoomOut(self, zoom=1.10):
-		self._controller.setZoom(self._controller.getZoom()/zoom)
-		
-	def resetZoom(self):
-		self._controller.setZoom(1)
-		
-	def rotateCounterClockwise(self):
-		self._controller.rotateCounterClockwise()
-		
-	def rotateClockwise(self):
-		self._controller.rotateClockwise()
-			
 	def _getRealCoords(self, sender, event):
+		""" Converts relative widget coordinate to absolute coordinates """
 		cw = sender
 		offsetX = event.getX()
 		offsetY = event.getY()
@@ -565,16 +628,7 @@
 			
 		return (offsetX, offsetY)
 		
-	def captureScreen(self):
-		userDir = fife_utils.getUserDataDirectory("fife", "editor")
-		t = userDir+"/screenshots"
-		if not os.path.isdir(t):
-			os.makedirs(t)
-		t += "/screen-%s-%s.png" % (date.today().strftime('%Y-%m-%d'),
-									time.strftime('%H-%M-%S'))
-		
-		self._editor.getEngine().getRenderBackend().captureScreen(t)
-		print "Saved screenshot to:", t
-		
 	def pump(self):
+		""" Called each frame """
+		# Scroll camera
 		self._controller.moveCamera(self._scrollX, self._scrollY)
\ No newline at end of file