Merge pull request #543 from acq4/target

Add targetitem class
This commit is contained in:
Luke Campagnola 2017-09-03 22:29:14 -07:00 committed by GitHub
commit 969cdac094

View File

@ -0,0 +1,125 @@
from ..Qt import QtGui, QtCore
import numpy as np
from ..Point import Point
from .. import functions as fn
from .GraphicsObject import GraphicsObject
from .TextItem import TextItem
class TargetItem(GraphicsObject):
"""Draws a draggable target symbol (circle plus crosshair).
The size of TargetItem will remain fixed on screen even as the view is zoomed.
Includes an optional text label.
"""
sigDragged = QtCore.Signal(object)
def __init__(self, movable=True, radii=(5, 10, 10), pen=(255, 255, 0), brush=(0, 0, 255, 100)):
GraphicsObject.__init__(self)
self._bounds = None
self._radii = radii
self._picture = None
self.movable = movable
self.moving = False
self.label = None
self.labelAngle = 0
self.pen = fn.mkPen(pen)
self.brush = fn.mkBrush(brush)
def setLabel(self, label):
if label is None:
if self.label is not None:
self.label.scene().removeItem(self.label)
self.label = None
else:
if self.label is None:
self.label = TextItem()
self.label.setParentItem(self)
self.label.setText(label)
self._updateLabel()
def setLabelAngle(self, angle):
self.labelAngle = angle
self._updateLabel()
def boundingRect(self):
if self._picture is None:
self._drawPicture()
return self._bounds
def dataBounds(self, axis, frac=1.0, orthoRange=None):
return [0, 0]
def viewTransformChanged(self):
self._picture = None
self.prepareGeometryChange()
self._updateLabel()
def _updateLabel(self):
if self.label is None:
return
# find an optimal location for text at the given angle
angle = self.labelAngle * np.pi / 180.
lbr = self.label.boundingRect()
center = lbr.center()
a = abs(np.sin(angle) * lbr.height()*0.5)
b = abs(np.cos(angle) * lbr.width()*0.5)
r = max(self._radii) + 2 + max(a, b)
pos = self.mapFromScene(self.mapToScene(QtCore.QPointF(0, 0)) + r * QtCore.QPointF(np.cos(angle), -np.sin(angle)) - center)
self.label.setPos(pos)
def paint(self, p, *args):
if self._picture is None:
self._drawPicture()
self._picture.play(p)
def _drawPicture(self):
self._picture = QtGui.QPicture()
p = QtGui.QPainter(self._picture)
p.setRenderHint(p.Antialiasing)
# Note: could do this with self.pixelLength, but this is faster.
o = self.mapToScene(QtCore.QPointF(0, 0))
px = abs(1.0 / (self.mapToScene(QtCore.QPointF(1, 0)) - o).x())
py = abs(1.0 / (self.mapToScene(QtCore.QPointF(0, 1)) - o).y())
r, w, h = self._radii
w = w * px
h = h * py
rx = r * px
ry = r * py
rect = QtCore.QRectF(-rx, -ry, rx*2, ry*2)
p.setPen(self.pen)
p.setBrush(self.brush)
p.drawEllipse(rect)
p.drawLine(Point(-w, 0), Point(w, 0))
p.drawLine(Point(0, -h), Point(0, h))
p.end()
bx = max(w, rx)
by = max(h, ry)
self._bounds = QtCore.QRectF(-bx, -by, bx*2, by*2)
def mouseDragEvent(self, ev):
if not self.movable:
return
if ev.button() == QtCore.Qt.LeftButton:
if ev.isStart():
self.moving = True
self.cursorOffset = self.pos() - self.mapToParent(ev.buttonDownPos())
self.startPosition = self.pos()
ev.accept()
if not self.moving:
return
self.setPos(self.cursorOffset + self.mapToParent(ev.pos()))
if ev.isFinish():
self.moving = False
self.sigDragged.emit(self)
def hoverEvent(self, ev):
if self.movable:
ev.acceptDrags(QtCore.Qt.LeftButton)