Exemple #1
0
class MPushButtonGroup(MButtonGroupBase):
    def __init__(self, orientation=Qt.Horizontal, parent=None):
        super(MPushButtonGroup, self).__init__(orientation=orientation, parent=parent)
        self.set_spacing(1)
        self._dayu_type = MPushButton.PrimaryType
        self._dayu_size = dayu_theme.default_size
        self._button_group.setExclusive(False)

    def create_button(self, data_dict):
        button = MPushButton()
        button.set_dayu_size(data_dict.get('dayu_size', self._dayu_size))
        button.set_dayu_type(data_dict.get('dayu_type', self._dayu_type))
        return button

    def get_dayu_size(self):
        return self._dayu_size

    def get_dayu_type(self):
        return self._dayu_type

    def set_dayu_size(self, value):
        self._dayu_size = value

    def set_dayu_type(self, value):
        self._dayu_type = value

    dayu_size = Property(int, get_dayu_size, set_dayu_size)
    dayu_type = Property(str, get_dayu_type, set_dayu_type)
Exemple #2
0
class MClickBrowserFolderToolButton(MToolButton):
    """A Clickable tool button to browser folders"""
    sig_folder_changed = Signal(str)
    sig_folders_changed = Signal(list)
    slot_browser_folder = _slot_browser_folder

    def __init__(self, multiple=False, parent=None):
        super(MClickBrowserFolderToolButton, self).__init__(parent=parent)

        self.set_dayu_svg('folder_line.svg')
        self.icon_only()
        self.clicked.connect(self.slot_browser_folder)
        self.setToolTip(self.tr('Click to browser folder'))

        self._path = None
        self._multiple = multiple

    def get_dayu_path(self):
        """
        Get last browser file path
        :return: str
        """
        return self._path

    def set_dayu_path(self, value):
        """
        Set browser file start path
        :param value: str
        :return: None
        """
        self._path = value

    def get_dayu_multiple(self):
        """
        Get browser can select multiple file or not
        :return: bool
        """
        return self._multiple

    def set_dayu_multiple(self, value):
        """
        Set browser can select multiple file or not
        :param value: bool
        :return: None
        """
        self._multiple = value

    dayu_multiple = Property(bool, get_dayu_multiple, set_dayu_multiple)
    dayu_path = Property(basestring, get_dayu_path, set_dayu_path)
Exemple #3
0
class MClickSaveFileToolButton(MToolButton):
    """A Clickable tool button to browser files"""
    sig_file_changed = Signal(str)
    slot_browser_file = _slot_save_file

    def __init__(self, multiple=False, parent=None):
        super(MClickSaveFileToolButton, self).__init__(parent=parent)
        self.set_dayu_svg('save_line.svg')
        self.icon_only()
        self.clicked.connect(self.slot_browser_file)
        self.setToolTip(self.tr('Click to save file'))

        self._path = None
        self._multiple = multiple
        self._filters = []

    def get_dayu_filters(self):
        """
        Get browser's format filters
        :return: list
        """
        return self._filters

    def set_dayu_filters(self, value):
        """
        Set browser file format filters
        :param value:
        :return: None
        """
        self._filters = value

    def get_dayu_path(self):
        """
        Get last browser file path
        :return: str
        """
        return self._path

    def set_dayu_path(self, value):
        """
        Set browser file start path
        :param value: str
        :return: None
        """
        self._path = value

    dayu_path = Property(basestring, get_dayu_path, set_dayu_path)
    dayu_filters = Property(list, get_dayu_filters, set_dayu_filters)
class MUnderlineButtonGroup(MButtonGroupBase):
    """MUnderlineButtonGroup"""
    sig_checked_changed = Signal(int)

    def __init__(self, parent=None):
        super(MUnderlineButtonGroup, self).__init__(parent=parent)
        self.set_spacing(1)
        self._button_group.setExclusive(True)
        self._button_group.buttonClicked[int].connect(self.sig_checked_changed)

    def create_button(self, data_dict):
        button = MUnderlineButton(parent=self)
        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

    def set_dayu_checked(self, value):
        """Set current checked button's id"""
        button = self._button_group.button(value)
        button.setChecked(True)
        self.sig_checked_changed.emit(value)

    def get_dayu_checked(self):
        """Get current checked button's id"""
        return self._button_group.checkedId()

    dayu_checked = Property(int, get_dayu_checked, set_dayu_checked, notify=sig_checked_changed)
Exemple #5
0
class MRadioButtonGroup(MButtonGroupBase):
    """
    Property:
        dayu_checked
    """
    sig_checked_changed = Signal(int)

    def __init__(self, orientation=Qt.Horizontal, parent=None):
        super(MRadioButtonGroup, self).__init__(orientation=orientation, parent=parent)
        self.set_spacing(15)
        self._button_group.setExclusive(True)
        self._button_group.buttonClicked[int].connect(self.sig_checked_changed)

    def create_button(self, data_dict):
        return MRadioButton()

    def set_dayu_checked(self, value):
        if value == self.get_dayu_checked():
            return
        button = self._button_group.button(value)
        if button:
            button.setChecked(True)
            self.sig_checked_changed.emit(value)
        else:
            print 'error'

    def get_dayu_checked(self):
        return self._button_group.checkedId()

    dayu_checked = Property(int, get_dayu_checked, set_dayu_checked, notify=sig_checked_changed)
Exemple #6
0
class MLoadingWrapper(QWidget):
    """
    A wrapper widget to show the loading widget or hide.
    Property:
        dayu_loading: bool. current loading state.
    """
    def __init__(self, widget, loading=True, parent=None):
        super(MLoadingWrapper, self).__init__(parent)
        self._widget = widget
        self._mask_widget = QFrame()
        self._mask_widget.setObjectName('mask')
        self._mask_widget.setSizePolicy(QSizePolicy.Expanding,
                                        QSizePolicy.Expanding)
        self._loading_widget = MLoading()
        self._loading_widget.setSizePolicy(QSizePolicy.Expanding,
                                           QSizePolicy.Expanding)

        self._main_lay = QGridLayout()
        self._main_lay.setContentsMargins(0, 0, 0, 0)
        self._main_lay.addWidget(widget, 0, 0)
        self._main_lay.addWidget(self._mask_widget, 0, 0)
        self._main_lay.addWidget(self._loading_widget, 0, 0, Qt.AlignCenter)
        self.setLayout(self._main_lay)
        self._loading = None
        self.set_dayu_loading(loading)

    def _set_loading(self):
        self._loading_widget.setVisible(self._loading)
        self._mask_widget.setVisible(self._loading)

    def set_dayu_loading(self, loading):
        """
        Set current state to loading or not
        :param loading: bool
        :return: None
        """
        self._loading = loading
        self._set_loading()

    def get_dayu_loading(self):
        """
        Get current loading widget is loading or not.
        :return: bool
        """
        return self._loading

    dayu_loading = Property(bool, get_dayu_loading, set_dayu_loading)
Exemple #7
0
class MProgressBar(QProgressBar):
    '''
    props:
        status: str

    '''
    ErrorStatus = 'error'
    NormalStatus = 'primary'
    SuccessStatus = 'success'

    def __init__(self, parent=None):
        super(MProgressBar, self).__init__(parent=parent)
        self.setAlignment(Qt.AlignCenter)
        self._status = MProgressBar.NormalStatus

    def auto_color(self):
        self.valueChanged.connect(self._update_color)
        return self

    @Slot(int)
    def _update_color(self, value):
        if value >= self.maximum():
            self.set_dayu_status(MProgressBar.SuccessStatus)
        else:
            self.set_dayu_status(MProgressBar.NormalStatus)

    def get_dayu_status(self):
        return self._status

    def set_dayu_status(self, value):
        self._status = value
        self.style().polish(self)

    dayu_status = Property(str, get_dayu_status, set_dayu_status)

    def normal(self):
        self.set_dayu_status(MProgressBar.NormalStatus)
        return self

    def error(self):
        self.set_dayu_status(MProgressBar.ErrorStatus)
        return self

    def success(self):
        self.set_dayu_status(MProgressBar.SuccessStatus)
        return self
Exemple #8
0
class MToolButtonGroup(MButtonGroupBase):
    sig_checked_changed = Signal(int)

    def __init__(self, size=None, type=None, exclusive=False, orientation=Qt.Horizontal,
                 parent=None):
        super(MToolButtonGroup, self).__init__(orientation=orientation, parent=parent)
        self.set_spacing(1)
        self._button_group.setExclusive(exclusive)
        self._size = size
        self._type = type
        self._button_group.buttonClicked[int].connect(self.sig_checked_changed)

    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

    def set_dayu_checked(self, value):
        if value == self.get_dayu_checked():
            return
        button = self._button_group.button(value)
        if button:
            button.setChecked(True)
            self.sig_checked_changed.emit(value)
        else:
            print 'error'

    def get_dayu_checked(self):
        return self._button_group.checkedId()

    dayu_checked = Property(int, get_dayu_checked, set_dayu_checked, notify=sig_checked_changed)
Exemple #9
0
class MDragFileButton(MToolButton):
    """A Clickable and draggable tool button to upload files"""
    sig_file_changed = Signal(str)
    sig_files_changed = Signal(list)
    slot_browser_file = _slot_browser_file

    def __init__(self, text='', multiple=False, parent=None):
        super(MDragFileButton, self).__init__(parent=parent)
        self.setAcceptDrops(True)
        self.setMouseTracking(True)
        self.text_under_icon()
        self.setText(text)

        self.set_dayu_size(60)
        self.set_dayu_svg('cloud_line.svg')
        self.setIconSize(QSize(60, 60))

        self.clicked.connect(self.slot_browser_file)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.setToolTip(self.tr('Click to browser file'))

        self._path = None
        self._multiple = multiple
        self._filters = []

    def get_dayu_filters(self):
        """
        Get browser's format filters
        :return: list
        """
        return self._filters

    def set_dayu_filters(self, value):
        """
        Set browser file format filters
        :param value:
        :return: None
        """
        self._filters = value

    def get_dayu_path(self):
        """
        Get last browser file path
        :return: str
        """
        return self._path

    def set_dayu_path(self, value):
        """
        Set browser file start path
        :param value: str
        :return: None
        """
        self._path = value

    def get_dayu_multiple(self):
        """
        Get browser can select multiple file or not
        :return: bool
        """
        return self._multiple

    def set_dayu_multiple(self, value):
        """
        Set browser can select multiple file or not
        :param value: bool
        :return: None
        """
        self._multiple = value

    dayu_multiple = Property(bool, get_dayu_multiple, set_dayu_multiple)
    dayu_path = Property(basestring, get_dayu_path, set_dayu_path)
    dayu_filters = Property(list, get_dayu_filters, set_dayu_filters)

    def dragEnterEvent(self, event):
        """Override dragEnterEvent. Validate dragged files"""
        if event.mimeData().hasFormat("text/uri-list"):
            file_list = self._get_valid_file_list(event.mimeData().urls())
            count = len(file_list)
            if count == 1 or (count > 1 and self.get_dayu_multiple()):
                event.acceptProposedAction()
                return

    def dropEvent(self, event):
        """Override dropEvent to accept the dropped files"""
        file_list = self._get_valid_file_list(event.mimeData().urls())
        if self.get_dayu_multiple():
            self.sig_files_changed.emit(file_list)
            self.set_dayu_path(file_list)
        else:
            self.sig_file_changed.emit(file_list[0])
            self.set_dayu_path(file_list[0])

    def _get_valid_file_list(self, url_list):
        import subprocess
        import sys
        file_list = []
        for url in url_list:
            file_name = url.toLocalFile()
            if sys.platform == 'darwin':
                sub_process = subprocess.Popen(
                    'osascript -e \'get posix path of posix file \"file://{}\" -- kthxbai\''
                    .format(file_name),
                    stdout=subprocess.PIPE,
                    shell=True)
                # print sub_process.communicate()[0].strip()
                file_name = sub_process.communicate()[0].strip()
                sub_process.wait()

            if os.path.isfile(file_name):
                if self.get_dayu_filters():
                    if os.path.splitext(
                            file_name)[-1] in self.get_dayu_filters():
                        file_list.append(file_name)
                else:
                    file_list.append(file_name)

        return file_list
Exemple #10
0
class MClickBrowserFilePushButton(MPushButton):
    """A Clickable push button to browser files"""
    sig_file_changed = Signal(str)
    sig_files_changed = Signal(list)
    slot_browser_file = _slot_browser_file

    def __init__(self, text='Browser', multiple=False, parent=None):
        super(MClickBrowserFilePushButton, self).__init__(text=text,
                                                          parent=parent)
        self.setProperty('multiple', multiple)
        self.clicked.connect(self.slot_browser_file)
        self.setToolTip(self.tr('Click to browser file'))

        self._path = None
        self._multiple = multiple
        self._filters = []

    def get_dayu_filters(self):
        """
        Get browser's format filters
        :return: list
        """
        return self._filters

    def set_dayu_filters(self, value):
        """
        Set browser file format filters
        :param value:
        :return: None
        """
        self._filters = value

    def get_dayu_path(self):
        """
        Get last browser file path
        :return: str
        """
        return self._path

    def set_dayu_path(self, value):
        """
        Set browser file start path
        :param value: str
        :return: None
        """
        self._path = value

    def get_dayu_multiple(self):
        """
        Get browser can select multiple file or not
        :return: bool
        """
        return self._multiple

    def set_dayu_multiple(self, value):
        """
        Set browser can select multiple file or not
        :param value: bool
        :return: None
        """
        self._multiple = value

    dayu_multiple = Property(bool, get_dayu_multiple, set_dayu_multiple)
    dayu_path = Property(basestring, get_dayu_path, set_dayu_path)
    dayu_filters = Property(list, get_dayu_filters, set_dayu_filters)
Exemple #11
0
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)
Exemple #12
0
class MProgressCircle(QProgressBar):
    """
    MProgressCircle: Display the current progress of an operation flow.
    When you need to display the completion percentage of an operation.

    Property:
        dayu_width: int
        dayu_color: str
    """
    def __init__(self, dashboard=False, parent=None):
        super(MProgressCircle, self).__init__(parent)
        self._main_lay = QHBoxLayout()
        self._default_label = MLabel().h3()
        self._default_label.setAlignment(Qt.AlignCenter)
        self._main_lay.addWidget(self._default_label)
        self.setLayout(self._main_lay)
        self._color = None
        self._width = None

        self._start_angle = 90 * 16
        self._max_delta_angle = 360 * 16
        self._height_factor = 1.0
        self._width_factor = 1.0
        if dashboard:
            self._start_angle = 225 * 16
            self._max_delta_angle = 270 * 16
            self._height_factor = (2 + pow(2, 0.5)) / 4 + 0.03

        self.set_dayu_width(120)
        self.set_dayu_color(dayu_theme.primary_color)

    def set_widget(self, widget):
        """
        Set a custom widget to show on the circle's inner center
         and replace the default percent label
        :param widget: QWidget
        :return: None
        """
        self.setTextVisible(False)
        self._main_lay.addWidget(widget)

    def get_dayu_width(self):
        """
        Get current circle fixed width
        :return: int
        """
        return self._width

    def set_dayu_width(self, value):
        """
        Set current circle fixed width
        :param value: int
        :return: None
        """
        self._width = value
        self.setFixedSize(
            QSize(self._width * self._width_factor,
                  self._width * self._height_factor))

    def get_dayu_color(self):
        """
        Get current circle foreground color
        :return: str
        """
        return self._color

    def set_dayu_color(self, value):
        """
        Set current circle's foreground color
        :param value: str
        :return:
        """
        self._color = value
        self.update()

    dayu_color = Property(str, get_dayu_color, set_dayu_color)
    dayu_width = Property(int, get_dayu_width, set_dayu_width)

    def paintEvent(self, event):
        """Override QProgressBar's paintEvent."""
        if self.text() != self._default_label.text():
            self._default_label.setText(self.text())
        if self.isTextVisible() != self._default_label.isVisible():
            self._default_label.setVisible(self.isTextVisible())

        percent = utils.get_percent(self.value(), self.minimum(),
                                    self.maximum())
        total_width = self.get_dayu_width()
        pen_width = int(3 * total_width / 50.0)
        radius = total_width - pen_width - 1

        painter = QPainter(self)
        painter.setRenderHints(QPainter.Antialiasing)

        # draw background circle
        pen_background = QPen()
        pen_background.setWidth(pen_width)
        pen_background.setColor(dayu_theme.background_selected_color)
        pen_background.setCapStyle(Qt.RoundCap)
        painter.setPen(pen_background)
        painter.drawArc(pen_width / 2.0 + 1, pen_width / 2.0 + 1, radius,
                        radius, self._start_angle, -self._max_delta_angle)

        # draw foreground circle
        pen_foreground = QPen()
        pen_foreground.setWidth(pen_width)
        pen_foreground.setColor(self._color)
        pen_foreground.setCapStyle(Qt.RoundCap)
        painter.setPen(pen_foreground)
        painter.drawArc(pen_width / 2.0 + 1, pen_width / 2.0 + 1, radius,
                        radius, self._start_angle,
                        -percent * 0.01 * self._max_delta_angle)
        painter.end()

    @classmethod
    def dashboard(cls, parent=None):
        """Create a dashboard style MCircle"""
        return MProgressCircle(dashboard=True, parent=parent)
Exemple #13
0
class MDivider(QWidget):
    '''
    A divider line separates different content.

    Property:
        dayu_text: basestring
    '''
    _alignment_map = {
        Qt.AlignCenter: 50,
        Qt.AlignLeft: 20,
        Qt.AlignRight: 80,
    }

    def __init__(self,
                 text='',
                 orientation=Qt.Horizontal,
                 alignment=Qt.AlignCenter,
                 parent=None):
        super(MDivider, self).__init__(parent)
        self._orient = orientation
        self._text_label = MLabel().secondary()
        self._left_frame = QFrame()
        self._right_frame = QFrame()
        self._main_lay = QHBoxLayout()
        self._main_lay.setContentsMargins(0, 0, 0, 0)
        self._main_lay.setSpacing(0)
        self._main_lay.addWidget(self._left_frame)
        self._main_lay.addWidget(self._text_label)
        self._main_lay.addWidget(self._right_frame)
        self.setLayout(self._main_lay)

        if orientation == Qt.Horizontal:
            self._left_frame.setFrameShape(QFrame.HLine)
            self._left_frame.setFrameShadow(QFrame.Sunken)
            self._right_frame.setFrameShape(QFrame.HLine)
            self._right_frame.setFrameShadow(QFrame.Sunken)
        else:
            self._text_label.setVisible(False)
            self._right_frame.setVisible(False)
            self._left_frame.setFrameShape(QFrame.VLine)
            self._left_frame.setFrameShadow(QFrame.Plain)
            self.setFixedWidth(2)
        self._main_lay.setStretchFactor(self._left_frame,
                                        self._alignment_map.get(alignment, 50))
        self._main_lay.setStretchFactor(
            self._right_frame, 100 - self._alignment_map.get(alignment, 50))
        self._text = None
        self.set_dayu_text(text)

    def set_dayu_text(self, value):
        """
        Set the divider's text.
        When text is empty, hide the text_label and right_frame to ensure the divider not has a gap.

        :param value: basestring
        :return: None
        """
        self._text = value
        self._text_label.setText(value)
        if self._orient == Qt.Horizontal:
            self._text_label.setVisible(bool(value))
            self._right_frame.setVisible(bool(value))

    def get_dayu_text(self):
        """
        Get current text
        :return: basestring
        """
        return self._text

    dayu_text = Property(basestring, get_dayu_text, set_dayu_text)

    @classmethod
    def left(cls, text=''):
        """Create a horizontal divider with text at left."""
        return cls(text, alignment=Qt.AlignLeft)

    @classmethod
    def right(cls, text=''):
        """Create a horizontal divider with text at right."""
        return cls(text, alignment=Qt.AlignRight)

    @classmethod
    def center(cls, text=''):
        """Create a horizontal divider with text at center."""
        return cls(text, alignment=Qt.AlignCenter)

    @classmethod
    def vertical(cls):
        """Create a vertical divider"""
        return cls(orientation=Qt.Vertical)
Exemple #14
0
class MPushButton(QPushButton):
    """
    QPushButton.

    Property:
        dayu_size: The size of push button
        dayu_type: The type of push button.
    """
    DefaultType = 'default'
    PrimaryType = 'primary'
    SuccessType = 'success'
    WarningType = 'warning'
    DangerType = 'danger'

    def __init__(self, text='', icon=None, parent=None):
        if icon is None:
            super(MPushButton, self).__init__(text=text, parent=parent)
        else:
            super(MPushButton, self).__init__(icon=icon,
                                              text=text,
                                              parent=parent)
        self._dayu_type = MPushButton.DefaultType
        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
        self.style().polish(self)

    def get_dayu_type(self):
        """
        Get the push button type.
        :return: string.
        """
        return self._dayu_type

    def set_dayu_type(self, value):
        """
        Set the push button type.
        :return: None
        """
        if value in [
                MPushButton.DefaultType, MPushButton.PrimaryType,
                MPushButton.SuccessType, MPushButton.WarningType,
                MPushButton.DangerType
        ]:
            self._dayu_type = value
        else:
            raise ValueError("Input argument 'value' should be one of "
                             "default/primary/success/warning/danger string.")
        self.style().polish(self)

    dayu_type = Property(str, get_dayu_type, set_dayu_type)
    dayu_size = Property(int, get_dayu_size, set_dayu_size)

    def primary(self):
        """Set MPushButton to PrimaryType"""
        self.set_dayu_type(MPushButton.PrimaryType)
        return self

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

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

    def danger(self):
        """Set MPushButton to DangerType"""
        self.set_dayu_type(MPushButton.DangerType)
        return self

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

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

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

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

    def tiny(self):
        """Set MPushButton to tiny size"""
        self.set_dayu_size(dayu_theme.tiny)
        return self
Exemple #15
0
class MLabel(QLabel):
    """
    Display title in different level.
    Property:
        dayu_level: integer
        dayu_type: str
    """
    SecondaryType = 'secondary'
    WarningType = 'warning'
    DangerType = 'danger'
    H1Level = 1
    H2Level = 2
    H3Level = 3
    H4Level = 4

    def __init__(self, text='', parent=None, flags=0):
        super(MLabel, self).__init__(text, parent, flags)
        self.setTextInteractionFlags(Qt.TextBrowserInteraction
                                     | Qt.LinksAccessibleByMouse)
        self.setSizePolicy(QSizePolicy.Preferred, QSizePolicy.Minimum)
        self._actual_text = text
        self._dayu_type = ''
        self._dayu_underline = False
        self._dayu_mark = False
        self._dayu_delete = False
        self._dayu_strong = False
        self._dayu_code = False
        self._dayu_level = 0
        self._elide_mode = Qt.ElideNone
        self.setProperty('dayu_text', text)

    def get_dayu_level(self):
        """Get MLabel level."""
        return self._dayu_level

    def set_dayu_level(self, value):
        """Set MLabel level"""
        self._dayu_level = value
        self.style().polish(self)

    def set_dayu_underline(self, value):
        """Set MLabel underline style."""
        self._dayu_underline = value
        self.style().polish(self)

    def get_dayu_underline(self):
        return self._dayu_underline

    def set_dayu_delete(self, value):
        """Set MLabel a delete line style."""
        self._dayu_delete = value
        self.style().polish(self)

    def get_dayu_delete(self):
        return self._dayu_delete

    def set_dayu_strong(self, value):
        """Set MLabel bold style."""
        self._dayu_strong = value
        self.style().polish(self)

    def get_dayu_strong(self):
        return self._dayu_strong

    def set_dayu_mark(self, value):
        """Set MLabel mark style."""
        self._dayu_mark = value
        self.style().polish(self)

    def get_dayu_mark(self):
        return self._dayu_mark

    def set_dayu_code(self, value):
        """Set MLabel code style."""
        self._dayu_code = value
        self.style().polish(self)

    def get_dayu_code(self):
        return self._dayu_code

    def get_elide_mode(self):
        return self._elide_mode

    def set_elide_mode(self, value):
        """Set MLabel elide mode.
        Only accepted Qt.ElideLeft/Qt.ElideMiddle/Qt.ElideRight/Qt.ElideNone"""
        self._elide_mode = value
        self._update_elided_text()

    def get_dayu_type(self):
        return self._dayu_type

    def set_dayu_type(self, value):
        self._dayu_type = value
        self.style().polish(self)

    dayu_level = Property(int, get_dayu_level, set_dayu_level)
    dayu_type = Property(str, get_dayu_type, set_dayu_type)
    dayu_underline = Property(bool, get_dayu_underline, set_dayu_underline)
    dayu_delete = Property(bool, get_dayu_delete, set_dayu_delete)
    dayu_strong = Property(bool, get_dayu_strong, set_dayu_strong)
    dayu_mark = Property(bool, get_dayu_mark, set_dayu_mark)
    dayu_code = Property(bool, get_dayu_code, set_dayu_code)
    dayu_elide_mod = Property(Qt.TextElideMode, get_dayu_code, set_dayu_code)

    def minimumSizeHint(self):
        return QSize(1, self.fontMetrics().height())

    def text(self):
        """
        Overridden base method to return the original unmodified text

        :returns:   The original unmodified text
        """
        return self._actual_text

    def setText(self, text):
        """
        Overridden base method to set the text on the label

        :param text:    The text to set on the label
        """
        self._actual_text = text
        self._update_elided_text()
        self.setToolTip(text)

    def _update_elided_text(self):
        """
        Update the elided text on the label
        """
        _font_metrics = self.fontMetrics()
        _elided_text = _font_metrics.elidedText(self._actual_text,
                                                self._elide_mode,
                                                self.width() - 2 * 2)
        super(MLabel, self).setText(_elided_text)

    def resizeEvent(self, event):
        """
        Overridden base method called when the widget is resized.

        :param event:    The resize event
        """
        self._update_elided_text()

    def h1(self):
        """Set QLabel with h1 type."""
        self.set_dayu_level(MLabel.H1Level)
        return self

    def h2(self):
        """Set QLabel with h2 type."""
        self.set_dayu_level(MLabel.H2Level)
        return self

    def h3(self):
        """Set QLabel with h3 type."""
        self.set_dayu_level(MLabel.H3Level)
        return self

    def h4(self):
        """Set QLabel with h4 type."""
        self.set_dayu_level(MLabel.H4Level)
        return self

    def secondary(self):
        """Set QLabel with secondary type."""
        self.set_dayu_type(MLabel.SecondaryType)
        return self

    def warning(self):
        """Set QLabel with warning type."""
        self.set_dayu_type(MLabel.WarningType)
        return self

    def danger(self):
        """Set QLabel with danger type."""
        self.set_dayu_type(MLabel.DangerType)
        return self

    def strong(self):
        """Set QLabel with strong style."""
        self.set_dayu_strong(True)
        return self

    def mark(self):
        """Set QLabel with mark style."""
        self.set_dayu_mark(True)
        return self

    def code(self):
        """Set QLabel with code style."""
        self.set_dayu_code(True)
        return self

    def delete(self):
        """Set QLabel with delete style."""
        self.set_dayu_delete(True)
        return self

    def underline(self):
        """Set QLabel with underline style."""
        self.set_dayu_underline(True)
        return self

    def event(self, event):
        if event.type() == QEvent.DynamicPropertyChange and event.propertyName(
        ) == 'dayu_text':
            self.setText(self.property('dayu_text'))
        return super(MLabel, self).event(event)
Exemple #16
0
class MDragFolderButton(MToolButton):
    """A Clickable and draggable tool button to browser folders"""
    sig_folder_changed = Signal(str)
    sig_folders_changed = Signal(list)
    slot_browser_folder = _slot_browser_folder

    def __init__(self, multiple=False, parent=None):
        super(MDragFolderButton, self).__init__(parent=parent)
        self.setAcceptDrops(True)
        self.setMouseTracking(True)
        self.text_under_icon()
        self.set_dayu_svg('folder_line.svg')
        self.set_dayu_size(60)
        self.setIconSize(QSize(60, 60))
        self.setText(self.tr('Click or drag folder here'))
        self.clicked.connect(self.slot_browser_folder)
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        self.setToolTip(self.tr('Click to browser folder or drag folder here'))

        self._path = None
        self._multiple = multiple

    def get_dayu_path(self):
        """
        Get last browser file path
        :return: str
        """
        return self._path

    def set_dayu_path(self, value):
        """
        Set browser file start path
        :param value: str
        :return: None
        """
        self._path = value

    def get_dayu_multiple(self):
        """
        Get browser can select multiple file or not
        :return: bool
        """
        return self._multiple

    def set_dayu_multiple(self, value):
        """
        Set browser can select multiple file or not
        :param value: bool
        :return: None
        """
        self._multiple = value

    dayu_multiple = Property(bool, get_dayu_multiple, set_dayu_multiple)
    dayu_path = Property(bool, get_dayu_path, set_dayu_path)

    def dragEnterEvent(self, event):
        """Override dragEnterEvent. Validate dragged folders"""
        if event.mimeData().hasFormat("text/uri-list"):
            folder_list = [
                url.toLocalFile() for url in event.mimeData().urls()
                if os.path.isdir(url.toLocalFile())
            ]
            count = len(folder_list)
            if count == 1 or (count > 1 and self.get_dayu_multiple()):
                event.acceptProposedAction()
                return

    def dropEvent(self, event):
        """Override dropEvent to accept the dropped folders"""
        folder_list = [
            url.toLocalFile() for url in event.mimeData().urls()
            if os.path.isdir(url.toLocalFile())
        ]
        if self.get_dayu_multiple():
            self.sig_folders_changed.emit(folder_list)
        else:
            self.sig_folder_changed.emit(folder_list[0])
        self.set_dayu_path(folder_list[0])
Exemple #17
0
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
Exemple #18
0
class MComboBox(QComboBox):
    Separator = '/'
    sig_value_changed = Signal(list)

    def __init__(self, parent=None):
        super(MComboBox, self).__init__(parent)
        self._root_menu = None
        self._display_formatter = utils.display_formatter
        self.setEditable(True)
        line_edit = self.lineEdit()
        line_edit.setReadOnly(True)
        line_edit.setTextMargins(4, 0, 4, 0)
        line_edit.setStyleSheet('background-color:transparent')
        # line_edit.setCursor(Qt.PointingHandCursor)
        line_edit.installEventFilter(self)
        self._has_custom_view = False
        self.set_value('')
        self.set_placeholder(self.tr('Please Select'))
        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Minimum)
        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
        self.lineEdit().setProperty('dayu_size', value)
        self.style().polish(self)

    dayu_size = Property(int, get_dayu_size, set_dayu_size)

    def set_formatter(self, func):
        self._display_formatter = func

    def set_placeholder(self, text):
        """Display the text when no item selected."""
        self.lineEdit().setPlaceholderText(text)

    def set_value(self, value):
        self.setProperty('value', value)

    def _set_value(self, value):
        self.lineEdit().setProperty('text', self._display_formatter(value))
        if self._root_menu:
            self._root_menu.set_value(value)

    def set_menu(self, menu):
        self._root_menu = menu
        self._root_menu.sig_value_changed.connect(self.sig_value_changed)
        self._root_menu.sig_value_changed.connect(self.set_value)

    def setView(self, *args, **kwargs):
        """Override setView to flag _has_custom_view variable."""
        self._has_custom_view = True
        super(MComboBox, self).setView(*args, **kwargs)

    def showPopup(self):
        """Override default showPopup. When set custom menu, show the menu instead."""
        if self._has_custom_view or self._root_menu is None:
            super(MComboBox, self).showPopup()
        else:
            QComboBox.hidePopup(self)
            self._root_menu.popup(self.mapToGlobal(QPoint(0, self.height())))

    # def setCurrentIndex(self, index):
    #     raise NotImplementedError

    def eventFilter(self, widget, event):
        if widget is self.lineEdit():
            if event.type() == QEvent.MouseButtonPress:
                self.showPopup()
        return super(MComboBox, self).eventFilter(widget, event)

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

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

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

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

    def tiny(self):
        """Set MComboBox to tiny size"""
        self.set_dayu_size(dayu_theme.tiny)
        return self
Exemple #19
0
class MAvatar(QLabel):
    """
    Avatar component. It can be used to represent people or object.

    Property:
        image: avatar image, should be QPixmap.
        dayu_size: the size of image.
    """
    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_size(self, value):
        """
        Set the avatar size.
        :param value: integer
        :return: None
        """
        self._dayu_size = value
        self._set_dayu_size()

    def _set_dayu_size(self):
        self.setFixedSize(QSize(self._dayu_size, self._dayu_size))
        self._set_dayu_image()

    def _set_dayu_image(self):
        self.setPixmap(
            self._pixmap.scaledToWidth(self.height(), Qt.SmoothTransformation))

    def set_dayu_image(self, value):
        """
        Set avatar image.
        :param value: QPixmap or None.
        :return: None
        """
        if value is None:
            self._pixmap = self._default_pix
        elif isinstance(value, QPixmap):
            self._pixmap = value
        else:
            raise TypeError(
                "Input argument 'value' should be QPixmap or None, "
                "but get {}".format(type(value)))
        self._set_dayu_image()

    def get_dayu_image(self):
        """
        Get the avatar image.
        :return: QPixmap
        """
        return self._pixmap

    def get_dayu_size(self):
        """
        Get the avatar size
        :return: integer
        """
        return self._dayu_size

    dayu_image = Property(QPixmap, get_dayu_image, set_dayu_image)
    dayu_size = Property(int, get_dayu_size, set_dayu_size)

    @classmethod
    def huge(cls, image=None):
        """Create a MAvatar with huge size"""
        inst = cls()
        inst.set_dayu_size(dayu_theme.huge)
        inst.set_dayu_image(image)
        return inst

    @classmethod
    def large(cls, image=None):
        """Create a MAvatar with large size"""
        inst = cls()
        inst.set_dayu_size(dayu_theme.large)
        inst.set_dayu_image(image)
        return inst

    @classmethod
    def medium(cls, image=None):
        """Create a MAvatar with medium size"""
        inst = cls()
        inst.set_dayu_size(dayu_theme.medium)
        inst.set_dayu_image(image)
        return inst

    @classmethod
    def small(cls, image=None):
        """Create a MAvatar with small size"""
        inst = cls()
        inst.set_dayu_size(dayu_theme.small)
        inst.set_dayu_image(image)
        return inst

    @classmethod
    def tiny(cls, image=None):
        """Create a MAvatar with tiny size"""
        inst = cls()
        inst.set_dayu_size(dayu_theme.tiny)
        inst.set_dayu_image(image)
        return inst
Exemple #20
0
class MCheckBoxGroup(MButtonGroupBase):
    sig_checked_changed = Signal(list)

    def __init__(self, orientation=Qt.Horizontal, parent=None):
        super(MCheckBoxGroup, self).__init__(orientation=orientation, parent=parent)
        self.set_spacing(15)
        self._button_group.setExclusive(False)

        self.setContextMenuPolicy(Qt.CustomContextMenu)
        self.customContextMenuRequested.connect(self._slot_context_menu)

        self._button_group.buttonClicked[int].connect(self._slot_map_signal)
        self._dayu_checked = []

    def create_button(self, data_dict):
        return MCheckBox()

    @Slot(QPoint)
    def _slot_context_menu(self, point):
        context_menu = MMenu(parent=self)
        action_select_all = context_menu.addAction('Select All')
        action_select_none = context_menu.addAction('Select None')
        action_select_invert = context_menu.addAction('Select Invert')
        action_select_all.triggered.connect(functools.partial(self._slot_set_select, True))
        action_select_none.triggered.connect(functools.partial(self._slot_set_select, False))
        action_select_invert.triggered.connect(functools.partial(self._slot_set_select, None))
        context_menu.exec_(QCursor.pos() + QPoint(10, 10))

    @Slot(bool)
    def _slot_set_select(self, state):
        for check_box in self._button_group.buttons():
            if state is None:
                old_state = check_box.isChecked()
                check_box.setChecked(not old_state)
            else:
                check_box.setChecked(state)
        self._slot_map_signal()

    @Slot(int)
    def _slot_map_signal(self, state=None):
        self.sig_checked_changed.emit(
            [check_box.text() for check_box in self._button_group.buttons() if
             check_box.isChecked()])

    def set_dayu_checked(self, value):
        if not isinstance(value, list):
            value = [value]
        if value == self.get_dayu_checked():
            return

        self._dayu_checked = value
        for check_box in self._button_group.buttons():
            flag = Qt.Checked if check_box.text() in value else Qt.Unchecked
            if flag != check_box.checkState():
                check_box.setCheckState(flag)
        self.sig_checked_changed.emit(value)

    def get_dayu_checked(self):
        return [check_box.text() for check_box in self._button_group.buttons() if
                              check_box.isChecked()]

    # TODO: pyside 的 Property 不直接支持 list,需要寻求解决办法
    dayu_checked = Property(list, get_dayu_checked, set_dayu_checked, notify=sig_checked_changed)
Exemple #21
0
class MBadge(QWidget):
    """
    Badge normally appears in proximity to notifications or user avatars with eye-catching appeal,
    typically displaying unread messages count.
    Show something at the wrapped widget top right.
    There is 3 type styles:
        dot: show a dot
        count: show a number at
        text: show a string

    Property:
        dayu_dot: bool
        dayu_text: basestring
        dayu_count: int
        dayu_overflow: int
    """
    def __init__(self, widget=None, parent=None):
        super(MBadge, self).__init__(parent)
        self._widget = widget
        self._overflow_count = 99

        self._dot = None
        self._text = None
        self._count = None

        self._badge_button = QPushButton()
        self._badge_button.setSizePolicy(QSizePolicy.Minimum,
                                         QSizePolicy.Minimum)

        self._main_lay = QGridLayout()
        self._main_lay.setContentsMargins(0, 0, 0, 0)
        if widget is not None:
            self._main_lay.addWidget(widget, 0, 0)
        self._main_lay.addWidget(self._badge_button, 0, 0,
                                 Qt.AlignTop | Qt.AlignRight)
        self.setLayout(self._main_lay)

    def get_dayu_overflow(self):
        """
        Get current overflow number
        :return: int
        """
        return self._overflow_count

    def set_dayu_overflow(self, num):
        """
        Set the overflow number
        :param num: new max number
        :return: None
        """
        self._overflow_count = num
        self._update_number()

    def get_dayu_dot(self):
        """
        Get current style is dot or not and dot is show or not
        :return: bool
        """
        return self._dot

    def set_dayu_dot(self, show):
        """
        Set dot style and weather show the dot or not
        :param show: bool
        :return: None
        """
        self._dot = show
        self._badge_button.setText('')
        self._badge_button.setVisible(show)
        self.style().polish(self)

    def get_dayu_count(self):
        """
        Get actual count number
        :return: int
        """
        return self._count

    def set_dayu_count(self, num):
        """
        Set current style to show a number

        :param num: int
        :return: None
        """
        self._count = num
        self._update_number()

    def _update_number(self):
        self._badge_button.setText(
            utils.overflow_format(self._count, self._overflow_count))
        self._badge_button.setVisible(self._count > 0)
        self._dot = None
        self.style().polish(self)

    def get_dayu_text(self):
        """
        Get current showed text
        :return: basestring
        """
        return self._text

    def set_dayu_text(self, text):
        """
        Set current style to show a text.
        :param text: basestring
        :return: None
        """
        self._text = text
        self._badge_button.setText(self._text)
        self._badge_button.setVisible(bool(self._text))
        self._dot = None
        self.style().polish(self)

    dayu_overflow = Property(int, get_dayu_overflow, set_dayu_overflow)
    dayu_dot = Property(bool, get_dayu_dot, set_dayu_dot)
    dayu_count = Property(int, get_dayu_count, set_dayu_count)
    dayu_text = Property(basestring, get_dayu_text, set_dayu_text)

    @classmethod
    def dot(cls, show=False, widget=None):
        """
        Create a Badge with dot style.
        :param show: bool
        :param widget: the wrapped widget
        :return: instance badge
        """
        inst = cls(widget=widget)
        inst.set_dayu_dot(show)
        return inst

    @classmethod
    def count(cls, count=0, widget=None):
        """
        Create a Badge with number style.
        :param count: int
        :param widget: the wrapped widget
        :return: instance badge
        """
        inst = cls(widget=widget)
        inst.set_dayu_count(count)
        return inst

    @classmethod
    def text(cls, text='', widget=None):
        """
        Create a Badge with text style.
        :param text: basestring
        :param widget: the wrapped widget
        :return: instance badge
        """
        inst = cls(widget=widget)
        inst.set_dayu_text(text)
        return inst
Exemple #22
0
class MSwitch(QRadioButton):
    """
    Switching Selector.

    Property:
        dayu_size: the size of switch widget. int
    """
    def __init__(self, parent=None):
        super(MSwitch, self).__init__(parent)
        self._dayu_size = dayu_theme.default_size
        self.setAutoExclusive(False)

    def minimumSizeHint(self):
        """
        Override the QRadioButton minimum size hint. We don't need the text space.
        :return:
        """
        height = self._dayu_size * 1.2
        return QSize(height, height / 2)

    def get_dayu_size(self):
        """
        Get the switch size.
        :return: int
        """
        return self._dayu_size

    def set_dayu_size(self, value):
        """
        Set the switch size.
        :param value: int
        :return: None
        """
        self._dayu_size = value
        self.style().polish(self)

    dayu_size = Property(int, get_dayu_size, set_dayu_size)

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

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

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

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

    def tiny(self):
        """Set MSwitch to tiny size"""
        self.set_dayu_size(dayu_theme.tiny)
        return self
Exemple #23
0
class MToolButton(QToolButton):
    """MToolButton"""
    def __init__(self, parent=None):
        super(MToolButton, self).__init__(parent=parent)
        self._dayu_svg = None
        self.setAutoExclusive(False)
        self.setAutoRaise(True)

        self._polish_icon()
        self.toggled.connect(self._polish_icon)
        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

        self._dayu_size = dayu_theme.default_size

    @Slot(bool)
    def _polish_icon(self, checked=None):
        if self._dayu_svg:
            if self.isCheckable() and self.isChecked():
                self.setIcon(MIcon(self._dayu_svg, dayu_theme.primary_color))
            else:
                self.setIcon(MIcon(self._dayu_svg))

    def enterEvent(self, event):
        """Override enter event to highlight the icon"""
        if self._dayu_svg:
            self.setIcon(MIcon(self._dayu_svg, dayu_theme.primary_color))
        return super(MToolButton, self).enterEvent(event)

    def leaveEvent(self, event):
        """Override leave event to recover the icon"""
        self._polish_icon()
        return super(MToolButton, self).leaveEvent(event)

    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
        self.style().polish(self)
        if self.toolButtonStyle() == Qt.ToolButtonIconOnly:
            self.setFixedSize(QSize(self._dayu_size, self._dayu_size))

    def get_dayu_svg(self):
        """Get current svg path"""
        return self._dayu_svg

    def set_dayu_svg(self, path):
        """Set current svg path"""
        self._dayu_svg = path
        self._polish_icon()

    dayu_size = Property(int, get_dayu_size, set_dayu_size)

    def huge(self):
        """Set MPushButton to PrimaryType"""
        self.set_dayu_size(dayu_theme.huge)
        return self

    def large(self):
        """Set MPushButton to SuccessType"""
        self.set_dayu_size(dayu_theme.large)
        return self

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

    def small(self):
        """Set MPushButton to DangerType"""
        self.set_dayu_size(dayu_theme.small)
        return self

    def tiny(self):
        """Set MPushButton to DangerType"""
        self.set_dayu_size(dayu_theme.tiny)
        return self

    def svg(self, path):
        """Set current svg path"""
        self.set_dayu_svg(path)
        return self

    def icon_only(self):
        """Set tool button style to icon only"""
        self.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self.setFixedSize(QSize(self._dayu_size, self._dayu_size))
        return self

    def text_only(self):
        """Set tool button style to text only"""
        self.setToolButtonStyle(Qt.ToolButtonTextOnly)
        return self

    def text_beside_icon(self):
        """Set tool button style to text beside icon"""
        self.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)
        return self

    def text_under_icon(self):
        """Set tool button style to text under icon"""
        self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)
        return self
Exemple #24
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)

    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()
Exemple #25
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 save_file(self, filters=None):
        """Add a MClickSaveFileToolButton for MLineEdit to set save file"""
        _suffix_button = MClickSaveFileToolButton()
        _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 set save file'))
        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