from common import * from math import floor, ceil import weakref class KPEditorItem(QtGui.QGraphicsItem): def __init__(self): QtGui.QGraphicsItem.__init__(self) self.setFlags( self.ItemSendsGeometryChanges | self.ItemIsSelectable | self.ItemIsMovable ) def itemChange(self, change, value): if change == self.ItemPositionChange: currentX, currentY = self.x(), self.y() # snap the item to 24x24 newpos = value.toPyObject() x, y = newpos.x(), newpos.y() x = int((x + 12) / 24) * 24 y = int((y + 12) / 24) * 24 if x < 0: x = 0 if x > 12264: x = 12264 if y < 0: y = 0 if y > 12264: y = 12264 if x != currentX or y != currentY: print "Position change" self._itemMoved(currentX, currentY, x, y) newpos.setX(x) newpos.setY(y) return newpos return QtGui.QGraphicsItem.itemChange(self, change, value) def boundingRect(self): return self._boundingRect def _itemMoved(self, oldX, oldY, newX, newY): pass class KPEditorObject(KPEditorItem): def __init__(self, obj, layer): KPEditorItem.__init__(self) obj.qtItem = self self._objRef = weakref.ref(obj) self._layerRef = weakref.ref(layer) self._updatePosition() self._updateSize() def _updatePosition(self): obj = self._objRef() x,y = obj.position self.setPos(x*24, y*24) def _updateSize(self): self.prepareGeometryChange() obj = self._objRef() w,h = obj.size self._boundingRect = QtCore.QRectF(0, 0, w*24, h*24) self._selectionRect = QtCore.QRectF(0, 0, w*24-1, h*24-1) 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): obj = self._objRef() obj.position = (newX/24, newY/24) self._layerRef().updateCache() class KPMapScene(QtGui.QGraphicsScene): def __init__(self): QtGui.QGraphicsScene.__init__(self, 0, 0, 512*24, 512*24) # todo: handle selectionChanged # todo: look up why I used setItemIndexMethod(self.NoIndex) in Reggie self.currentLayer = None def drawBackground(self, painter, rect): painter.fillRect(rect, Qt.white) areaLeft, areaTop = rect.x(), rect.y() areaWidth, areaHeight = rect.width(), rect.height() areaRight, areaBottom = areaLeft+areaWidth, areaTop+areaHeight areaLeftT = floor(areaLeft / 24) areaTopT = floor(areaTop / 24) areaRightT = ceil(areaRight / 24) areaBottomT = ceil(areaBottom / 24) for layer in KP.map.layers: left, top = layer.cacheBasePos width, height = layer.cacheSize right, bottom = left+width, top+height if width == 0 and height == 0: continue if right < areaLeftT: continue if left > areaRightT: continue if bottom < areaTopT: continue if top > areaBottomT: continue # decide how much of the layer we'll actually draw drawLeft = int(max(areaLeftT, left)) drawRight = int(min(areaRightT, right)) drawTop = int(max(areaTopT, top)) drawBottom = int(min(areaBottomT, bottom)) srcY = drawTop - top destY = drawTop * 24 baseSrcX = drawLeft - left baseDestX = drawLeft * 24 rows = layer.cache tileset = KP.map.loadedTilesets[layer.tileset] tileList = tileset.tiles for y in xrange(drawTop, drawBottom): srcX = baseSrcX destX = baseDestX row = rows[srcY] for x in xrange(drawLeft, drawRight): tile = row[srcX] if tile != -1: painter.drawPixmap(destX, destY, tileList[tile]) srcX += 1 destX += 24 srcY += 1 destY += 24 def setCurrentLayer(self, layer): if self.currentLayer is not None: self.setLayerObjectsFlag(self.currentLayer, QtGui.QGraphicsItem.ItemIsSelectable, False) self.currentLayer = layer self.setLayerObjectsFlag(layer, QtGui.QGraphicsItem.ItemIsSelectable, True) def setLayerObjectsFlag(self, layer, flag, value): for obj in layer.objects: item = obj.qtItem if item: item.setFlag(flag, value) class KPEditorWidget(QtGui.QGraphicsView): def __init__(self, scene, parent=None): QtGui.QGraphicsView.__init__(self, scene, parent) self.setAlignment(Qt.AlignLeft | Qt.AlignTop) self.setDragMode(self.RubberBandDrag) self.xScrollBar = QtGui.QScrollBar(Qt.Horizontal, parent) self.setHorizontalScrollBar(self.xScrollBar) self.yScrollBar = QtGui.QScrollBar(Qt.Vertical, parent) self.setVerticalScrollBar(self.yScrollBar) self.centerOn(0,0) # set up stuff for painting self.paintNext = None self.paintNextID = None self._resetPaintVars() def _resetPaintVars(self): self.painting = None self.paintingItem = None def _tryToPaint(self, event): '''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() if x < 0: x = 0 if y < 0: y = 0 x = int(x / 24) y = int(y / 24) layer = self.scene().currentLayer obj = KPObject() obj.position = (x,y) obj.size = (1,1) obj.tileset = layer.tileset obj.kind = self.paintNextID obj.updateCache() layer.objects.append(obj) layer.updateCache() item = KPEditorObject(obj, layer) self.scene().addItem(item) self.painting = obj self.paintingItem = item def mousePressEvent(self, event): if event.button() == Qt.RightButton: self._tryToPaint(event) event.accept() else: QtGui.QGraphicsView.mousePressEvent(self, event)