示例#1
0
    def overlay_text(
        self,
        message: str,
        color: int,
        size: int,
        x: int,
        y: int,
        timeout: int,
        font_name: str,
        centered: bool,
        shadow: bool,
    ):
        gfx = QGraphicsTextItem(message)
        gfx.setDefaultTextColor(decode_color(color))

        font = QFont(font_name, min(50, size))
        font.setStyleHint(QFont.SansSerif)
        gfx.setFont(font)

        if shadow:
            effect = QGraphicsDropShadowEffect(gfx)
            effect.setBlurRadius(0)
            effect.setColor(Qt.GlobalColor.black)
            effect.setOffset(1, 1)
            gfx.setGraphicsEffect(effect)

        if centered:
            # The provided x, y is at the center of the text
            bound = gfx.boundingRect()
            gfx.setPos(x - (bound.width() / 2), y - (bound.height() / 2))
        else:
            gfx.setPos(x, y)

        self._finalize_gfx(gfx, timeout)
示例#2
0
def css_button(qtwindow, button, color=None, shadow=True):
    ''' apply style to a button widget '''

    # default bg color is gray 80
    if color == 'red':
        bg_color = 'rgb(160, 20, 20)'  # red/white
        tx_color = 'rgb(255, 255, 255)'
    elif color == 'disabled':
        bg_color = 'rgb(80, 80, 80)'  # gray/gray
        tx_color = 'rgb(180, 180, 180)'
    elif color == 'blue':
        bg_color = 'rgb(46, 134, 193)'  # blue arcane/white
        tx_color = 'rgb(230, 230, 230)'
    else:
        bg_color = 'rgb(80, 80, 80)'  # gray
        tx_color = 'rgb(230, 230, 230)'

    css = "border-radius:3px;color:{};background:{};font-size:12px;font-family:Segoe UI;".format(
        tx_color, bg_color)
    button.setStyleSheet(css)

    if shadow:
        shadow = QGraphicsDropShadowEffect(qtwindow)
        shadow.setBlurRadius(6)
        shadow.setOffset(4)
        shadow.setColor(QColor(20, 20, 20, 200))
        button.setGraphicsEffect(shadow)
示例#3
0
文件: table.py 项目: wwmm/viewpca
    def card_shadow(self):
        effect = QGraphicsDropShadowEffect(self.main_widget)

        effect.setColor(QColor(0, 0, 0, 100))
        effect.setXOffset(2)
        effect.setYOffset(2)
        effect.setBlurRadius(5)

        return effect
示例#4
0
    def button_shadow(self):
        effect = QGraphicsDropShadowEffect(self.window)

        effect.setColor(QColor(0, 0, 0, 100))
        effect.setXOffset(1)
        effect.setYOffset(1)
        effect.setBlurRadius(5)

        return effect
示例#5
0
    def __init__(self, text: str, object_name: str = "blue"):
        super().__init__(text)

        self.setCursor(Qt.PointingHandCursor)

        if object_name:
            self.setObjectName(object_name)

        effect = QGraphicsDropShadowEffect(self)
        effect.setColor(QColor(0, 0, 0, 0.25 * 255))
        effect.setOffset(2, 4)
        effect.setBlurRadius(4)
        self.setGraphicsEffect(effect)
示例#6
0
 def add_window_drop_shadow() -> None:
     """Adds a drop-shadow behind the window"""
     if self.__use_shadow:
         self.layout().setMargin(self.__style.window.SHADOW_RADIUS_PX)
         drop_shadow_effect = QGraphicsDropShadowEffect(self)
         drop_shadow_effect.setEnabled(True)
         drop_shadow_effect.setBlurRadius(
             self.__style.window.SHADOW_RADIUS_PX)
         color = QColor(self.__style.window.SHADOW_COLOR_RGB)
         color.setAlpha(self.__style.window.SHADOW_OPACITY_HEX)
         drop_shadow_effect.setColor(color)
         drop_shadow_effect.setOffset(0)
         self.setGraphicsEffect(drop_shadow_effect)
示例#7
0
class MainWindow(QtWidgets.QMainWindow):
    role_value = None
    DATA_PATH = 'D:\\SASTRA\Code\\Dean Mam Project\\assignment\\Data\\Medical_Records.csv'

    def __init__(self):
        print('Main init')
        QtWidgets.QMainWindow.__init__(self)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)
        self.ui.stackedWidget.setCurrentIndex(0)
        for i in RBACClass.permission_dict['Administrator']:
            self.ui.tableWidget.setColumnHidden(i, True)

        ## ==> MAXIMIZE RESTORE FUNCTION
        def maximize_restore():
            global GLOBAL_STATE
            status = GLOBAL_STATE

            # IF NOT MAXIMIZED
            if status == 0:
                self.showMaximized()

                # SET GLOBAL TO 1
                GLOBAL_STATE = 1

                # IF MAXIMIZED REMOVE MARGINS AND BORDER RADIUS
                self.ui.drop_shadow_frame.setContentsMargins(0, 0, 0, 0)
                self.ui.drop_shadow_frame.setStyleSheet(
                    "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(42, 44, 111, 255), stop:0.521368 rgba(28, 29, 73, 255)); border-radius: 0px;"
                )
                self.ui.maximize_btn.setToolTip("Restore")
            else:
                GLOBAL_STATE = 0
                self.showNormal()
                self.resize(self.width() + 1, self.height() + 1)
                self.ui.drop_shadow_frame.setContentsMargins(10, 10, 10, 10)
                self.ui.drop_shadow_frame.setStyleSheet(
                    "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(42, 44, 111, 255), stop:0.521368 rgba(28, 29, 73, 255)); border-radius: 10px;"
                )
                self.ui.maximize_btn.setToolTip("Maximize")

        ## ==> UI DEFINITIONS
        def uiDefinitions():

            # REMOVE TITLE BAR
            self.setWindowFlag(QtCore.Qt.FramelessWindowHint)
            self.setAttribute(QtCore.Qt.WA_TranslucentBackground)

            # SET DROPSHADOW WINDOW
            self.shadow = QGraphicsDropShadowEffect(self)
            self.shadow.setBlurRadius(20)
            self.shadow.setXOffset(0)
            self.shadow.setYOffset(0)
            self.shadow.setColor(QColor(0, 0, 0, 100))

            # APPLY DROPSHADOW TO FRAME
            self.ui.drop_shadow_frame.setGraphicsEffect(self.shadow)

            # MAXIMIZE / RESTORE
            self.ui.maximize_btn.clicked.connect(lambda: maximize_restore())

            # MINIMIZE
            self.ui.minimize_btn.clicked.connect(lambda: self.showMinimized())

            # CLOSE
            self.ui.close_btn.clicked.connect(lambda: self.close())

            ## ==> CREATE SIZE GRIP TO RESIZE WINDOW
            self.sizegrip = QSizeGrip(self.ui.frame_grip)
            self.sizegrip.setStyleSheet(
                "QSizeGrip { width: 10px; height: 10px; margin: 5px } QSizeGrip:hover { background-color: rgb(50, 42, 94) }"
            )
            self.sizegrip.setToolTip("Resize Window")

        def rolePermission(role):
            for i in role:
                self.ui.tableWidget.setColumnHidden(i, False)

        # MOVE WINDOW
        def moveWindowMain(event):
            # RESTORE BEFORE MOVE
            if self.returnStatus() == 1:
                self.maximize_restore(self)

            # IF LEFT CLICK MOVE WINDOW
            if event.buttons() == Qt.LeftButton:
                self.move(self.pos() + event.globalPos() - self.dragPos)
                self.dragPos = event.globalPos()
                event.accept()

        def view_details():
            patient_id = self.ui.patientIdLineEdit_2.text()
            print(patient_id)
            self.ui.stackedWidget.setCurrentIndex(1)
            with open(MainWindow.DATA_PATH, 'r') as datafile:
                print('inside file')
                readData = csv.reader(datafile)
                rowValue = 0
                for row in readData:
                    print('inside row')
                    if row[1] == patient_id:
                        self.ui.tableWidget.insertRow(rowValue)
                        print(row[1], type(row[1]))
                        for i in MainWindow.role_value:
                            print('set')
                            self.ui.tableWidget.setItem(
                                rowValue, i, QTableWidgetItem(row[i]))
                        rowValue = rowValue + 1

        def go_back():
            self.ui.stackedWidget.setCurrentIndex(0)

        ## ==> SET UI DEFINITIONS
        uiDefinitions()

        print(MainWindow.role_value, "rolePerm")
        rolePermission(MainWindow.role_value)

        self.ui.viewDetailsPushButton_2.clicked.connect(view_details)
        self.ui.back_btn.clicked.connect(go_back)

        # SET TITLE BAR
        self.ui.title_bar_2.mouseMoveEvent = moveWindowMain

        ## SHOW ==> MAIN WINDOW
        ########################################################################
        self.show()

    ## RETURN STATUS IF WINDOWS IS MAXIMIZE OR RESTAURED
    def returnStatus(self):
        return GLOBAL_STATE

    ## APP EVENTS
    ########################################################################
    def mousePressEvent(self, event):
        self.dragPos = event.globalPos()
示例#8
0
class LoginWindow(QtWidgets.QWidget):
    def __init__(self):
        QtWidgets.QWidget.__init__(self)
        self.ui = Ui_Form()
        self.ui.setupUi(self)

        def uiDefinition():
            # REMOVE TITLE BAR
            self.shadow = QGraphicsDropShadowEffect(self)
            self.setWindowFlag(QtCore.Qt.FramelessWindowHint)
            self.setAttribute(QtCore.Qt.WA_TranslucentBackground)

            # SET DROPSHADOW WINDOW
            self.shadow.setBlurRadius(20)
            self.shadow.setXOffset(0)
            self.shadow.setYOffset(0)
            self.shadow.setColor(QColor(0, 0, 0, 100))

            # APPLY DROPSHADOW TO FRAME
            self.ui.login_frame.setGraphicsEffect(self.shadow)

            # CLOSE
            self.ui.closePushButton.clicked.connect(lambda: self.close())

        # MOVE WINDOW
        def moveWindowLogin(event):
            # IF LEFT CLICK MOVE WINDOW
            if event.buttons() == Qt.LeftButton():
                self.move(self.pos() + event.globalPos() - self.dragPos)
                self.dragPos = event.globalPos()
                event.accept()

        def show_new_window():
            print(self.ui.userNameLineEdit.text(),
                  self.ui.passwordLineEdit.text())
            r = RBACClass()
            MainWindow.role_value = r.logon(
                UserName=self.ui.userNameLineEdit.text(),
                Password=self.ui.passwordLineEdit.text())
            print(MainWindow.role_value, "show")
            if MainWindow.role_value != None:
                print('here')
                self.close()
                w = MainWindow()
                w.show()
            else:
                print('no')
                self.ui.userNameLineEdit.setPlaceholderText('Try Again')
                self.ui.passwordLineEdit.setPlaceholderText('Try Again')

        # SET TITLE BAR
        self.ui.login_frame.mouseMoveEvent = moveWindowLogin
        self.ui.loginPushButton.clicked.connect(show_new_window)

        ## ==> SET UI DEFINITIONS
        uiDefinition()

        ## SHOW ==> MAIN WINDOW
        ########################################################################
        self.show()

    ## APP EVENTS
    ########################################################################
    def mousePressEvent(self, event):
        self.dragPos = event.globalPos()
示例#9
0
class NodeInstance(QGraphicsItem):
    def __init__(self, params):
        super(NodeInstance, self).__init__()

        self.setFlags(QGraphicsItem.ItemIsSelectable
                      | QGraphicsItem.ItemIsMovable
                      | QGraphicsItem.ItemSendsScenePositionChanges)
        self.setAcceptHoverEvents(True)

        # GENERAL ATTRIBUTES

        # the constructor parameters are stored in a tuple to make the source code of custom NIs cleaner
        parent_node, flow, config = params

        self.parent_node = parent_node
        self.flow = flow
        self.movement_state = None
        self.movement_pos_from = None
        self.painted_once = False
        self.inputs = []
        self.outputs = []
        self.color = self.parent_node.color  # manipulated by self.animator
        # self.node_instance_painter = NodeInstancePainter(self)

        self.default_actions = {
            'remove': {
                'method': self.action_remove
            },
            'update shape': {
                'method': self.update_shape
            }
        }  # for context menus
        self.special_actions = {
        }  # only gets written in custom NodeInstance-subclasses
        self.personal_logs = []

        # 'initializing' will be set to False below. It's needed for the ports setup, to prevent shape updating stuff
        self.initializing = True

        self.temp_state_data = None
        self.init_config = config

        # UI
        self.shadow_effect = None
        self.width = -1
        self.height = -1

        self.title_label = TitleLabel(self)

        self.animator = NodeInstanceAnimator(self)  # needs self.title_label

        self.main_widget = None
        self.main_widget_proxy: FlowProxyWidget = None
        if self.parent_node.has_main_widget:
            self.main_widget = self.parent_node.main_widget_class(self)
            self.main_widget_proxy = FlowProxyWidget(self.flow)
            self.main_widget_proxy.setWidget(self.main_widget)

        # LOADING UI
        self.body_layout: QGraphicsLinearLayout = None
        self.inputs_layout: QGraphicsLinearLayout = None
        self.outputs_layout: QGraphicsLinearLayout = None
        self.layout: QGraphicsLinearLayout = self.setup_ui()
        self.widget = QGraphicsWidget(self)
        self.widget.setLayout(self.layout)

        # TOOLTIP
        if self.parent_node.description != '':
            self.setToolTip('<html><head/><body><p>' +
                            self.parent_node.description +
                            '</p></body></html>')
        self.setCursor(Qt.SizeAllCursor)

        # DESIGN THEME
        Design.flow_theme_changed.connect(self.theme_changed)

    def initialized(self):
        """All ports and the main widget get finally created here."""

        # LOADING CONFIG
        if self.init_config is not None:
            # self.setPos(config['position x'], config['position y'])
            self.setup_ports(self.init_config['inputs'],
                             self.init_config['outputs'])
            if self.main_widget:
                try:
                    self.main_widget.set_data(
                        self.init_config['main widget data'])
                except Exception as e:
                    print('Exception while setting data in',
                          self.parent_node.title,
                          'NodeInstance\'s main widget:', e,
                          ' (was this intended?)')

            self.special_actions = self.set_special_actions_data(
                self.init_config['special actions'])
            self.temp_state_data = self.init_config['state data']
        else:
            self.setup_ports()

        # LOADING DATA
        if self.temp_state_data is not None:
            try:
                self.set_data(self.temp_state_data)
            except Exception as e:
                print('Exception while setting data in',
                      self.parent_node.title, 'NodeInstance:', e,
                      ' (was this intended?)')

        self.initializing = False

        # No self.update_shape() here because for some reason, the bounding rect hasn't been initialized yet, so
        # self.update_shape() gets called when the item is being drawn the first time (see paint event in NI painter)
        # TODO: change that ^ once there is a solution for this: https://forum.qt.io/topic/117179/force-qgraphicsitem-to-update-immediately-wait-for-update-event

        self.update_design()  # load current design, update QGraphicsItem

        self.update()  # and finally update the NodeInstance once

    def setup_ui(self):
        """Creates the empty layouts for the NI's widget."""

        #   main layout
        layout = QGraphicsLinearLayout(Qt.Vertical)
        layout.setSpacing(10)

        if self.parent_node.design_style == 'extended':
            layout.addItem(self.title_label)
            layout.setAlignment(self.title_label, Qt.AlignTop)

        #   inputs
        self.inputs_layout = QGraphicsLinearLayout(Qt.Vertical)
        self.inputs_layout.setSpacing(2)

        #   outputs
        self.outputs_layout = QGraphicsLinearLayout(Qt.Vertical)
        self.outputs_layout.setSpacing(2)

        #   body
        self.body_layout = QGraphicsLinearLayout(Qt.Horizontal)

        self.body_layout.setSpacing(4)
        self.body_layout.addItem(self.inputs_layout)
        self.body_layout.setAlignment(self.inputs_layout,
                                      Qt.AlignVCenter | Qt.AlignLeft)
        self.body_layout.addStretch()
        self.body_layout.addItem(self.outputs_layout)
        self.body_layout.setAlignment(self.outputs_layout,
                                      Qt.AlignVCenter | Qt.AlignRight)

        if self.main_widget is not None:
            if self.parent_node.main_widget_pos == 'between ports':
                self.body_layout.insertItem(1, self.main_widget_proxy)
                self.body_layout.insertStretch(2)
                layout.addItem(self.body_layout)

            elif self.parent_node.main_widget_pos == 'under ports':
                layout.addItem(self.body_layout)
                layout.addItem(self.main_widget_proxy)
                layout.setAlignment(self.main_widget_proxy, Qt.AlignHCenter)
        else:
            layout.addItem(self.body_layout)

        return layout

    def rebuild_ui(self):
        """Due to some really strange and annoying behaviour of these QGraphicsWidgets, they don't want to shrink
        automatically when content is removed, they just stay large, even with a Minimum SizePolicy. I didn't find a
        way around that yet, so for now I have to recreate the whole layout and make sure the widget uses the smallest
        size possible."""

        # if I don't manually remove the ports from the layouts,
        # they get deleted when setting the widget's layout to None below
        for inp in self.inputs:
            self.inputs_layout.removeAt(0)
        for out in self.outputs:
            self.outputs_layout.removeAt(0)

        self.layout = self.setup_ui()  # recreate layout

        # forcefully making the widget shrink
        self.widget.setLayout(None)
        self.widget.resize(self.widget.minimumSize())

        self.widget.setLayout(self.layout)

        # add inputs to new layout
        for inp in self.inputs:
            self.add_input_to_layout(inp)
        for out in self.outputs:
            self.add_output_to_layout(out)

    #                        __                             _    __     __
    #              ____ _   / /  ____ _   ____     _____   (_)  / /_   / /_     ____ ___
    #             / __ `/  / /  / __ `/  / __ \   / ___/  / /  / __/  / __ \   / __ `__ \
    #            / /_/ /  / /  / /_/ /  / /_/ /  / /     / /  / /_   / / / /  / / / / / /
    #            \__,_/  /_/   \__, /   \____/  /_/     /_/   \__/  /_/ /_/  /_/ /_/ /_/
    #                         /____/

    def update(self, input_called=-1, output_called=-1):
        """This is the method used to activate a NodeInstance. Note that this signature shadows the update() method from
        QGraphicsItem used to graphically update a QGraphicsItem which can be accessed via
        QGraphicsItem.update(self)."""

        if Design.animations_enabled:
            self.animator.start()

        Debugger.debug('update in', self.parent_node.title, 'on input',
                       input_called)
        try:
            self.update_event(input_called)
        except Exception as e:
            Debugger.debug('EXCEPTION IN', self.parent_node.title, 'NI:', e)

    def update_event(self, input_called=-1):
        """Gets called when an input received a signal. This is where the magic begins in subclasses."""

        pass

    def input(self, index):
        """Returns the value of a data input.
        If the input is connected, the value of the connected output is used:
        If not, the value of the widget is used."""

        Debugger.debug('input called in', self.parent_node.title, 'NI:', index)
        return self.inputs[index].get_val()

    def exec_output(self, index):
        """Executes an execution output, sending a signal to all connected execution inputs causing the connected
        NIs to update."""
        self.outputs[index].exec()

    def set_output_val(self, index, val):
        """Sets the value of a data output.
        self.data_outputs_updated() has to be called manually after all values are set."""

        if not self.flow.viewport_update_mode.sync:  # asynchronous viewport updates
            vp = self.flow.viewport()
            vp.repaint(self.flow.mapFromScene(self.sceneBoundingRect()))

        self.outputs[index].set_val(val)

    def data_outputs_updated(self):
        """(outdated!) Sends update signals to all data outputs causing connected NIs to update."""

        Debugger.debug('updating data outputs in', self.parent_node.title)
        for o in self.outputs:
            if o.type_ == 'data':
                o.updated_val()
        Debugger.debug('data outputs in', self.parent_node.title, 'updated')

    def remove_event(self):
        """Method to stop all threads in hold of the NI itself."""

        pass

    #                                 _
    #              ____ _   ____     (_)
    #             / __ `/  / __ \   / /
    #            / /_/ /  / /_/ /  / /
    #            \__,_/  / .___/  /_/
    #                   /_/
    #
    # all algorithm-unrelated api methods:

    #   LOGGING
    def new_log(self, title):
        """Requesting a new personal Log. Handy method for subclasses."""
        new_log = self.flow.parent_script.logger.new_log(self, title)
        self.personal_logs.append(new_log)
        return new_log

    def disable_personal_logs(self):
        """Disables personal Logs. They remain visible unless the user closes them via the appearing button."""
        for log in self.personal_logs:
            log.disable()

    def enable_personal_logs(self):
        """Resets personal Logs to normal state (hiding close button, changing style sheet)."""
        for log in self.personal_logs:
            log.enable()

    def log_message(self, message: str, target='global'):
        """Access to global_tools Script Logs ('global' or 'error')."""
        self.flow.parent_script.logger.log_message(message, target)

    # SHAPE
    def update_shape(self):
        """Causes recompilation of the whole shape."""
        # if not self.initializing:   # just to make sure
        #     self.rebuild_ui()       # (hopefully) temporary fix -> see rebuild_ui() docstring

        if self.main_widget is not None:  # maybe the main_widget got resized
            self.main_widget_proxy.setMaximumSize(self.main_widget.size())
            self.widget.adjustSize()
            self.widget.adjustSize()

        self.body_layout.invalidate()
        self.layout.invalidate()
        self.layout.activate()
        # very essential; repositions everything in case content has changed (inputs/outputs/widget)

        if self.parent_node.design_style == 'minimalistic':

            # making it recompute its true minimumWidth here
            self.widget.adjustSize()

            if self.layout.minimumWidth() < self.title_label.width + 15:
                self.layout.setMinimumWidth(self.title_label.width + 15)
                self.layout.activate()

        self.width = self.boundingRect().width()
        self.height = self.boundingRect().height()
        rect = QRectF(QPointF(-self.width / 2, -self.height / 2),
                      QPointF(self.width / 2, self.height / 2))
        self.widget.setPos(rect.left(), rect.top())

        if not self.parent_node.design_style == 'extended':
            self.title_label.setPos(
                QPointF(-self.title_label.boundingRect().width() / 2,
                        -self.title_label.boundingRect().height() / 2))

        self.flow.viewport().update()

    # PORTS
    def create_new_input(self,
                         type_,
                         label,
                         widget_name=None,
                         widget_pos='under',
                         pos=-1,
                         config=None):
        """Creates and adds a new input. Handy for subclasses."""
        Debugger.debug('create_new_input called')
        pi = InputPortInstance(self,
                               type_,
                               label,
                               config_data=config,
                               widget_name=widget_name,
                               widget_pos=widget_pos)
        if pos < -1:
            pos += len(self.inputs)
        if pos == -1:
            self.inputs.append(pi)
            self.add_input_to_layout(pi)
        else:
            self.inputs.insert(pos, pi)
            self.insert_input_into_layout(pos, pi)

        if not self.initializing:
            self.update_shape()
            self.update()

    def add_input_to_layout(self, i):
        if self.inputs_layout.count() > 0:
            self.inputs_layout.addStretch()
        self.inputs_layout.addItem(i)
        self.inputs_layout.setAlignment(i, Qt.AlignLeft)

    def insert_input_into_layout(self, index, i):
        self.inputs_layout.insertItem(index * 2,
                                      i)  # *2 because of the stretches
        self.inputs_layout.setAlignment(i, Qt.AlignLeft)
        if len(self.inputs) > 1:
            self.inputs_layout.insertStretch(
                index * 2 + 1)  # *2+1 because of the stretches, too

    def delete_input(self, i):
        """Disconnects and removes input. Handy for subclasses."""
        inp: InputPortInstance = None
        if type(i) == int:
            inp = self.inputs[i]
        elif type(i) == InputPortInstance:
            inp = i

        for cpi in inp.connected_port_instances:
            self.flow.connect_gates(inp.gate, cpi.gate)

        # for some reason, I have to remove all widget items manually from the scene too. setting the items to
        # ownedByLayout(True) does not work, I don't know why.
        self.scene().removeItem(inp.gate)
        self.scene().removeItem(inp.label)
        if inp.proxy is not None:
            self.scene().removeItem(inp.proxy)

        self.inputs_layout.removeItem(inp)
        self.inputs.remove(inp)

        # just a temporary workaround for the issues discussed here:
        # https://forum.qt.io/topic/116268/qgraphicslayout-not-properly-resizing-to-change-of-content
        self.rebuild_ui()

        if not self.initializing:
            self.update_shape()
            self.update()

    def create_new_output(self, type_, label, pos=-1):
        """Creates and adds a new output. Handy for subclasses."""

        pi = OutputPortInstance(self, type_, label)
        if pos < -1:
            pos += len(self.outputs)
        if pos == -1:
            self.outputs.append(pi)
            self.add_output_to_layout(pi)
        else:
            self.outputs.insert(pos, pi)
            self.insert_output_into_layout(pos, pi)

        if not self.initializing:
            self.update_shape()
            self.update()

    def add_output_to_layout(self, o):
        if self.outputs_layout.count() > 0:
            self.outputs_layout.addStretch()
        self.outputs_layout.addItem(o)
        self.outputs_layout.setAlignment(o, Qt.AlignRight)

    def insert_output_into_layout(self, index, o):
        self.outputs_layout.insertItem(index * 2,
                                       o)  # *2 because of the stretches
        self.outputs_layout.setAlignment(o, Qt.AlignRight)
        if len(self.outputs) > 1:
            self.outputs_layout.insertStretch(
                index * 2 + 1)  # *2+1 because of the stretches, too

    def delete_output(self, o):
        """Disconnects and removes output. Handy for subclasses."""
        out: OutputPortInstance = None
        if type(o) == int:
            out = self.outputs[o]
        elif type(o) == OutputPortInstance:
            out = o

        for cpi in out.connected_port_instances:
            self.flow.connect_gates(out.gate, cpi.gate)

        # see delete_input() for info!
        self.scene().removeItem(out.gate)
        self.scene().removeItem(out.label)

        self.outputs_layout.removeItem(out)
        self.outputs.remove(out)

        # just a temporary workaround for the issues discussed here:
        # https://forum.qt.io/topic/116268/qgraphicslayout-not-properly-resizing-to-change-of-content
        self.rebuild_ui()

        if not self.initializing:
            self.update_shape()
            self.update()

    # GET, SET DATA
    def get_data(self):
        """
        This method gets subclassed and specified. If the NI has states (so, the behavior depends on certain values),
        all these values must be stored in JSON-able format in a dict here. This dictionary will be used to reload the
        node's state when loading a project or pasting copied/cut nodes in the Flow (the states get copied too), see
        self.set_data(self, data) below.
        Unfortunately, I can't use pickle or something like that due to PySide2 which runs on C++, not Python.
        :return: Dictionary representing all values necessary to determine the NI's current state
        """
        return {}

    def set_data(self, data):
        """
        If the NI has states, it's state should get reloaded here according to what was previously provided by the same
        class in get_data(), see above.
        :param data: Dictionary representing all values necessary to determine the NI's current state
        """
        pass

    @staticmethod
    def get_default_stylesheet():
        """Handy method for subclasses to access the application window's stylesheet for UI content."""
        return Design.ryven_stylesheet

    # VARIABLES

    def get_vars_handler(self):
        return self.flow.parent_script.variables_handler

    def get_var_val(self, name):
        return self.get_vars_handler().get_var_val(name)

    def set_var_val(self, name, val):
        return self.get_vars_handler().set_var(name, val)

    def register_var_receiver(self, name, method):
        self.get_vars_handler().register_receiver(self, name, method)

    def unregister_var_receiver(self, name):
        self.get_vars_handler().unregister_receiver(self, name)

    # --------------------------------------------------------------------------------------
    # UI STUFF ----------------------------------------

    def theme_changed(self, new_theme):
        self.title_label.theme_changed(new_theme)
        self.update_design()

    def update_design(self):
        """Loads the shadow effect option and causes redraw with active theme."""

        if Design.node_instance_shadows_shown:
            self.shadow_effect = QGraphicsDropShadowEffect()
            self.shadow_effect.setXOffset(12)
            self.shadow_effect.setYOffset(12)
            self.shadow_effect.setBlurRadius(20)
            self.shadow_effect.setColor(QColor('#2b2b2b'))
            self.setGraphicsEffect(self.shadow_effect)
        else:
            self.setGraphicsEffect(None)

        self.title_label.update_design()
        # print(self.title_label.color)
        self.animator.reload_values()

        QGraphicsItem.update(self)

    def boundingRect(self):
        # remember: (0, 0) shall be the NI's center!
        rect = QRectF()
        w = self.layout.geometry().width()
        h = self.layout.geometry().height()
        rect.setLeft(-w / 2)
        rect.setTop(-h / 2)
        rect.setWidth(w)
        rect.setHeight(h)
        return rect

    #   PAINTING
    def paint(self, painter, option, widget=None):
        """All painting is done by NodeInstancePainter"""

        # in order to access a meaningful geometry of GraphicsWidget contents in update_shape(), the paint event
        # has to be called once. See here:
        # https://forum.qt.io/topic/117179/force-qgraphicsitem-to-update-immediately-wait-for-update-event/4
        if not self.painted_once:
            self.title_label.update_design()  # also necessary
            self.update_shape()

        # self.node_instance_painter.paint(painter, option, self.color, self.width, self.height, self.boundingRect(),
        #                                  Design.flow_theme, widget)
        Design.flow_theme.node_inst_painter.paint_NI(
            design_style=self.parent_node.design_style,
            painter=painter,
            option=option,
            c=self.color,
            w=self.width,
            h=self.height,
            bounding_rect=self.boundingRect(),
            title_rect=self.title_label.boundingRect())

        self.painted_once = True

    def get_context_menu(self):
        menu = QMenu(self.flow)

        for a in self.get_actions(self.get_extended_default_actions(),
                                  menu):  # menu needed for 'parent'
            if type(a) == NodeInstanceAction:
                menu.addAction(a)
            elif type(a) == QMenu:
                menu.addMenu(a)

        menu.addSeparator()

        actions = self.get_actions(self.special_actions, menu)
        for a in actions:  # menu needed for 'parent'
            if type(a) == NodeInstanceAction:
                menu.addAction(a)
            elif type(a) == QMenu:
                menu.addMenu(a)

        return menu

    def itemChange(self, change, value):
        """This method ensures that all connections, selection borders etc. that get drawn in the Flow are constantly
        redrawn during a NI drag. Should get disabled when running in performance mode - not implemented yet."""

        if change == QGraphicsItem.ItemPositionChange:
            if Design.performance_mode == 'pretty':
                self.flow.viewport().update()
            if self.movement_state == MovementEnum.mouse_clicked:
                self.movement_state = MovementEnum.position_changed

        return QGraphicsItem.itemChange(self, change, value)

    def hoverEnterEvent(self, event):
        self.title_label.set_NI_hover_state(hovering=True)
        QGraphicsItem.hoverEnterEvent(self, event)

    def hoverLeaveEvent(self, event):
        self.title_label.set_NI_hover_state(hovering=False)
        QGraphicsItem.hoverLeaveEvent(self, event)

    def mousePressEvent(self, event):
        """Used for Moving-Commands in Flow - may be replaced later with a nicer determination of a moving action."""
        self.movement_state = MovementEnum.mouse_clicked
        self.movement_pos_from = self.pos()
        return QGraphicsItem.mousePressEvent(self, event)

    def mouseReleaseEvent(self, event):
        """Used for Moving-Commands in Flow - may be replaced later with a nicer determination of a moving action."""
        if self.movement_state == MovementEnum.position_changed:
            self.flow.selected_components_moved(self.pos() -
                                                self.movement_pos_from)
        self.movement_state = None
        return QGraphicsItem.mouseReleaseEvent(self, event)

    # ACTIONS
    def get_extended_default_actions(self):
        actions_dict = self.default_actions.copy()
        for index in range(len(self.inputs)):
            inp = self.inputs[index]
            if inp.type_ == 'exec':
                actions_dict['exec input ' + str(index)] = {
                    'method': self.action_exec_input,
                    'data': {
                        'input index': index
                    }
                }
        return actions_dict

    def action_exec_input(self, data):
        self.update(data['input index'])

    def get_actions(self, actions_dict, menu):
        actions = []

        for k in actions_dict:
            v_dict = actions_dict[k]
            try:
                method = v_dict['method']
                data = None
                try:
                    data = v_dict['data']
                except KeyError:
                    pass
                action = NodeInstanceAction(k, menu, data)
                action.triggered_with_data.connect(
                    method)  # see NodeInstanceAction for explanation
                action.triggered_without_data.connect(
                    method)  # see NodeInstanceAction for explanation
                actions.append(action)
            except KeyError:
                action_menu = QMenu(k, menu)
                sub_actions = self.get_actions(v_dict, action_menu)
                for a in sub_actions:
                    action_menu.addAction(a)
                actions.append(action_menu)

        return actions

    def action_remove(self):
        self.flow.remove_node_instance_triggered(self)

    def get_special_actions_data(self, actions):
        cleaned_actions = actions.copy()
        for key in cleaned_actions:
            v = cleaned_actions[key]
            if type(v) == M:  # callable(v):
                cleaned_actions[key] = v.method_name
            elif callable(v):
                cleaned_actions[key] = v.__name__
            elif type(v) == dict:
                cleaned_actions[key] = self.get_special_actions_data(v)
            else:
                cleaned_actions[key] = v
        return cleaned_actions

    def set_special_actions_data(self, actions_data):
        actions = {}
        for key in actions_data:
            if type(actions_data[key]) != dict:
                if key == 'method':
                    try:
                        actions['method'] = M(getattr(self, actions_data[key]))
                    except AttributeError:  # outdated method referenced
                        pass
                elif key == 'data':
                    actions['data'] = actions_data[key]
            else:
                actions[key] = self.set_special_actions_data(actions_data[key])
        return actions

    # PORTS
    def setup_ports(self, inputs_config=None, outputs_config=None):
        if not inputs_config and not outputs_config:
            for i in range(len(self.parent_node.inputs)):
                inp = self.parent_node.inputs[i]
                self.create_new_input(
                    inp.type_,
                    inp.label,
                    widget_name=self.parent_node.inputs[i].widget_name,
                    widget_pos=self.parent_node.inputs[i].widget_pos)

            for o in range(len(self.parent_node.outputs)):
                out = self.parent_node.outputs[o]
                self.create_new_output(out.type_, out.label)
        else:  # when loading saved NIs, the port instances might not be synchronised to the parent's ports anymore
            for inp in inputs_config:
                has_widget = inp['has widget']

                self.create_new_input(
                    inp['type'],
                    inp['label'],
                    widget_name=inp['widget name'] if has_widget else None,
                    widget_pos=inp['widget position'] if has_widget else None,
                    config=inp['widget data'] if has_widget else None)

            for out in outputs_config:
                self.create_new_output(out['type'], out['label'])

    def get_input_widget_class(self, widget_name):
        """Returns a reference to the widget class of a given name for instantiation."""
        custom_node_input_widget_classes = self.flow.parent_script.main_window.custom_node_input_widget_classes
        widget_class = custom_node_input_widget_classes[
            self.parent_node][widget_name]
        return widget_class

    def add_input_to_scene(self, i):
        self.flow.scene().addItem(i.gate)
        self.flow.scene().addItem(i.label)
        if i.widget:
            self.flow.scene().addItem(i.proxy)

    def del_and_remove_input_from_scene(self, i_index):
        i = self.inputs[i_index]
        for p in self.inputs[i_index].connected_port_instances:
            self.flow.connect_gates(i.gate, p.gate)

        self.flow.scene().removeItem(i.gate)
        self.flow.scene().removeItem(i.label)
        if i.widget:
            self.flow.scene().removeItem(i.proxy)
            i.widget.remove_event()
        self.inputs.remove(i)

    def add_output_to_scene(self, o):
        self.flow.scene().addItem(o.gate)
        self.flow.scene().addItem(o.label)

    def del_and_remove_output_from_scene(self, o_index):
        o = self.outputs[o_index]
        for p in self.outputs[o_index].connected_port_instances:
            self.flow.connect_gates(o.gate, p.gate)

        self.flow.scene().removeItem(o.gate)
        self.flow.scene().removeItem(o.label)
        self.outputs.remove(o)

    # GENERAL
    def about_to_remove_from_scene(self):
        """Called from Flow when the NI gets removed from the scene
        to stop all running threads and disable personal logs."""

        if self.main_widget:
            self.main_widget.remove_event()
        self.remove_event()

        self.disable_personal_logs()

    def is_active(self):
        for i in self.inputs:
            if i.type_ == 'exec':
                return True
        for o in self.outputs:
            if o.type_ == 'exec':
                return True
        return False

    def has_main_widget(self):
        """Might be used later in CodePreview_Widget to enable not only showing the NI's class but also it's
        main_widget's class."""
        return self.main_widget is not None

    def get_input_widgets(self):
        """Might be used later in CodePreview_Widget to enable not only showing the NI's class but its input widgets'
        classes."""
        input_widgets = []
        for i in range(len(self.inputs)):
            inp = self.inputs[i]
            if inp.widget is not None:
                input_widgets.append({i: inp.widget})
        return input_widgets

    def get_json_data(self):
        """Returns all metadata of the NI including position, package etc. in a JSON-able dict format.
        Used to rebuild the Flow when loading a project."""

        # general attributes
        node_instance_dict = {
            'parent node title': self.parent_node.title,
            'parent node type': self.parent_node.type_,
            'parent node package': self.parent_node.package,
            'parent node description': self.parent_node.description,
            'position x': self.pos().x(),
            'position y': self.pos().y()
        }
        if self.main_widget:
            node_instance_dict['main widget data'] = self.main_widget.get_data(
            )

        node_instance_dict['state data'] = self.get_data()
        node_instance_dict['special actions'] = self.get_special_actions_data(
            self.special_actions)

        # inputs
        node_instance_inputs_list = []
        for i in self.inputs:
            input_dict = i.get_json_data()
            node_instance_inputs_list.append(input_dict)
        node_instance_dict['inputs'] = node_instance_inputs_list

        # outputs
        node_instance_outputs_list = []
        for o in self.outputs:
            output_dict = o.get_json_data()
            node_instance_outputs_list.append(output_dict)
        node_instance_dict['outputs'] = node_instance_outputs_list

        return node_instance_dict
示例#10
0
def set_shadow(QtWindow, button):
    shadow = QGraphicsDropShadowEffect(QtWindow)
    shadow.setBlurRadius(6)
    shadow.setOffset(3)
    shadow.setColor(QColor(0, 0, 0, 160))
    button.setGraphicsEffect(shadow)
class UIFunctions(MainWindow):

    ## ==> MAXIMIZE RESTORE FUNCTION
    def maximize_restore(self):
        global GLOBAL_STATE
        status = GLOBAL_STATE

        # IF NOT MAXIMIZED
        if status == 0:
            self.showMaximized()

            # SET GLOBAL TO 1
            GLOBAL_STATE = 1

            # IF MAXIMIZED REMOVE MARGINS AND BORDER RADIUS
            self.ui.drop_shadow_layout.setContentsMargins(0, 0, 0, 0)
            self.ui.drop_shadow_frame.setStyleSheet(
                "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(42, 44, 111, 255), stop:0.521368 rgba(28, 29, 73, 255)); border-radius: 0px;")
            self.ui.maximize_btn.setToolTip("Restore")
        else:
            GLOBAL_STATE = 0
            self.showNormal()
            self.resize(self.width() + 1, self.height() + 1)
            self.ui.drop_shadow_layout.setContentsMargins(10, 10, 10, 10)
            self.ui.drop_shadow_frame.setStyleSheet(
                "background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:1, stop:0 rgba(42, 44, 111, 255), stop:0.521368 rgba(28, 29, 73, 255)); border-radius: 10px;")
            self.ui.maximize_btn.setToolTip("Maximize")

    ## ==> UI DEFINITIONS
    def uiDefinitions(self):

        # REMOVE TITLE BAR
        self.setWindowFlag(QtCore.Qt.FramelessWindowHint)
        self.setAttribute(QtCore.Qt.WA_TranslucentBackground)

        # SET DROPSHADOW WINDOW
        self.shadow = QGraphicsDropShadowEffect(self)
        self.shadow.setBlurRadius(20)
        self.shadow.setXOffset(0)
        self.shadow.setYOffset(0)
        self.shadow.setColor(QColor(0, 0, 0, 100))

        # APPLY DROPSHADOW TO FRAME
        self.ui.drop_shadow_frame.setGraphicsEffect(self.shadow)

        # MAXIMIZE / RESTORE
        self.ui.maximize_btn.clicked.connect(lambda: UIFunctions.maximize_restore(self))

        # MINIMIZE
        self.ui.minimize_btn.clicked.connect(lambda: self.showMinimized())

        # CLOSE
        self.ui.close_btn.clicked.connect(lambda: self.close())

        ## ==> CREATE SIZE GRIP TO RESIZE WINDOW
        self.sizegrip = QSizeGrip(self.ui.frame_grip)
        self.sizegrip.setStyleSheet(
            "QSizeGrip { width: 10px; height: 10px; margin: 5px } QSizeGrip:hover { background-color: rgb(50, 42, 94) }")
        self.sizegrip.setToolTip("Resize Window")

    ## RETURN STATUS IF WINDOWS IS MAXIMIZE OR RESTAURED
    def returnStatus(self):
        return GLOBAL_STATE
示例#12
0
class Central(QFrame):
    '''Initializes, styles, and connects the various classes'''

    def __init__(self):
        super().__init__()
        # Objects
        self.overallLayout = QVBoxLayout(self)
        self.contentLayout = QHBoxLayout()
        self.dropShadow = QGraphicsDropShadowEffect(self)
        self.boxManager = BoxManager.BoxManager()
        self.topBar = TopBar.TopBar()
        self.selectorArea = QFrame()
        self.selectorLayout = QVBoxLayout(self.selectorArea)
        self.folderArea = QFrame()
        self.folderLayout = QHBoxLayout(self.folderArea)
        self.folderList = FolderList.FolderList()
        self.folderBar = ScrollBar.ScrollBar(self.folderList)
        self.canvas = Canvas.Canvas(self.boxManager)
        self.imageArea = QFrame()
        self.imageList = ImageList.ImageList()
        self.imageLayout = QHBoxLayout(self.imageArea)
        self.imageBar = ScrollBar.ScrollBar(self.imageList)

        # Styling
        self.setStyleSheet('Central { background: transparent; }')
        self.overallLayout.setMargin(20)
        self.overallLayout.setSpacing(0)
        self.dropShadow.setOffset(QPointF(0,4))
        self.dropShadow.setColor(QColor(0,0,0,100))
        self.dropShadow.setBlurRadius(10)
        self.setGraphicsEffect(self.dropShadow)
        self.contentLayout.setAlignment(Qt.AlignCenter)
        self.contentLayout.setMargin(0)        
        self.contentLayout.setSpacing(0)
        self.selectorLayout.setMargin(0)
        self.selectorLayout.setSpacing(0)
        self.folderLayout.setMargin(0)
        self.folderLayout.setSpacing(0)
        self.imageLayout.setMargin(0)
        self.imageLayout.setSpacing(0)
        self.folderList.setVerticalScrollBar(self.folderBar)
        self.imageList.setVerticalScrollBar(self.imageBar)
        self.selectorArea.setMaximumWidth(400)
        self.selectorArea.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)

        # Layout
        self.folderLayout.addWidget(self.folderList)
        self.folderLayout.addSpacerItem(QSpacerItem(-7, 0))
        self.folderLayout.addWidget(self.folderBar)
        self.imageLayout.addWidget(self.imageList)
        self.imageLayout.addSpacerItem(QSpacerItem(-7, 0))
        self.imageLayout.addWidget(self.imageBar)
        self.selectorLayout.addWidget(self.folderArea, 15)
        self.selectorLayout.addWidget(self.imageArea, 85)
        self.contentLayout.addWidget(self.selectorArea, 30)
        self.contentLayout.addWidget(self.canvas, 70)
        self.overallLayout.addLayout(self.contentLayout)
        self.overallLayout.insertWidget(0, self.topBar)

        # Connections
        self.folderList.selectedFolderChanged.connect(self.handleSelectedFolderChanged)
        self.imageList.selectedImageChanged.connect(self.handleSelectedImageChanged)

    def handleSelectedFolderChanged(self, folder):
        self.imageList.populate(folder)
        self.canvas.changeImage(None)
        self.canvas.setMessage('Switching Folders - {}'.format(folder.data(role=Qt.DisplayRole)))
        self.topBar.setSelectedFolder(str(folder.data(role=Qt.UserRole+1)))
        self.topBar.setSelectedImage('')

    def handleSelectedImageChanged(self, image):
        self.canvas.changeImage(image)
        self.canvas.setMessage('Switching Images - {}'.format(image.data(role=Qt.DisplayRole)))
        self.topBar.setSelectedImage(str(image.data(role=Qt.DisplayRole)))
示例#13
0
class StyleWindow(QWidget):
    def __init__(self, parent=None):
        """
        基于QWidget的窗口,作为一些窗口的基类,提供一些基础的属性
        background_color_: 背景色, 目前只支持单色
        border_width_: 边框宽度, 为0表示没有边框
        border_color_:
        opacity_: 窗口透明度
        shadow_on_: 是否开启阴影
        shadow_color_:
        shadow_blur_: 阴影半径
        border_radius_: 四个角的弧度
        分别设置4个角的radius
        left_top_border_radius:
        left_bottom_border_radius_:
        right_top_border_radius_:
        right_bottom_border_radius_
        """
        QWidget.__init__(self, parent)

        self._border_width = 0
        self._border_indicator_width = 5
        self._mouse_left_button_pressed = False
        self._rt_pre_geometry = self.geometry()
        self._mouse_move_pre_pos = QPoint()
        self._background_color = Qt.white
        self._border_color = Qt.transparent
        self._border_width = 0
        self._border_radius = 0
        self._opacity = 1.0
        self._shadow = None
        self._main_v_layout_ = None
        self._cursor_calc_type = MousePosition.CenterPos
        # border
        self._left_top_border_radius = 0
        self._left_bottom_border_radius = 0
        self._right_top_border_radius = 0
        self._right_bottom_border_radius = 0
        self._enabled_drag = False
        self.setMouseTracking(True)
        # self.setAttribute(Qt.WA_TranslucentBackground)
        self._init_default_layout()

    def paint_style_widget(self, painter):
        style_opt = QStyleOption()
        style_opt.init(self)
        self.style().drawPrimitive(QStyle.PE_Widget, style_opt, painter)

    def paintEvent(self, event):
        """ paintEvent(self, event:PySide2.QtGui.QPaintEvent) """
        painter = QPainter(self)
        self.paint_border_background(painter)

    def border_width(self):
        return self._border_width

    def set_border_width(self, width):
        self._border_width = parse_pix_width(width)
        if self._main_v_layout_ is not None:
            self._main_v_layout_.setContentsMargins(self._border_width,
                                                    self._border_width,
                                                    self._border_width,
                                                    self._border_width)

    border_width_ = Property(str, fget=border_width, fset=set_border_width)

    def border_indicator_width(self):
        return self._border_indicator_width

    def set_border_indicator_width(self, width):
        self._border_indicator_width = parse_pix_width(width)

    border_indicator_width_ = Property(str,
                                       fget=border_indicator_width,
                                       fset=set_border_indicator_width)

    def mouseMoveEvent(self, event):
        """ mouseMoveEvent(self, event:PySide2.QtGui.QMouseEvent) """
        if self._enabled_drag:
            if self.isMaximized() is not True and self.isFullScreen(
            ) is not True:
                self._set_cursor_shape(
                    self._calc_cursor_pos(event.pos(),
                                          self._calc_cursor_col(event.pos())))
            if self._mouse_left_button_pressed and MousePosition.CenterPos != self._cursor_calc_type:
                self._drag_resize()
        super(StyleWindow, self).mouseMoveEvent(event)

    def _set_cursor_shape(self, pos):
        """setCurSorShape(self, pos:StyleWindow.MousePosition)"""
        cursor_shape = Qt.ArrowCursor
        if MousePosition.TopLeftPos == pos or MousePosition.BottomRightPos == pos:
            cursor_shape = Qt.SizeFDiagCursor
        elif MousePosition.LeftPos == pos or MousePosition.RightPos == pos:
            cursor_shape = Qt.SizeHorCursor
        elif MousePosition.BottomLeftPos == pos or MousePosition.TopRightPos == pos:
            cursor_shape = Qt.SizeBDiagCursor
        elif MousePosition.BottomPos == pos or MousePosition.TopPos == pos:
            cursor_shape = Qt.SizeVerCursor
        self.setCursor(cursor_shape)

    def _calc_cursor_col(self, pt):
        """calCursorCol(self, pt:PySide2.QtCore.QPoint)"""
        res = 3
        x = pt.x()
        if x < self.border_indicator_width():
            res = 1
        elif x < self.width() - self.border_indicator_width():
            res = 2
        return res

    def _calc_cursor_pos(self, pt, bit):
        """calCursorCol(self, pt:PySide2.QtCore.QPoint, bit)"""
        result = bit
        y = pt.y()
        if y < self.border_indicator_width():
            result += 10
        elif y > self.height() - self.border_indicator_width():
            result += 30
        else:
            result += 20

        return result

    def mousePressEvent(self, event):
        """ mousePressEvent(self, event:PySide2.QtGui.QMouseEvent) """
        if self._enabled_drag:
            self.set_calc_mouse_type(
                self._calc_cursor_pos(event.pos(),
                                      self._calc_cursor_col(event.pos())))
            if Qt.LeftButton == event.button(
            ) and MousePosition.CenterPos != self._cursor_calc_type:
                self._mouse_left_button_pressed = True
            self._rt_pre_geometry = self.geometry()
            self._mouse_move_pre_pos = event.globalPos()
        super(StyleWindow, self).mousePressEvent(event)

    def mouseReleaseEvent(self, event):
        """ mousePressEvent(self, event:PySide2.QtGui.QMouseEvent) """
        self._mouse_left_button_pressed = False
        QApplication.restoreOverrideCursor()
        super(StyleWindow, self).mouseReleaseEvent(event)

    def _drag_resize(self):
        mouse_cur_pos = QCursor.pos()
        move_pos = mouse_cur_pos - self._mouse_move_pre_pos
        after_resize_geometry = self._rt_pre_geometry
        if MousePosition.TopLeftPos == self._cursor_calc_type:
            after_resize_geometry.setTopLeft(self._rt_pre_geometry.topLeft() +
                                             move_pos)
        elif MousePosition.LeftPos == self._cursor_calc_type:
            after_resize_geometry.setLeft(self._rt_pre_geometry.left() +
                                          move_pos.x())
        elif MousePosition.BottomLeftPos == self._cursor_calc_type:
            after_resize_geometry.setBottomLeft(
                self._rt_pre_geometry.bottomLeft() + move_pos)
        elif MousePosition.BottomPos == self._cursor_calc_type:
            after_resize_geometry.setBottom(self._rt_pre_geometry.bottom() +
                                            move_pos.y())
        elif MousePosition.BottomRightPos == self._cursor_calc_type:
            after_resize_geometry.setBottomRight(
                self._rt_pre_geometry.bottomRight() + move_pos)
        elif MousePosition.RightPos == self._cursor_calc_type:
            after_resize_geometry.setRight(self._rt_pre_geometry.right() +
                                           move_pos.x())
        elif MousePosition.TopRightPos == self._cursor_calc_type:
            after_resize_geometry.setTopRight(
                self._rt_pre_geometry.topRight() + move_pos)
        elif MousePosition.TopPos == self._cursor_calc_type:
            after_resize_geometry.setTop(self._rt_pre_geometry.top() +
                                         move_pos.y())

        self.setGeometry(after_resize_geometry)
        self._mouse_move_pre_pos = mouse_cur_pos
        self._rt_pre_geometry = after_resize_geometry

    def background_color(self):
        return self._background_color

    def set_background_color(self, clr):
        self._background_color = clr

    background_color_ = Property(QColor,
                                 fget=background_color,
                                 fset=set_background_color)

    def border_color(self):
        return self._border_color

    def set_border_color(self, clr):
        self._border_color = clr

    border_color_ = Property(QColor, fget=border_color, fset=set_border_color)

    def border_radius(self):
        return self._border_radius

    def set_border_radius(self, radius):
        self._border_radius = parse_pix_width(radius)

    border_radius_ = Property(str, fget=border_radius, fset=set_border_radius)

    def paint_border_background(self, painter):
        """paint_border_background(self, painter:PySide2.QtGui.QPainter)"""
        painter.save()
        pen = QPen()
        pen.setColor(self.border_color())
        pen.setWidth(self.border_width())
        painter.setPen(pen)
        brush = QBrush(self.background_color())
        painter.setBrush(brush)
        painter.setOpacity(self.opacity())
        # painter.setRenderHint(QPainter.Antialiasing)
        rc = self.rect()
        paint_path = QPainterPath()
        # adjust shadow
        if self._shadow is not None:
            rc.adjust(self.shadow_blur(), self.shadow_blur(),
                      -self.shadow_blur(), -self.shadow_blur())

        # self._calc_background_path(rc, paint_path)
        if self._calc_background_path(rc, paint_path):
            painter.setRenderHint(QPainter.Antialiasing)

        if self.border_width() > 0:
            painter.drawPath(paint_path)
        else:
            painter.fillPath(paint_path, brush)

        painter.restore()

    def set_opacity(self, opacity):
        self._opacity = opacity

    def opacity(self) -> float:
        return self._opacity

    opacity_ = Property(float, fget=opacity, fset=set_opacity)

    def resizeEvent(self, event):
        super(StyleWindow, self).resizeEvent(event)
        # self.setGeometry(5, 5, self.width() - 5, self.height() - 5)

    def set_shadow(self, on):
        if on:
            self._shadow = QGraphicsDropShadowEffect(self)
            self._shadow.setOffset(0.0, 0.0)
            self._shadow.color()
            self.setGraphicsEffect(self._shadow)
            self.setGeometry(5, 5, self.width() - 5, self.height() - 5)

    def shadow(self):
        return self._shadow

    shadow_on_ = Property(bool, fget=shadow, fset=set_shadow)

    def shadow_color(self):
        if self._shadow is not None:
            return self._shadow.color()

    def set_shadow_color(self, color):
        if self._shadow is not None:
            self._shadow.setColor(color)

    shadow_color_ = Property(QColor, fget=shadow_color, fset=set_shadow_color)

    def shadow_blur(self):
        if self._shadow is not None:
            return self._shadow.blurRadius()
        return 0

    def set_shadow_blur(self, pix_blur):
        if self._shadow is not None:
            blur = parse_pix_width(pix_blur)
            self._shadow.setBlurRadius(blur)
            self.set_border_indicator_width(blur +
                                            self.border_indicator_width())
            if self._main_v_layout_ is not None:
                self._main_v_layout_.setContentsMargins(
                    blur + self.border_width(), blur + self.border_width(),
                    blur - 1 + self.border_width(), blur + self.border_width())

    shadow_blur_ = Property(str, fget=shadow_blur, fset=set_shadow_blur)

    def _init_default_layout(self):
        """setting a default QVBoxLayout"""
        self._main_v_layout_ = QVBoxLayout(self)
        self._main_v_layout_.setContentsMargins(0, 0, 0, 0)
        self.setLayout(self._main_v_layout_)

    def set_left_top_border_radius(self, radius):
        self._left_top_border_radius = parse_pix_width(radius)

    def left_top_border_radius(self):
        if self._left_top_border_radius:
            return self._left_top_border_radius
        return self.border_radius()

    left_top_border_radius_ = Property(str,
                                       fget=left_top_border_radius,
                                       fset=set_left_top_border_radius)

    def set_left_bottom_border_radius(self, radius):
        self._left_bottom_border_radius = parse_pix_width(radius)

    def left_bottom_border_radius(self):
        if self._left_bottom_border_radius:
            return self._left_bottom_border_radius
        return self.border_radius()

    left_bottom_border_radius_ = Property(str,
                                          fget=left_bottom_border_radius,
                                          fset=set_left_bottom_border_radius)

    def set_right_top_border_radius(self, radius):
        self._right_top_border_radius = parse_pix_width(radius)

    def right_top_border_radius(self):
        if self._right_top_border_radius:
            return self._right_top_border_radius
        return self.border_radius()

    right_top_border_radius_ = Property(str,
                                        fget=right_top_border_radius,
                                        fset=set_right_top_border_radius)

    def set_right_bottom_border_radius(self, radius):
        self._right_bottom_border_radius = parse_pix_width(radius)

    def right_bottom_border_radius(self):
        if self._right_bottom_border_radius:
            return self._right_bottom_border_radius
        return self.border_radius()

    right_bottom_border_radius_ = Property(str,
                                           fget=right_bottom_border_radius,
                                           fset=set_right_bottom_border_radius)

    def _calc_background_path(self, rc, painter_path):

        render_hint = False
        if self.border_radius():
            painter_path.addRoundedRect(rc, self.border_radius(),
                                        self.border_radius())
            render_hint = True
        else:
            if self.left_top_border_radius() or self.left_bottom_border_radius() \
                    or self.right_top_border_radius() or self.right_bottom_border_radius():
                # add radius
                render_hint = True
            radius_angle = 90.0
            rotate_angle = 90.0
            painter_path.moveTo(rc.left(), rc.top())
            painter_path.arcTo(rc.left(), rc.top(),
                               self.left_top_border_radius(),
                               self.left_top_border_radius(), rotate_angle,
                               radius_angle)
            painter_path.lineTo(
                rc.left(),
                rc.bottom() - self.left_bottom_border_radius() / 2)
            painter_path.arcTo(rc.left(),
                               rc.bottom() - self.left_bottom_border_radius(),
                               self.left_bottom_border_radius(),
                               self.left_bottom_border_radius(),
                               rotate_angle * 2, radius_angle)
            painter_path.lineTo(
                rc.right() - self.right_bottom_border_radius() / 2,
                rc.bottom())
            painter_path.arcTo(rc.right() - self.right_bottom_border_radius(),
                               rc.bottom() - self.right_bottom_border_radius(),
                               self.right_bottom_border_radius(),
                               self.right_bottom_border_radius(),
                               rotate_angle * 3, radius_angle)
            painter_path.lineTo(rc.right(),
                                rc.top() - self.right_top_border_radius() / 2)
            painter_path.arcTo(rc.right() - self.right_top_border_radius(),
                               rc.top(), self.right_top_border_radius(),
                               self.right_top_border_radius(),
                               rotate_angle * 4 % rotate_angle, radius_angle)
            painter_path.lineTo(rc.left() + self.left_top_border_radius() / 2,
                                rc.top())

        return render_hint

    def set_layout(self, layout):
        if self._main_v_layout_ is not None:
            self._main_v_layout_.addLayout(layout)

    @property
    def mouse_drag_enabled(self):
        return self._enabled_drag

    @mouse_drag_enabled.setter
    def mouse_drag_enabled(self, drag):
        self._enabled_drag = drag

    def _mouse_drag_is_center_type(self):
        if self._cursor_calc_type == MousePosition.CenterPos:
            return True
        return False

    def set_calc_mouse_type(self, mouse_type: MousePosition):
        self._cursor_calc_type = mouse_type