from common import * from editorcommon import * import weakref class KPEditorNode(KPEditorItem): SNAP_TO = (12,12) class ToggleButton(QtGui.QPushButton): stateToggled = QtCore.pyqtSignal(int) def __init__(self): QtGui.QPushButton.__init__(self) self.setIconSize(QtCore.QSize(24, 24)) self.setFixedSize(24, 24) self.iconList = [QtGui.QIcon("Resources/Through.png"), QtGui.QIcon("Resources/Level.png"), QtGui.QIcon("Resources/Exit.png")] self.state = 0 if not hasattr(KPEditorNode.ToggleButton, 'PALETTE'): KPEditorNode.ToggleButton.PALETTE = QtGui.QPalette(Qt.transparent) self.setPalette(self.PALETTE) self.released.connect(self.toggle) def toggle(self): self.state += 1 if self.state == 3: self.state = 0 self.stateToggled.emit(self.state) def paintEvent(self, event): painter = QtGui.QPainter(self) if self.isDown(): self.iconList[self.state].paint(painter, self.contentsRect(), Qt.AlignCenter, QtGui.QIcon.Disabled) else: self.iconList[self.state].paint(painter, self.contentsRect()) painter.end() class HiddenProxy(QtGui.QGraphicsProxyWidget): def __init__(self, button, parent, x, y): QtGui.QGraphicsProxyWidget.__init__(self, parent) self.setWidget(button) self.setPos(x, y) self.setZValue(parent.zValue()+1000) self.hide() class LevelSlotSpinner(QtGui.QSpinBox): def __init__(self): QtGui.QSpinBox.__init__(self) self.setRange(1, 99) palette = self.palette() palette.setColor(QtGui.QPalette.ButtonText, Qt.black) palette.setColor(QtGui.QPalette.Window, Qt.transparent) self.setPalette(palette) class TransitionBox(QtGui.QComboBox): def __init__(self): QtGui.QComboBox.__init__(self) self.addItems(['Fade Out', 'Circle Wipe', 'Bowser Wipe', 'Goo Wipe Down', 'Mario Wipe', 'Circle Wipe Slow', 'Glitchgasm']) palette = self.palette() palette.setColor(QtGui.QPalette.ButtonText, Qt.black) palette.setColor(QtGui.QPalette.Window, Qt.transparent) self.setPalette(palette) class mapArcEdit(QtGui.QLineEdit): def __init__(self): QtGui.QLineEdit.__init__(self) self.setText('None.arc') palette = self.palette() palette.setColor(QtGui.QPalette.ButtonText, Qt.black) palette.setColor(QtGui.QPalette.Window, Qt.transparent) self.setPalette(palette) def __init__(self, node): KPEditorItem.__init__(self) node.qtItem = self self._nodeRef = weakref.ref(node) self.setZValue(101) self._boundingRect = QtCore.QRectF(-24, -24, 48, 48) self._levelRect = self._boundingRect self._stopRect = QtCore.QRectF(-12, -12, 24, 24) self._tinyRect = QtCore.QRectF(-6, -6, 12, 12) if not hasattr(KPEditorNode, 'SELECTION_PEN'): KPEditorNode.SELECTION_PEN = QtGui.QPen(Qt.blue, 1, Qt.DotLine) self.button = self.ToggleButton() self.buttonProxy = self.HiddenProxy(self.button, self, 12, -24) self.button.stateToggled.connect(self.stateChange) self.world = self.LevelSlotSpinner() self.worldProxy = self.HiddenProxy(self.world, self, -42, 24) self.world.valueChanged.connect(self.worldChange) self.stage = self.LevelSlotSpinner() self.stageProxy = self.HiddenProxy(self.stage, self, 6, 24) self.stage.valueChanged.connect(self.stageChange) if node.level != None: self.world.setValue(node.level[0]) self.stage.setValue(node.level[1]) self.foreignID = self.LevelSlotSpinner() self.foreignIDProxy = self.HiddenProxy(self.foreignID, self, 60, 24) self.foreignID.valueChanged.connect(self.foreignIDChange) self.mapChange = self.mapArcEdit() self.mapChangeProxy = self.HiddenProxy(self.mapChange, self, -100, 60) self.mapChange.textEdited.connect(self.mapChangeChange) self.transition = self.TransitionBox() self.transitionProxy = self.HiddenProxy(self.transition, self, -102, 24) self.transition.currentIndexChanged.connect(self.transitionChange) if node.foreignID != None: self.foreignID.setValue(node.foreignID) if node.mapChange != None: self.mapChange.setText(node.mapChange) self.transition.setCurrentIndex(node.transition) self._updatePosition() @QtCore.pyqtSlot(int) def stateChange(self, state): node = self._nodeRef() node.transition = 0 node.mapChange = None node.mapID = None node.foreignID = None node.level = None if state == 1: node.level = [1, 1] self.world.setValue(node.level[0]) self.stage.setValue(node.level[1]) elif state == 2: node.transition = 0 node.mapChange = 'None.arc' node.foreignID = 0 usedIDs = [] for nodesPicker in KP.map.pathLayer.nodes: usedIDs.append(nodesPicker.mapID) i = 1 while i in usedIDs: i += 1 node.mapID = i self.foreignID.setValue(1) self.mapChange.setText('None.arc') self.transition.setCurrentIndex(0) self.update() KP.mainWindow.pathNodeList.update() @QtCore.pyqtSlot(int) def worldChange(self, world): node = self._nodeRef() node.level[0] = world KP.mainWindow.pathNodeList.update() @QtCore.pyqtSlot(int) def stageChange(self, stage): node = self._nodeRef() node.level[1] = stage KP.mainWindow.pathNodeList.update() @QtCore.pyqtSlot(int) def foreignIDChange(self, ID): node = self._nodeRef() node.foreignID = ID KP.mainWindow.pathNodeList.update() @QtCore.pyqtSlot(int) def transitionChange(self, index): node = self._nodeRef() node.transition = index KP.mainWindow.pathNodeList.update() @QtCore.pyqtSlot(str) def mapChangeChange(self, mapname): node = self._nodeRef() node.mapChange = mapname KP.mainWindow.pathNodeList.update() def _updatePosition(self): self.ignoreMovement = True node = self._nodeRef() x, y = node.position self.setPos(x+12, y+12) self.ignoreMovement = False def _itemMoved(self, oldX, oldY, newX, newY): node = self._nodeRef() node.position = (newX-12, newY-12) for exit in node.exits: exit.qtItem.updatePosition() def paint(self, painter, option, widget): painter.setRenderHint(QtGui.QPainter.Antialiasing) node = self._nodeRef() selectionRect = None if node.level: painter.setBrush(QtGui.QColor(0, 0, 0, 0)) painter.setPen(QtGui.QColor(0, 0, 0, 0)) painter.drawPixmap(self._boundingRect.topLeft(), QtGui.QPixmap("Resources/BlackLevel.png")) selectionRect = self._boundingRect.adjusted(1,5,-1,-5) elif node.mapChange != None: painter.setBrush(QtGui.QColor(0, 0, 0, 0)) painter.setPen(QtGui.QColor(0, 0, 0, 0)) painter.drawPixmap(self._boundingRect.topLeft(), QtGui.QPixmap("Resources/ExitWorld.png")) textPath = QtGui.QPainterPath() font = QtGui.QFont("Times", 22) font.setStyleStrategy(QtGui.QFont.ForceOutline) textPath.addText(-6, 3, font, str(node.mapID)) painter.setBrush(QtGui.QColor(140, 140, 255)) pen = QtGui.QPen(QtGui.QColor(80, 80, 255)) pen.setWidth(1) pen.setStyle(Qt.SolidLine) painter.setPen(pen) painter.drawPath(textPath) selectionRect = self._boundingRect.adjusted(1,5,-1,-5) elif len(node.exits) != 2: brush = QtGui.QBrush(QtGui.QColor(255, 220, 220)) painter.setPen(QtGui.QColor(255, 255, 255)) painter.setBrush(brush) painter.drawEllipse(self._stopRect) selectionRect = self._stopRect.adjusted(-1,-1,1,1) else: brush = QtGui.QBrush(QtGui.QColor(255, 255, 255)) painter.setPen(QtGui.QColor(255, 255, 255)) painter.setBrush(brush) painter.drawEllipse(self._tinyRect) selectionRect = self._tinyRect.adjusted(-1,-1,1,1) if self.isSelected(): painter.setPen(self.SELECTION_PEN) painter.setBrush(QtGui.QColor(0,0,0,0)) painter.drawEllipse(selectionRect) self.buttonProxy.show() if node.level: self.worldProxy.show() self.stageProxy.show() else: self.worldProxy.hide() self.stageProxy.hide() if node.mapChange != None: self.foreignID.show() self.transition.show() self.mapChange.show() else: self.foreignID.hide() self.transition.hide() self.mapChange.hide() else: self.buttonProxy.hide() self.worldProxy.hide() self.stageProxy.hide() self.foreignID.hide() self.transition.hide() self.mapChange.hide() def remove(self, withItem=False): node = self._nodeRef() layer = KP.map.pathLayer layer.nodes.remove(node) KP.mainWindow.pathNodeList.removeLayer(node) if len(node.exits) == 2: # let's try to join the two! pathOne, pathTwo = node.exits start1, end1 = pathOne._startNodeRef(), pathOne._endNodeRef() start2, end2 = pathTwo._startNodeRef(), pathTwo._endNodeRef() if start1 == node: start = end1 else: start = start1 if start2 == node: end = end2 else: end = start2 # make sure no path already exists between these nodes nope = False for pathToCheck in start.exits: if pathToCheck._startNodeRef() == end: nope = True elif pathToCheck._endNodeRef() == end: nope = True if not nope: joinedPath = KPPath(start, end, pathOne) KP.mainWindow.pathNodeList.addLayer(joinedPath) layer.paths.append(joinedPath) item = KPEditorPath(joinedPath) self.scene().addItem(item) for path in (pathOne, pathTwo): path.qtItem.remove(True) else: # we can't join them so just nuke them for exit in node.exits[:]: exit.qtItem.remove(True) if withItem: self.scene().removeItem(self) class KPEditorPath(QtGui.QGraphicsLineItem): class PathOptionsMenuButton(QtGui.QPushButton): class PathOptionsWidget(QtGui.QWidget): def __init__(self, pathRef): QtGui.QWidget.__init__(self) self._pathRef = pathRef TopLayout = QtGui.QGridLayout() Layout = QtGui.QGridLayout() # Make an exclusive button group for our animations. AnimationList = ["Walk", "WalkSand", "WalkSnow", "WalkWater", "Jump", "JumpSand", "JumpSnow", "JumpWater", "Ladder", "LadderLeft", "LadderRight", "Fall", "Swim", "Run", "Pipe", "Door"] self.ExclusiveButtons = QtGui.QButtonGroup() i = 0 j = 1 id = 0 for anim in AnimationList: newButton = QtGui.QPushButton(QtGui.QIcon("Resources/Anm/" + anim), "") newButton.setCheckable(True) newButton.setIconSize(QtCore.QSize(38, 38)) newButton.setToolTip(anim) self.ExclusiveButtons.addButton(newButton, id) Layout.addWidget(newButton, j, i) if id == 0: newButton.setChecked(True) id += 1 i += 1 if i == 4: i = 0 j += 1 # Movement Speed Spin Box self.moveSpeedSpinner = QtGui.QDoubleSpinBox() self.moveSpeedSpinner.setMinimum(0.0) self.moveSpeedSpinner.setMaximum(256.0) self.moveSpeedSpinner.setDecimals(2) self.moveSpeedSpinner.setSingleStep(0.05) self.moveSpeedSpinner.setValue(1.0) TopLayout.addWidget(self.moveSpeedSpinner, 1, 0) # Layer Combo Box # self.linkedLayer = QtGui.QComboBox(self) # self.linkedLayer.setModel(KP.map.layerModel) # TopLayout.addWidget(self.linkedLayer, 1, 1, 1, 3) # Connections # regular connect doesn't work for some reason... #self.ExclusiveButtons.buttonReleased.connect(self.updatePathAnim) QtCore.QObject.connect( self.ExclusiveButtons, QtCore.SIGNAL('buttonReleased(int)'), self.updatePathAnim) self.moveSpeedSpinner.valueChanged.connect(self.updateMoveSpeed) # self.linkedLayer.currentIndexChanged.connect(self.updateLinkLayer) # Layout TopLayout.addWidget(QtGui.QLabel("Speed:"), 0, 0) TopLayout.addWidget(QtGui.QLabel("Layer Shown on Unlock:"), 0, 1, 1, 3) Layout.addLayout(TopLayout, 0, 0, 1, 4) self.setLayout(Layout) @QtCore.pyqtSlot(float) def updateMoveSpeed(self, speed): path = self._pathRef() path.movementSpeed = speed path.qtItem.update() @QtCore.pyqtSlot(int) def updatePathAnim(self, buttonID): path = self._pathRef() path.animation = buttonID path.qtItem.update() @QtCore.pyqtSlot(int) def updateLinkLayer(self, layerIndex): path = self._pathRef() path.linkedLayer = KP.map.layers[layerIndex] def __init__(self, pathRef): QtGui.QPushButton.__init__(self) self.setText("Options") self.menu = QtGui.QMenu(self) layout = QtGui.QVBoxLayout() self.bgroupWidget = self.PathOptionsWidget(pathRef) layout.addWidget(self.bgroupWidget) self.menu.setLayout(layout) menuPalette = self.menu.palette() menuPalette.setColor(QtGui.QPalette.Window, Qt.black) self.menu.setPalette(menuPalette) # dropShadow = QtGui.QGraphicsDropShadowEffect() # self.menu.setGraphicsEffect(dropShadow) self.setMenu(self.menu) palette = self.palette() palette.setColor(QtGui.QPalette.ButtonText, Qt.black) palette.setColor(QtGui.QPalette.Window, Qt.transparent) self.setPalette(palette) class UnlockButton(QtGui.QPushButton): def __init__(self, pathRef): QtGui.QPushButton.__init__(self) self.setFixedSize(48,48) self.iconList = [QtGui.QIcon("Resources/Key.png"), QtGui.QIcon("Resources/SecretKey.png")] self.unlockIcon = QtGui.QIcon("Resources/Unlock.png") self.arrowIcon = [QtGui.QIcon("Resources/KeyArrow.png"), QtGui.QIcon("Resources/SecretKeyArrow.png")] self._pathRef = pathRef self.secret = 0 self.path = 0 if not hasattr(KPEditorPath.UnlockButton, 'PALETTE'): KPEditorPath.UnlockButton.PALETTE = QtGui.QPalette(Qt.transparent) self.setPalette(self.PALETTE) self.released.connect(self.toggle) def toggle(self): path = self._pathRef() if KP.app.keyboardModifiers() == Qt.ShiftModifier: if self.secret == 1: self.secret = 0 else: self.secret = 1 path.secret = self.secret else: self.path += 1 if self.path > 2: self.path = 0 path.unlocks = self.path def paintEvent(self, event): painter = QtGui.QPainter(self) contentsRect = self.contentsRect() smallRect = QtCore.QRect(12, 12, 24, 24) painter.setRenderHint(QtGui.QPainter.SmoothPixmapTransform) if self.path > 0: painter.save() displaceX, displaceY = contentsRect.width() / 2, contentsRect.height() / 2 pathItem = self._pathRef().qtItem.line() if self.path == 1: angle = 90 - pathItem.angle() else: angle = 270 - pathItem.angle() painter.translate(displaceX, displaceY) painter.rotate(angle) painter.translate(-displaceX, -displaceY) self.arrowIcon[self.secret].paint(painter, contentsRect, Qt.AlignCenter) painter.restore() if self.isDown(): self.iconList[self.secret].paint(painter, smallRect, Qt.AlignCenter, QtGui.QIcon.Disabled) else: self.iconList[self.secret].paint(painter, smallRect, Qt.AlignCenter) else: if self.isDown(): self.unlockIcon.paint(painter, smallRect, Qt.AlignCenter, QtGui.QIcon.Disabled) else: self.unlockIcon.paint(painter, smallRect, Qt.AlignCenter) painter.end() class HiddenProxy(QtGui.QGraphicsProxyWidget): def __init__(self, button, parent, x, y): QtGui.QGraphicsProxyWidget.__init__(self, parent) self.setWidget(button) self.setPos(x, y) self.setZValue(parent.zValue()+1000) self.hide() def __init__(self, path): QtGui.QGraphicsLineItem.__init__(self) self.setFlag(self.ItemIsSelectable, True) self.setZValue(100) startNode = path._startNodeRef().qtItem endNode = path._endNodeRef().qtItem startNode.update() endNode.update() self._startNodeRef = weakref.ref(startNode) self._endNodeRef = weakref.ref(endNode) self._pathRef = weakref.ref(path) path.qtItem = self if not hasattr(KPEditorPath, 'PEN'): KPEditorPath.BRUSH = QtGui.QBrush(QtGui.QColor(255, 255, 255, 140)) KPEditorPath.PEN = QtGui.QPen(KPEditorPath.BRUSH, 8, Qt.SolidLine, Qt.RoundCap) self.setPen(KPEditorPath.PEN) if not hasattr(KPEditorPath, 'SELECTION_PEN'): KPEditorPath.SELECTION_PEN = QtGui.QPen(Qt.blue, 1, Qt.DotLine) self.unlock = self.UnlockButton(self._pathRef) self.unlockProxy = self.HiddenProxy(self.unlock, self, -24, -24) self.unlock.secret = path.secret self.unlock.path = path.unlocks self.options = self.PathOptionsMenuButton(self._pathRef) self.optionsProxy = self.HiddenProxy(self.options, self, -54, +24) self.options.bgroupWidget.ExclusiveButtons.button(path.animation).setChecked(True) self.options.bgroupWidget.moveSpeedSpinner.setValue(path.movementSpeed) self.updatePosition() def updatePosition(self): path = self._pathRef() sn = path._startNodeRef() en = path._endNodeRef() if sn is None or en is None: return x1, y1 = path._startNodeRef().position x2, y2 = path._endNodeRef().position originLine = QtCore.QLineF(x1+12, y1+12, x2+12, y2+12) self.setPos(originLine.pointAt(0.5)) dy = originLine.dy()/2 dx = originLine.dx()/2 self.setLine(QtCore.QLineF(-dx, -dy, dx, dy)) def paint(self, painter, option, widget): painter.setRenderHint(QtGui.QPainter.Antialiasing) painter.setPen(KPEditorPath.PEN) painter.drawLine(self.line()) if self.isSelected(): painter.setPen(self.SELECTION_PEN) painter.setBrush(QtGui.QColor(0,0,0,0)) painter.drawPath(self.shape()) self.unlockProxy.show() self.optionsProxy.show() else: self.unlockProxy.hide() self.optionsProxy.hide() def remove(self, withItem=False): if hasattr(self, 'hasBeenRemovedAlready'): return self.hasBeenRemovedAlready = True path = self._pathRef() layer = KP.map.pathLayer KP.mainWindow.pathNodeList.removeLayer(path) layer.paths.remove(path) for ref in (self._startNodeRef, self._endNodeRef): node = ref()._nodeRef() try: node.exits.remove(path) node.qtItem.update() except ValueError: pass if withItem: self.scene().removeItem(self)