def cellsInRegion(list, r): cells = QVector() for tilelayer in list: for rect in r.rects(): for x in range(rect.left(), rect.right() + 1): for y in range(rect.top(), rect.bottom() + 1): cell = tilelayer.cellAt(x, y) if (not cells.contains(cell)): cells.append(cell) return cells
def cellsInRegion(list, r): cells = QVector() for tilelayer in list: for rect in r.rects(): for x in range(rect.left(), rect.right()+1): for y in range(rect.top(), rect.bottom()+1): cell = tilelayer.cellAt(x, y) if (not cells.contains(cell)): cells.append(cell) return cells
class TileStampManager(QObject): setStamp = pyqtSignal(TileStamp) def __init__(self, toolManager, parent=None): super().__init__(parent) self.mStampsByName = QMap() self.mQuickStamps = QVector() for i in range(TileStampManager.quickStampKeys().__len__()): self.mQuickStamps.append(0) self.mTileStampModel = TileStampModel(self) self.mToolManager = toolManager prefs = preferences.Preferences.instance() prefs.stampsDirectoryChanged.connect(self.stampsDirectoryChanged) self.mTileStampModel.stampAdded.connect(self.stampAdded) self.mTileStampModel.stampRenamed.connect(self.stampRenamed) self.mTileStampModel.stampChanged.connect(self.saveStamp) self.mTileStampModel.stampRemoved.connect(self.deleteStamp) self.loadStamps() def __del__(self): # needs to be over here where the TileStamp type is complete pass ## # Returns the keys used for quickly accessible tile stamps. # Note: To store a tile layer <Ctrl> is added. The given keys will work # for recalling the stored values. ## def quickStampKeys(): keys = [ Qt.Key_1, Qt.Key_2, Qt.Key_3, Qt.Key_4, Qt.Key_5, Qt.Key_6, Qt.Key_7, Qt.Key_8, Qt.Key_9 ] return keys def tileStampModel(self): return self.mTileStampModel def createStamp(self): stamp = self.tampFromContext(self.mToolManager.selectedTool()) if (not stamp.isEmpty()): self.mTileStampModel.addStamp(stamp) return stamp def addVariation(self, targetStamp): stamp = stampFromContext(self.mToolManager.selectedTool()) if (stamp.isEmpty()): return if (stamp == targetStamp): # avoid easy mistake of adding duplicates return for variation in stamp.variations(): self.mTileStampModel.addVariation(targetStamp, variation) def selectQuickStamp(self, index): stamp = self.mQuickStamps.at(index) if (not stamp.isEmpty()): self.setStamp.emit(stamp) def createQuickStamp(self, index): stamp = stampFromContext(self.mToolManager.selectedTool()) if (stamp.isEmpty()): return self.setQuickStamp(index, stamp) def extendQuickStamp(self, index): quickStamp = self.mQuickStamps[index] if (quickStamp.isEmpty()): self.createQuickStamp(index) else: self.addVariation(quickStamp) def stampsDirectoryChanged(self): # erase current stamps self.mQuickStamps.fill(TileStamp()) self.mStampsByName.clear() self.mTileStampModel.clear() self.loadStamps() def eraseQuickStamp(self, index): stamp = self.mQuickStamps.at(index) if (not stamp.isEmpty()): self.mQuickStamps[index] = TileStamp() if (not self.mQuickStamps.contains(stamp)): self.mTileStampModel.removeStamp(stamp) def setQuickStamp(self, index, stamp): stamp.setQuickStampIndex(index) # make sure existing quickstamp is removed from stamp model self.eraseQuickStamp(index) self.mTileStampModel.addStamp(stamp) self.mQuickStamps[index] = stamp def loadStamps(self): prefs = preferences.Preferences.instance() stampsDirectory = prefs.stampsDirectory() stampsDir = QDir(stampsDirectory) iterator = QDirIterator(stampsDirectory, ["*.stamp"], QDir.Files | QDir.Readable) while (iterator.hasNext()): stampFileName = iterator.next() stampFile = QFile(stampFileName) if (not stampFile.open(QIODevice.ReadOnly)): continue data = stampFile.readAll() document = QJsonDocument.fromBinaryData(data) if (document.isNull()): # document not valid binary data, maybe it's an JSON text file error = QJsonParseError() document = QJsonDocument.fromJson(data, error) if (error.error != QJsonParseError.NoError): qDebug("Failed to parse stamp file:" + error.errorString()) continue stamp = TileStamp.fromJson(document.object(), stampsDir) if (stamp.isEmpty()): continue stamp.setFileName(iterator.fileInfo().fileName()) self.mTileStampModel.addStamp(stamp) index = stamp.quickStampIndex() if (index >= 0 and index < self.mQuickStamps.size()): self.mQuickStamps[index] = stamp def stampAdded(self, stamp): if (stamp.name().isEmpty() or self.mStampsByName.contains(stamp.name())): # pick the first available stamp name name = QString() index = self.mTileStampModel.stamps().size() while (self.mStampsByName.contains(name)): name = str(index) index += 1 stamp.setName(name) self.mStampsByName.insert(stamp.name(), stamp) if (stamp.fileName().isEmpty()): stamp.setFileName(findStampFileName(stamp.name())) self.saveStamp(stamp) def stampRenamed(self, stamp): existingName = self.mStampsByName.key(stamp) self.mStampsByName.remove(existingName) self.mStampsByName.insert(stamp.name(), stamp) existingFileName = stamp.fileName() newFileName = findStampFileName(stamp.name(), existingFileName) if (existingFileName != newFileName): if (QFile.rename(stampFilePath(existingFileName), stampFilePath(newFileName))): stamp.setFileName(newFileName) def saveStamp(self, stamp): # make sure we have a stamps directory prefs = preferences.Preferences.instance() stampsDirectory = prefs.stampsDirectory() stampsDir = QDir(stampsDirectory) if (not stampsDir.exists() and not stampsDir.mkpath(".")): qDebug("Failed to create stamps directory" + stampsDirectory) return filePath = stampsDir.filePath(stamp.fileName()) file = QSaveFile(filePath) if (not file.open(QIODevice.WriteOnly)): qDebug("Failed to open stamp file for writing" + filePath) return stampJson = stamp.toJson(QFileInfo(filePath).dir()) file.write(QJsonDocument(stampJson).toJson(QJsonDocument.Compact)) if (not file.commit()): qDebug() << "Failed to write stamp" << filePath def deleteStamp(self, stamp): self.mStampsByName.remove(stamp.name()) QFile.remove(stampFilePath(stamp.fileName()))
def compareLayerTo(setLayer, listYes, listNo, ruleRegion, offset): if (listYes.isEmpty() and listNo.isEmpty()): return False cells = QVector() if (listYes.isEmpty()): cells = cellsInRegion(listNo, ruleRegion) if (listNo.isEmpty()): cells = cellsInRegion(listYes, ruleRegion) for rect in ruleRegion.rects(): for x in range(rect.left(), rect.right() + 1): for y in range(rect.top(), rect.bottom() + 1): # this is only used in the case where only one list has layers # it is needed for the exception mentioned above ruleDefinedListYes = False matchListYes = False matchListNo = False if (not setLayer.contains(x + offset.x(), y + offset.y())): return False c1 = setLayer.cellAt(x + offset.x(), y + offset.y()) # ruleDefined will be set when there is a tile in at least # one layer. if there is a tile in at least one layer, only # the given tiles in the different listYes layers are valid. # if there is given no tile at all in the listYes layers, # consider all tiles valid. for comparedTileLayer in listYes: if (not comparedTileLayer.contains(x, y)): return False c2 = comparedTileLayer.cellAt(x, y) if (not c2.isEmpty()): ruleDefinedListYes = True if (not c2.isEmpty() and c1 == c2): matchListYes = True for comparedTileLayer in listNo: if (not comparedTileLayer.contains(x, y)): return False c2 = comparedTileLayer.cellAt(x, y) if (not c2.isEmpty() and c1 == c2): matchListNo = True # when there are only layers in the listNo # check only if these layers are unmatched # no need to check explicitly the exception in this case. if (listYes.isEmpty()): if (matchListNo): return False else: continue # when there are only layers in the listYes # check if these layers are matched, or if the exception works if (listNo.isEmpty()): if (matchListYes): continue if (not ruleDefinedListYes and not cells.contains(c1)): continue return False # there are layers in both lists: # no need to consider ruleDefinedListXXX if ((matchListYes or not ruleDefinedListYes) and not matchListNo): continue else: return False return True
class TileStampManager(QObject): setStamp = pyqtSignal(TileStamp) def __init__(self, toolManager, parent = None): super().__init__(parent) self.mStampsByName = QMap() self.mQuickStamps = QVector() for i in range(TileStampManager.quickStampKeys().__len__()): self.mQuickStamps.append(0) self.mTileStampModel = TileStampModel(self) self.mToolManager = toolManager prefs = preferences.Preferences.instance() prefs.stampsDirectoryChanged.connect(self.stampsDirectoryChanged) self.mTileStampModel.stampAdded.connect(self.stampAdded) self.mTileStampModel.stampRenamed.connect(self.stampRenamed) self.mTileStampModel.stampChanged.connect(self.saveStamp) self.mTileStampModel.stampRemoved.connect(self.deleteStamp) self.loadStamps() def __del__(self): # needs to be over here where the TileStamp type is complete pass ## # Returns the keys used for quickly accessible tile stamps. # Note: To store a tile layer <Ctrl> is added. The given keys will work # for recalling the stored values. ## def quickStampKeys(): keys=[Qt.Key_1, Qt.Key_2, Qt.Key_3, Qt.Key_4, Qt.Key_5, Qt.Key_6, Qt.Key_7, Qt.Key_8, Qt.Key_9] return keys def tileStampModel(self): return self.mTileStampModel def createStamp(self): stamp = self.tampFromContext(self.mToolManager.selectedTool()) if (not stamp.isEmpty()): self.mTileStampModel.addStamp(stamp) return stamp def addVariation(self, targetStamp): stamp = stampFromContext(self.mToolManager.selectedTool()) if (stamp.isEmpty()): return if (stamp == targetStamp): # avoid easy mistake of adding duplicates return for variation in stamp.variations(): self.mTileStampModel.addVariation(targetStamp, variation) def selectQuickStamp(self, index): stamp = self.mQuickStamps.at(index) if (not stamp.isEmpty()): self.setStamp.emit(stamp) def createQuickStamp(self, index): stamp = stampFromContext(self.mToolManager.selectedTool()) if (stamp.isEmpty()): return self.setQuickStamp(index, stamp) def extendQuickStamp(self, index): quickStamp = self.mQuickStamps[index] if (quickStamp.isEmpty()): self.createQuickStamp(index) else: self.addVariation(quickStamp) def stampsDirectoryChanged(self): # erase current stamps self.mQuickStamps.fill(TileStamp()) self.mStampsByName.clear() self.mTileStampModel.clear() self.loadStamps() def eraseQuickStamp(self, index): stamp = self.mQuickStamps.at(index) if (not stamp.isEmpty()): self.mQuickStamps[index] = TileStamp() if (not self.mQuickStamps.contains(stamp)): self.mTileStampModel.removeStamp(stamp) def setQuickStamp(self, index, stamp): stamp.setQuickStampIndex(index) # make sure existing quickstamp is removed from stamp model self.eraseQuickStamp(index) self.mTileStampModel.addStamp(stamp) self.mQuickStamps[index] = stamp def loadStamps(self): prefs = preferences.Preferences.instance() stampsDirectory = prefs.stampsDirectory() stampsDir = QDir(stampsDirectory) iterator = QDirIterator(stampsDirectory, ["*.stamp"], QDir.Files | QDir.Readable) while (iterator.hasNext()): stampFileName = iterator.next() stampFile = QFile(stampFileName) if (not stampFile.open(QIODevice.ReadOnly)): continue data = stampFile.readAll() document = QJsonDocument.fromBinaryData(data) if (document.isNull()): # document not valid binary data, maybe it's an JSON text file error = QJsonParseError() document = QJsonDocument.fromJson(data, error) if (error.error != QJsonParseError.NoError): qDebug("Failed to parse stamp file:" + error.errorString()) continue stamp = TileStamp.fromJson(document.object(), stampsDir) if (stamp.isEmpty()): continue stamp.setFileName(iterator.fileInfo().fileName()) self.mTileStampModel.addStamp(stamp) index = stamp.quickStampIndex() if (index >= 0 and index < self.mQuickStamps.size()): self.mQuickStamps[index] = stamp def stampAdded(self, stamp): if (stamp.name().isEmpty() or self.mStampsByName.contains(stamp.name())): # pick the first available stamp name name = QString() index = self.mTileStampModel.stamps().size() while(self.mStampsByName.contains(name)): name = str(index) index += 1 stamp.setName(name) self.mStampsByName.insert(stamp.name(), stamp) if (stamp.fileName().isEmpty()): stamp.setFileName(findStampFileName(stamp.name())) self.saveStamp(stamp) def stampRenamed(self, stamp): existingName = self.mStampsByName.key(stamp) self.mStampsByName.remove(existingName) self.mStampsByName.insert(stamp.name(), stamp) existingFileName = stamp.fileName() newFileName = findStampFileName(stamp.name(), existingFileName) if (existingFileName != newFileName): if (QFile.rename(stampFilePath(existingFileName), stampFilePath(newFileName))): stamp.setFileName(newFileName) def saveStamp(self, stamp): # make sure we have a stamps directory prefs = preferences.Preferences.instance() stampsDirectory = prefs.stampsDirectory() stampsDir = QDir(stampsDirectory) if (not stampsDir.exists() and not stampsDir.mkpath(".")): qDebug("Failed to create stamps directory" + stampsDirectory) return filePath = stampsDir.filePath(stamp.fileName()) file = QSaveFile(filePath) if (not file.open(QIODevice.WriteOnly)): qDebug("Failed to open stamp file for writing" + filePath) return stampJson = stamp.toJson(QFileInfo(filePath).dir()) file.write(QJsonDocument(stampJson).toJson(QJsonDocument.Compact)) if (not file.commit()): qDebug() << "Failed to write stamp" << filePath def deleteStamp(self, stamp): self.mStampsByName.remove(stamp.name()) QFile.remove(stampFilePath(stamp.fileName()))
def compareLayerTo(setLayer, listYes, listNo, ruleRegion, offset): if (listYes.isEmpty() and listNo.isEmpty()): return False cells = QVector() if (listYes.isEmpty()): cells = cellsInRegion(listNo, ruleRegion) if (listNo.isEmpty()): cells = cellsInRegion(listYes, ruleRegion) for rect in ruleRegion.rects(): for x in range(rect.left(), rect.right()+1): for y in range(rect.top(), rect.bottom()+1): # this is only used in the case where only one list has layers # it is needed for the exception mentioned above ruleDefinedListYes = False matchListYes = False matchListNo = False if (not setLayer.contains(x + offset.x(), y + offset.y())): return False c1 = setLayer.cellAt(x + offset.x(), y + offset.y()) # ruleDefined will be set when there is a tile in at least # one layer. if there is a tile in at least one layer, only # the given tiles in the different listYes layers are valid. # if there is given no tile at all in the listYes layers, # consider all tiles valid. for comparedTileLayer in listYes: if (not comparedTileLayer.contains(x, y)): return False c2 = comparedTileLayer.cellAt(x, y) if (not c2.isEmpty()): ruleDefinedListYes = True if (not c2.isEmpty() and c1 == c2): matchListYes = True for comparedTileLayer in listNo: if (not comparedTileLayer.contains(x, y)): return False c2 = comparedTileLayer.cellAt(x, y) if (not c2.isEmpty() and c1 == c2): matchListNo = True # when there are only layers in the listNo # check only if these layers are unmatched # no need to check explicitly the exception in this case. if (listYes.isEmpty()): if (matchListNo): return False else: continue # when there are only layers in the listYes # check if these layers are matched, or if the exception works if (listNo.isEmpty()): if (matchListYes): continue if (not ruleDefinedListYes and not cells.contains(c1)): continue return False # there are layers in both lists: # no need to consider ruleDefinedListXXX if ((matchListYes or not ruleDefinedListYes) and not matchListNo): continue else: return False return True