Exemplo n.º 1
0
 def __init__(self, block):
     super().__init__()
     self.setFlag(QGraphicsItem.ItemIsMovable)
     self.setFlag(QGraphicsItem.ItemIsFocusable)
     self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
     self.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
     self.setAcceptHoverEvents(True)
     # define code text shape:
     self.code = QGraphicsTextItem()
     self.code.setHtml(block)
     f = QFont("Monospace")
     f.setPointSize(8)
     self.code.setFont(f)
     self.code.setParentItem(self)
     # define circle shape:
     self.codebox = QGraphicsRectItem(self.code.boundingRect().adjusted(
         -2, -2, 2, 2))
     self.codebox.setBrush(QBrush(QColor("#fdf6e3")))
     shadow = QGraphicsDropShadowEffect()
     shadow.setOffset(4)
     self.codebox.setGraphicsEffect(shadow)
     self.codebox.setParentItem(self)
     self.codebox.setZValue(1.0)
     self.code.setZValue(2.0)
     center = (self.codebox.boundingRect().center() -
               self.code.boundingRect().center())
     self.code.setPos(center)
     self.setZValue(1.0)
     self.cx = []
Exemplo n.º 2
0
 def __init__(self, name="?", r=10):
     super().__init__()
     self.setFlag(QGraphicsItem.ItemIsMovable)
     self.setFlag(QGraphicsItem.ItemIsFocusable)
     self.setFlag(QGraphicsItem.ItemSendsGeometryChanges)
     self.setCacheMode(QGraphicsItem.DeviceCoordinateCache)
     self.setAcceptHoverEvents(True)
     # define circle shape:
     w = 2 * r + 2
     self.el = QGraphicsEllipseItem(0, 0, w, w)
     self.el.setBrush(QBrush(QColor("white")))
     shadow = QGraphicsDropShadowEffect()
     shadow.setOffset(4)
     self.el.setGraphicsEffect(shadow)
     self.el.setParentItem(self)
     # define node label shape:
     self.label = QGraphicsTextItem(name)
     self.label.setDefaultTextColor(QColor("blue"))
     self.label.setFlag(QGraphicsItem.ItemIsSelectable)
     self.label.setParentItem(self)
     self.el.setZValue(1.0)
     self.label.setZValue(2.0)
     center = self.center() - self.label.boundingRect().center()
     self.label.setPos(self.mapFromScene(center))
     self.setZValue(1.0)
     self.cx = []
Exemplo n.º 3
0
    def __init__(self, lightTheme=False, useAlpha=False):
        super(ColorPicker, self).__init__()

        self.usingAlpha = useAlpha

        # Call UI Builder function
        if useAlpha:
            if lightTheme: self.ui = Ui_Light_Alpha()
            else: self.ui = Ui_Dark_Alpha()
            self.ui.setupUi(self)
        else:
            if lightTheme: self.ui = Ui_Light()
            else: self.ui = Ui_Dark()
            self.ui.setupUi(self)

        # Make Frameless
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setWindowTitle("Color Picker")

        # Add DropShadow
        self.shadow = QGraphicsDropShadowEffect(self)
        self.shadow.setBlurRadius(17)
        self.shadow.setXOffset(0)
        self.shadow.setYOffset(0)
        self.shadow.setColor(QColor(0, 0, 0, 150))
        self.ui.drop_shadow_frame.setGraphicsEffect(self.shadow)

        # Connect update functions
        self.ui.hue.mouseMoveEvent = self.moveHueSelector
        self.ui.red.textEdited.connect(self.rgbChanged)
        self.ui.green.textEdited.connect(self.rgbChanged)
        self.ui.blue.textEdited.connect(self.rgbChanged)
        self.ui.hex.textEdited.connect(self.hexChanged)
        if self.usingAlpha: self.ui.alpha.textEdited.connect(self.alphaChanged)

        # Connect window dragging functions
        self.ui.title_bar.mouseMoveEvent = self.moveWindow
        self.ui.title_bar.mousePressEvent = self.setDragPos
        self.ui.window_title.mouseMoveEvent = self.moveWindow
        self.ui.window_title.mousePressEvent = self.setDragPos

        # Connect selector moving function
        self.ui.black_overlay.mouseMoveEvent = self.moveSVSelector
        self.ui.black_overlay.mousePressEvent = self.moveSVSelector

        # Connect Ok|Cancel Button Box and X Button
        self.ui.buttonBox.accepted.connect(self.accept)
        self.ui.buttonBox.rejected.connect(self.reject)
        self.ui.exit_btn.clicked.connect(self.reject)

        self.lastcolor = (0, 0, 0)
        self.color = (0, 0, 0)
        self.alpha = 100
Exemplo n.º 4
0
    def __init__(self):
        super(SideMenu, self).__init__()
        self.setWindowFlags(self.windowFlags() | Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)

        self.shadow = QGraphicsDropShadowEffect()
        self.shadow.setBlurRadius(50)
        self.setGraphicsEffect(self.shadow)

        self.widget = SideMenuWidget()
        self.setWidget(self.widget)
        self.hide()
Exemplo n.º 5
0
    def __init__(self, base_path, file, file_config, parent=None):
        super().__init__(parent)

        board = BanBoard(file, file_config)
        board_area = QScrollArea()
        board_area.setWidget(board)
        board_area.setWidgetResizable(True)
        self.setCentralWidget(board_area)

        self.stbar = QStatusBar()

        # add a save button at the right bottom corner
        save_btn = BanButton(
            "save",
            objectName="appBtn_save",
            toolTip="save xban file",
            shortcut="Ctrl+S",
        )

        shadow = QGraphicsDropShadowEffect(self,
                                           blurRadius=10,
                                           offset=5,
                                           color=QColor("lightgrey"))
        save_btn.setGraphicsEffect(shadow)
        save_btn.pressed.connect(board.save_board)

        self.stbar.addPermanentWidget(save_btn)
        self.setStatusBar(self.stbar)
        log_handler = QLogHandler(self)
        root_logger = logging.getLogger()
        root_logger.addHandler(log_handler)
        log_handler.signal.log_msg.connect(
            partial(self.stbar.showMessage, timeout=1500))
        self.stbar.showMessage(f"Initiate {file}", 1500)
        self.show()
    def __init__(self):
        QWidget.__init__(self)

        self.shadow = QGraphicsDropShadowEffect(self)
        self.value = 0
        self.width = 200
        self.height = 200
        self.progress_width = 10
        self.progress_rounded_cap = True
        self.progress_color = 0x4988D1
        self.max_value = 100
        self.font_family = "Segoe UI"
        self.font_size = 12
        self.suffix = "%"
        self.text_color = 0x498BD1
        self.enable_shadow = True

        self.resize(self.width, self.height)
Exemplo n.º 7
0
    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 uiDefinitions(self):

        # DROP SHADOW
        self.shadow = QGraphicsDropShadowEffect(self)
        self.shadow.setBlurRadius(17)
        self.shadow.setXOffset(0)
        self.shadow.setYOffset(0)
        self.shadow.setColor(QColor(0, 0, 0, 150))
        self.ui.bgApp.setGraphicsEffect(self.shadow)

        # RESIZE WINDOW
        self.sizegrip = QSizeGrip(self.ui.frame_size_grip)
        self.sizegrip.setStyleSheet(
            "width: 20px; height: 20px; margin 0px; padding: 0px;")

        # MINIMIZE
        self.ui.minimizeAppBtn.clicked.connect(self.showMinimized)

        # MAXIMIZE/RESTORE
        self.ui.maximizeRestoreAppBtn.clicked.connect(self.maximize_restore)

        # CLOSE APPLICATION
        self.ui.closeAppBtn.clicked.connect(self.close)
Exemplo n.º 9
0
class ColorPicker(QDialog):
    def __init__(self, lightTheme=False, useAlpha=False):
        super(ColorPicker, self).__init__()

        self.usingAlpha = useAlpha

        # Call UI Builder function
        if useAlpha:
            if lightTheme: self.ui = Ui_Light_Alpha()
            else: self.ui = Ui_Dark_Alpha()
            self.ui.setupUi(self)
        else:
            if lightTheme: self.ui = Ui_Light()
            else: self.ui = Ui_Dark()
            self.ui.setupUi(self)

        # Make Frameless
        self.setWindowFlags(Qt.FramelessWindowHint)
        self.setAttribute(Qt.WA_TranslucentBackground)
        self.setWindowTitle("Color Picker")

        # Add DropShadow
        self.shadow = QGraphicsDropShadowEffect(self)
        self.shadow.setBlurRadius(17)
        self.shadow.setXOffset(0)
        self.shadow.setYOffset(0)
        self.shadow.setColor(QColor(0, 0, 0, 150))
        self.ui.drop_shadow_frame.setGraphicsEffect(self.shadow)

        # Connect update functions
        self.ui.hue.mouseMoveEvent = self.moveHueSelector
        self.ui.red.textEdited.connect(self.rgbChanged)
        self.ui.green.textEdited.connect(self.rgbChanged)
        self.ui.blue.textEdited.connect(self.rgbChanged)
        self.ui.hex.textEdited.connect(self.hexChanged)
        if self.usingAlpha: self.ui.alpha.textEdited.connect(self.alphaChanged)

        # Connect window dragging functions
        self.ui.title_bar.mouseMoveEvent = self.moveWindow
        self.ui.title_bar.mousePressEvent = self.setDragPos
        self.ui.window_title.mouseMoveEvent = self.moveWindow
        self.ui.window_title.mousePressEvent = self.setDragPos

        # Connect selector moving function
        self.ui.black_overlay.mouseMoveEvent = self.moveSVSelector
        self.ui.black_overlay.mousePressEvent = self.moveSVSelector

        # Connect Ok|Cancel Button Box and X Button
        self.ui.buttonBox.accepted.connect(self.accept)
        self.ui.buttonBox.rejected.connect(self.reject)
        self.ui.exit_btn.clicked.connect(self.reject)

        self.lastcolor = (0, 0, 0)
        self.color = (0, 0, 0)
        self.alpha = 100

    ## Main Function
    def getColor(self, lc=None):
        if lc != None and self.usingAlpha:
            alpha = lc[3]
            lc = lc[:3]
            self.setAlpha(alpha)
            self.alpha = alpha
        if lc == None: lc = self.lastcolor
        else: self.lastcolor = lc

        self.setRGB(lc)
        self.rgbChanged()
        r, g, b = lc
        self.ui.lastcolor_vis.setStyleSheet(
            f"background-color: rgb({r},{g},{b})")

        if self.exec_():
            r, g, b = self.hsv2rgb(self.color)
            self.lastcolor = (r, g, b)
            if self.usingAlpha: return (r, g, b, self.alpha)
            return (r, g, b)

        else:
            return self.lastcolor

    ## Update Functions
    def hsvChanged(self):
        h, s, v = (100 - self.ui.hue_selector.y() / 1.85,
                   (self.ui.selector.x() + 6) / 2.0,
                   (194 - self.ui.selector.y()) / 2.0)
        r, g, b = self.hsv2rgb(h, s, v)
        self.color = (h, s, v)
        self.setRGB((r, g, b))
        self.setHex(self.hsv2hex(self.color))
        self.ui.color_vis.setStyleSheet(f"background-color: rgb({r},{g},{b})")
        self.ui.color_view.setStyleSheet(
            f"border-radius: 5px;background-color: qlineargradient(x1:1, x2:0, stop:0 hsl({h}%,100%,50%), stop:1 #fff);"
        )

    def rgbChanged(self):
        r, g, b = self.i(self.ui.red.text()), self.i(
            self.ui.green.text()), self.i(self.ui.blue.text())
        cr, cg, cb = self.clampRGB((r, g, b))

        if r != cr or (r == 0 and self.ui.red.hasFocus()):
            self.setRGB((cr, cg, cb))
            self.ui.red.selectAll()
        if g != cg or (g == 0 and self.ui.green.hasFocus()):
            self.setRGB((cr, cg, cb))
            self.ui.green.selectAll()
        if b != cb or (b == 0 and self.ui.blue.hasFocus()):
            self.setRGB((cr, cg, cb))
            self.ui.blue.selectAll()

        self.color = self.rgb2hsv(r, g, b)
        self.setHSV(self.color)
        self.setHex(self.rgb2hex((r, g, b)))
        self.ui.color_vis.setStyleSheet(f"background-color: rgb({r},{g},{b})")

    def hexChanged(self):
        hex = self.ui.hex.text()
        r, g, b = self.hex2rgb(hex)
        self.color = self.hex2hsv(hex)
        self.setHSV(self.color)
        self.setRGB((r, g, b))
        self.ui.color_vis.setStyleSheet(f"background-color: rgb({r},{g},{b})")

    def alphaChanged(self):
        alpha = self.i(self.ui.alpha.text())
        oldalpha = alpha
        if alpha < 0: alpha = 0
        if alpha > 100: alpha = 100
        if alpha != oldalpha or alpha == 0:
            self.ui.alpha.setText(str(alpha))
            self.ui.alpha.selectAll()
        self.alpha = alpha

    ## Internal setting functions
    def setRGB(self, c):
        r, g, b = c
        self.ui.red.setText(str(self.i(r)))
        self.ui.green.setText(str(self.i(g)))
        self.ui.blue.setText(str(self.i(b)))

    def setHSV(self, c):
        self.ui.hue_selector.move(7, (100 - c[0]) * 1.85)
        self.ui.color_view.setStyleSheet(
            f"border-radius: 5px;background-color: qlineargradient(x1:1, x2:0, stop:0 hsl({c[0]}%,100%,50%), stop:1 #fff);"
        )
        self.ui.selector.move(c[1] * 2 - 6, (200 - c[2] * 2) - 6)

    def setHex(self, c):
        self.ui.hex.setText(c)

    def setAlpha(self, a):
        self.ui.alpha.setText(str(a))

    ## Color Utility
    def hsv2rgb(self, h_or_color, s=0, v=0, a=None):
        if type(h_or_color).__name__ == "tuple":
            if len(h_or_color) == 4:
                h, s, v, a = h_or_color
            else:
                h, s, v = h_or_color
        else:
            h = h_or_color
        r, g, b = colorsys.hsv_to_rgb(h / 100.0, s / 100.0, v / 100.0)
        if a != None: return (r * 255, g * 255, b * 255, a)
        return (r * 255, g * 255, b * 255)

    def rgb2hsv(self, r_or_color, g=0, b=0, a=None):
        if type(r_or_color).__name__ == "tuple":
            if len(r_or_color) == 4:
                r, g, b, a = r_or_color
            else:
                r, g, b = r_or_color
        else:
            r = r_or_color
        h, s, v = colorsys.rgb_to_hsv(r / 255.0, g / 255.0, b / 255.0)
        if a != None: return (h * 100, s * 100, v * 100, a)
        return (h * 100, s * 100, v * 100)

    def hex2rgb(self, hex):
        if len(hex) < 6: hex += "0" * (6 - len(hex))
        elif len(hex) > 6: hex = hex[0:6]
        rgb = tuple(int(hex[i:i + 2], 16) for i in (0, 2, 4))
        return rgb

    def rgb2hex(self, r_or_color, g=0, b=0, a=0):
        if type(r_or_color).__name__ == "tuple": r, g, b = r_or_color[:3]
        else: r = r_or_color
        hex = '%02x%02x%02x' % (int(r), int(g), int(b))
        return hex

    def hex2hsv(self, hex):
        return self.rgb2hsv(self.hex2rgb(hex))

    def hsv2hex(self, h_or_color, s=0, v=0, a=0):
        if type(h_or_color).__name__ == "tuple": h, s, v = h_or_color[:3]
        else: h = h_or_color
        return self.rgb2hex(self.hsv2rgb(h, s, v))

    ## Dragging Functions
    def setDragPos(self, event):
        self.dragPos = event.globalPos()

    def moveWindow(self, event):
        # MOVE WINDOW
        if event.buttons() == Qt.LeftButton:
            self.move(self.pos() + event.globalPos() - self.dragPos)
            self.dragPos = event.globalPos()
            event.accept()

    def moveSVSelector(self, event):
        if event.buttons() == Qt.LeftButton:
            pos = event.pos()
            if pos.x() < 0: pos.setX(0)
            if pos.y() < 0: pos.setY(0)
            if pos.x() > 200: pos.setX(200)
            if pos.y() > 200: pos.setY(200)
            self.ui.selector.move(pos - QPoint(6, 6))
            self.hsvChanged()

    def moveHueSelector(self, event):
        if event.buttons() == Qt.LeftButton:
            pos = event.pos().y() - 7
            if pos < 0: pos = 0
            if pos > 185: pos = 185
            self.ui.hue_selector.move(QPoint(7, pos))
            self.hsvChanged()

    ## Utility

    ## Custom int() function, that converts uncastable strings to 0
    def i(self, text):
        try:
            return int(text)
        except:
            return 0

    ## clamp function to remove near-zero values
    def clampRGB(self, rgb):
        r, g, b = rgb
        if r < 0.0001: r = 0
        if g < 0.0001: g = 0
        if b < 0.0001: b = 0
        if r > 255: r = 255
        if g > 255: g = 255
        if b > 255: b = 255
        return (r, g, b)
Exemplo n.º 10
0
    def __init__(self, tile_contents, color, parent=None):
        super().__init__(parent)
        title_name, tile_items = tile_contents
        self.color = color
        self.setObjectName("subBoardFrame")

        shadow = QGraphicsDropShadowEffect(self,
                                           blurRadius=10,
                                           offset=5,
                                           color=QColor("lightgrey"))
        self.setGraphicsEffect(shadow)

        board = QVBoxLayout()
        board.setContentsMargins(20, 20, 20, 20)
        tile_title = NoteTile(title_name, "boardEdit", self)
        tile_title.setPlaceholderText("Title here ...")

        board.addWidget(tile_title)

        self.listwidget = BanListWidget(self)
        self.listwidget.setStyleSheet(TILE_STYLE.get(color, "black"))
        for tile in tile_items:
            self.listwidget.add_item(tile)

        board.addWidget(self.listwidget)

        btn_layout = QHBoxLayout()
        add_btn = BanButton(
            "+",
            clicked=self.add_listitem,
            toolTip="add tile",
            objectName="boardBtn",
        )
        del_btn = BanButton(
            "-",
            clicked=self.del_listitem,
            toolTip="delete tile",
            objectName="boardBtn",
            shortcut=QKeySequence(Qt.Key_Backspace),
        )
        color_btn = BanButton(
            "\u2261",
            toolTip="change color",
            objectName="boardBtn_color",
            color=[("white", "#bdbdbd"), ("grey", "white")],
        )

        self.color_menu = self.context_menu()
        color_btn.setMenu(self.color_menu)
        color_btn.sizeSig.connect(self.menu_resize)

        destory_btn = BanButton(
            "\u00D7",
            clicked=self.delete_board,
            toolTip="delete board",
            objectName="boardBtn_des",
            color=[("white", "tomato"), ("white", "red")],
        )

        btn_layout.addWidget(add_btn)
        btn_layout.addWidget(del_btn)

        btn_layout.addWidget(color_btn)
        btn_layout.addWidget(destory_btn)
        board.addLayout(btn_layout)

        self.setLayout(board)
Exemplo n.º 11
0
 def __init__(self, parent=None):
     super(MainWindow, self).__init__()
     self.statusBar().showMessage("Move Dial to Deform Microphone Voice !.")
     self.setWindowTitle(__doc__)
     self.setMinimumSize(240, 240)
     self.setMaximumSize(480, 480)
     self.resize(self.minimumSize())
     self.setWindowIcon(QIcon.fromTheme("audio-input-microphone"))
     self.tray = QSystemTrayIcon(self)
     self.center()
     QShortcut("Ctrl+q", self, activated=lambda: self.close())
     self.menuBar().addMenu("&File").addAction("Quit", lambda: exit())
     self.menuBar().addMenu("Sound").addAction(
         "STOP !", lambda: call('killall rec', shell=True))
     windowMenu = self.menuBar().addMenu("&Window")
     windowMenu.addAction("Hide", lambda: self.hide())
     windowMenu.addAction("Minimize", lambda: self.showMinimized())
     windowMenu.addAction("Maximize", lambda: self.showMaximized())
     windowMenu.addAction("Restore", lambda: self.showNormal())
     windowMenu.addAction("FullScreen", lambda: self.showFullScreen())
     windowMenu.addAction("Center", lambda: self.center())
     windowMenu.addAction("Top-Left", lambda: self.move(0, 0))
     windowMenu.addAction("To Mouse", lambda: self.move_to_mouse_position())
     # widgets
     group0 = QGroupBox("Voice Deformation")
     self.setCentralWidget(group0)
     self.process = QProcess(self)
     self.process.error.connect(
         lambda: self.statusBar().showMessage("Info: Process Killed", 5000))
     self.control = QDial()
     self.control.setRange(-10, 20)
     self.control.setSingleStep(5)
     self.control.setValue(0)
     self.control.setCursor(QCursor(Qt.OpenHandCursor))
     self.control.sliderPressed.connect(
         lambda: self.control.setCursor(QCursor(Qt.ClosedHandCursor)))
     self.control.sliderReleased.connect(
         lambda: self.control.setCursor(QCursor(Qt.OpenHandCursor)))
     self.control.valueChanged.connect(
         lambda: self.control.setToolTip(f"<b>{self.control.value()}"))
     self.control.valueChanged.connect(lambda: self.statusBar().showMessage(
         f"Voice deformation: {self.control.value()}", 5000))
     self.control.valueChanged.connect(self.run)
     self.control.valueChanged.connect(lambda: self.process.kill())
     # Graphic effect
     self.glow = QGraphicsDropShadowEffect(self)
     self.glow.setOffset(0)
     self.glow.setBlurRadius(99)
     self.glow.setColor(QColor(99, 255, 255))
     self.control.setGraphicsEffect(self.glow)
     self.glow.setEnabled(False)
     # Timer to start
     self.slider_timer = QTimer(self)
     self.slider_timer.setSingleShot(True)
     self.slider_timer.timeout.connect(self.on_slider_timer_timeout)
     # an icon and set focus
     QLabel(self.control).setPixmap(
         QIcon.fromTheme("audio-input-microphone").pixmap(32))
     self.control.setFocus()
     QVBoxLayout(group0).addWidget(self.control)
     self.menu = QMenu(__doc__)
     self.menu.addAction(__doc__).setDisabled(True)
     self.menu.setIcon(self.windowIcon())
     self.menu.addSeparator()
     self.menu.addAction(
         "Show / Hide", lambda: self.hide()
         if self.isVisible() else self.showNormal())
     self.menu.addAction("STOP !", lambda: call('killall rec', shell=True))
     self.menu.addSeparator()
     self.menu.addAction("Quit", lambda: exit())
     self.tray.setContextMenu(self.menu)
     self.make_trayicon()
Exemplo n.º 12
0
class MainWindow(QMainWindow):
    """Voice Changer main window."""
    def __init__(self, parent=None):
        super(MainWindow, self).__init__()
        self.statusBar().showMessage("Move Dial to Deform Microphone Voice !.")
        self.setWindowTitle(__doc__)
        self.setMinimumSize(240, 240)
        self.setMaximumSize(480, 480)
        self.resize(self.minimumSize())
        self.setWindowIcon(QIcon.fromTheme("audio-input-microphone"))
        self.tray = QSystemTrayIcon(self)
        self.center()
        QShortcut("Ctrl+q", self, activated=lambda: self.close())
        self.menuBar().addMenu("&File").addAction("Quit", lambda: exit())
        self.menuBar().addMenu("Sound").addAction(
            "STOP !", lambda: call('killall rec', shell=True))
        windowMenu = self.menuBar().addMenu("&Window")
        windowMenu.addAction("Hide", lambda: self.hide())
        windowMenu.addAction("Minimize", lambda: self.showMinimized())
        windowMenu.addAction("Maximize", lambda: self.showMaximized())
        windowMenu.addAction("Restore", lambda: self.showNormal())
        windowMenu.addAction("FullScreen", lambda: self.showFullScreen())
        windowMenu.addAction("Center", lambda: self.center())
        windowMenu.addAction("Top-Left", lambda: self.move(0, 0))
        windowMenu.addAction("To Mouse", lambda: self.move_to_mouse_position())
        # widgets
        group0 = QGroupBox("Voice Deformation")
        self.setCentralWidget(group0)
        self.process = QProcess(self)
        self.process.error.connect(
            lambda: self.statusBar().showMessage("Info: Process Killed", 5000))
        self.control = QDial()
        self.control.setRange(-10, 20)
        self.control.setSingleStep(5)
        self.control.setValue(0)
        self.control.setCursor(QCursor(Qt.OpenHandCursor))
        self.control.sliderPressed.connect(
            lambda: self.control.setCursor(QCursor(Qt.ClosedHandCursor)))
        self.control.sliderReleased.connect(
            lambda: self.control.setCursor(QCursor(Qt.OpenHandCursor)))
        self.control.valueChanged.connect(
            lambda: self.control.setToolTip(f"<b>{self.control.value()}"))
        self.control.valueChanged.connect(lambda: self.statusBar().showMessage(
            f"Voice deformation: {self.control.value()}", 5000))
        self.control.valueChanged.connect(self.run)
        self.control.valueChanged.connect(lambda: self.process.kill())
        # Graphic effect
        self.glow = QGraphicsDropShadowEffect(self)
        self.glow.setOffset(0)
        self.glow.setBlurRadius(99)
        self.glow.setColor(QColor(99, 255, 255))
        self.control.setGraphicsEffect(self.glow)
        self.glow.setEnabled(False)
        # Timer to start
        self.slider_timer = QTimer(self)
        self.slider_timer.setSingleShot(True)
        self.slider_timer.timeout.connect(self.on_slider_timer_timeout)
        # an icon and set focus
        QLabel(self.control).setPixmap(
            QIcon.fromTheme("audio-input-microphone").pixmap(32))
        self.control.setFocus()
        QVBoxLayout(group0).addWidget(self.control)
        self.menu = QMenu(__doc__)
        self.menu.addAction(__doc__).setDisabled(True)
        self.menu.setIcon(self.windowIcon())
        self.menu.addSeparator()
        self.menu.addAction(
            "Show / Hide", lambda: self.hide()
            if self.isVisible() else self.showNormal())
        self.menu.addAction("STOP !", lambda: call('killall rec', shell=True))
        self.menu.addSeparator()
        self.menu.addAction("Quit", lambda: exit())
        self.tray.setContextMenu(self.menu)
        self.make_trayicon()

    def run(self):
        """Run/Stop the QTimer."""
        if self.slider_timer.isActive():
            self.slider_timer.stop()
        self.glow.setEnabled(True)
        call('killall rec ; killall play', shell=True)
        self.slider_timer.start(3000)

    def on_slider_timer_timeout(self):
        """Run subprocess to deform voice."""
        self.glow.setEnabled(False)
        value = int(self.control.value()) * 100
        command = f'play -q -V0 "|rec -q -V0 -n -d -R riaa bend pitch {value} "'
        print(f"Voice Deformation Value: {value}")
        print(f"Voice Deformation Command: {command}")
        self.process.start(command)
        if self.isVisible():
            self.statusBar().showMessage("Minimizing to System TrayIcon", 3000)
            print("Minimizing Main Window to System TrayIcon now...")
            sleep(3)
            self.hide()

    def center(self):
        """Center Window on the Current Screen,with Multi-Monitor support."""
        window_geometry = self.frameGeometry()
        mousepointer_position = QApplication.desktop().cursor().pos()
        screen = QApplication.desktop().screenNumber(mousepointer_position)
        centerPoint = QApplication.desktop().screenGeometry(screen).center()
        window_geometry.moveCenter(centerPoint)
        self.move(window_geometry.topLeft())

    def move_to_mouse_position(self):
        """Center the Window on the Current Mouse position."""
        window_geometry = self.frameGeometry()
        window_geometry.moveCenter(QApplication.desktop().cursor().pos())
        self.move(window_geometry.topLeft())

    def make_trayicon(self):
        """Make a Tray Icon."""
        if self.windowIcon() and __doc__:
            self.tray.setIcon(self.windowIcon())
            self.tray.setToolTip(__doc__)
            self.tray.activated.connect(
                lambda: self.hide() if self.isVisible() else self.showNormal())
            return self.tray.show()
class MainWindow(QMainWindow):
    def __init__(self):
        QMainWindow.__init__(self)

        # Install the converted ui file as interface
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # Enables the custom title bar
        self._configure_title_bar(True)

        # Set title and description
        self.setWindowTitle("PyDracula - Modern GUI")
        self.ui.titleRightInfo.setText(
            "PyDracula APP - Theme with colors based on Dracula for Python.")

        # Install event filter to handle own QResizeEvents
        self.installEventFilter(self)

        # Holds the position to drag to:
        self.drag_pos: Optional[QPoint] = None

        # SET UI DEFINITIONS
        # ///////////////////////////////////////////////////////////////
        self.uiDefinitions()

        # QTableWidget PARAMETERS
        # ///////////////////////////////////////////////////////////////
        self.ui.tableWidget.horizontalHeader().setSectionResizeMode(
            QHeaderView.Stretch)

        # connect button to toggle menu
        self.ui.toggleButton.clicked.connect(self.toggleMenu)

        # LEFT MENUS
        self.ui.btn_home.clicked.connect(self.on_home_btn_clicked)
        self.ui.btn_widgets.clicked.connect(self.on_widgets_btn_clicked)
        self.ui.btn_new.clicked.connect(self.on_new_btn_clicked)

        # EXTRA LEFT BOX
        self.ui.toggleLeftBox.clicked.connect(self.toggleLeftBox)
        self.ui.extraCloseColumnBtn.clicked.connect(self.toggleLeftBox)

        # EXTRA RIGHT BOX
        self.ui.settingsTopBtn.clicked.connect(self.toggleRightBox)

        # LOAD AND APPLY STYLE
        with open(r"themes\py_dracula_dark.qss", "r") as fhandle:
            self.ui.styleSheet.setStyleSheet(fhandle.read())

        # SET MANUAL STYLES
        self.ui.lineEdit.setStyleSheet("background-color: rgb(98, 114, 164);")
        self.ui.pushButton.setStyleSheet(
            "background-color: rgb(98, 114, 164);")
        self.ui.plainTextEdit.setStyleSheet(
            "background-color: rgb(98, 114, 164);")
        self.ui.tableWidget.setStyleSheet(
            "QScrollBar:vertical { background: rgb(98, 114, 164); } QScrollBar:horizontal { background: rgb(98, 114, 164); }"
        )
        self.ui.scrollArea.setStyleSheet(
            "QScrollBar:vertical { background: rgb(98, 114, 164); } QScrollBar:horizontal { background: rgb(98, 114, 164); }"
        )
        self.ui.comboBox.setStyleSheet("background-color: rgb(98, 114, 164);")
        self.ui.horizontalScrollBar.setStyleSheet(
            "background-color: rgb(98, 114, 164);")
        self.ui.verticalScrollBar.setStyleSheet(
            "background-color: rgb(98, 114, 164);")
        self.ui.commandLinkButton.setStyleSheet("color: rgb(255, 121, 198);")

        # SET HOME PAGE AND SELECT MENU
        # ///////////////////////////////////////////////////////////////
        self.ui.stackedWidget.setCurrentWidget(self.ui.home)
        self.ui.btn_home.setStyleSheet(
            self.selectMenu(self.ui.btn_home.styleSheet()))

    def eventFilter(self, obj: QObject, event: QEvent) -> bool:
        """Filter events for custom title bar."""
        if obj is self.ui.titleRightInfo and event.type(
        ) == QEvent.MouseButtonDblClick:
            # This was originally done with a delay of 250 but I didn't like it.
            # QTimer.singleShot(250, lambda: self.maximize_restore())
            self.maximize_restore()
        if obj is self.ui.titleRightInfo and event.type(
        ) == QEvent.MouseButtonPress:
            self.drag_pos = event.globalPos()
        if obj is self.ui.titleRightInfo and event.type() == QEvent.MouseMove:
            # Restore the window when it is moved in maximized state.
            if self.isMaximized():
                # TODO: When doing this, we also need to move the window so it's under the mouse cursor!
                self.maximize_restore()
            # Move the window to the new position.
            if event.buttons() == Qt.LeftButton:
                self.move(self.pos() + event.globalPos() - self.drag_pos)
                self.drag_pos = event.globalPos()
                return True
        if obj is self.ui.titleRightInfo and event.type(
        ) == QEvent.MouseButtonRelease:
            # Todo: Check if we should move it to the last received position.
            self.drag_pos = None
        if obj is self and event.type() == QEvent.Resize:
            self.resize_grips()
        return False

    def _configure_title_bar(self, custom) -> None:
        """Configures the app to use a standard or custom title bar."""
        self._enable_custom_title_bar = custom

        if self._enable_custom_title_bar:
            # Handle double click events to maximize/restore the MainWindow
            self.ui.titleRightInfo.installEventFilter(self)

            # Remove standard title bar.
            self.setWindowFlags(Qt.FramelessWindowHint)
            self.setAttribute(Qt.WA_TranslucentBackground)

            # CUSTOM GRIPS
            self.left_grip = CustomGrip(self, Qt.LeftEdge, True)
            self.right_grip = CustomGrip(self, Qt.RightEdge, True)
            self.top_grip = CustomGrip(self, Qt.TopEdge, True)
            self.bottom_grip = CustomGrip(self, Qt.BottomEdge, True)

        else:
            self.ui.appMargins.setContentsMargins(0, 0, 0, 0)
            self.ui.minimizeAppBtn.hide()
            self.ui.maximizeRestoreAppBtn.hide()
            self.ui.closeAppBtn.hide()
            self.ui.frame_size_grip.hide()

    @Slot(name="on_home_btn_clicked")
    def on_home_btn_clicked(self):
        """Handle a click on the home_btn."""
        self.ui.stackedWidget.setCurrentWidget(self.ui.home)
        self.resetStyle("btn_home")
        self.ui.btn_home.setStyleSheet(
            self.selectMenu(self.ui.btn_home.styleSheet()))

    @Slot(name="on_widgets_btn_clicked")
    def on_widgets_btn_clicked(self):
        """Handle a click on the widgets_btn."""
        self.ui.stackedWidget.setCurrentWidget(self.ui.widgets)
        self.resetStyle("btn_widgets")
        self.ui.btn_widgets.setStyleSheet(
            self.selectMenu(self.ui.btn_widgets.styleSheet()))

    @Slot(name="on_new_btn_clicked")
    def on_new_btn_clicked(self):
        """Handle a click on the new_btn."""
        self.ui.stackedWidget.setCurrentWidget(self.ui.new_page)
        self.resetStyle("btn_new")
        self.ui.btn_new.setStyleSheet(
            self.selectMenu(self.ui.btn_new.styleSheet()))

    def maximize_restore(self):
        if not self.isMaximized():
            self.showMaximized()
            self.ui.appMargins.setContentsMargins(0, 0, 0, 0)
            self.ui.maximizeRestoreAppBtn.setToolTip("Restore")
            self.ui.maximizeRestoreAppBtn.setIcon(
                QIcon(":/icons/images/icons/icon_restore.png"))
            self.ui.frame_size_grip.hide()
            self.left_grip.hide()
            self.right_grip.hide()
            self.top_grip.hide()
            self.bottom_grip.hide()
        else:
            self.showNormal()
            self.resize(self.width() + 1, self.height() + 1)
            self.ui.appMargins.setContentsMargins(10, 10, 10, 10)
            self.ui.maximizeRestoreAppBtn.setToolTip("Maximize")
            self.ui.maximizeRestoreAppBtn.setIcon(
                QIcon(":/icons/images/icons/icon_maximize.png"))
            self.ui.frame_size_grip.show()
            self.left_grip.show()
            self.right_grip.show()
            self.top_grip.show()
            self.bottom_grip.show()

    # TOGGLE MENU
    # ///////////////////////////////////////////////////////////////
    def toggleMenu(self):
        # GET WIDTH
        width = self.ui.leftMenuBg.width()
        maxExtend = Settings.MENU_WIDTH
        standard = 60

        # SET MAX WIDTH
        if width == 60:
            widthExtended = maxExtend
        else:
            widthExtended = standard

        # ANIMATION
        self.animation = QPropertyAnimation(self.ui.leftMenuBg,
                                            b"minimumWidth")
        self.animation.setDuration(Settings.TIME_ANIMATION)
        self.animation.setStartValue(width)
        self.animation.setEndValue(widthExtended)
        self.animation.setEasingCurve(QEasingCurve.InOutQuart)
        self.animation.start()

    # TOGGLE LEFT BOX
    # ///////////////////////////////////////////////////////////////
    def toggleLeftBox(self):
        # GET WIDTH
        width = self.ui.extraLeftBox.width()
        widthRightBox = self.ui.extraRightBox.width()
        color = Settings.BTN_LEFT_BOX_COLOR

        # GET BTN STYLE
        style = self.ui.toggleLeftBox.styleSheet()

        # SET MAX WIDTH
        if width == 0:
            # SELECT BTN
            self.ui.toggleLeftBox.setStyleSheet(style + color)
            if widthRightBox != 0:
                style = self.ui.settingsTopBtn.styleSheet()
                self.ui.settingsTopBtn.setStyleSheet(
                    style.replace(Settings.BTN_RIGHT_BOX_COLOR, ""))
        else:
            # RESET BTN
            self.ui.toggleLeftBox.setStyleSheet(style.replace(color, ""))

        self.start_box_animation(width, widthRightBox, "left")

    # TOGGLE RIGHT BOX
    # ///////////////////////////////////////////////////////////////
    def toggleRightBox(self):
        # GET WIDTH
        width = self.ui.extraRightBox.width()
        widthLeftBox = self.ui.extraLeftBox.width()
        color = Settings.BTN_RIGHT_BOX_COLOR

        # GET BTN STYLE
        style = self.ui.settingsTopBtn.styleSheet()

        # SET MAX WIDTH
        if width == 0:
            # SELECT BTN
            self.ui.settingsTopBtn.setStyleSheet(style + color)
            if widthLeftBox != 0:
                style = self.ui.toggleLeftBox.styleSheet()
                self.ui.toggleLeftBox.setStyleSheet(
                    style.replace(Settings.BTN_LEFT_BOX_COLOR, ""))
        else:
            # RESET BTN
            self.ui.settingsTopBtn.setStyleSheet(style.replace(color, ""))

        self.start_box_animation(widthLeftBox, width, "right")

    def start_box_animation(self, left_box_width, right_box_width, direction):

        # Check values
        if left_box_width == 0 and direction == "left":
            left_width = 240
        else:
            left_width = 0
        # Check values
        if right_box_width == 0 and direction == "right":
            right_width = 240
        else:
            right_width = 0

            # ANIMATION LEFT BOX
        self.left_box = QPropertyAnimation(self.ui.extraLeftBox,
                                           b"minimumWidth")
        self.left_box.setDuration(Settings.TIME_ANIMATION)
        self.left_box.setStartValue(left_box_width)
        self.left_box.setEndValue(left_width)
        self.left_box.setEasingCurve(QEasingCurve.InOutQuart)

        # ANIMATION RIGHT BOX
        self.right_box = QPropertyAnimation(self.ui.extraRightBox,
                                            b"minimumWidth")
        self.right_box.setDuration(Settings.TIME_ANIMATION)
        self.right_box.setStartValue(right_box_width)
        self.right_box.setEndValue(right_width)
        self.right_box.setEasingCurve(QEasingCurve.InOutQuart)

        # GROUP ANIMATION
        self.group = QParallelAnimationGroup()
        self.group.addAnimation(self.left_box)
        self.group.addAnimation(self.right_box)
        self.group.start()

    # SELECT/DESELECT MENU
    # ///////////////////////////////////////////////////////////////
    # SELECT
    @staticmethod
    def selectMenu(getStyle):
        select = getStyle + Settings.MENU_SELECTED_STYLESHEET
        return select

    # DESELECT
    @staticmethod
    def deselectMenu(getStyle):
        deselect = getStyle.replace(Settings.MENU_SELECTED_STYLESHEET, "")
        return deselect

    # START SELECTION
    def selectStandardMenu(self, widget):
        for w in self.ui.topMenu.findChildren(QPushButton):
            if w.objectName() == widget:
                w.setStyleSheet(self.selectMenu(w.styleSheet()))

    # RESET SELECTION
    def resetStyle(self, widget):
        for w in self.ui.topMenu.findChildren(QPushButton):
            if w.objectName() != widget:
                w.setStyleSheet(self.deselectMenu(w.styleSheet()))

    # START - GUI DEFINITIONS
    # ///////////////////////////////////////////////////////////////
    def uiDefinitions(self):

        # DROP SHADOW
        self.shadow = QGraphicsDropShadowEffect(self)
        self.shadow.setBlurRadius(17)
        self.shadow.setXOffset(0)
        self.shadow.setYOffset(0)
        self.shadow.setColor(QColor(0, 0, 0, 150))
        self.ui.bgApp.setGraphicsEffect(self.shadow)

        # RESIZE WINDOW
        self.sizegrip = QSizeGrip(self.ui.frame_size_grip)
        self.sizegrip.setStyleSheet(
            "width: 20px; height: 20px; margin 0px; padding: 0px;")

        # MINIMIZE
        self.ui.minimizeAppBtn.clicked.connect(self.showMinimized)

        # MAXIMIZE/RESTORE
        self.ui.maximizeRestoreAppBtn.clicked.connect(self.maximize_restore)

        # CLOSE APPLICATION
        self.ui.closeAppBtn.clicked.connect(self.close)

    def resize_grips(self):
        if self._enable_custom_title_bar:
            self.left_grip.setGeometry(0, 10, 10, self.height())
            self.right_grip.setGeometry(self.width() - 10, 10, 10,
                                        self.height())
            self.top_grip.setGeometry(0, 0, self.width(), 10)
            self.bottom_grip.setGeometry(0,
                                         self.height() - 10, self.width(), 10)
class CircularProgress(QWidget):
    def __init__(self):
        QWidget.__init__(self)

        self.shadow = QGraphicsDropShadowEffect(self)
        self.value = 0
        self.width = 200
        self.height = 200
        self.progress_width = 10
        self.progress_rounded_cap = True
        self.progress_color = 0x4988D1
        self.max_value = 100
        self.font_family = "Segoe UI"
        self.font_size = 12
        self.suffix = "%"
        self.text_color = 0x498BD1
        self.enable_shadow = True

        self.resize(self.width, self.height)

    def paintEvent(self, event: QtGui.QPaintEvent) -> None:
        width = self.width - self.progress_width
        height = self.height - self.progress_width
        margin = int(self.progress_width / 2)
        value = (self.value * 360) / self.max_value

        paint = QtGui.QPainter()
        paint.begin(self)
        paint.setRenderHint(QtGui.QPainter.Antialiasing)
        paint.setFont(QtGui.QFont(self.font_family, self.font_size))

        rect = QtCore.QRect(0, 0, self.width, self.height)
        paint.setPen(Qt.NoPen)
        paint.drawRect(rect)

        pen = QtGui.QPen()
        pen.setColor(QtGui.QColor(self.progress_color))
        pen.setWidth(self.progress_width)
        if self.progress_rounded_cap:
            pen.setCapStyle(Qt.RoundCap)

        paint.setPen(pen)
        paint.drawArc(margin, margin, width, height, -90 * 16,
                      int(-value * 16))

        pen.setColor(QtGui.QColor(self.text_color))
        paint.setPen(pen)
        paint.drawText(rect, Qt.AlignCenter, f"{self.value}{self.suffix}")

        paint.end()

    def set_value(self, value: int):
        self.value = value

    def add_shadow(self, enable):
        if enable:
            self.shadow.setBlurRadius(5)
            self.shadow.setXOffset(0)
            self.shadow.setYOffset(0)
            self.shadow.setColor(QtGui.QColor(0, 0, 0, 120))
            self.setGraphicsEffect(self.shadow)