def test_mavatar_init(qtbot, size, result, image): """Test for MAvatar init with different args""" widget = MAvatar() if image: widget.set_dayu_image(MPixmap(image)) if size: widget.set_dayu_size(size) qtbot.addWidget(widget) assert widget.height() == result assert widget.width() == result assert widget.get_dayu_size() == result pix = widget.pixmap() assert pix is not None assert not pix.isNull() assert pix.width() == result assert pix.width() == result orig = MPixmap('sphere.svg') widget.set_dayu_image(orig) pix = widget.pixmap() assert pix is not None assert not pix.isNull() assert pix.width() == result assert pix.width() == result assert orig is widget.get_dayu_image()
def __init__(self, size=None, color=None, parent=None): super(MLoading, self).__init__(parent) size = size or dayu_theme.default_size self.setFixedSize(QSize(size, size)) self.pix = MPixmap('loading.svg', color or dayu_theme.primary_color) \ .scaledToWidth(size, Qt.SmoothTransformation) self._rotation = 0 self._loading_ani = QPropertyAnimation() self._loading_ani.setTargetObject(self) # self.loading_ani.setEasingCurve(QEasingCurve.InOutQuad) self._loading_ani.setDuration(1000) self._loading_ani.setPropertyName('rotation') self._loading_ani.setStartValue(0) self._loading_ani.setEndValue(360) self._loading_ani.setLoopCount(-1) self._loading_ani.start()
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('windowOpacity') self._opacity_ani.setStartValue(0.0) self._opacity_ani.setEndValue(0.9) self._get_center_position(parent) self._fade_int()
def paint(self, painter, option, index): painter.save() icon_color = dayu_theme.icon_color if option.state & QStyle.State_MouseOver: painter.fillRect(option.rect, dayu_theme.primary_5) icon_color = '#fff' if option.state & QStyle.State_Selected: painter.fillRect(option.rect, dayu_theme.primary_6) icon_color = '#fff' painter.setRenderHint(QPainter.Antialiasing) painter.setPen(Qt.NoPen) painter.setBrush(QBrush(Qt.white)) pix = MPixmap('down_fill.svg', icon_color) h = option.rect.height() pix = pix.scaledToWidth(h * 0.5, Qt.SmoothTransformation) painter.drawPixmap(option.rect.x() + option.rect.width() - h, option.rect.y() + h / 4, pix) painter.restore() super(MOptionDelegate, self).paint(painter, option, index)
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)
def __init__(self, parent=None): super(AvatarExample, self).__init__(parent) self.setWindowTitle('Example for MAvatar') main_lay = QVBoxLayout() main_lay.addWidget(MDivider('different size')) size_list = [('Huge', MAvatar.huge), ('Large', MAvatar.large), ('Medium', MAvatar.medium), ('Small', MAvatar.small), ('Tiny', MAvatar.tiny)] self.pix_map_list = [ None, MPixmap('avatar.png'), MPixmap('app-maya.png'), MPixmap('app-nuke.png'), MPixmap('app-houdini.png') ] form_lay = QFormLayout() form_lay.setLabelAlignment(Qt.AlignRight) for label, cls in size_list: h_lay = QHBoxLayout() for image in self.pix_map_list: avatar_tmp = cls(image) h_lay.addWidget(avatar_tmp) h_lay.addStretch() form_lay.addRow(MLabel(label), h_lay) main_lay.addLayout(form_lay) self.register_field('image', None) main_lay.addWidget(MDivider('different image')) avatar = MAvatar() self.bind('image', avatar, 'dayu_image') button = MPushButton(text='Change Avatar Image').primary() button.clicked.connect(self.slot_change_image) main_lay.addWidget(avatar) main_lay.addWidget(button) main_lay.addStretch() self.setLayout(main_lay)
def test_avatar_class_method(qtbot, cls, result, image): """Test for MAvatar class methods""" if image: widget = cls(MPixmap(image)) else: widget = cls() qtbot.addWidget(widget) assert widget.height() == result assert widget.width() == result pix = widget.pixmap() assert pix is not None assert not pix.isNull() assert pix.width() == result assert pix.width() == result
def draw_empty_content(view, text=None, pix_map=None): from dayu_widgets3 import dayu_theme pix_map = pix_map or MPixmap('empty.svg') text = text or view.tr('No Data') painter = QPainter(view) font_metrics = painter.fontMetrics() painter.setPen(QPen(dayu_theme.secondary_text_color)) content_height = pix_map.height() + font_metrics.height() padding = 10 proper_min_size = min(view.height() - padding * 2, view.width() - padding * 2, content_height) if proper_min_size < content_height: pix_map = pix_map.scaledToHeight( proper_min_size - font_metrics.height(), Qt.SmoothTransformation) content_height = proper_min_size painter.drawText( view.width() / 2 - font_metrics.width(text) / 2, view.height() / 2 + content_height / 2 - font_metrics.height() / 2, text) painter.drawPixmap(view.width() / 2 - pix_map.width() / 2, view.height() / 2 - content_height / 2, pix_map) painter.end()
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 _init_ui(self): basic_card_lay = MFlowLayout() basic_card_lay.setSpacing(20) for setting in [{ 'title': '', }, { 'title': 'Card Title', 'size': dayu_theme.small }, { 'title': 'Card Title', 'image': MPixmap('app-houdini.png') }, { 'title': 'Card Title', 'extra': 'More', 'image': MPixmap('app-houdini.png') }, { 'title': 'Card Title', 'extra': 'More', }]: card_0 = MCard(**setting) content_widget_0 = QWidget() content_lay_0 = QVBoxLayout() content_lay_0.setContentsMargins(15, 15, 15, 15) content_widget_0.setLayout(content_lay_0) for i in range(4): content_lay_0.addWidget(MLabel('Card Content {}'.format(i + 1))) card_0.set_widget(content_widget_0) basic_card_lay.addWidget(card_0) meta_card_lay = MFlowLayout() meta_card_lay.setSpacing(20) for setting in [ { 'title': u'Houdini', 'description': u'Side Effects Software的旗舰级产品,是创建高级视觉效果的有效工具', 'avatar': MPixmap('user_line.svg'), 'cover': MPixmap('app-houdini.png') }, { 'title': u'Autodesk Maya', 'description': u'3D 数字动画和视觉效果的世界领先软件应用程序', 'cover': MPixmap('app-maya.png') }, ]: meta_card = MMeta() meta_card.setup_data(setting) meta_card_lay.addWidget(meta_card) task_card_lay = QVBoxLayout() # task_card_lay.setSpacing(10) for setting in [ { 'title': u'Task A', 'description': u'demo pl_0010 Animation \n2019/04/01 - 2019/04/09', 'avatar': MPixmap('success_line.svg', dayu_theme.success_color), }, { 'title': u'Task B', 'description': u'#2 closed by xiao hua.', 'avatar': MPixmap('error_line.svg', dayu_theme.error_color) }, { 'title': u'Task C', 'description': u'#3 closed by xiao hua.', 'avatar': MPixmap('warning_line.svg', dayu_theme.warning_color) } ] * 5: meta_card = MMeta(extra=True) meta_card.setup_data(setting) task_card_lay.addWidget(meta_card) left_lay = QVBoxLayout() left_lay.addWidget(MDivider('Basic')) left_lay.addLayout(basic_card_lay) left_lay.addWidget(MDivider('Meta E-Commerce Example')) left_lay.addLayout(meta_card_lay) left_lay.addStretch() left_widget = QWidget() left_widget.setLayout(left_lay) right_lay = QVBoxLayout() right_lay.addWidget(MDivider('Meta Task Item Example')) scroll = QScrollArea() scroll.setWidgetResizable(True) task_widget = QWidget() task_widget.setLayout(task_card_lay) scroll.setWidget(task_widget) right_lay.addWidget(scroll) right_widget = QWidget() right_widget.setLayout(right_lay) splitter = QSplitter() splitter.addWidget(left_widget) splitter.addWidget(right_widget) splitter.setStretchFactor(0, 80) splitter.setStretchFactor(1, 20) main_lay = QVBoxLayout() main_lay.addWidget(splitter) self.setLayout(main_lay)
def __init__(self, parent=None, flags=0): super(MAvatar, self).__init__(parent, flags) self._default_pix = MPixmap('user_fill.svg') self._pixmap = self._default_pix self._dayu_size = 0 self.set_dayu_size(dayu_theme.default_size)
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)
class MLoading(QWidget): """ Show a loading animation image. """ def __init__(self, size=None, color=None, parent=None): super(MLoading, self).__init__(parent) size = size or dayu_theme.default_size self.setFixedSize(QSize(size, size)) self.pix = MPixmap('loading.svg', color or dayu_theme.primary_color) \ .scaledToWidth(size, Qt.SmoothTransformation) self._rotation = 0 self._loading_ani = QPropertyAnimation() self._loading_ani.setTargetObject(self) # self.loading_ani.setEasingCurve(QEasingCurve.InOutQuad) self._loading_ani.setDuration(1000) self._loading_ani.setPropertyName('rotation') self._loading_ani.setStartValue(0) self._loading_ani.setEndValue(360) self._loading_ani.setLoopCount(-1) self._loading_ani.start() def _set_rotation(self, value): self._rotation = value self.update() def _get_rotation(self): return self._rotation rotation = Property(int, _get_rotation, _set_rotation) def paintEvent(self, event): """override the paint event to paint the 1/4 circle image.""" painter = QPainter(self) painter.setRenderHint(QPainter.SmoothPixmapTransform) painter.translate(self.pix.width() / 2, self.pix.height() / 2) painter.rotate(self._rotation) painter.drawPixmap(-self.pix.width() / 2, -self.pix.height() / 2, self.pix.width(), self.pix.height(), self.pix) painter.end() return super(MLoading, self).paintEvent(event) @classmethod def huge(cls, color=None): """Create a MLoading with huge size""" return cls(dayu_theme.huge, color) @classmethod def large(cls, color=None): """Create a MLoading with large size""" return cls(dayu_theme.large, color) @classmethod def medium(cls, color=None): """Create a MLoading with medium size""" return cls(dayu_theme.medium, color) @classmethod def small(cls, color=None): """Create a MLoading with small size""" return cls(dayu_theme.small, color) @classmethod def tiny(cls, color=None): """Create a MLoading with tiny size""" return cls(dayu_theme.tiny, color)