# !/usr/bin/python3
import sys, os
from PyQt5 import QtCore, QtGui, QtWidgets


# Originated from
# https://www.mail-archive.com/pyqt@riverbankcomputing.com/msg22889.html
# Modification refered from
# https://gist.github.com/Riateche/27e36977f7d5ea72cf4f

class RangeSlider(QtWidgets.QSlider):
    sliderMoved = QtCore.pyqtSignal(int, int)

    """ A slider for ranges.

        This class provides a dual-slider for ranges, where there is a defined
        maximum and minimum, as is a normal slider, but instead of having a
        single slider value, there are 2 slider values.

        This class emits the same signals as the QSlider base class, with the 
        exception of valueChanged
    """

    # ----------------------------------------------------------------------
    def __init__(self, *args):
        super().__init__(*args)

        self._low = self.minimum()
        self._high = self.maximum()

        self.pressed_control = QtWidgets.QStyle.SC_None
        self.tick_interval = 0
        self.tick_position = QtWidgets.QSlider.NoTicks
        self.hover_control = QtWidgets.QStyle.SC_None
        self.click_offset = 0

        # 0 for the low, 1 for the high, -1 for both
        self.active_slider = 0

    # ----------------------------------------------------------------------
    def low(self):
        return self._low

    # ----------------------------------------------------------------------
    def setLow(self, low: int):
        self._low = low
        self.update()

    # ----------------------------------------------------------------------
    def high(self):
        return self._high

    # ----------------------------------------------------------------------
    def setHigh(self, high):
        self._high = high
        self.update()

    # ----------------------------------------------------------------------
    def paintEvent(self, event):
        # based on http://qt.gitorious.org/qt/qt/blobs/master/src/gui/widgets/qslider.cpp

        painter = QtGui.QPainter(self)
        style = QtWidgets.QApplication.style()

        # draw groove
        opt = QtWidgets.QStyleOptionSlider()
        self.initStyleOption(opt)
        opt.siderValue = 0
        opt.sliderPosition = 0
        opt.subControls = QtWidgets.QStyle.SC_SliderGroove
        if self.tickPosition() != self.NoTicks:
            opt.subControls |= QtWidgets.QStyle.SC_SliderTickmarks
        style.drawComplexControl(QtWidgets.QStyle.CC_Slider, opt, painter, self)
        groove = style.subControlRect(QtWidgets.QStyle.CC_Slider, opt, QtWidgets.QStyle.SC_SliderGroove, self)

        self.initStyleOption(opt)
        opt.subControls = QtWidgets.QStyle.SC_SliderGroove

        opt.siderValue = 0
        opt.sliderPosition = self._low
        low_rect = style.subControlRect(QtWidgets.QStyle.CC_Slider, opt, QtWidgets.QStyle.SC_SliderHandle, self)
        opt.sliderPosition = self._high
        high_rect = style.subControlRect(QtWidgets.QStyle.CC_Slider, opt, QtWidgets.QStyle.SC_SliderHandle, self)

        low_pos = self.__pick(low_rect.center())
        high_pos = self.__pick(high_rect.center())

        min_pos = min(low_pos, high_pos)
        max_pos = max(low_pos, high_pos)

        c = QtCore.QRect(low_rect.center(), high_rect.center()).center()
        if opt.orientation == QtCore.Qt.Horizontal:
            span_rect = QtCore.QRect(QtCore.QPoint(min_pos, c.y() - 2), QtCore.QPoint(max_pos, c.y() + 1))
        else:
            span_rect = QtCore.QRect(QtCore.QPoint(c.x() - 2, min_pos), QtCore.QPoint(c.x() + 1, max_pos))

        if opt.orientation == QtCore.Qt.Horizontal:
            groove.adjust(0, 0, -1, 0)
        else:
            groove.adjust(0, 0, 0, -1)

        highlight = self.palette().color(QtGui.QPalette.Highlight)
        painter.setBrush(QtGui.QBrush(highlight))
        painter.setPen(QtGui.QPen(highlight, 0))

        painter.drawRect(span_rect.intersected(groove))

        for i, value in enumerate([self._low, self._high]):
            opt = QtWidgets.QStyleOptionSlider()
            self.initStyleOption(opt)

            # Only draw the groove for the first slider so it doesn't get drawn
            # on top of the existing ones every time
            if i == 0:
                opt.subControls = QtWidgets.QStyle.SC_SliderHandle  # | QtWidgets.QStyle.SC_SliderGroove
            else:
                opt.subControls = QtWidgets.QStyle.SC_SliderHandle

            if self.tickPosition() != self.NoTicks:
                opt.subControls |= QtWidgets.QStyle.SC_SliderTickmarks

            if self.pressed_control:
                opt.activeSubControls = self.pressed_control
            else:
                opt.activeSubControls = self.hover_control

            opt.sliderPosition = value
            opt.sliderValue = value
            style.drawComplexControl(QtWidgets.QStyle.CC_Slider, opt, painter, self)

    # ----------------------------------------------------------------------
    def __pick(self, pt):
        if self.orientation() == QtCore.Qt.Horizontal:
            return pt.x()
        else:
            return pt.y()

    # # ----------------------------------------------------------------------
    # def mousePressEvent(self, event):
    #     event.accept()
    #
    #     style = QtWidgets.QApplication.style()
    #     button = event.button()
    #
    #     # In a normal slider control, when the user clicks on a point in the
    #     # slider's total range, but not on the slider part of the control the
    #     # control would jump the slider value to where the user clicked.
    #     # For this control, clicks which are not direct hits will slide both
    #     # slider parts
    #
    #     if button:
    #         opt = QtWidgets.QStyleOptionSlider()
    #         self.initStyleOption(opt)
    #
    #         self.active_slider = -1
    #
    #         for i, value in enumerate([self._low, self._high]):
    #             opt.sliderPosition = value
    #             hit = style.hitTestComplexControl(style.CC_Slider, opt, event.pos(), self)
    #             if hit == style.SC_SliderHandle:
    #                 self.active_slider = i
    #                 self.pressed_control = hit
    #
    #                 self.triggerAction(self.SliderMove)
    #                 self.setRepeatAction(self.SliderNoAction)
    #                 self.setSliderDown(True)
    #                 break
    #
    #         if self.active_slider < 0:
    #             self.pressed_control = QtWidgets.QStyle.SC_SliderHandle
    #             self.click_offset = self.__pixelPosToRangeValue(self.__pick(event.pos()))
    #             self.triggerAction(self.SliderMove)
    #             self.setRepeatAction(self.SliderNoAction)
    #     else:
    #         event.ignore()
    #
    # # ----------------------------------------------------------------------
    # def mouseMoveEvent(self, event):
    #     if self.pressed_control != QtWidgets.QStyle.SC_SliderHandle:
    #         event.ignore()
    #         return
    #
    #     event.accept()
    #     new_pos = self.__pixelPosToRangeValue(self.__pick(event.pos()))
    #     opt = QtWidgets.QStyleOptionSlider()
    #     self.initStyleOption(opt)
    #
    #     if self.active_slider < 0:
    #         offset = new_pos - self.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
    #     elif self.active_slider == 0:
    #         if new_pos >= self._high:
    #             new_pos = self._high - 1
    #         self._low = new_pos
    #     else:
    #         if new_pos <= self._low:
    #             new_pos = self._low + 1
    #         self._high = new_pos
    #
    #     self.click_offset = new_pos
    #
    #     self.update()
    #
    #     # self.emit(QtCore.SIGNAL('sliderMoved(int)'), new_pos)
    #     self.sliderMoved.emit(self._low, self._high)
    #
    # # ----------------------------------------------------------------------
    # def __pixelPosToRangeValue(self, pos):
    #     opt = QtWidgets.QStyleOptionSlider()
    #     self.initStyleOption(opt)
    #     style = QtWidgets.QApplication.style()
    #
    #     gr = style.subControlRect(style.CC_Slider, opt, style.SC_SliderGroove, self)
    #     sr = style.subControlRect(style.CC_Slider, opt, style.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 style.sliderValueFromPosition(self.minimum(), self.maximum(),
    #                                          pos - slider_min, slider_max - slider_min,
    #                                          opt.upsideDown)