Example #1
0
class GameArea(QWidget):
    #constants of widget
    RATIO_WITH_SHIPLIST = 11 / 14
    RATIO_WITHOUT_SHIPLIST = 1
    EPS = 0.3

    #signals
    shipPlaced = pyqtSignal(Ship)

    def __init__(self, parent=None):
        super(GameArea, self).__init__(parent)
        self.__ui = Ui_GameArea()
        self.__ui.setupUi(self)

        self.__ratio = self.RATIO_WITH_SHIPLIST
        self.__scaleFactor = 1

        self.controller = Controller()
        self.controller._accept = self.__accept
        self.controller._decline = self.__decline
        self.__gameModel = None

        self.__shipList = {
            "boat": ShipListItem(length=1, name="boat", count=4),
            "destroyer": ShipListItem(length=2, name="destroyer", count=3),
            "cruiser": ShipListItem(length=3, name="cruiser", count=2),
            "battleship": ShipListItem(length=4, name="battleship", count=1),
        }

        # resources
        self.__cellImages = {"intact": None, "hit": None, "miss": None}

        self.__sprites = {"explosion": None, "splash": None}

        self.__originalTileSize = 0
        self.tileSize = 0

        self.__shipListImage = QImage()
        self.__counterImage = QImage()

        # drawing items
        self.__placedShips = []
        self.__field = [QGraphicsPixmapItem() for _ in range(100)]
        self.__letters = [QGraphicsTextItem() for _ in range(10)]
        self.__numbers = [QGraphicsTextItem() for _ in range(10)]
        for i in range(10):
            self.__letters[i].setDefaultTextColor(QColor.fromRgb(0, 0, 0))
            self.__numbers[i].setDefaultTextColor(QColor.fromRgb(0, 0, 0))

        self.__spriteAnimations = []

        self.__shipListItem = QGraphicsPixmapItem()
        self.__ghostShip = QGraphicsPixmapItem(
        )  # data: 0 - rotation; 1 - ShipListItem
        self.__placer = QGraphicsRectItem()
        self.__dragShip = False

        self.__targetPixmap = None
        self.__targets = []
        self.__scanEffect = None

        # prepare Qt objects
        self.__scene = QGraphicsScene()
        self.__loadResources()
        self.__initGraphicsView()
        self.__adjustedToSize = 0

    def serviceModel(self, game_model):
        self.removeModel()
        self.__gameModel = game_model
        self.__gameModel.shipKilled.connect(self.__shootAround)

    def removeModel(self):
        if self.__gameModel:
            self.shipKilled.disconnect()
            self.__gameModel = None

    def __loadResources(self):
        if DEBUG_RESOURCE:
            resourcesPath = os.path.join(os.path.dirname(__file__),
                                         DEBUG_RESOURCE)
        else:
            resourcesPath = Environment.Resources.path()

        first = True
        for imageName in self.__cellImages:
            image = QImage(
                os.path.join(resourcesPath, "img", "cells",
                             f"{imageName}.png"))
            if first:
                first = False
                self.__originalTileSize = min(image.width(), image.height())
            else:
                self.__originalTileSize = min(self.__originalTileSize,
                                              image.width(), image.height())
            self.__cellImages[imageName] = image

        for spriteName in self.__sprites:
            image = QImage(
                os.path.join(resourcesPath, "img", "cells",
                             f"{spriteName}.png"))
            self.__sprites[spriteName] = image

        for shipName, ship in self.__shipList.items():
            ship.image = QImage(
                os.path.join(resourcesPath, "img", "ships", f"{shipName}.png"))

        self.__shipListImage = QImage(
            os.path.join(resourcesPath, "img", "backgrounds", "shiplist.png"))
        self.__counterImage = QImage(
            os.path.join(resourcesPath, "img", "miscellaneous",
                         "shipcounter.png"))

        self.__targetPixmap = QPixmap(
            os.path.join(resourcesPath, "img", "cells", "target.png"))

    def __initGraphicsView(self):
        self.__ui.graphicsView.setScene(self.__scene)
        self.__ui.graphicsView.viewport().installEventFilter(self)
        self.__ui.graphicsView.setRenderHints(
            QPainter.RenderHint.HighQualityAntialiasing
            | QPainter.RenderHint.TextAntialiasing
            | QPainter.RenderHint.SmoothPixmapTransform)
        self.__ui.graphicsView.horizontalScrollBar().blockSignals(True)
        self.__ui.graphicsView.verticalScrollBar().blockSignals(True)

        for cell in self.__field:
            cell.setData(0, "intact")
            pixmap = QPixmap.fromImage(self.__cellImages["intact"])
            cell.setPixmap(pixmap)
            cell.setTransformationMode(
                Qt.TransformationMode.SmoothTransformation)
            self.__scene.addItem(cell)

        ca_letters = ["А", "Б", "В", "Г", "Д", "Е", "Ж", "З", "И", "К"]
        # ca_letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J"]
        ca_numbers = ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]

        font = QFont("Roboto")
        font.setPixelSize(int(self.__originalTileSize * 0.8))
        for i in range(10):
            self.__letters[i].setPlainText(ca_letters[i])
            self.__letters[i].setFont(font)
            self.__numbers[i].setPlainText(ca_numbers[i])
            self.__numbers[i].setFont(font)
            self.__scene.addItem(self.__letters[i])
            self.__scene.addItem(self.__numbers[i])

        self.__shipListItem.setPixmap(QPixmap.fromImage(self.__shipListImage))
        self.__shipListItem.setTransformationMode(
            Qt.TransformationMode.SmoothTransformation)
        self.__scene.addItem(self.__shipListItem)

        font.setPixelSize(int(self.__originalTileSize * 0.3))
        for _, ship in self.__shipList.items():
            t = QTransform().rotate(90)
            ship.shipItem.setPixmap(
                QPixmap.fromImage(ship.image).transformed(t))
            ship.shipItem.setTransformationMode(
                Qt.TransformationMode.SmoothTransformation)
            ship.counterItem.setPixmap(QPixmap.fromImage(self.__counterImage))
            ship.counterItem.setTransformationMode(
                Qt.TransformationMode.SmoothTransformation)
            ship.counterText.setPlainText(str(ship.count))
            ship.counterText.setFont(font)
            self.__scene.addItem(ship.shipItem)
            self.__scene.addItem(ship.counterItem)
            self.__scene.addItem(ship.counterText)

        self.__ghostShip.setTransformationMode(
            Qt.TransformationMode.SmoothTransformation)
        self.__ghostShip.setOpacity(0.7)

        pen = QPen()
        pen.setWidth(2)
        pen.setStyle(Qt.PenStyle.DashLine)
        pen.setJoinStyle(Qt.PenJoinStyle.RoundJoin)
        self.__placer.setPen(pen)

    def __setCell(self, x, y, cell_type):
        if cell_type not in self.__cellImages.keys():
            raise ValueError(
                f"Type is {cell_type}. Allowed \"intact\", \"miss\", \"hit\"")

        cellItem = self.__field[y * 10 + x]
        cellItem.setData(0, cell_type)
        pixmap = QPixmap.fromImage(self.__cellImages[cell_type])
        cellItem.setPixmap(pixmap)

    def __runAnimation(self, x, y, animation, looped=False):
        sprite = SpriteItem()
        sprite.setData(0, QPoint(x, y))
        spritePixmap = QPixmap.fromImage(self.__sprites[animation])

        sprite.setSpriteMap(spritePixmap, 60, 60, 5)
        sprite.setScale(self.__scaleFactor)
        sprite.setPos((x + 1) * self.tileSize, (y + 1) * self.tileSize)
        sprite.setZValue(10)

        self.__spriteAnimations.append(sprite)
        self.__scene.addItem(sprite)

        def removeAnimation():
            self.__scene.removeItem(sprite)
            self.__spriteAnimations.remove(sprite)
            sprite.stopAnimation()

        sprite.startAnimation(100, looped, removeAnimation)

    def __shootAround(self, ship: Ship):
        shipCells = []
        for i in range(ship.length):
            shipCells.append(ship.pos +
                             (QPoint(0, i) if ship.vertical else QPoint(i, 0)))
        cells = []

        for cell in shipCells:
            arounds = [
                cell + QPoint(i, j) for i in range(-1, 2)
                for j in range(-1, 2)
            ]
            for candidate in arounds:
                if 0 <= candidate.x() < 10 and 0 <= candidate.y() < 10:
                    if candidate not in cells:
                        cells.append(candidate)

        for cell in cells:
            if cell not in shipCells:
                self.__setCell(cell.x(), cell.y(), "miss")
                self.__runAnimation(cell.x(), cell.y(), "splash")
        log.debug(
            f"name: {ship.name} | length: {ship.length} | pos: {ship.pos} | vertical: {ship.vertical}"
        )

    def hasHeightForWidth(self):
        return True

    def heightForWidth(self, width):
        return width / self.__ratio

    def hideShipList(self):
        self.__ratio = self.RATIO_WITHOUT_SHIPLIST
        self.__scene.removeItem(self.__shipListItem)
        for _, ship in self.__shipList.items():
            self.__scene.removeItem(ship.shipItem)

        self.__adjustedToSize = None
        resize = QResizeEvent(self.size(), self.size())
        QApplication.postEvent(self, resize)

    def getPlacedShips(self):
        return self.__placedShips

    def placedShipsCount(self):
        return len(self.__placedShips)

    def hideShips(self):
        for ship in self.__placedShips:
            self.__scene.removeItem(ship)

    def removePlacedShips(self):
        if self.__shipListItem.scene() is None:
            return

        for ship in self.__placedShips:
            shipListItem = ship.data(1)
            shipListItem.count += 1
            shipListItem.counterText.setPlainText(str(shipListItem.count))
            self.__scene.removeItem(ship)

        self.__placedShips.clear()

    def shuffleShips(self):
        if self.__shipListItem.scene() is None:
            return

        self.removePlacedShips()

        def findPossibleCells(length, rotation):
            vertical = rotation.isVertical()
            if vertical == rotation.isHorizontal():
                raise Exception(
                    "Unknown state! Rotation is not horizontal and not vertical."
                )  # wtf

            width = 1 if vertical else length
            height = length if vertical else 1

            cells = []

            for x in range(10):
                for y in range(10):
                    if QRect(0, 0, 10, 10) != QRect(0, 0, 10, 10).united(
                            QRect(x, y, width, height)):
                        break
                    if self.__validatePosition(x, y, width, height):
                        cells.append(QPoint(x, y))

            return cells

        shipList = list(self.__shipList.values())
        shipList.sort(key=lambda ship: ship.length, reverse=True)
        for shipItem in shipList:
            for i in range(shipItem.count):
                rot = random.choice(list(Rotation))
                cells = findPossibleCells(shipItem.length, rot)

                if not cells:
                    rot = rot.next()
                    cells = findPossibleCells(shipItem.length, rot)

                if not cells:
                    return

                cell = random.choice(cells)
                self.__placeShip(shipItem, cell.x(), cell.y(), rot)

    def resizeEvent(self, event):
        size = event.size()
        if size == self.__adjustedToSize:
            return

        self.__adjustedToSize = size

        nowWidth = size.width()
        nowHeight = size.height()

        width = min(nowWidth, nowHeight * self.__ratio)
        height = min(nowHeight, nowWidth / self.__ratio)

        h_margin = round((nowWidth - width) / 2) - 2
        v_margin = round((nowHeight - height) / 2) - 2

        self.setContentsMargins(
            QMargins(h_margin, v_margin, h_margin, v_margin))
        self.__resizeScene()

    def scanEffect(self, x, y):
        """
        :return: True on success, False otherwise
        """
        if self.__scanEffect:
            return False

        def scanFinisedCallback():
            self.__scene.removeItem(self.__scanEffect)
            del self.__scanEffect
            self.__scanEffect = None

            target = FadingPixmapItem(self.__targetPixmap)
            target.setPos((x + 1) * self.tileSize, (y + 1) * self.tileSize)
            target.setScale(self.__scaleFactor)
            target.setData(0, (x, y))
            self.__targets.append(target)
            self.__scene.addItem(target)

        self.__scanEffect = FloatingGradientItem(
            QRectF(self.tileSize, self.tileSize, self.__originalTileSize * 10,
                   self.__originalTileSize * 10), scanFinisedCallback)

        self.__scanEffect.setScale(self.__scaleFactor)

        self.__scanEffect.setBackwards(True)
        self.__scene.addItem(self.__scanEffect)
        return True

    def __resizeScene(self):
        width = self.__ui.graphicsView.width()
        height = self.__ui.graphicsView.height()
        self.__scene.setSceneRect(0, 0, width, height)

        self.tileSize = min(width / 11, height / (11 / self.__ratio))
        self.__scaleFactor = self.tileSize / self.__originalTileSize

        for i, cell in enumerate(self.__field):
            x = i % 10
            y = i // 10
            cell.setScale(self.__scaleFactor)
            cell.setPos((x + 1) * self.tileSize, (y + 1) * self.tileSize)

        for sprite in self.__spriteAnimations:
            pos = sprite.data(0)
            sprite.setPos((pos.x() + 1) * self.tileSize,
                          (pos.y() + 1) * self.tileSize)
            sprite.setScale(self.__scaleFactor)

        for i in range(10):
            letter = self.__letters[i]
            letter.setScale(self.__scaleFactor)
            offsetX = (self.tileSize -
                       letter.boundingRect().width() * self.__scaleFactor) / 2
            offsetY = (self.tileSize -
                       letter.boundingRect().height() * self.__scaleFactor) / 2
            letter.setPos((i + 1) * self.tileSize + offsetX, offsetY)

            number = self.__numbers[i]
            number.setScale(self.__scaleFactor)
            offsetX = (self.tileSize -
                       number.boundingRect().width() * self.__scaleFactor) / 2
            offsetY = (self.tileSize -
                       number.boundingRect().height() * self.__scaleFactor) / 2
            number.setPos(offsetX, (i + 1) * self.tileSize + offsetY)

        xPos = 0
        for _, ship in self.__shipList.items():
            xPos += (ship.length - 1)
            xOffset = xPos * self.tileSize

            ship.shipItem.setScale(self.__scaleFactor)
            ship.shipItem.setPos(self.tileSize + xOffset,
                                 self.tileSize * (12 + self.EPS))

            ship.counterItem.setScale(self.__scaleFactor)
            ship.counterItem.setPos(self.tileSize + xOffset,
                                    self.tileSize * (12.65 + self.EPS))

            counterSize = ship.counterItem.boundingRect()
            textSize = ship.counterText.boundingRect()
            textXOffset = (counterSize.width() -
                           textSize.width()) * self.__scaleFactor / 2
            textYOffset = (counterSize.height() -
                           textSize.height()) * self.__scaleFactor / 2
            textX = ship.counterItem.pos().x() + textXOffset
            textY = ship.counterItem.pos().y() + textYOffset
            ship.counterText.setScale(self.__scaleFactor)
            ship.counterText.setPos(textX, textY)

        for ship in self.__placedShips:
            mapPos = ship.data(2)
            ship.setPos((mapPos.x() + 1) * self.tileSize,
                        (mapPos.y() + 1) * self.tileSize)
            ship.setScale(self.__scaleFactor)

        for target in self.__targets:
            x, y = target.data(0)
            target.setPos((x + 1) * self.tileSize, (y + 1) * self.tileSize)
            target.setScale(self.__scaleFactor)

        if self.__scanEffect:
            self.__scanEffect.setPos(self.tileSize, self.tileSize)
            self.__scanEffect.setScale(self.__scaleFactor)

        shipListX = self.tileSize
        shipListY = self.tileSize * (11 + self.EPS)
        self.__shipListItem.setScale(self.__scaleFactor)
        self.__shipListItem.setPos(shipListX, shipListY)
        self.__ghostShip.setScale(self.__scaleFactor)

    def eventFilter(self, obj, event):
        if obj is self.__ui.graphicsView.viewport():
            if event.type() == QEvent.MouseButtonPress:
                self.__viewportMousePressEvent(event)
            elif event.type() == QEvent.MouseButtonRelease:
                self.__viewportMouseReleaseEvent(event)
            elif event.type() == QEvent.MouseMove:
                self.__viewportMouseMoveEvent(event)

        return super().eventFilter(obj, event)

    def sceneToMap(self, x, y):
        x -= self.tileSize
        y -= self.tileSize
        x //= self.tileSize
        y //= self.tileSize
        return int(x), int(y)

    def __initGhostShip(self, ship, pos):
        self.__ghostShip.setPixmap(QPixmap.fromImage(ship.image))
        self.__ghostShip.setPos(pos)
        self.__ghostShip.setRotation(0)

        width = self.__ghostShip.boundingRect().width()
        height = self.__ghostShip.boundingRect().height()
        self.__ghostShip.setOffset(-width / 2, -height / 2)
        self.__ghostShip.setData(0, Rotation.UP)
        self.__ghostShip.setData(1, ship)

        self.__placer.setRect(0, 0, self.tileSize, self.tileSize * ship.length)
        self.__placer.setZValue(50)

        self.__scene.addItem(self.__ghostShip)
        self.__ghostShip.setZValue(100)

    def __rotateGhostShip(self, rotation=None):
        rotation = rotation if rotation else self.__ghostShip.data(0).next()
        self.__ghostShip.setData(0, rotation)
        self.__ghostShip.setRotation(rotation.value)

        placerRect = self.__placer.rect()
        maxSide = max(placerRect.width(), placerRect.height())
        minSide = min(placerRect.width(), placerRect.height())

        if rotation.isHorizontal():
            self.__placer.setRect(0, 0, maxSide, minSide)
        elif rotation.isVertical():
            self.__placer.setRect(0, 0, minSide, maxSide)
        else:
            raise Exception(
                "Unknown state! Rotation is not horizontal and not vertical."
            )  # wtf
        self.__validatePlacer()

    def __ghostShipLongSurface(self):
        pos = self.__ghostShip.pos()
        x = pos.x()
        y = pos.y()
        rot: Rotation = self.__ghostShip.data(0)
        length = self.__ghostShip.data(1).length
        if rot.isHorizontal():
            x -= self.tileSize * length / 2
            return x, y

        if rot.isVertical():
            y -= self.tileSize * length / 2
            return x, y

    def __validatePosition(self, x, y, width=1, height=1):
        positionRect = QRectF((x + 1) * self.tileSize, (y + 1) * self.tileSize,
                              self.tileSize * width, self.tileSize * height)

        isPlacerValid = True
        for ship in self.__placedShips:
            shipRect = ship.mapRectToScene(ship.boundingRect()).adjusted(
                -self.tileSize / 2, -self.tileSize / 2, self.tileSize / 2,
                self.tileSize / 2)
            isPlacerValid = not positionRect.intersects(shipRect)
            if not isPlacerValid:
                break
        return isPlacerValid

    def __validatePlacer(self):
        sceneX, sceneY = self.__ghostShipLongSurface()
        x, y = self.sceneToMap(sceneX, sceneY)
        self.__placer.setPos((x + 1) * self.tileSize, (y + 1) * self.tileSize)

        permittedArea = QRectF(self.__ui.graphicsView.viewport().geometry())
        permittedArea.setTopLeft(QPointF(self.tileSize, self.tileSize))
        permittedArea.setBottomRight(
            QPointF(self.tileSize * 12, self.tileSize * 12))
        placerSize = self.__placer.boundingRect()
        placerRect = QRectF(sceneX, sceneY, placerSize.width(),
                            placerSize.height())

        isPlacerValid = False
        # first validation - ship can be placed inside game field
        if permittedArea.contains(self.__ghostShip.pos(
        )) and permittedArea == permittedArea.united(placerRect):
            if self.__placer.scene() == None:
                self.__scene.addItem(self.__placer)
            x, y = self.sceneToMap(sceneX, sceneY)
            self.__placer.setPos((x + 1) * self.tileSize,
                                 (y + 1) * self.tileSize)
            isPlacerValid = True

        else:
            if self.__placer.scene() == self.__scene:
                self.__scene.removeItem(self.__placer)

        # second validation - placer does not intersect with other ships
        if isPlacerValid:
            isPlacerValid = self.__validatePosition(
                x, y,
                placerSize.width() / self.tileSize,
                placerSize.height() / self.tileSize)

        # set color of placer
        pen = self.__placer.pen()
        if isPlacerValid:
            pen.setColor(Qt.GlobalColor.darkGreen)
        else:
            pen.setColor(Qt.GlobalColor.red)
        self.__placer.setPen(pen)
        self.__placer.setData(0, isPlacerValid)

    def __placeShip(self, shipListItem, x, y, rotation):
        sceneX, sceneY = (x + 1) * self.tileSize, (y + 1) * self.tileSize

        shipListItem.count -= 1
        shipListItem.counterText.setPlainText(str(shipListItem.count))

        pixmap = QPixmap(shipListItem.image).transformed(QTransform().rotate(
            (rotation.value)))
        placedShip = QGraphicsPixmapItem(pixmap)
        placedShip.setData(0, rotation)
        placedShip.setData(1, shipListItem)
        placedShip.setData(2, QPoint(x, y))  # position in map coordinates

        placedShip.setPos(sceneX, sceneY)
        placedShip.setTransformationMode(
            Qt.TransformationMode.SmoothTransformation)
        placedShip.setScale(self.__scaleFactor)

        self.__placedShips.append(placedShip)
        self.__scene.addItem(placedShip)

    def __placeGhostShip(self):
        isPlacingPermitted = self.__placer.data(0)
        if isPlacingPermitted:
            sceneX = self.__placer.pos().x() + self.tileSize / 2
            sceneY = self.__placer.pos().y() + self.tileSize / 2
            mapX, mapY = self.sceneToMap(sceneX, sceneY)
            rotation = self.__ghostShip.data(0)
            if rotation.isVertical():
                vertical = True
            elif rotation.isHorizontal():
                vertical = False
            else:
                raise Exception(
                    "Unknown state! Rotation is not horizontal and not vertical."
                )  # wtf

            shipListItem = self.__ghostShip.data(1)
            self.__placeShip(shipListItem, mapX, mapY, rotation)

            log.debug(
                f"ship \"{shipListItem.name}\"; "
                f"position ({mapX}, {mapY}); "
                f"oriented {'vertically' if vertical else 'horizontally'}")

            self.shipPlaced.emit(
                Ship(name=shipListItem.name,
                     length=shipListItem.length,
                     pos=QPoint(mapX, mapY),
                     vertical=vertical))

    def __viewportMousePressEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            if self.__shipListItem.scene():
                # check press on shiplist
                shipUnderMouse = None
                for _, ship in self.__shipList.items():
                    if ship.shipItem.isUnderMouse():
                        shipUnderMouse = ship
                        break

                # check press on field
                rotation = Rotation.RIGHT
                if shipUnderMouse == None:
                    for ship in self.__placedShips:
                        if ship.isUnderMouse():
                            rotation = ship.data(0)
                            shipListItem = ship.data(1)

                            if shipListItem.count == 0:
                                shipListItem.shipItem.setGraphicsEffect(None)

                            shipListItem.count += 1
                            shipListItem.counterText.setPlainText(
                                str(shipListItem.count))
                            shipUnderMouse = shipListItem
                            self.__placedShips.remove(ship)
                            self.__scene.removeItem(ship)
                            break

                # if ship grabbed
                if shipUnderMouse and shipUnderMouse.count > 0:
                    self.__initGhostShip(shipUnderMouse, event.pos())
                    self.__rotateGhostShip(rotation)
                    self.__dragShip = True

            x, y = self.sceneToMap(event.pos().x(), event.pos().y())
            if x >= 0 and x < 10 and y >= 0 and y < 10:
                if self.controller.isBot:
                    return
                self.controller.emitHit(x, y)

        if event.button() == Qt.MouseButton.RightButton:
            if self.__dragShip:
                self.__rotateGhostShip()

    def __viewportMouseReleaseEvent(self, event):
        if event.button() == Qt.MouseButton.LeftButton:
            if self.__dragShip:
                self.__scene.removeItem(self.__ghostShip)
                self.__dragShip = False
            if self.__placer.scene() != None:
                self.__scene.removeItem(self.__placer)

            # self.__placeShip()
            self.__placeGhostShip()
            self.__placer.setData(0, False)

    def __viewportMouseMoveEvent(self, event):
        if self.__dragShip:
            self.__ghostShip.setPos(event.pos())

            permittedArea = QRectF(
                self.__ui.graphicsView.viewport().geometry())
            permittedArea.setTopLeft(QPointF(self.tileSize, self.tileSize))

            # stop dragging ship if mouse out of field
            # if not permittedArea.contains(event.pos()):
            #     self.__scene.removeItem(self.__ghostShip)
            #     self.__dragShip = False

            self.__validatePlacer()

    def __accept(self, x, y, hit_type: CellState):
        log.debug(
            f" -- ACCEPTED -- hit on point ({x}, {y}) hit type: {hit_type}")
        cell = self.__field[y * 10 + x]

        if cell.data(0) != "intact":
            return
        if hit_type in [CellState.HIT, CellState.KILLED]:
            self.__setCell(x, y, 'hit')
            self.__runAnimation(x, y, "explosion", looped=True)
            for target in self.__targets:
                if (x, y) == target.data(0):
                    self.__scene.removeItem(target)
                    self.__targets.remove(target)
                    break
        elif hit_type in [CellState.MISS]:
            self.__setCell(x, y, 'miss')
            self.__runAnimation(x, y, "splash", looped=False)

        if hit_type == CellState.KILLED:
            for ship in self.__placedShips:
                rotation = ship.data(0)
                length = ship.data(1).length
                position = ship.data(2)
                width = 1 if rotation.isVertical() else length
                height = length if rotation.isVertical() else 1
                rect = QRect(position.x(), position.y(), width, height)
                if rect.contains(x, y):
                    self.__scene.addItem(ship)

    def __decline(self, x, y):
        log.debug(f"declined hit on point ({x}, {y})")
Example #2
0
class BankNodeItem (NodeItem):
    maincolor = FlPalette.bank
    altcolor = FlPalette.bankvar
    label = "%s Bank"
    
    def __init__ (self, nodeobj, parent=None, view=None, state=1):
        super().__init__(nodeobj, parent, view, state)
        self.rect = QRectF()
        self.setZValue(-1)
        self.updatecomment()
        self.updatebanktype()
        self.updatebankmode()
    
    def nudgechildren(self):
        super().nudgechildren()
        for sub in self.sublist():
            sub.setrank(self)
    
    def sublist (self):
        ID = self.nodeobj.ID
        itemtable = self.view.itemtable
        if self.state == 1 and ID in itemtable and not self.iscollapsed():
            children = []
            for child in self.nodeobj.subnodes:
                if child in itemtable[ID]:
                    item = itemtable[ID][child]
                else:
                    continue
                if item.state > -1:
                    children.append(item)
            return children
        else:
            return []
    
    def treeposition (self, ranks=None):
        self.updatelayout(external=True)
        return super().treeposition(ranks)
    
    def graphicsetup (self):
        super().graphicsetup()
        darkbrush = QBrush(FlPalette.bg)
        nopen = QPen(0)
        viewport = self.view.viewport()
        
        self.btypeicon = QGraphicsPixmapItemCond(self.icon, self, viewport)
        self.btypeicon.setPos(self.iconx-self.style.itemmargin-self.iwidth, self.style.itemmargin)
        self.iconx = self.btypeicon.x()
        self.fggroup.addToGroup(self.btypeicon)
        
        self.centerbox = QGraphicsRectItem(self)
        self.centerbox.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
        self.centerbox.setRect(QRectF())
        self.centerbox.setBrush(darkbrush)
        self.centerbox.setPen(nopen)
        self.centerbox.setPos(0, self.nodelabel.y()+self.nodelabel.boundingRect().height()+self.style.itemmargin*2)
        self.fggroup.addToGroup(self.centerbox)
    
    def updatebanktype (self):
        types = {"talk": "(T)", "response": "(R)", "": ""}
        self.nodelabel.setText("%s Bank %s" % (self.realid(), types[self.nodeobj.banktype]))
    
    def updatebankmode (self):
        icons = {"First": "bank-first", "All": "bank-all", "Append": "bank-append", "": "blank"}
        pixmap = self.pixmap("images/%s.png" % icons[self.nodeobj.bankmode])
        self.btypeicon.setPixmap(pixmap)
        if self.nodeobj.bankmode:
            self.btypeicon.setToolTip("Bank mode: %s" % self.nodeobj.bankmode)
        else:
            self.btypeicon.setToolTip("")
    
    def updatecenterbox (self):
        verticalpos = self.centerbox.y()
        maxwidth = self.style.nodetextwidth
        subnodes = self.sublist()
        for subnode in subnodes:
            if subnode.nodeobj.typename == "bank":
                subnode.updatelayout(external=True)
            noderect = subnode.boundingRect()
            nodeheight = noderect.height()
            nodewidth = noderect.width()
            subnode.show()
            subnode.yoffset = self.mapToScene(0,verticalpos + nodeheight/2+self.style.activemargin).y()-self.y_bottom()
            verticalpos += nodeheight+self.style.activemargin*2
            maxwidth = max(maxwidth, nodewidth)
        centerrect = self.centerbox.rect()
        centerrect.setWidth(maxwidth+self.style.selectmargin*2)
        centerrect.setHeight(verticalpos-self.centerbox.y())
        self.centerbox.setRect(centerrect)
        centerrect = self.centerbox.mapRectToParent(centerrect)
        
        self.comment.setY(centerrect.bottom()+self.style.itemmargin)
    
    def updatelayout (self, external=False):
        subnodes = self.sublist()
        if self.iscollapsed():
            rect = self.nodelabel.mapRectToParent(self.nodelabel.boundingRect())
        else:
            self.updatecenterbox()
            rect = self.fggroup.childrenBoundingRect()
        mainrect = rect.marginsAdded(self.style.banknodemargins)
        self.mainbox.setRect(mainrect)
        self.shadowbox.setRect(mainrect)
        self.selectbox.setRect(mainrect.marginsAdded(self.style.selectmargins))
        activerect = mainrect.marginsAdded(self.style.activemargins)
        self.activebox.setRect(activerect)
        oldypos = self.centerbox.mapToScene(self.centerbox.pos()).y()
        self.graphgroup.setPos(-activerect.width()//2-activerect.x(), -activerect.height()//2-activerect.y())
        newypos = self.centerbox.mapToScene(self.centerbox.pos()).y()
        for subnode in subnodes:
            subnode.yoffset += newypos - oldypos
            subnode.setY(self.y())
        self.prepareGeometryChange()
        self.rect = self.graphgroup.mapRectToParent(mainrect)
        if not external:
            self.view.updatelayout()
    
    def setY (self, y):
        super().setY(y)
        for subnode in self.sublist():
            subnode.setY(y)
    
    def contextMenuEvent (self, event):
        menu = QMenu()
        if self.isselected():
            window = FlGlob.mainwindow
            menu.addAction(window.actions["collapse"])
            if self.isghost():
                menu.addAction(window.actions["selectreal"])
            menu.addAction(window.actions["copynode"])
            menu.addMenu(window.subnodemenu)
            menu.addMenu(window.addmenu)
            menu.addAction(window.actions["moveup"])
            menu.addAction(window.actions["movedown"])
            menu.addAction(window.actions["parentswap"])
            menu.addAction(window.actions["unlinknode"])
            menu.addAction(window.actions["unlinkstree"])
            menu.addAction(window.actions["settemplate"])
            menu.addMenu(window.transformmenu)
        if not menu.isEmpty():
            menu.exec_(event.screenPos())
Example #3
0
class CameraView(QGraphicsObject):

    font: QFont = QFont("monospace", 16)
    stick_link_requested = pyqtSignal(StickWidget)
    stick_context_menu = pyqtSignal('PyQt_PyObject', 'PyQt_PyObject')
    stick_widgets_out_of_sync = pyqtSignal('PyQt_PyObject')
    visibility_toggled = pyqtSignal()
    synchronize_clicked = pyqtSignal('PyQt_PyObject')
    previous_photo_clicked = pyqtSignal('PyQt_PyObject')
    next_photo_clicked = pyqtSignal('PyQt_PyObject')
    sync_confirm_clicked = pyqtSignal('PyQt_PyObject')
    sync_cancel_clicked = pyqtSignal('PyQt_PyObject')
    first_photo_clicked = pyqtSignal('PyQt_PyObject')
    enter_pressed = pyqtSignal()

    def __init__(self, scale: float, parent: Optional[QGraphicsItem] = None):
        QGraphicsObject.__init__(self, parent)
        self.current_highlight_color = QColor(0, 0, 0, 0)
        self.current_timer = -1
        self.scaling = scale
        self.pixmap = QGraphicsPixmapItem(self)
        self.stick_widgets: List[StickWidget] = []
        self.link_cam_text = QGraphicsSimpleTextItem("Link camera...", self)
        self.link_cam_text.setZValue(40)
        self.link_cam_text.setVisible(False)
        self.link_cam_text.setFont(CameraView.font)
        self.link_cam_text.setPos(0, 0)
        self.link_cam_text.setPen(QPen(QColor(255, 255, 255, 255)))
        self.link_cam_text.setBrush(QBrush(QColor(255, 255, 255, 255)))

        self.show_add_buttons = False
        self.camera = None

        self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, True)
        self.show_stick_widgets = False
        self.setAcceptHoverEvents(True)
        self.stick_edit_mode = False

        self.original_pixmap = self.pixmap.pixmap()

        self.hovered = False

        self.mode = 0  # TODO make enum Mode
        self.click_handler = None
        self.double_click_handler: Callable[[int, int], None] = None

        self.stick_widget_mode = StickMode.Display

        self.highlight_animation = QPropertyAnimation(self, b"highlight_color")
        self.highlight_animation.setEasingCurve(QEasingCurve.Linear)
        self.highlight_animation.valueChanged.connect(
            self.handle_highlight_color_changed)
        self.highlight_rect = QGraphicsRectItem(self)
        self.highlight_rect.setZValue(4)
        self.highlight_rect.setPen(QPen(QColor(0, 0, 0, 0)))
        self.title_btn = Button('btn_title', '', parent=self)
        self.title_btn.setFlag(QGraphicsItem.ItemIgnoresTransformations, False)
        self.title_btn.setZValue(5)
        self.title_btn.setVisible(False)

        self.sticks_without_width: List[Stick] = []
        self.current_image_name: str = ''
        self.control_widget = ControlWidget(parent=self)
        self.control_widget.setFlag(QGraphicsItem.ItemIgnoresTransformations,
                                    False)
        self.control_widget.setVisible(True)
        self._connect_control_buttons()
        self.image_available = True
        self.blur_eff = QGraphicsBlurEffect()
        self.blur_eff.setBlurRadius(5.0)
        self.blur_eff.setEnabled(False)
        self.pixmap.setGraphicsEffect(self.blur_eff)
        self.overlay_message = QGraphicsSimpleTextItem('not available',
                                                       parent=self)
        font = self.title_btn.font
        font.setPointSize(48)
        self.overlay_message.setFont(font)
        self.overlay_message.setBrush(QBrush(QColor(200, 200, 200, 200)))
        self.overlay_message.setPen(QPen(QColor(0, 0, 0, 200), 2.0))
        self.overlay_message.setVisible(False)
        self.overlay_message.setZValue(6)

        self.stick_box = QGraphicsRectItem(parent=self)
        self.stick_box.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.stick_box.setVisible(False)
        self.stick_box_start_pos = QPoint()

    def _connect_control_buttons(self):
        self.control_widget.synchronize_btn.clicked.connect(
            lambda: self.synchronize_clicked.emit(self))
        self.control_widget.prev_photo_btn.clicked.connect(
            lambda: self.previous_photo_clicked.emit(self))
        self.control_widget.next_photo_btn.clicked.connect(
            lambda: self.next_photo_clicked.emit(self))
        self.control_widget.accept_btn.clicked.connect(
            lambda: self.sync_confirm_clicked.emit(self))
        self.control_widget.cancel_btn.clicked.connect(
            lambda: self.sync_cancel_clicked.emit(self))
        self.control_widget.first_photo_btn.clicked.connect(
            lambda: self.first_photo_clicked.emit(self))

    def paint(self, painter: QPainter,
              option: PyQt5.QtWidgets.QStyleOptionGraphicsItem,
              widget: QWidget):
        if self.pixmap.pixmap().isNull():
            return
        painter.setRenderHint(QPainter.Antialiasing, True)

        if self.show_stick_widgets:
            brush = QBrush(QColor(255, 255, 255, 100))
            painter.fillRect(self.boundingRect(), brush)

        if self.mode and self.hovered:
            pen = QPen(QColor(0, 125, 200, 255))
            pen.setWidth(4)
            painter.setPen(pen)

    def boundingRect(self) -> PyQt5.QtCore.QRectF:
        return self.pixmap.boundingRect().united(
            self.title_btn.boundingRect().translated(self.title_btn.pos()))

    def initialise_with(self, camera: Camera):
        if self.camera is not None:
            self.camera.stick_added.disconnect(self.handle_stick_created)
            self.camera.sticks_added.disconnect(self.handle_sticks_added)
            self.camera.stick_removed.disconnect(self.handle_stick_removed)
            self.camera.sticks_removed.disconnect(self.handle_sticks_removed)
            self.camera.stick_changed.disconnect(self.handle_stick_changed)
        self.camera = camera
        self.prepareGeometryChange()
        self.set_image(camera.rep_image, Path(camera.rep_image_path).name)
        self.title_btn.set_label(self.camera.folder.name)
        self.title_btn.set_height(46)
        self.title_btn.fit_to_contents()
        self.title_btn.set_width(int(self.boundingRect().width()))
        self.title_btn.setPos(0, self.boundingRect().height())
        self.control_widget.title_btn.set_label(self.camera.folder.name)
        self.camera.stick_added.connect(self.handle_stick_created)
        self.camera.sticks_added.connect(self.handle_sticks_added)
        self.camera.stick_removed.connect(self.handle_stick_removed)
        self.camera.sticks_removed.connect(self.handle_sticks_removed)
        self.camera.stick_changed.connect(self.handle_stick_changed)

        self.control_widget.set_font_height(32)
        self.control_widget.set_widget_height(
            self.title_btn.boundingRect().height())
        self.control_widget.set_widget_width(int(self.boundingRect().width()))
        self.control_widget.setPos(0,
                                   self.pixmap.boundingRect().height()
                                   )  #self.boundingRect().height())
        self.control_widget.set_mode('view')
        self.update_stick_widgets()

    def set_image(self,
                  img: Optional[np.ndarray] = None,
                  image_name: Optional[str] = None):
        if img is None:
            self.show_overlay_message('not available')
            return
        self.show_overlay_message(None)
        self.prepareGeometryChange()
        barray = QByteArray(img.tobytes())
        image = QImage(barray, img.shape[1], img.shape[0],
                       QImage.Format_BGR888)
        self.original_pixmap = QPixmap.fromImage(image)
        self.pixmap.setPixmap(self.original_pixmap)
        self.highlight_rect.setRect(self.boundingRect())
        self.current_image_name = image_name

    def update_stick_widgets(self):
        stick_length = 60
        for stick in self.camera.sticks:
            sw = StickWidget(stick, self.camera, self)
            sw.set_mode(self.stick_widget_mode)
            self.connect_stick_widget_signals(sw)
            self.stick_widgets.append(sw)
            stick_length = stick.length_cm
        self.update_stick_box()
        self.scene().update()

    def scale_item(self, factor: float):
        self.prepareGeometryChange()
        pixmap = self.original_pixmap.scaledToHeight(
            int(self.original_pixmap.height() * factor))
        self.pixmap.setPixmap(pixmap)
        self.__update_title()

    def set_show_stick_widgets(self, value: bool):
        for sw in self.stick_widgets:
            sw.setVisible(value)
        self.scene().update()

    def hoverEnterEvent(self, e: QGraphicsSceneHoverEvent):
        self.hovered = True
        self.scene().update(self.sceneBoundingRect())

    def hoverLeaveEvent(self, e: QGraphicsSceneHoverEvent):
        self.hovered = False
        self.scene().update(self.sceneBoundingRect())

    def mousePressEvent(self, e: QGraphicsSceneMouseEvent):
        super().mousePressEvent(e)

    def mouseReleaseEvent(self, e: QGraphicsSceneMouseEvent):
        if self.mode == 1:
            self.click_handler(self.camera)

    def mouseDoubleClickEvent(self, event: QGraphicsSceneMouseEvent):
        if self.stick_widget_mode == StickMode.EditDelete:
            x = event.pos().toPoint().x()
            y = event.pos().toPoint().y()
            stick = self.camera.create_new_sticks(
                [(np.array([[x, y - 50], [x, y + 50]]), 3)],
                self.current_image_name)[
                    0]  #self.dataset.create_new_stick(self.camera)
            self.sticks_without_width.append(stick)

    def set_button_mode(self, click_handler: Callable[[Camera], None],
                        data: str):
        self.mode = 1  # TODO make a proper ENUM
        self.click_handler = lambda c: click_handler(c, data)

    def set_display_mode(self):
        self.mode = 0  # TODO make a proper ENUM
        self.click_handler = None

    def _remove_stick_widgets(self):
        for sw in self.stick_widgets:
            sw.setParentItem(None)
            self.scene().removeItem(sw)
            sw.deleteLater()
        self.stick_widgets.clear()

    def handle_stick_created(self, stick: Stick):
        if stick.camera_id != self.camera.id:
            return
        sw = StickWidget(stick, self.camera, self)
        sw.set_mode(self.stick_widget_mode)
        self.connect_stick_widget_signals(sw)
        self.stick_widgets.append(sw)
        self.stick_widgets_out_of_sync.emit(self)
        self.update()

    def handle_stick_removed(self, stick: Stick):
        if stick.camera_id != self.camera.id:
            return
        stick_widget = next(
            filter(lambda sw: sw.stick.id == stick.id, self.stick_widgets))
        self.disconnect_stick_widget_signals(stick_widget)
        self.stick_widgets.remove(stick_widget)
        stick_widget.setParentItem(None)
        self.scene().removeItem(stick_widget)
        stick_widget.deleteLater()
        self.update()

    def handle_sticks_removed(self, sticks: List[Stick]):
        if sticks[0].camera_id != self.camera.id:
            return
        for stick in sticks:
            to_remove: StickWidget = None
            for sw in self.stick_widgets:
                if sw.stick.id == stick.id:
                    to_remove = sw
                    break
            self.stick_widgets.remove(to_remove)
            to_remove.setParentItem(None)
            if self.scene() is not None:
                self.scene().removeItem(to_remove)
            to_remove.deleteLater()
        self.update()

    def handle_sticks_added(self, sticks: List[Stick]):
        if len(sticks) == 0:
            return
        if sticks[0].camera_id != self.camera.id:
            return
        for stick in sticks:
            sw = StickWidget(stick, self.camera, self)
            sw.set_mode(self.stick_widget_mode)
            self.connect_stick_widget_signals(sw)
            self.stick_widgets.append(sw)
        self.update_stick_box()
        self.stick_widgets_out_of_sync.emit(self)
        self.update()

    def connect_stick_widget_signals(self, stick_widget: StickWidget):
        stick_widget.delete_clicked.connect(
            self.handle_stick_widget_delete_clicked)
        stick_widget.stick_changed.connect(self.handle_stick_widget_changed)
        stick_widget.link_initiated.connect(self.handle_stick_link_initiated)
        stick_widget.right_clicked.connect(
            self.handle_stick_widget_context_menu)

    def disconnect_stick_widget_signals(self, stick_widget: StickWidget):
        stick_widget.delete_clicked.disconnect(
            self.handle_stick_widget_delete_clicked)
        stick_widget.stick_changed.disconnect(self.handle_stick_widget_changed)
        stick_widget.link_initiated.disconnect(
            self.handle_stick_link_initiated)
        stick_widget.right_clicked.disconnect(
            self.handle_stick_widget_context_menu)

    def handle_stick_widget_delete_clicked(self, stick: Stick):
        self.camera.remove_stick(stick)

    def set_stick_widgets_mode(self, mode: StickMode):
        self.stick_widget_mode = mode
        for sw in self.stick_widgets:
            sw.set_mode(mode)
        self.set_stick_edit_mode(mode == StickMode.Edit)

    def handle_stick_widget_changed(self, stick_widget: StickWidget):
        self.camera.stick_changed.emit(stick_widget.stick)

    def handle_stick_changed(self, stick: Stick):
        if stick.camera_id != self.camera.id:
            return
        sw = next(
            filter(lambda _sw: _sw.stick.id == stick.id, self.stick_widgets))
        sw.adjust_line()
        sw.update_tooltip()

    def handle_stick_link_initiated(self, stick_widget: StickWidget):
        self.stick_link_requested.emit(stick_widget)

    def get_top_left(self) -> QPointF:
        return self.sceneBoundingRect().topLeft()

    def get_top_right(self) -> QPointF:
        return self.sceneBoundingRect().topRight()

    def highlight(self, color: Optional[QColor]):
        if color is None:
            self.highlight_animation.stop()
            self.highlight_rect.setVisible(False)
            return
        alpha = color.alpha()
        color.setAlpha(0)
        self.highlight_animation.setStartValue(color)
        self.highlight_animation.setEndValue(color)
        color.setAlpha(alpha)
        self.highlight_animation.setKeyValueAt(0.5, color)
        self.highlight_animation.setDuration(2000)
        self.highlight_animation.setLoopCount(-1)
        self.highlight_rect.setPen(QPen(color))
        self.highlight_rect.setVisible(True)
        self.highlight_animation.start()

    @pyqtProperty(QColor)
    def highlight_color(self) -> QColor:
        return self.current_highlight_color

    @highlight_color.setter
    def highlight_color(self, color: QColor):
        self.current_highlight_color = color

    def handle_highlight_color_changed(self, color: QColor):
        self.highlight_rect.setBrush(QBrush(color))
        self.update()

    def handle_stick_widget_context_menu(self, sender: Dict[str, StickWidget]):
        self.stick_context_menu.emit(sender['stick_widget'], self)

    def show_overlay_message(self, msg: Optional[str]):
        if msg is None:
            self.overlay_message.setVisible(False)
            self.blur_eff.setEnabled(False)
            return
        self.overlay_message.setText(msg)
        self.overlay_message.setPos(
            self.pixmap.boundingRect().center() -
            QPointF(0.5 * self.overlay_message.boundingRect().width(), 0.5 *
                    self.overlay_message.boundingRect().height()))
        self.overlay_message.setVisible(True)
        self.blur_eff.setEnabled(True)

    def show_status_message(self, msg: Optional[str]):
        if msg is None:
            self.control_widget.set_title_text(self.camera.folder.name)
        else:
            self.control_widget.set_title_text(msg)

    def update_stick_box(self):
        left = 9000
        right = 0
        top = 9000
        bottom = -1

        for stick in self.camera.sticks:
            left = min(left, min(stick.top[0], stick.bottom[0]))
            right = max(right, max(stick.top[0], stick.bottom[0]))
            top = min(top, min(stick.top[1], stick.bottom[1]))
            bottom = max(bottom, max(stick.top[1], stick.bottom[1]))
        left -= 100
        right += 100
        top -= 100
        bottom += 100
        self.stick_box.setRect(left, top, right - left, bottom - top)
        pen = QPen(QColor(0, 100, 200, 200))
        pen.setWidth(2)
        pen.setStyle(Qt.DashLine)
        self.stick_box.setPen(pen)

    def set_stick_edit_mode(self, is_edit: bool):
        if is_edit:
            self.update_stick_box()
            self.stick_box_start_pos = self.stick_box.pos()
            for sw in self.stick_widgets:
                sw.setParentItem(self.stick_box)
        else:
            offset = self.stick_box.pos() - self.stick_box_start_pos
            for sw in self.stick_widgets:
                stick = sw.stick
                stick.translate(np.array([int(offset.x()), int(offset.y())]))
                sw.setParentItem(self)
                sw.set_stick(stick)
            self.stick_box.setParentItem(None)
            self.stick_box = QGraphicsRectItem(self)
            self.stick_box.setFlag(QGraphicsItem.ItemIsMovable, True)
            self.stick_box.setVisible(False)
        self.stick_box.setVisible(is_edit)

    def keyPressEvent(self, event: QKeyEvent) -> None:
        pass

    def keyReleaseEvent(self, event: QKeyEvent) -> None:
        if event.key() in [Qt.Key_Right, Qt.Key_Tab, Qt.Key_Space]:
            self.control_widget.next_photo_btn.click_button(True)
        elif event.key() in [Qt.Key_Left]:
            self.control_widget.prev_photo_btn.click_button(True)
        elif event.key() == Qt.Key_S:
            self.enter_pressed.emit()
Example #4
0
class SelectAreaDialog(QDialog):

    finish_selecting_area = pyqtSignal(TrimmingData)

    def __init__(self):
        super().__init__()
        self.ui = Ui_SelectAreaDialog()
        self.ui.setupUi(self)

        self.width = 200
        self.height = 200
        self.h, self.w = None, None
        self.select_area = None
        self.original_image_scene = None
        self.size_flag = True
        self.select_area_label = None
        self.select_area_label_proxy = None
        self.start_position = None

        self.get_ng_sample_image_path()

        if self.h <= self.height and self.w <= self.width:
            self.size_flag = False

        if self.size_flag:
            self.show_select_area_at_default_position()
        else:
            self.ui.notation_label.setText('この画像サイズは十分小さいため, 画像全体でトレーニングを行います.'
                                           '\nこのままトレーニング開始ボタンを押してください.')
            pass

        self.ui.ok_button.clicked.connect(self.on_clicked_ok_button)
        self.ui.cancel_button.clicked.connect(self.on_clicked_cancel_button)

    def get_ng_sample_image_path(self):
        test_ng_path = str(Dataset.images_path(Dataset.Category.TEST_NG))
        test_ng_images = os.listdir(test_ng_path)
        test_ng_images = [
            img for img in test_ng_images
            if Path(img).suffix in ['.jpg', '.jpeg', '.png', '.gif', '.bmp']
        ]
        if not test_ng_images:
            return
        original_image_path = os.path.join(test_ng_path, test_ng_images[0])
        original_image = cv2.imread(original_image_path)
        h, w, c = original_image.shape
        self.h, self.w = h, w
        original_image_shape = QSize(w + 2, h + 10)
        original_image_item = QGraphicsPixmapItem(QPixmap(original_image_path))
        original_image_item.setZValue(0)
        self.original_image_scene = QGraphicsScene()
        self.original_image_scene.addItem(original_image_item)
        self.ui.original_image_view.setScene(self.original_image_scene)
        self.ui.original_image_view.setBaseSize(original_image_shape)
        self.ui.original_image_view.setMaximumSize(original_image_shape)
        self.resize(self.w + 32, self.h + 72)

    def show_select_area_at_default_position(self):
        trimming_data = Project.latest_trimming_data()
        if trimming_data.position:
            self.start_position = QPoint(trimming_data.position[0],
                                         trimming_data.position[1])
            rect = QRectF(trimming_data.position[0], trimming_data.position[1],
                          self.width, self.height)
        else:
            self.start_position = QPoint((self.w - self.width) // 2,
                                         (self.h - self.height) // 2)
            rect = QRectF((self.w - self.width) // 2,
                          (self.h - self.height) // 2, self.width, self.height)
        self.select_area = QGraphicsRectItem(rect)
        self.select_area.setZValue(1)
        pen = QPen(QColor('#ffa00e'))
        pen.setWidth(4)
        pen.setJoinStyle(Qt.RoundJoin)
        self.select_area.setPen(pen)
        self.select_area.setFlag(QGraphicsItem.ItemIsMovable, True)
        self.original_image_scene.addItem(self.select_area)
        self.select_area_label_proxy = QGraphicsProxyWidget(self.select_area)
        self.select_area_label = SelectAreaLabel()
        self.select_area_label.set_label()
        self.select_area_label_proxy.setWidget(self.select_area_label)
        self.select_area_label_proxy.setPos(
            self.select_area.boundingRect().left() + 2,
            self.select_area.boundingRect().bottom() -
            self.select_area_label.height() - 2)

    def on_clicked_ok_button(self):
        if not self.size_flag:
            trimming_data = TrimmingData(position=(0, 0),
                                         size=(self.w, self.h),
                                         needs_trimming=False)
            self.finish_selecting_area.emit(trimming_data)
            self.close()
        else:
            rel_position = self.select_area.pos()
            position = (self.start_position.x() + rel_position.x(),
                        self.start_position.y() + rel_position.y())
            if position[0] < 0 or position[
                    0] > self.w - self.width - 1 or position[
                        1] < 0 or position[1] > self.h - self.height - 1:
                print('Error: Please set area contained in the image.')
                self.ui.notation_label.setText('エラー: 切り取る領域は画像内に収まるようにしてください.')
            else:
                trimming_data = TrimmingData(position=position,
                                             size=(self.width, self.height),
                                             needs_trimming=True)
                self.finish_selecting_area.emit(trimming_data)
                self.close()

    def on_clicked_cancel_button(self):
        self.close()

    def closeEvent(self, QCloseEvent):
        self.close()