Beispiel #1
0
class View(QWidget):
    def __init__(self):
        super().__init__()
        self.layout = QHBoxLayout(self)

        self.selected = None
        self.pixmap_cache = {}

        # The split view at first shows the list of manga items and the default item view.
        # After a manga has been selected, there will be a total of three widgets:
        # - Manga item list
        # - Manga description
        # - Manga info (incl. cover)
        self.layout.addWidget(MANGA_ITEMS)
        self.layout.addWidget(self.default())

        MANGA_ITEMS.itemClicked.connect(self.onSelectedManga)

    def default(self):
        label = QLabel("Select a manga from the side bar, or add a new one.")
        label.setAlignment(Qt.AlignCenter)

        return label

    def deleteLast(self):
        while self.layout.count() != 1:
            delete(self.layout.takeAt(1))

    def onSelectedManga(self, manga_item):
        self.deleteLast()
        self.selected = manga_item

        manga = _load_manga(manga_item.meta.hash)

        summary = SummaryView(manga)

        self.layout.addWidget(summary)

        infobox = ItemInfoBox(manga_item)
        scroll = QScrollArea()
        scroll.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scroll.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        scroll.setFrameShape(scroll.NoFrame)
        scroll.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Preferred)
        scroll.setWidget(infobox)

        self.layout.addWidget(scroll)

    def onDeletedManga(self):
        self.deleteLast()

        self.layout.addWidget(self.default())

    def reload(self):
        if self.selected is not None:
            self.onSelectedManga(self.selected)

        else:
            # no manga selected yet.
            self.onDeletedManga()
Beispiel #2
0
class BanBoard(QWidget):
    """The main board of xBan"""
    def __init__(self, filepath, file_config, parent=None):
        super().__init__(parent)

        self.filepath = filepath
        self.file_config = file_config

        self.draw_board(file_config)
        self.setAcceptDrops(True)

        gui_logger.info("Main xban board created")

    def draw_board(self, file_config):
        """Initiate UI

        The UI consists of 2 parts, top is the board title and info
        and button is the subbords with tiles in each ones
        the subboard is drawn based on file_configuration
        """
        config, content = file_config

        mainlayout = QVBoxLayout()
        mainlayout.setContentsMargins(20, 20, 20, 20)

        title_edit = QLineEdit(
            config["xban_config"]["title"],
            objectName="windowEdit_title",
            parent=self,
        )
        title_edit.setPlaceholderText("Enter title here ...")

        info_edit = NoteTile(config["xban_config"]["description"],
                             "windowEdit_text", self)
        info_edit.setPlaceholderText("Enter description here ...")

        mainlayout.addWidget(title_edit)
        mainlayout.addWidget(info_edit)

        self.sublayout = QHBoxLayout()
        color = config["xban_config"]["board_color"]
        self.sublayout.setContentsMargins(10, 10, 10, 10)

        self.sublayout.setSpacing(20)

        add_btn = BanButton(
            "+",
            clicked=self.insert_board,
            toolTip="add board",
            objectName="windowBtn_add",
        )
        shadow = QGraphicsDropShadowEffect(self,
                                           blurRadius=10,
                                           offset=5,
                                           color=QColor("lightgrey"))
        add_btn.setGraphicsEffect(shadow)
        self.sublayout.addWidget(add_btn)

        mainlayout.addLayout(self.sublayout)
        self.setLayout(mainlayout)

        for i, tile_contents in enumerate(content.items()):
            # insert the boards
            self.insert_board(tile_contents, color[i])

    def insert_board(self, content=("", ()), color="black"):
        """Insert a board into the layout"""
        new_board = SubBoard(content, color, self)
        new_board.delBoardSig.connect(partial(self.delete_board, new_board))
        new_board.listwidget.itemSelectionChanged.connect(
            partial(self.single_selection, new_board.listwidget))
        # insert second to last
        self.sublayout.insertWidget(self.sublayout.count() - 1, new_board)

    def delete_board(self, board):
        """Delete the board"""

        self.sublayout.removeWidget(board)
        board.deleteLater()

    def parse_board(self):
        """Parse the board to the correct yaml files

        Note this function will rewrite the file
        """
        color = []
        content = {}
        title = self.layout().itemAt(0).widget().text()
        description = self.layout().itemAt(1).widget().toPlainText()
        sublayout = self.layout().itemAt(2)
        # exclude the plus button
        for i in range(sublayout.count() - 1):
            subboard = sublayout.itemAt(i).widget()
            color.append(subboard.color)
            sub_content = subboard.parse()
            content.update({sub_content[0]: sub_content[1]})
        config = {
            "xban_config": {
                "title": title,
                "description": description,
                "board_color": color,
            }
        }
        return [config, content]

    def get_index(self, pos):
        """Get index of the subboard layout based on the mouse position"""

        sublayout = self.layout().itemAt(2)
        for i in range(sublayout.count()):
            if sublayout.itemAt(i).geometry().contains(pos):
                return i
        return -1

    def dragEnterEvent(self, event):
        """Drag enter event

        Only accept the drag event when the moving widget is SubBoard instance
        The accepted drap event will proceed to dropEvent

        mouseMoveEvent needs to be defined for the child class
        """

        if isinstance(event.source(), SubBoard):
            event.accept()

    def dropEvent(self, event):
        """Drop Event

        When the widget is dropped, determine the current layout index
        of the cursor and insert widget in the layout

        Note the last widget of the layout is the plus button, hence
        never insert at the end
        """

        position = event.pos()
        widget = event.source()

        sublayout = self.layout().itemAt(2)
        index_new = self.get_index(position)
        if index_new >= 0:
            index = min(index_new, sublayout.count() - 1)
            sublayout.insertWidget(index, widget)
        event.setDropAction(Qt.MoveAction)
        event.accept()

    def save_board(self):
        """Save the board to yaml file"""

        xban_content = self.parse_board()
        save_yaml(self.filepath, xban_content)
        gui_logger.info(f"Saved to {self.filepath}")

    def single_selection(self, selected_board):
        """ensure that only single tile from a board is selected

        This is achieved by emit and received every time there
        is a selection made. The has selection check makes sure
        that it does not go into a recursion, since clear
        selection also triggers the signal
        """

        if selected_board.selectionModel().hasSelection():
            for i in range(self.sublayout.count() - 1):
                subboard = self.sublayout.itemAt(i).widget().listwidget

                if subboard is not selected_board:
                    subboard.clearSelection()