summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/editorui.py281
-rw-r--r--src/mapdata.py3
-rw-r--r--src/ui.py178
3 files changed, 424 insertions, 38 deletions
diff --git a/src/editorui.py b/src/editorui.py
index c7da106..3b9b74e 100644
--- a/src/editorui.py
+++ b/src/editorui.py
@@ -1,6 +1,7 @@
from common import *
from math import floor, ceil
import weakref
+import math
class KPEditorItem(QtGui.QGraphicsItem):
@@ -236,33 +237,36 @@ class KPEditorObject(KPEditorItem):
self._layerRef().updateCache()
-class KPEditorDoodad(KPEditorItem):
+class KPEditorDoodad(QtGui.QGraphicsPixmapItem):
def __init__(self, doodad, layer):
- KPEditorItem.__init__(self)
- obj.qtItem = self
+ QtGui.QGraphicsPixmapItem.__init__(self)
+ self.setFlags(
+ self.ItemSendsGeometryChanges |
+ self.ItemIsSelectable |
+ self.ItemIsMovable
+ )
+
+ doodad.qtItem = self
self._doodadRef = weakref.ref(doodad)
self._layerRef = weakref.ref(layer)
- self._updatePosition()
- self._updateSize()
+
+ self.resizing = None
+ self.rotating = None
self.setAcceptHoverEvents(True)
+ self.setTransformationMode(1)
- def _updatePosition(self):
- self.setPos(*self._doodadRef().position)
-
- def _updateSize(self):
- self.prepareGeometryChange()
-
- w,h = self._doodadRef().size
+
+ def paint(self, painter, option, widget):
- self._boundingRect = QtCore.QRectF(0, 0, w, h)
- self._selectionRect = QtCore.QRectF(0, 0, w, h)
-
+ try:
+ QtGui.QGraphicsPixmapItem.paint(self, painter, option, widget)
+ except:
+ pass
- def paint(self, painter, option, widget):
if self.isSelected():
painter.setPen(QtGui.QPen(Qt.white, 1, Qt.DotLine))
- painter.drawRect(self._selectionRect)
+ painter.drawRect(self.boundingRect().adjusted(-1,-1,1,1))
def _itemMoved(self, oldX, oldY, newX, newY):
@@ -270,6 +274,207 @@ class KPEditorDoodad(KPEditorItem):
doodad.position = (newX, newY)
+ def itemChange(self, change, value):
+
+ return QtGui.QGraphicsItem.itemChange(self, change, value)
+
+
+ def resizerPortionAt(self, x, y):
+
+ rightBound = self.boundingRect().right() - 5
+ bottomBound = self.boundingRect().bottom() - 5
+
+ if y < 5:
+ if x < 5: return 1 # TOP_LEFT
+ elif x >= rightBound: return 2 # TOP_RIGHT
+ else: return 5 # TOP
+
+ elif y >= bottomBound:
+ if x < 5: return 3 # BOTTOM_LEFT
+ elif x >= rightBound: return 4 # BOTTOM_RIGHT
+ else: return 6 # BOTTOM
+
+ else:
+ if x < 5: return 7 # LEFT
+ elif x >= rightBound: return 8 # RIGHT
+ else: return None
+
+
+ def hoverMoveEvent(self, event):
+ if self._layerRef() != KP.mapScene.currentLayer:
+ self.setCursor(Qt.ArrowCursor)
+ return
+
+ pos = event.pos()
+ bit = self.resizerPortionAt(pos.x(), pos.y())
+
+
+ if (event.modifiers() == Qt.AltModifier):
+
+ if bit:
+ self.setCursor(Qt.OpenHandCursor)
+ else:
+ self.setCursor(Qt.ArrowCursor)
+
+ else:
+
+ if bit == 1 or bit == 4:
+ self.setCursor(Qt.SizeFDiagCursor)
+ elif bit == 2 or bit == 3:
+ self.setCursor(Qt.SizeBDiagCursor)
+ elif bit == 7 or bit == 8:
+ self.setCursor(Qt.SizeHorCursor)
+ elif bit == 5 or bit == 6:
+ self.setCursor(Qt.SizeVerCursor)
+ else:
+ self.setCursor(Qt.ArrowCursor)
+
+
+ def mousePressEvent(self, event):
+ if event.button() == Qt.LeftButton:
+ pos = event.pos()
+ bit = self.resizerPortionAt(pos.x(), pos.y())
+
+ if self._layerRef() == KP.mapScene.currentLayer and bit:
+ event.accept()
+
+ if (event.modifiers() == Qt.AltModifier):
+ self.rotating = self.mapToScene(pos), self._doodadRef().angle
+ self.setCursor(Qt.ClosedHandCursor)
+ return
+
+ else:
+ self.resizing = bit
+ return
+
+
+ KPEditorItem.mousePressEvent(self, event)
+
+
+ def _tryAndResize(self, bit, mousePosition, modifiers):
+
+ itemPos = self.mapFromScene(mousePosition)
+
+ x2 = self.boundingRect().right() + 5.0
+ y2 = self.boundingRect().bottom() + 5.0
+
+
+ if bit == 1:
+ relativeScale = min([(x2 - itemPos.x()) / x2, (y2 - itemPos.y()) / y2])
+ elif bit == 2:
+ relativeScale = min([itemPos.x() / x2, (y2 - itemPos.y()) / y2])
+ elif bit == 3:
+ relativeScale = min([(x2 - itemPos.x()) / x2, itemPos.y() / y2])
+ elif bit == 4:
+ relativeScale = min([itemPos.x() / x2, itemPos.y() / y2])
+ elif bit == 5:
+ relativeScale = (y2 - itemPos.y()) / y2
+ elif bit == 6:
+ relativeScale = itemPos.y() / y2
+ elif bit == 7:
+ relativeScale = (x2 - itemPos.x()) / x2
+ elif bit == 8:
+ relativeScale = itemPos.x() / x2
+ else:
+ return False, 0
+
+
+ if relativeScale > 1.0:
+ relativeScale = 1.0
+
+ if relativeScale < 0.1:
+ relativeScale = 0.1
+
+ self.setTransformOriginPoint(self.boundingRect().center())
+
+ return True, relativeScale
+
+
+ def _tryAndRotate(self, obj, mouseX, mouseY, originalPos, oldAngle, modifiers):
+ center = self.mapToScene(self.boundingRect().center())
+
+ objX = center.x()
+ objY = center.y()
+
+
+ origX = originalPos.x()
+ origY = originalPos.y()
+
+ dy = origY - objY
+ dx = origX - objX
+ rads = math.atan2(dy, dx)
+
+ origAngle = math.degrees(rads)
+
+
+
+
+ dy = mouseY - objY
+ dx = mouseX - objX
+ rads = math.atan2(dy, dx)
+
+ angle = math.degrees(rads)
+
+
+ # Move this to ItemChange() or something at some point.
+ #
+ # if (modifiers == Qt.ShiftModifier):
+ # if int(angle / 45.0) == int(oldAngle / 45.0):
+ # return False, 0
+ # else:
+ # angle = int(angle / 45.0) * 45.0
+
+ return True, angle - origAngle + oldAngle
+
+
+ def mouseMoveEvent(self, event):
+
+ # Fucking Transform can't do independent transforms with doing matrix math directly.
+ # And before anyone asks, using QTransform.scale() is no good.
+
+ if self.resizing:
+ obj = self._doodadRef()
+ scenePos = event.scenePos()
+
+ hasChanged = False
+ bit = self.resizing
+
+ hasChanged, scale = self._tryAndResize(bit, scenePos, event.modifiers())
+
+ if hasChanged:
+ obj.scale = scale
+
+ self.setScale(scale)
+
+
+ elif self.rotating:
+ obj = self._doodadRef()
+ scenePos = event.scenePos()
+
+ hasChanged = False
+
+ hasChanged, angle = self._tryAndRotate(obj, scenePos.x(), scenePos.y(), self.rotating[0], self.rotating[1], event.modifiers())
+
+ if hasChanged:
+ obj.angle = angle
+ self.setRotation(angle)
+
+
+ else:
+ KPEditorItem.mouseMoveEvent(self, event)
+
+
+ def mouseReleaseEvent(self, event):
+ if self.resizing and event.button() == Qt.LeftButton:
+ self.resizing = None
+ elif self.rotating and event.button() == Qt.LeftButton:
+ self.rotating = None
+
+ else:
+ KPEditorItem.mouseReleaseEvent(self, event)
+
+
+
class KPMapScene(QtGui.QGraphicsScene):
def __init__(self):
QtGui.QGraphicsScene.__init__(self, 0, 0, 512*24, 512*24)
@@ -282,7 +487,7 @@ class KPMapScene(QtGui.QGraphicsScene):
def drawBackground(self, painter, rect):
- painter.fillRect(rect, Qt.white)
+ painter.fillRect(rect, QtGui.QColor(209, 218, 236))
areaLeft, areaTop = rect.x(), rect.y()
areaWidth, areaHeight = rect.width(), rect.height()
@@ -320,10 +525,9 @@ class KPMapScene(QtGui.QGraphicsScene):
continue
for item in toDraw:
- painter.save()
- painter.setWorldTransform(item.transform(), True)
- painter.drawPixmap(0, 0, item.pixmap)
- painter.restore()
+ item.paint(painter, QtGui.QStyleOptionGraphicsItem(), self)
+ # painter.setWorldTransform(item.transform(), True)
+ # painter.drawPixmap(0, 0, item.pixmap)
elif isinstance(layer, KPTileLayer):
left, top = layer.cacheBasePos
@@ -419,8 +623,8 @@ class KPEditorWidget(QtGui.QGraphicsView):
'''Called when a paint attempt is initiated'''
if self.paintNext is None: return
-
paint = self.paintNext
+
if isinstance(paint, KPTileObject):
clicked = self.mapToScene(event.x(), event.y())
x, y = clicked.x(), clicked.y()
@@ -432,6 +636,7 @@ class KPEditorWidget(QtGui.QGraphicsView):
layer = self.scene().currentLayer
if not layer.visible: return
+ if not isinstance(layer, KPTileLayer): return
obj = KPObject()
obj.position = (x,y)
@@ -448,6 +653,36 @@ class KPEditorWidget(QtGui.QGraphicsView):
self.painting = obj
self.paintingItem = item
self.paintBeginPosition = (x, y)
+
+ if isinstance(paint, QtGui.QListWidgetItem):
+ clicked = self.mapToScene(event.x(), event.y())
+ x, y = clicked.x(), clicked.y()
+ if x < 0: x = 0
+ if y < 0: y = 0
+
+ layer = self.scene().currentLayer
+ if not layer.visible: return
+ if not isinstance(layer, KPDoodadLayer): return
+
+ size = paint.icon().availableSizes()[0]
+
+ obj = KPDoodad()
+ obj.position = (x,y)
+ obj.size = (size.width(), size.height())
+ obj.index = self.paintNextID
+ layer.objects.append(obj)
+
+ item = KPEditorDoodad(obj, layer)
+ item.setPixmap(paint.icon().pixmap(size))
+ item.setTransformOriginPoint(item.boundingRect().center())
+ item.setPos(x, y)
+ self.scene().addItem(item)
+
+ self.painting = obj
+ self.paintingItem = item
+ self.paintBeginPosition = (x, y)
+
+
def _movedWhilePainting(self, event):
'''Called when the mouse is moved while painting something'''
diff --git a/src/mapdata.py b/src/mapdata.py
index 53331c5..64a8f44 100644
--- a/src/mapdata.py
+++ b/src/mapdata.py
@@ -115,7 +115,8 @@ class KPDoodad(object):
def __init__(self):
self.position = (0,0)
self.angle = 0
- self.scale = (0,0)
+ self.scale = 1.0
+ self.index = 0
class KPDoodadLayer(KPLayer):
diff --git a/src/ui.py b/src/ui.py
index 247938e..825a713 100644
--- a/src/ui.py
+++ b/src/ui.py
@@ -2,6 +2,7 @@
from common import *
from editorui import *
+import os
class KPLayerList(QtGui.QWidget):
@@ -28,7 +29,8 @@ class KPLayerList(QtGui.QWidget):
def setupToolbar(self, tb):
- self.actAdd = tb.addAction(QtGui.QIcon(), 'Add', self.addLayer)
+ self.actAddTile = tb.addAction(QtGui.QIcon(), 'T+', self.addTileLayer)
+ self.actAddDoodad = tb.addAction(QtGui.QIcon(), 'D+', self.addDoodadLayer)
self.actRemove = tb.addAction(QtGui.QIcon(), 'Remove', self.removeLayer)
self.actMoveUp = tb.addAction(QtGui.QIcon(), 'Move Up', self.moveUp)
self.actMoveDown = tb.addAction(QtGui.QIcon(), 'Move Down', self.moveDown)
@@ -55,22 +57,26 @@ class KPLayerList(QtGui.QWidget):
self.setButtonStates()
- def addLayer(self):
+ def addTileLayer(self):
from dialogs import KPTilesetChooserDialog
- special = ['Doodads (Special)']
- tilesetName = KPTilesetChooserDialog.run('Choose a tileset for the new layer', special)
+ tilesetName = KPTilesetChooserDialog.run('Choose a tileset for the new layer')
if tilesetName is None:
return
- if tilesetName == 0:
- layer = KP.map.createNewDoodadLayer()
- else:
- layer = KP.map.createNewTileLayer(tilesetName)
+ layer = KP.map.createNewTileLayer(tilesetName)
+
+ KP.map.appendLayer(layer)
+ self.setButtonStates()
+
+
+ def addDoodadLayer(self):
+ layer = KP.map.createNewDoodadLayer()
KP.map.appendLayer(layer)
self.setButtonStates()
+
def removeLayer(self):
layer = self.selectedLayer()
scene = KP.mainWindow.scene
@@ -96,6 +102,135 @@ class KPLayerList(QtGui.QWidget):
+class KPDoodadSelector(QtGui.QWidget):
+ objChanged = QtCore.pyqtSignal(int, QtGui.QListWidgetItem)
+
+
+ def __init__(self):
+ """Initialises the widget."""
+
+ QtGui.QWidget.__init__(self)
+
+ self.layout = QtGui.QVBoxLayout()
+ self.layout.setSpacing(0)
+
+ self.doodadList = QtGui.QListWidget()
+ self.doodadList.setViewMode(1)
+ self.doodadList.setWrapping(True)
+ self.doodadList.setDragDropMode(1)
+ self.doodadList.setSelectionMode(1)
+ self.doodadList.setResizeMode(1)
+ self.doodadList.setGridSize(QtCore.QSize(128, 128))
+ self.doodadList.setIconSize(QtCore.QSize(100, 100))
+ self.doodadList.setSpacing(4)
+
+
+ self.toolbar = QtGui.QToolBar()
+ self.layout.addWidget(self.toolbar)
+
+ self.addDoodadButton = self.toolbar.addAction(QtGui.QIcon(), 'Add', self.addDoodadfromFile)
+ self.removeDoodadButton = self.toolbar.addAction(QtGui.QIcon(), 'Remove', self.removeDoodad)
+
+
+ self.layout.addWidget(self.doodadList)
+
+ self.setLayout(self.layout)
+
+ self.nextIndex = 0
+
+ self.doodadList.currentItemChanged.connect(self.handleRowChanged)
+
+
+ def keyPressEvent(self, event):
+
+ self.doodadList.keyPressEvent(event)
+
+ if event.key() == 0x1000003:
+
+ msgBox = QtGui.QMessageBox(QtGui.QMessageBox.Warning,
+ "Delete Doodad?", "Are you sure you want to delete this doodad? This action cannot be undone.",
+ QtGui.QMessageBox.NoButton, self)
+ msgBox.addButton("Delete", QtGui.QMessageBox.AcceptRole)
+ msgBox.addButton("Cancel", QtGui.QMessageBox.RejectRole)
+ if msgBox.exec_() == QtGui.QMessageBox.AcceptRole:
+ self.removeDoodad()
+
+
+ def addDoodad(self, image, name):
+ """Takes a name and a QPixmap and turns it into an icon, then goes ahead and makes a doodad.
+ Doodads are QListWidget items with an index number as Qt.UserRole #32."""
+
+
+ doodie = QtGui.QListWidgetItem(QtGui.QIcon(image), name)
+ doodie.setSizeHint(QtCore.QSize(128,128))
+ doodie.setData(32, self.nextIndex)
+ doodie.setToolTip(name)
+ doodie.setTextAlignment(Qt.AlignBottom | Qt.AlignHCenter)
+
+ self.doodadList.addItem(doodie)
+ self.nextIndex += 1
+
+
+ def addDoodadfromFile(self):
+ """Asks the user for files to load in as doodads."""
+
+ log = QtGui.QFileDialog()
+ log.setFileMode(3);
+
+ files = QtGui.QFileDialog.getOpenFileNames(self,
+ "Choose an image or several image files.", "",
+ "Images (*.png *.jpeg *.jpg *.bmp)")
+ if files:
+ for image in files:
+ name = os.path.basename(unicode(image)).split('.')[0]
+
+ pix = QtGui.QPixmap()
+ pix.load(image)
+
+ self.addDoodad(pix, name)
+
+
+ def removeDoodad(self):
+ """Removes selected doodad"""
+
+ item = self.doodadList.currentRow()
+
+ if item != -1:
+ self.doodadList.takeItem(item)
+
+
+ def getDoodad(self, index):
+ """Retrieves a doodad by index"""
+
+ for item in self.doodadList.items():
+ if item.data(32) == index:
+ return item
+
+
+ def getDoodadImage(self, index, width, height):
+ """Retrieves a doodad pixmap by index"""
+
+ for item in self.doodadList.items():
+ if item.data(32) == index:
+ return item.icon().pixmap(width, height)
+
+ def getDoodads(self):
+ """Returns a list of all doodads.
+
+ Name can be retrieved with doodad.text()
+ Image with doodad.icon().pixmap(doodad.icon().availableSizes()[0])
+ Index with doodad.data(32)"""
+
+ return self.doodadList.items()
+
+
+ @QtCore.pyqtSlot(QtGui.QListWidgetItem)
+ def handleRowChanged(self, current):
+ """Throws a signal emitting the current object when changed"""
+
+ self.objChanged.emit(current.data(32), current)
+
+
class KPObjectSelector(QtGui.QWidget):
@@ -246,11 +381,6 @@ class KPObjectSelector(QtGui.QWidget):
-
-
-
-
-
class KPMainWindow(QtGui.QMainWindow):
def __init__(self):
QtGui.QMainWindow.__init__(self)
@@ -285,16 +415,31 @@ class KPMainWindow(QtGui.QMainWindow):
self.objectSelectorDock = QtGui.QDockWidget('Objects')
self.objectSelectorDock.setWidget(self.objectSelector)
+ self.doodadSelector = KPDoodadSelector()
+ self.doodadSelector.objChanged.connect(self.handleSelectedDoodadChanged)
+
+ self.doodadSelectorDock = QtGui.QDockWidget('Doodads')
+ self.doodadSelectorDock.setWidget(self.doodadSelector)
+ self.doodadSelectorDock.hide()
self.addDockWidget(Qt.RightDockWidgetArea, self.layerListDock)
self.addDockWidget(Qt.RightDockWidgetArea, self.objectSelectorDock)
+ self.addDockWidget(Qt.RightDockWidgetArea, self.doodadSelectorDock)
@QtCore.pyqtSlot(KPLayer)
def handleSelectedLayerChanged(self, layer):
self.scene.setCurrentLayer(layer)
- self.objectSelector.setModel(KP.map.loadedTilesets[layer.tileset].getModel())
+ if isinstance(layer, KPDoodadLayer):
+ self.objectSelectorDock.hide()
+ self.doodadSelectorDock.show()
+
+ else:
+ self.doodadSelectorDock.hide()
+ self.objectSelectorDock.show()
+
+ self.objectSelector.setModel(KP.map.loadedTilesets[layer.tileset].getModel())
@QtCore.pyqtSlot(int, KPTileObject)
@@ -303,5 +448,10 @@ class KPMainWindow(QtGui.QMainWindow):
self.editor.paintNextID = index
+ @QtCore.pyqtSlot(int, QtGui.QListWidgetItem)
+ def handleSelectedDoodadChanged(self, index, obj):
+ self.editor.paintNext = obj
+ self.editor.paintNextID = index
+