def paintEvent(self, event):
        # based on
        # https://github.com/qt/qtbase/blob/f40dbe0d0b54ce83d2168e82905cf4f75059a841/src/widgets/widgets/qslider.cpp#L315
        # https://github.com/enthought/traitsui/blob/master/traitsui/qt4/extra/range_slider.py
        painter = QStylePainter(self)
        minpos = self.__min_position
        maxpos = self.__max_position

        # Draw the groove
        opt = QStyleOptionSlider()
        self.initStyleOption(opt)
        # Draw empty grove
        opt.sliderPosition = opt.minimum
        opt.subControls = QStyle.SC_SliderGroove
        if self.tickPosition() != self.NoTicks:
            opt.subControls |= QStyle.SC_SliderTickmarks
        painter.drawComplexControl(QStyle.CC_Slider, opt)
        # Draw the highlighted part on top
        # Qt4.8 and Qt5.3 draw the highlighted groove in a weird way because they
        # transpose opt.rect. Qt5.7 works fine.
        if QT_VERSION_STR >= '5.7.0':
            opt.subControls = QStyle.SC_SliderGroove
            opt.sliderPosition = opt.maximum
            if self.orientation() == Qt.Horizontal:
                _w = opt.rect.width() / opt.maximum
                x = round(_w * minpos)
                w = round(_w * (maxpos - minpos))
                opt.rect = QRect(x, 0, w, opt.rect.height())
            else:
                _h = opt.rect.height() / opt.maximum
                y = round(_h * minpos)
                h = round(_h * (maxpos - minpos))
                opt.rect = QRect(0, y, opt.rect.width(), h)
            painter.drawComplexControl(QStyle.CC_Slider, opt)

        # Draw the handles
        for i, position in enumerate((minpos, maxpos)):
            opt = QStyleOptionSlider()
            self.initStyleOption(opt)
            opt.subControls = QStyle.SC_SliderHandle

            if self.__pressed_control and (self.__active_slider == i or
                                           self.__active_slider < 0):
                opt.activeSubControls = self.__pressed_control
                opt.state |= QStyle.State_Sunken
            else:
                opt.activeSubControls = self.__hovered_control

            opt.sliderPosition = position
            opt.sliderValue = position
            painter.drawComplexControl(QStyle.CC_Slider, opt)
Exemple #2
0
    def drawSpan(self, painter, rect):
        opt = QStyleOptionSlider()
        QSlider.initStyleOption(self, opt)

        # area
        groove = self.style().subControlRect(QStyle.CC_Slider, opt,
                                             QStyle.SC_SliderGroove, self)
        if opt.orientation == QtCore.Qt.Horizontal:
            groove.adjust(0, 0, -1, 0)
        else:
            groove.adjust(0, 0, 0, -1)

        # pen & brush
        painter.setPen(QPen(self.gradientLeftColor, 0))
        if opt.orientation == QtCore.Qt.Horizontal:
            self.setupPainter(painter, opt.orientation,
                              groove.center().x(), groove.top(),
                              groove.center().x(), groove.bottom())
        else:
            self.setupPainter(painter, opt.orientation, groove.left(),
                              groove.center().y(), groove.right(),
                              groove.center().y())

        # draw groove
        intersected = QtCore.QRectF(rect.intersected(groove))
        gradient = QLinearGradient(intersected.topLeft(),
                                   intersected.topRight())
        gradient.setColorAt(0, self.gradientLeft)
        gradient.setColorAt(1, self.gradientRight)
        painter.fillRect(intersected, gradient)
    def mouseMoveEvent(self, event):
        if self.__pressed_control not in (QStyle.SC_SliderGroove,
                                          QStyle.SC_SliderHandle):
            event.ignore()
            return

        event.accept()
        opt = QStyleOptionSlider()
        self.initStyleOption(opt)
        pos = self._pixelPosToRangeValue(self._pick(event.pos()))

        if self.__active_slider < 0:
            offset = pos - self.__click_offset
            self.__max_position = min(self.__max_position + offset, self.maximum())
            self.__min_position = max(self.__min_position + offset, self.minimum())
            self.__click_offset = pos
        else:
            if self.__active_slider == 0:
                self.__min_position = max(self.minimum(), pos)
                self.__max_position = min(self.maximum(), max(self.__max_position, self.__min_position + 1))
            else:
                self.__max_position = min(self.maximum(), pos)
                self.__min_position = max(self.minimum(), min(self.__min_position, self.__max_position - 1))

        self.update()
        self.slidersMoved.emit(self.__min_position, self.__max_position)
        # This is different from QAbstractSlider, which sets the value
        # insider triggerAction() which would be called here instead.
        # But I don't want to override that as well, so simply:
        if self.hasTracking():
            self.setValues(self.__min_position, self.__max_position)
    def mousePressEvent(self, event):
        if not event.button():
            event.ignore()
            return

        event.accept()
        opt = QStyleOptionSlider()
        self.initStyleOption(opt)
        self.__active_slider = -1

        for i, value in enumerate((self.__min_position, self.__max_position)):
            opt.sliderPosition = value
            if self._hitTestHandle(opt, event.pos()):
                self.__active_slider = i
                self.__pressed_control = QStyle.SC_SliderHandle

                self.triggerAction(self.SliderMove)
                self.setRepeatAction(self.SliderNoAction)
                self.setSliderDown(True)
                break
        else:
            # If the user clicks the groove between the handles, the whole
            # interval is moved
            self.__pressed_control = QStyle.SC_SliderGroove
            self.__click_offset = self._pixelPosToRangeValue(self._pick(event.pos()))
            self.triggerAction(self.SliderMove)
            self.setRepeatAction(self.SliderNoAction)
Exemple #5
0
    def mousePressEvent(self, event):
        """ Handle the mouse press event for the control.

        In a typical slider control, when the user clicks on a point in
        the slider's total range but not on the thumbtrack, the control
        would jump to the value of the click location. For this control,
        clicks which are not direct hits will activate both slider
        handles for synchronized moving.

        """
        if event.button() != Qt.LeftButton:
            event.ignore()
            return

        event.accept()
        style = self.style()
        pos = event.pos()
        opt = QStyleOptionSlider()
        self.initStyleOption(opt)
        low, high = self._low, self._high

        # hit-test the high handle
        opt.sliderPosition = high
        high_rect = style.subControlRect(
            style.CC_Slider, opt, style.SC_SliderHandle, self
        )
        high_test = high_rect.contains(pos)

        # hit-test the low handle if needed.
        if high_test:
            low_test = False
        else:
            opt.sliderPosition = low
            low_rect = style.subControlRect(
                style.CC_Slider, opt, style.SC_SliderHandle, self
            )
            low_test = low_rect.contains(pos)

        # Set the internal state for painting and request an update.
        # The click offsets when clicking a thumbtrack are stored in
        # units of pixels. The offset for a click in the empty slider
        # area is stored in units of value.
        self._pressed_control = style.SC_SliderHandle
        if high_test:
            self._active_thumb = self.HighThumb
            self._click_offset = self._pick(pos - high_rect.topLeft())
        elif low_test:
            self._active_thumb = self.LowThumb
            self._click_offset = self._pick(pos - low_rect.topLeft())
        else:
            self._active_thumb = self.BothThumbs
            offset = self._pixelPosToRangeValue(self._pick(pos), opt)
            self._click_offset = offset
        self.setSliderDown(True)
        self.update()
Exemple #6
0
    def paintEvent(self, event):
        """ Override the paint event to draw both slider handles.

        """
        # based on the paintEvent for QSlider:
        # http://qt.gitorious.org/qt/qt/blobs/master/src/gui/widgets/qslider.cpp
        painter = QPainter(self)
        style = self.style()
        low, high = self._low, self._high

        # Draw the low handle along with the groove and ticks.
        opt = QStyleOptionSlider()
        self.initStyleOption(opt)
        opt.subControls = QStyle.SC_SliderGroove | QStyle.SC_SliderHandle
        if self.tickPosition() != self.NoTicks:
            opt.subControls |= QStyle.SC_SliderTickmarks
        if (self._pressed_control and
            self._active_thumb == self.LowThumb or
            self._active_thumb == self.BothThumbs):
            opt.activeSubControls = self._pressed_control
            opt.state |= QStyle.State_Sunken
        else:
            opt.activeSubControls = QStyle.SC_None
        opt.sliderPosition = low
        opt.sliderValue = low
        style.drawComplexControl(QStyle.CC_Slider, opt, painter, self)

        # Draw high handle. The groove and ticks do not need repainting.
        opt = QStyleOptionSlider()
        self.initStyleOption(opt)
        opt.subControls = QStyle.SC_SliderHandle
        if (self._pressed_control and
            self._active_thumb == self.HighThumb or
            self._active_thumb == self.BothThumbs):
            opt.activeSubControls = self._pressed_control
            opt.state |= QStyle.State_Sunken
        else:
            opt.activeSubControls = QStyle.SC_None
        opt.sliderPosition = high
        opt.sliderValue = high
        style.drawComplexControl(QStyle.CC_Slider, opt, painter, self)
Exemple #7
0
    def drawHandle(self, painter, handle):
        opt = QStyleOptionSlider()
        self._initStyleOption(opt, handle)
        opt.subControls = QStyle.SC_SliderHandle
        pressed = self.upperPressed
        if handle == QxtSpanSlider.LowerHandle:
            pressed = self.lowerPressed

        if pressed == QStyle.SC_SliderHandle:
            opt.activeSubControls = pressed
            opt.state |= QStyle.State_Sunken
        painter.drawComplexControl(QStyle.CC_Slider, opt)
    def _subControlRect(self, subcontrol):
        """Replaces QStyle.subControlRect() in _pixelPosToRangeValue().

        Return QRect for subcontrol which is one of
        QStyle.SC_SliderGrove or QStyle.SC_SliderHandle.
        Override this in subclasses that don't use the default groove/handles.

        This is used because PyQt<5.5 doesn't expose QProxyStyle.
        """
        opt = QStyleOptionSlider()
        self.initStyleOption(opt)
        return self.style().subControlRect(QStyle.CC_Slider, opt, subcontrol, self)
Exemple #9
0
    def mouseMoveEvent(self, event):
        """ Handle the mouse move event for the control.

        If the user has previously pressed the control, this will move
        the slider(s) to the appropriate position and request an update.

        """
        if self._pressed_control != QStyle.SC_SliderHandle:
            event.ignore()
            return

        event.accept()
        opt = QStyleOptionSlider()
        self.initStyleOption(opt)
        point = self._pick(event.pos())
        click_offset = self._click_offset

        thumb = self._active_thumb
        if thumb == self.BothThumbs:
            new_pos = self._pixelPosToRangeValue(point, opt)
            offset = new_pos - click_offset
            self._high += offset
            self._low += offset
            if self._low < self.minimum():
                diff = self.minimum() - self._low
                self._low += diff
                self._high += diff
            if self._high > self.maximum():
                diff = self.maximum() - self._high
                self._low += diff
                self._high += diff
            self._click_offset = new_pos
            self.lowValueChanged.emit(new_pos)
            self.highValueChanged.emit(new_pos)
        elif thumb == self.LowThumb:
            new_pos = self._pixelPosToRangeValue(point - click_offset, opt)
            if new_pos >= self._high:
                new_pos = self._high - 1
            self._low = new_pos
            self.lowValueChanged.emit(new_pos)
        elif thumb == self.HighThumb:
            new_pos = self._pixelPosToRangeValue(point - click_offset, opt)
            if new_pos <= self._low:
                new_pos = self._low + 1
            self._high = new_pos
            self.highValueChanged.emit(new_pos)
        else:
            raise ValueError('Invalid thumb enum value.')
        self.update()
Exemple #10
0
    def mouseMoveEvent(self, event):
        if self.lowerPressed != QStyle.SC_SliderHandle and self.upperPressed != QStyle.SC_SliderHandle:
            event.ignore()
            return

        opt = QStyleOptionSlider()
        self.initStyleOption(opt)
        m = self.style().pixelMetric(QStyle.PM_MaximumDragDistance, opt, self)
        newPosition = self.pixelPosToRangeValue(
            self.pick(event.pos()) - self.offset)
        if m >= 0:
            r = self.rect().adjusted(-m, -m, m, m)
            if not r.contains(event.pos()):
                newPosition = self.position

        # pick the preferred handle on the first movement
        if self.firstMovement:
            if self.lower == self.upper:
                if newPosition < self.lowerValue:
                    self.swapControls()
                    self.firstMovement = False
            else:
                self.firstMovement = False

        if self.lowerPressed == QStyle.SC_SliderHandle:
            if self.movement == QxtSpanSlider.NoCrossing:
                newPosition = min(newPosition, self.upper)
            elif self.movement == QxtSpanSlider.NoOverlapping:
                newPosition = min(newPosition, self.upper - 1)

            if (self.movement == QxtSpanSlider.FreeMovement
                    and newPosition > self.upper):
                self.swapControls()
                self.setUpperPosition(newPosition)
            else:
                self.setLowerPosition(newPosition)
        elif self.upperPressed == QStyle.SC_SliderHandle:
            if self.movement == QxtSpanSlider.NoCrossing:
                newPosition = max(newPosition, self.lowerValue)
            elif self.movement == QxtSpanSlider.NoOverlapping:
                newPosition = max(newPosition, self.lowerValue + 1)

            if (self.movement == QxtSpanSlider.FreeMovement
                    and newPosition < self.lower):
                self.swapControls()
                self.setLowerPosition(newPosition)
            else:
                self.setUpperPosition(newPosition)
        event.accept()
Exemple #11
0
 def handleMousePress(self, pos, control, value, handle):
     opt = QStyleOptionSlider()
     self._initStyleOption(opt, handle)
     oldControl = control
     control = self.style().hitTestComplexControl(QStyle.CC_Slider, opt,
                                                  pos, self)
     sr = self.style().subControlRect(QStyle.CC_Slider, opt,
                                      QStyle.SC_SliderHandle, self)
     if control == QStyle.SC_SliderHandle:
         self.position = value
         self.offset = self.pick(pos - sr.topLeft())
         self.lastPressed = handle
         self.setSliderDown(True)
         self.emit(SIGNAL("sliderPressed(PyQt_PyObject)"), handle)
     if control != oldControl:
         self.update(sr)
     return control
Exemple #12
0
    def paintEvent(self, event):
        painter = QStylePainter(self)

        # ticks
        opt = QStyleOptionSlider()
        self.initStyleOption(opt)
        opt.subControls = QStyle.SC_SliderTickmarks
        painter.drawComplexControl(QStyle.CC_Slider, opt)

        # groove
        opt.sliderPosition = 20
        opt.sliderValue = 0
        opt.subControls = QStyle.SC_SliderGroove
        painter.drawComplexControl(QStyle.CC_Slider, opt)

        # handle rects
        opt.sliderPosition = self.lowerPos
        lr = self.style().subControlRect(QStyle.CC_Slider, opt,
                                         QStyle.SC_SliderHandle, self)
        lrv = self.pick(lr.center())
        opt.sliderPosition = self.upperPos
        ur = self.style().subControlRect(QStyle.CC_Slider, opt,
                                         QStyle.SC_SliderHandle, self)
        urv = self.pick(ur.center())

        # span
        minv = min(lrv, urv)
        maxv = max(lrv, urv)
        c = self.style().subControlRect(QStyle.CC_Slider, opt,
                                        QStyle.SC_SliderGroove, self).center()
        spanRect = QRect(QPoint(c.x() - 2, minv), QPoint(c.x() + 1, maxv))
        if self.orientation() == QtCore.Qt.Horizontal:
            spanRect = QRect(QPoint(minv, c.y() - 2), QPoint(maxv, c.y() + 1))
        self.drawSpan(painter, spanRect)

        # handles
        if self.lastPressed == QxtSpanSlider.LowerHandle:
            self.drawHandle(painter, QxtSpanSlider.UpperHandle)
            self.drawHandle(painter, QxtSpanSlider.LowerHandle)
        else:
            self.drawHandle(painter, QxtSpanSlider.LowerHandle)
            self.drawHandle(painter, QxtSpanSlider.UpperHandle)
Exemple #13
0
    def pixelPosToRangeValue(self, pos):
        opt = QStyleOptionSlider()
        self.initStyleOption(opt)

        gr = self.style().subControlRect(QStyle.CC_Slider, opt,
                                         QStyle.SC_SliderGroove, self)
        sr = self.style().subControlRect(QStyle.CC_Slider, opt,
                                         QStyle.SC_SliderHandle, self)
        if self.orientation() == QtCore.Qt.Horizontal:
            slider_length = sr.width()
            slider_min = gr.x()
            slider_max = gr.right() - slider_length + 1
        else:
            slider_length = sr.height()
            slider_min = gr.y()
            slider_max = gr.bottom() - slider_length + 1

        return QStyle.sliderValueFromPosition(self.minimum(), self.maximum(),
                                              pos - slider_min,
                                              slider_max - slider_min,
                                              opt.upsideDown)
Exemple #14
0
 def get_slider_position(self, slider):
     style = slider.style()
     opt = QStyleOptionSlider()
     return style.subControlRect(QStyle.CC_Slider, opt,
                                 QStyle.SC_SliderHandle)