Example #1
0
class MainWindow(QWidget):
    def draw(self, mainlineMove):
        self.i += 1
        self.chessboard.push(mainlineMove)
        self.chessboardSvg = chess.svg.board(self.chessboard).encode('UTF-8')
        self.widgetSvg.load(self.chessboardSvg)

    def __init__(self, game):

        super().__init__()
        self.i = 0
        if game == None:
            self.chessboard = chess.Board()
        else:
            self.chessboard = game.board()
            self.MOVES = [x for x in game.mainline_moves()]
            print(self.MOVES)

        self.setGeometry(100, 100, 1000, 1000)

        self.widgetSvg = QSvgWidget(parent=self)
        self.widgetSvg.setGeometry(10, 10, 960, 960)

        self.button = QPushButton("Next Move")
        self.button.clicked.connect(self.draw(self.MOVES[self.i]))

        self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
        self.widgetSvg.load(self.chessboardSvg)
Example #2
0
 def visualizeAI(self):
     svgBytes = self.ai.visualize()
     dialog = QDialog(self)
     dialog.setWindowTitle("AI Algorithm Visualization")
     svgWidget = QSvgWidget(dialog)
     svgWidget.load(QByteArray(svgBytes))
     dialog.show()
Example #3
0
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setGeometry(100, 100, 1000, 1000)

        self.widgetSvg = QSvgWidget(parent=self)
        self.widgetSvg.setGeometry(10, 10, 900, 900)

        self.chessboard = chess.Board()

    def play(self, ai_params):
        while not self.chessboard.is_game_over():
            self.widgetSvg.load(
                chess.svg.board(self.chessboard, flipped=True).encode("UTF-8"))
            if self.chessboard.turn:
                print("Whites turn")
                self.chessboard.push(findBestMove(ai_params, self.chessboard))
            else:
                print("Blacks turn")
                while True:
                    legal_moves = [
                        str(move) for move in list(self.chessboard.legal_moves)
                    ]
                    move = input("Your move: ")
                    if move in legal_moves:
                        self.chessboard.push(chess.Move.from_uci(move))
                        break
                    else:
                        print(move, "This is not a legal move!")
                        print("Legal moves are: ", legal_moves)
        self.widgetSvg.load(
            chess.svg.board(self.chessboard, flipped=True).encode("UTF-8"))
        print("Game Over")
    def __init__(self, cover_path, figure_info, figure_title,
                 figure_score, figure_desc, figure_count, video_url, cover_url, img_path, *args, **kwargs):
        super(ItemWidget, self).__init__(*args, **kwargs)
        self.setMaximumSize(220, 380)
        self.setMaximumSize(220, 380)
        self.img_path = img_path
        self.cover_url = cover_url
        layout = QVBoxLayout(self)
        layout.setContentsMargins(0, 0, 0, 0)
        # 图片label
        self.clabel = CoverLabel(cover_path, figure_info, video_url, self)
        layout.addWidget(self.clabel)

        # 片名和分数
        flayout = QHBoxLayout()
        flayout.addWidget(QLabel(figure_title, self))
        flayout.addItem(QSpacerItem(
            20, 20, QSizePolicy.Expanding, QSizePolicy.Minimum))
        flayout.addWidget(QLabel(figure_score, self, styleSheet="color: red;"))
        layout.addLayout(flayout)

        # 主演
        layout.addWidget(
            QLabel(figure_desc, self, styleSheet="color: #999999;", openExternalLinks=True))

        # 播放量
        blayout = QHBoxLayout()
        count_icon = QSvgWidget(self)
        count_icon.setMaximumSize(16, 16)
        count_icon.load(Svg_icon_play_sm)
        blayout.addWidget(count_icon)
        blayout.addWidget(
            QLabel(figure_count, self, styleSheet="color: #999999;"))
        layout.addLayout(blayout)
Example #5
0
class MyWidget(QtWidgets.QWidget):
    def __init__(self):
        """
        This is the main window from my GUI
        """
        super().__init__()
        # Generate chess board
        self.setGeometry(0, 0, 620, 620)
        self.widgetSvg = QSvgWidget(parent=self)
        self.widgetSvg.setGeometry(10, 10, 600, 600)
        self.chessboard = chess.Board()
        self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
        self.widgetSvg.load(self.chessboardSvg)

        # configure and start thrread
        self.displayer_chess_game = ChessEngineBackend()
        self.thread = QtCore.QThread(self)
        self.displayer_chess_game.move.connect(self.move_callback)  # NOQA
        self.displayer_chess_game.moveToThread(self.thread)
        self.thread.started.connect(
            self.displayer_chess_game.chess_engine_backend)  # NOQA
        self.thread.start()

    @QtCore.pyqtSlot(str)
    def move_callback(self, move):
        """


        """
        self.chessboard.push(chess.Move.from_uci(move))
        self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
        self.widgetSvg.load(self.chessboardSvg)
Example #6
0
def __example_usage_latex_to_svg():
    plt.rc('mathtext', fontset='cm')
    latex = r'$1 + \dfrac{1}{1 + \dfrac{1}{3}}$'
    app = QApplication(sys.argv)
    svg = QSvgWidget()
    svg.load(latex_to_svg(latex))
    svg.show()
    sys.exit(app.exec_())
Example #7
0
class BoardView(QWidget):
    def __init__(self, svg_board, **kwargs):
        super().__init__(**kwargs)
        self.svgWidget = QSvgWidget()
        layout = EvenLayout(self)
        layout.addWidget(self.svgWidget, 0, 0)

        self.press_pos = None
        self.refresh(svg_board)

    def refresh(self, svg_board):
        data = createQByteArray(svg_board)
        self.svgWidget.load(data)

    def mousePressEvent(self, event):
        self.press_pos = self.calculate_board_position(event)

    def mouseReleaseEvent(self, event):
        if self.press_pos:
            release_pos = self.calculate_board_position(event)
            if release_pos:
                piece = self.parent().game.get_piece_at_pos(self.press_pos)
                move = self.press_pos + release_pos

                if ((piece == 'P' and release_pos[1] == '8'
                     and self.press_pos[1] == '7'
                     and self.parent().game.board.turn)
                        or (piece == 'p' and release_pos[1] == '1'
                            and self.press_pos[1] == '2'
                            and not self.parent().game.board.turn)):
                    # Promotion
                    # TODO: player input - await, asyncio
                    move += 'q'
                elif self.press_pos == release_pos:
                    move = '0000'  # uci null move
                self.parent().execute_game_command(move)

    def mouseMoveEvent(self, event):
        # TODO: Implement drag piece-icon
        pass

    # Returns a tuple with the board position as uci and the piece at that position,
    # or None.
    def calculate_board_position(self, event):
        margin = self.svgWidget.size() * 0.05 + QSize(2, 2)
        square = (self.svgWidget.size() - 2 * margin) / 8
        offset = (self.size() - self.svgWidget.size()) / 2. + margin
        x_coordinate = event.pos().x() - offset.width()
        y_coordinate = offset.height() + 8 * square.height() - event.pos().y()
        x_pos = int(1 + x_coordinate / square.width())
        y_pos = int(1 + y_coordinate / square.height())

        if (x_pos > 8 or x_pos < 1 or y_pos > 8 or y_pos < 1):
            return None
        else:
            return 'abcdefgh'[x_pos - 1] + str(y_pos)
Example #8
0
def main():
    FORMULA = r'\int_{-\infty}^\infty e^{-x^2}\,dx = \sqrt{\pi}'

    app = QApplication(sys.argv)

    svg = QSvgWidget()
    svg.load(tex2svg(FORMULA))
    svg.show()

    sys.exit(app.exec_())
Example #9
0
class GraphWindow(QMainWindow):
    """ Qt application window showing a single vector graph.
    
    Save graph using right click menu.

    Attributes:
        _graph_display  Widget that shows the graph image
        _svg_bytes  SVG bytes representing currently displayed image
    """
    window_width = 600  # type: float  # Height is computed from aspect ratio

    def __init__(self,
                 graph_svg: bytes = None,
                 aspect_ratio: float = 1.0) -> None:
        super().__init__()

        self._svg_bytes = bytes()

        # Add image widget:
        self._graph_display = QSvgWidget()
        self.setCentralWidget(self._graph_display)
        if graph_svg is not None:
            self.set_graph(graph_svg)
        self._graph_display.setContextMenuPolicy(Qt.CustomContextMenu)
        self._graph_display.customContextMenuRequested.connect(
            self._show_context_menu)
        self._graph_display.setToolTip("Right-click to save image")
        self._graph_display.setToolTipDuration(2000)

        # Set correct aspect ratio:
        self.setFixedSize(self.window_width, self.window_width * aspect_ratio)

    def _show_context_menu(self, point: QPoint) -> None:
        """ Show a context menu for the graph display. """
        menu = QMenu(self)
        save_action = QAction("Save current image...", menu)
        save_action.triggered.connect(
            lambda checked: self._save_current_image())
        menu.addAction(save_action)
        menu.exec(self._graph_display.mapToGlobal(point))

    def _save_current_image(self):
        """ Copy current image and save it to a file. """
        current_svg = deepcopy(self._svg_bytes)  # type: bytes
        file_path = QFileDialog.getSaveFileUrl()[0].path()  # type: str

        with open(file_path, "w") as outfile:
            outfile.write(current_svg.decode())

    @pyqtSlot(bytes)
    def set_graph(self, graph_svg: bytes) -> None:
        """Renders SVG bytes in the graph display."""
        self._graph_display.load(graph_svg)
        self._svg_bytes = graph_svg
Example #10
0
class SvgButton(QPushButton):
    def __init__(self, parent, svg_path):
        QWidget.__init__(self, parent)
        self.svg = QSvgWidget(self)
        self.svg.load(svg_path)
        self.setFocusPolicy(Qt.NoFocus)

    def setSize(self, w, h) -> None:
        self.resize(w, h)
        self.svg.resize(w, h)

    def load_svg(self, svg_path):
        self.svg.load(svg_path)
Example #11
0
class MainWindow(QWidget):
    def __init__(self, board):
        super().__init__()

        self.setGeometry(100, 100, 520, 520)

        self.widgetSvg = QSvgWidget(parent=self)
        self.widgetSvg.setGeometry(10, 10, 500, 500)

        self.set_board(board)

    def set_board(self, board):
        chessboardSvg = chess.svg.board(board).encode("UTF-8")
        self.widgetSvg.load(chessboardSvg)
Example #12
0
class DotWidget(QWidget):
    def __init__(self, path:str, gui):
        super().__init__()
        self.gui = gui

        self.label = QLabel(f"Dot Dump:")
        self.display = QSvgWidget()
        self.display.load(path)

        self.layout = QVBoxLayout()
        self.layout.addWidget(self.label)
        self.layout.addWidget(self.display)

        self.setWindowTitle(self.gui.windowTitle())

        self.setLayout(self.layout)
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setGeometry(100, 100, 1100, 1100)

        self.widgetSvg = QSvgWidget(parent=self)
        self.widgetSvg.setGeometry(10, 10, 1080, 1080)

        self.chessboard = chess.Board()

        self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
        self.widgetSvg.load(self.chessboardSvg)

    def paintEvent(self, event):
        self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
        self.widgetSvg.load(self.chessboardSvg)
Example #14
0
class ScrollWindow(QScrollArea):
    def __init__(self, *args, **kwargs):
        super(ScrollWindow, self).__init__(*args, **kwargs)
        # self.setAcceptDrops(True)  # 2
        self.resize(800, 600)
        self.setFrameShape(self.NoFrame)
        self.setWidgetResizable(True)
        self.setAlignment(Qt.AlignCenter)
        self._loadStart = False
        # 网格窗口
        self._widget = GridWidget(self)
        self._widget.loadStarted.connect(self.setLoadStarted)
        self.setWidget(self._widget)
        ####################################################
        # 连接竖着的滚动条滚动事件
        # self.verticalScrollBar().actionTriggered.connect(self.onActionTriggered)
        ####################################################
        # 进度条
        self.loadWidget = QSvgWidget(self,
                                     minimumHeight=180,
                                     minimumWidth=180,
                                     visible=False)
        self.loadWidget.load(Svg_icon_loading)

    def setLoadStarted(self, started):
        self._loadStart = started
        self.loadWidget.setVisible(started)

    def onActionTriggered(self, action):
        # 这里要判断action=QAbstractSlider.SliderMove,可以避免窗口大小改变的问题
        # 同时防止多次加载同一个url
        if action != QAbstractSlider.SliderMove or self._loadStart:
            return
        # 使用sliderPosition获取值可以同时满足鼠标滑动和拖动判断
        if self.verticalScrollBar().sliderPosition() == self.verticalScrollBar(
        ).maximum():
            # 可以下一页了
            self._widget.load()

    def resizeEvent(self, event):
        super(ScrollWindow, self).resizeEvent(event)
        self.loadWidget.setGeometry(
            int((self.width() - self.loadWidget.minimumWidth()) / 2),
            int((self.height() - self.loadWidget.minimumHeight()) / 2),
            self.loadWidget.minimumWidth(), self.loadWidget.minimumHeight())
Example #15
0
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.movehistory = []
        self.game = chess.pgn.Game()

        self.setGeometry(1050, 200, 500, 500)

        self.widgetSvg = QSvgWidget(parent=self)
        self.widgetSvg.setGeometry(0, 0, 500, 500)

        self.boardSize = min(self.widgetSvg.width(), self.widgetSvg.height())
        self.squareSize = self.boardSize / 8.0
        self.pieceToMove = [None, None]

        self.board = chess.Board()

        self.drawBoard()

    @pyqtSlot(QWidget)
    def mousePressEvent(self, event):
        if self.board.is_game_over(claim_draw=True) is False:
            if not self.board.turn:
                move = select_move(self.board, DEPTH)
                self.board.push(move)
                self.movehistory.append(move)
            elif event.x() <= self.boardSize and event.y() <= self.boardSize:
                if event.buttons() == Qt.LeftButton:
                    file = int((event.x()) / self.squareSize)
                    rank = 7 - int((event.y()) / self.squareSize)
                    square = chess.square(file, rank)
                    piece = self.board.piece_at(square)
                    coordinates = "{}{}".format(chr(file + 97), str(rank + 1))
                    if self.pieceToMove[0] is not None:
                        move = chess.Move.from_uci("{}{}".format(
                            self.pieceToMove[1], coordinates))
                        if move in self.board.legal_moves:
                            self.board.push(move)
                            self.movehistory.append(move)
                        piece = None
                        coordinates = None
                    self.pieceToMove = [piece, coordinates]
            self.drawBoard()
        else:
            self.game.add_line(self.movehistory)
            print(self.game, file=open("gameresult.pgn", "w"), end="\n\n")
            print("Game over")
            exit()

    def drawBoard(self):
        lastmove = self.board.peek() if self.board.move_stack else None
        self.boardSvg = chess.svg.board(board=self.board,
                                        lastmove=lastmove).encode("UTF-8")
        self.drawBoardSvg = self.widgetSvg.load(self.boardSvg)

        return self.boardSvg
Example #16
0
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setGeometry(100, 100, 850, 850)

        self.widgetSvg = QSvgWidget(parent=self)
        self.widgetSvg.setGeometry(10, 10, 800, 800)

        self.board = chess.Board()  #'8/8/8/rnbqk3/ppppp3/8/PPPPP3/RNBQK3')

        self.boardSvg = chess.svg.board(self.board).encode("UTF-8")
        self.widgetSvg.load(self.boardSvg)

    def reload(self):
        self.boardSvg = chess.svg.board(self.board).encode("UTF-8")
        self.widgetSvg.load(self.boardSvg)

    def replaceBoard(self, board):
        self.board = board
Example #17
0
    def __init_ui(self) -> NoReturn:
        self.setFixedSize(120, 60)
        self.setAttribute(Qt.WA_DeleteOnClose)
        self.setObjectName("item")

        self.setStyleSheet("""
            QFrame#item {
                border: 2px solid black;
                border-radius: 5px;
                background-color: """ + self._enum.background_color + """;
                }
            """)

        icon = QSvgWidget(self)
        icon.load(self._enum.path)
        icon.setFixedSize(40, 40)

        layout = QHBoxLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(icon)
        self.setLayout(layout)
Example #18
0
class DownloadSpeedWidget(QWidget):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.downloaded_bytes = 0
        self.total_bytes = 0

        self.timer = QTimer()
        self.timer.start(1000)
        self.timer.timeout.connect(self.monitor_download_show)
        self.layout = QHBoxLayout()
        self.layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self.layout)

        self.text = QLabel()
        self.set_text()

        size = self.text.fontMetrics().height()

        self.icon = QSvgWidget()
        self.icon.load(os.path.join(ASSETS_PATH, "speed_download.svg"))
        self.icon.setFixedSize(size * 0.7, size * 0.7)

        self.layout.addWidget(self.icon)
        self.layout.addWidget(self.text)

    def set_text(self):
        self.text.setText(
            f"{format_bytes(self.downloaded_bytes)}/s ({format_bytes(self.total_bytes)})"
        )

    def reset(self):
        self.total_bytes = 0

    def monitor_download(self, size):
        self.downloaded_bytes += size
        self.total_bytes += size

    def monitor_download_show(self):
        self.set_text()
        self.downloaded_bytes = 0
    def get_svg_widget(self,
                       element: Gui_Element,
                       height: int,
                       width: int,
                       fill: str = "#FF9933",
                       text: str = "00") -> QSvgWidget:

        svg = self.read_svg_from_file(element)
        svg = self.interpolate_svg(svg, fill, text)

        svg_bytes = bytearray(svg, encoding='utf-8')
        svg_widget = QSvgWidget()
        svg_widget.load(svg_bytes)
        #svg_widget.renderer().load(svg_bytes)
        if height > 0 and width > 0:
            size = QSize(width, height)
            svg_widget.setFixedSize(size)
        #else:
        #    svg_widget.setFixedSize(svg_widget.renderer().defaultSize())
        #    svg_widget.setFixedSize(svg_w)

        return svg_widget
Example #20
0
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("PinkFish")
        self.setGeometry(400, 400, 1300, 1300)
        self.widgetSvg = QSvgWidget(self)
        self.widgetSvg.setGeometry(20, 20, 1200, 1200)
        self.chessboard = chess.Board()
        self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")

        self.checkThreadTimer = QTimer(self)
        self.checkThreadTimer.setInterval(1000)
        self.checkThreadTimer.start()
        self.checkThreadTimer.timeout.connect(self.play)

    @pyqtSlot(QWidget)
    def mousePressEvent(self, event):
        if event.buttons() == Qt.LeftButton:
            self.update()

    @pyqtSlot(QWidget)
    def paintEvent(self, event):
        self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
        self.widgetSvg.load(self.chessboardSvg)

    def play(self):
        dirname = os.path.dirname(__file__)
        filename = os.path.join(dirname, 'stockfish-9-win\Windows\stockfish_9_x64')
        stockfish = Stockfish(filename)
        stockfish.set_skill_level(15)
        if not self.chessboard.is_game_over() and not self.chessboard.is_stalemate():
            board = self.chessboard.fen()
            stockfish.set_fen_position(board)
            ai_move = stockfish.get_best_move()
            move = chess.Move.from_uci(ai_move)
            print(move)
            self.chessboard.push(move)
            self.update()
Example #21
0
class MainWindow(QWidget):
    def __init__(self):
        super().__init__()

        self.setGeometry(100, 100, 500, 500)

        self.widgetSvg = QSvgWidget(parent=self)
        self.widgetSvg.setGeometry(10, 10, 480, 480)

        self.chessboard = chess.Board()

        self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
        self.widgetSvg.load(self.chessboardSvg)

    def paintEvent(self, event):
        self.game_over()
        self.rand()
        self.tela_jog()

    def tela_jog(self):
        self.chessboardSvg = chess.svg.board(self.chessboard).encode("UTF-8")
        self.widgetSvg.load(self.chessboardSvg)

    def game_over(self):
        if self.chessboard.is_game_over() == True:
            print(self.chessboard.outcome())
            input()
            exit()

    def rand(self):
        legal_count = self.chessboard.legal_moves.count()
        move_list = list(self.chessboard.legal_moves)  # Find legal moves
        which_move = random.randint(0, legal_count - 1)  # Random move index
        first_move = move_list[which_move]  # Select move
        move_holder = chess.Move.from_uci(str(first_move))

        self.chessboard.push(move_holder)
        time.sleep(0.5)
Example #22
0
class Window(QWidget):
    def __init__(self, left=100, top=100, width=500, height=500):
        super().__init__()
        self.left = max(0, left)
        self.top = max(0, top)
        self.width = max(20, width)
        self.height = max(20, height)
        self.update_geometry()
        self.widgetSvg = QSvgWidget(parent=self)
        self.widgetSvg.setGeometry(10, 10, self.width - 20, self.height - 20)

    def update_geometry(self):
        self.setGeometry(self.left, self.top, self.width, self.height)

    def display_svg(self, svg):
        self.widgetSvg.load(svg)
        self.repaint()

    def add_button(self, text, on_click):
        btn = QPushButton(text, self)
        self.height = self.height + 60
        self.update_geometry()
        btn.move(int(self.width / 2) - 50, self.height - 50)
        btn.clicked.connect(on_click)
Example #23
0
class Icon(QWidget):
    def __init__(self, parent, icon, size=None, padding=None, color=None):
        QWidget.__init__(self, parent)
        padding = padding or 0
        self._theme_manager = ThemeManager.get(self)

        self._color = format_color(
            color or self._theme_manager.get_color('button_foreground'),
            ColorFormat.rgb_string_256)

        self._svgdoc = QDomDocument()
        self._icon_widget = QSvgWidget(self)

        self.loadIcon(icon)

        if size:
            self._icon_widget.setFixedSize(
                QSize(size.width() - 2 * padding,
                      size.height() - 2 * padding))

        self._layout = QHBoxLayout(self)
        self._layout.setContentsMargins(padding, padding, padding, padding)
        self._layout.addWidget(self._icon_widget, Qt.AlignCenter)

    def loadIcon(self, icon):
        file = QFile(f'icons:{icon}')
        file.open(QFile.ReadOnly)
        self._svgdoc.setContent(file.readAll())
        self._svgdoc.documentElement().setAttribute('fill', self._color)
        file.close()
        self._icon_widget.load(self._svgdoc.toByteArray())

    def setEnabled(self, enabled):
        QWidget.setEnabled(self, enabled)
        self._svgdoc.documentElement().setAttribute('fill', self._color)
        self._svgdoc.documentElement().setAttribute(
            'fill-opacity', '1' if self.isEnabled() else '0.4')
        self._icon_widget.load(self._svgdoc.toByteArray())

    def setColor(self, color=None):
        color = format_color(
            color or self._theme_manager.get_color('button_foreground'),
            ColorFormat.rgb_string_256) or self._color
        self._svgdoc.documentElement().setAttribute('fill', color)
        self._svgdoc.documentElement().setAttribute(
            'fill-opacity', '1' if self.isEnabled() else '0.4')
        self._icon_widget.load(self._svgdoc.toByteArray())
Example #24
0
class Result(QWidget):
    def __init__(self, parent=None):
        super(Result, self).__init__(parent)
        self.capture = Capture(None)
        self.draw = Canvas(None)
        self.setAcceptDrops(True)
        self.setWindowIcon(QIcon("favicon.ico"))
        # region WindowSettings
        self.setFixedWidth(600)
        self.setWindowTitle("MathPix+")
        self.setWindowFlags(Qt.MSWindowsFixedSizeDialogHint
                            | Qt.WindowCloseButtonHint
                            | Qt.WindowStaysOnTopHint)
        # endregion
        # region Svg
        self.svg_container = QWidget()
        self.svg_container.setFixedSize(QSize(578, 200))
        self.svg = QSvgWidget(self.svg_container)
        # endregion
        # region Info Label
        self.label = QLabel()
        self.label.setFont(QFont("等线", 20))
        self.label.setMaximumHeight(30)
        self.label.setAlignment(Qt.AlignCenter)
        # endregion
        # region Image
        self.img = QLabel()
        self.img.setFixedSize(578, 200)
        self.img.setAlignment(Qt.AlignCenter)
        # endregion
        # region TeX LineEdit
        self.tex = QLineEdit()
        self.tex.setAlignment(Qt.AlignCenter)
        self.tex.setFont(QFont("Cambria Math", 20))
        self.tex.setMaximumHeight(60)
        self.tex.setPlaceholderText("Enter Your Tex Here")
        self.tex.setEchoMode(QLineEdit.Normal)
        self.tex.textChanged.connect(self.on_tex_changed)
        # endregion
        # region PushButtons
        self.save_as_raw_tex = QPushButton("&Raw")
        self.save_as_raw_tex.setFixedHeight(40)
        self.save_as_raw_tex.setFont(QFont("等线", 20))
        self.save_as_raw_tex.clicked.connect(
            lambda: self.copy_tex_to_clipboard(""))
        self.save_as_inline_tex = QPushButton("&Inline")
        self.save_as_inline_tex.setFixedHeight(40)
        self.save_as_inline_tex.setFont(QFont("等线", 20))
        self.save_as_inline_tex.clicked.connect(
            lambda: self.copy_tex_to_clipboard("$"))
        self.save_as_block_tex = QPushButton("&Block")
        self.save_as_block_tex.setFixedHeight(40)
        self.save_as_block_tex.setFont(QFont("等线", 20))
        self.save_as_block_tex.clicked.connect(
            lambda: self.copy_tex_to_clipboard("$$"))
        self.open_img = QPushButton("&Open")
        self.open_img.setFixedHeight(40)
        self.open_img.setFont(QFont("等线", 20))
        self.open_img.clicked.connect(lambda: self.get_tex(self.get_img()))
        self.snap_img = QPushButton("&Snap")
        self.snap_img.setFixedHeight(40)
        self.snap_img.setFont(QFont("等线", 20))
        self.snap_img.clicked.connect(self.capture_img)
        self.draw_img = QPushButton("&Draw")
        self.draw_img.setFixedHeight(40)
        self.draw_img.setFont(QFont("等线", 20))
        self.draw_img.clicked.connect(self.canvas_img)
        # endregion
        # region Layout
        self.copy_hlo = QHBoxLayout()
        self.open_hlo = QHBoxLayout()
        self.copy_hlo.addWidget(self.save_as_raw_tex)
        self.copy_hlo.addWidget(self.save_as_inline_tex)
        self.copy_hlo.addWidget(self.save_as_block_tex)
        self.open_hlo.addWidget(self.open_img)
        self.open_hlo.addWidget(self.snap_img)
        self.open_hlo.addWidget(self.draw_img)
        self.vlo = QVBoxLayout()
        self.vlo.addWidget(self.svg_container)
        self.vlo.addWidget(self.img)
        self.vlo.addWidget(self.label)
        self.vlo.addWidget(self.tex)
        self.vlo.addLayout(self.copy_hlo)
        self.vlo.addLayout(self.open_hlo)
        # endregion
        self.get_tex("")
        self.setLayout(self.vlo)

    def on_tex_changed(self):
        try:
            parser = math_text.MathTextParser('svg')
            parser.parse(r"$" + self.tex.text() + r"$")
        except ValueError:
            self.label.setText("TeX语法不正确")
        else:
            self.label.setText('')
            self.generate_svg(self.tex.text())

    def copy_tex_to_clipboard(self, string):
        clipboard = QApplication.clipboard()
        clipboard.setText(string + self.tex.text() + string)
        self.label.setText("TeX已复制至剪贴板")

    def generate_svg(self, raw_tex):
        fig = Figure(figsize=(5, 4), dpi=300)
        canvas = FigureCanvasAgg(fig)
        fig.text(.5, .5, r"$" + raw_tex + r"$", fontsize=40)
        fig.savefig("output.svg", bbox_inches="tight", facecolor=(1, 1, 1, 0))
        self.svg.load("output.svg")
        renderer = QSvgRenderer('output.svg').defaultSize()
        w = renderer.width()
        h = renderer.height()
        if w / h > 578 / 200:
            display_w = 578
            display_h = int(578 * h / w)
        else:
            display_h = 200
            display_w = int(200 * w / h)
        self.svg.setFixedWidth(display_w)
        self.svg.setFixedHeight(display_h)
        self.svg.setGeometry(
            QRect(289 - int(display_w / 2), 100 - int(display_h / 2),
                  display_w, display_h))

    def get_img(self):
        file_name, file_type = QFileDialog.getOpenFileName(
            self, "选取图片", "./", "所有文件 (*);;图片文件 (*.jpg *.png)")
        print(file_name, file_type)
        return file_name

    def get_tex(self, url=r"limit.jpg"):
        if url == "":
            self.set_data("limit.jpg",
                          r"\lim_{x\rightarrow3}(\frac{x^{2}+9}{x-3})", 1)
            return
        with open(url, 'rb') as pic:
            base64_data = base64.b64encode(pic.read())
            print(base64_data)
        img_url = "data:image/jpg;base64," + base64_data.decode()
        r = requests.post("https://api.mathpix.com/v3/latex",
                          data=json.dumps({'url': img_url}),
                          headers={
                              "app_id": "******",
                              "app_key": "********************************",
                              "Content-type": "application/json"
                          })
        print(json.dumps(json.loads(r.text), indent=4, sort_keys=True))
        try:
            raw_data = json.loads(r.text)
        except AttributeError:
            return
        else:
            if "latex" in raw_data:
                tex = raw_data["latex"]
            else:
                return
            if "latex_confidence" in raw_data:
                confidence = raw_data["latex_confidence"]
            else:
                confidence = 1

            self.set_data(url, tex, confidence)

    def set_data(self, img, tex, con):
        raw_img = QPixmap(img)
        w = raw_img.width()
        h = raw_img.height()
        if w / h > 578 / 200:
            self.img.setPixmap(
                raw_img.scaledToWidth(578, Qt.SmoothTransformation))
        else:
            self.img.setPixmap(
                raw_img.scaledToHeight(200, Qt.SmoothTransformation))

        tex_data = tex
        tex_data = tex_data.replace(r"\\", "\\")
        tex_data = tex_data.replace(' ', '')
        self.tex.setText(tex_data)
        self.generate_svg(tex_data)

        if con < 0.8:
            self.label.setText("置信值低于0.8, 建议进行人工校对 : ")

    def dragEnterEvent(self, event):
        if event.mimeData().hasUrls:
            event.accept()
        else:
            event.ignore()

    def dragMoveEvent(self, event):
        if event.mimeData().hasUrls:
            event.setDropAction(Qt.CopyAction)
            event.accept()
        else:
            event.ignore()

    def dropEvent(self, event):
        print("dropped")
        url = str(event.mimeData().urls()[0].toLocalFile())
        print(url)
        self.get_tex(url)

    def capture_img(self):
        self.capture.grab_new_img()
        self.capture.show()
        self.capture.captured.connect(lambda: self.get_tex("capture.jpg"))

    def canvas_img(self):
        self.draw.show()
        self.draw.drawn.connect(lambda: self.get_tex("canvas.jpg"))
Example #25
0
class Window(QListWidget):
    Page = 0

    def __init__(self, *args, **kwargs):
        super(Window, self).__init__(*args, **kwargs)
        self.resize(800, 600)
        self.setFrameShape(self.NoFrame)  # 无边框
        self.setFlow(self.LeftToRight)  # 从左到右
        self.setWrapping(True)  # 这三个组合可以达到和FlowLayout一样的效果
        self.setResizeMode(self.Adjust)

        self._loadStart = False
        # 连接竖着的滚动条滚动事件
        self.verticalScrollBar().actionTriggered.connect(
            self.onActionTriggered)
        # 进度条
        self.loadWidget = QSvgWidget(self,
                                     minimumHeight=120,
                                     minimumWidth=120,
                                     visible=False)
        self.loadWidget.load(Svg_icon_loading)

        # 异步网络下载管理器
        self._manager = QNetworkAccessManager(self)
        self._manager.finished.connect(self.onFinished)

    def load(self):
        if self.Page == -1:
            return
        self._loadStart = True
        self.loadWidget.setVisible(True)
        # 延迟一秒后调用目的在于显示进度条
        QTimer.singleShot(1000, self._load)

    def _load(self):
        print("load url:", Url.format(self.Page * 30))
        url = QUrl(Url.format(self.Page * 30))
        self._manager.get(QNetworkRequest(url))

    def onFinished(self, reply):
        # 请求完成后会调用该函数
        req = reply.request()  # 获取请求
        iwidget = req.attribute(QNetworkRequest.User + 1, None)
        path = req.attribute(QNetworkRequest.User + 2, None)
        html = reply.readAll().data()
        reply.deleteLater()
        del reply
        if iwidget and path and html:
            # 这里是图片下载完毕
            open(path, "wb").write(html)
            iwidget.setCover(path)
            return
        # 解析网页
        self._parseHtml(html)
        self._loadStart = False
        self.loadWidget.setVisible(False)

    def _parseHtml(self, html):
        #         encoding = chardet.detect(html) or {}
        #         html = html.decode(encoding.get("encoding","utf-8"))
        html = HTML(html)
        # 查找所有的li list_item
        lis = html.xpath("//li[@class='list_item']")
        if not lis:
            self.Page = -1  # 后面没有页面了
            return
        self.Page += 1
        self._makeItem(lis)

    def _makeItem(self, lis):
        for li in lis:
            a = li.find("a")
            video_url = a.get("href")  # 视频播放地址
            img = a.find("img")
            cover_url = "http:" + img.get("r-lazyload")  # 封面图片
            figure_title = img.get("alt")  # 电影名
            figure_info = a.find("div/span")
            figure_info = "" if figure_info is None else figure_info.text  # 影片信息
            figure_score = "".join(li.xpath(".//em/text()"))  # 评分
            # 主演
            figure_desc = "<span style=\"font-size: 12px;\">主演:</span>" + \
                          "".join([Actor.format(**dict(fd.items()))
                                   for fd in li.xpath(".//div[@class='figure_desc']/a")])
            # 播放数
            figure_count = (
                li.xpath(".//div[@class='figure_count']/span/text()")
                or [""])[0]
            path = "cache/{0}.jpg".format(
                os.path.splitext(os.path.basename(video_url))[0])
            cover_path = "Data/pic_v.png"
            if os.path.isfile(path):
                cover_path = path
            iwidget = ItemWidget(cover_path, figure_info, figure_title,
                                 figure_score, figure_desc, figure_count,
                                 video_url, cover_url, path, self._manager,
                                 self)
            item = QListWidgetItem(self)
            item.setSizeHint(iwidget.sizeHint())
            self.setItemWidget(item, iwidget)

    def onActionTriggered(self, action):
        # 这里要判断action=QAbstractSlider.SliderMove,可以避免窗口大小改变的问题
        # 同时防止多次加载同一个url
        if action != QAbstractSlider.SliderMove or self._loadStart:
            return
        # 使用sliderPosition获取值可以同时满足鼠标滑动和拖动判断
        if self.verticalScrollBar().sliderPosition() == self.verticalScrollBar(
        ).maximum():
            # 可以下一页了
            self.load()

    def resizeEvent(self, event):
        super(Window, self).resizeEvent(event)
        self.loadWidget.setGeometry(
            int((self.width() - self.loadWidget.minimumWidth()) / 2),
            int((self.height() - self.loadWidget.minimumHeight()) / 2),
            self.loadWidget.minimumWidth(), self.loadWidget.minimumHeight())
Example #26
0
class ScalableDial(QDial):
    # enum CustomPaintMode
    CUSTOM_PAINT_MODE_NULL = 0  # default (NOTE: only this mode has label gradient)
    CUSTOM_PAINT_MODE_CARLA_WET = 1  # color blue-green gradient (reserved #3)
    CUSTOM_PAINT_MODE_CARLA_VOL = 2  # color blue (reserved #3)
    CUSTOM_PAINT_MODE_CARLA_L = 3  # color yellow (reserved #4)
    CUSTOM_PAINT_MODE_CARLA_R = 4  # color yellow (reserved #4)
    CUSTOM_PAINT_MODE_CARLA_PAN = 5  # color yellow (reserved #3)
    CUSTOM_PAINT_MODE_COLOR = 6  # color, selectable (reserved #3)
    CUSTOM_PAINT_MODE_ZITA = 7  # custom zita knob (reserved #6)
    CUSTOM_PAINT_MODE_NO_GRADIENT = 8  # skip label gradient

    # enum Orientation
    HORIZONTAL = 0
    VERTICAL = 1

    HOVER_MIN = 0
    HOVER_MAX = 9

    MODE_DEFAULT = 0
    MODE_LINEAR = 1

    # signals
    dragStateChanged = pyqtSignal(bool)
    realValueChanged = pyqtSignal(float)

    def __init__(self, parent, index=0):
        QDial.__init__(self, parent)

        self.fDialMode = self.MODE_LINEAR

        self.fMinimum = 0.0
        self.fMaximum = 1.0
        self.fRealValue = 0.0
        self.fPrecision = 10000
        self.fIsInteger = False

        self.fIsHovered = False
        self.fIsPressed = False
        self.fHoverStep = self.HOVER_MIN

        self.fLastDragPos = None
        self.fLastDragValue = 0.0

        self.fIndex = index
        self.fImage = QSvgWidget(":/scalable/dial_03.svg")
        self.fImageNum = "01"

        if self.fImage.sizeHint().width() > self.fImage.sizeHint().height():
            self.fImageOrientation = self.HORIZONTAL
        else:
            self.fImageOrientation = self.VERTICAL

        self.fLabel = ""
        self.fLabelPos = QPointF(0.0, 0.0)
        self.fLabelFont = QFont(self.font())
        self.fLabelFont.setPixelSize(8)
        self.fLabelWidth = 0
        self.fLabelHeight = 0

        if self.palette().window().color().lightness() > 100:
            # Light background
            c = self.palette().dark().color()
            self.fLabelGradientColor1 = c
            self.fLabelGradientColor2 = QColor(c.red(), c.green(), c.blue(), 0)
            self.fLabelGradientColorT = [
                self.palette().buttonText().color(),
                self.palette().mid().color()
            ]
        else:
            # Dark background
            self.fLabelGradientColor1 = QColor(0, 0, 0, 255)
            self.fLabelGradientColor2 = QColor(0, 0, 0, 0)
            self.fLabelGradientColorT = [Qt.white, Qt.darkGray]

        self.fLabelGradient = QLinearGradient(0, 0, 0, 1)
        self.fLabelGradient.setColorAt(0.0, self.fLabelGradientColor1)
        self.fLabelGradient.setColorAt(0.6, self.fLabelGradientColor1)
        self.fLabelGradient.setColorAt(1.0, self.fLabelGradientColor2)

        self.fLabelGradientRect = QRectF(0.0, 0.0, 0.0, 0.0)

        self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_NULL
        self.fCustomPaintColor = QColor(0xff, 0xff, 0xff)

        self.updateSizes()

        # Fake internal value, custom precision
        QDial.setMinimum(self, 0)
        QDial.setMaximum(self, self.fPrecision)
        QDial.setValue(self, 0)

        self.valueChanged.connect(self.slot_valueChanged)

    def getIndex(self):
        return self.fIndex

    def getBaseSize(self):
        return self.fImageBaseSize

    def forceWhiteLabelGradientText(self):
        self.fLabelGradientColor1 = QColor(0, 0, 0, 255)
        self.fLabelGradientColor2 = QColor(0, 0, 0, 0)
        self.fLabelGradientColorT = [Qt.white, Qt.darkGray]

    def setLabelColor(self, enabled, disabled):
        self.fLabelGradientColor1 = QColor(0, 0, 0, 255)
        self.fLabelGradientColor2 = QColor(0, 0, 0, 0)
        self.fLabelGradientColorT = [enabled, disabled]

    def updateSizes(self):
        if isinstance(self.fImage, QPixmap):
            self.fImageWidth = self.fImage.width()
            self.fImageHeight = self.fImage.height()
        else:
            self.fImageWidth = self.fImage.sizeHint().width()
            self.fImageHeight = self.fImage.sizeHint().height()

        if self.fImageWidth < 1:
            self.fImageWidth = 1

        if self.fImageHeight < 1:
            self.fImageHeight = 1

        if self.fImageOrientation == self.HORIZONTAL:
            self.fImageBaseSize = self.fImageHeight
            self.fImageLayersCount = self.fImageWidth / self.fImageHeight
        else:
            self.fImageBaseSize = self.fImageWidth
            self.fImageLayersCount = self.fImageHeight / self.fImageWidth

        self.setMinimumSize(self.fImageBaseSize,
                            self.fImageBaseSize + self.fLabelHeight + 5)
        self.setMaximumSize(self.fImageBaseSize,
                            self.fImageBaseSize + self.fLabelHeight + 5)

        if not self.fLabel:
            self.fLabelHeight = 0
            self.fLabelWidth = 0
            return

        self.fLabelWidth = QFontMetrics(self.fLabelFont).width(self.fLabel)
        self.fLabelHeight = QFontMetrics(self.fLabelFont).height()

        self.fLabelPos.setX(
            float(self.fImageBaseSize) / 2.0 - float(self.fLabelWidth) / 2.0)

        if self.fImageNum in ("01", "02", "07", "08", "09", "10"):
            self.fLabelPos.setY(self.fImageBaseSize + self.fLabelHeight)
        elif self.fImageNum in ("11", ):
            self.fLabelPos.setY(self.fImageBaseSize +
                                self.fLabelHeight * 2 / 3)
        else:
            self.fLabelPos.setY(self.fImageBaseSize + self.fLabelHeight / 2)

        self.fLabelGradient.setStart(0, float(self.fImageBaseSize) / 2.0)
        self.fLabelGradient.setFinalStop(
            0, self.fImageBaseSize + self.fLabelHeight + 5)

        self.fLabelGradientRect = QRectF(
            float(self.fImageBaseSize) / 8.0,
            float(self.fImageBaseSize) / 2.0,
            float(self.fImageBaseSize * 3) / 4.0,
            self.fImageBaseSize + self.fLabelHeight + 5)

    def setCustomPaintMode(self, paintMode):
        if self.fCustomPaintMode == paintMode:
            return

        self.fCustomPaintMode = paintMode
        self.update()

    def setCustomPaintColor(self, color):
        if self.fCustomPaintColor == color:
            return

        self.fCustomPaintColor = color
        self.update()

    def setLabel(self, label):
        if self.fLabel == label:
            return

        self.fLabel = label
        self.updateSizes()
        self.update()

    def setIndex(self, index):
        self.fIndex = index

    def setImage(self, imageId):
        self.fImageNum = "%02i" % imageId
        if imageId in (2, 6, 7, 8, 9, 10, 11, 12, 13):
            img = ":/bitmaps/dial_%s%s.png" % (self.fImageNum,
                                               "" if self.isEnabled() else "d")
        else:
            img = ":/scalable/dial_%s%s.svg" % (self.fImageNum, ""
                                                if self.isEnabled() else "d")

        if img.endswith(".png"):
            if not isinstance(self.fImage, QPixmap):
                self.fImage = QPixmap()
        else:
            if not isinstance(self.fImage, QSvgWidget):
                self.fImage = QSvgWidget()

        self.fImage.load(img)

        if self.fImage.width() > self.fImage.height():
            self.fImageOrientation = self.HORIZONTAL
        else:
            self.fImageOrientation = self.VERTICAL

        # special svgs
        if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_NULL:
            # reserved for carla-wet, carla-vol, carla-pan and color
            if self.fImageNum == "03":
                self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_COLOR

            # reserved for carla-L and carla-R
            elif self.fImageNum == "04":
                self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_CARLA_L

            # reserved for zita
            elif self.fImageNum == "06":
                self.fCustomPaintMode = self.CUSTOM_PAINT_MODE_ZITA

        self.updateSizes()
        self.update()

    def setPrecision(self, value, isInteger):
        self.fPrecision = value
        self.fIsInteger = isInteger
        QDial.setMaximum(self, value)

    def setMinimum(self, value):
        self.fMinimum = value

    def setMaximum(self, value):
        self.fMaximum = value

    def rvalue(self):
        return self.fRealValue

    def setValue(self, value, emitSignal=False):
        if self.fRealValue == value or isnan(value):
            return

        if value <= self.fMinimum:
            qtValue = 0
            self.fRealValue = self.fMinimum

        elif value >= self.fMaximum:
            qtValue = self.fPrecision
            self.fRealValue = self.fMaximum

        else:
            qtValue = round(
                float(value - self.fMinimum) /
                float(self.fMaximum - self.fMinimum) * self.fPrecision)
            self.fRealValue = value

        # Block change signal, we'll handle it ourselves
        self.blockSignals(True)
        QDial.setValue(self, qtValue)
        self.blockSignals(False)

        if emitSignal:
            self.realValueChanged.emit(self.fRealValue)

    @pyqtSlot(int)
    def slot_valueChanged(self, value):
        self.fRealValue = float(value) / self.fPrecision * (
            self.fMaximum - self.fMinimum) + self.fMinimum
        self.realValueChanged.emit(self.fRealValue)

    @pyqtSlot()
    def slot_updateImage(self):
        self.setImage(int(self.fImageNum))

    def minimumSizeHint(self):
        return QSize(self.fImageBaseSize, self.fImageBaseSize)

    def sizeHint(self):
        return QSize(self.fImageBaseSize, self.fImageBaseSize)

    def changeEvent(self, event):
        QDial.changeEvent(self, event)

        # Force svg update if enabled state changes
        if event.type() == QEvent.EnabledChange:
            self.slot_updateImage()

    def enterEvent(self, event):
        self.fIsHovered = True
        if self.fHoverStep == self.HOVER_MIN:
            self.fHoverStep = self.HOVER_MIN + 1
        QDial.enterEvent(self, event)

    def leaveEvent(self, event):
        self.fIsHovered = False
        if self.fHoverStep == self.HOVER_MAX:
            self.fHoverStep = self.HOVER_MAX - 1
        QDial.leaveEvent(self, event)

    def mousePressEvent(self, event):
        if self.fDialMode == self.MODE_DEFAULT:
            return QDial.mousePressEvent(self, event)

        if event.button() == Qt.LeftButton:
            self.fIsPressed = True
            self.fLastDragPos = event.pos()
            self.fLastDragValue = self.fRealValue
            self.dragStateChanged.emit(True)

    def mouseMoveEvent(self, event):
        if self.fDialMode == self.MODE_DEFAULT:
            return QDial.mouseMoveEvent(self, event)

        if not self.fIsPressed:
            return

        range = (self.fMaximum - self.fMinimum) / 4.0
        pos = event.pos()
        dx = range * float(pos.x() - self.fLastDragPos.x()) / self.width()
        dy = range * float(pos.y() - self.fLastDragPos.y()) / self.height()
        value = self.fLastDragValue + dx - dy

        if value < self.fMinimum:
            value = self.fMinimum
        elif value > self.fMaximum:
            value = self.fMaximum
        elif self.fIsInteger:
            value = float(round(value))

        self.setValue(value, True)

    def mouseReleaseEvent(self, event):
        if self.fDialMode == self.MODE_DEFAULT:
            return QDial.mouseReleaseEvent(self, event)

        if self.fIsPressed:
            self.fIsPressed = False
            self.dragStateChanged.emit(False)

    def paintEvent(self, event):
        painter = QPainter(self)
        event.accept()

        painter.save()
        painter.setRenderHint(QPainter.Antialiasing, True)

        if self.fLabel:
            if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_NULL:
                painter.setPen(self.fLabelGradientColor2)
                painter.setBrush(self.fLabelGradient)
                painter.drawRect(self.fLabelGradientRect)

            painter.setFont(self.fLabelFont)
            painter.setPen(
                self.fLabelGradientColorT[0 if self.isEnabled() else 1])
            painter.drawText(self.fLabelPos, self.fLabel)

        if self.isEnabled():
            normValue = float(self.fRealValue -
                              self.fMinimum) / float(self.fMaximum -
                                                     self.fMinimum)
            curLayer = int((self.fImageLayersCount - 1) * normValue)

            if self.fImageOrientation == self.HORIZONTAL:
                xpos = self.fImageBaseSize * curLayer
                ypos = 0.0
            else:
                xpos = 0.0
                ypos = self.fImageBaseSize * curLayer

            source = QRectF(xpos, ypos, self.fImageBaseSize,
                            self.fImageBaseSize)

            if isinstance(self.fImage, QPixmap):
                target = QRectF(0.0, 0.0, self.fImageBaseSize,
                                self.fImageBaseSize)
                painter.drawPixmap(target, self.fImage, source)
            else:
                self.fImage.renderer().render(painter, source)

            # Custom knobs (Dry/Wet and Volume)
            if self.fCustomPaintMode in (self.CUSTOM_PAINT_MODE_CARLA_WET,
                                         self.CUSTOM_PAINT_MODE_CARLA_VOL):
                # knob color
                colorGreen = QColor(0x5D, 0xE7,
                                    0x3D).lighter(100 + self.fHoverStep * 6)
                colorBlue = QColor(0x3E, 0xB8,
                                   0xBE).lighter(100 + self.fHoverStep * 6)

                # draw small circle
                ballRect = QRectF(8.0, 8.0, 15.0, 15.0)
                ballPath = QPainterPath()
                ballPath.addEllipse(ballRect)
                #painter.drawRect(ballRect)
                tmpValue = (0.375 + 0.75 * normValue)
                ballValue = tmpValue - floor(tmpValue)
                ballPoint = ballPath.pointAtPercent(ballValue)

                # draw arc
                startAngle = 218 * 16
                spanAngle = -255 * 16 * normValue

                if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_CARLA_WET:
                    painter.setBrush(colorBlue)
                    painter.setPen(QPen(colorBlue, 0))
                    painter.drawEllipse(
                        QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))

                    gradient = QConicalGradient(15.5, 15.5, -45)
                    gradient.setColorAt(0.0, colorBlue)
                    gradient.setColorAt(0.125, colorBlue)
                    gradient.setColorAt(0.625, colorGreen)
                    gradient.setColorAt(0.75, colorGreen)
                    gradient.setColorAt(0.76, colorGreen)
                    gradient.setColorAt(1.0, colorGreen)
                    painter.setBrush(gradient)
                    painter.setPen(QPen(gradient, 3))

                else:
                    painter.setBrush(colorBlue)
                    painter.setPen(QPen(colorBlue, 0))
                    painter.drawEllipse(
                        QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))

                    painter.setBrush(colorBlue)
                    painter.setPen(QPen(colorBlue, 3))

                painter.drawArc(4.0, 4.0, 26.0, 26.0, startAngle, spanAngle)

            # Custom knobs (L and R)
            elif self.fCustomPaintMode in (self.CUSTOM_PAINT_MODE_CARLA_L,
                                           self.CUSTOM_PAINT_MODE_CARLA_R):
                # knob color
                color = QColor(0xAD, 0xD5,
                               0x48).lighter(100 + self.fHoverStep * 6)

                # draw small circle
                ballRect = QRectF(7.0, 8.0, 11.0, 12.0)
                ballPath = QPainterPath()
                ballPath.addEllipse(ballRect)
                #painter.drawRect(ballRect)
                tmpValue = (0.375 + 0.75 * normValue)
                ballValue = tmpValue - floor(tmpValue)
                ballPoint = ballPath.pointAtPercent(ballValue)

                painter.setBrush(color)
                painter.setPen(QPen(color, 0))
                painter.drawEllipse(
                    QRectF(ballPoint.x(), ballPoint.y(), 2.0, 2.0))

                # draw arc
                if self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_CARLA_L:
                    startAngle = 218 * 16
                    spanAngle = -255 * 16 * normValue
                else:
                    startAngle = 322.0 * 16
                    spanAngle = 255.0 * 16 * (1.0 - normValue)

                painter.setPen(QPen(color, 2.5))
                painter.drawArc(3.5, 3.5, 22.0, 22.0, startAngle, spanAngle)

            # Custom knobs (Color)
            elif self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_COLOR:
                # knob color
                color = self.fCustomPaintColor.lighter(100 +
                                                       self.fHoverStep * 6)

                # draw small circle
                ballRect = QRectF(8.0, 8.0, 15.0, 15.0)
                ballPath = QPainterPath()
                ballPath.addEllipse(ballRect)
                tmpValue = (0.375 + 0.75 * normValue)
                ballValue = tmpValue - floor(tmpValue)
                ballPoint = ballPath.pointAtPercent(ballValue)

                # draw arc
                startAngle = 218 * 16
                spanAngle = -255 * 16 * normValue

                painter.setBrush(color)
                painter.setPen(QPen(color, 0))
                painter.drawEllipse(
                    QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2))

                painter.setBrush(color)
                painter.setPen(QPen(color, 3))
                painter.drawArc(4.0, 4.8, 26.0, 26.0, startAngle, spanAngle)

            # Custom knobs (Zita)
            elif self.fCustomPaintMode == self.CUSTOM_PAINT_MODE_ZITA:
                a = normValue * pi * 1.5 - 2.35
                r = 10.0
                x = 10.5
                y = 10.5
                x += r * sin(a)
                y -= r * cos(a)
                painter.setBrush(Qt.black)
                painter.setPen(QPen(Qt.black, 2))
                painter.drawLine(QPointF(11.0, 11.0), QPointF(x, y))

            # Custom knobs
            else:
                painter.restore()
                return

            if self.HOVER_MIN < self.fHoverStep < self.HOVER_MAX:
                self.fHoverStep += 1 if self.fIsHovered else -1
                QTimer.singleShot(20, self.update)

        else:  # isEnabled()
            target = QRectF(0.0, 0.0, self.fImageBaseSize, self.fImageBaseSize)
            if isinstance(self.fImage, QPixmap):
                painter.drawPixmap(target, self.fImage, target)
            else:
                self.fImage.renderer().render(painter, target)

        painter.restore()

    def resizeEvent(self, event):
        QDial.resizeEvent(self, event)
        self.updateSizes()
Example #27
0
class ChessBoard(QWidget, chess.Board):
    """
      BRIEF  An interactive chessboard that only allows legal moves
   """

    ReadyForNextMove = pyqtSignal(str)
    GameOver = pyqtSignal()

    def __init__(self, parent=None):
        """
         BRIEF  Initialize the chessboard
      """
        super().__init__(parent)
        self.setWindowTitle("Chess")

        self.svg_xy = 50  # top left x,y-pos of chessboard
        self.board_size = 600  # size of chessboard
        self.margin = 0.05 * self.board_size
        self.square_size = (self.board_size - 2 * self.margin) / 8.0
        wnd_wh = self.board_size + 2 * self.svg_xy

        self.setMinimumSize(wnd_wh, wnd_wh)
        self.svg_widget = QSvgWidget(parent=self)
        self.svg_widget.setGeometry(self.svg_xy, self.svg_xy, self.board_size,
                                    self.board_size)

        self.last_click = None
        self.DrawBoard()

    @pyqtSlot(QWidget)
    def mousePressEvent(self, event):
        """
         BRIEF  Update the board state based on user clicks
                If the state changes, update the svg widget
      """
        if self.LeftClickedBoard(event):
            this_click = self.GetClicked(event)

            if self.last_click:
                if self.last_click != this_click:
                    uci = self.last_click + this_click
                    self.ApplyMove(uci + self.GetPromotion(uci))

            self.last_click = this_click

    def GetPromotion(self, uci):
        """
         BRIEF  Get the uci piece type the pawn will be promoted to
      """
        if chess.Move.from_uci(uci + 'q') in self.legal_moves:
            dialog = PromotionDialog(self)
            if dialog.exec() == QDialog.Accepted:
                return dialog.SelectedPiece()
        return ''

    @pyqtSlot(str)
    def ApplyMove(self, uci):
        """
         BRIEF  Apply a move to the board
      """
        move = chess.Move.from_uci(uci)
        if move in self.legal_moves:
            self.push(move)
            self.DrawBoard()

            print(self.fen())
            if not self.is_game_over():
                self.ReadyForNextMove.emit(self.fen())
            else:
                print("Game over!")
                self.GameOver.emit()
            sys.stdout.flush()

    @pyqtSlot()
    def UndoMove(self):
        """
      """
        try:
            self.pop()
            self.DrawBoard()
            self.ReadyForNextMove.emit(self.fen())
        except IndexError:
            pass

    def DrawBoard(self):
        """
         BRIEF  Redraw the chessboard based on board state
                Highlight src and dest squares for last move
                Highlight king if in check
      """
        self.svg_widget.load(self._repr_svg_().encode("utf-8"))

    def GetClicked(self, event):
        """
         BRIEF  Get the algebraic notation for the clicked square
      """
        top_left = self.svg_xy + self.margin
        file_i = int((event.x() - top_left) / self.square_size)
        rank_i = 7 - int((event.y() - top_left) / self.square_size)
        return chr(file_i + 97) + str(rank_i + 1)

    def LeftClickedBoard(self, event):
        """
         BRIEF  Check to see if they left-clicked on the chess board
      """
        topleft = self.svg_xy + self.margin
        bottomright = self.board_size + self.svg_xy - self.margin
        return all([
            event.buttons() == Qt.LeftButton,
            topleft < event.x() < bottomright,
            topleft < event.y() < bottomright,
        ])
Example #28
0
class Notification(object):
    def __init__(self,
                 window,
                 styleFunction,
                 stylesheet=["", "", ""],
                 img_margin=5,
                 top_margin=5,
                 pos=[0, 0],
                 size=[100, 20]):
        self._styleFunction = styleFunction
        self._currApp = ''
        self._pos = pos

        # Create components
        ### Notification Background
        self._background_main_stylesheet = stylesheet[0]
        self._background = QLabel(window)
        self._background.setGeometry(pos[0], pos[1], size[0], size[1])
        self._background.hide()
        ### Notification Logo
        self._logo = None
        self._logo_geometry = [
            img_margin, img_margin, size[1] - img_margin * 2,
            size[1] - img_margin * 2
        ]
        ### Notification Title
        self._title = QLabel(self._background)
        self._title.setAttribute(Qt.WA_TranslucentBackground)
        self._title.setAlignment(Qt.AlignTop | Qt.AlignLeft)
        self._title.setStyleSheet('QLabel{' + stylesheet[1] + '}')
        self._title.setText('Title')
        self._title.adjustSize()
        self._title.setGeometry(
            img_margin + self._logo_geometry[2] + 4, top_margin,
            size[0] - img_margin - self._logo_geometry[2] - 4,
            self._title.height())
        self._title.show()
        ### Notification Message
        self._message = QLabel(self._background)
        self._message.setAttribute(Qt.WA_TranslucentBackground)
        self._message.setAlignment(Qt.AlignTop | Qt.AlignLeft)
        self._message.setStyleSheet('QLabel{' + stylesheet[2] + '}')
        self._message.setText('Message')
        self._message.adjustSize()
        self._message.setGeometry(
            img_margin + self._logo_geometry[2] + 8,
            top_margin + self._title.height() + 2,
            size[0] - img_margin - self._logo_geometry[2] - 8,
            self._message.height() * 2)
        self._message.show()

    def setParent(self, p):
        self._background.setParent(p)

    def deleteLater(self):
        self._background.deleteLater()

    def setText(self, app, title, message):
        if self._currApp != app:
            logoPath, backgroundColor = self._styleFunction(app)
            if self._logo == None:
                self._logo = QSvgWidget(logoPath, self._background)
                self._logo.setGeometry(self._logo_geometry[0],
                                       self._logo_geometry[1],
                                       self._logo_geometry[2],
                                       self._logo_geometry[3])
                self._logo.show()
            else:
                self._logo.load(logoPath)
            self._background.setStyleSheet('QLabel {background-color:' +
                                           backgroundColor + ';' +
                                           self._background_main_stylesheet +
                                           '}')
            self._logo.setStyleSheet('background-color:' + backgroundColor +
                                     ';')
            self._currApp = app

        # Update Textual Contents
        self._title.setText(title)
        self._message.setText(message)
        self._message.setWordWrap(True)

    def update(self):
        self._background.update()
        self._logo.update()
        self._title.update()
        self._message.update()

    def show(self):
        self._background.show()

    def hide(self):
        self._background.hide()

    def move(self, x, y):
        self._pos = [x, y]
        self._background.move(x, y)

    def moveX(self, x):
        self._pos[0] = x
        self._background.move(x, self._pos[1])

    def moveY(self, y):
        self._pos[1] = y
        self._background.move(self._pos[0], y)

    def bringToFront(self):
        self._background.raise_()

    def bringToBack(self):
        self._background.lower()
Example #29
0
 def add_svg(self, title, data):
     svg = QSvgWidget()
     svg.load(data)
     scrollpane = QScrollArea()
     scrollpane.setWidget(svg)
     self.tabs.addTab(scrollpane, title)
Example #30
0
 def add_svg(self, title, data):
     editor = QSvgWidget()
     editor.load(data)
     self.tabs.addTab(editor, title)
Example #31
0
 def add_svg(self, title, data):
     editor = QSvgWidget()
     editor.load(data)
     self.tabs.addTab(editor, title)
Example #32
0
class Emulator(QWidget, ui_emulator.Ui_Emulator):
    game_found = QtCore.pyqtSignal(int, dict, str, int)
    games_loaded = QtCore.pyqtSignal()

    def __init__(self, data):
        super(Emulator, self).__init__()
        self.setupUi(self)
        self.data = data

        self.processes = { }
        self.roms = [ ]

        self.settings = QSettings('SanderTheDragon', 'Qtendo')
        self.settings_prefix = 'emulation/emulator/' + self.data['name'].lower().replace(' ', '_')

        self.config_files = self.get_config_files()

        self.settings_dialog = emulator_settings.EmulatorSettingsDialog(parent=self, data=self.data)
        self.settings_dialog.accepted.connect(lambda: self.reload_settings())
        self.settings_dialog.setWindowTitle(self.data['name'] + ' Settings')

        self.ui_create()
        self.ui_connect()

        Thread(target=self.find_games, daemon=True).start()



    def ui_create(self):
        self.pathLabel.setText(self.settings.value(self.settings_prefix + '/path', self.data['path'], type=str))

        name = self.nameLabel.text()
        name = name.replace('{NAME}', self.data['name'])
        name = name.replace('{URL}', self.data['site'])

        version = self.data['version']
        if version == 'Not Found' and len(self.pathLabel.text()) > 0:
            version_ = self.data['get_version'](self.pathLabel.text())
            if len(version) > 0:
                version = version_
        self.version_pos = name.find('{VERSION}')
        name = name[:self.version_pos] + version

        self.nameLabel.setText(name)

        if self.data['icon'].endswith('.svg'):
            self.svgWidget = QSvgWidget()
            self.svgWidget.load(':' + self.data['icon'])
            self.svgWidget.setMaximumSize(QSize(24, 24))
            self.gridLayout.addWidget(self.svgWidget, 0, 0)
        else:
            self.iconLabel = QLabel()
            self.iconLabel.setPixmap(QPixmap(':' + self.data['icon']).scaled(24, 24))
            self.gridLayout.addWidget(self.iconLabel, 0, 0)

        platformText = ''
        for platform in self.data['platforms'].keys():
            platformText += '&nbsp;&nbsp;&nbsp;&nbsp;• ' + platform + ' (' + ', '.join(self.data['platforms'][platform]) + ')<br/>'

        self.platformLabel.setText(self.platformLabel.text().replace('{PLATFORMS}', platformText))

        self.gameList.insertColumn(0)
        self.gameList.insertColumn(1)
        self.gameList.insertColumn(2)
        self.gameList.insertColumn(3)
        self.gameList.insertColumn(4)
        self.gameList.setHorizontalHeaderLabels([ 'Platform', 'ID', 'Title', 'Region', 'Path' ])
        self.gameList.horizontalHeader().setStretchLastSection(True)

        self.gameList.setContextMenuPolicy(Qt.CustomContextMenu)


    def ui_connect(self):
        self.game_found.connect(self.add_game)
        self.games_loaded.connect(self.done_loading)

        self.gameList.customContextMenuRequested.connect(lambda position: self.game_list_context_menu(position))
        self.gameList.cellDoubleClicked.connect(lambda row, column: self.launch_game(self.gameList.item(row, 4).text()))
        self.refreshButton.pressed.connect(lambda: ( self.reset_list(), Thread(target=self.find_games, daemon=True).start() ))
        self.settingsButton.pressed.connect(lambda: self.settings_dialog.exec_())
        self.filterEdit.textChanged.connect(lambda text: self.search())



    def find_games(self):
        file_types = [ ]
        for platform in self.data['platforms'].keys():
            file_types += self.data['platforms'][platform]

        logging.debug('[' + self.data['name'] + '] Searching for ( ' + ', '.join(file_types) + ' ) files')

        paths = self.settings.value('emulation/roms/paths', [ ], type=str)
        games_length = 0
        for path in paths:
            if not os.path.isdir(path):
                continue

            possible_games = utils.find_files(path, file_types)
            games_length = len(possible_games)
            logging.debug('[' + self.data['name'] + '] Found ' + str(games_length) + ' possible ROM' + ('s' if games_length != 1 else ''))
            for game in possible_games:
                index = self.gameList.rowCount()

                try:
                    rom_ = rom.Rom(game, self.data['platforms'])
                    if rom_.is_rom:
                        logging.debug('[' + self.data['name'] + '] \'' + game + '\' is a valid ROM')
                        self.roms.append(rom_)
                        info = rom_.module.get_info(game)
                        self.game_found.emit(index, info, game, games_length)
                    else:
                        logging.debug('[' + self.data['name'] + '] \'' + game + '\' is not a valid ROM')
                        games_length -= 1
                except:
                    traceback.print_exc()

        logging.debug('[' + self.data['name'] + '] Found ' + str(games_length) + ' ROM' + ('s' if games_length != 1 else ''))
        self.games_loaded.emit()


    def add_game(self, index, info, path, count):
        self.gameList.insertRow(index)

        if len(info.keys()) > 0:
            self.gameList.setItem(index, 0, QTableWidgetItem(info['platform']))
            self.gameList.setItem(index, 1, QTableWidgetItem(info['id']))
            self.gameList.setItem(index, 2, QTableWidgetItem(info['title']))
            self.gameList.setItem(index, 3, QTableWidgetItem(info['region'] + '(' + info['region_code'] + ')'))

        self.gameList.setItem(index, 4, QTableWidgetItem(path))
        self.gameList.resizeColumnsToContents()

        self.progressBar.setValue(int(100.0 / float(count) * float(index + 1)))


    def reset_list(self):
        self.refreshButton.setEnabled(False)
        self.progressBar.setValue(0)
        self.progressBar.setVisible(True)
        self.gameList.setSortingEnabled(False)
        self.gameList.setRowCount(0)
        self.roms.clear()


    def done_loading(self):
        self.gameList.setSortingEnabled(True)
        self.gameList.sortItems(1)
        self.progressBar.setVisible(False)
        self.refreshButton.setEnabled(True)
        self.search()


    def launch_game(self, path):
        if path in self.processes:
            return

        command = self.settings.value(self.settings_prefix + '/command', '{EXEC} {ARGS} {ROM}', type=str)
        command = command.replace('{EXEC}', self.settings.value(self.settings_prefix + '/path', self.data['path'], type=str))
        command = command.replace('{ARGS}', ' '.join(self.data['arguments']))
        command = command.replace('{ROM}', shlex.quote(path))
        logging.info('[' + self.data['name'] + '] Launching: `' + command + '`')

        process = QProcess(self)
        process.finished.connect(functools.partial(self.end_game, path))

        if self.settings.value('emulation/log/stdout', True, type=bool):
            process.readyReadStandardOutput.connect(functools.partial(lambda path: self.log_game(path, bytes(self.processes[path].readAllStandardOutput()).decode('utf-8')), path))

        if self.settings.value('emulation/log/stderr', True, type=bool):
            process.readyReadStandardError.connect(functools.partial(lambda path: self.log_game(path, bytes(self.processes[path].readAllStandardError()).decode('utf-8'), logging.error), path))
            process.errorOccurred.connect(functools.partial(lambda path, error: self.log_game(path, str(error), logging.error), path))

        args = shlex.split(command)
        self.processes[path] = process
        self.processes[path].start(args[0], args[1:])


    def log_game(self, path, message, method=logging.info):
        if '\n' in message:
            for line in message.split('\n'):
                self.log_game(path, line, method)
        else:
            message = utils.ansi_trim(message.strip())
            if len(message) == 0:
                return

            method('[' + self.data['name'] + ':' + path[path.rfind('/') + 1:] + '] ' + message)


    def end_game(self, path, code, status):
        if code == 0:
            logging.info('[' + self.data['name'] + '] Process for \'' + path + '\' exited')
        else:
            logging.error('[' + self.data['name'] + '] Process for \'' + path + '\' exited with non-zero code: ' + str(code))

        del self.processes[path]


    def reload_settings(self):
        self.pathLabel.setText(self.settings.value(self.settings_prefix + '/path', self.data['path'], type=str))

        name = self.nameLabel.text()
        version = self.data['get_version'](self.pathLabel.text())
        if len(version) > 0:
            name = name[:self.version_pos] + version
        self.nameLabel.setText(name)

        self.data['reload_settings']()


    def game_list_context_menu(self, position):
        menu = QMenu()
        launchAction = menu.addAction("Launch")
        menu.addSeparator()

        action = menu.exec_(self.gameList.mapToGlobal(position))

        if action == launchAction:
             self.launch_game(self.gameList.item(self.gameList.selectionModel().selectedRows()[0].row(), 4).text())


    def search(self):
        text = self.filterEdit.text()
        for i in range(self.gameList.rowCount()):
            if text.lower() in self.gameList.item(i, 2).text().lower():
                self.gameList.showRow(i)
            else:
                self.gameList.hideRow(i)
Example #33
0
class SuggestRow(QPushButton):
    def __init__(self, parent, suggestion: Suggestion):
        QWidget.__init__(self, parent)
        # defines whether the command has associated options
        self.has_options = True if hasattr(suggestion,
                                           "option_suggestions") else False
        # gets the current theme
        self.active_theme = parent.active_theme
        # gets the font
        self.custom_font = parent.custom_font
        # setting height the row
        width, height = [parent.width(), 57]
        self.resize(width, height)
        # makes command dictionary a class variable
        self.suggestion = suggestion  # Stores information about the command the row will hold
        # widget creation
        self.icon = None  # This can either be an svg or jpg file
        icon_path = self.suggestion.icon_name  # gets the icon path
        if "svg" in icon_path:
            self.icon = QSvgWidget(self)
            self.icon.load(icon_path)
        else:
            pixmap = QPixmap(icon_path)
            icon = QLabel(self)
            icon.setPixmap(pixmap)
            self.icon = icon
        self.title_lbl = QLabel(self.suggestion.title, self)
        self.description_lbl = QLabel(self.suggestion.description, self)
        self.option_icon = QSvgWidget(self)
        self.option_icon.load(f"{ASSETS_DIR}svg{sep}ellipsis.svg")
        self.set_style()

    def set_style(self):
        # TODO: Add support for theming for icon and layout scalability components
        # set style and location of icon
        if "svg" in self.suggestion.icon_name:  # different location and sizes depending on icon type
            self.icon.move(18, 18)
            self.icon.resize(20, 20)
            self.icon.setStyleSheet("background-color: rgba(0,0,0,0%);")
        else:
            self.icon.move(8, 8)
            self.icon.resize(40, 40)
            self.icon.setAlignment(Qt.AlignCenter)
            self.icon.setScaledContents(True)
        # set style for options icon
        self.option_icon.move(490, 16)
        self.option_icon.resize(25, 25)
        self.option_icon.setStyleSheet("background-color: rgba(0,0,0,0%);")
        self.option_icon.hide()
        # set style and location of title
        self.title_lbl.move(56, 9)
        self.title_lbl.setStyleSheet(
            f"font-size: 20px; color: {self.active_theme.foreground}; background-color: rgba(0,0,0,0%);"
        )
        self.title_lbl.setFont(self.custom_font)
        # set style and location of description
        self.description_lbl.resize(479, 15)
        self.description_lbl.move(56, 33)
        self.description_lbl.setStyleSheet(
            f"font-size: 13px; color: {self.active_theme.foreground}; background-color: rgba(0,0,0,0%);"
        )
        self.description_lbl.setFont(self.custom_font)
        # style for widget
        self.setStyleSheet('''
        QPushButton {
            border: none;
        }
        QPushButton:hover {
            background-color: #251e1e;
        }
        QPushButton:hover:focus {
            background-color: #322828;
        }
        QPushButton:focus {
            background-color: #3f3232;
            outline: 0px
        }
        ''')

    def show_option_icon(self):
        if self.has_options:
            self.option_icon.show()

    def hide_option_icon(self):
        if self.has_options:
            self.option_icon.hide()
Example #34
0
class SvgDiagram(E5MainWindow):
    """
    Class implementing a dialog showing a SVG graphic.
    """
    ZoomLevels = [
        1, 3, 5, 7, 9,
        10, 20, 30, 50, 67, 80, 90,
        100,
        110, 120, 133, 150, 170, 200, 240, 300, 400,
        500, 600, 700, 800, 900, 1000,
    ]
    ZoomLevelDefault = 100
    
    def __init__(self, svgFile, parent=None, name=None):
        """
        Constructor
        
        @param svgFile filename of a SVG graphics file to show (string)
        @param parent parent widget of the view (QWidget)
        @param name name of the view widget (string)
        """
        super(SvgDiagram, self).__init__(parent)
        if name:
            self.setObjectName(name)
        else:
            self.setObjectName("SvgDiagram")
        self.setWindowTitle(self.tr("SVG-Viewer"))
        
        self.svgWidget = QSvgWidget()
        self.svgWidget.setObjectName("svgWidget")
        self.svgWidget.setBackgroundRole(QPalette.Base)
        self.svgWidget.setSizePolicy(QSizePolicy.Ignored, QSizePolicy.Ignored)
        
        self.svgView = QScrollArea()
        self.svgView.setObjectName("svgView")
        self.svgView.setBackgroundRole(QPalette.Dark)
        self.svgView.setWidget(self.svgWidget)
        
        self.setCentralWidget(self.svgView)
        
        self.__zoomWidget = E5ZoomWidget(
            UI.PixmapCache.getPixmap("zoomOut.png"),
            UI.PixmapCache.getPixmap("zoomIn.png"),
            UI.PixmapCache.getPixmap("zoomReset.png"), self)
        self.statusBar().addPermanentWidget(self.__zoomWidget)
        self.__zoomWidget.setMapping(
            SvgDiagram.ZoomLevels, SvgDiagram.ZoomLevelDefault)
        self.__zoomWidget.valueChanged.connect(self.__doZoom)
        
        # polish up the dialog
        self.resize(QSize(800, 600).expandedTo(self.minimumSizeHint()))
        
        self.zoom = 1.0
        self.svgFile = svgFile
        self.svgWidget.load(self.svgFile)
        self.svgWidget.resize(self.svgWidget.renderer().defaultSize())
        
        self.__initActions()
        self.__initContextMenu()
        self.__initToolBars()
        
        self.grabGesture(Qt.PinchGesture)
        
    def __initActions(self):
        """
        Private method to initialize the view actions.
        """
        self.closeAct = \
            QAction(UI.PixmapCache.getIcon("close.png"),
                    self.tr("Close"), self)
        self.closeAct.triggered.connect(self.close)
        
        self.printAct = \
            QAction(UI.PixmapCache.getIcon("print.png"),
                    self.tr("Print"), self)
        self.printAct.triggered.connect(self.__printDiagram)
        
        self.printPreviewAct = \
            QAction(UI.PixmapCache.getIcon("printPreview.png"),
                    self.tr("Print Preview"), self)
        self.printPreviewAct.triggered.connect(self.__printPreviewDiagram)
        
    def __initContextMenu(self):
        """
        Private method to initialize the context menu.
        """
        self.__menu = QMenu(self)
        self.__menu.addAction(self.closeAct)
        self.__menu.addSeparator()
        self.__menu.addAction(self.printPreviewAct)
        self.__menu.addAction(self.printAct)
        
        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self.__showContextMenu)
        
    def __showContextMenu(self, coord):
        """
        Private slot to show the context menu of the listview.
        
        @param coord the position of the mouse pointer (QPoint)
        """
        self.__menu.popup(self.mapToGlobal(coord))
        
    def __initToolBars(self):
        """
        Private method to populate the toolbars with our actions.
        """
        self.windowToolBar = QToolBar(self.tr("Window"), self)
        self.windowToolBar.setIconSize(UI.Config.ToolBarIconSize)
        self.windowToolBar.addAction(self.closeAct)
        
        self.graphicsToolBar = QToolBar(self.tr("Graphics"), self)
        self.graphicsToolBar.setIconSize(UI.Config.ToolBarIconSize)
        self.graphicsToolBar.addAction(self.printPreviewAct)
        self.graphicsToolBar.addAction(self.printAct)
        
        self.addToolBar(Qt.TopToolBarArea, self.windowToolBar)
        self.addToolBar(Qt.TopToolBarArea, self.graphicsToolBar)
        
    def getDiagramName(self):
        """
        Public method to retrieve a name for the diagram.
        
        @return name for the diagram
        """
        return self.svgFile
    
    def wheelEvent(self, evt):
        """
        Protected method to handle wheel events.
        
        @param evt reference to the wheel event (QWheelEvent)
        """
        if evt.modifiers() & Qt.ControlModifier:
            if qVersion() >= "5.0.0":
                delta = evt.angleDelta().y()
            else:
                delta = evt.delta()
            if delta < 0:
                self.__zoomOut()
            else:
                self.__zoomIn()
            evt.accept()
            return
        
        super(SvgDiagram, self).wheelEvent(evt)
    
    def event(self, evt):
        """
        Public method handling events.
        
        @param evt reference to the event (QEvent)
        @return flag indicating, if the event was handled (boolean)
        """
        if evt.type() == QEvent.Gesture:
            self.gestureEvent(evt)
            return True
        
        return super(SvgDiagram, self).event(evt)
    
    def gestureEvent(self, evt):
        """
        Protected method handling gesture events.
        
        @param evt reference to the gesture event (QGestureEvent
        """
        pinch = evt.gesture(Qt.PinchGesture)
        if pinch:
            if pinch.state() == Qt.GestureStarted:
                pinch.setScaleFactor(self.__zoom() / 100)
            else:
                self.__doZoom(int(pinch.scaleFactor() * 100))
            evt.accept()
    
    ###########################################################################
    ## Private menu handling methods below.
    ###########################################################################
    
    def __adjustScrollBar(self, scrollBar, factor):
        """
        Private method to adjust a scrollbar by a certain factor.
        
        @param scrollBar reference to the scrollbar object (QScrollBar)
        @param factor factor to adjust by (float)
        """
        scrollBar.setValue(
            int(factor * scrollBar.value() +
                ((factor - 1) * scrollBar.pageStep() / 2)))
        
    def __levelForZoom(self, zoom):
        """
        Private method determining the zoom level index given a zoom factor.
        
        @param zoom zoom factor (integer)
        @return index of zoom factor (integer)
        """
        try:
            index = SvgDiagram.ZoomLevels.index(zoom)
        except ValueError:
            for index in range(len(SvgDiagram.ZoomLevels)):
                if zoom <= SvgDiagram.ZoomLevels[index]:
                    break
        return index
    
    def __doZoom(self, value):
        """
        Private method to set the zoom value in percent.
        
        @param value zoom value in percent (integer)
        """
        oldValue = self.__zoom()
        if value != oldValue:
            self.svgWidget.resize(value / 100 * self.svgWidget.sizeHint())
            
            factor = value / oldValue
            self.__adjustScrollBar(self.svgView.horizontalScrollBar(), factor)
            self.__adjustScrollBar(self.svgView.verticalScrollBar(), factor)
            
            self.__zoomWidget.setValue(value)
        
    def __zoomIn(self):
        """
        Private method to zoom into the SVG.
        """
        index = self.__levelForZoom(self.__zoom())
        if index < len(SvgDiagram.ZoomLevels) - 1:
            self.__doZoom(SvgDiagram.ZoomLevels[index + 1])
        
    def __zoomOut(self):
        """
        Private method to zoom out of the SVG.
        """
        index = self.__levelForZoom(self.__zoom())
        if index > 0:
            self.__doZoom(SvgDiagram.ZoomLevels[index - 1])
        
    def __zoomReset(self):
        """
        Private method to reset the zoom value.
        """
        self.__doZoom(SvgDiagram.ZoomLevels[SvgDiagram.ZoomLevelDefault])
        
    def __zoom(self):
        """
        Private method to get the current zoom factor in percent.
        
        @return current zoom factor in percent (integer)
        """
        return int(self.svgWidget.width() /
                   self.svgWidget.sizeHint().width() * 100.0)
        
    def __printDiagram(self):
        """
        Private slot called to print the diagram.
        """
        printer = QPrinter(mode=QPrinter.ScreenResolution)
        printer.setFullPage(True)
        if Preferences.getPrinter("ColorMode"):
            printer.setColorMode(QPrinter.Color)
        else:
            printer.setColorMode(QPrinter.GrayScale)
        if Preferences.getPrinter("FirstPageFirst"):
            printer.setPageOrder(QPrinter.FirstPageFirst)
        else:
            printer.setPageOrder(QPrinter.LastPageFirst)
        printerName = Preferences.getPrinter("PrinterName")
        if printerName:
            printer.setPrinterName(printerName)
        
        printDialog = QPrintDialog(printer, self)
        if printDialog.exec_():
            self.__print(printer)
        
    def __printPreviewDiagram(self):
        """
        Private slot called to show a print preview of the diagram.
        """
        from PyQt5.QtPrintSupport import QPrintPreviewDialog
        
        printer = QPrinter(mode=QPrinter.ScreenResolution)
        printer.setFullPage(True)
        if Preferences.getPrinter("ColorMode"):
            printer.setColorMode(QPrinter.Color)
        else:
            printer.setColorMode(QPrinter.GrayScale)
        if Preferences.getPrinter("FirstPageFirst"):
            printer.setPageOrder(QPrinter.FirstPageFirst)
        else:
            printer.setPageOrder(QPrinter.LastPageFirst)
        printer.setPageMargins(
            Preferences.getPrinter("LeftMargin") * 10,
            Preferences.getPrinter("TopMargin") * 10,
            Preferences.getPrinter("RightMargin") * 10,
            Preferences.getPrinter("BottomMargin") * 10,
            QPrinter.Millimeter
        )
        printerName = Preferences.getPrinter("PrinterName")
        if printerName:
            printer.setPrinterName(printerName)
        
        preview = QPrintPreviewDialog(printer, self)
        preview.paintRequested[QPrinter].connect(self.__print)
        preview.exec_()
        
    def __print(self, printer):
        """
        Private slot to the actual printing.
        
        @param printer reference to the printer object (QPrinter)
        """
        painter = QPainter()
        painter.begin(printer)

        # calculate margin and width of printout
        font = QFont("times", 10)
        painter.setFont(font)
        fm = painter.fontMetrics()
        fontHeight = fm.lineSpacing()
        marginX = printer.pageRect().x() - printer.paperRect().x()
        marginX = Preferences.getPrinter("LeftMargin") * \
            int(printer.resolution() / 2.54) - marginX
        marginY = printer.pageRect().y() - printer.paperRect().y()
        marginY = Preferences.getPrinter("TopMargin") * \
            int(printer.resolution() / 2.54) - marginY

        width = printer.width() - marginX - \
            Preferences.getPrinter("RightMargin") * \
            int(printer.resolution() / 2.54)
        height = printer.height() - fontHeight - 4 - marginY - \
            Preferences.getPrinter("BottomMargin") * \
            int(printer.resolution() / 2.54)

        # write a foot note
        s = self.tr("Diagram: {0}").format(self.getDiagramName())
        tc = QColor(50, 50, 50)
        painter.setPen(tc)
        painter.drawRect(marginX, marginY, width, height)
        painter.drawLine(marginX, marginY + height + 2,
                         marginX + width, marginY + height + 2)
        painter.setFont(font)
        painter.drawText(marginX, marginY + height + 4, width,
                         fontHeight, Qt.AlignRight, s)

        # render the diagram
        painter.setViewport(marginX, marginY, width, height)
        self.svgWidget.renderer().render(painter)
        painter.end()