Exemplo n.º 1
0
    def __init__(self,
                 text,
                 duration=None,
                 theme_type=None,
                 closable=False,
                 parent=None):

        self._text = text
        self._duration = duration
        self._theme_type = theme_type
        self._closable = closable

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

        self.setAttribute(Qt.WA_TranslucentBackground)

        close_timer = QTimer(self)
        close_timer.setSingleShot(True)
        close_timer.timeout.connect(self.close)
        close_timer.timeout.connect(self.closed)
        close_timer.setInterval(
            (duration or self.DEFAULT_CONFIG['duration']) * 1000)
        anim_timer = QTimer(self)
        anim_timer.timeout.connect(self._on_fade_out)
        anim_timer.setInterval((duration or self.DEFAULT_CONFIG['duration']) *
                               1000 - 300)
        close_timer.start()
        anim_timer.start()

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

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

        self._set_proper_position(parent)
        self._fade_in()
Exemplo n.º 2
0
Arquivo: qt.py Projeto: renemilk/pyMor
    class PlotMainWindow(QWidget):
        """Base class for plot main windows."""

        def __init__(self, U, plot, length=1, title=None):
            super().__init__()

            layout = QVBoxLayout()

            if title:
                title = QLabel('<b>' + title + '</b>')
                title.setAlignment(Qt.AlignHCenter)
                layout.addWidget(title)
            layout.addWidget(plot)

            plot.set(U, 0)

            if length > 1:
                hlayout = QHBoxLayout()

                self.slider = QSlider(Qt.Horizontal)
                self.slider.setMinimum(0)
                self.slider.setMaximum(length - 1)
                self.slider.setTickPosition(QSlider.TicksBelow)
                hlayout.addWidget(self.slider)

                lcd = QLCDNumber(m.ceil(m.log10(length)))
                lcd.setDecMode()
                lcd.setSegmentStyle(QLCDNumber.Flat)
                hlayout.addWidget(lcd)

                layout.addLayout(hlayout)

                hlayout = QHBoxLayout()

                toolbar = QToolBar()
                self.a_play = QAction(self.style().standardIcon(QStyle.SP_MediaPlay), 'Play', self)
                self.a_play.setCheckable(True)
                self.a_rewind = QAction(self.style().standardIcon(QStyle.SP_MediaSeekBackward), 'Rewind', self)
                self.a_toend = QAction(self.style().standardIcon(QStyle.SP_MediaSeekForward), 'End', self)
                self.a_step_backward = QAction(self.style().standardIcon(QStyle.SP_MediaSkipBackward),
                                               'Step Back', self)
                self.a_step_forward = QAction(self.style().standardIcon(QStyle.SP_MediaSkipForward), 'Step', self)
                self.a_loop = QAction(self.style().standardIcon(QStyle.SP_BrowserReload), 'Loop', self)
                self.a_loop.setCheckable(True)
                toolbar.addAction(self.a_play)
                toolbar.addAction(self.a_rewind)
                toolbar.addAction(self.a_toend)
                toolbar.addAction(self.a_step_backward)
                toolbar.addAction(self.a_step_forward)
                toolbar.addAction(self.a_loop)
                if hasattr(self, 'save'):
                    self.a_save = QAction(self.style().standardIcon(QStyle.SP_DialogSaveButton), 'Save', self)
                    toolbar.addAction(self.a_save)
                    self.a_save.triggered.connect(self.save)
                hlayout.addWidget(toolbar)

                self.speed = QSlider(Qt.Horizontal)
                self.speed.setMinimum(0)
                self.speed.setMaximum(100)
                hlayout.addWidget(QLabel('Speed:'))
                hlayout.addWidget(self.speed)

                layout.addLayout(hlayout)

                self.timer = QTimer()
                self.timer.timeout.connect(self.update_solution)

                self.slider.valueChanged.connect(self.slider_changed)
                self.slider.valueChanged.connect(lcd.display)
                self.speed.valueChanged.connect(self.speed_changed)
                self.a_play.toggled.connect(self.toggle_play)
                self.a_rewind.triggered.connect(self.rewind)
                self.a_toend.triggered.connect(self.to_end)
                self.a_step_forward.triggered.connect(self.step_forward)
                self.a_step_backward.triggered.connect(self.step_backward)

                self.speed.setValue(50)

            elif hasattr(self, 'save'):
                hlayout = QHBoxLayout()
                toolbar = QToolBar()
                self.a_save = QAction(self.style().standardIcon(QStyle.SP_DialogSaveButton), 'Save', self)
                toolbar.addAction(self.a_save)
                hlayout.addWidget(toolbar)
                layout.addLayout(hlayout)
                self.a_save.triggered.connect(self.save)

            self.setLayout(layout)
            self.plot = plot
            self.U = U
            self.length = length

        def slider_changed(self, ind):
            self.plot.set(self.U, ind)

        def speed_changed(self, val):
            self.timer.setInterval(val * 20)

        def update_solution(self):
            ind = self.slider.value() + 1
            if ind >= self.length:
                if self.a_loop.isChecked():
                    ind = 0
                else:
                    self.a_play.setChecked(False)
                    return
            self.slider.setValue(ind)

        def toggle_play(self, checked):
            if checked:
                if self.slider.value() + 1 == self.length:
                    self.slider.setValue(0)
                self.timer.start()
            else:
                self.timer.stop()

        def rewind(self):
            self.slider.setValue(0)

        def to_end(self):
            self.a_play.setChecked(False)
            self.slider.setValue(self.length - 1)

        def step_forward(self):
            self.a_play.setChecked(False)
            ind = self.slider.value() + 1
            if ind == self.length and self.a_loop.isChecked():
                ind = 0
            if ind < self.length:
                self.slider.setValue(ind)

        def step_backward(self):
            self.a_play.setChecked(False)
            ind = self.slider.value() - 1
            if ind == -1 and self.a_loop.isChecked():
                ind = self.length - 1
            if ind >= 0:
                self.slider.setValue(ind)
Exemplo n.º 3
0
class ToolTipWidget(QWidget, object):

    hidden = Signal()

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

        self._layout = None
        self._content = None
        self._content_parent = None
        self._hide_timer = QTimer(self)

        self._init()

    def enterEvent(self, event):
        if self.hide_delay() > 0:
            self._hide_timer.stop()
        else:
            self.hide()

    def hideEvent(self, event):
        self._remove_widget()
        QTimer.singleShot(0, self.hidden.emit)

    def leaveEvent(self, event):
        self.hide()

    # def paintEvent(self, event):
    #     painter = QStylePainter(self)
    #     painter.setClipRegion(event.region())
    #     option = QStyleOptionFrame()
    #     option.init(self)
    #     painter.drawPrimitive(QStyle.PE_PanelTipLabel, option)
    #     painter.end()
    #
    #     super(ToolTipWidget, self).paintEvent(event)

    def show_at(self, pos, content, parent_window=None):
        """
        Shows tooltip in given position and with given widget
        :param pos: QPoint
        :param content: QWidget
        :param parent_window: QWindow
        """

        parent_window = parent_window or dcc.get_main_window().windowHandle()

        self._add_widget(content)
        self._show(pos, parent_window)

    def show_below(self, rect, content, parent_window=None):
        """
        Shows tooltip below given rect and with given content
        :param rect: QRect
        :param content: QWidget
        :param parent_window: QWindow
        """

        parent_window = parent_window or dcc.get_main_window().windowHandle()

        self._add_widget(content)
        margin_size = QSize(
            2 * content.style().pixelMetric(QStyle.PM_DefaultTopLevelMargin),
            2 * content.style().pixelMetric(QStyle.PM_DefaultTopLevelMargin)
        )
        content.setMaximumSize(parent_window.screen().geometry().size() - margin_size)
        self._show(self._center_below(rect, parent_window.screen()), parent_window)

    def hide_delay(self):
        """
        Returns timer hide interval
        :return: float
        """

        return self._hide_timer.interval()

    def set_hide_delay(self, hide_delay_interval):
        """
        Sets the delay timer value
        :param hide_delay_interval: float
        """

        self._hide_timer.setInterval(hide_delay_interval)

    def hide_later(self):
        """
        Hides tooltip if timer is over
        """

        if not self.isVisible():
            return

        if self.hide_delay() > 0:
            self._hide_timer.start()
        else:
            self.hide()

    def _init(self):
        """
        Internal function that initializes tooltip widget
        """

        self.setMouseTracking(True)
        self._layout = layouts.VerticalLayout(parent=self)
        self._hide_timer.setSingleShot(True)
        self._hide_timer.setInterval(500)
        self._hide_timer.timeout.connect(self._on_timer_timeout)
        # self.setAttribute(Qt.WA_TranslucentBackground)
        self.setWindowFlags(Qt.ToolTip | Qt.FramelessWindowHint | Qt.NoDropShadowWindowHint)

    def _add_widget(self, widget):
        """
        Internal function that adds replaces current contained wiget with the given one
        :param widget: QWidget
        """

        self._remove_widget()
        self._content = widget
        self._store_parent()
        self._layout.addWidget(self._content)
        widget.destroyed.connect(widget.hide)

    def _remove_widget(self):
        """
        Internal function that removes current contained widget from the tooltip
        """

        self._layout.removeWidget(self._content)
        self._restore_parent()

    def _show(self, pos, parent_window):

        if not pos or pos.isNull():
            return

        offset_pos = QPoint(pos.x() - 5, pos.y() - 5)

        self.move(offset_pos)
        self.createWinId()
        self.windowHandle().setProperty('ENABLE_BLUR_BEHIND_HINT', True)
        self.windowHandle().setTransientParent(parent_window)

        self.show()

    def _store_parent(self):
        """
        Internal function that stores parent of current contained widget
        """

        if not self._content:
            return

        self._content_parent = self._content.parent()

    def _restore_parent(self):
        """
        Internal function that reparent current contained widget to current tooltip parent widget
        """

        if not self._content or not self._content_parent:
            return

        self._content.setParent(self._content_parent)

    def _center_below(self, rect, screen):
        """
        Internal function that returns a position for the tooltip ensuring that:
            1) The content is fully visible
            2) The content is not drawn inside rect
        :param rect: QRect
        :param screen: QScreen
        :return: QPoint
        """

        size = self.sizeHint()
        margin = self.style().pixelMetric(QStyle.PM_ToolTipLabelFrameWidth)
        screen_geometry = screen.geometry()

        has_room_to_left = (rect.left() - size.width() - margin >= screen_geometry.left())
        has_room_to_right = (rect.right() + size.width() + margin <= screen_geometry.right())
        has_room_above = (rect.top() - size.height() - margin >= screen_geometry.top())
        has_room_below = (rect.bottom() + size.height() + margin <= screen_geometry.bottom())
        if not has_room_above and not has_room_below and not has_room_to_left and not has_room_to_right:
            return QPoint()

        x = 0
        y = 0
        if has_room_below or has_room_above:
            x = max(screen_geometry.left(), rect.center().x() - size.width() / 2)
            if x + size.width() >= screen_geometry.right():
                x = screen_geometry.right() - size.width() + 1
            assert x >= 0
            if has_room_below:
                y = rect.bottom() + margin
            else:
                y = rect.top() - size.height() - margin + 1
        else:
            assert has_room_to_left or has_room_to_right
            if has_room_to_right:
                x = rect.right() + margin
            else:
                x = rect.left() - size.width() - margin + 1

            # Put tooltip at the bottom of the screen. The x-coordinate has already been adjusted,
            # so no overlapping with rect occurs
            y = screen_geometry.bottom() - size.height() + 1

        return QPoint(x, y)

    def _on_timer_timeout(self):
        self.hide()
Exemplo n.º 4
0
    class PlotMainWindow(QWidget):
        """Base class for plot main windows."""
        def __init__(self, U, plot, length=1, title=None):
            super().__init__()

            layout = QVBoxLayout()

            if title:
                title = QLabel('<b>' + title + '</b>')
                title.setAlignment(Qt.AlignHCenter)
                layout.addWidget(title)
            layout.addWidget(plot)

            plot.set(U, 0)

            if length > 1:
                hlayout = QHBoxLayout()

                self.slider = QSlider(Qt.Horizontal)
                self.slider.setMinimum(0)
                self.slider.setMaximum(length - 1)
                self.slider.setTickPosition(QSlider.TicksBelow)
                hlayout.addWidget(self.slider)

                lcd = QLCDNumber(m.ceil(m.log10(length)))
                lcd.setDecMode()
                lcd.setSegmentStyle(QLCDNumber.Flat)
                hlayout.addWidget(lcd)

                layout.addLayout(hlayout)

                hlayout = QHBoxLayout()

                toolbar = QToolBar()
                self.a_play = QAction(
                    self.style().standardIcon(QStyle.SP_MediaPlay), 'Play',
                    self)
                self.a_play.setCheckable(True)
                self.a_rewind = QAction(
                    self.style().standardIcon(QStyle.SP_MediaSeekBackward),
                    'Rewind', self)
                self.a_toend = QAction(
                    self.style().standardIcon(QStyle.SP_MediaSeekForward),
                    'End', self)
                self.a_step_backward = QAction(
                    self.style().standardIcon(QStyle.SP_MediaSkipBackward),
                    'Step Back', self)
                self.a_step_forward = QAction(
                    self.style().standardIcon(QStyle.SP_MediaSkipForward),
                    'Step', self)
                self.a_loop = QAction(
                    self.style().standardIcon(QStyle.SP_BrowserReload), 'Loop',
                    self)
                self.a_loop.setCheckable(True)
                toolbar.addAction(self.a_play)
                toolbar.addAction(self.a_rewind)
                toolbar.addAction(self.a_toend)
                toolbar.addAction(self.a_step_backward)
                toolbar.addAction(self.a_step_forward)
                toolbar.addAction(self.a_loop)
                if hasattr(self, 'save'):
                    self.a_save = QAction(
                        self.style().standardIcon(QStyle.SP_DialogSaveButton),
                        'Save', self)
                    toolbar.addAction(self.a_save)
                    self.a_save.triggered.connect(self.save)
                hlayout.addWidget(toolbar)

                self.speed = QSlider(Qt.Horizontal)
                self.speed.setMinimum(0)
                self.speed.setMaximum(100)
                hlayout.addWidget(QLabel('Speed:'))
                hlayout.addWidget(self.speed)

                layout.addLayout(hlayout)

                self.timer = QTimer()
                self.timer.timeout.connect(self.update_solution)

                self.slider.valueChanged.connect(self.slider_changed)
                self.slider.valueChanged.connect(lcd.display)
                self.speed.valueChanged.connect(self.speed_changed)
                self.a_play.toggled.connect(self.toggle_play)
                self.a_rewind.triggered.connect(self.rewind)
                self.a_toend.triggered.connect(self.to_end)
                self.a_step_forward.triggered.connect(self.step_forward)
                self.a_step_backward.triggered.connect(self.step_backward)

                self.speed.setValue(50)

            elif hasattr(self, 'save'):
                hlayout = QHBoxLayout()
                toolbar = QToolBar()
                self.a_save = QAction(
                    self.style().standardIcon(QStyle.SP_DialogSaveButton),
                    'Save', self)
                toolbar.addAction(self.a_save)
                hlayout.addWidget(toolbar)
                layout.addLayout(hlayout)
                self.a_save.triggered.connect(self.save)

            self.setLayout(layout)
            self.plot = plot
            self.U = U
            self.length = length

        def slider_changed(self, ind):
            self.plot.set(self.U, ind)

        def speed_changed(self, val):
            self.timer.setInterval(val * 20)

        def update_solution(self):
            ind = self.slider.value() + 1
            if ind >= self.length:
                if self.a_loop.isChecked():
                    ind = 0
                else:
                    self.a_play.setChecked(False)
                    return
            self.slider.setValue(ind)

        def toggle_play(self, checked):
            if checked:
                if self.slider.value() + 1 == self.length:
                    self.slider.setValue(0)
                self.timer.start()
            else:
                self.timer.stop()

        def rewind(self):
            self.slider.setValue(0)

        def to_end(self):
            self.a_play.setChecked(False)
            self.slider.setValue(self.length - 1)

        def step_forward(self):
            self.a_play.setChecked(False)
            ind = self.slider.value() + 1
            if ind == self.length and self.a_loop.isChecked():
                ind = 0
            if ind < self.length:
                self.slider.setValue(ind)

        def step_backward(self):
            self.a_play.setChecked(False)
            ind = self.slider.value() - 1
            if ind == -1 and self.a_loop.isChecked():
                ind = self.length - 1
            if ind >= 0:
                self.slider.setValue(ind)
Exemplo n.º 5
0
    def ui(self):
        super(BaseToast, self).ui()

        self.setWindowFlags(Qt.FramelessWindowHint | Qt.Dialog
                            | Qt.WA_TranslucentBackground
                            | Qt.WA_DeleteOnClose)
        self.setAttribute(Qt.WA_StyledBackground)
        self.setFixedSize(QSize(120, 120))

        icon_layout = layouts.HorizontalLayout()
        icon_layout.addStretch()

        widget_theme = self.theme()

        if self._toast_type == self.ToastTypes.LOADING:
            icon_layout.addWidget(
                loading.CircleLoading(size=widget_theme.huge,
                                      color=widget_theme.text_color_inverse))
        else:
            icon_label = avatar.Avatar()
            icon_label.theme_size = 60
            icon_label.image = resources.pixmap(
                self._toast_type or self.ToastTypes.INFO,
                color=widget_theme.text_color_inverse)
            icon_layout.addWidget(icon_label)
        icon_layout.addStretch()

        content_label = label.BaseLabel()
        content_label.setText(self._text or '')
        content_label.setAlignment(Qt.AlignCenter)

        self.main_layout.addStretch()
        self.main_layout.addLayout(icon_layout)
        self.main_layout.addSpacing(10)
        self.main_layout.addWidget(content_label)
        self.main_layout.addStretch()

        close_timer = QTimer(self)
        close_timer.setSingleShot(True)
        close_timer.timeout.connect(self.close)
        close_timer.timeout.connect(self.toastClosed.emit)
        close_timer.setInterval(
            (self._duration or self.DEFAULT_CONFIG.get('duration', 2)) * 1000)

        anim_timer = QTimer(self)
        anim_timer.timeout.connect(self._fade_out)
        anim_timer.setInterval(
            (self._duration or self.DEFAULT_CONFIG.get('duration', 2)) * 1000 -
            300)

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

        close_timer.start()
        anim_timer.start()

        self._get_center_position(self._parent)
        self._fade_in()
Exemplo n.º 6
0
class SliderPanel(base.BaseWidget, object):
    """
    Panel that slides in from the edge of the window
    """

    closed = Signal()
    closeButtonClicked = Signal()

    def __init__(self,
                 title,
                 position=SliderPanelPositions.RIGHT,
                 closable=True,
                 parent=None):

        self._title = title
        self._position = position
        self._closable = closable
        self._is_first_close = True

        super(SliderPanel, self).__init__(parent)

        self.setObjectName('sliderPanel')
        self.setWindowFlags(Qt.Popup)
        self.setAttribute(Qt.WA_StyledBackground)

        self._close_timer = QTimer(self)
        self._close_timer.setInterval(300)
        self._close_timer.setSingleShot(True)
        self._close_timer.timeout.connect(self.close)
        self._close_timer.timeout.connect(self.closed.emit)

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

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

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

    @property
    def position(self):
        """
        Returns the placement of the panel in parent window
        :return: str
        """

        return self._position

    @position.setter
    def position(self, value):
        """
        Sets the position of the panel in parent window ('top', 'right', 'bottom' or 'left').
        :param value: str
        """

        self._position = value
        if value in [SliderPanelPositions.BOTTOM, SliderPanelPositions.TOP]:
            self.setFixedHeight(200)
        else:
            self.setFixedWidth(200)

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

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

        self._title_label = label.BaseLabel(parent=self).h4()
        self._title_label.setText(self._title)

        self._close_btn = buttons.BaseToolButton(
            parent=self).icon_only().image('close', theme='window').small()
        self._close_btn.setVisible(self._closable or False)

        title_layout = layouts.HorizontalLayout()
        title_layout.addWidget(self._title_label)
        title_layout.addStretch()
        title_layout.addWidget(self._close_btn)

        self._button_layout = layouts.HorizontalLayout()
        self._button_layout.addStretch()

        self._scroll_area = QScrollArea()
        self.main_layout.addLayout(title_layout)
        self.main_layout.addWidget(dividers.Divider())
        self.main_layout.addWidget(self._scroll_area)
        self.main_layout.addWidget(dividers.Divider())
        self.main_layout.addLayout(self._button_layout)

    def setup_signals(self):
        self._close_btn.clicked.connect(self.close)
        self._close_btn.clicked.connect(self.closeButtonClicked.emit)

    def show(self):
        self._update_position()
        self._fade_in()

        return super(SliderPanel, self).show()

    def closeEvent(self, event):
        if self._is_first_close:
            self._is_first_close = False
            self._close_timer.stop()
            self._fade_out()
            self.closed.emit()
            event.ignore()
        else:
            event.accept()

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

    def set_widget(self, widget):
        """
        Sets the widget that will be contained inside the panel
        :param widget: QWidget
        """

        self._scroll_area.setWidget(widget)

    def add_button(self, button):
        """
        Adds a new button to the bottom part of the panel
        :param button: QPushButton
        """

        self._button_layout.addWidget(button)

    def left(self):
        """
        Sets the panel's placement to left
        :return: SliderPanel
        """

        self.position = SliderPanelPositions.LEFT

        return self

    def right(self):
        """
        Sets the panel's placement to right
        :return: SliderPanel
        """

        self.position = SliderPanelPositions.RIGHT

        return self

    def top(self):
        """
        Sets the panel's placement to top
        :return: SliderPanel
        """

        self.position = SliderPanelPositions.TOP

        return self

    def bottom(self):
        """
        Sets the panel's placement to bottom
        :return: SliderPanel
        """

        self.position = SliderPanelPositions.BOTTOM

        return self

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

    def _fade_in(self):
        """
        Internal function that fades in the panel
        """

        self._pos_anim.start()
        self._opacity_anim.start()

    def _fade_out(self):
        """
        Internal function that fades out the panel
        """

        self._pos_anim.setDirection(QAbstractAnimation.Backward)
        self._pos_anim.start()
        self._opacity_anim.setDirection(QAbstractAnimation.Backward)
        self._opacity_anim.start()

    def _update_position(self):
        """
        Internal function that makes sure that panel is positioned in the proper place
        """

        parent = self.parent()
        parent_parent = parent.parent()
        dcc_win = dcc.get_main_window()
        dcc_window = parent_parent == dcc_win
        if parent_parent and dcc_win:
            dcc_window = dcc_window or parent_parent.objectName(
            ) == dcc_win.objectName()
        parent_geo = parent.geometry()
        if self._position == SliderPanelPositions.LEFT:
            pos = parent_geo.topLeft() if dcc_window else parent.mapToGlobal(
                parent_geo.topLeft())
            target_x = pos.x()
            target_y = pos.y()
            self.setFixedHeight(parent_geo.height())
            self._pos_anim.setStartValue(
                QPoint(target_x - self.width(), target_y))
            self._pos_anim.setEndValue(QPoint(target_x, target_y))
        if self._position == SliderPanelPositions.RIGHT:
            pos = parent_geo.topRight() if dcc_window else parent.mapToGlobal(
                parent_geo.topRight())
            self.setFixedHeight(parent_geo.height())
            target_x = pos.x() - self.width()
            target_y = pos.y()
            self._pos_anim.setStartValue(
                QPoint(target_x + self.width(), target_y))
            self._pos_anim.setEndValue(QPoint(target_x, target_y))
        if self._position == SliderPanelPositions.TOP:
            pos = parent_geo.topLeft(
            ) if dcc_window or 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_anim.setStartValue(
                QPoint(target_x, target_y - self.height()))
            self._pos_anim.setEndValue(QPoint(target_x, target_y))
        if self._position == SliderPanelPositions.BOTTOM:
            pos = parent_geo.bottomLeft(
            ) if dcc_window else parent.mapToGlobal(parent_geo.bottomLeft())
            self.setFixedWidth(parent_geo.width())
            target_x = pos.x()
            target_y = pos.y() - self.height()
            self._pos_anim.setStartValue(
                QPoint(target_x, target_y + self.height()))
            self._pos_anim.setEndValue(QPoint(target_x, target_y))
Exemplo n.º 7
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())