From 38e50fb9870ff1b253a28ba6143339727a5b476f Mon Sep 17 00:00:00 2001 From: Colin Noga Date: Fri, 4 Nov 2011 22:02:51 -0500 Subject: Koopuzzle now seems to be working 100%..., included a testing tileset called Test5.arc that covers all group use cases. --- Koopuzzle/Koopuzzle.py | 1878 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1878 insertions(+) create mode 100755 Koopuzzle/Koopuzzle.py (limited to 'Koopuzzle/Koopuzzle.py') diff --git a/Koopuzzle/Koopuzzle.py b/Koopuzzle/Koopuzzle.py new file mode 100755 index 0000000..4962e5c --- /dev/null +++ b/Koopuzzle/Koopuzzle.py @@ -0,0 +1,1878 @@ +#!/usr/bin/env python + +import archive +import os.path +import struct +import sys +import cPickle + +from ctypes import create_string_buffer +from PyQt4 import QtCore, QtGui + + + +######################################################## +# To Do: +# +# - Object Editor +# - Moving objects around +# +# - Make UI simpler for Pop +# - C speed saving +# +######################################################## + + +Tileset = None + +############################################################################################# +########################## Tileset Class and Tile/Object Subclasses ######################### + +class TilesetClass(): + '''Contains Tileset data. Inits itself to a blank tileset. + Methods: addTile, removeTile, addObject, removeObject, clear''' + + class Tile(): + def __init__(self, image): + '''Tile Constructor''' + + self.image = image + + + class Object(): + + def __init__(self, height, width, uslope, lslope, tilelist): + '''Tile Constructor''' + + self.height = height + self.width = width + + self.upperslope = uslope + self.lowerslope = lslope + + self.tiles = tilelist + + + def __init__(self): + '''Constructor''' + + self.tiles = [] + self.objects = [] + + self.slot = 0 + + + def addTile(self, image): + '''Adds an tile class to the tile list with the passed image or parameters''' + + self.tiles.append(self.Tile(image)) + + + def addObject(self, height = 1, width = 1, uslope = [0, 0], lslope = [0, 0], tilelist = [[(0, 0xFFFF, 0)]]): + '''Adds a new object''' + + global Tileset + + + # Initialize trusim power! This is required to work, due to python's single default parameter initialization + if tilelist == [[(0, 0xFFFF, 0)]]: + tilelist = [[(0, 0xFFFF, 0)]] + + self.objects.append(self.Object(height, width, uslope, lslope, tilelist)) + + + def removeObject(self, index): + '''Removes an Object by Index number. Don't use this much, because we want objects to preserve their ID.''' + + self.objects.pop(index) + + + def clear(self): + '''Clears the tileset for a new file''' + + self.tiles = [] + self.objects = [] + + + def clearObjects(self): + '''Clears the object data''' + + self.objects = [] + + +############################################################################################# +##################### Object List Widget and Model Setup with Painter ####################### + + +class objectList(QtGui.QListView): + + def __init__(self, parent=None): + super(objectList, self).__init__(parent) + + + self.setFlow(QtGui.QListView.TopToBottom) + # self.setViewMode(QtGui.QListView.ListMode) + self.setIconSize(QtCore.QSize(96,96)) + self.setGridSize(QtCore.QSize(100,100)) + self.setMovement(QtGui.QListView.Static) + self.setBackgroundRole(QtGui.QPalette.BrightText) + self.setEditTriggers(QtGui.QAbstractItemView.NoEditTriggers) + self.setWrapping(False) + + + +def SetupObjectModel(self, objects, tiles, treecko, group): + global Tileset + self.clear() + + count = 0 + for object in objects: + tex = QtGui.QPixmap(object.width * 24, object.height * 24) + tex.fill(QtCore.Qt.transparent) + painter = QtGui.QPainter(tex) + + Xoffset = 0 + Yoffset = 0 + + for i in range(len(object.tiles)): + for tile in object.tiles[i]: + if (tile[1] != 0xFFFF): + painter.drawPixmap(Xoffset, Yoffset, tiles[tile[1]].image) + Xoffset += 24 + Xoffset = 0 + Yoffset += 24 + + painter.end() + + self.appendRow(QtGui.QStandardItem(QtGui.QIcon(tex), 'Object {0}'.format(count))) + + count += 1 + + if group != None: + grovyle = cPickle.loads(group) + makeTree(grovyle, treecko) + + +def makeTree(grovyle, treecko): + + for razorLeaf in grovyle: + + if (type(razorLeaf) is str) and (razorLeaf[:6] == "Object"): + + pix = QtGui.QPixmap(24, 24) + pix.fill(QtCore.Qt.transparent) + painter = QtGui.QPainter(pix) + painter.drawPixmap(0, 0, pix) + painter.end() + + a = QtGui.QTreeWidgetItem(treecko) + a.setText(0, razorLeaf) + a.setFlags(QtCore.Qt.ItemFlags(0x25)) + a.setIcon(1, QtGui.QIcon(pix)) + + else: + + a = QtGui.QTreeWidgetItem(treecko) + a.setText(0, razorLeaf[0]) + a.setFlags(QtCore.Qt.ItemFlags(0x2F)) + a.setChildIndicatorPolicy(QtGui.QTreeWidgetItem.ShowIndicator) + a.setExpanded(True) + + + makeTree(razorLeaf[1], a) + + + + +@QtCore.pyqtSlot(QtGui.QTreeWidgetItem, int) +def connectToTileWidget(tree, column): + + row = tree.text(0) + if row[:7] == "Object ": + + newrow = int(row[7:]) + index = window.objmodel.index(newrow, 0) + + window.objectList.setCurrentIndex(index) + + window.tileWidget.setObject(index) + + + +############################################################################################# +######################## List Widget with custom painter/MouseEvent ######################### + + +class displayWidget(QtGui.QListView): + + def __init__(self, parent=None): + super(displayWidget, self).__init__(parent) + + self.setMinimumWidth(818) + self.setMaximumWidth(818) + self.setMinimumHeight(404) + self.setMaximumHeight(404) + self.setDragEnabled(True) + self.setViewMode(QtGui.QListView.IconMode) + self.setIconSize(QtCore.QSize(24,24)) + self.setGridSize(QtCore.QSize(25,25)) + self.setMovement(QtGui.QListView.Static) + self.setAcceptDrops(False) + self.setDropIndicatorShown(True) + self.setResizeMode(QtGui.QListView.Adjust) + self.setUniformItemSizes(True) + self.setBackgroundRole(QtGui.QPalette.BrightText) + self.setMouseTracking(True) + self.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) + + self.setItemDelegate(self.TileItemDelegate()) + + + + class TileItemDelegate(QtGui.QAbstractItemDelegate): + """Handles tiles and their rendering""" + + def __init__(self): + """Initialises the delegate""" + QtGui.QAbstractItemDelegate.__init__(self) + + def paint(self, painter, option, index): + """Paints an object""" + + global Tileset + p = index.model().data(index, QtCore.Qt.DecorationRole) + painter.drawPixmap(option.rect.x(), option.rect.y(), p.pixmap(24,24)) + + x = option.rect.x() + y = option.rect.y() + + + # Highlight stuff. + colour = QtGui.QColor(option.palette.highlight()) + colour.setAlpha(80) + + if option.state & QtGui.QStyle.State_Selected: + painter.fillRect(option.rect, colour) + + + def sizeHint(self, option, index): + """Returns the size for the object""" + return QtCore.QSize(24,24) + + + +############################################################################################# +############################ Tile widget for drag n'drop Objects ############################ + + +class tileOverlord(QtGui.QWidget): + + def __init__(self): + super(tileOverlord, self).__init__() + + # Setup Widgets + self.tiles = tileWidget() + + self.addObject = QtGui.QPushButton('Add') + self.removeObject = QtGui.QPushButton('Remove') + + self.addRow = QtGui.QPushButton('+') + self.removeRow = QtGui.QPushButton('-') + + self.addColumn = QtGui.QPushButton('+') + self.removeColumn = QtGui.QPushButton('-') + + self.tilingMethod = QtGui.QComboBox() + + self.tilingMethod.addItems(['Repeat', + 'Stretch Center', + 'Stretch X', + 'Stretch Y', + 'Repeat Bottom', + 'Repeat Top', + 'Repeat Left', + 'Repeat Right', + 'Upward slope', + 'Downward slope', + 'Downward reverse slope', + 'Upward reverse slope']) + + + # Connections + self.addObject.released.connect(self.addObj) + self.removeObject.released.connect(self.removeObj) + self.addRow.released.connect(self.tiles.addRow) + self.removeRow.released.connect(self.tiles.removeRow) + self.addColumn.released.connect(self.tiles.addColumn) + self.removeColumn.released.connect(self.tiles.removeColumn) + + self.tilingMethod.activated.connect(self.setTiling) + + + # Layout + layout = QtGui.QGridLayout() + + layout.addWidget(self.tilingMethod, 0, 0, 1, 3) + + layout.addWidget(self.addObject, 0, 6, 1, 1) + layout.addWidget(self.removeObject, 0, 7, 1, 1) + + layout.setRowMinimumHeight(1, 40) + + layout.setRowStretch(1, 1) + layout.setRowStretch(2, 5) + layout.setRowStretch(5, 5) + layout.addWidget(self.tiles, 2, 1, 4, 6) + + layout.addWidget(self.addColumn, 3, 7, 1, 1) + layout.addWidget(self.removeColumn, 4, 7, 1, 1) + layout.addWidget(self.addRow, 6, 3, 1, 1) + layout.addWidget(self.removeRow, 6, 4, 1, 1) + + self.setLayout(layout) + + + def addObj(self): + global Tileset + + Tileset.addObject() + + pix = QtGui.QPixmap(24, 24) + pix.fill(QtCore.Qt.transparent) + painter = QtGui.QPainter(pix) + painter.drawPixmap(0, 0, pix) + painter.end() + + count = len(Tileset.objects) + window.objmodel.appendRow(QtGui.QStandardItem(QtGui.QIcon(pix), 'Object {0}'.format(count-1))) + a = QtGui.QTreeWidgetItem(window.treeki) + a.setText(0, 'Object {0}'.format(count-1)) + a.setFlags(QtCore.Qt.ItemFlags(0x25)) + a.setIcon(1, QtGui.QIcon(pix)) + + index = window.objectList.currentIndex() + window.objectList.setCurrentIndex(index) + self.setObject(index) + + window.objectList.update() + self.update() + + + def removeObj(self): + global Tileset + + index = window.objectList.currentIndex() + + Tileset.removeObject(index.row()) + window.objmodel.removeRow(index.row()) + self.tiles.clear() + + matchList = window.treeki.findItems("Object {0}".format(index.row()), QtCore.Qt.MatchExactly | QtCore.Qt.MatchRecursive | QtCore.Qt.MatchWrap) + for x in matchList: + index = window.treeki.indexFromItem(x, 0) + realx = index.row() + if x.parent(): + y = x.parent().takeChild(realx) + del y + else: + y =window.treeki.takeTopLevelItem(realx) + del y + + + window.objectList.update() + self.update() + + + def setObject(self, index): + global Tileset + object = Tileset.objects[index.row()] + + width = len(object.tiles[0])-1 + height = len(object.tiles)-1 + Xuniform = True + Yuniform = True + Xstretch = False + Ystretch = False + + for tile in object.tiles[0]: + if tile[0] != object.tiles[0][0][1]: + Xuniform = False + + for tile in object.tiles: + if tile[0][0] != object.tiles[0][0][1]: + Yuniform = False + + if object.tiles[0][0][1] == object.tiles[0][width][0] and Xuniform == False: + Xstretch = True + + if object.tiles[0][0][1] == object.tiles[height][0][0] and Xuniform == False: + Ystretch = True + + + + if object.upperslope[0] != 0: + if object.upperslope[0] == 0x90: + self.tilingMethod.setCurrentIndex(8) + elif object.upperslope[0] == 0x91: + self.tilingMethod.setCurrentIndex(9) + elif object.upperslope[0] == 0x92: + self.tilingMethod.setCurrentIndex(10) + elif object.upperslope[0] == 0x93: + self.tilingMethod.setCurrentIndex(11) + + else: + if Xuniform and Yuniform: + self.tilingMethod.setCurrentIndex(0) + elif Xstretch and Ystretch: + self.tilingMethod.setCurrentIndex(1) + elif Xstretch: + self.tilingMethod.setCurrentIndex(2) + elif Ystretch: + self.tilingMethod.setCurrentIndex(3) + elif Xuniform and Yuniform == False and object.tiles[0][0][0] == 0: + self.tilingMethod.setCurrentIndex(4) + elif Xuniform and Yuniform == False and object.tiles[height][0][0] == 0: + self.tilingMethod.setCurrentIndex(5) + elif Xuniform == False and Yuniform and object.tiles[0][0][0] == 0: + self.tilingMethod.setCurrentIndex(6) + elif Xuniform == False and Yuniform and object.tiles[0][width][0] == 0: + self.tilingMethod.setCurrentIndex(7) + + + self.tiles.setObject(object) + + # print 'Object {0}, Width: {1} / Height: {2}, Slope {3}/{4}'.format(index.row(), object.width, object.height, object.upperslope, object.lowerslope) + # for row in object.tiles: + # print 'Row: {0}'.format(row) + # print '' + + @QtCore.pyqtSlot(int) + def setTiling(self, listindex): + global Tileset + + index = window.objectList.currentIndex() + object = Tileset.objects[index.row()] + + + if listindex == 0: # Repeat + ctile = 0 + crow = 0 + + for row in object.tiles: + for tile in row: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + ctile += 1 + crow += 1 + ctile = 0 + + if listindex == 1: # Stretch Center + + if object.width < 3 and object.height < 3: + reply = QtGui.QMessageBox.information(self, "Warning", "An object must be at least 3 tiles\nwide and 3 tiles tall to apply stretch center.") + self.setObject(index) + return + + ctile = 0 + crow = 0 + + for row in object.tiles: + for tile in row: + if crow == 0 and ctile == 0: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + elif crow == 0 and ctile == object.width-1: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + elif crow == object.height-1 and ctile == object.width-1: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + elif crow == object.height-1 and ctile == 0: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + elif crow == 0 or crow == object.height-1: + object.tiles[crow][ctile] = (1, tile[1], tile[2]) + elif ctile == 0 or ctile == object.width-1: + object.tiles[crow][ctile] = (2, tile[1], tile[2]) + else: + object.tiles[crow][ctile] = (3, tile[1], tile[2]) + ctile += 1 + crow += 1 + ctile = 0 + + object.upperslope = [0, 0] + object.lowerslope = [0, 0] + + if listindex == 2: # Stretch X + + if object.width < 3: + reply = QtGui.QMessageBox.information(self, "Warning", "An object must be at least 3 tiles\nwide to apply stretch X.") + self.setObject(index) + return + + ctile = 0 + crow = 0 + + for row in object.tiles: + for tile in row: + if ctile == 0: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + elif ctile == object.width-1: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + else: + object.tiles[crow][ctile] = (1, tile[1], tile[2]) + ctile += 1 + crow += 1 + ctile = 0 + + object.upperslope = [0, 0] + object.lowerslope = [0, 0] + + if listindex == 3: # Stretch Y + + if object.height < 3: + reply = QtGui.QMessageBox.information(self, "Warning", "An object must be at least 3 tiles\ntall to apply stretch Y.") + self.setObject(index) + return + + ctile = 0 + crow = 0 + + for row in object.tiles: + for tile in row: + if crow == 0: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + elif crow == object.height-1: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + else: + object.tiles[crow][ctile] = (2, tile[1], tile[2]) + ctile += 1 + crow += 1 + ctile = 0 + + object.upperslope = [0, 0] + object.lowerslope = [0, 0] + + if listindex == 4: # Repeat Bottom + + if object.height < 2: + reply = QtGui.QMessageBox.information(self, "Warning", "An object must be at least 2 tiles\ntall to apply repeat bottom.") + self.setObject(index) + return + + ctile = 0 + crow = 0 + + for row in object.tiles: + for tile in row: + if crow == object.height-1: + object.tiles[crow][ctile] = (2, tile[1], tile[2]) + else: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + ctile += 1 + crow += 1 + ctile = 0 + + object.upperslope = [0, 0] + object.lowerslope = [0, 0] + + if listindex == 5: # Repeat Top + + if object.height < 2: + reply = QtGui.QMessageBox.information(self, "Warning", "An object must be at least 2 tiles\ntall to apply repeat top.") + self.setObject(index) + return + + ctile = 0 + crow = 0 + + for row in object.tiles: + for tile in row: + if crow == 0: + object.tiles[crow][ctile] = (2, tile[1], tile[2]) + else: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + ctile += 1 + crow += 1 + ctile = 0 + + object.upperslope = [0, 0] + object.lowerslope = [0, 0] + + if listindex == 6: # Repeat Left + + if object.width < 2: + reply = QtGui.QMessageBox.information(self, "Warning", "An object must be at least 2 tiles\nwide to apply repeat left.") + self.setObject(index) + return + + ctile = 0 + crow = 0 + + for row in object.tiles: + for tile in row: + if ctile == 0: + object.tiles[crow][ctile] = (1, tile[1], tile[2]) + else: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + ctile += 1 + crow += 1 + ctile = 0 + + object.upperslope = [0, 0] + object.lowerslope = [0, 0] + + if listindex == 7: # Repeat Right + + if object.width < 2: + reply = QtGui.QMessageBox.information(self, "Warning", "An object must be at least 2 tiles\nwide to apply repeat right.") + self.setObject(index) + return + + ctile = 0 + crow = 0 + + for row in object.tiles: + for tile in row: + if ctile == object.width-1: + object.tiles[crow][ctile] = (1, tile[1], tile[2]) + else: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + ctile += 1 + crow += 1 + ctile = 0 + + object.upperslope = [0, 0] + object.lowerslope = [0, 0] + + + if listindex == 8: # Upward Slope + ctile = 0 + crow = 0 + for row in object.tiles: + for tile in row: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + ctile += 1 + crow += 1 + ctile = 0 + + object.upperslope = [0x90, 1] + object.lowerslope = [0x84, object.height - 1] + self.tiles.slope = 1 + + self.tiles.update() + + if listindex == 9: # Downward Slope + ctile = 0 + crow = 0 + for row in object.tiles: + for tile in row: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + ctile += 1 + crow += 1 + ctile = 0 + + object.upperslope = [0x91, 1] + object.lowerslope = [0x84, object.height - 1] + self.tiles.slope = 1 + + self.tiles.update() + + if listindex == 10: # Upward Reverse Slope + ctile = 0 + crow = 0 + for row in object.tiles: + for tile in row: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + ctile += 1 + crow += 1 + ctile = 0 + + object.upperslope = [0x92, object.height - 1] + object.lowerslope = [0x84, 1] + self.tiles.slope = 0-(object.height-1) + + self.tiles.update() + + if listindex == 11: # Downward Reverse Slope + ctile = 0 + crow = 0 + for row in object.tiles: + for tile in row: + object.tiles[crow][ctile] = (0, tile[1], tile[2]) + ctile += 1 + crow += 1 + ctile = 0 + + object.upperslope = [0x93, object.height - 1] + object.lowerslope = [0x84, 1] + self.tiles.slope = 0-(object.height-1) + + self.tiles.update() + + +class tileWidget(QtGui.QWidget): + + def __init__(self): + super(tileWidget, self).__init__() + + self.tiles = [] + + self.size = [1, 1] + self.setMinimumSize(120, 120) + + self.slope = 0 + + self.highlightedRect = QtCore.QRect() + + self.setAcceptDrops(True) + self.object = 0 + + + def clear(self): + self.tiles = [] + self.size = [1, 1] # [width, height] + + self.slope = 0 + self.highlightedRect = QtCore.QRect() + + self.update() + + return + + + def addColumn(self): + global Tileset + + if self.size[0] >= 24: + return + + if len(Tileset.objects) == 0: + window.tileWidget.addObj() + + self.size[0] += 1 + self.setMinimumSize(self.size[0]*24, self.size[1]*24) + + pix = QtGui.QPixmap(24,24) + pix.fill(QtGui.QColor(205, 205, 255)) + + for y in xrange(self.size[1]): + self.tiles.insert(((y+1) * self.size[0]) -1, [self.size[0]-1, y, pix]) + + + curObj = Tileset.objects[self.object] + curObj.width += 1 + + for row in curObj.tiles: + row.append((0, 0xFFFF, 0)) + + self.update() + self.updateList() + + + def removeColumn(self): + global Tileset + + if self.size[0] == 1: + return + + if len(Tileset.objects) == 0: + window.tileWidget.addObj() + + for y in xrange(self.size[1]): + self.tiles.pop(((y+1) * self.size[0])-(y+1)) + + self.size[0] = self.size[0] - 1 + self.setMinimumSize(self.size[0]*24, self.size[1]*24) + + + curObj = Tileset.objects[self.object] + curObj.width -= 1 + + for row in curObj.tiles: + row.pop() + + self.update() + self.updateList() + + + def addRow(self): + global Tileset + + if len(Tileset.objects) == 0: + window.tileWidget.addObj() + + if self.size[1] >= 24: + return + + self.size[1] += 1 + self.setMinimumSize(self.size[0]*24, self.size[1]*24) + + pix = QtGui.QPixmap(24,24) + pix.fill(QtGui.QColor(205, 205, 255)) + + for x in xrange(self.size[0]): + self.tiles.append([x, self.size[1]-1, pix]) + + curObj = Tileset.objects[self.object] + curObj.height += 1 + + curObj.tiles.append([]) + for i in xrange(0, curObj.width): + curObj.tiles[len(curObj.tiles)-1].append((0, 0xFFFF, 0)) + + self.update() + self.updateList() + + + def removeRow(self): + global Tileset + + if self.size[1] == 1: + return + + if len(Tileset.objects) == 0: + window.tileWidget.addObj() + + for x in xrange(self.size[0]): + self.tiles.pop() + + self.size[1] -= 1 + self.setMinimumSize(self.size[0]*24, self.size[1]*24) + + curObj = Tileset.objects[self.object] + curObj.height -= 1 + + curObj.tiles.pop() + + self.update() + self.updateList() + + + def setObject(self, object): + self.clear() + + global Tileset + + self.size = [object.width, object.height] + + if not object.upperslope[1] == 0: + if object.upperslope[0] & 2: + self.slope = 0 - object.lowerslope[1] + else: + self.slope = object.upperslope[1] + + x = 0 + y = 0 + for row in object.tiles: + for tile in row: + + if (Tileset.slot == 0) or ((tile[2] & 3) != 0): + if (tile[1] == 0xFFFF): + pix = QtGui.QPixmap(24,24) + pix.fill(QtGui.QColor(205, 205, 255)) + self.tiles.append([x, y, pix]) + else: + self.tiles.append([x, y, Tileset.tiles[tile[1]].image]) + else: + pix = QtGui.QPixmap(24,24) + pix.fill(QtGui.QColor(205, 205, 255)) + self.tiles.append([x, y, pix]) + x += 1 + y += 1 + x = 0 + + + self.object = window.objectList.currentIndex().row() + self.update() + self.updateList() + + + def contextMenuEvent(self, event): + + TileMenu = QtGui.QMenu(self) + self.contX = event.x() + self.contY = event.y() + + TileMenu.addAction('Set tile...', self.setTile) + + TileMenu.exec_(event.globalPos()) + + + def mousePressEvent(self, event): + global Tileset + + if event.button() == 2: + return + + if window.tileDisplay.selectedIndexes() == []: + return + + currentSelected = window.tileDisplay.selectedIndexes() + + ix = 0 + iy = 0 + for modelItem in currentSelected: + # Update yourself! + centerPoint = self.contentsRect().center() + + tile = modelItem.row() + upperLeftX = centerPoint.x() - self.size[0]*12 + upperLeftY = centerPoint.y() - self.size[1]*12 + + lowerRightX = centerPoint.x() + self.size[0]*12 + lowerRightY = centerPoint.y() + self.size[1]*12 + + + x = (event.x() - upperLeftX)/24 + ix + y = (event.y() - upperLeftY)/24 + iy + + if event.x() < upperLeftX or event.y() < upperLeftY or event.x() > lowerRightX or event.y() > lowerRightY: + return + + self.tiles[(y * self.size[0]) + x][2] = Tileset.tiles[tile].image + + Tileset.objects[self.object].tiles[y][x] = (Tileset.objects[self.object].tiles[y][x][0], tile, Tileset.slot) + + ix += 1 + if self.size[0]-1 < ix: + ix = 0 + iy += 1 + if iy > self.size[1]-1: + break + + + self.update() + + self.updateList() + + + def updateList(self): + # Update the list >.> + object = window.objmodel.itemFromIndex(window.objectList.currentIndex()) + matchList = window.treeki.findItems("Object {0}".format(window.objectList.currentIndex().row()), QtCore.Qt.MatchExactly | QtCore.Qt.MatchRecursive | QtCore.Qt.MatchWrap) + + + tex = QtGui.QPixmap(self.size[0] * 24, self.size[1] * 24) + tex.fill(QtCore.Qt.transparent) + painter = QtGui.QPainter(tex) + + Xoffset = 0 + Yoffset = 0 + + for tile in self.tiles: + painter.drawPixmap(tile[0]*24, tile[1]*24, tile[2]) + + painter.end() + + try: + object.setIcon(QtGui.QIcon(tex)) + matchList[0].setIcon(1, QtGui.QIcon(tex)) + except: + pass + + window.objectList.update() + + + + def setTile(self): + global Tileset + + dlg = self.setTileDialog() + if dlg.exec_() == QtGui.QDialog.Accepted: + # Do stuff + centerPoint = self.contentsRect().center() + + upperLeftX = centerPoint.x() - self.size[0]*12 + upperLeftY = centerPoint.y() - self.size[1]*12 + + tile = dlg.tile.value() + tileset = dlg.tileset.currentIndex() + + x = (self.contX - upperLeftX)/24 + y = (self.contY - upperLeftY)/24 + + if tileset != Tileset.slot: + tex = QtGui.QPixmap(self.size[0] * 24, self.size[1] * 24) + tex.fill(QtCore.Qt.transparent) + + self.tiles[(y * self.size[0]) + x][2] = tex + + Tileset.objects[self.object].tiles[y][x] = (Tileset.objects[self.object].tiles[y][x][0], tile, tileset) + + self.update() + self.updateList() + + + class setTileDialog(QtGui.QDialog): + + def __init__(self): + QtGui.QDialog.__init__(self) + + self.setWindowTitle('Set tiles') + + self.tile = QtGui.QSpinBox() + self.tile.setRange(0, 512) + + self.buttons = QtGui.QDialogButtonBox(QtGui.QDialogButtonBox.Ok | QtGui.QDialogButtonBox.Cancel) + self.buttons.accepted.connect(self.accept) + self.buttons.rejected.connect(self.reject) + + self.layout = QtGui.QGridLayout() + self.layout.addWidget(QtGui.QLabel('Tile:'), 0,3,1,1, QtCore.Qt.AlignLeft) + self.layout.addWidget(self.tile, 1, 3, 1, 3) + self.layout.addWidget(self.buttons, 2, 3) + self.setLayout(self.layout) + + + + def paintEvent(self, event): + painter = QtGui.QPainter() + painter.begin(self) + + centerPoint = self.contentsRect().center() + upperLeftX = centerPoint.x() - self.size[0]*12 + lowerRightX = centerPoint.x() + self.size[0]*12 + + upperLeftY = centerPoint.y() - self.size[1]*12 + lowerRightY = centerPoint.y() + self.size[1]*12 + + + painter.fillRect(upperLeftX, upperLeftY, self.size[0] * 24, self.size[1]*24, QtGui.QColor(205, 205, 255)) + + for x, y, pix in self.tiles: + painter.drawPixmap(upperLeftX + (x * 24), upperLeftY + (y * 24), pix) + + if not self.slope == 0: + pen = QtGui.QPen() + # pen.setStyle(QtCore.Qt.QDashLine) + pen.setWidth(1) + pen.setColor(QtCore.Qt.blue) + painter.setPen(QtGui.QPen(pen)) + painter.drawLine(upperLeftX, upperLeftY + (abs(self.slope) * 24), lowerRightX, upperLeftY + (abs(self.slope) * 24)) + + if self.slope > 0: + main = 'Main' + sub = 'Sub' + elif self.slope < 0: + main = 'Sub' + sub = 'Main' + + font = painter.font() + font.setPixelSize(8) + font.setFamily('Monaco') + painter.setFont(font) + + painter.drawText(upperLeftX+1, upperLeftY+10, main) + painter.drawText(upperLeftX+1, upperLeftY + (abs(self.slope) * 24) + 9, sub) + + painter.end() + + + +############################################################################################# +############################ Subclassed one dimension Item Model ############################ + + +class PiecesModel(QtCore.QAbstractListModel): + def __init__(self, parent=None): + super(PiecesModel, self).__init__(parent) + + self.pixmaps = [] + self.setSupportedDragActions(QtCore.Qt.CopyAction | QtCore.Qt.MoveAction | QtCore.Qt.LinkAction) + + def data(self, index, role=QtCore.Qt.DisplayRole): + if not index.isValid(): + return None + + if role == QtCore.Qt.DecorationRole: + return QtGui.QIcon(self.pixmaps[index.row()]) + + if role == QtCore.Qt.UserRole: + return self.pixmaps[index.row()] + + return None + + def addPieces(self, pixmap): + row = len(self.pixmaps) + + self.beginInsertRows(QtCore.QModelIndex(), row, row) + self.pixmaps.insert(row, pixmap) + self.endInsertRows() + + def flags(self,index): + if index.isValid(): + return (QtCore.Qt.ItemIsEnabled | QtCore.Qt.ItemIsSelectable | + QtCore.Qt.ItemIsDragEnabled) + + def clear(self): + row = len(self.pixmaps) + + del self.pixmaps[:] + + + def mimeTypes(self): + return ['image/x-tile-piece'] + + + def mimeData(self, indexes): + mimeData = QtCore.QMimeData() + encodedData = QtCore.QByteArray() + + stream = QtCore.QDataStream(encodedData, QtCore.QIODevice.WriteOnly) + + for index in indexes: + if index.isValid(): + pixmap = QtGui.QPixmap(self.data(index, QtCore.Qt.UserRole)) + stream << pixmap + + mimeData.setData('image/x-tile-piece', encodedData) + return mimeData + + + def rowCount(self, parent): + if parent.isValid(): + return 0 + else: + return len(self.pixmaps) + + def supportedDragActions(self): + return QtCore.Qt.CopyAction | QtCore.Qt.MoveAction + + + +############################################################################################# +################## Python-based RGB5a3 Decoding code from my BRFNT program ################## + + +def RGB4A3Decode(tex): + dest = QtGui.QImage(1024,512,QtGui.QImage.Format_ARGB32) + dest.fill(QtCore.Qt.transparent) + + i = 0 + for ytile in xrange(0, 512, 4): + for xtile in xrange(0, 1024, 4): + for ypixel in xrange(ytile, ytile + 4): + for xpixel in xrange(xtile, xtile + 4): + + if(xpixel >= 1024 or ypixel >= 512): + continue + + newpixel = struct.unpack_from('>H', tex, i)[0] + # newpixel = (int(tex[i]) << 8) | int(tex[i+1]) + + + if(newpixel >= 0x8000): # Check if it's RGB555 + red = ((newpixel >> 10) & 0x1F) * 255 / 0x1F + green = ((newpixel >> 5) & 0x1F) * 255 / 0x1F + blue = (newpixel & 0x1F) * 255 / 0x1F + alpha = 0xFF + + else: # If not, it's RGB4A3 + alpha = ((newpixel & 0x7000) >> 12) * 255 / 0x7 + blue = ((newpixel & 0xF00) >> 8) * 255 / 0xF + green = ((newpixel & 0xF0) >> 4) * 255 / 0xF + red = (newpixel & 0xF) * 255 / 0xF + + argb = (blue) | (green << 8) | (red << 16) | (alpha << 24) + dest.setPixel(xpixel, ypixel, argb) + i += 2 + return dest + + +def RGB4A3Encode(tex): + destBuffer = create_string_buffer(1024*512*2) + + shortstruct = struct.Struct('>H') + offset = 0 + + for ytile in xrange(0, 512, 4): + for xtile in xrange(0, 1024, 4): + for ypixel in xrange(ytile, ytile + 4): + for xpixel in xrange(xtile, xtile + 4): + + if(xpixel >= 1024 or ypixel >= 512): + continue + + pixel = tex.pixel(xpixel, ypixel) + + a = pixel >> 24 + r = (pixel >> 16) & 0xFF + g = (pixel >> 8) & 0xFF + b = pixel & 0xFF + + if a < 245: #RGB4A3 + alpha = a/32 + red = r/16 + green = g/16 + blue = b/16 + + rgbDAT = (blue) | (green << 4) | (red << 8) | (alpha << 12) + + else: # RGB555 + red = r/8 + green = g/8 + blue = b/8 + + rgbDAT = (blue) | (green << 5) | (red << 10) | (0x8000) # 0rrrrrgggggbbbbb + + shortstruct.pack_into(destBuffer, offset, rgbDAT) + offset += 2 + + return destBuffer.raw + + +############################################################################################# +############ Main Window Class. Takes care of menu functions and widget creation ############ + + +class MainWindow(QtGui.QMainWindow): + def __init__(self, parent=None): + super(MainWindow, self).__init__(parent) + + self.tileImage = QtGui.QPixmap() + self.alpha = True + + global Tileset + Tileset = TilesetClass() + + self.name = '' + + self.setupMenus() + self.setupWidgets() + + self.setuptile() + + self.newTileset() + + self.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, + QtGui.QSizePolicy.Fixed)) + self.setWindowTitle("New Tileset") + + + def setuptile(self): + self.tileWidget.tiles.clear() + self.model.clear() + + if self.alpha == True: + for tile in Tileset.tiles: + self.model.addPieces(tile.image) + else: + for tile in Tileset.tiles: + self.model.addPieces(tile.noalpha) + + + def newTileset(self): + '''Creates a new, blank tileset''' + + global Tileset + Tileset.clear() + self.treeki.clear() + self.objmodel.clear() + + Tileset = TilesetClass() + + EmptyPix = QtGui.QPixmap(24, 24) + EmptyPix.fill(QtCore.Qt.black) + + for i in range(512): + Tileset.addTile(EmptyPix) + + self.setuptile() + self.setWindowTitle('New Tileset') + + + def openTileset(self): + '''Opens a Koopatlas tileset arc and parses the heck out of it.''' + + global Tileset + + path = str(QtGui.QFileDialog.getOpenFileName(self, "Open Koopatlas Tileset", '', + "Image Files (*.arc)")) + + if path: + self.setWindowTitle(os.path.basename(path)) + Tileset.clear() + self.treeki.clear() + self.objmodel.clear() + + name = path[str(path).rfind('/')+1:-4] + + file = open(path,'rb') + data = file.read() + file.close() + + arc = archive.U8() + arc._load(data) + + Image = None + behaviourdata = None + objstrings = None + metadata = None + + for key, value in arc.files: + if value == None: + pass + if key.startswith('BG_tex/') and key.endswith('_tex.bin'): + Image = arc[key] + if key.startswith('BG_grp/') and key.endswith('_grp.bin'): + group = arc[key] + if key.startswith('BG_unt/'): + if key.endswith('_hd.bin'): + metadata = arc[key] + elif key.endswith('.bin'): + objstrings = arc[key] + + if (Image == None) or (group == None) or (objstrings == None) or (metadata == None): + QtGui.QMessageBox.warning(None, 'Error', 'Error - the necessary files were not found.\n\nNot a valid Koopatlas tileset, sadly.') + return + + dest = RGB4A3Decode(Image) + + self.tileImage = QtGui.QPixmap.fromImage(dest) + + # Makes us some nice Tile Classes! + Xoffset = 4 + Yoffset = 4 + for i in range(512): + Tileset.addTile(self.tileImage.copy(Xoffset,Yoffset,24,24)) + Xoffset += 32 + if Xoffset >= 1024: + Xoffset = 4 + Yoffset += 32 + + # Load Objects + + meta = [] + for i in xrange(len(metadata)/4): + meta.append(struct.unpack_from('>H2B', metadata, i * 4)) + + tilelist = [[]] + upperslope = [0, 0] + lowerslope = [0, 0] + byte = 0 + + for entry in meta: + offset = entry[0] + byte = struct.unpack_from('>B', objstrings, offset)[0] + row = 0 + + while byte != 0xFF: + + if byte == 0xFE: + tilelist.append([]) + + if (upperslope[0] != 0) and (lowerslope[0] == 0): + upperslope[1] = upperslope[1] + 1 + + if lowerslope[0] != 0: + lowerslope[1] = lowerslope[1] + 1 + + offset += 1 + byte = struct.unpack_from('>B', objstrings, offset)[0] + + elif (byte & 0x80): + + if upperslope[0] == 0: + upperslope[0] = byte + else: + lowerslope[0] = byte + + offset += 1 + byte = struct.unpack_from('>B', objstrings, offset)[0] + + else: + untile = struct.unpack_from('>BH', objstrings, offset) + retile = (untile[0], untile[1], 0) + + tilelist[len(tilelist)-1].append(retile) + + offset += 3 + byte = struct.unpack_from('>B', objstrings, offset)[0] + + tilelist.pop() + + if (upperslope[0] & 0x80) and (upperslope[0] & 0x2): + for i in range(lowerslope[1]): + pop = tilelist.pop() + tilelist.insert(0, pop) + + Tileset.addObject(entry[2], entry[1], upperslope, lowerslope, tilelist) + + tilelist = [[]] + upperslope = [0, 0] + lowerslope = [0, 0] + + self.setuptile() + SetupObjectModel(self.objmodel, Tileset.objects, Tileset.tiles, self.treeki, group) + + self.tileWidget.tiles.updateList() + + self.name = path + + + def openImage(self): + '''Opens an Image from png, and creates a new tileset from it.''' + + path = QtGui.QFileDialog.getOpenFileName(self, "Open Image", '', + "Image Files (*.png)") + + if path: + newImage = QtGui.QPixmap() + self.tileImage = newImage + + if not newImage.load(path): + QtGui.QMessageBox.warning(self, "Open Image", + "The image file could not be loaded.", + QtGui.QMessageBox.Cancel) + return + + if ((newImage.width() == 768) & (newImage.height() == 384)): + x = 0 + y = 0 + for i in range(512): + Tileset.tiles[i].image = self.tileImage.copy(x*24,y*24,24,24) + x += 1 + if (x * 24) >= 768: + y += 1 + x = 0 + + else: + QtGui.QMessageBox.warning(self, "Open Image", + "The image was not the proper dimensions." + "Please resize the image to 768x384 pixels.", + QtGui.QMessageBox.Cancel) + return + + + self.setuptile() + + + def saveImage(self): + + fn = QtGui.QFileDialog.getSaveFileName(self, 'Choose a new filename', '', '.png (*.png)') + if fn == '': return + + tex = QtGui.QPixmap(768, 384) + tex.fill(QtCore.Qt.transparent) + painter = QtGui.QPainter(tex) + + Xoffset = 0 + Yoffset = 0 + + for tile in Tileset.tiles: + painter.drawPixmap(Xoffset, Yoffset, tile.image) + Xoffset += 24 + if Xoffset >= 768: + Xoffset = 0 + Yoffset += 24 + + painter.end() + + tex.save(fn) + + def saveTileset(self): + if self.name == '': + self.saveTilesetAs() + return + + + outdata = self.saving(os.path.basename(unicode(self.name))[:-4]) + + fn = unicode(self.name) + f = open(fn, 'wb') + f.write(outdata) + f.close() + + reply = QtGui.QMessageBox.information(self, "Save Complete", "Tileset saved as {0}.".format(os.path.basename(unicode(self.name))[:-4])) + + def saveTilesetAs(self): + + fn = QtGui.QFileDialog.getSaveFileName(self, 'Choose a new filename', '', '.arc (*.arc)') + if fn == '': return + + self.name = fn + self.setWindowTitle(os.path.basename(unicode(fn))) + + outdata = self.saving(os.path.basename(unicode(fn))[:-4]) + f = open(fn, 'wb') + f.write(outdata) + f.close() + + reply = QtGui.QMessageBox.information(self, "Save Complete", "Tileset saved as {0}.".format(os.path.basename(unicode(self.name))[:-4])) + + + def saving(self, name): + + # Prepare tiles, objects, object metadata, and textures and stuff into buffers. + + textureBuffer = self.PackTexture() + objectBuffers = self.PackObjects() + objectBuffer = objectBuffers[0] + objectMetaBuffer = objectBuffers[1] + groupBuffer = self.PackGroups() + + + # Make an arc and pack up the files! + arc = archive.U8() + arc['BG_tex'] = None + arc['BG_tex/{0}_tex.bin'.format(name)] = textureBuffer + + arc['BG_unt'] = None + arc['BG_unt/{0}.bin'.format(name)] = objectBuffer + arc['BG_unt/{0}_hd.bin'.format(name)] = objectMetaBuffer + + arc['BG_grp'] = None + arc['BG_grp/{0}_grp.bin'.format(name)] = groupBuffer + + return arc._dump() + + + def PackTexture(self): + + tex = QtGui.QImage(1024, 512, QtGui.QImage.Format_ARGB32) + tex.fill(QtCore.Qt.transparent) + painter = QtGui.QPainter(tex) + + Xoffset = 0 + Yoffset = 0 + + for tile in Tileset.tiles: + minitex = QtGui.QImage(32, 32, QtGui.QImage.Format_ARGB32) + minitex.fill(QtCore.Qt.transparent) + minipainter = QtGui.QPainter(minitex) + + minipainter.drawPixmap(4, 4, tile.image) + minipainter.end() + + # Read colours and DESTROY THEM (or copy them to the edges, w/e) + for i in xrange(4,28): + + # Top Clamp + colour = minitex.pixel(i, 4) + for p in xrange(0,4): + minitex.setPixel(i, p, colour) + + # Left Clamp + colour = minitex.pixel(4, i) + for p in xrange(0,4): + minitex.setPixel(p, i, colour) + + # Right Clamp + colour = minitex.pixel(i, 27) + for p in xrange(27,31): + minitex.setPixel(i, p, colour) + + # Bottom Clamp + colour = minitex.pixel(27, i) + for p in xrange(27,31): + minitex.setPixel(p, i, colour) + + # UpperLeft Corner Clamp + colour = minitex.pixel(4, 4) + for x in xrange(0,4): + for y in xrange(0,4): + minitex.setPixel(x, y, colour) + + # UpperRight Corner Clamp + colour = minitex.pixel(27, 4) + for x in xrange(27,31): + for y in xrange(0,4): + minitex.setPixel(x, y, colour) + + # LowerLeft Corner Clamp + colour = minitex.pixel(4, 27) + for x in xrange(0,4): + for y in xrange(27,31): + minitex.setPixel(x, y, colour) + + # LowerRight Corner Clamp + colour = minitex.pixel(27, 27) + for x in xrange(27,31): + for y in xrange(27,31): + minitex.setPixel(x, y, colour) + + + painter.drawImage(Xoffset, Yoffset, minitex) + + Xoffset += 32 + + if Xoffset >= 1024: + Xoffset = 0 + Yoffset += 32 + + painter.end() + + dest = RGB4A3Encode(tex) + + return dest + + + + def PackObjects(self): + objectStrings = [] + + o = 0 + for object in Tileset.objects: + + + # Slopes + if object.upperslope[0] != 0: + + # Reverse Slopes + if object.upperslope[0] & 0x2: + a = struct.pack('>B', object.upperslope[0]) + + if object.height == 1: + iterationsA = 0 + iterationsB = 1 + else: + iterationsA = object.upperslope[1] + iterationsB = object.lowerslope[1] + object.upperslope[1] + + for row in xrange(iterationsA, iterationsB): + for tile in object.tiles[row]: + a = a + struct.pack('>BH', tile[0], tile[1]) + a = a + '\xfe' + + if object.height > 1: + a = a + struct.pack('>B', object.lowerslope[0]) + + for row in xrange(0, object.upperslope[1]): + for tile in object.tiles[row]: + a = a + struct.pack('>BH', tile[0], tile[1]) + a = a + '\xfe' + + a = a + '\xff' + + objectStrings.append(a) + + + # Regular Slopes + else: + a = struct.pack('>B', object.upperslope[0]) + + for row in xrange(0, object.upperslope[1]): + for tile in object.tiles[row]: + a = a + struct.pack('>BH', tile[0], tile[1]) + a = a + '\xfe' + + if object.height > 1: + a = a + struct.pack('>B', object.lowerslope[0]) + + for row in xrange(object.upperslope[1], object.height): + for tile in object.tiles[row]: + a = a + struct.pack('>BH', tile[0], tile[1]) + a = a + '\xfe' + + a = a + '\xff' + + objectStrings.append(a) + + + # Not slopes! + else: + a = '' + + for tilerow in object.tiles: + for tile in tilerow: + a = a + struct.pack('>BH', tile[0], tile[1]) + + a = a + '\xfe' + + a = a + '\xff' + + objectStrings.append(a) + + o += 1 + + Objbuffer = '' + Metabuffer = '' + i = 0 + for a in objectStrings: + Metabuffer = Metabuffer + struct.pack('>H2B', len(Objbuffer), Tileset.objects[i].width, Tileset.objects[i].height) + Objbuffer = Objbuffer + a + + i += 1 + + return (Objbuffer, Metabuffer) + + + + def PackGroups(self): + + groupList = [] + + # Walk through all top level items + for kiddy in xrange(self.treeki.topLevelItemCount()): + groupList.append(self.walkTree(self.treeki.topLevelItem(kiddy))) + + return cPickle.dumps(groupList) + + + def walkTree(self, treeItem): + + # If item has kids, walk through each kid. If not, just add the string. + + name = str(treeItem.text(0)) + + alist = [] + + if treeItem.childCount() > 0: + + for kiddy in xrange(treeItem.childCount()): + alist.append(self.walkTree(treeItem.child(kiddy))) + + return (name, alist) + + else: + return name + + + def setupMenus(self): + fileMenu = self.menuBar().addMenu("&File") + + pixmap = QtGui.QPixmap(60,60) + pixmap.fill(QtCore.Qt.black) + icon = QtGui.QIcon(pixmap) + + self.action = fileMenu.addAction(icon, "New", self.newTileset, QtGui.QKeySequence.New) + fileMenu.addAction("Open...", self.openTileset, QtGui.QKeySequence.Open) + fileMenu.addAction("Import Image...", self.openImage, QtGui.QKeySequence('Ctrl+I')) + fileMenu.addAction("Export Image...", self.saveImage, QtGui.QKeySequence('Ctrl+E')) + fileMenu.addAction("Save", self.saveTileset, QtGui.QKeySequence.Save) + fileMenu.addAction("Save as...", self.saveTilesetAs, QtGui.QKeySequence.SaveAs) + fileMenu.addAction("Quit", self.close, QtGui.QKeySequence('Ctrl-Q')) + + taskMenu = self.menuBar().addMenu("&Tasks") + + taskMenu.addAction("Clear Object Data", Tileset.clearObjects, QtGui.QKeySequence('Ctrl+Alt+Backspace')) + + + def TriggerNewGroup(self): + + a = QtGui.QTreeWidgetItem(self.treeki) + a.setText(0, 'Double Click to Rename') + a.setFlags(QtCore.Qt.ItemFlags(0x2F)) + a.setChildIndicatorPolicy(QtGui.QTreeWidgetItem.ShowIndicator) + a.setExpanded(True) + + + def TriggerDelGroup(self): + + treecko = self.treeki.currentItem() + if str(treecko.text(0)).find("Object"): + eggs = treecko.takeChildren() + + self.treeki.addTopLevelItems(eggs) + + index = window.treeki.indexFromItem(treecko, 0) + realx = index.row() + + if treecko.parent(): + y = treecko.parent().takeChild(realx) + else: + y = self.treeki.takeTopLevelItem(realx) + + del y + + + + def setupWidgets(self): + frame = QtGui.QFrame() + frameLayout = QtGui.QHBoxLayout(frame) + + # Displays the tiles + self.tileDisplay = displayWidget() + + # Sets up the model for the tile pieces + self.model = PiecesModel(self) + self.tileDisplay.setModel(self.model) + + # Object List + self.objectList = objectList() + self.objmodel = QtGui.QStandardItemModel() + self.objectList.setModel(self.objmodel) + + self.tileWidget = tileOverlord() + + # Vertical Container A + self.container = QtGui.QWidget() + layout = QtGui.QVBoxLayout() + layout.addWidget(self.tileDisplay) + layout.addWidget(self.tileWidget) + self.container.setLayout(layout) + + + # Create the Group Tree + self.treeki = QtGui.QTreeWidget() + self.treeki.setSelectionMode(QtGui.QAbstractItemView.ExtendedSelection) + self.treeki.setDragEnabled(True) + self.treeki.setDragDropMode(QtGui.QAbstractItemView.InternalMove) + self.treeki.setAcceptDrops(True) + self.treeki.setDropIndicatorShown(True) + self.treeki.setEditTriggers(QtGui.QAbstractItemView.DoubleClicked) + self.treeki.setColumnCount(2) + self.treeki.setColumnWidth(0, 200) + + self.treeki.setColumnWidth(1, 40) + + + # Vertical Container B + self.treeBario = QtGui.QWidget() + tlayout = QtGui.QVBoxLayout() + tlayout.addWidget(self.treeki) + + self.groupbar = QtGui.QToolBar() + + self.newGroup = QtGui.QAction('New Group', self.groupbar) + self.newGroup.triggered.connect(self.TriggerNewGroup) + self.newGroup.setShortcut(QtGui.QKeySequence('Ctrl+Shift+N')) + + self.delGroup = QtGui.QAction('Delete Group', self.groupbar) + self.delGroup.triggered.connect(self.TriggerDelGroup) + self.delGroup.setShortcut(QtGui.QKeySequence('Ctrl+Shift+Del')) + + self.groupbar.addAction(self.newGroup) + self.groupbar.addAction(self.delGroup) + + self.groupbar.setFloatable(False) + + tlayout.addWidget(self.groupbar) + self.treeBario.setLayout(tlayout) + + + # Creates the Tab Widget for behaviours and objects + self.tabWidget = QtGui.QTabWidget() + + # Sets the Tabs + self.tabWidget.addTab(self.objectList, 'Object List') + self.tabWidget.addTab(self.treeBario, 'Object Groups') + + + + # Connections do things! + self.objectList.clicked.connect(self.tileWidget.setObject) + self.treeki.itemClicked.connect(connectToTileWidget) + + + SetupObjectModel(self.objmodel, Tileset.objects, Tileset.tiles, self.treeki, None) + + + frameLayout.addWidget(self.container) + frameLayout.addWidget(self.tabWidget) + + + self.setCentralWidget(frame) + + + + +############################################################################################# +####################################### Main Function ####################################### + + +if __name__ == '__main__': + + import sys + + app = QtGui.QApplication(sys.argv) + window = MainWindow() + window.show() + sys.exit(app.exec_()) + app.deleteLater() \ No newline at end of file -- cgit v1.2.3