#!/usr/bin/env python
# ---------------------------------------------------------------------------------------------
# Copyright (c) 2011-2012, Ryan Galloway (ryan@rsgalloway.com)
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:
#
# - Redistributions of source code must retain the above copyright notice, this
# list of conditions and the following disclaimer.
#
# - Redistributions in binary form must reproduce the above copyright notice,
# this list of conditions and the following disclaimer in the documentation
# and/or other materials provided with the distribution.
#
# - Neither the name of the software nor the names of its contributors
# may be used to endorse or promote products derived from this software
# without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# ---------------------------------------------------------------------------------------------
# docs and latest version available for download at
# http://rsgalloway.github.com/qrangeslider
# ---------------------------------------------------------------------------------------------
__author__ = "Ryan Galloway <ryan@rsgalloway.com>"
__version__ = "0.1"
# ---------------------------------------------------------------------------------------------
# SUMMARY
# ---------------------------------------------------------------------------------------------
"""
The QRangeSlider class implements a horizontal range slider widget.
"""
# ---------------------------------------------------------------------------------------------
# TODO
# ---------------------------------------------------------------------------------------------
"""
- smoother mouse move event handler
- support splits and joins
- verticle sliders
- ticks
"""
# ---------------------------------------------------------------------------------------------
# IMPORTS
# ---------------------------------------------------------------------------------------------
import os
import sys
from PyQt4 import QtCore
from PyQt4 import QtGui
from PyQt4 import uic
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
_fromUtf8 = lambda s: s
__all__ = ['QRangeSlider']
DEFAULT_CSS = """
QRangeSlider * {
border: 0px;
padding: 0px;
}
QRangeSlider #Head {
background: #222;
}
QRangeSlider #Span {
background: #393;
}
QRangeSlider #Span:active {
background: #282;
}
QRangeSlider #Tail {
background: #222;
}
QRangeSlider > QSplitter::handle {
background: #393;
}
QRangeSlider > QSplitter::handle:vertical {
height: 4px;
}
QRangeSlider > QSplitter::handle:pressed {
background: #ca5;
}
"""
class Ui_Form(object):
"""default range slider form"""
def setupUi(self, Form):
Form.setObjectName(_fromUtf8("QRangeSlider"))
Form.resize(300, 30)
Form.setStyleSheet(_fromUtf8(DEFAULT_CSS))
self.gridLayout = QtGui.QGridLayout(Form)
self.gridLayout.setMargin(0)
self.gridLayout.setSpacing(0)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self._splitter = QtGui.QSplitter(Form)
self._splitter.setMinimumSize(QtCore.QSize(0, 0))
self._splitter.setMaximumSize(QtCore.QSize(16777215, 16777215))
self._splitter.setOrientation(QtCore.Qt.Horizontal)
self._splitter.setObjectName(_fromUtf8("splitter"))
self._head = QtGui.QGroupBox(self._splitter)
self._head.setTitle(_fromUtf8(""))
self._head.setObjectName(_fromUtf8("Head"))
self._handle = QtGui.QGroupBox(self._splitter)
self._handle.setTitle(_fromUtf8(""))
self._handle.setObjectName(_fromUtf8("Span"))
self._tail = QtGui.QGroupBox(self._splitter)
self._tail.setTitle(_fromUtf8(""))
self._tail.setObjectName(_fromUtf8("Tail"))
self.gridLayout.addWidget(self._splitter, 0, 0, 1, 1)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
Form.setWindowTitle(QtGui.QApplication.translate("QRangeSlider", "QRangeSlider", None, QtGui.QApplication.UnicodeUTF8))
class Element(QtGui.QGroupBox):
def __init__(self, parent, main):
super(Element, self).__init__(parent)
self.main = main
def setStyleSheet(self, style):
"""redirect style to parent groupbox"""
self.parent().setStyleSheet(style)
def textColor(self):
"""text paint color"""
return getattr(self, '__textColor', QtGui.QColor(125, 125, 125))
def setTextColor(self, color):
"""set the text paint color"""
if type(color) == tuple and len(color) == 3:
color = QtGui.QColor(color[0], color[1], color[2])
elif type(color) == int:
color = QtGui.QColor(color, color, color)
setattr(self, '__textColor', color)
def paintEvent(self, event):
"""overrides paint event to handle text"""
qp = QtGui.QPainter()
qp.begin(self)
if self.main.drawValues():
self.drawText(event, qp)
qp.end()
class Head(Element):
"""area before the handle"""
def __init__(self, parent, main):
super(Head, self).__init__(parent, main)
def drawText(self, event, qp):
qp.setPen(self.textColor())
qp.setFont(QtGui.QFont('Arial', 10))
qp.drawText(event.rect(), QtCore.Qt.AlignLeft, str(self.main.min()))
class Tail(Element):
"""area after the handle"""
def __init__(self, parent, main):
super(Tail, self).__init__(parent, main)
def drawText(self, event, qp):
qp.setPen(self.textColor())
qp.setFont(QtGui.QFont('Arial', 10))
qp.drawText(event.rect(), QtCore.Qt.AlignRight, str(self.main.max()))
class Handle(Element):
"""handle area"""
def __init__(self, parent, main):
super(Handle, self).__init__(parent, main)
def drawText(self, event, qp):
qp.setPen(self.textColor())
qp.setFont(QtGui.QFont('Arial', 10))
qp.drawText(event.rect(), QtCore.Qt.AlignLeft, str(self.main.start()))
qp.drawText(event.rect(), QtCore.Qt.AlignRight, str(self.main.end()))
def mouseMoveEvent(self, event):
event.accept()
mx = event.globalX()
_mx = getattr(self, '__mx', None)
if not _mx:
setattr(self, '__mx', mx)
dx = 0
else:
dx = mx - _mx
setattr(self, '__mx', mx)
if dx == 0:
event.ignore()
return
elif dx > 0:
dx = 1
elif dx < 0:
dx = -1
s = self.main.start() + dx
e = self.main.end() + dx
if s >= self.main.min() and e <= self.main.max():
self.main.setRange(s, e)
class QRangeSlider(QtGui.QWidget, Ui_Form):
"""
The QRangeSlider class implements a horizontal range slider widget.
Inherits QWidget.
Methods
* __init__ (self, QWidget parent = None)
* bool drawValues (self)
* int end (self)
* (int, int) getRange (self)
* int max (self)
* int min (se