def pointAt(self, axes, axis_values): """ Returns the point that best represents this graph information. :param axes | [<XChartAxis>, ..] axis_values | {<str> axisName, <variant> value :return <QPointF> """ point = QPointF() rect = self._buildData.get('axis_rect') if not rect: return point x_range = rect.right() - rect.left() y_range = rect.bottom() - rect.top() for axis in axes: if not axis.name() in axis_values: continue perc = axis.percentAt(axis_values[axis.name()]) if axis.orientation() == Qt.Vertical: point.setY(rect.bottom() - perc * y_range) else: point.setX(rect.left() + perc * x_range) return point
def draw(self, qpainter, zoom=1): """Draw this figure Parameters ---------- qpainter: PySide.QtGui.QPainter """ size_x = self.size_x * zoom size_y = self.size_y * zoom pensize = 3 qpainter.setPen( QtGui.QPen(PipelineDrawer.blue_cta, pensize, QtCore.Qt.SolidLine)) text_pos = QPointF(self.center) text_pos.setX(text_pos.x() - size_x / 2 + 2) text_pos.setY(text_pos.y() + pensize) qpainter.drawText(text_pos, str(self.nb_job_done)) pt = QPointF(self.center) pt.setX(5) pos = self.name.find("$$thread_number$$") if pos != -1: name = self.name[0:pos] else: name = self.name qpainter.drawText(pt, name) if self.running == True: qpainter.setPen( QtGui.QPen(PipelineDrawer.mygreen, 3, QtCore.Qt.SolidLine)) else: qpainter.setPen( QtGui.QPen(PipelineDrawer.blue_cta, 3, QtCore.Qt.SolidLine)) x1 = self.center.x() - (size_x / 2) y1 = self.center.y() - (size_y / 2) qpainter.drawRoundedRect(x1, y1, size_x, size_y, 12.0, 12.0)
def showMoveHelper(self, visible=True): """show help text In empty HandBoards""" if visible: if not self.__moveHelper: splitter = QGraphicsRectItem(self) hbCenter = self.rect().center() splitter.setRect(hbCenter.x() * 0.5, hbCenter.y(), hbCenter.x() * 1, 1) helpItems = [splitter] for name, yFactor in [(m18n('Move Exposed Tiles Here'), 0.5), (m18n('Move Concealed Tiles Here'), 1.5)]: helper = QGraphicsSimpleTextItem(name, self) helper.setScale(3) nameRect = QRectF() nameRect.setSize(helper.mapToParent(helper.boundingRect()).boundingRect().size()) center = QPointF(hbCenter) center.setY(center.y() * yFactor) helper.setPos(center - nameRect.center()) if self.sceneRotation() == 180: rotateCenter(helper, 180) helpItems.append(helper) self.__moveHelper = self.scene().createItemGroup(helpItems) self.__moveHelper.setVisible(True) else: if self.__moveHelper: self.__moveHelper.setVisible(False)
def drawPipeline(self, qp): """Called by paintEvent, it draws figures and link between them. Parameters ---------- qp : QtGui.QPainter Performs low-level painting """ # If self.levels is empty, indeed, it does not make sense to draw # something. if self.levels is None: return # define Rep position because they change whan resising main windows width = self.size().width() height = self.size().height() if len(self.levels) != 0: total_height = (len(self.levels) - 1) * ( STAGE_SIZE_Y + ROUTER_SIZE_Y) self.zoom = height / total_height else: self.zoom = 1 # center figures on screen last_point = QPointF(width / 2, -GAP_Y / 2 * self.zoom) for level in self.levels: total_x = len(level) * STAGE_SIZE_X * self.zoom + ( len(level) - 1 * STAGE_GAP_X * self.zoom) last_point.setX(width / 2 - total_x / 2) last_point.setY(last_point.y() + GAP_Y * self.zoom) for figure in level: figure.setCenter(QPointF(last_point)) last_point.setX(last_point.x() + STAGE_GAP_X * self.zoom) # Start to paint size = self.size() lines = list() last_level_pt = list() for level in self.levels: current_level_pt = list() for figure in level: figure.draw(qp, zoom=self.zoom) connexion_pt = QPointF(figure.center.x(), figure.center.y() - figure.size_y / 2 * self.zoom) current_level_pt.append(QPointF(connexion_pt.x(), connexion_pt.y() + figure.size_y * self.zoom)) # Link to previous level connexion point(s) for point in last_level_pt: lines.append(QLineF(point, connexion_pt)) # Keep points for next level last_level_pt = list(current_level_pt) for line in lines: qp.setPen(QtGui.QPen(self.blue_cta, 1, QtCore.Qt.SolidLine)) qp.drawLine(line)
def draw(self, qpainter, zoom=1): """Draw this figure Parameters ---------- qpainter: PySide.QtGui.QPainter """ size_x = self.size_x * zoom size_y = self.size_y * zoom pensize = 3 qpainter.setPen( QtGui.QPen(QtCore.Qt.black, pensize, QtCore.Qt.SolidLine)) qpainter.drawEllipse(self.center, size_x / 2, size_y / 2) text_pos = QPointF(self.center) text_pos.setX(text_pos.x() - size_x / 2 + 10) text_pos.setY(text_pos.y() + pensize) qpainter.drawText(text_pos, str(self.queue_size)) qpainter.setPen( QtGui.QPen(PipelineDrawer.blue_cta, 3, QtCore.Qt.SolidLine))
def getXover(self, phg, strandtype, fromHelix,\ fromIndex, toHelix, toIndex): """ Draws a line from the center of the fromBase (pA) to the top or bottom of that same base, depending on its direction (qA), then a quad curve to the top or bottom of the toBase (qB), and finally to the center of the toBase (pB). """ # if we need to speed this up, we could keep track if pA changed? pA = QPointF(*fromHelix.baseLocation(strandtype,\ fromIndex,\ center=True)) pA = phg.mapFromItem(fromHelix, pA) pB = QPointF(*toHelix.baseLocation(strandtype,\ toIndex,\ center=True)) pB = phg.mapFromItem(toHelix, pB) yA = yB = self._baseWidth / 2 if fromHelix.vhelix().directionOfStrandIs5to3(strandtype): orientA = HandleOrient.LeftUp yA = -yA else: orientA = HandleOrient.RightDown if toHelix.vhelix().directionOfStrandIs5to3(strandtype): orientB = HandleOrient.RightUp yB = -yB else: orientB = HandleOrient.LeftDown # Determine start and end points of quad curve qA = QPointF(pA.x(), pA.y() + yA) qB = QPointF(pB.x(), pB.y() + yB) # Determine control point of quad curve c1 = QPointF() # case 1: same strand if fromHelix.number() == toHelix.number(): if pA.x() < pB.x(): # draw only from left if orientA == HandleOrient.LeftUp or \ orientA == HandleOrient.RightUp: dx = abs(pB.x() - pA.x()) c1.setX(0.5 * (pA.x() + pB.x())) c1.setY(pA.y() - self.yScale * dx) # end if # end if # case 2: same parity elif fromHelix.evenParity() == toHelix.evenParity(): dy = abs(pB.y() - pA.y()) c1.setX(pA.x() + self.xScale * dy) c1.setY(0.5 * (pA.y() + pB.y())) # case 3: default else: if orientA == HandleOrient.LeftUp: c1.setX(pA.x() - self.xScale * abs(pB.y() - pA.y())) else: c1.setX(pA.x() + self.xScale * abs(pB.y() - pA.y())) c1.setY(0.5 * (pA.y() + pB.y())) # Construct painter path painterpath = QPainterPath() painterpath.moveTo(pA) painterpath.lineTo(qA) painterpath.quadTo(c1, qB) painterpath.lineTo(pB) return painterpath
def interactiveResize(self, mousePos): """ Perform shape interactive resize. """ offset = self.handleSize + self.handleSpace boundingRect = self.boundingRect() rect = self.rect() diff = QPointF(0, 0) self.prepareGeometryChange() if self.handleSelected == self.handleTopLeft: fromX = self.mousePressRect.left() fromY = self.mousePressRect.top() toX = fromX + mousePos.x() - self.mousePressPos.x() toY = fromY + mousePos.y() - self.mousePressPos.y() diff.setX(toX - fromX) diff.setY(toY - fromY) boundingRect.setLeft(toX) boundingRect.setTop(toY) rect.setLeft(boundingRect.left() + offset) rect.setTop(boundingRect.top() + offset) self.setRect(rect) elif self.handleSelected == self.handleTopMiddle: fromY = self.mousePressRect.top() toY = fromY + mousePos.y() - self.mousePressPos.y() diff.setY(toY - fromY) boundingRect.setTop(toY) rect.setTop(boundingRect.top() + offset) self.setRect(rect) elif self.handleSelected == self.handleTopRight: fromX = self.mousePressRect.right() fromY = self.mousePressRect.top() toX = fromX + mousePos.x() - self.mousePressPos.x() toY = fromY + mousePos.y() - self.mousePressPos.y() diff.setX(toX - fromX) diff.setY(toY - fromY) boundingRect.setRight(toX) boundingRect.setTop(toY) rect.setRight(boundingRect.right() - offset) rect.setTop(boundingRect.top() + offset) self.setRect(rect) elif self.handleSelected == self.handleMiddleLeft: fromX = self.mousePressRect.left() toX = fromX + mousePos.x() - self.mousePressPos.x() diff.setX(toX - fromX) boundingRect.setLeft(toX) rect.setLeft(boundingRect.left() + offset) self.setRect(rect) elif self.handleSelected == self.handleMiddleRight: print("MR") fromX = self.mousePressRect.right() toX = fromX + mousePos.x() - self.mousePressPos.x() diff.setX(toX - fromX) boundingRect.setRight(toX) rect.setRight(boundingRect.right() - offset) self.setRect(rect) elif self.handleSelected == self.handleBottomLeft: fromX = self.mousePressRect.left() fromY = self.mousePressRect.bottom() toX = fromX + mousePos.x() - self.mousePressPos.x() toY = fromY + mousePos.y() - self.mousePressPos.y() diff.setX(toX - fromX) diff.setY(toY - fromY) boundingRect.setLeft(toX) boundingRect.setBottom(toY) rect.setLeft(boundingRect.left() + offset) rect.setBottom(boundingRect.bottom() - offset) self.setRect(rect) elif self.handleSelected == self.handleBottomMiddle: fromY = self.mousePressRect.bottom() toY = fromY + mousePos.y() - self.mousePressPos.y() diff.setY(toY - fromY) boundingRect.setBottom(toY) rect.setBottom(boundingRect.bottom() - offset) self.setRect(rect) elif self.handleSelected == self.handleBottomRight: fromX = self.mousePressRect.right() fromY = self.mousePressRect.bottom() toX = fromX + mousePos.x() - self.mousePressPos.x() toY = fromY + mousePos.y() - self.mousePressPos.y() diff.setX(toX - fromX) diff.setY(toY - fromY) boundingRect.setRight(toX) boundingRect.setBottom(toY) rect.setRight(boundingRect.right() - offset) rect.setBottom(boundingRect.bottom() - offset) self.setRect(rect) self.updateHandlesPos()
class Particle(QGraphicsItem): def __init__(self, parent=None): super(Particle, self).__init__(parent) self.effect = QGraphicsBlurEffect() self.blur_radius = random.uniform(0.8, 1.6) self.effect.setBlurRadius(self.blur_radius) self.setGraphicsEffect(self.effect) self.height = random.uniform(1, 6) self.width = random.uniform(1, 6) self.depth = 1 self.setZValue(self.depth) self.newPos = QPointF() self.animation_timer = QTimer() self.animation_timer.setInterval(1000 / 25) self.animation_timer.timeout.connect(self.advance) self.animation_timer.start() self.speed = 1 self.next_pos = QPointF(0, 0) self.animated = True self.max_speed = 3.0 self.color = QColor(0, 0, 0, 50) # self.change_position_timer = QTimer() # self.change_position_timer.setInterval(5000) # self.change_position_timer.timeout.connect(self.calculate_next_pos) def animate(self, bool): self.animated = bool def calculate_forces(self): # Sum up all forces pushing this item away. xvel = 0.0 yvel = 0.0 line = QtCore.QLineF(self.next_pos, self.pos()) dx = line.dx() dy = line.dy() l = math.sqrt(math.pow(dx, 2) + math.pow(dy, 2)) # l = 2.0 * (dx * dx + dy * dy) if l > 0: xvel -= (dx * self.speed) / l yvel -= (dy * self.speed) / l if l < 10: self.calculate_next_pos() scene_rect = self.scene().sceneRect() self.newPos = self.pos() + QtCore.QPointF(xvel, yvel) self.newPos.setX( min(max(self.newPos.x(), scene_rect.left() + 10), scene_rect.right() - 10)) self.newPos.setY( min(max(self.newPos.y(), scene_rect.top() + 10), scene_rect.bottom() - 10)) def calculate_next_pos(self): particle_x = random.uniform(-self.scene().sceneRect().width() / 2, self.scene().sceneRect().width() / 2) particle_y = random.uniform(-self.scene().sceneRect().height() / 2, self.scene().sceneRect().height() / 2) self.next_pos = QPointF(particle_x, particle_y) self.blur_radius = random.uniform(0.8, 1.6) self.effect.setBlurRadius(self.blur_radius) self.setGraphicsEffect(self.effect) self.height = random.uniform(1, 6) self.width = random.uniform(1, 6) self.depth = random.uniform(0, 6) self.speed *= random.uniform(0.1, 2.0) self.speed %= self.max_speed # print self.speed def advance(self): if self.animated: self.calculate_forces() if self.newPos == self.pos(): return False self.setPos(self.newPos) return True else: return False def paint(self, painter, options, widget=None): # painter.drawRect(self.boundingRect()) painter.setBrush(self.color) painter.setPen(self.color) painter.drawEllipse(-self.width / 2, -self.height / 2, self.width, self.height) def boundingRect(self): return QRectF(-self.width / 2, -self.height / 2, self.width, self.height) def reduce_speed(self, factor=0.9): if factor < 1 and factor > 0: self.speed *= factor def increase_speed(self, factor=1.1): if factor > 1: self.speed *= factor def set_color(self, color): self.color = color def instant_pos_change(self): particle_x = random.uniform(-self.scene().sceneRect().width() / 2, self.scene().sceneRect().width() / 2) particle_y = random.uniform(-self.scene().sceneRect().height() / 2, self.scene().sceneRect().height() / 2) self.setPos(QPointF(particle_x, particle_y)) self.next_pos = QPointF(particle_x, particle_y)
class PixmapDial(QDial): # enum CustomPaint CUSTOM_PAINT_NULL = 0 CUSTOM_PAINT_CARLA_WET = 1 CUSTOM_PAINT_CARLA_VOL = 2 CUSTOM_PAINT_CARLA_L = 3 CUSTOM_PAINT_CARLA_R = 4 # enum Orientation HORIZONTAL = 0 VERTICAL = 1 HOVER_MIN = 0 HOVER_MAX = 9 def __init__(self, parent): QDial.__init__(self, parent) self.fPixmap = QPixmap("./bitmaps/dial_01d.png") self.fPixmapNum = "01" self.fCustomPaint = self.CUSTOM_PAINT_NULL self.fHovered = False self.fHoverStep = self.HOVER_MIN if self.fPixmap.width() > self.fPixmap.height(): self.fOrientation = self.HORIZONTAL else: self.fOrientation = self.VERTICAL self.fLabel = "" self.fLabelPos = QPointF(0.0, 0.0) self.fLabelFont = QFont() self.fLabelFont.setPointSize(6) self.fLabelWidth = 0 self.fLabelHeight = 0 self.fLabelGradient = QLinearGradient(0, 0, 0, 1) if self.palette().window().color().lightness() > 100: # Light background c = self.palette().dark().color() self.fColor1 = c self.fColor2 = QColor(c.red(), c.green(), c.blue(), 0) self.fColorT = [self.palette().buttonText().color(), self.palette().mid().color()] else: # Dark background self.fColor1 = QColor(0, 0, 0, 255) self.fColor2 = QColor(0, 0, 0, 0) self.fColorT = [Qt.white, Qt.darkGray] self.updateSizes() def getSize(self): return self.fSize def setCustomPaint(self, paint): self.fCustomPaint = paint self.fLabelPos.setY(self.fSize + self.fLabelHeight/2) self.update() def setEnabled(self, enabled): if self.isEnabled() != enabled: self.fPixmap.load("./bitmaps/dial_%s%s.png" % (self.fPixmapNum, "" if enabled else "d")) self.updateSizes() self.update() QDial.setEnabled(self, enabled) def setLabel(self, label): self.fLabel = label self.fLabelWidth = QFontMetrics(self.fLabelFont).width(label) self.fLabelHeight = QFontMetrics(self.fLabelFont).height() self.fLabelPos.setX(float(self.fSize)/2.0 - float(self.fLabelWidth)/2.0) self.fLabelPos.setY(self.fSize + self.fLabelHeight) self.fLabelGradient.setColorAt(0.0, self.fColor1) self.fLabelGradient.setColorAt(0.6, self.fColor1) self.fLabelGradient.setColorAt(1.0, self.fColor2) self.fLabelGradient.setStart(0, float(self.fSize)/2.0) self.fLabelGradient.setFinalStop(0, self.fSize + self.fLabelHeight + 5) self.fLabelGradientRect = QRectF(float(self.fSize)/8.0, float(self.fSize)/2.0, float(self.fSize*6)/8.0, self.fSize+self.fLabelHeight+5) self.update() def setPixmap(self, pixmapId): self.fPixmapNum = "%02i" % pixmapId self.fPixmap.load("./bitmaps/dial_%s%s.png" % (self.fPixmapNum, "" if self.isEnabled() else "d")) if self.fPixmap.width() > self.fPixmap.height(): self.fOrientation = self.HORIZONTAL else: self.fOrientation = self.VERTICAL self.updateSizes() self.update() def minimumSizeHint(self): return QSize(self.fSize, self.fSize) def sizeHint(self): return QSize(self.fSize, self.fSize) def updateSizes(self): self.fWidth = self.fPixmap.width() self.fHeight = self.fPixmap.height() if self.fWidth < 1: self.fWidth = 1 if self.fHeight < 1: self.fHeight = 1 if self.fOrientation == self.HORIZONTAL: self.fSize = self.fHeight self.fCount = self.fWidth / self.fHeight else: self.fSize = self.fWidth self.fCount = self.fHeight / self.fWidth self.setMinimumSize(self.fSize, self.fSize + self.fLabelHeight + 5) self.setMaximumSize(self.fSize, self.fSize + self.fLabelHeight + 5) def enterEvent(self, event): self.fHovered = True if self.fHoverStep == self.HOVER_MIN: self.fHoverStep = self.HOVER_MIN + 1 QDial.enterEvent(self, event) def leaveEvent(self, event): self.fHovered = False if self.fHoverStep == self.HOVER_MAX: self.fHoverStep = self.HOVER_MAX - 1 QDial.leaveEvent(self, event) def paintEvent(self, event): event.accept() painter = QPainter(self) painter.save() painter.setRenderHint(QPainter.Antialiasing, True) if self.fLabel: if self.fCustomPaint == self.CUSTOM_PAINT_NULL: painter.setPen(self.fColor2) painter.setBrush(self.fLabelGradient) painter.drawRect(self.fLabelGradientRect) painter.setFont(self.fLabelFont) painter.setPen(self.fColorT[0 if self.isEnabled() else 1]) painter.drawText(self.fLabelPos, self.fLabel) if self.isEnabled(): current = float(self.value() - self.minimum()) divider = float(self.maximum() - self.minimum()) if divider == 0.0: return value = current / divider target = QRectF(0.0, 0.0, self.fSize, self.fSize) per = int((self.fCount - 1) * value) if self.fOrientation == self.HORIZONTAL: xpos = self.fSize * per ypos = 0.0 else: xpos = 0.0 ypos = self.fSize * per source = QRectF(xpos, ypos, self.fSize, self.fSize) painter.drawPixmap(target, self.fPixmap, source) # Custom knobs (Dry/Wet and Volume) if self.fCustomPaint in (self.CUSTOM_PAINT_CARLA_WET, self.CUSTOM_PAINT_CARLA_VOL): # knob color colorGreen = QColor(0x5D, 0xE7, 0x3D, 191 + self.fHoverStep*7) colorBlue = QColor(0x3E, 0xB8, 0xBE, 191 + self.fHoverStep*7) # draw small circle ballRect = QRectF(8.0, 8.0, 15.0, 15.0) ballPath = QPainterPath() ballPath.addEllipse(ballRect) #painter.drawRect(ballRect) tmpValue = (0.375 + 0.75*value) ballValue = tmpValue - floor(tmpValue) ballPoint = ballPath.pointAtPercent(ballValue) # draw arc startAngle = 216*16 spanAngle = -252*16*value if self.fCustomPaint == self.CUSTOM_PAINT_CARLA_WET: painter.setBrush(colorBlue) painter.setPen(QPen(colorBlue, 0)) painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2)) gradient = QConicalGradient(15.5, 15.5, -45) gradient.setColorAt(0.0, colorBlue) gradient.setColorAt(0.125, colorBlue) gradient.setColorAt(0.625, colorGreen) gradient.setColorAt(0.75, colorGreen) gradient.setColorAt(0.76, colorGreen) gradient.setColorAt(1.0, colorGreen) painter.setBrush(gradient) painter.setPen(QPen(gradient, 3)) else: painter.setBrush(colorBlue) painter.setPen(QPen(colorBlue, 0)) painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2)) painter.setBrush(colorBlue) painter.setPen(QPen(colorBlue, 3)) painter.drawArc(4.0, 4.0, 26.0, 26.0, startAngle, spanAngle) # Custom knobs (L and R) elif self.fCustomPaint in (self.CUSTOM_PAINT_CARLA_L, self.CUSTOM_PAINT_CARLA_R): # knob color color = QColor(0xAD + self.fHoverStep*5, 0xD5 + self.fHoverStep*4, 0x4B + self.fHoverStep*5) # draw small circle ballRect = QRectF(7.0, 8.0, 11.0, 12.0) ballPath = QPainterPath() ballPath.addEllipse(ballRect) #painter.drawRect(ballRect) tmpValue = (0.375 + 0.75*value) ballValue = tmpValue - floor(tmpValue) ballPoint = ballPath.pointAtPercent(ballValue) painter.setBrush(color) painter.setPen(QPen(color, 0)) painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.0, 2.0)) # draw arc if self.fCustomPaint == self.CUSTOM_PAINT_CARLA_L: startAngle = 216*16 spanAngle = -252.0*16*value elif self.fCustomPaint == self.CUSTOM_PAINT_CARLA_R: startAngle = 324.0*16 spanAngle = 252.0*16*(1.0-value) else: return painter.setPen(QPen(color, 2)) painter.drawArc(3.5, 4.5, 22.0, 22.0, startAngle, spanAngle) if self.HOVER_MIN < self.fHoverStep < self.HOVER_MAX: self.fHoverStep += 1 if self.fHovered else -1 QTimer.singleShot(20, self, SLOT("update()")) else: # isEnabled() target = QRectF(0.0, 0.0, self.fSize, self.fSize) painter.drawPixmap(target, self.fPixmap, target) painter.restore() def resizeEvent(self, event): self.updateSizes() QDial.resizeEvent(self, event)
def draw(self, painter, size = None): """ :Arguments: painter : QPainter Opened painter on which to draw """ bounding_rect = QRectF() position = self.position transfer_function = self.transfer_function font = QFont(self.font) text_color = self.text_color line_color = self.line_color line_thickness = self.line_thickness value_range = self.value_range if size is None: viewport = painter.viewport() # viewport rectangle mat, ok = painter.worldMatrix().inverted() if not ok: raise ValueError("Transformation matrix of painter is singular.") viewport = mat.mapRect(viewport) else: viewport = size # First, prepare the gradient w = viewport.width() h = viewport.height() #print("Size of viewport: {0}x{1}".format(w, h)) gr = QLinearGradient() nb_values = ceil(w/5.0) brush_color = QColor() for i in range(int(nb_values)): brush_color.setRgbF(*transfer_function.rgba(i/nb_values)) gr.setColorAt(i/nb_values, brush_color) # Second, find its position metric = QFontMetricsF(font, painter.device()) font_test = [ str(i)*5 for i in range(10) ] lim_width = 0 lim_height = 0 for t in font_test: rect = metric.boundingRect(t) lim_width = max(lim_width, rect.width()) lim_height = max(lim_height, rect.height()) lim_height *= 3 length = self.scale_length shift_length = (1-length)/2 width = self.scale_width shift_width = self.scale_shift_width delta_value = value_range[1]-value_range[0] if position == "Top": scale_rect = QRectF(shift_length*w, shift_width*h, length*w, width*h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.left(), scale_rect.center().y()) gr.setFinalStop(scale_rect.right(), scale_rect.center().y()) start_pos = scale_rect.bottomLeft() end_pos = scale_rect.bottomRight() elif position == "Right": scale_rect = QRectF((1-shift_width-width)*w, shift_length*h, width*w, length*h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.center().x(), scale_rect.bottom()) gr.setFinalStop(scale_rect.center().x(), scale_rect.top()) start_pos = scale_rect.bottomLeft() end_pos = scale_rect.topLeft() elif position == "Bottom": scale_rect = QRectF(shift_length*w, (1-shift_width-width)*h, length*w, width*h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.left(), scale_rect.center().y()) gr.setFinalStop(scale_rect.right(), scale_rect.center().y()) start_pos = scale_rect.topLeft() end_pos = scale_rect.topRight() elif position == "Left": scale_rect = QRectF(shift_width*w, shift_length*h, width*w, length*h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.center().x(), scale_rect.bottom()) gr.setFinalStop(scale_rect.center().x(), scale_rect.top()) start_pos = scale_rect.bottomRight() end_pos = scale_rect.topRight() else: raise ValueError("Invalid scale position: %s" % position) shift_pos = (end_pos-start_pos)/delta_value if position in ["Left", "Right"]: is_vertical = True length = scale_rect.height() else: is_vertical = False length = scale_rect.width() # Get the ticks ticks = self.selectValues(length, is_vertical, painter) if len(ticks) == 0: return ticks_str, ticks_extra = self._tick2str(ticks) # Figure the shifts dist_to_bar = self.text_to_bar max_width = 0 max_height = 0 for t in ticks_str: rect = metric.boundingRect(t) max_width = max(rect.width(), max_width) max_height = max(rect.height(), max_height) if position == "Left": shift_left = dist_to_bar shift_top = None elif position == "Right": shift_left = -dist_to_bar-max_width shift_top = None elif position == "Top": shift_left = None shift_top = dist_to_bar else: shift_left = None shift_top = -dist_to_bar-max_height painter.save() painter.translate(viewport.topLeft()) #print("viewport.topLeft() = {0}x{1}".format(viewport.left(), viewport.top())) painter.setBrush(gr) line_pen = QPen(line_color) line_pen.setWidth(line_thickness) painter.setPen(line_pen) painter.drawRect(scale_rect) bounding_rect |= scale_rect #print("Scale rect: +{0}+{1}x{2}x{3}".format(scale_rect.left(), #scale_rect.top(), scale_rect.width(), scale_rect.height())) painter.setFont(font) painter.setPen(text_color) for ts,t in zip(ticks_str, ticks): r = metric.boundingRect(ts) pos = start_pos+shift_pos*(t-value_range[0]) if shift_left is None: pos.setX( pos.x() - r.width()/2 ) else: pos.setX( pos.x() + shift_left ) if shift_top is None: pos.setY( pos.y() - r.height()/2) else: pos.setY( pos.y() + shift_top ) r.moveTo(pos) real_rect = painter.drawText(r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, ts) bounding_rect |= real_rect if ticks_extra is not None or self.unit: unit = self.unit exp_width = width = space_width = 0 exp_txt = "" r = exp_r = unit_r = QRectF() exp_font = None if ticks_extra is not None: exp_txt = u"×10" r = metric.boundingRect(exp_txt) exp_font = QFont(font) exp_size = self.exp_size if exp_font.pixelSize() != -1: exp_font.setPixelSize(exp_size*exp_font.pixelSize()) else: exp_font.setPointSizeF(exp_size*exp_font.pointSizeF()) exp_metric = QFontMetricsF(exp_font, painter.device()) exp_r = exp_metric.boundingRect(ticks_extra) if unit: unit_r = metric.boundingRect(unit) total_width = r.width()+exp_r.width()+unit_r.width() total_height = max(r.height(),unit_r.height())+exp_r.height()/2 pos = scale_rect.topRight() log_debug("top right of scale bar = (%g,%g)" % (pos.x(), pos.y())) log_debug("Size of image = (%d,%d)" % (w,h)) log_debug("Size of text = (%g,%g)" % (total_width, total_height)) if position == "Bottom": pos.setY(pos.y() + scale_rect.height() + dist_to_bar) pos.setX(pos.x() - total_width) elif position == "Top": pos.setY(pos.y() - dist_to_bar - total_height) pos.setX(pos.x() - total_width) else: # position == "left" or "right" pos.setX(pos.x() - (scale_rect.width() + total_width)/2) if pos.x() < 0: pos.setX(dist_to_bar) elif pos.x()+total_width+dist_to_bar > w: pos.setX(w - total_width - dist_to_bar) pos.setY(pos.y() - dist_to_bar - total_height) log_debug("Display unit at position: (%g,%g)" % (pos.x(), pos.y())) if ticks_extra is not None: r.moveTo(pos) real_rect = painter.drawText(r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, exp_txt) bounding_rect |= real_rect pos.setX( pos.x() + r.width() ) pos.setY( pos.y() - metric.ascent()/2 ) exp_r.moveTo(pos) painter.setFont(exp_font) real_rect = painter.drawText(exp_r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, ticks_extra) bounding_rect |= real_rect pos.setY(pos.y() + metric.ascent()/2) if unit: pos.setX(pos.x() + space_width + exp_r.width()) unit_r.moveTo(pos) painter.setFont(font) real_rect = painter.drawText(unit_r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, unit) bounding_rect |= real_rect # Draw the ticks now painter.setPen(line_pen) tick_size = self.tick_size if is_vertical: width = scale_rect.width()*tick_size else: width = scale_rect.height()*tick_size pen_width = painter.pen().widthF() if pen_width == 0: pen_width = 1.0 for t in ticks: pos1 = start_pos + shift_pos*(t-value_range[0]) pos2 = QPointF(pos1) if is_vertical: pos1.setX(scale_rect.left() + pen_width) pos2.setX(pos1.x() + width - pen_width) painter.drawLine(pos1, pos2) pos1.setX(scale_rect.right() - pen_width) pos2.setX(pos1.x() - width + pen_width) painter.drawLine(pos1, pos2) else: pos1.setY(scale_rect.top() + pen_width) pos2.setY(pos1.y() + width - pen_width) painter.drawLine(pos1, pos2) pos1.setY(scale_rect.bottom() - pen_width) pos2.setY(pos1.y() - width + pen_width) painter.drawLine(pos1, pos2) painter.restore() bounding_rect = bounding_rect.adjusted(-pen_width, -pen_width, pen_width, pen_width) return bounding_rect
def getRectBetweenTwoPoints(self, firstP, secondP, firstCorner=CornerType.UNDEFINED, secondCorner=CornerType.UNDEFINED): halfthick = 0.5 * self.CONNECTION_THICKNESS * self.zoomFactor() cornerRoundness = halfthick ** 0.5 offset = 2*halfthick #* (cornerRoundness + 1) - 1 # -1 prevents one pixel gaps which sometimes appear at corners. direction = self.getPointToPointDirection(firstP, secondP) firstOffset = 0 if self.cornerIsDefined(firstCorner): firstOffset = offset secondOffset = 0 if self.cornerIsDefined(secondCorner): secondOffset = offset topLeft = QPointF() bottomRight = QPointF() if direction == self.ConnectionDirection.LEFT: # horizontal, negative topLeft.setX(secondP.x() + secondOffset) topLeft.setY(secondP.y() - halfthick) bottomRight.setX(firstP.x() - firstOffset + 1) bottomRight.setY(firstP.y() + halfthick) elif direction == self.ConnectionDirection.RIGHT: # horizontal, positive topLeft.setX(firstP.x() + firstOffset) topLeft.setY(firstP.y() - halfthick) bottomRight.setX(secondP.x() - secondOffset + 1) bottomRight.setY(secondP.y() + halfthick) elif direction == self.ConnectionDirection.UP: # vrtical, negative topLeft.setX(secondP.x() - halfthick) topLeft.setY(secondP.y() + secondOffset) bottomRight.setX(firstP.x() + halfthick) bottomRight.setY(firstP.y() - firstOffset + 1) elif direction == self.ConnectionDirection.DOWN: # vertical, positive topLeft.setX(firstP.x() - halfthick) topLeft.setY(firstP.y() + firstOffset) bottomRight.setX(secondP.x() + halfthick) bottomRight.setY(secondP.y() - secondOffset + 1) else: return QRectF(topLeft, bottomRight) return QRectF(topLeft, bottomRight)
def betweenTwoPoints(self, point, first, second): """ Checks whether 'point' lies between 'first' and 'second'. This function can currently (08-11-15) only deal with horizontal and vertical distances. """ halfthick = 0.5 * self.CONNECTION_THICKNESS * self.zoomFactor() direction = self.getPointToPointDirection(first, second) topLeft = QPointF() bottomRight = QPointF() if direction == self.ConnectionDirection.LEFT: # horizontal, negative topLeft.setX(second.x()) topLeft.setY(second.y() - halfthick) bottomRight.setX(first.x()) bottomRight.setY(first.y() + halfthick) elif direction == self.ConnectionDirection.RIGHT: # horizontal, positive topLeft.setX(first.x()) topLeft.setY(first.y() - halfthick) bottomRight.setX(second.x()) bottomRight.setY(second.y() + halfthick) elif direction == self.ConnectionDirection.UP: # vertical, negative topLeft.setX(second.x() - halfthick) topLeft.setY(second.y()) bottomRight.setX(first.x() + halfthick) bottomRight.setY(first.y()) elif direction == self.ConnectionDirection.UP: # vertical, positive topLeft.setX(first.x() - halfthick) topLeft.setY(first.y()) bottomRight.setX(second.x() + halfthick) bottomRight.setY(second.y()) else: return False rect = QRectF(topLeft, bottomRight) return rect.contains(QPointF(point))
class Node(QGraphicsItem): Type = QGraphicsItem.UserType + 1 def __init__(self, graphWidget, text=""): super(Node, self).__init__() self.graph = graphWidget self.edgeList = [] self.newPos = QPointF() self.setFlag(QGraphicsItem.ItemIsMovable) self.setFlag(QGraphicsItem.ItemSendsGeometryChanges) self.setCacheMode(QGraphicsItem.DeviceCoordinateCache) self.setZValue(1) self.text = text self.active = False self.b = 15 def type(self): return Node.Type def addEdge(self, edge): self.edgeList.append(edge) edge.adjust() def setActive(self, value=True): self.active = value def edges(self): return self.edgeList def calculateForces(self): if not self.scene() or self.scene().mouseGrabberItem() is self: self.newPos = self.pos() return # Sum up all forces pushing this item away. xvel = 0.0 yvel = 0.0 for item in self.scene().items(): if not isinstance(item, Node): continue line = QLineF(self.mapFromItem(item, 0, 0), QPointF(0, 0)) dx = line.dx() dy = line.dy() l = 2.0 * (dx * dx + dy * dy) if l > 0: xvel += (dx * 150.0) / l yvel += (dy * 150.0) / l # Now subtract all forces pulling items together. #weight = (len(self.edgeList) + 1) * 100.0 for edge in self.edgeList: if edge.sourceNode() is self: pos = self.mapFromItem(edge.destNode(), 0, 0) else: weight = edge.weight * 6 pos = self.mapFromItem(edge.sourceNode(), 0, 0) xvel += pos.x() / weight yvel += pos.y() / weight if qAbs(xvel) < 0.1 and qAbs(yvel) < 0.1: xvel = yvel = 0.0 sceneRect = self.scene().sceneRect() self.newPos = self.pos() + QPointF(xvel, yvel) self.newPos.setX( min(max(self.newPos.x(), sceneRect.left() + 10), sceneRect.right() - 10)) self.newPos.setY( min(max(self.newPos.y(), sceneRect.top() + 10), sceneRect.bottom() - 10)) def advance(self): if self.newPos == self.pos(): return False self.setPos(self.newPos) return True def boundingRect(self): adjust = 2.0 return QRectF(-self.b - adjust, -self.b - adjust, 2 * self.b + 3 + adjust, 2 * self.b + 3 + adjust) def shape(self): path = QPainterPath() path.addEllipse(-self.b, -self.b, 2 * self.b, 2 * self.b) return path def paint(self, painter, option, widget): self.setZValue(5) palette = QPalette() painter.setPen(Qt.NoPen) painter.setBrush(Qt.darkGray) gradient = QRadialGradient(-3, -3, 15) if option.state & QStyle.State_Sunken or self.active: gradient.setCenter(3, 3) gradient.setFocalPoint(3, 3) gradient.setColorAt( 1, palette.color(QPalette.Active, QPalette.Button)) gradient.setColorAt( 0, palette.color(QPalette.Active, QPalette.Button)) pen = QPen(palette.color(QPalette.Active, QPalette.ButtonText), 2) else: gradient.setColorAt( 1, palette.color(QPalette.Disabled, QPalette.Button)) gradient.setColorAt( 0, palette.color(QPalette.Disabled, QPalette.Button)) pen = QPen(palette.color(QPalette.Disabled, QPalette.ButtonText), 0) painter.setBrush(QBrush(gradient)) painter.setPen(pen) painter.drawEllipse(-self.b, -self.b, 2 * self.b, 2 * self.b) painter.drawText(self.boundingRect(), Qt.AlignCenter, self.text) def itemChange(self, change, value): if change == QGraphicsItem.ItemPositionHasChanged: for edge in self.edgeList: edge.adjust() self.graph.itemMoved() return super(Node, self).itemChange(change, value) def mousePressEvent(self, event): self.update() super(Node, self).mousePressEvent(event) def mouseReleaseEvent(self, event): self.update() super(Node, self).mouseReleaseEvent(event)
class GroundControlPoint(): def __init__(self, raw=None, map=None, enabled=True): self._raw = QPointF() self._map = QgsPoint() self._local = QPointF() self._enabled = True self.setRaw(raw) self.setMap(map) self.setEnabled(enabled) def isValid(self): return self.isRawSet() and self.isMapSet() def isRawSet(self): return self._raw is not None def raw(self): if self._raw is None: return QPointF() else: return self._raw def setRaw(self, raw): if raw is None: self._raw = None else: self._raw = raw def setRawX(self, x): if self._raw is None: self._raw = QPointF() self._raw.setX(x) def setRawY(self, y): if self._raw is None: self._raw = QPointF() self._raw.setY(y) def isMapSet(self): return self._raw is not None def map(self): if self._map is None: return QgsPoint() else: return self._map def setMap(self, map): if map is None: self._map = None else: self._map = map def local(self): if self._local is None: return QPointF() else: return self._local def setLocal(self, local): if local is None: self._local = None else: self._local = local def isEnabled(self): return self._enabled def setEnabled(self, enabled): self._enabled = enabled def asCsv(self): return utils.csv([self.map().x(), self.map().y(), self.raw().x(), self.raw().y(), int(self._enabled)])
def getRectBetweenTwoPoints(self, firstP, secondP, firstCorner=CornerType.UNDEFINED, secondCorner=CornerType.UNDEFINED): halfthick = 0.5 * self.CONNECTION_THICKNESS * self.zoomFactor() cornerRoundness = halfthick**0.5 offset = 2 * halfthick #* (cornerRoundness + 1) - 1 # -1 prevents one pixel gaps which sometimes appear at corners. direction = self.getPointToPointDirection(firstP, secondP) firstOffset = 0 if self.cornerIsDefined(firstCorner): firstOffset = offset secondOffset = 0 if self.cornerIsDefined(secondCorner): secondOffset = offset topLeft = QPointF() bottomRight = QPointF() if direction == self.ConnectionDirection.LEFT: # horizontal, negative topLeft.setX(secondP.x() + secondOffset) topLeft.setY(secondP.y() - halfthick) bottomRight.setX(firstP.x() - firstOffset + 1) bottomRight.setY(firstP.y() + halfthick) elif direction == self.ConnectionDirection.RIGHT: # horizontal, positive topLeft.setX(firstP.x() + firstOffset) topLeft.setY(firstP.y() - halfthick) bottomRight.setX(secondP.x() - secondOffset + 1) bottomRight.setY(secondP.y() + halfthick) elif direction == self.ConnectionDirection.UP: # vrtical, negative topLeft.setX(secondP.x() - halfthick) topLeft.setY(secondP.y() + secondOffset) bottomRight.setX(firstP.x() + halfthick) bottomRight.setY(firstP.y() - firstOffset + 1) elif direction == self.ConnectionDirection.DOWN: # vertical, positive topLeft.setX(firstP.x() - halfthick) topLeft.setY(firstP.y() + firstOffset) bottomRight.setX(secondP.x() + halfthick) bottomRight.setY(secondP.y() - secondOffset + 1) else: return QRectF(topLeft, bottomRight) return QRectF(topLeft, bottomRight)
def draw(self, painter, size=None): """ :Arguments: painter : QPainter Opened painter on which to draw """ bounding_rect = QRectF() position = self.position transfer_function = self.transfer_function font = QFont(self.font) text_color = self.text_color line_color = self.line_color line_thickness = self.line_thickness value_range = self.value_range if size is None: viewport = painter.viewport() # viewport rectangle mat, ok = painter.worldMatrix().inverted() if not ok: raise ValueError( "Transformation matrix of painter is singular.") viewport = mat.mapRect(viewport) else: viewport = size # First, prepare the gradient w = viewport.width() h = viewport.height() #print("Size of viewport: {0}x{1}".format(w, h)) gr = QLinearGradient() nb_values = ceil(w / 5.0) brush_color = QColor() for i in range(int(nb_values)): brush_color.setRgbF(*transfer_function.rgba(i / nb_values)) gr.setColorAt(i / nb_values, brush_color) # Second, find its position metric = QFontMetricsF(font, painter.device()) font_test = [str(i) * 5 for i in range(10)] lim_width = 0 lim_height = 0 for t in font_test: rect = metric.boundingRect(t) lim_width = max(lim_width, rect.width()) lim_height = max(lim_height, rect.height()) lim_height *= 3 length = self.scale_length shift_length = (1 - length) / 2 width = self.scale_width shift_width = self.scale_shift_width delta_value = value_range[1] - value_range[0] if position == "Top": scale_rect = QRectF(shift_length * w, shift_width * h, length * w, width * h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.left(), scale_rect.center().y()) gr.setFinalStop(scale_rect.right(), scale_rect.center().y()) start_pos = scale_rect.bottomLeft() end_pos = scale_rect.bottomRight() elif position == "Right": scale_rect = QRectF((1 - shift_width - width) * w, shift_length * h, width * w, length * h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.center().x(), scale_rect.bottom()) gr.setFinalStop(scale_rect.center().x(), scale_rect.top()) start_pos = scale_rect.bottomLeft() end_pos = scale_rect.topLeft() elif position == "Bottom": scale_rect = QRectF(shift_length * w, (1 - shift_width - width) * h, length * w, width * h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.left(), scale_rect.center().y()) gr.setFinalStop(scale_rect.right(), scale_rect.center().y()) start_pos = scale_rect.topLeft() end_pos = scale_rect.topRight() elif position == "Left": scale_rect = QRectF(shift_width * w, shift_length * h, width * w, length * h) limit_rect(scale_rect, viewport, lim_width, lim_height) gr.setStart(scale_rect.center().x(), scale_rect.bottom()) gr.setFinalStop(scale_rect.center().x(), scale_rect.top()) start_pos = scale_rect.bottomRight() end_pos = scale_rect.topRight() else: raise ValueError("Invalid scale position: %s" % position) shift_pos = (end_pos - start_pos) / delta_value if position in ["Left", "Right"]: is_vertical = True length = scale_rect.height() else: is_vertical = False length = scale_rect.width() # Get the ticks ticks = self.selectValues(length, is_vertical, painter) if len(ticks) == 0: return ticks_str, ticks_extra = self._tick2str(ticks) # Figure the shifts dist_to_bar = self.text_to_bar max_width = 0 max_height = 0 for t in ticks_str: rect = metric.boundingRect(t) max_width = max(rect.width(), max_width) max_height = max(rect.height(), max_height) if position == "Left": shift_left = dist_to_bar shift_top = None elif position == "Right": shift_left = -dist_to_bar - max_width shift_top = None elif position == "Top": shift_left = None shift_top = dist_to_bar else: shift_left = None shift_top = -dist_to_bar - max_height painter.save() painter.translate(viewport.topLeft()) #print("viewport.topLeft() = {0}x{1}".format(viewport.left(), viewport.top())) painter.setBrush(gr) line_pen = QPen(line_color) line_pen.setWidth(line_thickness) painter.setPen(line_pen) painter.drawRect(scale_rect) bounding_rect |= scale_rect #print("Scale rect: +{0}+{1}x{2}x{3}".format(scale_rect.left(), #scale_rect.top(), scale_rect.width(), scale_rect.height())) painter.setFont(font) painter.setPen(text_color) for ts, t in zip(ticks_str, ticks): r = metric.boundingRect(ts) pos = start_pos + shift_pos * (t - value_range[0]) if shift_left is None: pos.setX(pos.x() - r.width() / 2) else: pos.setX(pos.x() + shift_left) if shift_top is None: pos.setY(pos.y() - r.height() / 2) else: pos.setY(pos.y() + shift_top) r.moveTo(pos) real_rect = painter.drawText( r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, ts) bounding_rect |= real_rect if ticks_extra is not None or self.unit: unit = self.unit exp_width = width = space_width = 0 exp_txt = "" r = exp_r = unit_r = QRectF() exp_font = None if ticks_extra is not None: exp_txt = u"×10" r = metric.boundingRect(exp_txt) exp_font = QFont(font) exp_size = self.exp_size if exp_font.pixelSize() != -1: exp_font.setPixelSize(exp_size * exp_font.pixelSize()) else: exp_font.setPointSizeF(exp_size * exp_font.pointSizeF()) exp_metric = QFontMetricsF(exp_font, painter.device()) exp_r = exp_metric.boundingRect(ticks_extra) if unit: unit_r = metric.boundingRect(unit) total_width = r.width() + exp_r.width() + unit_r.width() total_height = max(r.height(), unit_r.height()) + exp_r.height() / 2 pos = scale_rect.topRight() log_debug("top right of scale bar = (%g,%g)" % (pos.x(), pos.y())) log_debug("Size of image = (%d,%d)" % (w, h)) log_debug("Size of text = (%g,%g)" % (total_width, total_height)) if position == "Bottom": pos.setY(pos.y() + scale_rect.height() + dist_to_bar) pos.setX(pos.x() - total_width) elif position == "Top": pos.setY(pos.y() - dist_to_bar - total_height) pos.setX(pos.x() - total_width) else: # position == "left" or "right" pos.setX(pos.x() - (scale_rect.width() + total_width) / 2) if pos.x() < 0: pos.setX(dist_to_bar) elif pos.x() + total_width + dist_to_bar > w: pos.setX(w - total_width - dist_to_bar) pos.setY(pos.y() - dist_to_bar - total_height) log_debug("Display unit at position: (%g,%g)" % (pos.x(), pos.y())) if ticks_extra is not None: r.moveTo(pos) real_rect = painter.drawText( r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, exp_txt) bounding_rect |= real_rect pos.setX(pos.x() + r.width()) pos.setY(pos.y() - metric.ascent() / 2) exp_r.moveTo(pos) painter.setFont(exp_font) real_rect = painter.drawText( exp_r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, ticks_extra) bounding_rect |= real_rect pos.setY(pos.y() + metric.ascent() / 2) if unit: pos.setX(pos.x() + space_width + exp_r.width()) unit_r.moveTo(pos) painter.setFont(font) real_rect = painter.drawText( unit_r, Qt.TextDontClip | Qt.AlignVCenter | Qt.AlignHCenter, unit) bounding_rect |= real_rect # Draw the ticks now painter.setPen(line_pen) tick_size = self.tick_size if is_vertical: width = scale_rect.width() * tick_size else: width = scale_rect.height() * tick_size pen_width = painter.pen().widthF() if pen_width == 0: pen_width = 1.0 for t in ticks: pos1 = start_pos + shift_pos * (t - value_range[0]) pos2 = QPointF(pos1) if is_vertical: pos1.setX(scale_rect.left() + pen_width) pos2.setX(pos1.x() + width - pen_width) painter.drawLine(pos1, pos2) pos1.setX(scale_rect.right() - pen_width) pos2.setX(pos1.x() - width + pen_width) painter.drawLine(pos1, pos2) else: pos1.setY(scale_rect.top() + pen_width) pos2.setY(pos1.y() + width - pen_width) painter.drawLine(pos1, pos2) pos1.setY(scale_rect.bottom() - pen_width) pos2.setY(pos1.y() - width + pen_width) painter.drawLine(pos1, pos2) painter.restore() bounding_rect = bounding_rect.adjusted(-pen_width, -pen_width, pen_width, pen_width) return bounding_rect
class PixmapDial(QDial): HORIZONTAL = 0 VERTICAL = 1 CUSTOM_PAINT_CARLA_WET = 1 CUSTOM_PAINT_CARLA_VOL = 2 CUSTOM_PAINT_CARLA_L = 3 CUSTOM_PAINT_CARLA_R = 4 HOVER_MIN = 0 HOVER_MAX = 9 def __init__(self, parent): QDial.__init__(self, parent) self.m_pixmap = QPixmap(":/bitmaps/dial_01d.png") self.m_pixmap_n_str = "01" self.m_custom_paint = 0 self.m_hovered = False self.m_hover_step = self.HOVER_MIN if self.m_pixmap.width() > self.m_pixmap.height(): self.m_orientation = self.HORIZONTAL else: self.m_orientation = self.VERTICAL self.m_label = "" self.m_label_pos = QPointF(0.0, 0.0) self.m_label_width = 0 self.m_label_height = 0 self.m_label_gradient = QLinearGradient(0, 0, 0, 1) if self.palette().window().color().lightness() > 100: # Light background self.m_color1 = QColor(100, 100, 100, 255) self.m_color2 = QColor(0, 0, 0, 0) self.m_colorT = [self.palette().text().color(), self.palette().mid().color()] else: # Dark background self.m_color1 = QColor(0, 0, 0, 255) self.m_color2 = QColor(0, 0, 0, 0) self.m_colorT = [Qt.white, Qt.darkGray] self.updateSizes() def getSize(self): return self.p_size def setCustomPaint(self, paint): self.m_custom_paint = paint self.update() def setEnabled(self, enabled): if self.isEnabled() != enabled: self.m_pixmap.load(":/bitmaps/dial_%s%s.png" % (self.m_pixmap_n_str, "" if enabled else "d")) self.updateSizes() self.update() QDial.setEnabled(self, enabled) def setLabel(self, label): self.m_label = label self.m_label_width = QFontMetrics(self.font()).width(label) self.m_label_height = QFontMetrics(self.font()).height() self.m_label_pos.setX((self.p_size / 2) - (self.m_label_width / 2)) self.m_label_pos.setY(self.p_size + self.m_label_height) self.m_label_gradient.setColorAt(0.0, self.m_color1) self.m_label_gradient.setColorAt(0.6, self.m_color1) self.m_label_gradient.setColorAt(1.0, self.m_color2) self.m_label_gradient.setStart(0, self.p_size / 2) self.m_label_gradient.setFinalStop(0, self.p_size + self.m_label_height + 5) self.m_label_gradient_rect = QRectF(self.p_size * 1 / 8, self.p_size / 2, self.p_size * 6 / 8, self.p_size + self.m_label_height + 5) self.update() def setPixmap(self, pixmap_id): if pixmap_id > 10: self.m_pixmap_n_str = str(pixmap_id) else: self.m_pixmap_n_str = "0%i" % pixmap_id self.m_pixmap.load(":/bitmaps/dial_%s%s.png" % (self.m_pixmap_n_str, "" if self.isEnabled() else "d")) if self.m_pixmap.width() > self.m_pixmap.height(): self.m_orientation = self.HORIZONTAL else: self.m_orientation = self.VERTICAL self.updateSizes() self.update() def minimumSizeHint(self): return QSize(self.p_size, self.p_size) def sizeHint(self): return QSize(self.p_size, self.p_size) def updateSizes(self): self.p_width = self.m_pixmap.width() self.p_height = self.m_pixmap.height() if self.p_width < 1: self.p_width = 1 if self.p_height < 1: self.p_height = 1 if self.m_orientation == self.HORIZONTAL: self.p_size = self.p_height self.p_count = self.p_width / self.p_height else: self.p_size = self.p_width self.p_count = self.p_height / self.p_width self.setMinimumSize(self.p_size, self.p_size + self.m_label_height + 5) self.setMaximumSize(self.p_size, self.p_size + self.m_label_height + 5) def enterEvent(self, event): self.m_hovered = True if self.m_hover_step == self.HOVER_MIN: self.m_hover_step = self.HOVER_MIN + 1 QDial.enterEvent(self, event) def leaveEvent(self, event): self.m_hovered = False if self.m_hover_step == self.HOVER_MAX: self.m_hover_step = self.HOVER_MAX - 1 QDial.leaveEvent(self, event) def paintEvent(self, event): painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing, True) if self.m_label: painter.setPen(self.m_color2) painter.setBrush(self.m_label_gradient) painter.drawRect(self.m_label_gradient_rect) painter.setPen(self.m_colorT[0] if self.isEnabled() else self.m_colorT[1]) painter.drawText(self.m_label_pos, self.m_label) if self.isEnabled(): current = float(self.value() - self.minimum()) divider = float(self.maximum() - self.minimum()) if divider == 0.0: return target = QRectF(0.0, 0.0, self.p_size, self.p_size) value = (current / divider) ## Regular knobs #else: per = int((self.p_count - 1) * (current / divider)) if self.m_orientation == self.HORIZONTAL: xpos = self.p_size * per ypos = 0.0 else: xpos = 0.0 ypos = self.p_size * per source = QRectF(xpos, ypos, self.p_size, self.p_size) painter.drawPixmap(target, self.m_pixmap, source) # Custom knobs (Dry/Wet and Volume) if self.m_custom_paint in (self.CUSTOM_PAINT_CARLA_WET, self.CUSTOM_PAINT_CARLA_VOL): # knob color colorGreen = QColor(0x5D, 0xE7, 0x3D, 191 + self.m_hover_step*7) colorBlue = QColor(0x3E, 0xB8, 0xBE, 191 + self.m_hover_step*7) #colorGreen = QColor(0x5D + self.m_hover_step*6, 0xE7 + self.m_hover_step*1, 0x3D + self.m_hover_step*5) #colorBlue = QColor(0x52 + self.m_hover_step*8, 0xEE + self.m_hover_step*1, 0xF8 + self.m_hover_step/2) # draw small circle ballPath = QPainterPath() ballRect = QRectF(8.0, 8.0, 15.0, 15.0) ballPath.addEllipse(ballRect) #painter.drawRect(ballRect) ballValue = (0.375 + 0.75*value) % 1.0 ballPoint = ballPath.pointAtPercent(ballValue) # draw arc startAngle = 216*16 spanAngle = -252.0*16*value if self.m_custom_paint == self.CUSTOM_PAINT_CARLA_WET: painter.setBrush(colorBlue) painter.setPen(QPen(colorBlue, 0)) painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2)) gradient = QConicalGradient(15.5, 15.5, -45) gradient.setColorAt(0.0, colorBlue) gradient.setColorAt(0.125, colorBlue) gradient.setColorAt(0.625, colorGreen) gradient.setColorAt(0.75, colorGreen) gradient.setColorAt(0.76, colorGreen) gradient.setColorAt(1.0, colorGreen) painter.setBrush(gradient) painter.setPen(QPen(gradient, 3)) else: painter.setBrush(colorBlue) painter.setPen(QPen(colorBlue, 0)) painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.2, 2.2)) painter.setBrush(colorBlue) painter.setPen(QPen(colorBlue, 3)) painter.drawArc(4.0, 4.0, 26.0, 26.0, startAngle, spanAngle) # Custom knobs (L and R) elif self.m_custom_paint in (self.CUSTOM_PAINT_CARLA_L, self.CUSTOM_PAINT_CARLA_R): # knob color color = QColor(0xAD + self.m_hover_step*5, 0xD5 + self.m_hover_step*4, 0x4B + self.m_hover_step*5) # draw small circle ballPath = QPainterPath() ballRect = QRectF(7.0, 8.0, 11.0, 12.0) ballPath.addEllipse(ballRect) #painter.drawRect(ballRect) ballValue = (0.375 + 0.75*value) % 1.0 ballPoint = ballPath.pointAtPercent(ballValue) painter.setBrush(color) painter.setPen(QPen(color, 0)) painter.drawEllipse(QRectF(ballPoint.x(), ballPoint.y(), 2.0, 2.0)) # draw arc if self.m_custom_paint == self.CUSTOM_PAINT_CARLA_L: startAngle = 216*16 spanAngle = -252.0*16*value elif self.m_custom_paint == self.CUSTOM_PAINT_CARLA_R: startAngle = 324.0*16 spanAngle = 252.0*16*(1.0-value) else: return painter.setPen(QPen(color, 2)) painter.drawArc(3.5, 4.5, 22.0, 22.0, startAngle, spanAngle) if self.HOVER_MIN < self.m_hover_step < self.HOVER_MAX: self.m_hover_step += 1 if self.m_hovered else -1 QTimer.singleShot(20, self, SLOT("update()")) elif not self.m_custom_paint: target = QRectF(0.0, 0.0, self.p_size, self.p_size) source = target painter.drawPixmap(target, self.m_pixmap, source) def resizeEvent(self, event): self.updateSizes() QDial.resizeEvent(self, event)