# -*- coding: UTF-8 -*- from common import * from editorui.editorcommon import * from editorui.editormain import * import os class KPLayerList(QtGui.QWidget): def __init__(self): QtGui.QWidget.__init__(self) self.layout = QtGui.QVBoxLayout() self.layout.setSpacing(0) self.model = KP.map.layerModel self.listView = QtGui.QListView() self.listView.setModel(self.model) self.listView.selectionModel().currentRowChanged.connect(self.handleRowChanged) self.layout.addWidget(self.listView) self.toolbar = QtGui.QToolBar() self.layout.addWidget(self.toolbar) self.setupToolbar(self.toolbar) self.setButtonStates() self.setLayout(self.layout) def setupToolbar(self, tb): self.actAddTile = tb.addAction(KP.icon('LayerNewTile'), 'Add Tile Layer', self.addTileLayer) self.actAddDoodad = tb.addAction(KP.icon('LayerNewObjects'), 'Add Doodad Layer', self.addDoodadLayer) self.actRemove = tb.addAction(KP.icon('LayerRemove'), 'Remove', self.removeLayer) self.actMoveUp = tb.addAction(QtGui.QIcon(), 'Move Up', self.moveUp) self.actMoveDown = tb.addAction(QtGui.QIcon(), 'Move Down', self.moveDown) def setButtonStates(self): index = self.selectedLayerIndex() self.actRemove.setEnabled((index != -1) and (len(KP.map.layers) > 1)) self.actMoveUp.setEnabled(index > 0) self.actMoveDown.setEnabled((index != -1) and (index < (len(KP.map.layers) - 1))) def selectedLayerIndex(self): return self.listView.selectionModel().currentIndex().row() def selectedLayer(self): return KP.map.layers[self.listView.selectionModel().currentIndex().row()] selectedLayerChanged = QtCore.pyqtSignal(KPLayer) @QtCore.pyqtSlot(QtCore.QModelIndex, QtCore.QModelIndex) def handleRowChanged(self, current, previous): self.selectedLayerChanged.emit(KP.map.layers[current.row()]) self.setButtonStates() def addTileLayer(self): from dialogs import KPTilesetChooserDialog tilesetName = KPTilesetChooserDialog.run('Choose a tileset for the new layer') if tilesetName is None: return 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 for obj in layer.objects: item = obj.qtItem if item: scene.removeItem(item) KP.map.removeLayer(self.selectedLayer()) self.setButtonStates() def moveUp(self): index = self.selectedLayerIndex() KP.map.moveLayer(index, index - 1) KP.mainWindow.editor.viewport().update() def moveDown(self): index = self.selectedLayerIndex() KP.map.moveLayer(index, index + 2) KP.mainWindow.editor.viewport().update() 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() == QtCore.Qt.Key_Delete or event.key() == QtCore.Qt.Key_Backspace: 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""" index = QtCore.QVariant(index) widget = self.doodadList 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 i in xrange(widget.count()): item = widget.item(i) 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)""" # 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).toPyObject(), current) class KPObjectSelector(QtGui.QWidget): def __init__(self): """Initialises the widget. Remember to call setModel() on it with a KPGroupModel whenever the layer changes.""" QtGui.QWidget.__init__(self) self.menuSetup = False self.sorterButton = QtGui.QToolButton() self.sorterButton.setText('Pick a Layer') self.sorterButton.setEnabled(False) self.sorterButton.setPopupMode(self.sorterButton.InstantPopup) self.sorterButton.setToolButtonStyle(Qt.ToolButtonTextOnly) self.sorterButton.setSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding) self.sorterMenu = QtGui.QMenu() self.sorterButton.setMenu(self.sorterMenu) self.layout = QtGui.QVBoxLayout() self.layout.setSpacing(0) self.toolbar = QtGui.QToolBar() self.toolbar.setFixedHeight(28) self.toolbar.addWidget(self.sorterButton) self.layout.addWidget(self.toolbar) self.listView = QtGui.QListView() self.listView.setFlow(QtGui.QListView.LeftToRight) self.listView.setLayoutMode(QtGui.QListView.SinglePass) self.listView.setMovement(QtGui.QListView.Static) self.listView.setResizeMode(QtGui.QListView.Adjust) self.listView.setWrapping(True) self.listView.setEnabled(False) self.layout.addWidget(self.listView) self.setLayout(self.layout) self.model = None # Borrowed the signals and junk from Reggie, figure we'll need em' # Some more signals are set in setModel self.listView.clicked.connect(self.handleObjReplace) self.sorterMenu.aboutToShow.connect(self.fixUpMenuSize) self.sorterMenu.triggered.connect(self.toggleTopLevel) def beginUsingMenu(self): if self.menuSetup: return font = QtGui.QFont() font.setPixelSize(18) font.setBold(True) self.sorterButton.setFont(font) self.sorterButton.setEnabled(True) self.menuSetup = True def fixUpMenuSize(self): self.sorterMenu.setFixedWidth(self.sorterButton.width()) def currentSelectedObject(self): """Returns the currently selected object reference, for painting purposes.""" index = self.listView.currentIndex().row() object = self.model.groupItem().getItem(index) return object def setModel(self, model): """Sets the model and the menu sorting list""" if model == self.model: return self.model = model self.listView.setModel(model) self.listView.setEnabled(True) model.view = self.listView menuList = model.groupItem().getGroupList() self.beginUsingMenu() string = QtCore.QString(QtCore.QChar(0x25BE)) string.append(' All Groups') self.sorterButton.setText(string) self.sorterMenu.clear() for item in menuList: actionMan = self.sorterMenu.addAction(item[0]) actionMan.setData((item[1], item[2])) # a Quick Fix self.listView.setRowHidden(0, True) # set up signals self.listView.selectionModel().currentRowChanged.connect(self.handleRowChanged) def toggleTopLevel(self, action): """Changes the top level group in the list view.""" name = str(action.text()).strip() startRow = action.data().toPyObject()[0] + 1 endRow = action.data().toPyObject()[1] for row in xrange(self.model.rowCount()): if (row < startRow) or (row > endRow): self.listView.setRowHidden(row, True) else: self.listView.setRowHidden(row, False) string = QtCore.QString(QtCore.QChar(0x25BE)) string.append(' ' + name) self.sorterButton.setText(string) @QtCore.pyqtSlot(QtCore.QModelIndex, QtCore.QModelIndex) def handleRowChanged(self, current, previous): """Throws a signal emitting the current object when changed""" i = current.row() object, depth = self.model.groupItem().getItem(i) self.objChanged.emit(i, object) def handleObjReplace(self, index): """Throws a signal when the selected object is used as a replacement""" if QtGui.QApplication.keyboardModifiers() == QtCore.Qt.AltModifier: i = current.row() object, depth = self.model.groupItem().getItem(i) self.objReplaced.emit(i, object) objChanged = QtCore.pyqtSignal(int, KPTileObject) objReplaced = QtCore.pyqtSignal(int, KPTileObject) class KPMainWindow(QtGui.QMainWindow): def __init__(self): QtGui.QMainWindow.__init__(self) self.scene = KPMapScene() self.editor = KPEditorWidget(self.scene) self.setCentralWidget(self.editor) self.setupMenuBar() self.setupDocks() def setupMenuBar(self): mb = self.menuBar() m = mb.addMenu('&File') # ... def setupDocks(self): self.layerList = KPLayerList() self.layerListDock = QtGui.QDockWidget('Layers') self.layerListDock.setWidget(self.layerList) self.layerList.selectedLayerChanged.connect(self.handleSelectedLayerChanged) self.objectSelector = KPObjectSelector() self.objectSelector.objChanged.connect(self.handleSelectedObjectChanged) 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) if isinstance(layer, KPDoodadLayer): self.objectSelectorDock.hide() self.doodadSelectorDock.show() elif isinstance(layer, KPTileLayer): self.doodadSelectorDock.hide() self.objectSelectorDock.show() self.objectSelector.setModel(KP.map.loadedTilesets[layer.tileset].getModel()) @QtCore.pyqtSlot(int, KPTileObject) def handleSelectedObjectChanged(self, index, obj): self.editor.paintNext = obj self.editor.paintNextID = index @QtCore.pyqtSlot(int, QtGui.QListWidgetItem) def handleSelectedDoodadChanged(self, index, obj): self.editor.paintNext = obj self.editor.paintNextID = index