Source code for schrodinger.application.dendrogram.gradientSelector

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 PropertyWidget(QWidget):
[docs] def __init__(self): QWidget.__init__(self) self.setLayout(QVBoxLayout()) self._combobox = QComboBox() self._gradientView = GradientSelectorView() self._deleteButton = QPushButton("x") self.layout().addWidget(self._deleteButton) self.layout().addWidget(self._combobox) self.layout().addWidget(self._gradientView) self._gradientView.setMaximumHeight(60)
[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())