diff options
-rw-r--r-- | src/editorui.py | 310 | ||||
-rw-r--r-- | src/mapdata.py | 8 | ||||
-rw-r--r-- | src/ui.py | 14 |
3 files changed, 185 insertions, 147 deletions
diff --git a/src/editorui.py b/src/editorui.py index 5dd68b5..98d57f2 100644 --- a/src/editorui.py +++ b/src/editorui.py @@ -12,23 +12,26 @@ class KPEditorItem(QtGui.QGraphicsItem): self.ItemIsSelectable | self.ItemIsMovable ) + + self.overrideSnap = False def itemChange(self, change, value): - if change == self.ItemPositionChange: + if change == self.ItemPositionChange and not self.overrideSnap: currentX, currentY = self.x(), self.y() - # snap the item to 24x24 + # snap the item + snapX, snapY = self.SNAP_TO newpos = value.toPyObject() x, y = newpos.x(), newpos.y() - x = int((x + 12) / 24) * 24 - y = int((y + 12) / 24) * 24 + x = int((x + (snapX/2)) / snapX) * snapX + y = int((y + (snapY/2)) / snapY) * snapY if x < 0: x = 0 - if x > 12264: x = 12264 + if x >= (12288+snapX): x = (12288+snapX-1) if y < 0: y = 0 - if y > 12264: y = 12264 + if y >= (12288+snapY): y = (12288+snapY-1) if x != currentX or y != currentY: self._itemMoved(currentX, currentY, x, y) @@ -42,11 +45,46 @@ class KPEditorItem(QtGui.QGraphicsItem): def boundingRect(self): return self._boundingRect + + RESIZER_TOP_LEFT = 1 + RESIZER_TOP_RIGHT = 2 + RESIZER_BOTTOM_LEFT = 3 + RESIZER_BOTTOM_RIGHT = 4 + RESIZER_TOP = 5 + RESIZER_BOTTOM = 6 + RESIZER_LEFT = 7 + RESIZER_RIGHT = 8 + + def resizerPortionAt(self, x, y): + try: + rightBound, bottomBound = self._resizerEndXY + except AttributeError: + rect = self._boundingRect + rightBound, bottomBound = rect.right() - 5, rect.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 _itemMoved(self, oldX, oldY, newX, newY): pass class KPEditorObject(KPEditorItem): + SNAP_TO = (24,24) + def __init__(self, obj, layer): KPEditorItem.__init__(self) obj.qtItem = self @@ -64,9 +102,7 @@ class KPEditorObject(KPEditorItem): # care of the layered drawing def _updatePosition(self): - obj = self._objRef() - x,y = obj.position - + x,y = self._objRef().position self.setPos(x*24, y*24) def _updateSize(self): @@ -87,34 +123,6 @@ class KPEditorObject(KPEditorItem): painter.drawRect(self._selectionRect) - RESIZER_TOP_LEFT = 1 - RESIZER_TOP_RIGHT = 2 - RESIZER_BOTTOM_LEFT = 3 - RESIZER_BOTTOM_RIGHT = 4 - RESIZER_TOP = 5 - RESIZER_BOTTOM = 6 - RESIZER_LEFT = 7 - RESIZER_RIGHT = 8 - - def resizerPortionAt(self, x, y): - rightBound, bottomBound = self._resizerEndXY - - 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) @@ -165,6 +173,8 @@ class KPEditorObject(KPEditorItem): objPosition = obj.position[axisIndex] objSize = obj.size[axisIndex] + mousePosition = int(mousePosition / 12) * 12 + if stationarySide == 0: # Resize the right/bottom side @@ -215,10 +225,14 @@ class KPEditorObject(KPEditorItem): hasChanged |= self._tryAndResize(obj, 1, int(scenePos.y() / 24), ySide) if hasChanged: + # TODO: move overrides into updatePosition? + # TODO: snapping for resizing + self.overrideSnap = True obj.updateCache() self._layerRef().updateCache() self._updatePosition() self._updateSize() + self.overrideSnap = False else: KPEditorItem.mouseMoveEvent(self, event) @@ -238,19 +252,18 @@ class KPEditorObject(KPEditorItem): def remove(self): - obj = self._objRef() layer = self._layerRef() - index = layer.objects.index(obj) - layer.objects.pop(index) + layer.objects.remove(obj) layer.updateCache() - del obj -class KPEditorDoodad(QtGui.QGraphicsPixmapItem): +class KPEditorDoodad(KPEditorItem): + SNAP_TO = (12,12) + def __init__(self, doodad, layer): - QtGui.QGraphicsPixmapItem.__init__(self) + KPEditorItem.__init__(self) self.setFlags( self.ItemSendsGeometryChanges | self.ItemIsSelectable | @@ -261,56 +274,68 @@ class KPEditorDoodad(QtGui.QGraphicsPixmapItem): self._doodadRef = weakref.ref(doodad) self._layerRef = weakref.ref(layer) + # TODO: refactor this to store source doodad data under KP.map + sourceItem = KP.mainWindow.doodadSelector.getDoodad(doodad.index) + self._sourceRef = weakref.ref(sourceItem) + self.resizing = None self.rotating = None + self._updatePixmap() + self._updatePosition() + self._updateSize() + self._updateTransform() + self.setAcceptHoverEvents(True) - self.setTransformationMode(1) - def paint(self, painter, option, widget): + def _updatePixmap(self): + source = self._sourceRef() + pixmap = source.icon().pixmap(source.icon().availableSizes()[0]) - try: - QtGui.QGraphicsPixmapItem.paint(self, painter, option, widget) - except: - pass + self.prepareGeometryChange() + w, h = pixmap.width(), pixmap.height() - if self.isSelected(): - painter.setPen(QtGui.QPen(Qt.white, 1, Qt.DotLine)) - painter.drawRect(self.boundingRect().adjusted(-1,-1,1,1)) - - - def _itemMoved(self, oldX, oldY, newX, newY): - doodad = self._doodadRef() - doodad.position = (newX, newY) + self.pixmap = pixmap + def _updatePosition(self): + x,y = self._doodadRef().position + self.setPos(x, y) - def itemChange(self, change, value): + def _updateSize(self): + self.prepareGeometryChange() - return QtGui.QGraphicsItem.itemChange(self, change, value) + w,h = self._doodadRef().size + self.setTransformOriginPoint(w/2, h/2) + self._boundingRect = QtCore.QRectF(0, 0, w, h) + self._selectionRect = QtCore.QRectF(0, 0, w-1, h-1) - def resizerPortionAt(self, x, y): + self._resizerEndXY = (w-5, h-5) - rightBound = self.boundingRect().right() - 5 - bottomBound = self.boundingRect().bottom() - 5 + def _updateTransform(self): + doodad = self._doodadRef() + pixmap = self.pixmap + displaceX, displaceY = pixmap.width()/2, pixmap.height()/2 - if y < 5: - if x < 5: return 1 # TOP_LEFT - elif x >= rightBound: return 2 # TOP_RIGHT - else: return 5 # TOP + transform = QtGui.QTransform() + transform.translate(displaceX, displaceY) + transform.rotate(doodad.angle) + transform.translate(-displaceX, -displaceY) + self.setTransform(transform) - 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 paint(self, painter, option, widget): + if self.isSelected(): + painter.setPen(QtGui.QPen(Qt.white, 1, Qt.DotLine)) + painter.drawRect(self._selectionRect) + def _itemMoved(self, oldX, oldY, newX, newY): + doodad = self._doodadRef() + doodad.position = (newX, newY) + + def hoverMoveEvent(self, event): if self._layerRef() != KP.mapScene.currentLayer: self.setCursor(Qt.ArrowCursor) @@ -320,7 +345,7 @@ class KPEditorDoodad(QtGui.QGraphicsPixmapItem): bit = self.resizerPortionAt(pos.x(), pos.y()) - if (event.modifiers() == Qt.AltModifier): + if (event.modifiers() == Qt.ShiftModifier): if bit: self.setCursor(Qt.OpenHandCursor) @@ -349,56 +374,69 @@ class KPEditorDoodad(QtGui.QGraphicsPixmapItem): if self._layerRef() == KP.mapScene.currentLayer and bit: event.accept() - if (event.modifiers() == Qt.AltModifier): + if (event.modifiers() & Qt.ShiftModifier): self.rotating = self.mapToScene(pos), self._doodadRef().angle self.setCursor(Qt.ClosedHandCursor) return else: - self.resizing = bit + x, xSide, y, ySide = False, None, False, None + + if bit == 1 or bit == 7 or bit == 3: + x, xSide = True, 1 + elif bit == 2 or bit == 4 or bit == 8: + x, xSide = True, 0 + + if bit == 1 or bit == 2 or bit == 5: + y, ySide = True, 1 + elif bit == 3 or bit == 4 or bit == 6: + y, ySide = True, 0 + + self.resizing = (x, xSide, y, ySide) 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 + def _tryAndResize(self, obj, axisIndex, mousePosition, stationarySide): + objPosition = obj.position[axisIndex] + objSize = obj.size[axisIndex] + + + if stationarySide == 0: + # Resize the right/bottom side + relativeMousePosition = mousePosition - objPosition + newSize = relativeMousePosition + 1 + if newSize == objSize or newSize < 1: + return False + + if axisIndex == 1: + obj.size = (obj.size[0], newSize) + else: + obj.size = (newSize, obj.size[1]) + else: - return False, 0 + # Resize the left/top side + rightSide = objPosition + objSize - 1 + newLeftSide = mousePosition + newPosition = newLeftSide + newSize = rightSide - newLeftSide + 1 - if relativeScale > 1.0: - relativeScale = 1.0 + if newSize < 1: + return False + if newPosition == objPosition and newSize == objSize: + return False - if relativeScale < 0.1: - relativeScale = 0.1 - - self.setTransformOriginPoint(self.boundingRect().center()) + if axisIndex == 1: + obj.position = (obj.position[0], newPosition) + obj.size = (obj.size[0], newSize) + else: + obj.position = (newPosition, obj.position[1]) + obj.size = (newSize, obj.size[1]) - return True, relativeScale + return True def _tryAndRotate(self, obj, mouseX, mouseY, originalPos, oldAngle, modifiers): @@ -417,9 +455,6 @@ class KPEditorDoodad(QtGui.QGraphicsPixmapItem): origAngle = math.degrees(rads) - - - dy = mouseY - objY dx = mouseX - objX rads = math.atan2(dy, dx) @@ -428,34 +463,30 @@ class KPEditorDoodad(QtGui.QGraphicsPixmapItem): # 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 + finalAngle = angle - origAngle + oldAngle - return True, angle - origAngle + oldAngle + if (modifiers & Qt.ControlModifier): + finalAngle = int(finalAngle / 45.0) * 45.0 + return True, finalAngle - 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. + def mouseMoveEvent(self, event): if self.resizing: obj = self._doodadRef() scenePos = event.scenePos() hasChanged = False - bit = self.resizing + resizeX, xSide, resizeY, ySide = self.resizing - hasChanged, scale = self._tryAndResize(bit, scenePos, event.modifiers()) + if resizeX: + hasChanged |= self._tryAndResize(obj, 0, scenePos.x(), xSide) + if resizeY: + hasChanged |= self._tryAndResize(obj, 1, scenePos.y(), ySide) if hasChanged: - obj.scale = scale - - self.setScale(scale) + self._updatePosition() + self._updateSize() elif self.rotating: @@ -468,7 +499,7 @@ class KPEditorDoodad(QtGui.QGraphicsPixmapItem): if hasChanged: obj.angle = angle - self.setRotation(angle) + self._updateTransform() else: @@ -486,12 +517,10 @@ class KPEditorDoodad(QtGui.QGraphicsPixmapItem): def remove(self): - doodad = self._doodadRef() layer = self._layerRef() - index = layer.objects.index(doodad) - layer.objects.pop(index) + layer.objects.remove(doodad) del doodad @@ -632,10 +661,12 @@ class KPMapScene(QtGui.QGraphicsScene): except KeyError: continue - for item in toDraw: - item.paint(painter, QtGui.QStyleOptionGraphicsItem(), self) - # painter.setWorldTransform(item.transform(), True) - # painter.drawPixmap(0, 0, item.pixmap) + for item in reversed(toDraw): + painter.save() + painter.setWorldTransform(item.sceneTransform(), True) + w, h = item._doodadRef().size + painter.drawPixmap(0, 0, w, h, item.pixmap) + painter.restore() elif isinstance(layer, KPTileLayer): left, top = layer.cacheBasePos @@ -771,18 +802,13 @@ class KPEditorWidget(QtGui.QGraphicsView): 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 + obj.setDefaultSize() 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 diff --git a/src/mapdata.py b/src/mapdata.py index 3c60e53..8671430 100644 --- a/src/mapdata.py +++ b/src/mapdata.py @@ -114,9 +114,15 @@ class KPTileLayer(KPLayer): class KPDoodad(object): def __init__(self): self.position = (0,0) + self.size = (0,0) self.angle = 0 - self.scale = 1.0 self.index = 0 + + def setDefaultSize(self): + source = KP.mainWindow.doodadSelector.getDoodad(self.index) + pixmap = source.icon().pixmap(source.icon().availableSizes()[0]) + self.size = pixmap.width(), pixmap.height() + class KPDoodadLayer(KPLayer): @@ -201,16 +201,22 @@ class KPDoodadSelector(QtGui.QWidget): def getDoodad(self, index): """Retrieves a doodad by index""" + index = QtCore.QVariant(index) + widget = self.doodadList - for item in self.doodadList.items(): + for i in xrange(widget.count()): + item = widget.item(i) if item.data(32) == index: return item def getDoodadImage(self, index, width, height): """Retrieves a doodad pixmap by index""" + index = QtCore.QVariant(index) + widget = self.doodadList - for item in self.doodadList.items(): + for i in xrange(widget.count()): + item = widget.item(i) if item.data(32) == index: return item.icon().pixmap(width, height) @@ -221,14 +227,14 @@ class KPDoodadSelector(QtGui.QWidget): Image with doodad.icon().pixmap(doodad.icon().availableSizes()[0]) Index with doodad.data(32)""" + # TODO: FIX THIS 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) + self.objChanged.emit(current.data(32).toPyObject(), current) |