def Print(self, p: QPainter, m: QMargins, o: int = 0): if self.Report.TotalPagesCalculated is False or self.Visible is False: return r1, r2 = self.Report.onBeforePrint( self.Report._CurrentCopys, self.Section, self.Section._GetCurrentPrintRecord(), self) if r1: return txt = r2 if not (r2 is None) else self.getPrintText() rect = self._NewRect(m, o) # 填充颜色 if self.FillColor: p.fillRect(rect, self.FillColor) # 绘制边框及文本 if self.Bolder or self.FillColor: p.drawRect(rect) rect = rect - QMargins(1, 1, 1, 1) p.setFont(self.Font) if self.Transform: # 文本旋转的情况 FontHeight = QFontMetrics(self.Font).height() p.save() p.translate(self.Rect.x() + m.left() + FontHeight, self.Rect.y() + m.top() + o) # 第一个参数为距离 p.rotate(90) p.drawText(QRect(0, 0, self.Rect.width(), self.Rect.height()), self.AlignmentFlag, txt) # 第一个参数Left为调整后距离页面顶端的距离 p.restore() else: # 文字不旋转的情况 fm = p.fontMetrics() # 处理长文本省略 if self.AutoEllipsis: elidedText = fm.elidedText(txt, Qt.ElideRight, rect.width()) # 处理长文本自动缩小字体 if self.AutoShrinkFont: self.__AutoShrinkFont(p, rect, txt) if self.AutoEllipsis: p.drawText(rect, self.AlignmentFlag, elidedText) else: p.drawText(rect, self.AlignmentFlag, txt)
class ProblemArea(ScrollArea): # area similar to excel sheet to display problem cells widget: QWidget layout: QGridLayout def __init__(self, controller, model): super().__init__() self.controller = controller self.model = model self._init_UI() self._connect_scroll_bars() def _init_UI(self): self.panels = self.model.panels self.margins = QMargins(self.panels.left_margin, self.panels.top_margin, 0, 0) self.setViewportMargins(self.margins) self.setWidgetResizable(True) self.header = self.panels.sector_view self.left_panel = self.panels.grade_view self.info_panel = self.panels.info_view self.header.setParent(self) self.left_panel.setParent(self) self.info_panel.setParent(self) self.widget = QWidget() self.layout = QGridLayout() self.layout.setSpacing(2) self.layout.setContentsMargins(0, 0, 0, 0) self._set_cell_data() self.widget.setLayout(self.layout) self.setWidget(self.widget) def _connect_scroll_bars(self): self.horizontalScrollBar().valueChanged.connect( lambda x: self.header.horizontalScrollBar().setValue(x)) self.header.horizontalScrollBar().valueChanged.connect( lambda x: self.horizontalScrollBar().setValue(x)) self.verticalScrollBar().valueChanged.connect( lambda x: self.left_panel.verticalScrollBar().setValue(x)) self.left_panel.verticalScrollBar().valueChanged.connect( lambda x: self.verticalScrollBar().setValue(x)) def update_UI(self): self._remove_bottom_rows() self._remove_right_cols() self._set_cell_data() def _remove_bottom_rows(self) -> None: current_rows = self.layout.rowCount() new_rows = self.model.changes.n_row if new_rows < current_rows: for row in reversed(range(current_rows)[new_rows:]): for col in reversed(range(self.layout.columnCount())): self._remove_cell(row, col) def _remove_cell(self, row: int, col: int) -> None: item = self.layout.itemAtPosition(row, col) if not item is None: cell = self.layout.itemAtPosition(row, col).widget() self.layout.removeWidget(cell) cell.setParent(None) def _remove_right_cols(self) -> None: current_cols = self.layout.columnCount() new_cols = self.model.changes.n_col if new_cols < current_cols: for row in reversed(range(self.layout.rowCount())): for col in reversed(range(current_cols)[new_cols:]): self._remove_cell(row, col) def _set_cell_data(self): for cell_data in self.model.changes.cells: if self.layout.itemAtPosition(cell_data.row, cell_data.col) is None: self._generate_cell(cell_data, 96, 48) else: cell = self.layout.itemAtPosition(cell_data.row, cell_data.col).widget() cell.set_data(cell_data) def _generate_cell(self, cell_data: ProblemCellData, width: int, height: int): cell = ProblemCell(width, height, cell_data) cell.set_clicked_command(self.controller.on_cell_clicked) self.layout.addWidget(cell, cell_data.row, cell_data.col) def resizeEvent(self, event): rect = self.viewport().geometry() self.header.setGeometry(rect.x(), 0, rect.width(), self.margins.top() - 4) self.left_panel.setGeometry(0, rect.y(), self.margins.left() - 4, rect.height()) QScrollArea.resizeEvent(self, event)
class TileLayer(Layer): ## # Constructor. ## def __init__(self, name, x, y, width, height): super().__init__(Layer.TileLayerType, name, x, y, width, height) self.mMaxTileSize = QSize(0, 0) self.mGrid = QVector() for i in range(width * height): self.mGrid.append(Cell()) self.mOffsetMargins = QMargins() def __iter__(self): return self.mGrid.__iter__() ## # Returns the maximum tile size of this layer. ## def maxTileSize(self): return self.mMaxTileSize ## # Returns the margins that have to be taken into account while drawing # this tile layer. The margins depend on the maximum tile size and the # offset applied to the tiles. ## def drawMargins(self): return QMargins(self.mOffsetMargins.left(), self.mOffsetMargins.top() + self.mMaxTileSize.height(), self.mOffsetMargins.right() + self.mMaxTileSize.width(), self.mOffsetMargins.bottom()) ## # Recomputes the draw margins. Needed after the tile offset of a tileset # has changed for example. # # Generally you want to call Map.recomputeDrawMargins instead. ## def recomputeDrawMargins(self): maxTileSize = QSize(0, 0) offsetMargins = QMargins() i = 0 while(i<self.mGrid.size()): cell = self.mGrid.at(i) tile = cell.tile if tile: size = tile.size() if (cell.flippedAntiDiagonally): size.transpose() offset = tile.offset() maxTileSize = maxSize(size, maxTileSize) offsetMargins = maxMargins(QMargins(-offset.x(), -offset.y(), offset.x(), offset.y()), offsetMargins) i += 1 self.mMaxTileSize = maxTileSize self.mOffsetMargins = offsetMargins if (self.mMap): self.mMap.adjustDrawMargins(self.drawMargins()) ## # Returns whether (x, y) is inside this map layer. ## def contains(self, *args): l = len(args) if l==2: x, y = args return x >= 0 and y >= 0 and x < self.mWidth and y < self.mHeight elif l==1: point = args[0] return self.contains(point.x(), point.y()) ## # Calculates the region of cells in this tile layer for which the given # \a condition returns True. ## def region(self, *args): l = len(args) if l==1: condition = args[0] region = QRegion() for y in range(self.mHeight): for x in range(self.mWidth): if (condition(self.cellAt(x, y))): rangeStart = x x += 1 while(x<=self.mWidth): if (x == self.mWidth or not condition(self.cellAt(x, y))): rangeEnd = x region += QRect(rangeStart + self.mX, y + self.mY, rangeEnd - rangeStart, 1) break x += 1 return region elif l==0: ## # Calculates the region occupied by the tiles of this layer. Similar to # Layer.bounds(), but leaves out the regions without tiles. ## return self.region(lambda cell:not cell.isEmpty()) ## # Returns a read-only reference to the cell at the given coordinates. The # coordinates have to be within this layer. ## def cellAt(self, *args): l = len(args) if l==2: x, y = args return self.mGrid.at(x + y * self.mWidth) elif l==1: point = args[0] return self.cellAt(point.x(), point.y()) ## # Sets the cell at the given coordinates. ## def setCell(self, x, y, cell): if (cell.tile): size = cell.tile.size() if (cell.flippedAntiDiagonally): size.transpose() offset = cell.tile.offset() self.mMaxTileSize = maxSize(size, self.mMaxTileSize) self.mOffsetMargins = maxMargins(QMargins(-offset.x(), -offset.y(), offset.x(), offset.y()), self.mOffsetMargins) if (self.mMap): self.mMap.adjustDrawMargins(self.drawMargins()) self.mGrid[x + y * self.mWidth] = cell ## # Returns a copy of the area specified by the given \a region. The # caller is responsible for the returned tile layer. ## def copy(self, *args): l = len(args) if l==1: region = args[0] if type(region) != QRegion: region = QRegion(region) area = region.intersected(QRect(0, 0, self.width(), self.height())) bounds = region.boundingRect() areaBounds = area.boundingRect() offsetX = max(0, areaBounds.x() - bounds.x()) offsetY = max(0, areaBounds.y() - bounds.y()) copied = TileLayer(QString(), 0, 0, bounds.width(), bounds.height()) for rect in area.rects(): for x in range(rect.left(), rect.right()+1): for y in range(rect.top(), rect.bottom()+1): copied.setCell(x - areaBounds.x() + offsetX, y - areaBounds.y() + offsetY, self.cellAt(x, y)) return copied elif l==4: x, y, width, height = args return self.copy(QRegion(x, y, width, height)) ## # Merges the given \a layer onto this layer at position \a pos. Parts that # fall outside of this layer will be lost and empty tiles in the given # layer will have no effect. ## def merge(self, pos, layer): # Determine the overlapping area area = QRect(pos, QSize(layer.width(), layer.height())) area &= QRect(0, 0, self.width(), self.height()) for y in range(area.top(), area.bottom()+1): for x in range(area.left(), area.right()+1): cell = layer.cellAt(x - pos.x(), y - pos.y()) if (not cell.isEmpty()): self.setCell(x, y, cell) ## # Removes all cells in the specified region. ## def erase(self, area): emptyCell = Cell() for rect in area.rects(): for x in range(rect.left(), rect.right()+1): for y in range(rect.top(), rect.bottom()+1): self.setCell(x, y, emptyCell) ## # Sets the cells starting at the given position to the cells in the given # \a tileLayer. Parts that fall outside of this layer will be ignored. # # When a \a mask is given, only cells that fall within this mask are set. # The mask is applied in local coordinates. ## def setCells(self, x, y, layer, mask = QRegion()): # Determine the overlapping area area = QRegion(QRect(x, y, layer.width(), layer.height())) area &= QRect(0, 0, self.width(), self.height()) if (not mask.isEmpty()): area &= mask for rect in area.rects(): for _x in range(rect.left(), rect.right()+1): for _y in range(rect.top(), rect.bottom()+1): self.setCell(_x, _y, layer.cellAt(_x - x, _y - y)) ## # Flip this tile layer in the given \a direction. Direction must be # horizontal or vertical. This doesn't change the dimensions of the # tile layer. ## def flip(self, direction): newGrid = QVector() for i in range(self.mWidth * self.mHeight): newGrid.append(Cell()) for y in range(self.mHeight): for x in range(self.mWidth): dest = newGrid[x + y * self.mWidth] if (direction == FlipDirection.FlipHorizontally): source = self.cellAt(self.mWidth - x - 1, y) dest = source dest.flippedHorizontally = not source.flippedHorizontally elif (direction == FlipDirection.FlipVertically): source = self.cellAt(x, self.mHeight - y - 1) dest = source dest.flippedVertically = not source.flippedVertically self.mGrid = newGrid ## # Rotate this tile layer by 90 degrees left or right. The tile positions # are rotated within the layer, and the tiles themselves are rotated. The # dimensions of the tile layer are swapped. ## def rotate(self, direction): rotateRightMask = [5, 4, 1, 0, 7, 6, 3, 2] rotateLeftMask = [3, 2, 7, 6, 1, 0, 5, 4] if direction == RotateDirection.RotateRight: rotateMask = rotateRightMask else: rotateMask = rotateLeftMask newWidth = self.mHeight newHeight = self.mWidth newGrid = QVector(newWidth * newHeight) for y in range(self.mHeight): for x in range(self.mWidth): source = self.cellAt(x, y) dest = source mask = (dest.flippedHorizontally << 2) | (dest.flippedVertically << 1) | (dest.flippedAntiDiagonally << 0) mask = rotateMask[mask] dest.flippedHorizontally = (mask & 4) != 0 dest.flippedVertically = (mask & 2) != 0 dest.flippedAntiDiagonally = (mask & 1) != 0 if (direction == RotateDirection.RotateRight): newGrid[x * newWidth + (self.mHeight - y - 1)] = dest else: newGrid[(self.mWidth - x - 1) * newWidth + y] = dest t = self.mMaxTileSize.width() self.mMaxTileSize.setWidth(self.mMaxTileSize.height()) self.mMaxTileSize.setHeight(t) self.mWidth = newWidth self.mHeight = newHeight self.mGrid = newGrid ## # Computes and returns the set of tilesets used by this tile layer. ## def usedTilesets(self): tilesets = QSet() i = 0 while(i<self.mGrid.size()): tile = self.mGrid.at(i).tile if tile: tilesets.insert(tile.tileset()) i += 1 return tilesets ## # Returns whether this tile layer has any cell for which the given # \a condition returns True. ## def hasCell(self, condition): i = 0 for cell in self.mGrid: if (condition(cell)): return True i += 1 return False ## # Returns whether this tile layer is referencing the given tileset. ## def referencesTileset(self, tileset): i = 0 while(i<self.mGrid.size()): tile = self.mGrid.at(i).tile if (tile and tile.tileset() == tileset): return True i += 1 return False ## # Removes all references to the given tileset. This sets all tiles on this # layer that are from the given tileset to null. ## def removeReferencesToTileset(self, tileset): i = 0 while(i<self.mGrid.size()): tile = self.mGrid.at(i).tile if (tile and tile.tileset() == tileset): self.mGrid.replace(i, Cell()) i += 1 ## # Replaces all tiles from \a oldTileset with tiles from \a newTileset. ## def replaceReferencesToTileset(self, oldTileset, newTileset): i = 0 while(i<self.mGrid.size()): tile = self.mGrid.at(i).tile if (tile and tile.tileset() == oldTileset): self.mGrid[i].tile = newTileset.tileAt(tile.id()) i += 1 ## # Resizes this tile layer to \a size, while shifting all tiles by # \a offset. ## def resize(self, size, offset): if (self.size() == size and offset.isNull()): return newGrid = QVector() for i in range(size.width() * size.height()): newGrid.append(Cell()) # Copy over the preserved part startX = max(0, -offset.x()) startY = max(0, -offset.y()) endX = min(self.mWidth, size.width() - offset.x()) endY = min(self.mHeight, size.height() - offset.y()) for y in range(startY, endY): for x in range(startX, endX): index = x + offset.x() + (y + offset.y()) * size.width() newGrid[index] = self.cellAt(x, y) self.mGrid = newGrid self.setSize(size) ## # Offsets the tiles in this layer within \a bounds by \a offset, # and optionally wraps them. # # \sa ObjectGroup.offset() ## def offsetTiles(self, offset, bounds, wrapX, wrapY): newGrid = QVector() for i in range(self.mWidth * self.mHeight): newGrid.append(Cell()) for y in range(self.mHeight): for x in range(self.mWidth): # Skip out of bounds tiles if (not bounds.contains(x, y)): newGrid[x + y * self.mWidth] = self.cellAt(x, y) continue # Get position to pull tile value from oldX = x - offset.x() oldY = y - offset.y() # Wrap x value that will be pulled from if (wrapX and bounds.width() > 0): while oldX < bounds.left(): oldX += bounds.width() while oldX > bounds.right(): oldX -= bounds.width() # Wrap y value that will be pulled from if (wrapY and bounds.height() > 0): while oldY < bounds.top(): oldY += bounds.height() while oldY > bounds.bottom(): oldY -= bounds.height() # Set the new tile if (self.contains(oldX, oldY) and bounds.contains(oldX, oldY)): newGrid[x + y * self.mWidth] = self.cellAt(oldX, oldY) else: newGrid[x + y * self.mWidth] = Cell() self.mGrid = newGrid def canMergeWith(self, other): return other.isTileLayer() def mergedWith(self, other): o = other unitedBounds = self.bounds().united(o.bounds()) offset = self.position() - unitedBounds.topLeft() merged = self.clone() merged.resize(unitedBounds.size(), offset) merged.merge(o.position() - unitedBounds.topLeft(), o) return merged ## # Returns the region where this tile layer and the given tile layer # are different. The relative positions of the layers are taken into # account. The returned region is relative to this tile layer. ## def computeDiffRegion(self, other): ret = QRegion() dx = other.x() - self.mX dy = other.y() - self.mY r = QRect(0, 0, self.width(), self.height()) r &= QRect(dx, dy, other.width(), other.height()) for y in range(r.top(), r.bottom()+1): for x in range(r.left(), r.right()+1): if (self.cellAt(x, y) != other.cellAt(x - dx, y - dy)): rangeStart = x while (x <= r.right() and self.cellAt(x, y) != other.cellAt(x - dx, y - dy)): x += 1 rangeEnd = x ret += QRect(rangeStart, y, rangeEnd - rangeStart, 1) return ret ## # Returns True if all tiles in the layer are empty. ## def isEmpty(self): i = 0 while(i<self.mGrid.size()): if (not self.mGrid.at(i).isEmpty()): return False i += 1 return True ## # Returns a duplicate of this TileLayer. # # \sa Layer.clone() ## def clone(self): return self.initializeClone(TileLayer(self.mName, self.mX, self.mY, self.mWidth, self.mHeight)) def begin(self): return self.mGrid.begin() def end(self): return self.mGrid.end() def initializeClone(self, clone): super().initializeClone(clone) clone.mGrid = self.mGrid clone.mMaxTileSize = self.mMaxTileSize clone.mOffsetMargins = self.mOffsetMargins return clone
class TileLayer(Layer): ## # Constructor. ## def __init__(self, name, x, y, width, height): super().__init__(Layer.TileLayerType, name, x, y, width, height) self.mMaxTileSize = QSize(0, 0) self.mGrid = QVector() for i in range(width * height): self.mGrid.append(Cell()) self.mOffsetMargins = QMargins() def __iter__(self): return self.mGrid.__iter__() ## # Returns the maximum tile size of this layer. ## def maxTileSize(self): return self.mMaxTileSize ## # Returns the margins that have to be taken into account while drawing # this tile layer. The margins depend on the maximum tile size and the # offset applied to the tiles. ## def drawMargins(self): return QMargins( self.mOffsetMargins.left(), self.mOffsetMargins.top() + self.mMaxTileSize.height(), self.mOffsetMargins.right() + self.mMaxTileSize.width(), self.mOffsetMargins.bottom()) ## # Recomputes the draw margins. Needed after the tile offset of a tileset # has changed for example. # # Generally you want to call Map.recomputeDrawMargins instead. ## def recomputeDrawMargins(self): maxTileSize = QSize(0, 0) offsetMargins = QMargins() i = 0 while (i < self.mGrid.size()): cell = self.mGrid.at(i) tile = cell.tile if tile: size = tile.size() if (cell.flippedAntiDiagonally): size.transpose() offset = tile.offset() maxTileSize = maxSize(size, maxTileSize) offsetMargins = maxMargins( QMargins(-offset.x(), -offset.y(), offset.x(), offset.y()), offsetMargins) i += 1 self.mMaxTileSize = maxTileSize self.mOffsetMargins = offsetMargins if (self.mMap): self.mMap.adjustDrawMargins(self.drawMargins()) ## # Returns whether (x, y) is inside this map layer. ## def contains(self, *args): l = len(args) if l == 2: x, y = args return x >= 0 and y >= 0 and x < self.mWidth and y < self.mHeight elif l == 1: point = args[0] return self.contains(point.x(), point.y()) ## # Calculates the region of cells in this tile layer for which the given # \a condition returns True. ## def region(self, *args): l = len(args) if l == 1: condition = args[0] region = QRegion() for y in range(self.mHeight): for x in range(self.mWidth): if (condition(self.cellAt(x, y))): rangeStart = x x += 1 while (x <= self.mWidth): if (x == self.mWidth or not condition(self.cellAt(x, y))): rangeEnd = x region += QRect(rangeStart + self.mX, y + self.mY, rangeEnd - rangeStart, 1) break x += 1 return region elif l == 0: ## # Calculates the region occupied by the tiles of this layer. Similar to # Layer.bounds(), but leaves out the regions without tiles. ## return self.region(lambda cell: not cell.isEmpty()) ## # Returns a read-only reference to the cell at the given coordinates. The # coordinates have to be within this layer. ## def cellAt(self, *args): l = len(args) if l == 2: x, y = args return self.mGrid.at(x + y * self.mWidth) elif l == 1: point = args[0] return self.cellAt(point.x(), point.y()) ## # Sets the cell at the given coordinates. ## def setCell(self, x, y, cell): if (cell.tile): size = cell.tile.size() if (cell.flippedAntiDiagonally): size.transpose() offset = cell.tile.offset() self.mMaxTileSize = maxSize(size, self.mMaxTileSize) self.mOffsetMargins = maxMargins( QMargins(-offset.x(), -offset.y(), offset.x(), offset.y()), self.mOffsetMargins) if (self.mMap): self.mMap.adjustDrawMargins(self.drawMargins()) self.mGrid[x + y * self.mWidth] = cell ## # Returns a copy of the area specified by the given \a region. The # caller is responsible for the returned tile layer. ## def copy(self, *args): l = len(args) if l == 1: region = args[0] if type(region) != QRegion: region = QRegion(region) area = region.intersected(QRect(0, 0, self.width(), self.height())) bounds = region.boundingRect() areaBounds = area.boundingRect() offsetX = max(0, areaBounds.x() - bounds.x()) offsetY = max(0, areaBounds.y() - bounds.y()) copied = TileLayer(QString(), 0, 0, bounds.width(), bounds.height()) for rect in area.rects(): for x in range(rect.left(), rect.right() + 1): for y in range(rect.top(), rect.bottom() + 1): copied.setCell(x - areaBounds.x() + offsetX, y - areaBounds.y() + offsetY, self.cellAt(x, y)) return copied elif l == 4: x, y, width, height = args return self.copy(QRegion(x, y, width, height)) ## # Merges the given \a layer onto this layer at position \a pos. Parts that # fall outside of this layer will be lost and empty tiles in the given # layer will have no effect. ## def merge(self, pos, layer): # Determine the overlapping area area = QRect(pos, QSize(layer.width(), layer.height())) area &= QRect(0, 0, self.width(), self.height()) for y in range(area.top(), area.bottom() + 1): for x in range(area.left(), area.right() + 1): cell = layer.cellAt(x - pos.x(), y - pos.y()) if (not cell.isEmpty()): self.setCell(x, y, cell) ## # Removes all cells in the specified region. ## def erase(self, area): emptyCell = Cell() for rect in area.rects(): for x in range(rect.left(), rect.right() + 1): for y in range(rect.top(), rect.bottom() + 1): self.setCell(x, y, emptyCell) ## # Sets the cells starting at the given position to the cells in the given # \a tileLayer. Parts that fall outside of this layer will be ignored. # # When a \a mask is given, only cells that fall within this mask are set. # The mask is applied in local coordinates. ## def setCells(self, x, y, layer, mask=QRegion()): # Determine the overlapping area area = QRegion(QRect(x, y, layer.width(), layer.height())) area &= QRect(0, 0, self.width(), self.height()) if (not mask.isEmpty()): area &= mask for rect in area.rects(): for _x in range(rect.left(), rect.right() + 1): for _y in range(rect.top(), rect.bottom() + 1): self.setCell(_x, _y, layer.cellAt(_x - x, _y - y)) ## # Flip this tile layer in the given \a direction. Direction must be # horizontal or vertical. This doesn't change the dimensions of the # tile layer. ## def flip(self, direction): newGrid = QVector() for i in range(self.mWidth * self.mHeight): newGrid.append(Cell()) for y in range(self.mHeight): for x in range(self.mWidth): dest = newGrid[x + y * self.mWidth] if (direction == FlipDirection.FlipHorizontally): source = self.cellAt(self.mWidth - x - 1, y) dest = source dest.flippedHorizontally = not source.flippedHorizontally elif (direction == FlipDirection.FlipVertically): source = self.cellAt(x, self.mHeight - y - 1) dest = source dest.flippedVertically = not source.flippedVertically self.mGrid = newGrid ## # Rotate this tile layer by 90 degrees left or right. The tile positions # are rotated within the layer, and the tiles themselves are rotated. The # dimensions of the tile layer are swapped. ## def rotate(self, direction): rotateRightMask = [5, 4, 1, 0, 7, 6, 3, 2] rotateLeftMask = [3, 2, 7, 6, 1, 0, 5, 4] if direction == RotateDirection.RotateRight: rotateMask = rotateRightMask else: rotateMask = rotateLeftMask newWidth = self.mHeight newHeight = self.mWidth newGrid = QVector(newWidth * newHeight) for y in range(self.mHeight): for x in range(self.mWidth): source = self.cellAt(x, y) dest = source mask = (dest.flippedHorizontally << 2) | ( dest.flippedVertically << 1) | ( dest.flippedAntiDiagonally << 0) mask = rotateMask[mask] dest.flippedHorizontally = (mask & 4) != 0 dest.flippedVertically = (mask & 2) != 0 dest.flippedAntiDiagonally = (mask & 1) != 0 if (direction == RotateDirection.RotateRight): newGrid[x * newWidth + (self.mHeight - y - 1)] = dest else: newGrid[(self.mWidth - x - 1) * newWidth + y] = dest t = self.mMaxTileSize.width() self.mMaxTileSize.setWidth(self.mMaxTileSize.height()) self.mMaxTileSize.setHeight(t) self.mWidth = newWidth self.mHeight = newHeight self.mGrid = newGrid ## # Computes and returns the set of tilesets used by this tile layer. ## def usedTilesets(self): tilesets = QSet() i = 0 while (i < self.mGrid.size()): tile = self.mGrid.at(i).tile if tile: tilesets.insert(tile.tileset()) i += 1 return tilesets ## # Returns whether this tile layer has any cell for which the given # \a condition returns True. ## def hasCell(self, condition): i = 0 for cell in self.mGrid: if (condition(cell)): return True i += 1 return False ## # Returns whether this tile layer is referencing the given tileset. ## def referencesTileset(self, tileset): i = 0 while (i < self.mGrid.size()): tile = self.mGrid.at(i).tile if (tile and tile.tileset() == tileset): return True i += 1 return False ## # Removes all references to the given tileset. This sets all tiles on this # layer that are from the given tileset to null. ## def removeReferencesToTileset(self, tileset): i = 0 while (i < self.mGrid.size()): tile = self.mGrid.at(i).tile if (tile and tile.tileset() == tileset): self.mGrid.replace(i, Cell()) i += 1 ## # Replaces all tiles from \a oldTileset with tiles from \a newTileset. ## def replaceReferencesToTileset(self, oldTileset, newTileset): i = 0 while (i < self.mGrid.size()): tile = self.mGrid.at(i).tile if (tile and tile.tileset() == oldTileset): self.mGrid[i].tile = newTileset.tileAt(tile.id()) i += 1 ## # Resizes this tile layer to \a size, while shifting all tiles by # \a offset. ## def resize(self, size, offset): if (self.size() == size and offset.isNull()): return newGrid = QVector() for i in range(size.width() * size.height()): newGrid.append(Cell()) # Copy over the preserved part startX = max(0, -offset.x()) startY = max(0, -offset.y()) endX = min(self.mWidth, size.width() - offset.x()) endY = min(self.mHeight, size.height() - offset.y()) for y in range(startY, endY): for x in range(startX, endX): index = x + offset.x() + (y + offset.y()) * size.width() newGrid[index] = self.cellAt(x, y) self.mGrid = newGrid self.setSize(size) ## # Offsets the tiles in this layer within \a bounds by \a offset, # and optionally wraps them. # # \sa ObjectGroup.offset() ## def offsetTiles(self, offset, bounds, wrapX, wrapY): newGrid = QVector() for i in range(self.mWidth * self.mHeight): newGrid.append(Cell()) for y in range(self.mHeight): for x in range(self.mWidth): # Skip out of bounds tiles if (not bounds.contains(x, y)): newGrid[x + y * self.mWidth] = self.cellAt(x, y) continue # Get position to pull tile value from oldX = x - offset.x() oldY = y - offset.y() # Wrap x value that will be pulled from if (wrapX and bounds.width() > 0): while oldX < bounds.left(): oldX += bounds.width() while oldX > bounds.right(): oldX -= bounds.width() # Wrap y value that will be pulled from if (wrapY and bounds.height() > 0): while oldY < bounds.top(): oldY += bounds.height() while oldY > bounds.bottom(): oldY -= bounds.height() # Set the new tile if (self.contains(oldX, oldY) and bounds.contains(oldX, oldY)): newGrid[x + y * self.mWidth] = self.cellAt(oldX, oldY) else: newGrid[x + y * self.mWidth] = Cell() self.mGrid = newGrid def canMergeWith(self, other): return other.isTileLayer() def mergedWith(self, other): o = other unitedBounds = self.bounds().united(o.bounds()) offset = self.position() - unitedBounds.topLeft() merged = self.clone() merged.resize(unitedBounds.size(), offset) merged.merge(o.position() - unitedBounds.topLeft(), o) return merged ## # Returns the region where this tile layer and the given tile layer # are different. The relative positions of the layers are taken into # account. The returned region is relative to this tile layer. ## def computeDiffRegion(self, other): ret = QRegion() dx = other.x() - self.mX dy = other.y() - self.mY r = QRect(0, 0, self.width(), self.height()) r &= QRect(dx, dy, other.width(), other.height()) for y in range(r.top(), r.bottom() + 1): for x in range(r.left(), r.right() + 1): if (self.cellAt(x, y) != other.cellAt(x - dx, y - dy)): rangeStart = x while (x <= r.right() and self.cellAt(x, y) != other.cellAt(x - dx, y - dy)): x += 1 rangeEnd = x ret += QRect(rangeStart, y, rangeEnd - rangeStart, 1) return ret ## # Returns True if all tiles in the layer are empty. ## def isEmpty(self): i = 0 while (i < self.mGrid.size()): if (not self.mGrid.at(i).isEmpty()): return False i += 1 return True ## # Returns a duplicate of this TileLayer. # # \sa Layer.clone() ## def clone(self): return self.initializeClone( TileLayer(self.mName, self.mX, self.mY, self.mWidth, self.mHeight)) def begin(self): return self.mGrid.begin() def end(self): return self.mGrid.end() def initializeClone(self, clone): super().initializeClone(clone) clone.mGrid = self.mGrid clone.mMaxTileSize = self.mMaxTileSize clone.mOffsetMargins = self.mOffsetMargins return clone