コード例 #1
0
ファイル: alert.py プロジェクト: muyr/dayu_widgets3
    def __init__(self, text='', parent=None, flags=0):
        super(MAlert, self).__init__(parent, flags)
        self.setAttribute(Qt.WA_StyledBackground)
        self._icon_label = MAvatar()
        self._icon_label.set_dayu_size(dayu_theme.tiny)
        self._content_label = MLabel().secondary()
        self._close_button = MToolButton().svg(
            'close_line.svg').tiny().icon_only()
        self._close_button.clicked.connect(
            functools.partial(self.setVisible, False))

        self._main_lay = QHBoxLayout()
        self._main_lay.setContentsMargins(8, 8, 8, 8)
        self._main_lay.addWidget(self._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)

        self.set_show_icon(True)
        self.set_closeable(False)
        self._dayu_type = None
        self._dayu_text = None
        self.set_dayu_type(MAlert.InfoType)
        self.set_dayu_text(text)
コード例 #2
0
ファイル: drawer.py プロジェクト: muyr/dayu_widgets3
    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)
コード例 #3
0
ファイル: badge_example.py プロジェクト: muyr/dayu_widgets3
    def _init_ui(self):
        standalone_lay = QHBoxLayout()
        standalone_lay.addWidget(MBadge.count(0))
        standalone_lay.addWidget(MBadge.count(20))
        standalone_lay.addWidget(MBadge.count(100))
        standalone_lay.addWidget(MBadge.dot(True))
        standalone_lay.addWidget(MBadge.text('new'))
        standalone_lay.addStretch()

        button = MToolButton().svg('trash_line.svg')
        avatar = MAvatar.large(MPixmap('avatar.png'))
        button_alert = MToolButton().svg('alert_fill.svg').large()
        badge_1 = MBadge.dot(True, widget=button)
        badge_2 = MBadge.dot(True, widget=avatar)
        badge_3 = MBadge.dot(True, widget=button_alert)
        button.clicked.connect(lambda: badge_1.set_dayu_dot(False))

        spin_box = MSpinBox()
        spin_box.setRange(0, 9999)
        spin_box.valueChanged.connect(badge_3.set_dayu_count)
        spin_box.setValue(1)

        self.register_field('button1_selected', u'北京')
        menu1 = MMenu()
        menu1.set_data([u'北京', u'上海', u'广州', u'深圳'])
        select1 = MComboBox()
        select1.set_menu(menu1)
        self.bind('button1_selected',
                  select1,
                  'value',
                  signal='sig_value_changed')

        badge_hot = MBadge.text('hot', widget=MLabel(u'你的理想城市  '))

        sub_lay1 = QHBoxLayout()
        sub_lay1.addWidget(badge_1)
        sub_lay1.addWidget(badge_2)
        sub_lay1.addWidget(badge_3)
        sub_lay1.addStretch()

        sub_lay2 = QHBoxLayout()
        sub_lay2.addWidget(badge_hot)
        sub_lay2.addWidget(select1)
        sub_lay2.addStretch()

        main_lay = QVBoxLayout()
        main_lay.addWidget(MDivider('use standalone'))
        main_lay.addLayout(standalone_lay)
        main_lay.addWidget(MDivider('different type'))
        main_lay.addLayout(sub_lay1)
        main_lay.addWidget(spin_box)
        main_lay.addWidget(MDivider('different type'))
        main_lay.addLayout(sub_lay2)
        main_lay.addStretch()
        self.setLayout(main_lay)
コード例 #4
0
ファイル: button_group.py プロジェクト: muyr/dayu_widgets3
 def create_button(self, data_dict):
     button = MToolButton()
     if data_dict.get('svg'):
         button.svg(data_dict.get('svg'))
     if data_dict.get('text'):
         if data_dict.get('svg') or data_dict.get('icon'):
             button.text_beside_icon()
         else:
             button.text_only()
     else:
         button.icon_only()
     return button
コード例 #5
0
    def __init__(self,
                 title='',
                 expand=False,
                 widget=None,
                 closeable=False,
                 parent=None):
        super(MSectionItem, self).__init__(parent)
        self._central_widget = None
        self.setAttribute(Qt.WA_StyledBackground)
        self.title_label = MLabel(parent=self)
        self.expand_icon = MLabel(parent=self)
        self.expand_icon.setSizePolicy(QSizePolicy.Minimum,
                                       QSizePolicy.Minimum)
        self._close_button = MToolButton().icon_only().tiny().svg(
            'close_line.svg')
        self._close_button.clicked.connect(self.close)

        header_lay = QHBoxLayout()
        header_lay.addWidget(self.expand_icon)
        header_lay.addWidget(self.title_label)
        header_lay.addStretch()
        header_lay.addWidget(self._close_button)
        self.header_widget = QWidget(parent=self)
        self.header_widget.setAttribute(Qt.WA_StyledBackground)
        self.header_widget.setObjectName('title')
        self.header_widget.setLayout(header_lay)
        self.header_widget.setSizePolicy(QSizePolicy.Minimum,
                                         QSizePolicy.Minimum)
        self.header_widget.setCursor(Qt.PointingHandCursor)
        self.title_label.setCursor(Qt.PointingHandCursor)
        self.header_widget.installEventFilter(self)
        self.title_label.installEventFilter(self)

        self.content_widget = QWidget(parent=self)
        self.content_layout = QHBoxLayout()
        self.content_widget.setLayout(self.content_layout)

        self.main_lay = QVBoxLayout()
        self.main_lay.setContentsMargins(0, 0, 0, 0)
        self.main_lay.setSpacing(0)
        self.main_lay.addWidget(self.header_widget)
        self.main_lay.addWidget(self.content_widget)
        self.setLayout(self.main_lay)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.setMouseTracking(True)
        self.set_title(title)
        self.set_closeable(closeable)
        if widget:
            self.set_content(widget)
        self.set_expand(expand)
コード例 #6
0
ファイル: line_edit.py プロジェクト: muyr/dayu_widgets3
 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
コード例 #7
0
ファイル: card.py プロジェクト: muyr/dayu_widgets3
    def __init__(self,
                 cover=None,
                 avatar=None,
                 title=None,
                 description=None,
                 extra=False,
                 parent=None):
        super(MMeta, self).__init__(parent)
        self.setAttribute(Qt.WA_StyledBackground)
        self._cover_label = QLabel()
        self._avatar = MAvatar()
        self._title_label = MLabel().h4()
        self._description_label = MLabel().secondary()
        self._description_label.setWordWrap(True)
        self._description_label.set_elide_mode(Qt.ElideRight)
        self._title_layout = QHBoxLayout()
        self._title_layout.addWidget(self._title_label)
        self._title_layout.addStretch()
        self._extra_button = MToolButton(
            parent=self).icon_only().svg('more.svg')
        self._title_layout.addWidget(self._extra_button)
        self._extra_button.setVisible(extra)

        content_lay = QFormLayout()
        content_lay.setContentsMargins(5, 5, 5, 5)
        content_lay.addRow(self._avatar, self._title_layout)
        content_lay.addRow(self._description_label)

        self._button_layout = QHBoxLayout()

        main_lay = QVBoxLayout()
        main_lay.setSpacing(0)
        main_lay.setContentsMargins(1, 1, 1, 1)
        main_lay.addWidget(self._cover_label)
        main_lay.addLayout(content_lay)
        main_lay.addLayout(self._button_layout)
        main_lay.addStretch()
        self.setLayout(main_lay)
        self._cover_label.setFixedSize(QSize(200, 200))
コード例 #8
0
ファイル: card.py プロジェクト: muyr/dayu_widgets3
    def __init__(self,
                 title=None,
                 image=None,
                 size=None,
                 extra=None,
                 type=None,
                 parent=None):
        super(MCard, self).__init__(parent=parent)
        self.setAttribute(Qt.WA_StyledBackground)
        self.setProperty('border', False)
        size = size or dayu_theme.default_size
        map_label = {
            dayu_theme.large: (MLabel.H2Level, 20),
            dayu_theme.medium: (MLabel.H3Level, 15),
            dayu_theme.small: (MLabel.H4Level, 10),
        }
        self._title_label = MLabel(text=title)
        self._title_label.set_dayu_level(map_label.get(size)[0])

        padding = map_label.get(size)[-1]
        self._title_layout = QHBoxLayout()
        self._title_layout.setContentsMargins(padding, padding, padding,
                                              padding)
        if image:
            self._title_icon = MAvatar()
            self._title_icon.set_dayu_image(image)
            self._title_icon.set_dayu_size(size)
            self._title_layout.addWidget(self._title_icon)
        self._title_layout.addWidget(self._title_label)
        self._title_layout.addStretch()
        if extra:
            self._extra_button = MToolButton().icon_only().svg('more.svg')
            self._title_layout.addWidget(self._extra_button)

        self._content_layout = QVBoxLayout()

        self._main_lay = QVBoxLayout()
        self._main_lay.setSpacing(0)
        self._main_lay.setContentsMargins(1, 1, 1, 1)
        if title:
            self._main_lay.addLayout(self._title_layout)
            self._main_lay.addWidget(MDivider())
        self._main_lay.addLayout(self._content_layout)
        self.setLayout(self._main_lay)
コード例 #9
0
    def _init_ui(self):
        item_list = [
            {
                'text': 'Overview',
                'svg': 'home_line.svg',
                'clicked': functools.partial(MMessage.info, u'首页', parent=self)
            },
            {
                'text': u'我的',
                'svg': 'user_line.svg',
                'clicked': functools.partial(MMessage.info,
                                             u'编辑账户',
                                             parent=self)
            },
            {
                'text': u'Notice',
                'svg': 'alert_line.svg',
                'clicked': functools.partial(MMessage.info,
                                             u'查看通知',
                                             parent=self)
            },
        ]
        tool_bar = MMenuTabWidget()
        tool_bar.tool_bar_insert_widget(
            MLabel('DaYu').h4().secondary().strong())
        tool_bar.tool_bar_append_widget(
            MBadge.dot(
                show=True,
                widget=MToolButton().icon_only().svg('user_fill.svg').large()))
        self.content_widget = MLabel()
        for index, data_dict in enumerate(item_list):
            tool_bar.add_menu(data_dict, index)
        tool_bar.tool_button_group.set_dayu_checked(0)

        main_lay = QVBoxLayout()
        main_lay.setContentsMargins(0, 0, 0, 0)
        main_lay.addWidget(tool_bar)
        main_lay.addWidget(self.content_widget)

        self.setLayout(main_lay)
コード例 #10
0
ファイル: line_edit.py プロジェクト: muyr/dayu_widgets3
    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
コード例 #11
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()
コード例 #12
0
class MMessage(QWidget):
    """
    Display global messages as feedback in response to user operations.
    """
    InfoType = 'info'
    SuccessType = 'success'
    WarningType = 'warning'
    ErrorType = 'error'
    LoadingType = 'loading'

    default_config = {'duration': 2, 'top': 24}

    sig_closed = Signal()

    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()

    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):
        parent_geo = parent.geometry()
        pos = parent_geo.topLeft(
        ) if parent.parent() is None else parent.mapToGlobal(
            parent_geo.topLeft())
        offset = 0
        for child in parent.children():
            if isinstance(child, MMessage) and child.isVisible():
                offset = max(offset, child.y())
        base = pos.y() + MMessage.default_config.get('top')
        target_x = pos.x() + parent_geo.width() / 2 - 100
        target_y = (offset + 50) if offset else base
        self._pos_ani.setStartValue(QPoint(target_x, target_y - 40))
        self._pos_ani.setEndValue(QPoint(target_x, target_y))

    @classmethod
    def info(cls, text, parent, duration=None, closable=None):
        """Show a normal message"""
        inst = cls(text,
                   dayu_type=MMessage.InfoType,
                   duration=duration,
                   closable=closable,
                   parent=parent)
        inst.show()
        return inst

    @classmethod
    def success(cls, text, parent, duration=None, closable=None):
        """Show a success message"""
        inst = cls(text,
                   dayu_type=MMessage.SuccessType,
                   duration=duration,
                   closable=closable,
                   parent=parent)

        inst.show()
        return inst

    @classmethod
    def warning(cls, text, parent, duration=None, closable=None):
        """Show a warning message"""
        inst = cls(text,
                   dayu_type=MMessage.WarningType,
                   duration=duration,
                   closable=closable,
                   parent=parent)
        inst.show()
        return inst

    @classmethod
    def error(cls, text, parent, duration=None, closable=None):
        """Show an error message"""
        inst = cls(text,
                   dayu_type=MMessage.ErrorType,
                   duration=duration,
                   closable=closable,
                   parent=parent)
        inst.show()
        return inst

    @classmethod
    def loading(cls, text, parent):
        """Show a message with loading animation"""
        inst = cls(text, dayu_type=MMessage.LoadingType, parent=parent)
        inst.show()
        return inst

    @classmethod
    def config(cls, duration=None, top=None):
        """
        Config the global MMessage duration and top setting.
        :param duration: int (unit is second)
        :param top: int (unit is px)
        :return: None
        """
        if duration is not None:
            cls.default_config['duration'] = duration
        if top is not None:
            cls.default_config['top'] = top
コード例 #13
0
    def _init_ui(self):
        size_lay = QHBoxLayout()
        line_edit_l = MLineEdit().large()
        line_edit_l.setPlaceholderText('large size')
        line_edit_m = MLineEdit().medium()
        line_edit_m.setPlaceholderText('default size')
        line_edit_s = MLineEdit().small()
        line_edit_s.setPlaceholderText('small size')
        size_lay.addWidget(line_edit_l)
        size_lay.addWidget(line_edit_m)
        size_lay.addWidget(line_edit_s)

        line_edit_tool_button = MLineEdit(text='MToolButton')
        line_edit_tool_button.set_prefix_widget(MToolButton().svg('user_line.svg').icon_only())

        line_edit_label = MLineEdit(text='MLabel')
        tool_button = MLabel(text='User').mark().secondary()
        tool_button.setAlignment(Qt.AlignCenter)
        tool_button.setFixedWidth(80)
        line_edit_label.set_prefix_widget(tool_button)

        line_edit_push_button = MLineEdit(text='MPushButton')
        push_button = MPushButton(text='Go').primary()
        push_button.setFixedWidth(40)
        line_edit_push_button.set_suffix_widget(push_button)

        search_engine_line_edit = MLineEdit().search_engine().large()
        search_engine_line_edit.returnPressed.connect(self.slot_search)

        line_edit_options = MLineEdit()
        combobox = MComboBox()
        option_menu = MMenu()
        option_menu.set_separator('|')
        option_menu.set_data([r'http://', r'https://'])
        combobox.set_menu(option_menu)
        combobox.set_value('http://')
        combobox.setFixedWidth(90)
        line_edit_options.set_prefix_widget(combobox)

        main_lay = QVBoxLayout()
        main_lay.addWidget(MDivider('different size'))
        main_lay.addLayout(size_lay)
        main_lay.addWidget(MDivider('custom prefix and suffix widget'))
        main_lay.addWidget(line_edit_tool_button)
        main_lay.addWidget(line_edit_label)
        main_lay.addWidget(line_edit_push_button)
        main_lay.addWidget(MDivider('preset'))

        main_lay.addWidget(MLabel('error'))
        main_lay.addWidget(MLineEdit(text='waring: file d:/ddd/ccc.jpg not exists.').error())
        main_lay.addWidget(MLabel('search'))
        main_lay.addWidget(MLineEdit().search().small())
        main_lay.addWidget(MLabel('search_engine'))
        main_lay.addWidget(search_engine_line_edit)
        main_lay.addWidget(MLabel('file'))
        main_lay.addWidget(MLineEdit().file().small())
        main_lay.addWidget(MLabel('folder'))
        main_lay.addWidget(MLineEdit().folder().small())
        main_lay.addWidget(MLabel('MLineEdit.options()'))
        main_lay.addWidget(line_edit_options)
        main_lay.addStretch()
        self.setLayout(main_lay)
コード例 #14
0
ファイル: drawer.py プロジェクト: muyr/dayu_widgets3
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)

    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())
            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())
            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())
            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())
            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):
        if self._is_first_close:
            self._is_first_close = False
            self._close_timer.start()
            self._fade_out()
            event.ignore()
        else:
            event.accept()
コード例 #15
0
ファイル: card.py プロジェクト: muyr/dayu_widgets3
class MMeta(QWidget):
    def __init__(self,
                 cover=None,
                 avatar=None,
                 title=None,
                 description=None,
                 extra=False,
                 parent=None):
        super(MMeta, self).__init__(parent)
        self.setAttribute(Qt.WA_StyledBackground)
        self._cover_label = QLabel()
        self._avatar = MAvatar()
        self._title_label = MLabel().h4()
        self._description_label = MLabel().secondary()
        self._description_label.setWordWrap(True)
        self._description_label.set_elide_mode(Qt.ElideRight)
        self._title_layout = QHBoxLayout()
        self._title_layout.addWidget(self._title_label)
        self._title_layout.addStretch()
        self._extra_button = MToolButton(
            parent=self).icon_only().svg('more.svg')
        self._title_layout.addWidget(self._extra_button)
        self._extra_button.setVisible(extra)

        content_lay = QFormLayout()
        content_lay.setContentsMargins(5, 5, 5, 5)
        content_lay.addRow(self._avatar, self._title_layout)
        content_lay.addRow(self._description_label)

        self._button_layout = QHBoxLayout()

        main_lay = QVBoxLayout()
        main_lay.setSpacing(0)
        main_lay.setContentsMargins(1, 1, 1, 1)
        main_lay.addWidget(self._cover_label)
        main_lay.addLayout(content_lay)
        main_lay.addLayout(self._button_layout)
        main_lay.addStretch()
        self.setLayout(main_lay)
        self._cover_label.setFixedSize(QSize(200, 200))
        # self.setFixedWidth(200)

    def get_more_button(self):
        return self._extra_button

    def setup_data(self, data_dict):
        if data_dict.get('title'):
            self._title_label.setText(data_dict.get('title'))
            self._title_label.setVisible(True)
        else:
            self._title_label.setVisible(False)

        if data_dict.get('description'):
            self._description_label.setText(data_dict.get('description'))
            self._description_label.setVisible(True)
        else:
            self._description_label.setVisible(False)

        if data_dict.get('avatar'):
            self._avatar.set_dayu_image(data_dict.get('avatar'))
            self._avatar.setVisible(True)
        else:
            self._avatar.setVisible(False)

        if data_dict.get('cover'):
            fixed_height = self._cover_label.width()
            self._cover_label.setPixmap(
                data_dict.get('cover').scaledToWidth(fixed_height,
                                                     Qt.SmoothTransformation))
            self._cover_label.setVisible(True)
        else:
            self._cover_label.setVisible(False)
コード例 #16
0
ファイル: page.py プロジェクト: muyr/dayu_widgets3
    def __init__(self, parent=None):
        super(MPage, self).__init__(parent)
        self.register_field('page_size_selected', 25)
        self.register_field('page_size_list', [{
            'label': '25 - Fastest',
            'value': 25
        }, {
            'label': '50 - Fast',
            'value': 50
        }, {
            'label': '75 - Medium',
            'value': 75
        }, {
            'label': '100 - Slow',
            'value': 100
        }])
        self.register_field('total', 0)
        self.register_field('current_page', 0)
        self.register_field(
            'total_page', lambda: utils.get_total_page(
                self.field('total'), self.field('page_size_selected')))
        self.register_field('total_page_text',
                            lambda: str(self.field('total_page')))
        self.register_field(
            'display_text', lambda: utils.get_page_display_string(
                self.field('current_page'), self.field('page_size_selected'),
                self.field('total')))
        self.register_field('can_pre', lambda: self.field('current_page') > 1)
        self.register_field(
            'can_next',
            lambda: self.field('current_page') < self.field('total_page'))
        page_setting_menu = MMenu(parent=self)

        self._display_label = MLabel()
        self._display_label.setAlignment(Qt.AlignCenter)
        self._change_page_size_button = MComboBox().small()
        self._change_page_size_button.setFixedWidth(110)
        self._change_page_size_button.set_menu(page_setting_menu)
        self._change_page_size_button.set_formatter(
            lambda x: u'{} per page'.format(x))
        self._change_page_size_button.sig_value_changed.connect(
            self._emit_page_changed)

        self._pre_button = MToolButton().icon_only().svg(
            'left_fill.svg').small()
        self._pre_button.clicked.connect(
            functools.partial(self._slot_change_current_page, -1))
        self._next_button = MToolButton().small().icon_only().svg(
            'right_fill.svg')
        self._next_button.clicked.connect(
            functools.partial(self._slot_change_current_page, 1))
        self._current_page_spin_box = MSpinBox()
        self._current_page_spin_box.setMinimum(1)
        self._current_page_spin_box.set_dayu_size(dayu_theme.small)
        self._current_page_spin_box.valueChanged.connect(
            self._emit_page_changed)
        self._total_page_label = MLabel()

        self.bind('page_size_list', page_setting_menu, 'data')
        self.bind('page_size_selected',
                  page_setting_menu,
                  'value',
                  signal='sig_value_changed')
        self.bind('page_size_selected',
                  self._change_page_size_button,
                  'value',
                  signal='sig_value_changed')
        self.bind('current_page',
                  self._current_page_spin_box,
                  'value',
                  signal='valueChanged')
        self.bind('total_page', self._current_page_spin_box, 'maximum')
        self.bind('total_page_text', self._total_page_label, 'dayu_text')
        self.bind('display_text', self._display_label, 'dayu_text')
        self.bind('can_pre', self._pre_button, 'enabled')
        self.bind('can_next', self._next_button, 'enabled')

        main_lay = QHBoxLayout()
        main_lay.setContentsMargins(0, 0, 0, 0)
        main_lay.setSpacing(2)
        main_lay.addStretch()
        main_lay.addWidget(self._display_label)
        main_lay.addStretch()
        main_lay.addWidget(MLabel('|').secondary())
        main_lay.addWidget(self._change_page_size_button)
        main_lay.addWidget(MLabel('|').secondary())
        main_lay.addWidget(self._pre_button)
        main_lay.addWidget(MLabel('Page'))
        main_lay.addWidget(self._current_page_spin_box)
        main_lay.addWidget(MLabel('/'))
        main_lay.addWidget(self._total_page_label)
        main_lay.addWidget(self._next_button)
        self.setLayout(main_lay)
コード例 #17
0
    def _init_ui(self):
        size_lay = QVBoxLayout()
        sub_lay1 = QHBoxLayout()
        sub_lay1.addWidget(MToolButton().svg('left_line.svg').icon_only())
        sub_lay1.addWidget(MToolButton().svg('right_line.svg').icon_only())
        sub_lay1.addWidget(MToolButton().svg('up_line.svg').icon_only())
        sub_lay1.addWidget(MToolButton().svg('down_line.svg').icon_only())
        sub_lay1.addStretch()
        size_lay.addLayout(sub_lay1)

        button2 = MToolButton().svg('detail_line.svg').icon_only()
        button2.setEnabled(False)
        button7 = MToolButton().svg('trash_line.svg').icon_only()
        button7.setCheckable(True)
        state_lay = QHBoxLayout()
        state_lay.addWidget(button2)
        state_lay.addWidget(button7)
        state_lay.addStretch()

        button_trash = MToolButton().svg('trash_line.svg').text_beside_icon()
        button_trash.setText('Delete')
        button_login = MToolButton().svg('user_line.svg').text_beside_icon()
        button_login.setText('Login')

        button_lay = QHBoxLayout()
        button_lay.addWidget(button_trash)
        button_lay.addWidget(button_login)

        sub_lay2 = QHBoxLayout()
        sub_lay2.addWidget(button2)
        sub_lay2.addWidget(button7)

        main_lay = QVBoxLayout()
        main_lay.addWidget(MDivider('different button_size'))
        main_lay.addLayout(size_lay)
        main_lay.addWidget(MDivider('disabled & checkable'))
        main_lay.addLayout(state_lay)
        main_lay.addWidget(MDivider('type=normal'))
        main_lay.addLayout(button_lay)
        main_lay.addStretch()
        self.setLayout(main_lay)
コード例 #18
0
ファイル: alert.py プロジェクト: muyr/dayu_widgets3
class MAlert(QWidget):
    """
    Alert component for feedback.

    Property:
        dayu_type: The feedback type with different color container.
        dayu_text: The feedback string showed in container.
    """
    InfoType = 'info'
    SuccessType = 'success'
    WarningType = 'warning'
    ErrorType = 'error'

    def __init__(self, text='', parent=None, flags=0):
        super(MAlert, self).__init__(parent, flags)
        self.setAttribute(Qt.WA_StyledBackground)
        self._icon_label = MAvatar()
        self._icon_label.set_dayu_size(dayu_theme.tiny)
        self._content_label = MLabel().secondary()
        self._close_button = MToolButton().svg(
            'close_line.svg').tiny().icon_only()
        self._close_button.clicked.connect(
            functools.partial(self.setVisible, False))

        self._main_lay = QHBoxLayout()
        self._main_lay.setContentsMargins(8, 8, 8, 8)
        self._main_lay.addWidget(self._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)

        self.set_show_icon(True)
        self.set_closeable(False)
        self._dayu_type = None
        self._dayu_text = None
        self.set_dayu_type(MAlert.InfoType)
        self.set_dayu_text(text)

    def set_closeable(self, closeable):
        """Display the close icon button or not."""
        self._close_button.setVisible(closeable)

    def set_show_icon(self, show_icon):
        """Display the information type icon or not."""
        self._icon_label.setVisible(show_icon)

    def _set_dayu_text(self):
        self._content_label.setText(self._dayu_text)
        self.setVisible(bool(self._dayu_text))

    def set_dayu_text(self, value):
        """Set the feedback content."""
        if isinstance(value, basestring):
            self._dayu_text = value
        else:
            raise TypeError("Input argument 'value' should be string type, "
                            "but get {}".format(type(value)))
        self._set_dayu_text()

    def _set_dayu_type(self):
        self._icon_label.set_dayu_image(
            MPixmap('{}_fill.svg'.format(self._dayu_type),
                    vars(dayu_theme).get(self._dayu_type + '_color')))
        self.style().polish(self)

    def set_dayu_type(self, value):
        """Set feedback type."""
        if value in [
                MAlert.InfoType, MAlert.SuccessType, MAlert.WarningType,
                MAlert.ErrorType
        ]:
            self._dayu_type = value
        else:
            raise ValueError("Input argument 'value' should be one of "
                             "info/success/warning/error string.")
        self._set_dayu_type()

    def get_dayu_type(self):
        """
        Get MAlert feedback type.
        :return: str
        """
        return self._dayu_type

    def get_dayu_text(self):
        """
        Get MAlert feedback message.
        :return: basestring
        """
        return self._dayu_text

    dayu_text = Property(unicode, get_dayu_text, set_dayu_text)
    dayu_type = Property(str, get_dayu_type, set_dayu_type)

    def info(self):
        """Set MAlert to InfoType"""
        self.set_dayu_type(MAlert.InfoType)
        return self

    def success(self):
        """Set MAlert to SuccessType"""
        self.set_dayu_type(MAlert.SuccessType)
        return self

    def warning(self):
        """Set MAlert to  WarningType"""
        self.set_dayu_type(MAlert.WarningType)
        return self

    def error(self):
        """Set MAlert to ErrorType"""
        self.set_dayu_type(MAlert.ErrorType)
        return self

    def closable(self):
        """Set MAlert closebale is True"""
        self.set_closeable(True)
        return self
コード例 #19
0
    def __init__(self, table_view=True, big_view=False, parent=None):
        super(MItemViewFullSet, self).__init__(parent)
        self.sort_filter_model = MSortFilterModel()
        self.source_model = MTableModel()
        self.sort_filter_model.setSourceModel(self.source_model)

        self.stack_widget = QStackedWidget()

        self.view_button_grp = MToolButtonGroup(exclusive=True)
        data_group = []
        if table_view:
            self.table_view = MTableView(show_row_count=True)
            self.table_view.doubleClicked.connect(self.sig_double_clicked)
            self.table_view.pressed.connect(self.slot_left_clicked)
            self.table_view.setModel(self.sort_filter_model)
            self.stack_widget.addWidget(self.table_view)
            data_group.append({
                'svg': 'table_view.svg',
                'checkable': True,
                'tooltip': u'Table View'
            })
        if big_view:
            self.big_view = MBigView()
            self.big_view.doubleClicked.connect(self.sig_double_clicked)
            self.big_view.pressed.connect(self.slot_left_clicked)
            self.big_view.setModel(self.sort_filter_model)
            self.stack_widget.addWidget(self.big_view)
            data_group.append({
                'svg': 'big_view.svg',
                'checkable': True,
                'tooltip': u'Big View'
            })

        # 设置多个view 共享 MItemSelectionModel
        leader_view = self.stack_widget.widget(0)
        self.selection_model = leader_view.selectionModel()
        for index in range(self.stack_widget.count()):
            if index == 0:
                continue
            other_view = self.stack_widget.widget(index)
            other_view.setSelectionModel(self.selection_model)

        self.selection_model.currentChanged.connect(self.sig_current_changed)
        self.selection_model.currentRowChanged.connect(
            self.sig_current_row_changed)
        self.selection_model.currentColumnChanged.connect(
            self.sig_current_column_changed)
        self.selection_model.selectionChanged.connect(
            self.sig_selection_changed)

        self.tool_bar = QWidget()
        self.top_lay = QHBoxLayout()
        self.top_lay.setContentsMargins(0, 0, 0, 0)
        if data_group and len(data_group) > 1:
            self.view_button_grp.sig_checked_changed.connect(
                self.stack_widget.setCurrentIndex)
            self.view_button_grp.set_button_list(data_group)
            self.view_button_grp.set_dayu_checked(0)
            self.top_lay.addWidget(self.view_button_grp)
        self.search_line_edit = MLineEdit().search().small()
        self.search_attr_button = MToolButton().icon_only().svg(
            'down_fill.svg').small()
        self.search_line_edit.set_prefix_widget(self.search_attr_button)
        self.search_line_edit.textChanged.connect(
            self.sort_filter_model.set_search_pattern)
        self.search_line_edit.setVisible(False)

        self.top_lay.addStretch()
        self.top_lay.addWidget(self.search_line_edit)
        self.tool_bar.setLayout(self.top_lay)

        self.page_set = MPage()
        self.main_lay = QVBoxLayout()
        self.main_lay.setSpacing(5)
        self.main_lay.setContentsMargins(0, 0, 0, 0)
        self.main_lay.addWidget(self.tool_bar)
        self.main_lay.addWidget(self.stack_widget)
        self.main_lay.addWidget(self.page_set)
        self.setLayout(self.main_lay)
コード例 #20
0
    def add_item(self, data_dict, index=None):
        """Add a item"""
        button = MToolButton()
        button.setText(data_dict.get('text'))
        if data_dict.get('svg'):
            button.svg(data_dict.get('svg'))
        if data_dict.get('tooltip'):
            button.setProperty('toolTip', data_dict.get('tooltip'))
        if data_dict.get('clicked'):
            button.clicked.connect(data_dict.get('clicked'))
        if data_dict.get('text'):
            if data_dict.get('svg') or data_dict.get('icon'):
                button.text_beside_icon()
            else:
                button.text_only()
        else:
            button.icon_only()

        if self._button_group.buttons():
            separator = MLabel(self._separator).secondary()
            self._label_list.append(separator)
            self._main_layout.insertWidget(self._main_layout.count() - 1,
                                           separator)
        self._main_layout.insertWidget(self._main_layout.count() - 1, button)

        if index is None:
            self._button_group.addButton(button)
        else:
            self._button_group.addButton(button, index)
コード例 #21
0
class MSectionItem(QWidget):
    sig_context_menu = Signal(object)

    def __init__(self,
                 title='',
                 expand=False,
                 widget=None,
                 closeable=False,
                 parent=None):
        super(MSectionItem, self).__init__(parent)
        self._central_widget = None
        self.setAttribute(Qt.WA_StyledBackground)
        self.title_label = MLabel(parent=self)
        self.expand_icon = MLabel(parent=self)
        self.expand_icon.setSizePolicy(QSizePolicy.Minimum,
                                       QSizePolicy.Minimum)
        self._close_button = MToolButton().icon_only().tiny().svg(
            'close_line.svg')
        self._close_button.clicked.connect(self.close)

        header_lay = QHBoxLayout()
        header_lay.addWidget(self.expand_icon)
        header_lay.addWidget(self.title_label)
        header_lay.addStretch()
        header_lay.addWidget(self._close_button)
        self.header_widget = QWidget(parent=self)
        self.header_widget.setAttribute(Qt.WA_StyledBackground)
        self.header_widget.setObjectName('title')
        self.header_widget.setLayout(header_lay)
        self.header_widget.setSizePolicy(QSizePolicy.Minimum,
                                         QSizePolicy.Minimum)
        self.header_widget.setCursor(Qt.PointingHandCursor)
        self.title_label.setCursor(Qt.PointingHandCursor)
        self.header_widget.installEventFilter(self)
        self.title_label.installEventFilter(self)

        self.content_widget = QWidget(parent=self)
        self.content_layout = QHBoxLayout()
        self.content_widget.setLayout(self.content_layout)

        self.main_lay = QVBoxLayout()
        self.main_lay.setContentsMargins(0, 0, 0, 0)
        self.main_lay.setSpacing(0)
        self.main_lay.addWidget(self.header_widget)
        self.main_lay.addWidget(self.content_widget)
        self.setLayout(self.main_lay)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.setMouseTracking(True)
        self.set_title(title)
        self.set_closeable(closeable)
        if widget:
            self.set_content(widget)
        self.set_expand(expand)

    def set_content(self, widget):
        if self._central_widget:
            self.content_layout.removeWidget(self._central_widget)
            self._central_widget.close()
        self.content_layout.addWidget(widget)
        self._central_widget = widget

    def get_content(self):
        return self._central_widget

    def set_closeable(self, value):
        self.setProperty('closeable', value)

    def _set_closeable(self, value):
        self.content_widget.setVisible(value)
        self._close_button.setVisible(value)

    def set_expand(self, value):
        self.setProperty('expand', value)

    def _set_expand(self, value):
        self.content_widget.setVisible(value)
        self.expand_icon.setPixmap(
            MPixmap('down_line.svg' if value else 'right_line.svg').
            scaledToHeight(12))

    def set_title(self, value):
        self.setProperty('title', value)

    def _set_title(self, value):
        self.title_label.setText(value)

    def eventFilter(self, widget, event):
        if widget in [self.header_widget, self.title_label]:
            if event.type() == QEvent.MouseButtonRelease:
                self.set_expand(not self.property('expand'))
        return super(QWidget, self).eventFilter(widget, event)