import sys
from past.utils import old_div
from schrodinger.Qt import QtCore
from schrodinger.Qt import QtWidgets
from schrodinger.Qt.QtCore import QPointF
from schrodinger.Qt.QtCore import QRectF
from schrodinger.Qt.QtGui import QBrush
from schrodinger.Qt.QtGui import QColor
from schrodinger.Qt.QtGui import QLinearGradient
from schrodinger.Qt.QtGui import QPainter
from schrodinger.Qt.QtGui import QPen
from schrodinger.Qt.QtWidgets import QColorDialog
from schrodinger.Qt.QtWidgets import QComboBox
from schrodinger.Qt.QtWidgets import QGraphicsScene
from schrodinger.Qt.QtWidgets import QGraphicsView
from schrodinger.Qt.QtWidgets import QPushButton
from schrodinger.Qt.QtWidgets import QVBoxLayout
from schrodinger.Qt.QtWidgets import QWidget
[docs]class GradientSelectorView(QGraphicsView):
[docs] def __init__(self):
QGraphicsView.__init__(self)
self._select = None
self.rescale(self.width())
self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
self.setRenderHints(QPainter.Antialiasing)
border = 8
self.setScene(QGraphicsScene(-10000, -10000, 20000, 20000))
self.fitInView(0 - border, 0 - border, self._scale + 2 * border,
0 + 2 * border, QtCore.Qt.KeepAspectRatio)
self._select = GradientSelector(self)
self.scene().addItem(self._select)
self.scene().addItem(self._select._ghostColor)
c1 = self.addColorStop(0., QColor(0, 0, 0))
c2 = self.addColorStop(1., QColor(255, 0, 0))
c1._fixed = True
c2._fixed = True
self._grabbedColor = None
self.setMouseTracking(True)
gradientUpdated = QtCore.pyqtSignal()
preciseGradientUpdated = QtCore.pyqtSignal()
[docs] def setLimits(self, m, M):
self._select.setLimits(m, M)
[docs] def setValues(self, values):
self._select.setValues(values)
[docs] def colorAt(self, x):
return self._select.colorAt(x)
[docs] def resizeEvent(self, event):
self.rescale(event.size().width())
border = 15
self.fitInView(0 - border, 0 - border, self._scale + 2 * border,
0 + 2 * border, QtCore.Qt.KeepAspectRatio)
[docs] def rescale(self, width):
self._scale = width
if (self._select):
for color in self._select._colors:
color.moveTo(color.getX())
[docs] def mouseReleaseEvent(self, event):
if self._grabbedColor and self._mouseTravelledDistance < 1:
color = QColorDialog.getColor(self._grabbedColor.getColor(), None,
"Choose Color")
self._grabbedColor.setColor(color)
if self._grabbedColor:
self.gradientUpdated.emit()
self._grabbedColor = None
self._grabbedColorDeleted = False
[docs] def grabbedColorMoveEvent(self, event):
self._mouseTravelledDistance += (
event.pos() - self._lastMousePress).manhattanLength()
self._lastMousePress = event.pos()
if self._grabbedColor._fixed:
return
scenePos = self.mapToScene(event.pos())
x = old_div(scenePos.x(), self._scale)
y = scenePos.y()
if (y < 0 or y > 20):
if not self._grabbedColorDeleted:
self._select.removeColor(self._grabbedColor)
self._grabbedColorDeleted = True
else:
if self._grabbedColorDeleted:
self._select.addColor(self._grabbedColor)
self._grabbedColorDeleted = False
if (x > 0 and x < 1):
self._grabbedColor.moveTo(x)
[docs] def mouseMoveEvent(self, event):
if (self._grabbedColor):
self.grabbedColorMoveEvent(event)
return
p = event.pos()
sceneP = self.mapToScene(p)
x = old_div(sceneP.x(), self._scale)
y = sceneP.y()
if (y < 0 or y > 20):
self._select._ghostColor.hide()
return
item = self.scene().itemAt(sceneP)
if (item and item != self._select._ghostColor):
self._select._ghostColor.hide()
return
if (x > 0 and x < 1):
self._select._ghostColor.show()
self._select._ghostColor.moveTo(x)
self._select._ghostColor.setColor(self._select.colorAt(x))
[docs] def mousePressEvent(self, event):
self._grabbedColor = None
p = event.pos()
sceneP = self.mapToScene(p)
item = self.scene().itemAt(sceneP)
if item and not item._ghost:
self._grabbedColor = item
self._lastMousePress = p
self._mouseTravelledDistance = 0
return
if (self._select._ghostColor.isVisible()):
self.addColorStop(self._select._ghostColor.getX(),
self._select._ghostColor.getColor())
self._select._ghostColor.hide()
[docs] def addColorStop(self, x, color):
color = ColorSelector(x, color, self._select)
self._select.addColor(color)
return color
[docs]class GradientSelector(QtWidgets.QGraphicsItem):
[docs] def __init__(self, view):
QtWidgets.QGraphicsItem.__init__(self)
self.setPos(0, 0)
self._colors = []
self._view = view
self._gradient = QLinearGradient(0, 0, self._view._scale, 0)
self.recalculateGradient()
self._ghostColor = ColorSelector(0.5, self.colorAt(0.5), self)
self._ghostColor.setZValue(-1)
self._ghostColor._ghost = True
self._ghostColor.setOpacity(0.2)
self._ghostColor.hide()
self._grabbedColor = None
self._grabbedColorDeleted = False
self._shownValues = []
self._barHeight = 10
self.setLimits(0., 1.)
[docs] def setLimits(self, minim, maxim):
self._min = minim
self._max = maxim
[docs] def setValues(self, values):
span = self._max - self._min
self._shownValues = [old_div((x - self._min), span) for x in values]
self.update()
[docs] def mousePressEvent(self, event):
pass
[docs] def mouseReleaseEvent(self, event):
pass
[docs] def addColor(self, color):
self._colors.append(color)
self._colors.sort(key=lambda col: col.getX())
self._view.scene().addItem(color)
self.recalculateGradient()
[docs] def removeColor(self, color):
self._colors.remove(color)
self._view.scene().removeItem(color)
self.recalculateGradient()
[docs] def colorAt(self, x):
lastColor = None
if x <= 0.:
return self._colors[0].getColor()
elif x >= 1.:
return self._colors[-1].getColor()
for color in self._colors:
if lastColor is None:
lastColor = color
continue
newx = color.getX()
if (newx > x):
oldx = lastColor.getX()
f = old_div((x - oldx), (newx - oldx))
newColor = color.getColor()
oldColor = lastColor.getColor()
redF = oldColor.redF() * (1 - f) + newColor.redF() * f
greenF = oldColor.greenF() * (1 - f) + newColor.greenF() * f
blueF = oldColor.blueF() * (1 - f) + newColor.blueF() * f
returnC = QColor()
returnC.setRedF(redF)
returnC.setGreenF(greenF)
returnC.setBlueF(blueF)
return returnC
lastColor = color
return QColor(0, 0, 0)
[docs] def recalculateGradient(self):
width = 3
self._gradient = QLinearGradient(0, 0, self._view._scale, 0)
for color in self._colors:
self._gradient.setColorAt(color.getX(), color.getColor())
self._pen = QPen()
self._pen.setCapStyle(QtCore.Qt.RoundCap)
self._pen.setWidthF(width)
self._pen.setBrush(QBrush(self._gradient))
self.update()
self._view.preciseGradientUpdated.emit()
[docs] def getGradient(self):
return self._gradient
[docs] def paint(self, painter, options, widget=None):
painter.save()
painter.setPen(self._pen)
painter.drawLine(0., 0., self._view._scale, 0.)
for value in self._shownValues:
painter.drawLine(value * self._view._scale, -self._barHeight,
value * self._view._scale, 0.)
painter.restore()
[docs] def boundingRect(self):
width = 3
return QRectF(0 - width, 0 - width - self._barHeight,
self._view._scale + 2 * width,
0 + 2 * width + self._barHeight)
[docs]class ColorSelector(QtWidgets.QGraphicsItem):
[docs] def __init__(self, x, color, parent):
self._ghost = False
self._fixed = False
QtWidgets.QGraphicsItem.__init__(self)
self._color = color
self._rad = 5
self._parent = parent
self.moveTo(x)
[docs] def moveTo(self, x):
self._x = x
self.setPos(x * self._parent._view._scale, 0.)
self.update()
if not self._ghost:
self._parent.recalculateGradient()
[docs] def getColor(self):
return self._color
[docs] def setColor(self, color):
self._color = color
self.update()
if not self._ghost:
self._parent.recalculateGradient()
[docs] def getX(self):
return self._x
[docs] def paint(self, painter, options, widget=None):
painter.save()
painter.setPen(QColor(0, 0, 0))
painter.setBrush(self._color)
painter.drawEllipse(QPointF(0, self._rad + 5), self._rad, self._rad)
painter.restore()
[docs] def boundingRect(self):
return QRectF(-self._rad, 5, 2 * self._rad, 2 * self._rad)
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
view = PropertyWidget()
view.show()
sys.exit(app.exec())