예제 #1
0
    def __init__(self, text, duration=None, dayu_type=None, closable=False, parent=None):
        super(MMessage, self).__init__(parent)
        self.setObjectName('message')
        self.setWindowFlags(
            Qt.FramelessWindowHint | Qt.Dialog | Qt.WA_TranslucentBackground | Qt.WA_DeleteOnClose)
        self.setAttribute(Qt.WA_StyledBackground)

        if dayu_type == MMessage.LoadingType:
            _icon_label = MLoading.tiny()
        else:
            _icon_label = MAvatar.tiny()
            current_type = dayu_type or MMessage.InfoType
            _icon_label.set_dayu_image(MPixmap('{}_fill.svg'.format(current_type),
                                               vars(dayu_theme).get(current_type + '_color')))

        self._content_label = MLabel(parent=self)
        # self._content_label.set_elide_mode(Qt.ElideMiddle)
        self._content_label.setText(text)

        self._close_button = MToolButton(parent=self).icon_only().svg('close_line.svg').tiny()
        self._close_button.clicked.connect(self.close)
        self._close_button.setVisible(closable or False)

        self._main_lay = QHBoxLayout()
        self._main_lay.addWidget(_icon_label)
        self._main_lay.addWidget(self._content_label)
        self._main_lay.addStretch()
        self._main_lay.addWidget(self._close_button)
        self.setLayout(self._main_lay)

        _close_timer = QTimer(self)
        _close_timer.setSingleShot(True)
        _close_timer.timeout.connect(self.close)
        _close_timer.timeout.connect(self.sig_closed)
        _close_timer.setInterval((duration or self.default_config.get('duration')) * 1000)

        _ani_timer = QTimer(self)
        _ani_timer.timeout.connect(self._fade_out)
        _ani_timer.setInterval((duration or self.default_config.get('duration')) * 1000 - 300)

        _close_timer.start()
        _ani_timer.start()

        self._pos_ani = QPropertyAnimation(self)
        self._pos_ani.setTargetObject(self)
        self._pos_ani.setEasingCurve(QEasingCurve.OutCubic)
        self._pos_ani.setDuration(300)
        self._pos_ani.setPropertyName('pos')

        self._opacity_ani = QPropertyAnimation()
        self._opacity_ani.setTargetObject(self)
        self._opacity_ani.setDuration(300)
        self._opacity_ani.setEasingCurve(QEasingCurve.OutCubic)
        self._opacity_ani.setPropertyName('windowOpacity')
        self._opacity_ani.setStartValue(0.0)
        self._opacity_ani.setEndValue(1.0)

        self._set_proper_position(parent)
        self._fade_int()
예제 #2
0
class ProgressBarExample(QWidget, MFieldMixin):
    def __init__(self, parent=None):
        super(ProgressBarExample, self).__init__(parent)
        self.setWindowTitle('Examples for MProgressBar')
        self._init_ui()

    def _init_ui(self):
        progress_1 = MProgressBar()
        progress_1.setValue(10)
        progress_1.setAlignment(Qt.AlignCenter)
        progress_2 = MProgressBar()
        progress_2.setValue(80)

        progress_normal = MProgressBar()
        progress_normal.setValue(30)
        progress_success = MProgressBar().success()
        progress_success.setValue(100)
        progress_error = MProgressBar().error()
        progress_error.setValue(50)
        form_lay = QFormLayout()
        form_lay.addRow('Primary:', progress_normal)
        form_lay.addRow('Success:', progress_success)
        form_lay.addRow('Error:', progress_error)

        self.progress_count = 0
        self.timer = QTimer()
        self.timer.setInterval(10)
        self.timer.timeout.connect(self.slot_timeout)
        run_button = MPushButton(text='Run Something')
        run_button.clicked.connect(self.slot_run)
        self.auto_color_progress = MProgressBar().auto_color()
        auto_color_lay = QVBoxLayout()
        auto_color_lay.addWidget(run_button)
        auto_color_lay.addWidget(self.auto_color_progress)

        main_lay = QVBoxLayout()
        main_lay.addWidget(MDivider('Basic'))

        main_lay.addWidget(progress_1)
        main_lay.addWidget(progress_2)
        main_lay.addWidget(MDivider('different type'))
        main_lay.addLayout(form_lay)
        main_lay.addWidget(MDivider('auto color'))
        main_lay.addLayout(auto_color_lay)
        main_lay.addStretch()
        self.setLayout(main_lay)

    def slot_run(self):
        self.timer.start()
        self.auto_color_progress.setValue(0)

    def slot_timeout(self):
        if self.auto_color_progress.value() > 99:
            self.timer.stop()
        else:
            self.auto_color_progress.setValue(
                self.auto_color_progress.value() + 1)
예제 #3
0
    def __init__(self, text, duration=None, dayu_type=None, parent=None):
        super(MToast, self).__init__(parent)
        self.setWindowFlags(Qt.FramelessWindowHint | Qt.Dialog
                            | Qt.WA_TranslucentBackground
                            | Qt.WA_DeleteOnClose)
        self.setAttribute(Qt.WA_StyledBackground)

        _icon_lay = QHBoxLayout()
        _icon_lay.addStretch()

        if dayu_type == MToast.LoadingType:
            _icon_lay.addWidget(
                MLoading(size=dayu_theme.huge,
                         color=dayu_theme.text_color_inverse))
        else:
            _icon_label = MAvatar()
            _icon_label.set_dayu_size(60)
            _icon_label.set_dayu_image(
                MPixmap('{}_line.svg'.format(dayu_type or MToast.InfoType),
                        dayu_theme.text_color_inverse))
            _icon_lay.addWidget(_icon_label)
        _icon_lay.addStretch()

        _content_label = MLabel()
        _content_label.setText(text)
        _content_label.setAlignment(Qt.AlignCenter)

        _main_lay = QVBoxLayout()
        _main_lay.setContentsMargins(0, 0, 0, 0)
        _main_lay.addStretch()
        _main_lay.addLayout(_icon_lay)
        _main_lay.addSpacing(10)
        _main_lay.addWidget(_content_label)
        _main_lay.addStretch()
        self.setLayout(_main_lay)
        self.setFixedSize(QSize(120, 120))

        _close_timer = QTimer(self)
        _close_timer.setSingleShot(True)
        _close_timer.timeout.connect(self.close)
        _close_timer.timeout.connect(self.sig_closed)
        _close_timer.setInterval(
            (duration or self.default_config.get('duration')) * 1000)

        _ani_timer = QTimer(self)
        _ani_timer.timeout.connect(self._fade_out)
        _ani_timer.setInterval(
            (duration or self.default_config.get('duration')) * 1000 - 300)

        _close_timer.start()
        _ani_timer.start()

        self._opacity_ani = QPropertyAnimation()
        self._opacity_ani.setTargetObject(self)
        self._opacity_ani.setDuration(300)
        self._opacity_ani.setEasingCurve(QEasingCurve.OutCubic)
        self._opacity_ani.setPropertyName(b'windowOpacity')
        self._opacity_ani.setStartValue(0.0)
        self._opacity_ani.setEndValue(0.9)

        self._get_center_position(parent)
        self._fade_int()
예제 #4
0
class ParmerPanel(QWidget):
    """参数面板类"""
    send_message_signal = Signal(str, str)

    def __init__(self, username):
        super(ParmerPanel, self).__init__()

        self.username = username
        self.id = None

        self.setObjectName("parmPanel")

        self.setupUI()

        dayu_theme.apply(self)

    # 设置UI界面
    def setupUI(self):

        self.setMaximumWidth(Data.getWindowWidth() / 3)

        self.ui = loadUi(file_path + "\\res\\UI\\ParameterWindow.ui")

        self.ui.setParent(self)
        self.setLayout(QVBoxLayout())
        self.layout().addWidget(self.ui)

        self.widget_1 = self.ui.findChild(QWidget, "widget")
        self.widget_2 = self.ui.findChild(QWidget, "widget_2")
        self.widget_3 = self.ui.findChild(QWidget, "widget_3")
        self.widget_4 = self.ui.findChild(QWidget, "widget_4")
        self.widget_1.setLayout(QVBoxLayout())
        self.widget_2.setLayout(QVBoxLayout())
        self.widget_4.setLayout(QVBoxLayout())
        self.widget_2.layout().setSpacing(8)
        #设置布局

        tab_card = MTabWidget()
        self.label_filePic = MLabel("")
        self.widget_1.setMinimumSize(Data.getWindowHeight() / 2.8,
                                     Data.getWindowHeight() / 2.8)
        tab_card.addTab(self.label_filePic, u'预览图')

        # Todo 加载3d视口
        # self.model_widget = QWidget()
        self.model_widget = CefBrowser(self, url="editor")
        # self.model_widget.setLayout(QVBoxLayout())
        tab_card.addTab(self.model_widget, u'3D视口')

        self.widget_1.layout().addWidget(tab_card)
        self.widget_1.layout().setContentsMargins(0, 0, 0, 0)

        self.widget_2.layout().addWidget(MDivider(u'操作面板'))

        self.let_filename = MLineEdit(text='filename')
        tool_button = MLabel(text=u'文件名').mark().secondary()
        tool_button.setAlignment(Qt.AlignCenter)
        tool_button.setFixedWidth(80)
        self.let_filename.set_prefix_widget(tool_button)
        self.widget_2.layout().addWidget(self.let_filename)

        self.let_path = MLineEdit(text='filepath')
        tool_button_2 = MLabel(text=u'文件地址').mark().secondary()
        tool_button_2.setAlignment(Qt.AlignCenter)
        tool_button_2.setFixedWidth(80)
        self.let_path.set_prefix_widget(tool_button_2)
        self.widget_2.layout().addWidget(self.let_path)
        self.widget_2.layout().addWidget(MLabel(u'标签'))

        self.let_tag = MLineEdit(text='tag')
        self.btn_reviseTag = MPushButton(text=u'修改').primary()
        self.btn_reviseTag.setFixedWidth(80)
        self.let_tag.set_suffix_widget(self.btn_reviseTag)
        self.widget_2.layout().addWidget(self.let_tag)
        self.btn_export = MPushButton(u'导出到houdini').primary()
        self.widget_2.layout().addWidget(self.btn_export)
        self.btn_exportToMaya = MPushButton(u'导出到Maya').primary()
        self.widget_2.layout().addWidget(self.btn_exportToMaya)

        self.timer = QTimer()
        self.timer.setInterval(0.1)
        self.timer.timeout.connect(self.slot_timeout)
        self.auto_color_progress = MProgressBar().auto_color()

        self.widget_2.layout().addWidget(self.auto_color_progress)

        self.widget_4.layout().addWidget(MDivider(u'操作记录'))
        self.setWindowTitle(u"参数面板")

        # #获取控件

        self.tableWidget_operationNote = self.ui.findChild(
            QTableWidget, "tableWidget_operationNote")

        self.tableWidget_operationNote.setStyleSheet(Data.getQSS())
        #设置默认值
        self.let_filename.setReadOnly(True)  #只读
        self.let_path.setReadOnly(True)  #只读
        self.let_tag.setReadOnly(True)  #只读
        self.tableWidget_operationNote.setHorizontalHeaderLabels(
            [u'用户', u'操作', u'时间'])

        # #连接信号与槽
        self.btn_export.clicked.connect(self.slot_run)
        self.btn_reviseTag.clicked.connect(lambda: self.reviseTag())
        # self.tableWidget_operationNote.setColumnCount(3)
        setSectionResizeMode(self.tableWidget_operationNote.horizontalHeader(),
                             QHeaderView.Stretch)  # 自适应

    def setParam(self, type, name, path):
        self.type = type
        self.filename = name
        self.filepath = path

        # 根据图片类型设置图片
        if (type == "jpg" or type == "jpeg" or type == "png"):
            self.setPic(path)
        elif (type == "obj" or type == "fbx"):
            self.setObjPic()

        filepath = os.path.dirname(path)
        filename = filepath.split("/")[-1]

        self.let_filename.setText(filename)
        self.let_path.setText(filepath)

        tags = ""
        assetdb = client[type]
        assetcol = assetdb[name]
        for tagdic in assetcol.find({}, {"Tag": 1}):
            if "Tag" in tagdic:
                tag = tagdic["Tag"]
                tags += tag + ","
        self.let_tag.setText(tags)

        #设置资产操作记录表:
        assetdb = client[type]
        assetcol = assetdb[name]
        assetlist = assetcol.find({}, {
            "UserName": 1,
            "Operation": 1,
            "Time": 1
        })
        #rowcount = len(assetlist)      #assetlist并不是列表类型
        i = 0
        # for x in assetlist:
        #     i += 1  #求得行数减一

        for xdir in assetlist:

            if "UserName" in xdir:
                str1 = xdir["UserName"]
                newItem1 = QTableWidgetItem(str1)
                self.tableWidget_operationNote.setItem(i, 0, newItem1)

            if "Time" in xdir:
                str3 = xdir["Time"]
                newItem3 = QTableWidgetItem(str3)
                self.tableWidget_operationNote.setItem(i, 2, newItem3)

            if "Operation" in xdir:
                str2 = xdir["Operation"]
                newItem2 = QTableWidgetItem(str2)
                self.tableWidget_operationNote.setItem(i, 1, newItem2)
                i += 1

        self.saveBrowseNode(self.username, name, type)  #保存浏览信息到库

        # 链接信号与槽函数
        self.btn_export.clicked.connect(
            lambda: self.exportModelToHoudini(name, type, path))
        self.btn_exportToMaya.clicked.connect(
            lambda: self.exportModelToMaya(name, type, path))
        # self.saveBrowseNode(self.username, name, type)

    # 进度条
    def slot_run(self):
        self.timer.start()
        self.auto_color_progress.setValue(0)

    def slot_timeout(self):
        if self.auto_color_progress.value() > 99:
            self.timer.stop()
        else:
            self.auto_color_progress.setValue(
                self.auto_color_progress.value() + 1)

    def setPic(self, path):
        pixmap = QPixmap(path)
        self.label_filePic.setPixmap(pixmap)
        self.label_filePic.setScaledContents(True)

    def setObjPic(self):
        """加载的是obj模型,设置obj的图片"""
        pixmap = QPixmap(file_path + r"\res\image\objimg.jpg")
        self.label_filePic.setPixmap(pixmap)
        self.label_filePic.setScaledContents(True)

    def saveBrowseNode(self, username, filename, type):

        RTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
        #将浏览信息存入用户数据库
        col = userdb[username]
        dict = {"Operation": "Browse", "Time": RTime, "FileName": filename}
        col.insert_one(dict)

        #将浏览信息存入资产数据库
        assetdb = client[type]
        assetcol = assetdb[filename]
        adict = {"UserName": username, "Time": RTime, "Operation": "Browse"}
        assetcol.insert_one(adict)

    def exportModelToHoudini(self, filename, type, path):
        try:

            import hrpyc
            connection, hou = hrpyc.import_remote_module()
            name = filename.split(".")[0]
            if (type == "obj" or type == "fbx"):
                print("exportModelHoudiniOBJ")

                geo = hou.node('/obj').createNode('geo', name)
                fileNode = geo.createNode('file', name)
                fileNode.parm('file').set(path)

                prinShaderNode = hou.node('/mat').createNode(
                    'principledshader', name)
                prinShaderNode.parm('basecolor_useTexture').set(1)

                materialNode = geo.createNode('material', name + "_material")
                materialNode.parm('shop_materialpath1').set("/mat/" + name)
                materialNode.setInput(0, fileNode)
                materialNode.moveToGoodPosition()
                materialNode.setDisplayFlag(1)

            if (type == "jpg" or type == "jpeg"):
                try:
                    print("exportModelHoudiniJPG")
                    # 路径不能有中文
                    imgNode = hou.node('/img').createNode('img', "comp1")
                    imgNode = hou.node('/img/comp1').createNode('file', name)
                    # fileNode = imgNode.createNode('file', name)
                    imgNode.parm('filename1').set(path)
                except:
                    print("ExportPictureFail")

            #保存导出记录到资产数据库
            RTime = time.strftime('%Y-%m-%d %H:%M:%S',
                                  time.localtime(time.time()))
            assetdb = client[type]
            assetcol = assetdb[filename]
            adict = {
                "UserName": self.username,
                "Time": RTime,
                "Operation": "Export"
            }
            assetcol.insert_one(adict)
            # 保存导出记录到用户数据库
            usercol = userdb[self.username]
            adict = {
                "FileName": filename,
                "Time": RTime,
                "Operation": "Export"
            }
            usercol.insert_one(adict)
        except:
            self.slot_show_message(MMessage.info,
                                   (u'导出失败!请确认Houdini是否配置成功或启动。'))
            print(path)
            print(type)

    def exportModelToMaya(self, filename, type, path):

        if type == "obj" or type == "fbx":
            print("ExportModelToMaya")

            import socket

            try:
                s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
                s.connect(('127.0.0.1', 7001))
                #s.send('print("HelloWord!!!!!!!!!!!!");')
                name = filename.split(".")[0]

                command0 = "import maya.cmds as mc;"
                command1 = "imported_objects = mc.file(r'" + path + "\', ns='ns', i=True, rnn=True);"
                command2 = "transforms = mc.ls(imported_objects, type='transform');"
                command = command0 + command1 + command2
                s.send(command)
            except:
                self.slot_show_message(MMessage.info,
                                       (u'导出失败!请确认Maya是否配置成功或启动。'))
                print(path)
                print(type)
        else:
            print("This can't export to Maya")

    def saveExportModelNode(self, username, filename, type):
        RTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
        # 将浏览信息存入用户数据库
        col = userdb[username]
        dict = {"Operation": "Export", "Time": RTime, "FileName": filename}
        col.insert_one(dict)

        # 将浏览信息存入资产数据库
        assetdb = client[type]
        assetcol = assetdb[filename]
        adict = {"UserName": username, "Time": RTime, "Operation": "Export"}
        assetcol.insert_one(adict)

    def reviseTag(self):

        if self.username != None:
            usercol = userdb[self.username]
            idlist = usercol.find({"_id": "UserID"}, {"UserID": 1})
            for iddir in idlist:
                self.id = iddir["UserID"]

            if self.id != "管理员":
                self.send_message_signal.emit("warnning", u"只有管理员才可以修改标签")
                return 0

            self.let_tag.setReadOnly(False)  #可写入
            self.btn_reviseTag.setText(u"确认修改")

            self.btn_reviseTag.clicked.disconnect()
            self.btn_reviseTag.clicked.connect(lambda: self.confirmReviseTag())

    def confirmReviseTag(self):
        self.let_tag.setReadOnly(True)  # 只读

        #连接数据库
        assetdb = client[self.type]
        assetcol = assetdb[self.filename]
        assetdb = client[self.type]
        assetcol = assetdb[self.filename]

        newTags = self.let_tag.text().split(",")
        self.oldTags = []
        taglist = assetcol.find({}, {"Tag": 1})
        for tag in taglist:
            if "Tag" in tag:
                self.oldTags.append(tag["Tag"])

        #是否有删除标签
        for oldTag in self.oldTags:
            delTag = True
            for newTag in newTags:
                if newTag == oldTag:
                    delTag = False
            if delTag:  #存在
                # 删除资产库里的标签
                deldir = {"Tag": oldTag}
                assetcol.delete_one(deldir)
                #删除标签文件库里对应的文件
                tagfilecol = tagfiledb[oldTag]
                deldir = {"FileName": self.filename}
                tagfilecol.delete_one(deldir)

        #是否有新标签
        for newTag in newTags:
            if newTag == "":
                continue
            # 是否为从未有过的标签
            new = True
            for x in tagcol.find({}, {"Tag": 1}):  # 把数据库里的标签取出
                if newTag == x["Tag"]:
                    new = False
            if new:
                newTagdir = {"Tag": newTag}
                tagcol.insert_one(newTagdir)  # 添加到标签数据库

            addTag = True
            for oldTag in self.oldTags:
                if newTag == oldTag:
                    addTag = False
            if addTag:
                #资产库里添加新标签
                adict = {"Tag": newTag}
                assetcol.insert_one(adict)
                # 标签文件库里添加对应的文件
                tagfilecol = tagfiledb[newTag]
                deldir = {"FileName": self.filename}
                tagfilecol.insert_one(deldir)

        self.btn_reviseTag.setText(u"修改")
        self.send_message_signal.emit("info", u"已成功修改标签")

        #保存操作记录到用户数据库
        RTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))
        usercol = userdb[self.username]
        adict = {
            "FileName": self.filename,
            "Time": RTime,
            "Operation": "EditTag"
        }
        usercol.insert_one(adict)
        #保存操作记录到资产数据库
        RTime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(time.time()))

        adict = {
            "UserName": self.username,
            "Time": RTime,
            "Operation": "EditTag"
        }
        assetcol.insert_one(adict)

        self.btn_reviseTag.clicked.disconnect()
        self.btn_reviseTag.clicked.connect(lambda: self.reviseTag())

    # Todo: 传入预览图路径,加载3d视口资源到3d视口
    def setModelWidget(self, path):

        file = os.path.dirname(path)
        tex_type = [
            'albedo', 'bump', 'roughness', 'specular', 'opacity', 'normal',
            'displacement'
        ]
        data = {}  #存储贴图数据

        for name in os.listdir(file):
            if name.split(".")[-1] == "obj" or name.split(".")[-1] == "fbx":
                modelpath = os.path.join(file, name).replace("\\", "/")
                data["model"] = modelpath

            elif name.split(".")[-1] == "jpg":
                for typ in tex_type:
                    _typ = "_%s." % typ
                    if _typ in name.lower():
                        data[typ] = os.path.join(file, name).replace("\\", "/")
                        break
        import json
        # self.model_widget.layout().addWidget(MLabel(modelpath))
        data = json.dumps(data)
        print data
        self.model_widget.loadAsset(data)

    # 弹出信息提示窗口
    def slot_show_message(self, func, config):
        func(config, parent=self.parent())
예제 #5
0
class MLineEdit(QLineEdit):
    """MLineEdit"""
    sig_delay_text_changed = Signal(basestring)

    def __init__(self, text='', parent=None):
        super(MLineEdit, self).__init__(text, parent)
        self._main_layout = QHBoxLayout()
        self._main_layout.setContentsMargins(0, 0, 0, 0)
        self._main_layout.addStretch()

        self._prefix_widget = None
        self._suffix_widget = None

        self.setLayout(self._main_layout)
        self.setProperty('history', self.property('text'))
        self.setTextMargins(2, 0, 2, 0)

        self._delay_timer = QTimer()
        self._delay_timer.setInterval(500)
        self._delay_timer.setSingleShot(True)
        self._delay_timer.timeout.connect(self._slot_delay_text_changed)

        self._dayu_size = dayu_theme.default_size

    def get_dayu_size(self):
        """
        Get the push button height
        :return: integer
        """
        return self._dayu_size

    def set_dayu_size(self, value):
        """
        Set the avatar size.
        :param value: integer
        :return: None
        """
        self._dayu_size = value
        if hasattr(self._prefix_widget, 'set_dayu_size'):
            self._prefix_widget.set_dayu_size(self._dayu_size)
        if hasattr(self._suffix_widget, 'set_dayu_size'):
            self._suffix_widget.set_dayu_size(self._dayu_size)
        self.style().polish(self)

    dayu_size = Property(int, get_dayu_size, set_dayu_size)

    def set_delay_duration(self, millisecond):
        """Set delay timer's timeout duration."""
        self._delay_timer.setInterval(millisecond)

    @Slot()
    def _slot_delay_text_changed(self):
        self.sig_delay_text_changed.emit(self.text())

    def get_prefix_widget(self):
        """Get the prefix widget for user to edit"""
        return self._prefix_widget

    def set_prefix_widget(self, widget):
        """Set the line edit left start widget"""
        if self._prefix_widget:
            index = self._main_layout.indexOf(self._prefix_widget)
            self._main_layout.takeAt(index)
            self._prefix_widget.setVisible(False)
        # if isinstance(widget, MPushButton):
        widget.setProperty('combine', 'horizontal')
        widget.setProperty('position', 'left')
        if hasattr(widget, 'set_dayu_size'):
            widget.set_dayu_size(self._dayu_size)

        margin = self.textMargins()
        margin.setLeft(margin.left() + widget.width())
        self.setTextMargins(margin)

        self._main_layout.insertWidget(0, widget)
        self._prefix_widget = widget
        return widget

    def get_suffix_widget(self):
        """Get the suffix widget for user to edit"""
        return self._suffix_widget

    def set_suffix_widget(self, widget):
        """Set the line edit right end widget"""
        if self._suffix_widget:
            index = self._main_layout.indexOf(self._suffix_widget)
            self._main_layout.takeAt(index)
            self._suffix_widget.setVisible(False)
        # if isinstance(widget, MPushButton):
        widget.setProperty('combine', 'horizontal')
        widget.setProperty('position', 'right')
        if hasattr(widget, 'set_dayu_size'):
            widget.set_dayu_size(self._dayu_size)

        margin = self.textMargins()
        margin.setRight(margin.right() + widget.width())
        self.setTextMargins(margin)
        self._main_layout.addWidget(widget)
        self._suffix_widget = widget
        return widget

    def setText(self, text):
        """Override setText save text to history"""
        self.setProperty('history', u'{}\n{}'.format(self.property('history'),
                                                     text))
        return super(MLineEdit, self).setText(text)

    def clear(self):
        """Override clear to clear history"""
        self.setProperty('history', '')
        return super(MLineEdit, self).clear()

    def keyPressEvent(self, event):
        """Override keyPressEvent to start delay timer"""
        if event.key() not in [Qt.Key_Enter, Qt.Key_Tab]:
            if self._delay_timer.isActive():
                self._delay_timer.stop()
            self._delay_timer.start()
        super(MLineEdit, self).keyPressEvent(event)

    def search(self):
        """Add a search icon button for MLineEdit."""
        suffix_button = MToolButton().icon_only().svg('close_line.svg')
        suffix_button.clicked.connect(self.clear)
        self.set_suffix_widget(suffix_button)
        self.setPlaceholderText(self.tr('Enter key word to search...'))
        return self

    def error(self):
        """A a toolset to MLineEdit to store error info with red style"""
        @Slot()
        def _slot_show_detail(self):
            dialog = QTextEdit(self)
            dialog.setReadOnly(True)
            geo = QApplication.desktop().screenGeometry()
            dialog.setGeometry(geo.width() / 2,
                               geo.height() / 2,
                               geo.width() / 4,
                               geo.height() / 4)
            dialog.setWindowTitle(self.tr('Error Detail Information'))
            dialog.setText(self.property('history'))
            dialog.setWindowFlags(Qt.Dialog)
            dialog.show()

        self.setProperty('dayu_type', 'error')
        self.setReadOnly(True)
        _suffix_button = MToolButton().icon_only().svg('detail_line.svg')
        _suffix_button.clicked.connect(
            functools.partial(_slot_show_detail, self))
        self.set_suffix_widget(_suffix_button)
        self.setPlaceholderText(self.tr('Error information will be here...'))
        return self

    def search_engine(self, text='Search'):
        """Add a MPushButton to suffix for MLineEdit"""
        _suffix_button = MPushButton(text=text).primary()
        _suffix_button.clicked.connect(self.returnPressed)
        _suffix_button.setFixedWidth(100)
        self.set_suffix_widget(_suffix_button)
        self.setPlaceholderText(self.tr('Enter key word to search...'))
        return self

    def file(self, filters=None):
        """Add a MClickBrowserFileToolButton for MLineEdit to select file"""
        _suffix_button = MClickBrowserFileToolButton()
        _suffix_button.sig_file_changed.connect(self.setText)
        _suffix_button.set_dayu_filters(filters or [])
        self.textChanged.connect(_suffix_button.set_dayu_path)
        self.set_suffix_widget(_suffix_button)
        self.setPlaceholderText(self.tr('Click button to browser files'))
        return self

    def folder(self):
        """Add a MClickBrowserFolderToolButton for MLineEdit to select folder"""
        _suffix_button = MClickBrowserFolderToolButton()
        _suffix_button.sig_folder_changed.connect(self.setText)
        self.textChanged.connect(_suffix_button.set_dayu_path)
        self.set_suffix_widget(_suffix_button)
        self.setPlaceholderText(self.tr('Click button to browser folder'))
        return self

    def huge(self):
        """Set MLineEdit to huge size"""
        self.set_dayu_size(dayu_theme.huge)
        return self

    def large(self):
        """Set MLineEdit to large size"""
        self.set_dayu_size(dayu_theme.large)
        return self

    def medium(self):
        """Set MLineEdit to  medium"""
        self.set_dayu_size(dayu_theme.medium)
        return self

    def small(self):
        """Set MLineEdit to small size"""
        self.set_dayu_size(dayu_theme.small)
        return self

    def tiny(self):
        """Set MLineEdit to tiny size"""
        self.set_dayu_size(dayu_theme.tiny)
        return self

    def password(self):
        """Set MLineEdit to password echo mode"""
        self.setEchoMode(QLineEdit.Password)
        return self
예제 #6
0
class MDrawer(QWidget):
    """
    A panel which slides in from the edge of the screen.
    """
    LeftPos = 'left'
    RightPos = 'right'
    TopPos = 'top'
    BottomPos = 'bottom'

    sig_closed = Signal()

    def __init__(self, title, position='right', closable=True, parent=None):
        super(MDrawer, self).__init__(parent)
        self.setObjectName('message')
        # self.setWindowFlags(Qt.Popup )
        # self.setWindowFlags(
        #     Qt.FramelessWindowHint | Qt.Popup | Qt.WA_TranslucentBackground)
        self.setAttribute(Qt.WA_StyledBackground)

        self._title_label = MLabel(parent=self).h4()
        # self._title_label.set_elide_mode(Qt.ElideRight)
        self._title_label.setText(title)

        self._close_button = MToolButton(
            parent=self).icon_only().svg('close_line.svg').small()
        self._close_button.clicked.connect(self.close)
        self._close_button.setVisible(closable or False)

        _title_lay = QHBoxLayout()
        _title_lay.addWidget(self._title_label)
        _title_lay.addStretch()
        _title_lay.addWidget(self._close_button)
        self._button_lay = QHBoxLayout()
        self._button_lay.addStretch()

        self._scroll_area = QScrollArea()
        self._main_lay = QVBoxLayout()
        self._main_lay.addLayout(_title_lay)
        self._main_lay.addWidget(MDivider())
        self._main_lay.addWidget(self._scroll_area)
        self._main_lay.addWidget(MDivider())
        self._main_lay.addLayout(self._button_lay)
        self.setLayout(self._main_lay)

        self._position = position

        self._close_timer = QTimer(self)
        self._close_timer.setSingleShot(True)
        self._close_timer.timeout.connect(self.close)
        self._close_timer.timeout.connect(self.sig_closed)
        self._close_timer.setInterval(300)
        self._is_first_close = True

        self._pos_ani = QPropertyAnimation(self)
        self._pos_ani.setTargetObject(self)
        self._pos_ani.setEasingCurve(QEasingCurve.OutCubic)
        self._pos_ani.setDuration(300)
        self._pos_ani.setPropertyName('pos')

        self._opacity_ani = QPropertyAnimation()
        self._opacity_ani.setTargetObject(self)
        self._opacity_ani.setDuration(300)
        self._opacity_ani.setEasingCurve(QEasingCurve.OutCubic)
        self._opacity_ani.setPropertyName('windowOpacity')
        self._opacity_ani.setStartValue(0.0)
        self._opacity_ani.setEndValue(1.0)
        # self._shadow_effect = QGraphicsDropShadowEffect(self)
        # color = dayu_theme.red
        # self._shadow_effect.setColor(color)
        # self._shadow_effect.setOffset(0, 0)
        # self._shadow_effect.setBlurRadius(5)
        # self._shadow_effect.setEnabled(False)
        # self.setGraphicsEffect(self._shadow_effect)

        self.app = QApplication.instance()
        self.app.installEventFilter(self)
        self.protect_time = time.time()

    def retrieveChildren(self, parent, receiver):
        if parent is receiver:
            return True
        if not hasattr(parent, "children"):
            return

        for child in parent.children():

            ret = self.retrieveChildren(child, receiver)
            if ret:
                return ret

    def eventFilter(self, receiver, event):
        # Note QEvent.Type.MouseButtonPress 为 2
        if event.type() == 2:
            if self.retrieveChildren(self, receiver):
                self.protect_time = time.time()
            # NOTE 如果点击多次触发,通过时间进行保护
            if (time.time() - self.protect_time) > .1:
                self.close()
        elif event.type() == QEvent.Type.Resize and receiver is self.window():
            self.close()
        return False

    def set_widget(self, widget):
        self._scroll_area.setWidget(widget)

    def add_button(self, button):
        self._button_lay.addWidget(button)

    def _fade_out(self):
        self._pos_ani.setDirection(QAbstractAnimation.Backward)
        self._pos_ani.start()
        self._opacity_ani.setDirection(QAbstractAnimation.Backward)
        self._opacity_ani.start()

    def _fade_int(self):
        self._pos_ani.start()
        self._opacity_ani.start()

    def _set_proper_position(self):
        parent = self.parent()
        parent_geo = parent.geometry()
        if self._position == MDrawer.LeftPos:
            pos = parent_geo.topLeft(
            ) if parent.parent() is None else parent.mapToGlobal(
                parent_geo.topLeft())
            pos -= self.window().geometry().topLeft()
            target_x = pos.x()
            target_y = pos.y()
            self.setFixedHeight(parent_geo.height())
            self._pos_ani.setStartValue(
                QPoint(target_x - self.width(), target_y))
            self._pos_ani.setEndValue(QPoint(target_x, target_y))
        if self._position == MDrawer.RightPos:
            pos = parent_geo.topRight(
            ) if parent.parent() is None else parent.mapToGlobal(
                parent_geo.topRight())
            pos -= self.window().geometry().topLeft()
            self.setFixedHeight(parent_geo.height())
            target_x = pos.x() - self.width()
            target_y = pos.y()
            self._pos_ani.setStartValue(
                QPoint(target_x + self.width(), target_y))
            self._pos_ani.setEndValue(QPoint(target_x, target_y))
        if self._position == MDrawer.TopPos:
            pos = parent_geo.topLeft(
            ) if parent.parent() is None else parent.mapToGlobal(
                parent_geo.topLeft())
            pos -= self.window().geometry().topLeft()
            self.setFixedWidth(parent_geo.width())
            target_x = pos.x()
            target_y = pos.y()
            self._pos_ani.setStartValue(
                QPoint(target_x, target_y - self.height()))
            self._pos_ani.setEndValue(QPoint(target_x, target_y))
        if self._position == MDrawer.BottomPos:
            pos = parent_geo.bottomLeft(
            ) if parent.parent() is None else parent.mapToGlobal(
                parent_geo.bottomLeft())
            pos -= self.window().geometry().topLeft()
            self.setFixedWidth(parent_geo.width())
            target_x = pos.x()
            target_y = pos.y() - self.height()
            self._pos_ani.setStartValue(
                QPoint(target_x, target_y + self.height()))
            self._pos_ani.setEndValue(QPoint(target_x, target_y))

    def set_dayu_position(self, value):
        """
        Set the placement of the MDrawer.
        top/right/bottom/left, default is right
        :param value: str
        :return: None
        """
        self._position = value
        if value in [MDrawer.BottomPos, MDrawer.TopPos]:
            self.setFixedHeight(200)
        else:
            self.setFixedWidth(200)

    def get_dayu_position(self):
        """
        Get the placement of the MDrawer
        :return: str
        """
        return self._position

    dayu_position = Property(str, get_dayu_position, set_dayu_position)

    def left(self):
        """Set drawer's placement to left"""
        self.set_dayu_position(MDrawer.LeftPos)
        return self

    def right(self):
        """Set drawer's placement to right"""
        self.set_dayu_position(MDrawer.RightPos)
        return self

    def top(self):
        """Set drawer's placement to top"""
        self.set_dayu_position(MDrawer.TopPos)
        return self

    def bottom(self):
        """Set drawer's placement to bottom"""
        self.set_dayu_position(MDrawer.BottomPos)
        return self

    def show(self):
        self._set_proper_position()
        self._fade_int()
        return super(MDrawer, self).show()

    def closeEvent(self, event):
        self.app.removeEventFilter(self)
        if self._is_first_close:
            self._is_first_close = False
            self._close_timer.start()
            self._fade_out()
            event.ignore()
        else:
            event.accept()