示例#1
0
class BaseLineEdit(QLineEdit, object):
    """
     Basic line edit
     """

    delayTextChanged = Signal(str)

    def __init__(self, text='', input_mode=None, parent=None):
        super(BaseLineEdit, self).__init__(text, parent)

        self._prefix_widget = None
        self._suffix_widget = None
        self._size = self.theme_default_size()

        self._main_layout = layouts.HorizontalLayout()
        self._main_layout.setContentsMargins(0, 0, 0, 0)
        self._main_layout.addStretch()
        self.setLayout(self._main_layout)

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

        if input_mode == 'float':
            self.setValidator(QDoubleValidator())
        elif input_mode == 'int':
            self.setValidator(QIntValidator())

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

    # =================================================================================================================
    # PROPERTIES
    # =================================================================================================================

    def _get_text(self):
        return self.text()

    def _set_text(self, value):
        with qt_contexts.block_signals(self):
            self.setText(value)

    def _get_size(self):
        """
        Returns the spin box height size
        :return: float
        """

        return self._size

    def _set_size(self, value):
        """
        Sets spin box height size
        :param value: float
        """

        self._size = value
        if hasattr(self._prefix_widget, 'theme_size'):
            self._prefix_widget.theme_size = self._size
        if hasattr(self._suffix_widget, 'theme_size'):
            self._suffix_widget.theme_size = self._size
        self.style().polish(self)

    theme_size = Property(int, _get_size, _set_size)
    line_text = Property(str, _get_text, _set_text)

    # =================================================================================================================
    # OVERRIDES
    # =================================================================================================================

    def setText(self, text):
        """
        Overrides base QLineEdit setText base function.
        Save history
        :param text: str
        """

        self.setProperty('history', '{}\n{}'.format(self.property('history'),
                                                    text))
        return super(BaseLineEdit, self).setText(text)

    def clear(self):
        """
        Overrides base QLineEdit clear function
        :return:
        """

        self.setProperty('history', '')
        return super(BaseLineEdit, self).clear()

    def keyPressEvent(self, event):
        """
        Overrides base QLineEdit keyPressEvent function
        :param event: QKeyEvent
        """

        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(BaseLineEdit, self).keyPressEvent(event)

    # =================================================================================================================
    # BASE
    # =================================================================================================================

    def set_delay_duration(self, ms):
        """
        Sets the delay timer duration
        :param ms: float
        """

        self._delay_timer.setInterval(ms)

    def get_prefix_widget(self):
        """
        Returns prefix widget for user to edit
        :return: QWidget
        """

        return self._prefix_widget

    def set_prefix_widget(self, widget):
        """
        Sets the edit line left start widget
        :param widget: QWidget
        :return: QWidget
        """

        if self._prefix_widget:
            index = self._main_layout.indexOf(self._prefix_widget)
            self._main_layout.takeAt(index)
            self._prefix_widget.setVisible(False)
            self._prefix_widget.deleteLater()

        widget.setProperty('combine', 'horizontal')
        widget.setProperty('position', 'left')
        if hasattr(widget, 'theme_size'):
            widget.them_size = self.theme_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):
        """
        Returns suffix widget for user to edit
        :return: QWidget
        """

        return self._suffix_widget

    def set_suffix_widget(self, widget):
        """
        Sets the edit line right start widget
        :param widget: QWidget
        :return: QWidget
        """

        if self._suffix_widget:
            index = self._main_layout.indexOf(self._suffix_widget)
            self._main_layout.takeAt(index)
            self._suffix_widget.setVisible(False)
            self._suffix_widget.deleteLater()

        widget.setProperty('combine', 'horizontal')
        widget.setProperty('position', 'right')
        if hasattr(widget, 'theme_size'):
            widget.them_size = self.theme_size

        margin = self.textMargins()
        margin.setRight(margin.right() + widget.width())
        self.setTextMargins(margin)

        self._main_layout.addWidget(widget)
        self._prefix_widget = widget

        return widget

    def search(self):
        """
        Adds a search icon button for line edit
        :return: self
        """

        prefix_btn = buttons.BaseToolButton().image('search').icon_only()
        suffix_btn = buttons.BaseToolButton().image('close').icon_only()
        suffix_btn.clicked.connect(self.clear)
        self.set_prefix_widget(prefix_btn)
        self.set_suffix_widget(suffix_btn)
        self.setPlaceholderText('Enter keyword to search ...')

        return self

    def search_engine(self, text='Search'):
        """
        Adds a search push button to line edit
        :param text: str
        :return: self
        """

        _suffix_btn = buttons.BaseButton(text).primary()
        _suffix_btn.clicked.connect(self.returnPressed)
        _suffix_btn.setFixedWidth(100)
        self.set_suffix_widget(_suffix_btn)
        self.setPlaceholderText('Enter keyword to search ...')

        return self

    def file(self, filters=None):
        """
        Adds a ClickBrowserFileToolButton to line edit
        :param filters:
        :return: self
        """

        _suffix_btn = browser.ClickBrowserFileToolButton()
        _suffix_btn.fileChanged.connect(self.setText)
        _suffix_btn.filters = filters
        self.textChanged.connect(_suffix_btn.set_path)
        self.set_suffix_widget(_suffix_btn)
        self.setPlaceholderText('Click button to browse files')

        return self

    def save_file(self, filters=None):
        """
        Adds a ClickSaveFileToolButton to line edit
        :param filters:
        :return: self
        """

        _suffix_button = browser.ClickSaveFileToolButton()
        _suffix_button.fileChanged.connect(self.setText)
        _suffix_button.filters = filters or list()
        self.textChanged.connect(_suffix_button.set_path)
        self.set_suffix_widget(_suffix_button)
        self.setPlaceholderText('Click button to set save file')

        return self

    def folder(self):
        """
        Adds a ClickBrowserFileToolButton to line edit
        :return: self
        """

        _suffix_btn = browser.ClickBrowserFolderToolButton()
        _suffix_btn.folderChanged.connect(self.setText)
        self.textChanged.connect(_suffix_btn.set_path)
        self.set_suffix_widget(_suffix_btn)
        self.setPlaceholderText('Click button to browse folder')

        return self

    def error(self):
        """
        Shows error in line edit with red style
        :return: self
        """
        def _on_show_detail(self):
            dlg = QTextEdit(self)
            dlg.setReadOnly(True)
            geo = QApplication.desktop().screenGeometry()
            dlg.setGeometry(geo.width() / 2,
                            geo.height() / 2,
                            geo.width() / 4,
                            geo.height() / 4)
            dlg.setWindowTitle('Error Detail Information')
            dlg.setText(self.property('history'))
            dlg.setWindowFlags(Qt.Dialog)
            dlg.show()

        self.setProperty('theme_type', 'error')
        self.setReadOnly(True)
        _suffix_btn = buttons.BaseToolButton().image(
            'delete_message').icon_only()
        _suffix_btn.clicked.connect(partial(_on_show_detail, self))
        self.set_suffix_widget(_suffix_btn)
        self.setPlaceholderText('Error information will be here ...')

        return self

    def tiny(self):
        """
        Sets line edit to tiny size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.tiny if widget_theme else theme.Theme.Sizes.TINY

        return self

    def small(self):
        """
        Sets line edit to small size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.small if widget_theme else theme.Theme.Sizes.SMALL

        return self

    def medium(self):
        """
        Sets line edit to medium size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.medium if widget_theme else theme.Theme.Sizes.MEDIUM

        return self

    def large(self):
        """
        Sets line edit to large size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.large if widget_theme else theme.Theme.Sizes.LARGE

        return self

    def huge(self):
        """
        Sets line edit to huge size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.huge if widget_theme else theme.Theme.Sizes.HUGE

        return self

    def password(self):
        """
        Sets line edit password mode
        """

        self.setEchoMode(QLineEdit.Password)

        return self

    # =================================================================================================================
    # CALLBACKS
    # =================================================================================================================

    def _on_delay_text_changed(self):
        """
        Internal callback function that is called when delay timer is completed
        """

        self.delayTextChanged.emit(self.text())
示例#2
0
class BaseDateEdit(QDateEdit, object):
    def __init__(self, parent=None):
        super(BaseDateEdit, self).__init__(parent=parent)

        self._size = self.theme_default_size()

    # =================================================================================================================
    # PROPERTIES
    # =================================================================================================================

    def _get_size(self):
        """
        Returns the date edit height size
        :return: float
        """

        return self._size

    def _set_size(self, value):
        """
        Sets date edit height size
        :param value: float
        """

        self._size = value
        self.style().polish(self)

    theme_size = Property(int, _get_size, _set_size)

    # =================================================================================================================
    # BASE
    # =================================================================================================================

    def tiny(self):
        """
        Sets date edit to tiny size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.tiny if widget_theme else theme.Theme.Sizes.TINY

        return self

    def small(self):
        """
        Sets date edit to small size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.small if widget_theme else theme.Theme.Sizes.SMALL

        return self

    def medium(self):
        """
        Sets date edit to medium size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.medium if widget_theme else theme.Theme.Sizes.MEDIUM

        return self

    def large(self):
        """
        Sets date edit to large size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.large if widget_theme else theme.Theme.Sizes.LARGE

        return self

    def huge(self):
        """
        Sets date edit to huge size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.huge if widget_theme else theme.Theme.Sizes.HUGE

        return self
示例#3
0
class BaseButton(QPushButton, object):
    class Types(object):
        DEFAULT = 'default'
        PRIMARY = 'primary'
        SUCCESS = 'success'
        WARNING = 'warning'
        DANGER = 'danger'

    def __init__(self, text='', icon=None, elided=False, parent=None):

        self._text = text
        self._elided = elided

        if not icon:
            super(BaseButton, self).__init__(text=text, parent=parent)
        else:
            super(BaseButton, self).__init__(text=text,
                                             parent=parent,
                                             icon=icon)

        self._type = self.Types.DEFAULT
        self._size = self.theme_default_size()

        # NOTE: Without this, button will not call focusIn/out events when pressed
        self.setFocusPolicy(Qt.StrongFocus)

    # =================================================================================================================
    # PROPERTIES
    # =================================================================================================================

    def _get_type(self):
        """
        Returns button type
        :return: float
        """

        return self._type

    def _set_type(self, value):
        """
        Sets button type
        :param value: str
        """

        if value in [
                self.Types.DEFAULT, self.Types.PRIMARY, self.Types.SUCCESS,
                self.Types.WARNING, self.Types.DANGER
        ]:
            self._type = value
        else:
            raise ValueError(
                'Given button type: "{}" is not supported. Supported types '
                'are: default, primary, success, warning and danger'.format(
                    value))
        self.style().polish(self)

    def _get_size(self):
        """
        Returns the button height size
        :return: float
        """

        return self._size

    def _set_size(self, value):
        """
        Sets button height size
        :param value: float
        """

        self._size = value
        self.style().polish(self)

    theme_type = Property(str, _get_type, _set_type)
    theme_size = Property(int, _get_size, _set_size)

    # =================================================================================================================
    # BASE
    # =================================================================================================================

    def default(self):
        """
        Sets button to default style
        """

        self.theme_type = self.Types.DEFAULT

        return self

    def primary(self):
        """
        Sets button to primary style
        """

        self.theme_type = self.Types.PRIMARY

        return self

    def success(self):
        """
        Sets button to success style
        """

        self.theme_type = self.Types.SUCCESS

        return self

    def warning(self):
        """
        Sets button to warning style
        """

        self.theme_type = self.Types.WARNING

        return self

    def danger(self):
        """
        Sets button to danger style
        """

        self.theme_type = self.Types.DANGER

        return self

    def tiny(self):
        """
        Sets button to tiny size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.tiny if widget_theme else theme.Theme.Sizes.TINY

        return self

    def small(self):
        """
        Sets button to small size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.small if widget_theme else theme.Theme.Sizes.SMALL

        return self

    def medium(self):
        """
        Sets button to medium size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.medium if widget_theme else theme.Theme.Sizes.MEDIUM

        return self

    def large(self):
        """
        Sets button to large size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.large if widget_theme else theme.Theme.Sizes.LARGE

        return self

    def huge(self):
        """
        Sets button to huge size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.huge if widget_theme else theme.Theme.Sizes.HUGE

        return self

    def setText(self, text):
        self._text = text
        super(BaseButton, self).setText(text)

    def resizeEvent(self, event):
        if self._elided:
            has_icon = self.icon() and not self.icon().isNull()
            if has_icon:
                font_metrics = QFontMetrics(self.font())
                elided = font_metrics.elidedText(self._text, Qt.ElideMiddle,
                                                 self.width() - 30)
                super(BaseButton, self).setText(elided)
        super(BaseButton, self).resizeEvent(event)
示例#4
0
class Badge(base.BaseWidget, object):
    """
    Widget that can be located near notification or user avatars to display unread messages count
    We support 3 types of styles:
        1. dof: show a dot
        2. count: show a number
        3. text: show a string
    """
    def __init__(self, widget=None, parent=None):

        self._dot = None
        self._text = None
        self._count = None
        self._widget = widget
        self._overflow_count = 99

        super(Badge, self).__init__(parent=parent)

    # =================================================================================================================
    # PROPERTIES
    # =================================================================================================================

    @property
    def overflow(self):
        """
        Returns current overflow number
        :return: int
        """

        return self._overflow_count

    @overflow.setter
    def overflow(self, value):
        """
        Sets overflow number
        :param value: int
        """

        self._overflow_count = value
        self._update_number()

    @property
    def count(self):
        """
        Returns current badge count number
        :return: int
        """

        return self._count

    @count.setter
    def count(self, value):
        """
        Sets current badge count number
        :param value: int
        """

        self._count = value
        self._update_number()

    @property
    def text(self):
        """
        Returns current badge text
        :return: str
        """

        return self._text

    @text.setter
    def text(self, value):
        """
        Sets current badge text
        :param value: str
        """

        self._text = value
        self._badge_btn.setText(self._text)
        self._badge_btn.setVisible(bool(self._text))
        self._dot = None
        self.style().polish(self)

    def _get_dot(self):
        """
        Returns whether or not current badge style is dot
        :return: bool
        """

        return self._dot

    def _set_dot(self, flag):
        """
        Sets whether or not current badge style is dot
        :param flag: bool
        """

        self._dot = flag
        self._badge_btn.setText('')
        self._badge_btn.setVisible(flag)
        self.style().polish(self)

    dot = Property(bool, _get_dot, _set_dot)

    # =================================================================================================================
    # OVERRIDES
    # =================================================================================================================

    def get_main_layout(self):
        main_layout = layouts.GridLayout(margins=(0, 0, 0, 0))

        return main_layout

    def ui(self):
        super(Badge, self).ui()

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

        if self._widget is not None:
            self.main_layout.addWidget(self._widget, 0, 0)
        self.main_layout.addWidget(self._badge_btn, 0, 0,
                                   Qt.AlignTop | Qt.AlignRight)

    # =================================================================================================================
    # BASE
    # =================================================================================================================

    @classmethod
    def create_dot(cls, show=False, widget=None, parent=None):
        """
        Creates a new badge with dot style
        :param show: bool
        :param widget: QWidget
        :param parent: QWidget
        :return: Badge
        """

        inst = cls(widget=widget, parent=parent)
        inst.dot = show

        return inst

    @classmethod
    def create_count(cls, count=0, widget=None, parent=None):
        """
        Creates a new badge with count style
        :param count: int
        :param widget: QWidget
        :param parent: QWidget
        :return: Badge
        """

        inst = cls(widget=widget, parent=parent)
        inst.count = count

        return inst

    @classmethod
    def create_text(cls, text='', widget=None, parent=None):
        """
        Creates a new badge with dot style
        :param text: str
        :param widget: QWidget
        :param parent: QWidget
        :return: Badge
        """

        inst = cls(widget=widget, parent=parent)
        inst.text = text

        return inst

    # =================================================================================================================
    # INTERNAL
    # =================================================================================================================

    def _update_number(self):
        """
        Internal function that updates overflow number
        """

        self._badge_btn.setText(
            formatters.overflow_format(self._count, self._overflow_count))
        self._badge_btn.setVisible(self._count > 0)
        self._dot = None
        self.style().polish(self)
示例#5
0
class ToolBar(QToolBar, object):
    """
    Class that adds functionality to expand/collapse QToolBars
    """

    DEFAULT_EXPANDED_HEIGHT = 32
    DEFAULT_COLLAPSED_HEIGHT = 10
    ICON_SIZE = 32

    def __init__(self, *args, **kwargs):
        super(ToolBar, self).__init__(*args, **kwargs)

        self._dpi = 1
        self._is_expanded = True
        self._expanded_height = self.DEFAULT_EXPANDED_HEIGHT
        self._collapsed_height = self.DEFAULT_COLLAPSED_HEIGHT

        self.setMinimumHeight(self.DEFAULT_EXPANDED_HEIGHT)

    def _get_expanded(self):
        return self._is_expanded

    def _set_expanded(self, flag):
        self._is_expanded = flag

    expanded = Property(bool, _get_expanded, _set_expanded)

    # =================================================================================================================
    # OVERRIDES
    # =================================================================================================================

    def mousePressEvent(self, event):
        if not self.is_expanded():
            self.expand()

    def setFixedHeight(self, value):
        """
        Overrides base QToolBar setFixedHeight
        Allows to also set the height for all child widgets of the menu bar
        :param value: float
        """

        self.set_children_height(value)
        super(ToolBar, self).setFixedHeight(value)
        print(self.height())

    def insertAction(self, before, action):
        """
        Overrides base QToolBar insertAction function
        Support the before argument as string
        :param before: QAction or str
        :param action: QAction
        :return: QAction
        """

        action.setParent(self)
        if python.is_string(before):
            before = self.find_action(before)

        action = super(ToolBar, self).insertAction(before, action)

        return action

    def actions(self):
        """
        Overrides base QToolBar actions function
        Returns all the widgets that are a child of the menu bar widget
        :return: list(QWidget)
        """

        actions = list()

        for child in self.children():
            if isinstance(child, QAction):
                actions.append(child)

        return actions

    # =================================================================================================================
    # DPI
    # =================================================================================================================

    def dpi(self):
        """
        Returns the zoom multiplier
        :return: float
        """

        return self._dpi

    def set_dpi(self, dpi):
        """
        Set the zoom multiplier
        :param : float
        """

        self._dpi = dpi
        if self.is_expanded():
            self.expand()
        else:
            self.collapse()

    # =================================================================================================================
    # BASE
    # =================================================================================================================

    def widgets(self):
        """
        Returns all the widgets that are a child of the menu bar widget
        :return: list(QWidget)
        """

        widgets = list()
        for i in range(self.layout().count()):
            w = self.layout().itemAt(i).widget()
            if isinstance(w, QWidget):
                widgets.append(w)

        return widgets

    def is_expanded(self):
        """
        Returns whether the menu bar is expanded or not
        :return: bool
        """

        return self._is_expanded

    def expand_height(self):
        """
        Returns the height of menu bar when is expanded
        :return: float
        """

        return int(self._expanded_height * self.dpi())

    def collapse_height(self):
        """
        Returns the height of widget when collapsed
        :return: int
        """

        return int(self._collapsed_height * self.dpi())

    def set_children_hidden(self, flag):
        """
        Hide/Show all child widgets
        :param flag: bool
        """

        for action in self.actions():
            action.setVisible(not flag)

        # for w in self.widgets():
        #     w.setHidden(flag)

    def set_children_height(self, height):
        """
        Set the height of all the child widgets to the given height
        :param height: int
        """

        for w in self.widgets():
            w.setFixedHeight(height)

    def expand(self):
        """
        Expand the menu bar to the expand height
        """

        self._is_expanded = True
        height = self.expand_height()
        self.setFixedHeight(height)
        self.set_children_hidden(False)
        icon_size = self.ICON_SIZE * self.dpi()
        self.setIconSize(QSize(icon_size, icon_size))
        self.setStyleSheet(self.styleSheet())

    def collapse(self):
        """
        Collapse the menu bar to the collapse height
        """

        self._is_expanded = False
        height = self.collapse_height()
        self.setFixedHeight(height)
        self.set_children_height(0)
        self.set_children_hidden(True)
        self.setIconSize(QSize(0, 0))
        self.setStyleSheet(self.styleSheet())

    def set_icon_color(self, color):
        """
        Set the icon colors to the current foregroundRole
        :param color: QColor
        """

        for action in self.actions():
            action_icon = action.icon()
            action_icon = icon.Icon(action_icon)
            action_icon.set_color(color)
            action.setIcon(action_icon)

    def find_action(self, text):
        """
        Find the action with the given text
        :param text: str
        :return: QAction or None
        """

        for child in self.children():
            if isinstance(child, QAction):
                if child.text() == text:
                    return child

    def find_tool_button(self, text):
        """
        Find the QToolButton with the given text
        :param text: str
        :return: QToolButton or None
        """

        for child in self.children():
            if isinstance(child, QAction):
                if child.text() == text:
                    return self.widgetForAction(child)
示例#6
0
class BaseToolButton(QToolButton, object):
    def __init__(self, parent=None):
        super(BaseToolButton, self).__init__(parent=parent)

        self._image = None
        self._image_theme = None
        self._size = self.theme_default_size()

        self.setAutoExclusive(False)
        self.setAutoRaise(True)
        self.setSizePolicy(QSizePolicy.Minimum, QSizePolicy.Minimum)

        self._polish_icon()

        self.toggled.connect(self._polish_icon)

    # =================================================================================================================
    # PROPERTIES
    # =================================================================================================================

    def _get_size(self):
        """
        Returns the button height size
        :return: float
        """

        return self._size

    def _set_size(self, value):
        """
        Sets button height size
        :param value: float
        """

        self._size = value
        self.style().polish(self)
        if self.toolButtonStyle() == Qt.ToolButtonIconOnly:
            self.setFixedSize(self._size, self._size)

    theme_size = Property(int, _get_size, _set_size)

    # =================================================================================================================
    # OVERRIDES
    # =================================================================================================================

    def enterEvent(self, event):
        if self._image:
            theme = self.theme()
            if theme:
                accent_color = theme.accent_color
                if self._image_theme:
                    self.setIcon(
                        resources.icon(self._image,
                                       theme=self._image_theme,
                                       color=accent_color))
                else:
                    self.setIcon(
                        resources.icon(self._image, color=accent_color))
        return super(BaseToolButton, self).enterEvent(event)

    def leaveEvent(self, event):
        self._polish_icon()
        return super(BaseToolButton, self).leaveEvent(event)

    def _polish_icon(self, checked=None, **kwargs):
        if self._image:
            image_theme = kwargs.get('theme', self._image_theme)
            if image_theme:
                kwargs['theme'] = image_theme
            if self.isCheckable() and self.isChecked():
                self.setIcon(resources.icon(self._image, **kwargs))
            else:
                self.setIcon(resources.icon(self._image, **kwargs))

    # =================================================================================================================
    # BASE
    # =================================================================================================================

    def image(self, name, **kwargs):
        """
        Sets the name of the icon to use by the tool button
        :param str name:
        :return:
        """

        self._image = name
        self._image_theme = kwargs.get('theme', None)
        self._polish_icon(**kwargs)

        return self

    def tiny(self):
        """
        Sets tool button to tiny size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.tiny if widget_theme else theme.Theme.Sizes.TINY

        return self

    def small(self):
        """
        Sets tool button to small size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.small if widget_theme else theme.Theme.Sizes.SMALL

        return self

    def medium(self):
        """
        Sets tool button to medium size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.medium if widget_theme else theme.Theme.Sizes.MEDIUM

        return self

    def large(self):
        """
        Sets tool button to large size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.large if widget_theme else theme.Theme.Sizes.LARGE

        return self

    def huge(self):
        """
        Sets tool button to huge size
        """

        widget_theme = self.theme()
        self.theme_size = widget_theme.huge if widget_theme else theme.Theme.Sizes.HUGE

        return self

    def icon_only(self):
        """
        Sets tool button style to icon only
        """

        self.setToolButtonStyle(Qt.ToolButtonIconOnly)
        self.setFixedSize(self._size, self._size)

        return self

    def text_only(self):
        """
        Sets tool button style to icon only
        """

        self.setToolButtonStyle(Qt.ToolButtonTextOnly)

        return self

    def text_beside_icon(self):
        """
        Sets tool button style to text beside icon
        """

        self.setToolButtonStyle(Qt.ToolButtonTextBesideIcon)

        return self

    def text_under_icon(self):
        """
        Sets tool button style to text under icon
        """

        self.setToolButtonStyle(Qt.ToolButtonTextUnderIcon)

        return self
示例#7
0
class FilePickerWidget(QWidget):
    filenamePicked = Signal(str)
    filenameChanged = Signal(str)
    filenameEdited = Signal(str)

    def __init__(self, parent=None):
        self._correctBackground = QColor(156, 206, 156, 255)
        self._correctForeground = QColor(Qt.white)
        self._inCorrectBackground = QColor(210, 156, 156, 255)
        self._inCorrectForeground = QColor(Qt.white)
        self._defaultLocation = ''
        QWidget.__init__(self, parent)

        self.uiFilenameTXT = LineEdit(self)
        self.uiPickFileBTN = QToolButton(self)
        self.uiPickFileBTN.setText('...')
        self.uiPickFileBTN.setToolTip(
            '<html><head/><body><p>Browse to a file path.</p><p>Ctrl + LMB: Explore to current path.</p></body></html>'
        )
        # Make this widget focusable and pass the widget focus to uiFilenameTXT
        self.setFocusProxy(self.uiFilenameTXT)
        self.setFocusPolicy(Qt.StrongFocus)
        layout = QHBoxLayout(self)
        layout.addWidget(self.uiFilenameTXT)
        layout.addWidget(self.uiPickFileBTN)
        layout.setContentsMargins(0, 0, 0, 0)
        self.setLayout(layout)

        self._caption = "Pick file..."
        self._filters = "All Files (*.*)"
        self._pickFolder = False
        self._openFile = False
        self._resolvePath = False
        #self._imageSequence = False
        self._resolved = False
        self._chosenPath = None
        #self._imageSequenceFormat = '{pre}[{firstNum}:{lastNum}]{post}'

        self.uiFilenameTXT.textChanged.connect(self.emitFilenameChanged)

        self.uiFilenameTXT.editingFinished.connect(self.emitFilenameEdited)
        self.uiPickFileBTN.clicked.connect(self.pickPath)
        self.resolvedStylesheet = resolvedStylesheetDefault

        self.resolve()

    def caption(self):
        return self._caption

    def emitFilenameChanged(self):
        self.resolve()
        if (not self.signalsBlocked()):
            self.filenameChanged.emit(self.uiFilenameTXT.text())

    def emitFilenameEdited(self):
        if (not self.signalsBlocked()):
            self.filenameEdited.emit(self.uiFilenameTXT.text())

    def filePath(self):
        # if it's an image sequence, return the last chosen image path
        return self._chosenPath or self.uiFilenameTXT.text()

    def filters(self):
        return self._filters

    def isResolved(self):
        return self._resolved

    def openFile(self):
        return self._openFile

    def pickFolder(self):
        return self._pickFolder

    def pickPath(self):
        initialPath = self.uiFilenameTXT.text() or self.defaultLocation
        initialPath = str(initialPath)
        while not os.path.exists(initialPath):
            if os.path.dirname(initialPath) == initialPath:
                break
            else:
                initialPath = os.path.dirname(initialPath)
        if QApplication.keyboardModifiers() == Qt.ControlModifier:
            import blurdev
            blurdev.osystem.explore(initialPath)
        else:
            if self._pickFolder:
                filepath = QFileDialog.getExistingDirectory(
                    self, self._caption, initialPath)
            elif self._openFile:
                filepath, _ = QtCompat.QFileDialog.getOpenFileName(
                    self, self._caption, initialPath, self._filters)
            else:
                filepath, _ = QtCompat.QFileDialog.getSaveFileName(
                    self, self._caption, initialPath, self._filters)
            if filepath:
                self.uiFilenameTXT.setText(filepath)
                if (not self.signalsBlocked()):
                    self.filenamePicked.emit(filepath)

    def resolve(self):
        if self.resolvePath():
            path = self.uiFilenameTXT.text()
            if self._pickFolder:
                valid = os.path.isdir(path)
            else:
                valid = os.path.isfile(path)
            if valid:
                fg = self.correctForeground
                bg = self.correctBackground
                self._resolved = True
            else:
                fg = self.inCorrectForeground
                bg = self.inCorrectBackground
                self._resolved = False

            style = self.resolvedStylesheet % {
                'bg': bg.getRgb(),
                'fg': fg.getRgb()
            }
        else:
            style = ''
            self._resolved = False

        self.uiFilenameTXT.setStyleSheet(style)

    def resolvePath(self):
        return self._resolvePath

    def setCaption(self, caption):
        self._caption = caption

    @Slot(str)
    def setFilePath(self, filePath):
        self.uiFilenameTXT.setText(filePath)
        self.resolve()

    def setFilters(self, filters):
        self._filters = filters

    def setOpenFile(self, state):
        self._openFile = state

    def setPickFolder(self, state):
        self._pickFolder = state

    @Slot(bool)
    def setNotResolvePath(self, state):
        """ Set resolvePath to the oposite of state. """
        self.setResolvePath(not state)

    @Slot(bool)
    def setResolvePath(self, state):
        self._resolvePath = state
        self.resolve()

    pyCaption = Property("QString", caption, setCaption)
    pyFilters = Property("QString", filters, setFilters)
    pyPickFolder = Property("bool", pickFolder, setPickFolder)
    pyOpenFile = Property("bool", openFile, setOpenFile)
    pyResolvePath = Property("bool", resolvePath, setResolvePath)
    #pyImageSequence	= Property( "bool", imageSequence, setImageSequence )
    pyFilePath = Property("QString", filePath, setFilePath)

    # Load the colors from the stylesheets
    @Property(QColor)
    def correctBackground(self):
        return self._correctBackground

    @correctBackground.setter
    def correctBackground(self, color):
        self._correctBackground = color
        self.resolve()

    @Property(QColor)
    def correctForeground(self):
        return self._correctForeground

    @correctForeground.setter
    def correctForeground(self, color):
        self._correctForeground = color
        self.resolve()

    @Property(QColor)
    def inCorrectBackground(self):
        return self._inCorrectBackground

    @inCorrectBackground.setter
    def inCorrectBackground(self, color):
        self._inCorrectBackground = color
        self.resolve()

    @Property(QColor)
    def inCorrectForeground(self):
        return self._inCorrectForeground

    @inCorrectForeground.setter
    def inCorrectForeground(self, color):
        self._inCorrectForeground = color
        self.resolve()

    @Property("QString")
    def defaultLocation(self):
        return self._defaultLocation

    @defaultLocation.setter
    def defaultLocation(self, value):
        self._defaultLocation = str(value)
示例#8
0
class BaseMessage(base.BaseWidget, object):
    def __init__(self, text='', parent=None):

        self._type = None
        self._text = ''

        super(BaseMessage, self).__init__(parent)

        self.setAttribute(Qt.WA_StyledBackground)

        self.set_show_icon(True)
        self.set_closable(False)
        self.theme_type = MessageTypes.INFO
        self.text = text

    # =================================================================================================================
    # PROPERTIES
    # =================================================================================================================

    def _get_text(self):
        """
        Returns message text
        :return: str
        """

        return self._text

    def _set_text(self, text):
        """
        Sets message text content
        :param text: str
        """

        self._text = str(text)
        self._content_label.setText(self._text)
        self.setVisible(bool(self._text))

    def _get_type(self):
        """
        Returns message type
        :return: float
        """

        return self._type

    def _set_type(self, value):
        """
        Sets message type
        :param value: str
        """

        current_theme = self.theme()

        if value in [
                MessageTypes.INFO, MessageTypes.SUCCESS, MessageTypes.WARNING,
                MessageTypes.ERROR
        ]:
            self._type = value
        else:
            raise ValueError(
                'Given button type: "{}" is not supported. Supported types '
                'are: info, success, warning, error'.format(value))

        if current_theme:
            self._icon_label.image = resources.pixmap(
                self._type,
                color=getattr(current_theme, '{}_color'.format(self._type)))
        else:
            self._icon_label.image = resources.pixmap(self._type)
        self.style().polish(self)

    text = Property(str, _get_text, _set_text)
    theme_type = Property(str, _get_type, _set_type)

    # =================================================================================================================
    # OVERRIDES
    # =================================================================================================================

    def get_main_layout(self):
        main_layout = layouts.HorizontalLayout(margins=(8, 8, 8, 8))

        return main_layout

    def ui(self):
        super(BaseMessage, self).ui()

        current_theme = self.theme()

        self._icon_label = avatar.Avatar()
        self._icon_label.theme_size = current_theme.huge if current_theme else theme.Theme.Sizes.HUGE
        self._content_label = label.BaseLabel().secondary()
        self._close_btn = buttons.BaseToolButton().image(
            'close', theme='window').large().icon_only()

        self.main_layout.addWidget(self._icon_label)
        self.main_layout.addWidget(self._content_label)
        self.main_layout.addStretch()
        self.main_layout.addWidget(self._close_btn)

    def setup_signals(self):
        self._close_btn.clicked.connect(partial(self.setVisible, False))

    # =================================================================================================================
    # BASE
    # =================================================================================================================

    def set_closable(self, flag):
        """
        Sets whether or not the message is closable
        :param flag: bool
        """

        self._close_btn.setVisible(flag)

        return self

    def set_show_icon(self, flag):
        """
        Sets whether or not the display information type icon is visible or not
        :param flag: bool
        """

        self._icon_label.setVisible(flag)

        return self

    def info(self):
        """
        Sets message to info type
        """

        self.theme_type = MessageTypes.INFO

        return self

    def success(self):
        """
        Sets message to success type
        """

        self.theme_type = MessageTypes.SUCCESS

        return self

    def warning(self):
        """
        Sets message to warning type
        """

        self.theme_type = MessageTypes.WARNING

        return self

    def error(self):
        """
        Sets message to error type
        """

        self.theme_type = MessageTypes.ERROR

        return self

    def closable(self):
        """
        Sets message to info type
        """

        self.set_closable(True)

        return self
示例#9
0
class StatusWidget(QFrame, object):

    DEFAULT_DISPLAY_TIME = 10000  # milliseconds -> 10 seconds

    def __init__(self, *args):
        super(StatusWidget, self).__init__(*args)

        self._status = None
        self._blocking = False
        self._timer = QTimer(self)

        self.setObjectName('StatusWidget')
        self.setFrameShape(QFrame.NoFrame)
        self.setFixedHeight(19)
        self.setMinimumWidth(5)

        self._label = label.BaseLabel('', parent=self)
        self._label.setStyleSheet('background-color: transparent;')
        self._label.setCursor(Qt.IBeamCursor)
        self._label.setTextInteractionFlags(Qt.TextSelectableByMouse)
        self._label.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)

        self.label_image = label.BaseLabel(parent=self)
        self.label_image.setMaximumSize(QSize(17, 17))
        self.label_image.hide()

        self.main_layout = QHBoxLayout(self)
        self.main_layout.setContentsMargins(1, 0, 0, 0)

        self.main_layout.addWidget(self.label_image)
        self.main_layout.addWidget(self._label)

        self.setLayout(self.main_layout)

        self._timer.timeout.connect(self._reset)

        # Force set to initialize default status Qt property
        self.status = ''

    def _get_status(self):
        return self._status

    def _set_status(self, value):
        self._status = str(value)
        self.polish()

    status = Property(str, _get_status, _set_status)

    def is_blocking(self):
        """
        Returns True if the status widget is blocking, otherwise return False
        :return: bool
        """

        return self._blocking

    def show_ok_message(self, message, msecs=None):
        """
        Set an ok message to be displayed in the status widget
        :param message: str
        :param msecs: int
        """

        if self.is_blocking():
            return

        self.status = 'ok'
        icon = resources.icon('ok')
        self._show_message(message, icon, msecs)

    def show_info_message(self, message, msecs=None):
        """
        Set an info message to be displayed in the status widget
        :param message: str
        :param msecs: int
        """

        if self.is_blocking():
            return

        self.status = 'info'
        icon = resources.icon('info')
        self._show_message(message, icon, msecs)

    def show_warning_message(self, message, msecs=None):
        """
       Set a warning message to be displayed in the status widget
       :param message: str
       :param msecs: int
       """

        if self.is_blocking():
            return

        self.status = 'warning'
        icon = resources.icon('warning')
        self._show_message(message, icon, msecs)

    def show_error_message(self, message, msecs=None):
        """
       Set an error message to be displayed in the status widget
       :param message: str
       :param msecs: int
       """

        self.status = 'error'
        icon = resources.icon('error', extension='png')
        self._show_message(message, icon, msecs, blocking=True)

    def _reset(self):
        """
        Called when the current animation has finished
        """

        self._timer.stop()
        self.label_image.setVisible(False)
        self._label.setText('')
        icon = resources.pixmap('blank')
        self.label_image.setPixmap(
            icon) if icon else self.label_image.setPixmap(QPixmap())
        self.setStyleSheet('')
        self._blocking = False
        self.status = ''

    def _show_message(self, message, icon, msecs=None, blocking=False):
        """
        Set the given text to be displayed in the status widget
        :param message: str
        :param icon: QIcon
        :param msecs: int
        :param blocking: bool
        """

        msecs = msecs or self.DEFAULT_DISPLAY_TIME
        self._blocking = blocking

        self.label_image.setStyleSheet('border: 0px;')

        if icon:
            self.label_image.setPixmap(icon.pixmap(QSize(17, 17)))
            self.label_image.show()
        else:
            self.label_image.hide()

        if message:
            self._label.setText(str(message))
            self._timer.stop()
            self._timer.start(msecs)
        else:
            self._reset()

        self.update()
示例#10
0
class HoudiniDoubleSlider(QWidget, object):
    """
    Slider that encapsulates a DoubleSlider and Houdini draggers linked together
    """

    valueChanged = Signal(object)

    def __init__(self, parent, slider_type='float', style=0, name=None, slider_range=None, default_value=0.0,
                 dragger_steps=None, main_color=None, *args):
        if slider_range is None:
            slider_range = (-100.0, 100.0)
        if dragger_steps is None:
            dragger_steps = FLOAT_SLIDER_DRAG_STEPS
        super(HoudiniDoubleSlider, self).__init__(parent=parent, *args)

        h = 20
        self._parent = parent
        self._type = slider_type
        self._value = 0.0
        self._label = None
        self._style_type = style

        theme = self.theme()
        if theme:
            theme_color = theme.accent_color
            if core_color.string_is_hex(theme_color):
                theme_color = core_color.hex_to_rgb(theme_color)
                main_color = QColor(*theme_color).getRgb()

        self._main_color = main_color or QColor(215, 128, 26).getRgb()

        self.setMaximumHeight(h)
        self.setMinimumHeight(h)

        self._main_layout = layouts.HorizontalLayout(margins=(10, 0, 0, 0))
        self.setLayout(self._main_layout)

        self._input = DraggerSlider(slider_type=slider_type)
        self._input.setButtonSymbols(QAbstractSpinBox.NoButtons)
        self._input.setRange(slider_range[0], slider_range[1])
        self._input.setContentsMargins(0, 0, 0, 0)
        self._input.setMinimumWidth(60 if self._type == 'float' else 40)
        self._input.setMaximumWidth(60 if self._type == 'float' else 40)
        self._input.setMinimumHeight(h)
        self._input.setMaximumHeight(h)
        self._input.valueIncremented.connect(self._on_increment_value)

        if self._type == 'float':
            self._slider = DoubleSlider(parent=self, default_value=default_value, slider_range=slider_range,
                                        dragger_steps=dragger_steps)
        else:
            self._slider = Slider(parent=self, slider_range=slider_range)
            self._slider.valueIncremented.connect(self._on_increment_value)
        self._slider.setContentsMargins(0, 0, 0, 0)
        self._slider.setMinimumHeight(h)
        self._slider.setMaximumHeight(h)
        self._slider.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)

        if name:
            self._label = label.BaseLabel(name + '  ', parent=self)
            self._main_layout.addWidget(self._label)
        self._main_layout.addWidget(self._input)
        self._main_layout.addWidget(self._slider)

        style_sheet = self._get_style_sheet(self._style_type)
        if self._style_type == 0:
            self._main_layout.setSpacing(0)
        self._slider.setStyleSheet(style_sheet)

        self._slider.valueChanged.connect(self._on_slider_value_changed)
        self._input.valueChanged.connect(self._on_houdini_slider_value_changed)

    def update(self):
        style_sheet = self._get_style_sheet(self._style_type)
        if self._style_type == 0:
            self._main_layout.setSpacing(0)
        self._slider.setStyleSheet(style_sheet)

    @property
    def minimum(self):
        return self._input.minimum()

    @property
    def maximum(self):
        return self._input.maximum()

    @property
    def _value_range(self):
        return self.maximum - self.minimum

    def _get_value(self):
        return self.value()

    def _set_value(self, value):
        with qt_contexts.block_signals(self):
            self.set_value(value)

    intValue = Property(int, _get_value, _set_value, user=True)
    floatValue = Property(float, _get_value, _set_value, user=True)

    def value(self):
        self._value = self._input.value()
        if self._type == 'int':
            self._value = int(self._value)

        return self._value

    def set_value(self, value):
        self._input.setValue(value)
        self._value = self._input.value()
        self.valueChanged.emit(self.value())
        # self._on_houdini_slider_value_changed(0)

    def set_decimals(self, decimals):
        self._input.setDecimals(decimals)

    def set_single_step(self, step):
        self._input.setSingleStep(step)

    def hide_label(self):
        if self._label:
            self._label.hide()

    def show_label(self):
        if self._label:
            self._label.show()

    def hide_slider(self):
        self._slider.hide()

    def show_slider(self):
        self._slider.show()

    def set_range(self, minimum_value, maximum_value):
        self._input.setRange(minimum_value, maximum_value)

    def _on_increment_value(self, step):
        if step == 0.0:
            return
        old = self._input.value()
        new = old + step
        self._input.setValue(new)
        self.valueChanged.emit(new)

    def _on_slider_value_changed(self, value):
        out_value = utils.map_range_unclamped(
            value, self._slider.minimum(), self._slider.maximum(), self._input.minimum(), self._input.maximum())
        with qt_contexts.block_signals(self._input):
            self._input.setValue(out_value)
        self.valueChanged.emit(out_value)

    def _on_houdini_slider_value_changed(self, value):
        in_value = utils.map_range_unclamped(
            self._input.value(), self._input.minimum(), self._input.maximum(),
            self._slider.minimum(), self._slider.maximum())
        with qt_contexts.block_signals(self._slider):
            self._slider.setValue(int(in_value))
        self.valueChanged.emit(value)

    def _get_style_sheet(self, style_type):
        if style_type == 0:
            return """
            QWidget{
                border: 1.25 solid black;
            }
            QSlider::groove:horizontal,
                QSlider::sub-page:horizontal {
                background: %s;
            }
            QSlider::add-page:horizontal,
                QSlider::sub-page:horizontal:disabled {
                background: rgb(32, 32, 32);
            }
            QSlider::add-page:horizontal:disabled {
                background: grey;
            }
            QSlider::handle:horizontal {
                width: 1px;
             }
            """ % "rgba%s" % str(self._main_color)
        else:
            return """
            QSlider::groove:horizontal {
                border: 1px solid #bbb;
                background: white;
                height: 3px;
                border-radius: 2px;
            }
            QSlider::sub-page:horizontal {
                background: %s;
                border: 0px solid #777;
                height: 3px;
                border-radius: 2px;
            }
            QSlider::add-page:horizontal {
                background: #fff;
                border: 1px solid #777;
                height: 3px;
                border-radius: 2px;
            }
            QSlider::handle:horizontal {
                background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                    stop:0 #eee, stop:1 #ccc);
                border: 1px solid #777;
                width: 4px;
                margin-top: -8px;
                margin-bottom: -8px;
                border-radius: 2px;
                height : 10px;
            }
            QSlider::handle:horizontal:hover {
                background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                    stop:0 #fff, stop:1 #ddd);
                border: 1px solid #444;
                border-radius: 2px;
            }
            QSlider::sub-page:horizontal:disabled {
                background: #bbb;
                border-color: #999;
            }
            QSlider::add-page:horizontal:disabled {
                background: #eee;
                border-color: #999;
            }
            QSlider::handle:horizontal:disabled {
                background: #eee;
                border: 1px solid #aaa;
                border-radius: 2px;
                height : 10;
            }
            """ % "rgba%s" % str(self._main_color)
示例#11
0
class Avatar(QLabel, object):
    """
    Widget that can be used to represent users or objects
    """

    def __init__(self, parent=None):
        super(Avatar, self).__init__(parent)

        self._default_pixmap = resources.pixmap('user')
        self._pixmap = self._default_pixmap
        self._size = 0
        self._set_size(self.theme_default_size())

    # =================================================================================================================
    # PROPERTIES
    # =================================================================================================================

    def _get_size(self):
        """
        Returns the avatar height size
        :return: float
        """

        return self._size

    def _set_size(self, value):
        """
        Sets avatar height size
        :param value: float
        """

        self._size = value
        self.setFixedSize(self._size, self._size)
        self.setPixmap(self._pixmap.scaledToWidth(self.height(), Qt.SmoothTransformation))

    def _get_image(self):
        """
        Returns avatar image
        :return: QPixmap
        """

        return self._pixmap

    def _set_image(self, value):
        """
        Sets avatar image
        :param value: QPixmap or None
        """

        if value is None:
            self._pixmap = self._default_pixmap
        elif isinstance(value, QPixmap):
            self._pixmap = value
        else:
            raise TypeError('Input argument value should be QPixmap or None, but get "{}"'.format(type(value)))
        self.setPixmap(self._pixmap.scaledToWidth(self.height(), Qt.SmoothTransformation))

    theme_size = Property(int, _get_size, _set_size)
    image = Property(QPixmap, _get_image, _set_image)

    # =================================================================================================================
    # BASE
    # =================================================================================================================

    @classmethod
    def tiny(cls, image=None, parent=None):
        """
        Creates a new avatar widget with tiny size
        :param image:
        :param parent:
        :return:
        """

        avatar_widget = cls(parent=parent)
        loading_theme = avatar_widget.theme()
        loading_size = loading_theme.tiny if loading_theme else theme.Theme.Sizes.TINY
        avatar_widget.theme_size = loading_size
        avatar_widget.image = image

        return avatar_widget

    @classmethod
    def small(cls, image=None, parent=None):
        """
        Creates a new avatar widget with small size
        :param image:
        :param parent:
        :return:
        """

        avatar_widget = cls(parent=parent)
        loading_theme = avatar_widget.theme()
        loading_size = loading_theme.small if loading_theme else theme.Theme.Sizes.SMALL
        avatar_widget.theme_size = loading_size
        avatar_widget.image = image

        return avatar_widget

    @classmethod
    def medium(cls, image=None, parent=None):
        """
        Creates a new avatar widget with medium size
        :param image:
        :param parent:
        :return:
        """

        avatar_widget = cls(parent=parent)
        loading_theme = avatar_widget.theme()
        loading_size = loading_theme.medium if loading_theme else theme.Theme.Sizes.MEDIUM
        avatar_widget.theme_size = loading_size
        avatar_widget.image = image

        return avatar_widget

    @classmethod
    def large(cls, image=None, parent=None):
        """
        Creates a new avatar widget with large size
        :param image:
        :param parent:
        :return:
        """

        avatar_widget = cls(parent=parent)
        loading_theme = avatar_widget.theme()
        loading_size = loading_theme.large if loading_theme else theme.Theme.Sizes.LARGE
        avatar_widget.theme_size = loading_size
        avatar_widget.image = image

        return avatar_widget

    @classmethod
    def huge(cls, image=None, parent=None):
        """
        Creates a new avatar widget with huge size
        :param image:
        :param parent:
        :return:
        """

        avatar_widget = cls(parent=parent)
        loading_theme = avatar_widget.theme()
        loading_size = loading_theme.huge if loading_theme else theme.Theme.Sizes.HUGE
        avatar_widget.theme_size = loading_size
        avatar_widget.image = image

        return avatar_widget