Ejemplo n.º 1
0
 def __grabRect(self):
     """
     Private method to grab the selected rectangle (i.e. do the snapshot).
     """
     if self.__mode == SnapshotRegionGrabber.Ellipse:
         ell = QRegion(self.__selection, QRegion.Ellipse)
         if not ell.isEmpty():
             self.__grabbing = True
             
             xOffset = self.__pixmap.rect().x() - ell.boundingRect().x()
             yOffset = self.__pixmap.rect().y() - ell.boundingRect().y()
             translatedEll = ell.translated(xOffset, yOffset)
             
             pixmap2 = QPixmap(ell.boundingRect().size())
             pixmap2.fill(Qt.transparent)
             
             pt = QPainter()
             pt.begin(pixmap2)
             if pt.paintEngine().hasFeature(QPaintEngine.PorterDuff):
                 pt.setRenderHints(
                     QPainter.Antialiasing |
                     QPainter.HighQualityAntialiasing |
                     QPainter.SmoothPixmapTransform,
                     True)
                 pt.setBrush(Qt.black)
                 pt.setPen(QPen(QBrush(Qt.black), 0.5))
                 pt.drawEllipse(translatedEll.boundingRect())
                 pt.setCompositionMode(QPainter.CompositionMode_SourceIn)
             else:
                 pt.setClipRegion(translatedEll)
                 pt.setCompositionMode(QPainter.CompositionMode_Source)
             
             pt.drawPixmap(pixmap2.rect(), self.__pixmap,
                           ell.boundingRect())
             pt.end()
             
             self.grabbed.emit(pixmap2)
     else:
         r = QRect(self.__selection)
         if not r.isNull() and r.isValid():
             self.__grabbing = True
             self.grabbed.emit(self.__pixmap.copy(r))
Ejemplo n.º 2
0
    def __grabRect(self):
        """
        Private method to grab the selected rectangle (i.e. do the snapshot).
        """
        if self.__mode == SnapshotRegionGrabber.Ellipse:
            ell = QRegion(self.__selection, QRegion.Ellipse)
            if not ell.isEmpty():
                self.__grabbing = True

                xOffset = self.__pixmap.rect().x() - ell.boundingRect().x()
                yOffset = self.__pixmap.rect().y() - ell.boundingRect().y()
                translatedEll = ell.translated(xOffset, yOffset)

                pixmap2 = QPixmap(ell.boundingRect().size())
                pixmap2.fill(Qt.transparent)

                pt = QPainter()
                pt.begin(pixmap2)
                if pt.paintEngine().hasFeature(QPaintEngine.PorterDuff):
                    pt.setRenderHints(
                        QPainter.Antialiasing
                        | QPainter.HighQualityAntialiasing
                        | QPainter.SmoothPixmapTransform, True)
                    pt.setBrush(Qt.black)
                    pt.setPen(QPen(QBrush(Qt.black), 0.5))
                    pt.drawEllipse(translatedEll.boundingRect())
                    pt.setCompositionMode(QPainter.CompositionMode_SourceIn)
                else:
                    pt.setClipRegion(translatedEll)
                    pt.setCompositionMode(QPainter.CompositionMode_Source)

                pt.drawPixmap(pixmap2.rect(), self.__pixmap,
                              ell.boundingRect())
                pt.end()

                self.grabbed.emit(pixmap2)
        else:
            r = QRect(self.__selection)
            if not r.isNull() and r.isValid():
                self.__grabbing = True
                self.grabbed.emit(self.__pixmap.copy(r))
Ejemplo n.º 3
0
    def doErase(self, continuation):
        tileLayer = self.currentTileLayer()
        tilePos = self.tilePosition()
        eraseRegion = QRegion(tilePos.x(), tilePos.y(), 1, 1)
        if (continuation):
            for p in pointsOnLine(self.mLastTilePos, tilePos):
                eraseRegion |= QRegion(p.x(), p.y(), 1, 1)

        self.mLastTilePos = self.tilePosition()
        if (not tileLayer.bounds().intersects(eraseRegion.boundingRect())):
            return
        erase = EraseTiles(self.mapDocument(), tileLayer, eraseRegion)
        erase.setMergeable(continuation)
        self.mapDocument().undoStack().push(erase)
        self.mapDocument().emitRegionEdited(eraseRegion, tileLayer)
Ejemplo n.º 4
0
    def paintEvent(self, ev):
        """Called when paint is needed, finds out which page to magnify."""
        view = self.parent().parent()
        layout = view.pageLayout()

        scale = max(
            min(self._scale,
                view.MAX_ZOOM * self.MAX_EXTRA_ZOOM / layout.zoomFactor),
            view.MIN_ZOOM / layout.zoomFactor)
        matrix = QTransform().scale(scale, scale)

        # the position of our center on the layout
        c = self.geometry().center() - view.layoutPosition()

        # make a region scaling back to the view scale
        rect = matrix.inverted()[0].mapRect(self.rect())
        rect.moveCenter(c)
        region = QRegion(rect,
                         QRegion.Ellipse)  # touches the Pages we need to draw

        # our rect on the enlarged pages
        our_rect = self.rect()
        our_rect.moveCenter(matrix.map(c))

        # the virtual position of the whole scaled-up layout
        ev_rect = ev.rect().translated(our_rect.topLeft())

        # draw shadow border?
        shadow = False
        if hasattr(view, "drawDropShadow") and view.dropShadowEnabled:
            shadow = True
            shadow_width = layout.spacing * scale // 2

        painter = QPainter(self)
        for p in layout.pagesAt(region.boundingRect()):
            # get a (reused) the copy of the page
            page = p.copy(self, matrix)
            # now paint it
            rect = (page.geometry() & ev_rect).translated(-page.pos())
            painter.save()
            painter.translate(page.pos() - our_rect.topLeft())
            if shadow:
                view.drawDropShadow(page, painter, shadow_width)
            page.paint(painter, rect, self.repaintPage)
            painter.restore()

        self.drawBorder(painter)
Ejemplo n.º 5
0
    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))
Ejemplo n.º 6
0
    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))
Ejemplo n.º 7
0
class BucketFillTool(AbstractTileTool):
    def tr(self, sourceText, disambiguation = '', n = -1):
        return QCoreApplication.translate('BucketFillTool', sourceText, disambiguation, n)

    def __init__(self, parent = None):
        super().__init__(self.tr("Bucket Fill Tool"),
                           QIcon(":images/22x22/stock-tool-bucket-fill.png"),
                           QKeySequence(self.tr("F")),
                           parent)
        self.mStamp = TileStamp()
        self.mFillOverlay = None
        self.mFillRegion = QRegion()
        self.mMissingTilesets = QVector()
        self.mIsActive = False
        self.mLastShiftStatus = False
        ##
        # Indicates if the tool is using the random mode.
        ##
        self.mIsRandom = False
        ##
        # Contains the value of mIsRandom at that time, when the latest call of
        # tilePositionChanged() took place.
        # This variable is needed to detect if the random mode was changed during
        # mFillOverlay being brushed at an area.
        ##
        self.mLastRandomStatus = False
        ##
        # Contains all used random cells to use in random mode.
        # The same cell can be in the list multiple times to make different
        # random weights possible.
        ##
        self.mRandomCellPicker = RandomPicker()

    def __del__(self):
        pass

    def activate(self, scene):
        super().activate(scene)
        self.mIsActive = True
        self.tilePositionChanged(self.tilePosition())

    def deactivate(self, scene):
        super().deactivate(scene)
        self.mFillRegion = QRegion()
        self.mIsActive = False

    def mousePressed(self, event):
        if (event.button() != Qt.LeftButton or self.mFillRegion.isEmpty()):
            return
        if (not self.brushItem().isVisible()):
            return
        
        preview = self.mFillOverlay
        if not preview:
            return

        paint = PaintTileLayer(self.mapDocument(),
                                       self.currentTileLayer(),
                                       preview.x(),
                                       preview.y(),
                                       preview)

        paint.setText(QCoreApplication.translate("Undo Commands", "Fill Area"))

        if not self.mMissingTilesets.isEmpty():
            for tileset in self.mMissingTilesets:
                AddTileset(self.mapDocument(), tileset, paint)

            self.mMissingTilesets.clear()
            
        fillRegion = QRegion(self.mFillRegion)
        self.mapDocument().undoStack().push(paint)
        self.mapDocument().emitRegionEdited(fillRegion, self.currentTileLayer())

    def mouseReleased(self, event):
        pass

    def modifiersChanged(self, modifiers):
        # Don't need to recalculate fill region if there was no fill region
        if (not self.mFillOverlay):
            return
        self.tilePositionChanged(self.tilePosition())

    def languageChanged(self):
        self.setName(self.tr("Bucket Fill Tool"))
        self.setShortcut(QKeySequence(self.tr("F")))

    ##
    # Sets the stamp that is drawn when filling. The BucketFillTool takes
    # ownership over the stamp layer.
    ##
    def setStamp(self, stamp):
        # Clear any overlay that we presently have with an old stamp
        self.clearOverlay()
        self.mStamp = stamp
        self.updateRandomListAndMissingTilesets()
        if (self.mIsActive and self.brushItem().isVisible()):
            self.tilePositionChanged(self.tilePosition())

    ##
    # This returns the actual tile layer which is used to define the current
    # state.
    ##
    def stamp(self):
        return TileStamp(self.mStamp)

    def setRandom(self, value):
        if (self.mIsRandom == value):
            return
        self.mIsRandom = value
        self.updateRandomListAndMissingTilesets()
        
        # Don't need to recalculate fill region if there was no fill region
        if (not self.mFillOverlay):
            return
        self.tilePositionChanged(self.tilePosition())

    def tilePositionChanged(self, tilePos):
        # Skip filling if the stamp is empty
        if  self.mStamp.isEmpty():
            return
            
        # Make sure that a tile layer is selected
        tileLayer = self.currentTileLayer()
        if (not tileLayer):
            return
        
        shiftPressed = QApplication.keyboardModifiers() & Qt.ShiftModifier
        fillRegionChanged = False
        
        regionComputer = TilePainter(self.mapDocument(), tileLayer)
        # If the stamp is a single tile, ignore it when making the region
        if (not shiftPressed and self.mStamp.variations().size() == 1):
            variation = self.mStamp.variations().first()
            stampLayer = variation.tileLayer()
            if (stampLayer.size() == QSize(1, 1) and stampLayer.cellAt(0, 0) == regionComputer.cellAt(tilePos)):
                return
            
        # This clears the connections so we don't get callbacks
        self.clearConnections(self.mapDocument())
        # Optimization: we don't need to recalculate the fill area
        # if the new mouse position is still over the filled region
        # and the shift modifier hasn't changed.
        if (not self.mFillRegion.contains(tilePos) or shiftPressed != self.mLastShiftStatus):
            # Clear overlay to make way for a new one
            self.clearOverlay()
            # Cache information about how the fill region was created
            self.mLastShiftStatus = shiftPressed
            # Get the new fill region
            if (not shiftPressed):
                # If not holding shift, a region is generated from the current pos
                self.mFillRegion = regionComputer.computePaintableFillRegion(tilePos)
            else:
                # If holding shift, the region is the selection bounds
                self.mFillRegion = self.mapDocument().selectedArea()
                # Fill region is the whole map if there is no selection
                if (self.mFillRegion.isEmpty()):
                    self.mFillRegion = tileLayer.bounds()
                # The mouse needs to be in the region
                if (not self.mFillRegion.contains(tilePos)):
                    self.mFillRegion = QRegion()

            fillRegionChanged = True

        # Ensure that a fill region was created before making an overlay layer
        if (self.mFillRegion.isEmpty()):
            return
        if (self.mLastRandomStatus != self.mIsRandom):
            self.mLastRandomStatus = self.mIsRandom
            fillRegionChanged = True

        if (not self.mFillOverlay):
            # Create a new overlay region
            fillBounds = self.mFillRegion.boundingRect()
            self.mFillOverlay = TileLayer(QString(),
                                         fillBounds.x(),
                                         fillBounds.y(),
                                         fillBounds.width(),
                                         fillBounds.height())

        # Paint the new overlay
        if (not self.mIsRandom):
            if (fillRegionChanged or self.mStamp.variations().size() > 1):
                fillWithStamp(self.mFillOverlay, self.mStamp, self.mFillRegion.translated(-self.mFillOverlay.position()))
                fillRegionChanged = True
        else:
            self.randomFill(self.mFillOverlay, self.mFillRegion)
            fillRegionChanged = True

        if (fillRegionChanged):
            # Update the brush item to draw the overlay
            self.brushItem().setTileLayer(self.mFillOverlay)

        # Create connections to know when the overlay should be cleared
        self.makeConnections()

    def mapDocumentChanged(self, oldDocument, newDocument):
        super().mapDocumentChanged(oldDocument, newDocument)
        self.clearConnections(oldDocument)
        # Reset things that are probably invalid now
        if newDocument:
            self.updateRandomListAndMissingTilesets()

        self.clearOverlay()

    def clearOverlay(self):
        # Clear connections before clearing overlay so there is no
        # risk of getting a callback and causing an infinite loop
        self.clearConnections(self.mapDocument())
        self.brushItem().clear()
        self.mFillOverlay = None

        self.mFillRegion = QRegion()

    def makeConnections(self):
        if (not self.mapDocument()):
            return
        # Overlay may need to be cleared if a region changed
        self.mapDocument().regionChanged.connect(self.clearOverlay)
        # Overlay needs to be cleared if we switch to another layer
        self.mapDocument().currentLayerIndexChanged.connect(self.clearOverlay)
        # Overlay needs be cleared if the selection changes, since
        # the overlay may be bound or may need to be bound to the selection
        self.mapDocument().selectedAreaChanged.connect(self.clearOverlay)

    def clearConnections(self, mapDocument):
        if (not mapDocument):
            return
        try:
            mapDocument.regionChanged.disconnect(self.clearOverlay)
            mapDocument.currentLayerIndexChanged.disconnect(self.clearOverlay)
            mapDocument.selectedAreaChanged.disconnect(self.clearOverlay)
        except:
            pass

    ##
    # Updates the list of random cells.
    # This is done by taking all non-null tiles from the original stamp mStamp.
    ##
    def updateRandomListAndMissingTilesets(self):
        self.mRandomCellPicker.clear()
        self.mMissingTilesets.clear()
        
        for variation in self.mStamp.variations():
            self.mapDocument().unifyTilesets(variation.map, self.mMissingTilesets)

            if self.mIsRandom:
                for cell in variation.tileLayer():
                    if not cell.isEmpty():
                        self.mRandomCellPicker.add(cell, cell.tile.probability())

    ##
    # Fills the given \a region in the given \a tileLayer with random tiles.
    ##
    def randomFill(self, tileLayer, region):
        if (region.isEmpty() or self.mRandomList.empty()):
            return
        for rect in region.translated(-tileLayer.position()).rects():
            for _x in range(rect.left(), rect.right()+1):
                for _y in range(rect.top(), rect.bottom()+1):
                    tileLayer.setCell(_x, _y, self.mRandomCellPicker.pick())
Ejemplo n.º 8
0
class BucketFillTool(AbstractTileTool):
    def tr(self, sourceText, disambiguation='', n=-1):
        return QCoreApplication.translate('BucketFillTool', sourceText,
                                          disambiguation, n)

    def __init__(self, parent=None):
        super().__init__(self.tr("Bucket Fill Tool"),
                         QIcon(":images/22x22/stock-tool-bucket-fill.png"),
                         QKeySequence(self.tr("F")), parent)
        self.mStamp = TileStamp()
        self.mFillOverlay = None
        self.mFillRegion = QRegion()
        self.mMissingTilesets = QVector()
        self.mIsActive = False
        self.mLastShiftStatus = False
        ##
        # Indicates if the tool is using the random mode.
        ##
        self.mIsRandom = False
        ##
        # Contains the value of mIsRandom at that time, when the latest call of
        # tilePositionChanged() took place.
        # This variable is needed to detect if the random mode was changed during
        # mFillOverlay being brushed at an area.
        ##
        self.mLastRandomStatus = False
        ##
        # Contains all used random cells to use in random mode.
        # The same cell can be in the list multiple times to make different
        # random weights possible.
        ##
        self.mRandomCellPicker = RandomPicker()

    def __del__(self):
        pass

    def activate(self, scene):
        super().activate(scene)
        self.mIsActive = True
        self.tilePositionChanged(self.tilePosition())

    def deactivate(self, scene):
        super().deactivate(scene)
        self.mFillRegion = QRegion()
        self.mIsActive = False

    def mousePressed(self, event):
        if (event.button() != Qt.LeftButton or self.mFillRegion.isEmpty()):
            return
        if (not self.brushItem().isVisible()):
            return

        preview = self.mFillOverlay
        if not preview:
            return

        paint = PaintTileLayer(self.mapDocument(), self.currentTileLayer(),
                               preview.x(), preview.y(), preview)

        paint.setText(QCoreApplication.translate("Undo Commands", "Fill Area"))

        if not self.mMissingTilesets.isEmpty():
            for tileset in self.mMissingTilesets:
                AddTileset(self.mapDocument(), tileset, paint)

            self.mMissingTilesets.clear()

        fillRegion = QRegion(self.mFillRegion)
        self.mapDocument().undoStack().push(paint)
        self.mapDocument().emitRegionEdited(fillRegion,
                                            self.currentTileLayer())

    def mouseReleased(self, event):
        pass

    def modifiersChanged(self, modifiers):
        # Don't need to recalculate fill region if there was no fill region
        if (not self.mFillOverlay):
            return
        self.tilePositionChanged(self.tilePosition())

    def languageChanged(self):
        self.setName(self.tr("Bucket Fill Tool"))
        self.setShortcut(QKeySequence(self.tr("F")))

    ##
    # Sets the stamp that is drawn when filling. The BucketFillTool takes
    # ownership over the stamp layer.
    ##
    def setStamp(self, stamp):
        # Clear any overlay that we presently have with an old stamp
        self.clearOverlay()
        self.mStamp = stamp
        self.updateRandomListAndMissingTilesets()
        if (self.mIsActive and self.brushItem().isVisible()):
            self.tilePositionChanged(self.tilePosition())

    ##
    # This returns the actual tile layer which is used to define the current
    # state.
    ##
    def stamp(self):
        return TileStamp(self.mStamp)

    def setRandom(self, value):
        if (self.mIsRandom == value):
            return
        self.mIsRandom = value
        self.updateRandomListAndMissingTilesets()

        # Don't need to recalculate fill region if there was no fill region
        if (not self.mFillOverlay):
            return
        self.tilePositionChanged(self.tilePosition())

    def tilePositionChanged(self, tilePos):
        # Skip filling if the stamp is empty
        if self.mStamp.isEmpty():
            return

        # Make sure that a tile layer is selected
        tileLayer = self.currentTileLayer()
        if (not tileLayer):
            return

        shiftPressed = QApplication.keyboardModifiers() & Qt.ShiftModifier
        fillRegionChanged = False

        regionComputer = TilePainter(self.mapDocument(), tileLayer)
        # If the stamp is a single tile, ignore it when making the region
        if (not shiftPressed and self.mStamp.variations().size() == 1):
            variation = self.mStamp.variations().first()
            stampLayer = variation.tileLayer()
            if (stampLayer.size() == QSize(1, 1) and stampLayer.cellAt(0, 0)
                    == regionComputer.cellAt(tilePos)):
                return

        # This clears the connections so we don't get callbacks
        self.clearConnections(self.mapDocument())
        # Optimization: we don't need to recalculate the fill area
        # if the new mouse position is still over the filled region
        # and the shift modifier hasn't changed.
        if (not self.mFillRegion.contains(tilePos)
                or shiftPressed != self.mLastShiftStatus):
            # Clear overlay to make way for a new one
            self.clearOverlay()
            # Cache information about how the fill region was created
            self.mLastShiftStatus = shiftPressed
            # Get the new fill region
            if (not shiftPressed):
                # If not holding shift, a region is generated from the current pos
                self.mFillRegion = regionComputer.computePaintableFillRegion(
                    tilePos)
            else:
                # If holding shift, the region is the selection bounds
                self.mFillRegion = self.mapDocument().selectedArea()
                # Fill region is the whole map if there is no selection
                if (self.mFillRegion.isEmpty()):
                    self.mFillRegion = tileLayer.bounds()
                # The mouse needs to be in the region
                if (not self.mFillRegion.contains(tilePos)):
                    self.mFillRegion = QRegion()

            fillRegionChanged = True

        # Ensure that a fill region was created before making an overlay layer
        if (self.mFillRegion.isEmpty()):
            return
        if (self.mLastRandomStatus != self.mIsRandom):
            self.mLastRandomStatus = self.mIsRandom
            fillRegionChanged = True

        if (not self.mFillOverlay):
            # Create a new overlay region
            fillBounds = self.mFillRegion.boundingRect()
            self.mFillOverlay = TileLayer(QString(), fillBounds.x(),
                                          fillBounds.y(), fillBounds.width(),
                                          fillBounds.height())

        # Paint the new overlay
        if (not self.mIsRandom):
            if (fillRegionChanged or self.mStamp.variations().size() > 1):
                fillWithStamp(
                    self.mFillOverlay, self.mStamp,
                    self.mFillRegion.translated(-self.mFillOverlay.position()))
                fillRegionChanged = True
        else:
            self.randomFill(self.mFillOverlay, self.mFillRegion)
            fillRegionChanged = True

        if (fillRegionChanged):
            # Update the brush item to draw the overlay
            self.brushItem().setTileLayer(self.mFillOverlay)

        # Create connections to know when the overlay should be cleared
        self.makeConnections()

    def mapDocumentChanged(self, oldDocument, newDocument):
        super().mapDocumentChanged(oldDocument, newDocument)
        self.clearConnections(oldDocument)
        # Reset things that are probably invalid now
        if newDocument:
            self.updateRandomListAndMissingTilesets()

        self.clearOverlay()

    def clearOverlay(self):
        # Clear connections before clearing overlay so there is no
        # risk of getting a callback and causing an infinite loop
        self.clearConnections(self.mapDocument())
        self.brushItem().clear()
        self.mFillOverlay = None

        self.mFillRegion = QRegion()

    def makeConnections(self):
        if (not self.mapDocument()):
            return
        # Overlay may need to be cleared if a region changed
        self.mapDocument().regionChanged.connect(self.clearOverlay)
        # Overlay needs to be cleared if we switch to another layer
        self.mapDocument().currentLayerIndexChanged.connect(self.clearOverlay)
        # Overlay needs be cleared if the selection changes, since
        # the overlay may be bound or may need to be bound to the selection
        self.mapDocument().selectedAreaChanged.connect(self.clearOverlay)

    def clearConnections(self, mapDocument):
        if (not mapDocument):
            return
        try:
            mapDocument.regionChanged.disconnect(self.clearOverlay)
            mapDocument.currentLayerIndexChanged.disconnect(self.clearOverlay)
            mapDocument.selectedAreaChanged.disconnect(self.clearOverlay)
        except:
            pass

    ##
    # Updates the list of random cells.
    # This is done by taking all non-null tiles from the original stamp mStamp.
    ##
    def updateRandomListAndMissingTilesets(self):
        self.mRandomCellPicker.clear()
        self.mMissingTilesets.clear()

        for variation in self.mStamp.variations():
            self.mapDocument().unifyTilesets(variation.map,
                                             self.mMissingTilesets)

            if self.mIsRandom:
                for cell in variation.tileLayer():
                    if not cell.isEmpty():
                        self.mRandomCellPicker.add(cell,
                                                   cell.tile.probability())

    ##
    # Fills the given \a region in the given \a tileLayer with random tiles.
    ##
    def randomFill(self, tileLayer, region):
        if (region.isEmpty() or self.mRandomList.empty()):
            return
        for rect in region.translated(-tileLayer.position()).rects():
            for _x in range(rect.left(), rect.right() + 1):
                for _y in range(rect.top(), rect.bottom() + 1):
                    tileLayer.setCell(_x, _y, self.mRandomCellPicker.pick())
Ejemplo n.º 9
0
class BrushItem(QGraphicsItem):
    ##
    # Constructor.
    ##
    def __init__(self):
        super().__init__()

        self.mMapDocument = None
        self.mBoundingRect = QRectF()
        self.mRegion = QRegion()
        self.setFlag(QGraphicsItem.ItemUsesExtendedStyleOption)

    ##
    # Sets the map document this brush is operating on.
    ##
    def setMapDocument(self, mapDocument):
        if (self.mMapDocument == mapDocument):
            return
        self.mMapDocument = mapDocument
        # The tiles in the stamp may no longer be valid
        self.clear()

    ##
    # Clears the tile layer and region set on this item.
    ##
    def clear(self):
        self.setTileLayer(None)

    ##
    # Sets a tile layer representing this brush. When no tile layer is set,
    # the brush only draws the selection color.
    #
    # The BrushItem does not take ownership over the tile layer, but makes a
    # personal copy of the tile layer.
    ##
    def setTileLayer(self, tileLayer):
        self.mTileLayer = tileLayer
        if (tileLayer):
            self.mRegion = tileLayer.region()
        else:
            self.mRegion = QRegion()

        self.updateBoundingRect()
        self.update()

    ##
    # Returns the current tile layer.
    ##
    def tileLayer(self):
        return self.mTileLayer

    ##
    # Changes the position of the tile layer, if one is set.
    ##
    def setTileLayerPosition(self, pos):
        if (not self.mTileLayer):
            return
        oldPosition = QPoint(self.mTileLayer.x(), self.mTileLayer.y())
        if (oldPosition == pos):
            return

        self.mRegion.translate(pos - oldPosition)
        self.mTileLayer.setX(pos.x())
        self.mTileLayer.setY(pos.y())
        self.updateBoundingRect()

    ##
    # Sets the region of tiles that this brush item occupies.
    ##
    def setTileRegion(self, region):
        if type(region) != QRegion:
            region = QRegion(region)
        if (self.mRegion == region):
            return
        self.mRegion = region
        self.updateBoundingRect()

    ##
    # Sets the layer offset used by the currently active layer.
    ##
    def setLayerOffset(self, offset):
        self.setPos(offset)

    ##
    # Returns the region of the current tile layer or the region that was set
    # using setTileRegion.
    ##
    def tileRegion(self):
        return self.mRegion

    # QGraphicsItem
    def boundingRect(self):
        return self.mBoundingRect

    def paint(self, painter, option, widget=None):
        insideMapHighlight = QApplication.palette().highlight().color()
        insideMapHighlight.setAlpha(64)
        outsideMapHighlight = QColor(255, 0, 0, 64)
        mapWidth = self.mMapDocument.map().width()
        mapHeight = self.mMapDocument.map().height()
        mapRegion = QRegion(0, 0, mapWidth, mapHeight)
        insideMapRegion = self.mRegion.intersected(mapRegion)
        outsideMapRegion = self.mRegion.subtracted(mapRegion)
        renderer = self.mMapDocument.renderer()
        if (self.mTileLayer):
            opacity = painter.opacity()
            painter.setOpacity(0.75)
            renderer.drawTileLayer(painter, self.mTileLayer,
                                   option.exposedRect)
            painter.setOpacity(opacity)
        renderer.drawTileSelection(painter, insideMapRegion,
                                   insideMapHighlight, option.exposedRect)
        renderer.drawTileSelection(painter, outsideMapRegion,
                                   outsideMapHighlight, option.exposedRect)

    def updateBoundingRect(self):
        self.prepareGeometryChange()
        if (not self.mMapDocument):
            self.mBoundingRect = QRectF()
            return

        bounds = self.mRegion.boundingRect()
        self.mBoundingRect = QRectF(
            self.mMapDocument.renderer().boundingRect(bounds))
        # Adjust for amount of pixels tiles extend at the top and to the right
        if (self.mTileLayer):
            map = self.mMapDocument.map()
            drawMargins = self.mTileLayer.drawMargins()
            drawMargins.setTop(drawMargins.top() - map.tileHeight())
            drawMargins.setRight(drawMargins.right() - map.tileWidth())
            # Since we're also drawing a tile selection, we should not apply
            # negative margins
            self.mBoundingRect.adjust(min(0, -drawMargins.left()),
                                      min(0, -drawMargins.top()),
                                      max(0, drawMargins.right()),
                                      max(0, drawMargins.bottom()))
Ejemplo n.º 10
0
    def drawPreviewLayer(self, _list):
        self.mPreviewLayer = None

        if self.mStamp.isEmpty():
            return

        if self.mIsRandom:
            if self.mRandomCellPicker.isEmpty():
                return

            paintedRegion = QRegion()
            for p in _list:
                paintedRegion += QRect(p, QSize(1, 1))

            bounds = paintedRegion.boundingRect()
            preview = TileLayer(QString(),
                                  bounds.x(), bounds.y(),
                                  bounds.width(), bounds.height())

            for p in _list:
                cell = self.mRandomCellPicker.pick()
                preview.setCell(p.x() - bounds.left(),
                                 p.y() - bounds.top(),
                                 cell)

            self.mPreviewLayer = preview
        else:
            self.mMissingTilesets.clear()

            paintedRegion = QRegion()
            operations = QVector()
            regionCache = QHash()

            for p in _list:
                variation = self.mStamp.randomVariation()
                self.mapDocument().unifyTilesets(variation.map, self.mMissingTilesets)

                stamp = variation.tileLayer()

                stampRegion = QRegion()
                if regionCache.contains(stamp):
                    stampRegion = regionCache.value(stamp)
                else:
                    stampRegion = stamp.region()
                    regionCache.insert(stamp, stampRegion)

                centered = QPoint(p.x() - int(stamp.width() / 2), p.y() - int(stamp.height() / 2))

                region = stampRegion.translated(centered.x(), centered.y())
                if not paintedRegion.intersects(region):
                    paintedRegion += region

                    op = PaintOperation(centered, stamp)
                    operations.append(op)

            bounds = paintedRegion.boundingRect()
            preview = TileLayer(QString(),
                                      bounds.x(), bounds.y(),
                                      bounds.width(), bounds.height())

            for op in operations:
                preview.merge(op.pos - bounds.topLeft(), op.stamp)
            
            self.mPreviewLayer = preview
Ejemplo n.º 11
0
class BrushItem(QGraphicsItem):
    ##
    # Constructor.
    ##
    def __init__(self):
        super().__init__()

        self.mMapDocument = None
        self.mBoundingRect = QRectF()
        self.mRegion = QRegion()
        self.setFlag(QGraphicsItem.ItemUsesExtendedStyleOption)
        
    ##
    # Sets the map document this brush is operating on.
    ##
    def setMapDocument(self, mapDocument):
        if (self.mMapDocument == mapDocument):
            return
        self.mMapDocument = mapDocument
        # The tiles in the stamp may no longer be valid
        self.clear()

    ##
    # Clears the tile layer and region set on this item.
    ##
    def clear(self):
        self.setTileLayer(None)
        
    ##
    # Sets a tile layer representing this brush. When no tile layer is set,
    # the brush only draws the selection color.
    #
    # The BrushItem does not take ownership over the tile layer, but makes a
    # personal copy of the tile layer.
    ##
    def setTileLayer(self, tileLayer):
        self.mTileLayer = tileLayer
        if (tileLayer):
            self.mRegion = tileLayer.region()
        else:
            self.mRegion = QRegion()

        self.updateBoundingRect()
        self.update()

    ##
    # Returns the current tile layer.
    ##
    def tileLayer(self):
        return self.mTileLayer

    ##
    # Changes the position of the tile layer, if one is set.
    ##
    def setTileLayerPosition(self, pos):
        if (not self.mTileLayer):
            return
        oldPosition = QPoint(self.mTileLayer.x(), self.mTileLayer.y())
        if (oldPosition == pos):
            return

        self.mRegion.translate(pos - oldPosition)
        self.mTileLayer.setX(pos.x())
        self.mTileLayer.setY(pos.y())
        self.updateBoundingRect()

    ##
    # Sets the region of tiles that this brush item occupies.
    ##
    def setTileRegion(self, region):
        if type(region)!=QRegion:
            region = QRegion(region)
        if (self.mRegion == region):
            return
        self.mRegion = region
        self.updateBoundingRect()

    ##
    # Sets the layer offset used by the currently active layer.
    ##
    def setLayerOffset(self, offset):
        self.setPos(offset)
        
    ##
    # Returns the region of the current tile layer or the region that was set
    # using setTileRegion.
    ##
    def tileRegion(self):
        return self.mRegion

    # QGraphicsItem
    def boundingRect(self):
        return self.mBoundingRect

    def paint(self, painter, option, widget = None):
        insideMapHighlight = QApplication.palette().highlight().color()
        insideMapHighlight.setAlpha(64)
        outsideMapHighlight = QColor(255, 0, 0, 64)
        mapWidth = self.mMapDocument.map().width()
        mapHeight = self.mMapDocument.map().height()
        mapRegion = QRegion(0, 0, mapWidth, mapHeight)
        insideMapRegion = self.mRegion.intersected(mapRegion)
        outsideMapRegion = self.mRegion.subtracted(mapRegion)
        renderer = self.mMapDocument.renderer()
        if (self.mTileLayer):
            opacity = painter.opacity()
            painter.setOpacity(0.75)
            renderer.drawTileLayer(painter, self.mTileLayer, option.exposedRect)
            painter.setOpacity(opacity)
        renderer.drawTileSelection(painter, insideMapRegion, insideMapHighlight, option.exposedRect)
        renderer.drawTileSelection(painter, outsideMapRegion, outsideMapHighlight, option.exposedRect)

    def updateBoundingRect(self):
        self.prepareGeometryChange()
        if (not self.mMapDocument):
            self.mBoundingRect = QRectF()
            return

        bounds = self.mRegion.boundingRect()
        self.mBoundingRect = QRectF(self.mMapDocument.renderer().boundingRect(bounds))
        # Adjust for amount of pixels tiles extend at the top and to the right
        if (self.mTileLayer):
            map = self.mMapDocument.map()
            drawMargins = self.mTileLayer.drawMargins()
            drawMargins.setTop(drawMargins.top() - map.tileHeight())
            drawMargins.setRight(drawMargins.right() - map.tileWidth())
            # Since we're also drawing a tile selection, we should not apply
            # negative margins
            self.mBoundingRect.adjust(min(0, -drawMargins.left()),
                                 min(0, -drawMargins.top()),
                                 max(0, drawMargins.right()),
                                 max(0, drawMargins.bottom()))
Ejemplo n.º 12
0
class Mask:
    def __init__(self, mask_path: Path):
        mask_pix = QPixmap()
        if not mask_pix.load(str(mask_path)):
            raise ValueError(f"Failed to load mask from {mask_path}")

        self.size = mask_pix.size()
        logger.debug("size: %s", self.size)

        self.clip_region = QRegion(
            mask_pix.createMaskFromColor(QColor("white"), Qt.MaskInColor)
        )
        logger.debug("clip_region: %s", self.clip_region)
        logger.debug("clip_region bounding rect: %s", self.clip_region.boundingRect())

    def mask(self, image: QImage) -> QImage:
        clip_rect = self._build_clip_rect(image)

        masked = QImage(self.size, QImage.Format_RGB32)

        painter = QPainter(masked)
        painter.setRenderHints(QPainter.Antialiasing, QPainter.SmoothPixmapTransform)
        painter.setClipRegion(self.clip_region)
        painter.drawImage(masked.rect(), image, clip_rect)

        painter.end()

        return masked

    def shrink_and_clip_to_mask_size(self, image):
        clip_rect = self._build_clip_rect(image)

        shrunk_and_clipped = QImage(self.size, QImage.Format_RGB32)

        painter = QPainter(shrunk_and_clipped)
        painter.setRenderHints(QPainter.Antialiasing, QPainter.SmoothPixmapTransform)
        painter.drawImage(shrunk_and_clipped.rect(), image, clip_rect)

        painter.end()

        return shrunk_and_clipped

    def _build_clip_rect(self, image):
        logger.debug("Image size: %s", image.size())
        image_height_for_width = image.height() / image.width()
        mask_height_for_width = float(self.size.height()) / self.size.width()
        logger.debug(
            "Height for widths - image: %s mask: %s",
            image_height_for_width,
            mask_height_for_width,
        )
        if image_height_for_width > mask_height_for_width:
            # image is taller than mask
            clip_height = int(image.size().width() * mask_height_for_width)
            clip_rect = QRect(
                0,
                (image.size().height() - clip_height) / 2,
                image.size().width(),
                clip_height,
            )
        else:
            # image is wider than mask
            clip_width = int(image.size().height() / mask_height_for_width)
            clip_rect = QRect(
                (image.size().width() - clip_width) / 2,
                0,
                clip_width,
                image.size().height(),
            )
        logger.debug("Clip rect: %s", clip_rect)
        return clip_rect
Ejemplo n.º 13
0
    def drawPreviewLayer(self, _list):
        self.mPreviewLayer = None

        if self.mStamp.isEmpty():
            return

        if self.mIsRandom:
            if self.mRandomCellPicker.isEmpty():
                return

            paintedRegion = QRegion()
            for p in _list:
                paintedRegion += QRect(p, QSize(1, 1))

            bounds = paintedRegion.boundingRect()
            preview = TileLayer(QString(), bounds.x(), bounds.y(),
                                bounds.width(), bounds.height())

            for p in _list:
                cell = self.mRandomCellPicker.pick()
                preview.setCell(p.x() - bounds.left(),
                                p.y() - bounds.top(), cell)

            self.mPreviewLayer = preview
        else:
            self.mMissingTilesets.clear()

            paintedRegion = QRegion()
            operations = QVector()
            regionCache = QHash()

            for p in _list:
                variation = self.mStamp.randomVariation()
                self.mapDocument().unifyTilesets(variation.map,
                                                 self.mMissingTilesets)

                stamp = variation.tileLayer()

                stampRegion = QRegion()
                if regionCache.contains(stamp):
                    stampRegion = regionCache.value(stamp)
                else:
                    stampRegion = stamp.region()
                    regionCache.insert(stamp, stampRegion)

                centered = QPoint(p.x() - int(stamp.width() / 2),
                                  p.y() - int(stamp.height() / 2))

                region = stampRegion.translated(centered.x(), centered.y())
                if not paintedRegion.intersects(region):
                    paintedRegion += region

                    op = PaintOperation(centered, stamp)
                    operations.append(op)

            bounds = paintedRegion.boundingRect()
            preview = TileLayer(QString(), bounds.x(), bounds.y(),
                                bounds.width(), bounds.height())

            for op in operations:
                preview.merge(op.pos - bounds.topLeft(), op.stamp)

            self.mPreviewLayer = preview
Ejemplo n.º 14
0
class Menu(QMainWindow):
    # ------------------------- Init ----------------------------------
    def __init__(self):
        super(Menu, self).__init__()
        self.background_picture = QGraphicsView()
        self.scene = QGraphicsScene()
        self.grp = QGroupBox("Mon Groupe")
        self.palette = QPalette()
        self.proxy = QGraphicsProxyWidget()
        self.background_picture2 = QPixmap()
        self.fenetre_creer_une_partie = None
        self.bouton_creer = QPushButton(self)
        self.bouton_rejoindre = QPushButton(self)
        self.bouton_quitter = QPushButton(self)
        self.bouton_help = QPushButton(self)
        self.label = QLabel(self)
        self.init_ui()
        self.setWindowTitle("Bienvenue dans Skip-Bo!")
        self.hauteur = int
        self.quart_hauteur = int
        self.longueur = int
        self.quart_longueur = int
        self.test_rect = QRect()
        self.test_region = QRegion()
        self.rsp = None
        self.rsp2 = None
        self.rsp3 = None
        self.join = QDialog()
        self.verification = QDialog()
        self.quitter_icon = QIcon()
        self.join_icon = QIcon()
        self.creer_icon = QIcon()
        self.help_icon = QIcon()
        self.msg_help = QMessageBox()
        # self.socket_connexion = None

    # ---------------------- Fin du Init ------------------------------

    # ---------------------- Fonction pour centrer la fenêtre dans l'écran ----------------------
    def center(self):
        frame = self.frameGeometry()
        ecran_actif = QApplication.desktop().screenNumber(
            QApplication.desktop().cursor().pos())
        point_central = QApplication.desktop().screenGeometry(
            ecran_actif).center()
        frame.moveCenter(point_central)
        self.move(frame.topLeft())

    # --------------------- Fin de la fonction --------------------------------------------------

    # --------------------- Fonction quitter ----------------------------------------------------
    def quitter(self):
        self.close()

    # --------------------- Fin de la fonction --------------------------------------------------

    # --------------------- Fonction pour créer une partie --------------------------------------
    def creer_nouvelle_partie(self):
        self.fenetre_creer_une_partie = creation_partie.NouvellePartie()
        self.fenetre_creer_une_partie.setModal(True)
        self.fenetre_creer_une_partie.show()
        self.rsp = self.fenetre_creer_une_partie.exec_()
        if self.rsp == QDialog.Accepted:
            self.close()
        else:
            print("Cancel")

    # --------------------- Fin de la fonction -------------------------------------------------

    # --------------------- Fonction pour joindre une partie -----------------------------------
    def joindre_partie(self):
        self.verification = verification.Verification()
        self.verification.setModal(True)
        self.verification.show()
        self.rsp2 = self.verification.exec_()
        # print(self.verification.socket_de_connection)
        if self.rsp2 == QDialog.Accepted:
            # print(self.socket_connexion)
            self.join = join.JoinPartie()
            self.join.setModal(True)
            self.join.show()
            self.rsp3 = self.join.exec_()
            if self.rsp3 == QDialog.Accepted:
                self.close()
            else:
                print("Join canceled")
        else:
            print("Cancel")

    # --------------------- Fin de la fonction -------------------------------------------------

    # --------------------- Fonction d'aide ----------------------------------------------------
    def help(self):
        self.msg_help.setIcon(QMessageBox.Information)
        self.msg_help.setText("Bienvenue dans la rubrique d'aide")
        self.msg_help.setInformativeText(
            'Pour créer une partie, cliquez sur le bouton "Créer une partie".\n \nPour '
            'joindre une partie, ayez d\'abord votre code d\'invitation en main, puis '
            'cliquez sur joindre une partie.')
        self.msg_help.setWindowTitle("Rubrique d'aide")
        self.msg_help.setStandardButtons(QMessageBox.Ok)
        self.msg_help.exec_()

    # --------------------- Fin de la fonction -------------------------------------------------

    # --------------------- Initialisation de la fenêtre et des éléments graphique -------------
    def init_ui(self):
        # --------------- Paramètres de la fenêtre --------------------
        self.resize(1280, 720)
        self.setMaximumSize(1280, 720)
        self.setMinimumSize(1280, 720)
        self.center()
        self.background_picture2.load('backgroundmenu3.png')
        self.palette.setBrush(self.backgroundRole(),
                              QBrush(self.background_picture2))
        self.setPalette(self.palette)

        # --------------- Éléments présents dans la fenêtre ----------
        self.hauteur = int(self.frameGeometry().height())
        self.quart_hauteur = int(self.hauteur / 4)
        self.longueur = int(self.frameGeometry().width())
        self.quart_longueur = int(self.longueur / 4)
        self.label.setText("* Skip-Bo est une marque déposée de Mattel Inc.")
        self.label.move(20, 690)
        self.label.adjustSize()
        self.bouton_creer.setText("")
        self.creer_icon = QIcon("bouton_creer.png")
        self.bouton_creer.setIcon(self.creer_icon)
        self.bouton_creer.setIconSize(QSize(320, 90))
        self.bouton_creer.setGeometry((self.quart_longueur - 160),
                                      (3 * self.quart_hauteur),
                                      self.quart_longueur,
                                      int(self.quart_hauteur / 2))
        self.bouton_creer.clicked.connect(self.creer_nouvelle_partie)
        self.bouton_rejoindre.setText("")
        self.join_icon = QIcon("bouton_join.png")
        self.bouton_rejoindre.setIcon(self.join_icon)
        self.bouton_rejoindre.setIconSize(QSize(318, 88))
        self.bouton_rejoindre.setGeometry(((2 * self.quart_longueur) - 160),
                                          (3 * self.quart_hauteur),
                                          self.quart_longueur,
                                          int(self.quart_hauteur / 2))
        self.bouton_rejoindre.clicked.connect(self.joindre_partie)
        self.bouton_help.setText("")
        self.help_icon = QIcon("bouton_help.png")
        self.bouton_help.setIcon(self.help_icon)
        self.bouton_help.setIconSize(QSize(65, 65))
        self.bouton_help.setFixedHeight(100)
        self.bouton_help.setFixedWidth(100)
        self.bouton_help.move(
            self.longueur - int(self.quart_longueur / (4 / 2)), -10)
        self.bouton_help.clicked.connect(self.help)
        self.test_rect = QRect(20, 20, 60, 60)
        self.test_region = QRegion(self.test_rect, QRegion.Ellipse)
        self.test_region.boundingRect().size()
        self.bouton_help.setMask(self.test_region)
        self.bouton_quitter.setText("")
        self.quitter_icon = QIcon("bouton_quitter.png")
        self.bouton_quitter.setIcon(self.quitter_icon)
        self.bouton_quitter.setIconSize(QSize(318, 88))
        self.bouton_quitter.setGeometry(((3 * self.quart_longueur) - 160),
                                        (3 * self.quart_hauteur),
                                        self.quart_longueur,
                                        int(self.quart_hauteur / 2))
        self.bouton_quitter.clicked.connect(self.quitter)