def paintEvent(self, event): QFrame.paintEvent(self, event) text = QDateTime.currentDateTime().toString(Qt.SystemLocaleLongDate) logicalRect = QRectF(QPointF(0, 0), QSizeF(QFontMetrics(self.font()).size(Qt.TextSingleLine, text))) physicalRect, frameWidth = QRectF(self.rect()), self.frameWidth() physicalRect.adjust(frameWidth, frameWidth, -frameWidth, -frameWidth) scaleForWidth = physicalRect.width() / logicalRect.width() scaleForHeight = physicalRect.height() / logicalRect.height() logicalRect.moveTo(frameWidth / scaleForWidth , frameWidth / scaleForHeight) painter = QStylePainter(self) painter.scale(scaleForWidth, scaleForHeight) painter.drawText(logicalRect, Qt.AlignCenter, text)
def exportAsImage(self): filename = unicode(QFileDialog.getSaveFileName(self, self.tr('Save Model As Image'), '', self.tr('PNG files (*.png *.PNG)'))) if not filename: return if not filename.lower().endswith('.png'): filename += '.png' totalRect = QRectF(0, 0, 1, 1) for item in self.scene.items(): totalRect = totalRect.united(item.sceneBoundingRect()) totalRect.adjust(-10, -10, 10, 10) img = QImage(totalRect.width(), totalRect.height(), QImage.Format_ARGB32_Premultiplied) img.fill(Qt.white) painter = QPainter() painter.setRenderHint(QPainter.Antialiasing) painter.begin(img) self.scene.render(painter, totalRect, totalRect) painter.end() img.save(filename)
def exportAsImage(self): filename = unicode( QFileDialog.getSaveFileName(self, self.tr('Save Model As Image'), '', self.tr('PNG files (*.png *.PNG)'))) if not filename: return if not filename.lower().endswith('.png'): filename += '.png' totalRect = QRectF(0, 0, 1, 1) for item in self.scene.items(): totalRect = totalRect.united(item.sceneBoundingRect()) totalRect.adjust(-10, -10, 10, 10) img = QImage(totalRect.width(), totalRect.height(), QImage.Format_ARGB32_Premultiplied) img.fill(Qt.white) painter = QPainter() painter.setRenderHint(QPainter.Antialiasing) painter.begin(img) self.scene.render(painter, totalRect, totalRect) painter.end() img.save(filename)
def paintEvent(self, event): QFrame.paintEvent(self, event) text = QDateTime.currentDateTime().toString(Qt.SystemLocaleLongDate) logicalRect = QRectF( QPointF(0, 0), QSizeF(QFontMetrics(self.font()).size(Qt.TextSingleLine, text))) physicalRect, frameWidth = QRectF(self.rect()), self.frameWidth() physicalRect.adjust(frameWidth, frameWidth, -frameWidth, -frameWidth) scaleForWidth = physicalRect.width() / logicalRect.width() scaleForHeight = physicalRect.height() / logicalRect.height() logicalRect.moveTo(frameWidth / scaleForWidth, frameWidth / scaleForHeight) painter = QStylePainter(self) painter.scale(scaleForWidth, scaleForHeight) painter.drawText(logicalRect, Qt.AlignCenter, text)
def ensureZoomFit(self): if self._data: prev_rect = self._previousScene.sceneRect() cur_rect = self._currentScene.sceneRect() prev_wnd = QRectF(self.ui.previousData.childrenRect()) cur_wnd = QRectF(self.ui.currentData.childrenRect()) prev_matrix = self.ui.previousData.matrix() cur_matrix = self.ui.currentData.matrix() prev_mapped_rect = prev_matrix.mapRect(prev_rect) cur_mapped_rect = cur_matrix.mapRect(cur_rect) if (prev_mapped_rect.width() < prev_wnd.width() or prev_mapped_rect.height() < prev_wnd.height() or cur_mapped_rect.width() < cur_wnd.width() or cur_mapped_rect.height() < cur_wnd.height()): self.on_action_Fit_triggered()
def paintEvent(self, event): QWidget.paintEvent(self, event) rect = QRectF(self.rect()) painter = QPainter(self) painter.setBrush(self._corFundo) pen = QPen() pen.setColor(Qt.gray) painter.setPen(pen) painter.drawRoundedRect(QRectF(2, 1, rect.width()-6, rect.height()-4), 8, 2) if self.getPorcentagem() > 0: painter.setBrush(self._corBarra) larguraBarra = self.getPorcentagem()*((rect.width()-6)/100.) painter.drawRoundedRect(QRectF(2, 1, larguraBarra, rect.height()-4), 8, 2) painter.end()
def data2scene(self, data2scene): self._data2scene = data2scene self.scene2data, isInvertible = data2scene.inverted() assert isInvertible for patchNr in range(self._patchAccessor.patchCount): # the patch accessor uses the data coordinate system. # because the patch is drawn on the screen, its holds coordinates # corresponding to Qt's QGraphicsScene's system, which need to be # converted to scene coordinates # the image rectangle includes an overlap margin imageRectF = data2scene.mapRect( self._patchAccessor.patchRectF(patchNr, self.overlap)) # the patch rectangle has per default no overlap patchRectF = data2scene.mapRect( self._patchAccessor.patchRectF(patchNr, 0)) # add a little overlap when the overlap_draw setting is # activated if self._overlap_draw != 0: patchRectF = QRectF( patchRectF.x() - self._overlap_draw, patchRectF.y() - self._overlap_draw, patchRectF.width() + 2 * self._overlap_draw, patchRectF.height() + 2 * self._overlap_draw) patchRect = QRect(round(patchRectF.x()), round(patchRectF.y()), round(patchRectF.width()), round(patchRectF.height())) # the image rectangles of neighboring patches can overlap # slightly, to account for inaccuracies in sub-pixel # rendering of many ImagePatch objects imageRect = QRect(round(imageRectF.x()), round(imageRectF.y()), round(imageRectF.width()), round(imageRectF.height())) self.imageRectFs[patchNr] = imageRectF self.dataRectFs[patchNr] = imageRectF self.tileRectFs[patchNr] = patchRectF self.imageRects[patchNr] = imageRect self.tileRects[patchNr] = patchRect
def data2scene(self, data2scene): self._data2scene = data2scene self.scene2data, isInvertible = data2scene.inverted() assert isInvertible for patchNr in range(self._patchAccessor.patchCount): # the patch accessor uses the data coordinate system. # because the patch is drawn on the screen, its holds coordinates # corresponding to Qt's QGraphicsScene's system, which need to be # converted to scene coordinates # the image rectangle includes an overlap margin imageRectF = data2scene.mapRect(self._patchAccessor.patchRectF(patchNr, self.overlap)) # the patch rectangle has per default no overlap patchRectF = data2scene.mapRect(self._patchAccessor.patchRectF(patchNr, 0)) # add a little overlap when the overlap_draw setting is # activated if self._overlap_draw != 0: patchRectF = QRectF(patchRectF.x() - self._overlap_draw, patchRectF.y() - self._overlap_draw, patchRectF.width() + 2 * self._overlap_draw, patchRectF.height() + 2 * self._overlap_draw) patchRect = QRect(round(patchRectF.x()), round(patchRectF.y()), round(patchRectF.width()), round(patchRectF.height())) # the image rectangles of neighboring patches can overlap # slightly, to account for inaccuracies in sub-pixel # rendering of many ImagePatch objects imageRect = QRect(round(imageRectF.x()), round(imageRectF.y()), round(imageRectF.width()), round(imageRectF.height())) self.imageRectFs[patchNr] = imageRectF self.dataRectFs[ patchNr] = imageRectF self.tileRectFs[ patchNr] = patchRectF self.imageRects[ patchNr] = imageRect self.tileRects[ patchNr] = patchRect
def wait(self): array_data = self._arrayreq.wait() rectf = self.rectf if array_data.handedness_switched: # array_data should be of type slicingtools.ProjectedArray rectf = QRectF(rectf.height(), rectf.width()) from PyQt4.QtGui import QPainter img = QImage( QSize( self.rectf.width(), self.rectf.height() ), QImage.Format_ARGB32_Premultiplied) img.fill(0xffffffff) p = QPainter(img) p.drawImage(0,0, img) DummyItem(self.rectf).paint(p, None) return img
def grab_svg(scene): """ Return a SVG rendering of the scene contents. Parameters ---------- scene : :class:`CanvasScene` """ from PyQt4.QtSvg import QSvgGenerator svg_buffer = QBuffer() gen = QSvgGenerator() gen.setOutputDevice(svg_buffer) items_rect = scene.itemsBoundingRect().adjusted(-10, -10, 10, 10) if items_rect.isNull(): items_rect = QRectF(0, 0, 10, 10) width, height = items_rect.width(), items_rect.height() rect_ratio = float(width) / height # Keep a fixed aspect ratio. aspect_ratio = 1.618 if rect_ratio > aspect_ratio: height = int(height * rect_ratio / aspect_ratio) else: width = int(width * aspect_ratio / rect_ratio) target_rect = QRectF(0, 0, width, height) source_rect = QRectF(0, 0, width, height) source_rect.moveCenter(items_rect.center()) gen.setSize(target_rect.size().toSize()) gen.setViewBox(target_rect) painter = QPainter(gen) # Draw background. painter.setBrush(QBrush(Qt.white)) painter.drawRect(target_rect) # Render the scene scene.render(painter, target_rect, source_rect) painter.end() buffer_str = str(svg_buffer.buffer()) return unicode(buffer_str.decode("utf-8"))
def relayout(self): """Approximate Fruchterman-Reingold spring layout""" nodes = list(self.nodes.values()) pos = np.array([(np.cos(i / len(nodes) * 2 * np.pi + np.pi / 4), np.sin(i / len(nodes) * 2 * np.pi + np.pi / 4)) for i in range(1, 1 + len(nodes))]) K = 1 / np.sqrt(pos.shape[0]) GRAVITY, ITERATIONS = 10, 20 TEMPERATURES = np.linspace(.3, .01, ITERATIONS) for temp in chain([.8, .5], TEMPERATURES): # Repulsive forces delta = pos[:, np.newaxis, :] - pos delta /= np.abs(delta).sum( 2)[:, :, np.newaxis]**2 # NOTE: This warning was expected delta = np.nan_to_num(delta) # Reverse the effect of zero-division disp = -delta.sum(0) * K * K # Attractive forces for edge in self.edges: n1, n2 = nodes.index(edge.source), nodes.index(edge.dest) delta = pos[n1] - pos[n2] magnitude = np.abs(delta).sum() disp[n1] -= delta * magnitude / K disp[n2] += delta * magnitude / K # Gravity; tend toward center magnitude = np.sqrt(np.sum(np.abs(pos)**2, 1)) disp -= (pos.T * K * GRAVITY * magnitude).T # Limit max displacement and reposition magnitude = np.sqrt(np.sum(np.abs(disp)**2, 1)) pos += (disp.T / magnitude).T * np.clip(np.abs(disp), 0, temp) for node, position in zip(nodes, 500 * pos): node.setPos(*position) for edge in self.edges: edge.adjust() MARGIN, rect = 10, self.scene().itemsBoundingRect() rect = QRectF(rect.x() - MARGIN, rect.y() - MARGIN, rect.width() + 2 * MARGIN, rect.height() + 2 * MARGIN) self.scene().setSceneRect(rect) self.scene().invalidate()
def relayout(self): """Approximate Fruchterman-Reingold spring layout""" nodes = list(self.nodes.values()) pos = np.array([(np.cos(i/len(nodes)*2*np.pi + np.pi/4), np.sin(i/len(nodes)*2*np.pi + np.pi/4)) for i in range(1, 1 + len(nodes))]) K = 1 / np.sqrt(pos.shape[0]) GRAVITY, ITERATIONS = 10, 20 TEMPERATURES = np.linspace(.3, .01, ITERATIONS) for temp in chain([.8, .5], TEMPERATURES): # Repulsive forces delta = pos[:, np.newaxis, :] - pos delta /= np.abs(delta).sum(2)[:, :, np.newaxis]**2 # NOTE: This warning was expected delta = np.nan_to_num(delta) # Reverse the effect of zero-division disp = -delta.sum(0)*K*K # Attractive forces for edge in self.edges: n1, n2 = nodes.index(edge.source), nodes.index(edge.dest) delta = pos[n1] - pos[n2] magnitude = np.abs(delta).sum() disp[n1] -= delta*magnitude/K disp[n2] += delta*magnitude/K # Gravity; tend toward center magnitude = np.sqrt(np.sum(np.abs(pos)**2, 1)) disp -= (pos.T*K*GRAVITY*magnitude).T # Limit max displacement and reposition magnitude = np.sqrt(np.sum(np.abs(disp)**2, 1)) pos += (disp.T / magnitude).T * np.clip(np.abs(disp), 0, temp) for node, position in zip(nodes, 500*pos): node.setPos(*position) for edge in self.edges: edge.adjust() MARGIN, rect = 10, self.scene().itemsBoundingRect() rect = QRectF(rect.x() - MARGIN, rect.y() - MARGIN, rect.width() + 2*MARGIN, rect.height() + 2*MARGIN) self.scene().setSceneRect(rect) self.scene().invalidate()
class DummyRasterRequest(object): """ For stupid tests. Uses DummyItem, but rasterizes it to turn it into a QImage. """ def __init__(self, arrayreq, rect): self.rectf = QRectF(rect) self._arrayreq = arrayreq def wait(self): array_data = self._arrayreq.wait() rectf = self.rectf if array_data.handedness_switched: # array_data should be of type slicingtools.ProjectedArray rectf = QRectF(rectf.height(), rectf.width()) from PyQt4.QtGui import QPainter img = QImage( QSize( self.rectf.width(), self.rectf.height() ), QImage.Format_ARGB32_Premultiplied) img.fill(0xffffffff) p = QPainter(img) p.drawImage(0,0, img) DummyItem(self.rectf).paint(p, None) return img
def run_loader(self): filename = self.result try: self.retryObject = None # First, prepare the data by getting the images and computing how big they # should be f = open(filename) first_line = f.readline() f.close() if first_line.startswith("TRKR_VERSION"): result = Result(None) result.load(self.result, **self._loading_arguments) result_type = "Growth" else: result = TrackingData() result.load(self.result, **self._loading_arguments) result_type = "Data" self.result = result self.result_type = result_type if result_type == "Data": data = result images = data.images_name if data.cells: self.has_cells = True self.has_walls = True else: self.has_cells = False self.has_walls = False self.has_points = bool(data.cell_points) else: data = result.data images = result.images self.has_cells = False self.has_walls = False self.has_points = False self.images = images cache = image_cache.cache self.update_nb_images(len(result)) bbox = QRectF() ms = data.minScale() for i in range(len(result)): img_name = images[i] img_data = data[img_name] img = cache.image(data.image_path(img_name)) matrix = QTransform() matrix = img_data.matrix() sc = QTransform() sc.scale(1.0/ms, 1.0/ms) matrix *= sc r = QRectF(img.rect()) rbox = matrix.map(QPolygonF(r)).boundingRect() bbox |= rbox log_debug("Image '%s':\n\tSize = %gx%g\n\tTransformed = %gx%g %+g %+g\n\tGlobal bbox = %gx%g %+g %+g\n" % (img_name, r.width(), r.height(), rbox.width(), rbox.height(), rbox.left(), rbox.top(), bbox.width(), bbox.height(), bbox.left(), bbox.top())) log_debug("Matrix:\n%g\t%g\t%g\n%g\t%g\t%g\n" % (matrix.m11(), matrix.m12(), matrix.dx(), matrix.m21(), matrix.m22(), matrix.dy())) if result_type == "Growth": if result.cells[i]: self.has_cells = True if result.walls[i]: self.has_walls = True self.has_points = bool(result.data.cell_points) self.nextImage() translate = bbox.topLeft() translate *= -1 self.translate = translate size = bbox.size().toSize() self.img_size = size self._crop = QRect(QPoint(0,0), size) self.finished() self._loading_arguments = {} # All done, we don't need that anymore except RetryTrackingDataException as ex: ex.filename = filename self.retryObject = ex self.finished() return except Exception as ex: _, _, exceptionTraceback = sys.exc_info() self.abort(ex, traceback=exceptionTraceback) raise
def setAxisIntersect(self, intersect): self._axisIntersect = intersect #print "SkeletonsLayer(axis=%d) is updating intersect=%d" % (self._axis, self._axisIntersect) nodes, eIntersected, ePlane = self._3d._skeletons.intersect(self._axis, self._axisIntersect) #update existing items toRemove = [] for node, item in self._node2view.iteritems(): if node.pos[self._axis] != self._axisIntersect: self._scene.removeItem(item) toRemove.append(node) elif node.pointF(self._axis) != item.pos(): item.setPos( self._scene.data2scene.map( node.pointF(self._axis) ) ) if node.isSelected() != item.isSelected(): item.setSelected(node.isSelected()) assert item.isSelected() == node.isSelected() i = 0 newSize = [0,0] for j in range(3): if j == self._axis: continue newSize[i] = node.shape[j] i += 1 newRectF = QRectF(0,0,*newSize) newRectF = self._scene.data2scene.mapRect(newRectF) item.setRect(QRectF(-newRectF.width()/2.0, -newRectF.height()/2.0, newRectF.width(), newRectF.height())) for r in toRemove: del self._node2view[r] #add new views for nodes for n in nodes: if n in self._node2view: continue pos2D = list(n.pos) del pos2D[self._axis] shape2D = n.shape2D(self._axis) itm = QGraphicsSkeletonNode(shape2D, skeletons=self._3d._skeletons, node = n) itm.setPos(self._scene.data2scene.map(QPointF(*pos2D))) itm.setSelected(n.isSelected()) self._scene.addItem(itm) self._node2view[n] = itm for itm in self._edge2view.values(): self._scene.removeItem(itm) self._edge2view = dict() for e in ePlane: l = QLineF(e[0].pointF(), e[1].pointF()) c1 = e[0].color() c2 = e[1].color() mixColor = QColor( (c1.red()+c2.red())/2, (c1.green()+c2.green())/2, (c1.blue()+c2.blue())/2 ) line = QGraphicsLineItem(self._scene.data2scene.map(l)) line.setPen(QPen(mixColor)) self._scene.addItem(line) self._edge2view[e] = line for theEdge, e in eIntersected: c1 = theEdge[0].color() c2 = theEdge[1].color() mixColor = QColor( (c1.red()+c2.red())/2, (c1.green()+c2.green())/2, (c1.blue()+c2.blue())/2 ) nodeSize = 6 p = QGraphicsRectItem(-nodeSize/2, -nodeSize/2, nodeSize, nodeSize) pos2D = list(e) del pos2D[self._axis] p.setPos(self._scene.data2scene.map(QPointF(*pos2D))) p.setPen(QPen(mixColor)) self._scene.addItem(p) self._edge2view[e] = p
class ENode(QGraphicsObject): onMove = pyqtSignal() onPress = pyqtSignal() kGuiAttributeId = EObject() kGuiAttributeType = EObject() kGuiAttributePlug = EObject() kGuiAttributeParent = EObject() kGuiAttributeParentName = EObject() kGuiAttributeLongName = EObject() kGuiAttributeShortName = EObject() def __init__(self, eNodeHandle): QGraphicsObject.__init__(self) self.setFlag(QGraphicsItem.ItemIsMovable, True) self.setAcceptsHoverEvents(True) self.__isDefaultPen = False self.__pen = None self.__pens = { 0: EDraw.EColor.DefaultLeaveHoverPen, 1: EDraw.EColor.DefaultEnterHoverPen } self.setPen(self.__pens[self.__isDefaultPen]) self.Name = eNodeHandle.Name self.__font = QFont('Helvetica', 8, False) self.__nodeHandle = eNodeHandle self.__nodeHandle.Message.connect(self.__messageFilter) self.__attrRect = QRectF(0, 0, 15, 15) self.__titleRect = QRectF(0, 0, 125, 20) self.__textSpace = QRectF( self.__attrRect.width() + self.pen().width(), 0.0, (self.__titleRect.width() - self.__attrRect.width() * 2 - self.pen().width() * 2) / 2, self.__attrRect.height()) self.__attributes = {} self.__out_attr_step = self.__titleRect.height() + self.pen().width() self.__in_attr_step = self.__titleRect.height() + self.pen().width() self.__buildAttributes() self.__height = max([self.__in_attr_step, self.__out_attr_step]) def __messageFilter(self, message): if message.match(self.__nodeHandle.kMessageAttributeAdded): self.__buildAttribute(message.getData()) def __getAttrShortName(self, attributeName): fm = QFontMetrics(self.__font) shortName = '' if fm.width(attributeName) > self.__textSpace.width(): for x in range(len(attributeName) + 1): if fm.width(shortName) > int(self.__textSpace.width()) - 10: return shortName shortName = attributeName[:x] + '...' return attributeName def __getAttributePosition(self, attrType): attr_x_pos = 0 if attrType.match(EAttribute.kTypeOutput): attr_x_pos = self.__titleRect.width() - self.__attrRect.width() rect = self.__attrRect.translated( QPointF(attr_x_pos, self.__out_attr_step)) point = QPointF((rect.topRight() + rect.bottomRight()) / 2) point.setX(point.x() + self.pen().width() * 2) self.__out_attr_step += self.__attrRect.width() + self.pen().width( ) return [rect, point] rect = self.__attrRect.translated( QPointF(attr_x_pos, self.__in_attr_step)) point = QPointF((rect.topLeft() + rect.bottomLeft()) / 2) point.setX(point.x() - self.pen().width() * 2) self.__in_attr_step += self.__attrRect.width() + self.pen().width() return [rect, point] def __buildAttribute(self, attribute): data = self.__getAttributePosition(attribute.Type) self.__attributes[data[0]] = dict({ self.kGuiAttributeId: attribute.Id, self.kGuiAttributeType: attribute.Type, self.kGuiAttributeParent: self, self.kGuiAttributeParentName: self.__nodeHandle.Name, self.kGuiAttributePlug: data[1], self.kGuiAttributeLongName: attribute.Name, self.kGuiAttributeShortName: self.__getAttrShortName(attribute.Name) }) self.__height = max([self.__in_attr_step, self.__out_attr_step]) self.update() self.onMove.emit() def __buildAttributes(self): for eddAttr in self.__nodeHandle.ls(): self.__buildAttribute(eddAttr) def __toggleHighlight(self): if self.__isDefaultPen: self.__isDefaultPen = False self.setPen(self.__pens[self.__isDefaultPen]) #self.setZValue(0.0) return self.__isDefaultPen = True self.setPen(self.__pens[self.__isDefaultPen]) #self.setZValue(-2.0) @property def Id(self): return self.__nodeHandle.Id def pen(self): return self.__pen def setPen(self, pen): if not isinstance(pen, QPen): raise AttributeError self.__pen = pen @property def Handle(self): return self.__nodeHandle def mapFromPoint(self, QPoint): for attrRect, attrValues in self.__attributes.iteritems(): if attrRect.contains(self.mapFromScene(QPoint)): return attrValues[self.kGuiAttributeId] return self.__nodeHandle.Id def mapFromId(self, attrId): for attrValue in self.__attributes.itervalues(): if attrValue[self.kGuiAttributeId] == attrId: return attrValue return None def hoverEnterEvent(self, mouseEvent): QGraphicsObject.hoverEnterEvent(self, mouseEvent) self.__toggleHighlight() def hoverMoveEvent(self, mouseEvent): QGraphicsObject.hoverMoveEvent(self, mouseEvent) def hoverLeaveEvent(self, mouseEvent): QGraphicsObject.hoverLeaveEvent(self, mouseEvent) self.__toggleHighlight() def mousePressEvent(self, mouseEvent): QGraphicsObject.mousePressEvent(self, mouseEvent) #if mouseEvent.button() == Qt.RightButton: #print self.mapFromPoint(mouseEvent.scenePos()) self.onPress.emit() def mouseDoubleClickEvent(self, mouseEvent): QGraphicsObject.mouseDoubleClickEvent(self, mouseEvent) #self.__nodeHandle.compute() def mouseMoveEvent(self, mouseEvent): QGraphicsObject.mouseMoveEvent(self, mouseEvent) self.onMove.emit() def boundingRect(self): extra = self.pen().width() return self.__titleRect.normalized().adjusted( -extra, -extra, extra, (self.__height - self.__titleRect.height()) + extra) def shape(self): return QGraphicsItem.shape(self) def paint(self, painter, option, widget=None): painter.setBrush(Qt.darkGray) painter.setPen(self.pen()) painter.drawRect(self.boundingRect()) painter.setPen(Qt.NoPen) painter.setBrush(QColor(43, 43, 43)) painter.drawRect(self.__titleRect) painter.setPen(Qt.darkGray) painter.drawText(self.__titleRect, Qt.AlignCenter, self.Name) painter.setPen(Qt.NoPen) painter.setBrush(QColor(60, 63, 65)) for rect in self.__attributes.iterkeys(): painter.drawRect(rect) painter.setBrush(Qt.darkGray) for rect in self.__attributes.iterkeys(): painter.drawPolygon( EDraw.Circle(rect.height() / 3, 3).translated(rect.center())) painter.setPen(QPen(QColor(43, 43, 43), 1.0, Qt.SolidLine)) painter.setBrush(Qt.NoBrush) painter.setFont(self.__font) for attrRect, attrValues in self.__attributes.iteritems(): attrNameRect = self.__textSpace.translated(attrRect.topLeft()) align = Qt.AlignLeft if attrRect.topLeft().x() > 0: attrNameRect = self.__textSpace.translated( QPointF((self.__titleRect.width() / 2) - (attrRect.width() + self.pen().width()), attrRect.topLeft().y())) align = Qt.AlignRight painter.drawText(attrNameRect, align, attrValues[self.kGuiAttributeShortName])
class EFrameLayout(QGraphicsPolygonItem): def __init__(self, parent=None, scene=None): super(EFrameLayout, self).__init__(parent, scene) self.setFlag(QGraphicsItem.ItemIsMovable, True) self.setAcceptsHoverEvents(True) self.__name = QGraphicsTextItem() self.__name.setPlainText('Frame Layout') self.__handleWidth = 500 self.__handleHeight = 20 self.__separator = 5 self.__boundExtra = 3 + self.pen().width() self.__handleRect = QRectF( 0.0 , 0.0 , self.__handleWidth, self.__handleHeight ) self.__controlsBound = 0.0 self.__controls = [] self.__isDefaultPen = False self.__isCollapsed = True self.__pens = { 0: EDraw.EColor.DefaultLeaveHoverPen, 1: EDraw.EColor.DefaultEnterHoverPen } self.setPen(self.__pens[self.__isDefaultPen]) @property def Label(self): return self.__name.toPlainText() @Label.setter def Label(self, label): self.__name.setPlainText( str( label ) ) @property def Width(self): return self.__handleWidth @Width.setter def Width(self, width): self.__handleWidth = width self.updateGeometry() def toggleContentVisibility(self): if not len(self.__controls): return if self.__controls[0].isVisible(): [ control.hide() for control in self.__controls ] self.__isCollapsed = True return [ control.show() for control in self.__controls ] self.__isCollapsed = False def updateGeometry(self): self.__handleRect = QRectF( 0.0 , 0.0 , self.__handleWidth, self.__handleHeight ) if not len(self.__controls) or self.__isCollapsed: self.__controlsBound = 0.0 return self.__controlsBound = 0.0 self.__controlsBound = self.__separator self.__controlsBound += sum( [ control.boundingRect().height() + self.__separator for control in self.__controls ] ) step = self.__handleHeight + self.__separator * 2 for control in self.__controls: control.Name.setTextWidth( self.__controlNameWidth ) control.Width = self.__handleRect.normalized().adjusted( 5.0, 0.0, -5.0, 0.0 ).width() control.setPos( 5.0 , step ) step += control.boundingRect().height() + self.__separator def addControl(self, control): if not isinstance(control, EControlsGroup): raise AttributeError self.__controls.append(control) control.setParentItem(self) control.setFlag(QGraphicsItem.ItemIsMovable, False) self.__controlNameWidth = max([ control.Name.boundingRect().width() for control in self.__controls ]) + 5 self.__isCollapsed = False self.updateGeometry() def clear(self): [ control.setParentItem(None) for control in self.__controls ] self.__controls = [] self.updateGeometry() def mouseDoubleClickEvent(self, mouseEvent): QGraphicsPolygonItem.mouseDoubleClickEvent(self, mouseEvent) self.toggleContentVisibility() self.updateGeometry() def shape(self): return QGraphicsItem.shape(self) def boundingRect(self): return self.__handleRect.normalized().adjusted( 0.0, 0.0, 0.0, self.__controlsBound ) def paint(self, painter, option, widget=None): if not self.__isCollapsed: painter.setPen( QPen( QColor( 0, 0, 0, 50 ), 2 , Qt.SolidLine ) ) painter.setBrush( QColor( 0, 0, 0, 50 ) ) painter.drawRect( self.boundingRect().adjusted( self.pen().width(), self.__handleHeight , -self.pen().width(), 0.0 ) ) painter.setPen(self.pen()) painter.setBrush( EDraw.EColor.LinearGradient( self.__handleRect, Qt.darkGray ) ) #painter.drawPolygon( QPolygonF( self.__handleRect.normalized().adjusted(-self.__boundExtra, 0.0, self.__boundExtra, 0.0 ) ) ) painter.drawPolygon( QPolygonF( self.__handleRect ) ) painter.setPen(Qt.lightGray) r = QRectF( 0.0, 0.0, self.__name.boundingRect().width(), self.__handleRect.height() ) painter.drawText( r, Qt.AlignCenter, self.__name.toPlainText() )
class DrawableNote(DrawableNode, QGraphicsItem): def __init__(self, uml_object): super(DrawableNote, self).__init__(uml_object) QGraphicsItem.__init__(self) self.__bounding_rect = QRectF(0, 0, 100, 100) self.__font = Drawable.get_font() self.__text_margin = 3 self.__note_margin = 10 self.setFlag(QGraphicsItem.ItemIsMovable, 1) self.setFlag(QGraphicsItem.ItemIsSelectable, 1) self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, 1) def boundingRect(self): return self.__bounding_rect def paint(self, painter, style, widget): metrics = QFontMetrics(self.__font) painter.setFont(self.__font) painter.setPen(QColor(0, 0, 0)) painter.fillRect(QRectF(self.__bounding_rect), QBrush(QColor(255, 255, 255), Qt.SolidPattern)) # Draw folded corner first painter.drawLine(self.__bounding_rect.width() - self.__note_margin, 0, self.__bounding_rect.width(), self.__note_margin) painter.drawLine(self.__bounding_rect.width() - self.__note_margin, 0, self.__bounding_rect.width() - self.__note_margin, self.__note_margin) painter.drawLine(self.__bounding_rect.width() - self.__note_margin, self.__note_margin, self.__bounding_rect.width(), self.__note_margin) text_rect = QRect(self.__text_margin, self.__text_margin, self.__bounding_rect.width() - self.__note_margin, self.__bounding_rect.height()) if('text' in self.uml_object): painter.drawText(text_rect, Qt.TextWordWrap, self.uml_object['text']) painter.drawLine(0, 0, self.__bounding_rect.width() - self.__note_margin, 0) painter.drawLine(0, 0, 0, self.__bounding_rect.height()) painter.drawLine(0, self.__bounding_rect.height(), self.__bounding_rect.width(), self.__bounding_rect.height()) painter.drawLine(self.__bounding_rect.width(), self.__note_margin, self.__bounding_rect.width(), self.__bounding_rect.height()) def update(self): metrics = QFontMetrics(self.__font) if('text' in self.uml_object): text = self.uml_object['text'] width = metrics.width(text) height = metrics.height() rect_ratio = (width / height) * 0.337 # LOL MAGIC NUMBER rect_ratio = min(10, rect_ratio) note_width = height * rect_ratio note_height = 2 * note_width / height # no higher than that self.__bounding_rect = QRectF(metrics.boundingRect(QRect(0,0, note_width, note_height), Qt.TextWordWrap | Qt.TextDontClip, text) .adjusted(0, 0, 2 * self.__text_margin + self.__note_margin, 2 * self.__text_margin)) else: self.__bounding_rect = QRectF(0,0,50,50) def itemChange(self, change, value): if(change == QGraphicsItem.ItemPositionChange): for anchor in self.anchors: anchor.connector.update() self.resize_scene_rect() return QGraphicsItem.itemChange(self, change, value) def crop_line(self, line, line_point): global_rect = self.globalBoundingRect() vertexes = [global_rect.topLeft(), global_rect.topRight(), global_rect.bottomRight(), global_rect.bottomLeft(), # Folded corner QPointF(global_rect.topRight().x() - self.__note_margin, global_rect.topRight().y()), QPointF(global_rect.topRight().x(), global_rect.topRight().y() + self.__note_margin) ] intersection_point = QPointF() # Iterate over pairs of vertices that make rectangle edges # Check folded corner first and we don't have to crop # rest of the edges. for (a, b) in [(4, 5), (0, 1), (1, 2), (2, 3), (3, 0)]: bok = QLineF(vertexes[a], vertexes[b]) itype = line.intersect(bok, intersection_point) if(itype == QLineF.BoundedIntersection): if(line_point == 0): return QLineF(intersection_point, line.p2()) else: return QLineF(line.p1(), intersection_point) return line def find_anchor(self): return self.globalBoundingRect().center()
class TreeNode(object): """store data for a class and manage hierarchy""" def __init__(self, classid,name,rect=None,color=None,pos=None,accu = 1.0,parent=None): super(TreeNode, self).__init__() self.classid = classid self.name = name self.parent = parent self.accu = accu self.rect = QRectF(*rect) if rect else rect self.color = QColor(color) if color else color self.pos = QPointF(*pos) if pos else pos self.children = [] if parent: parent.children.append(self) # def __init__(self,jsonobj): # self.__init__(jsonobj['id'],jsonobj['name'],jsonobj['rect'],jsonobj['color'],jsonobj['pos']) # for child in jsonobj['children']: # childItem = TreeNode(child) # self.children.append(childItem) # childItem.parent = self def isLeaf(self): if self.children: return False else: return True def isRoot(self): if self.parent: return False else: return True def toJSON(self): jsonObj = {} jsonObj['id']= self.classid jsonObj['name'] = self.name jsonObj['rect'] = [self.rect.left(),self.rect.top(),self.rect.width(),self.rect.height()] if self.rect else self.rect jsonObj['color'] = str(self.color.name()) if self.color else self.color jsonObj['pos'] = [self.pos.x(),self.pos.y()] if isinstance(self.pos,QPointF) else self.pos jsonObj['accu'] = self.accu jsonObj['children'] = [] for child in self.children: jsonObj['children'].append(child.toJSON()) return jsonObj def __str__(self): tempstr = "%s %s\n" % (self.classid,self.name) for child in self.children: tempstr+= ' '+str(child) return tempstr def findNode(self,id): if self.classid == id: return self for child in self.children: result = child.findNode(id) if result: return result return None def toplogicalDistance(self,id1,id2): if id1==id2: return 0 else: node1 = self.findNode(id1) node2 = self.findNode(id2) if node1 and node2: if node1.parent == node2.parent: return 1 else: return 2 return 0 def matrixDistance(self,id1,id2): if id1==id2: return 0 else: node1 = self.findNode(id1) node2 = self.findNode(id2) if node1 and node2: pos1 = node1.pos + node1.parent.pos pos2 = node2.pos + node2.parent.pos return QLineF(pos1,pos2).length() return 2000.0 def transactionPossibility(self,id1,id2): node1 = self.findNode(id1) node2 = self.findNode(id2) if node1 and node2: return node1.accu * node2.accu else: return 1.0
class SlideshowFrame(object): def __init__(self, win, rect, filename, metadata): self.win = win self.rect = rect self.filename = filename self.metadata = metadata if self.metadata: self.line1 = self.metadata['Name'] self.line2 = "%s Mission" % (self.metadata['Mission']) self.line3 = "%s" % (self.metadata['Time']) else: self.line1 = "" self.line2 = "" self.line3 = "" self.image = QGraphicsPixmapItem() self.win.scene.addItem(self.image) self.image.setTransformationMode(Qt.SmoothTransformation) self.use_two_lines = True self.fontsize1 = 32 self.fontsize2 = 26 self.fontsize3 = 24 self.font1 = QFont('Times New Roman', self.fontsize1) self.font2 = QFont('Times New Roman', self.fontsize2) self.font3 = QFont('Times New Roman', self.fontsize3) self.title1 = self.win.scene.addText(self.line1, self.font1) self.title1.setDefaultTextColor(Qt.white) self.title1.setVisible(False) self.title2 = self.win.scene.addText(self.line2, self.font2) self.title2.setDefaultTextColor(Qt.white) self.title2.setVisible(False) self.title3 = self.win.scene.addText(self.line3, self.font3) self.title3.setDefaultTextColor(Qt.white) self.title3.setVisible(False) self.reservedHeight = 128 self.padding = 20 self.hide() def move(self, x, y): self.rect = QRectF(x, y, self.rect.width(), self.rect.height()) def __rotate(self, metadata, origImgSize): # Qt only handles orientation properly from v5.5 try: # try directly to get the tag, because sometimes get_tags() returns # tags that don't actually are in the file rot = metadata['Exif.Image.Orientation'] except KeyError: # guess :-/ rot = '1' # see http://www.daveperrett.com/images/articles/2012-07-28-exif-orientation-handling-is-a-ghetto/EXIF_Orientations.jpg # we have to 'undo' the rotations, so the numbers are negative if rot == '1': rotate = 0 imgSize = origImgSize if rot == '8': rotate = -90 imgSize = QSize(origImgSize.height(), origImgSize.width()) if rot == '3': rotate = -180 imgSize = origImgSize if rot == '6': rotate = -270 imgSize = QSize(origImgSize.height(), origImgSize.width()) # undo the last rotation and apply the new one self.image.setRotation(rotate) return imgSize def __zoomFit(self, imgSize): reservedHeight = self.reservedHeight + self.padding * 2 hZoom = self.rect.width() / imgSize.width() vZoom = (self.rect.height() - reservedHeight) / imgSize.height() scale = min(hZoom, vZoom) self.image.setScale(scale) width = imgSize.width() * scale height = imgSize.height() * scale self.image.setPos( (self.rect.width() - width) / 2 + self.rect.x(), (self.rect.height() - reservedHeight - height) / 2 + self.rect.y()) def layoutText(self): reservedHeight = self.reservedHeight + self.padding vertical_spacing = (self.reservedHeight - self.title1.boundingRect().height() - self.title2.boundingRect().height() - self.title3.boundingRect().height()) / 3 x = (self.rect.width() - self.title1.boundingRect().width()) / 2 y = self.rect.height() - reservedHeight + vertical_spacing self.title1.setPos(x + self.rect.x(), y + self.rect.y()) x = (self.rect.width() - self.title2.boundingRect().width()) / 2 y = self.rect.height( ) - reservedHeight + vertical_spacing * 2 + self.title1.boundingRect( ).height() self.title2.setPos(x + self.rect.x(), y + self.rect.y()) x = (self.rect.width() - self.title3.boundingRect().width()) / 2 y = self.rect.height( ) - reservedHeight + vertical_spacing * 3 + self.title1.boundingRect( ).height() + self.title2.boundingRect().height() self.title3.setPos(x + self.rect.x(), y + self.rect.y()) def show(self): img = QPixmap(self.filename) try: metadata = GExiv2.Metadata(self.filename) except GLib.Error as e: print(repr(e)) return self.image.setPixmap(img) self.image.setScale(1.0) self.image.setRotation(0) imgSize = self.__rotate(metadata, img.size()) self.__zoomFit(imgSize) self.layoutText() self.title1.setVisible(True) self.title2.setVisible(True) self.title3.setVisible(True) self.image.setVisible(True) def hide(self): self.title1.setVisible(False) self.title2.setVisible(False) self.title3.setVisible(False) self.image.setVisible(False) self.image.setPixmap(QPixmap()) def showImage(self, file, md): self.metadata = md try: metadata = GExiv2.Metadata(file) except GLib.Error as e: print(repr(e)) return img = QPixmap(file) self.image.setPixmap(img) self.image.setScale(1.0) self.image.setRotation(0) imgSize = self.__rotate(metadata, img.size()) self.__zoomFit(imgSize) self.layoutMetadata()
class QGraphicsListData(QGraphicsItem): # IGNORE:abstract-class-not-used _editName = "" def __init__(self, qScore, parent = None): super(QGraphicsListData, self).__init__(parent = parent, scene = qScore) self._qScore = qScore self._props = qScore.displayProperties self._rect = QRectF(0, 0, 0, 0) self.setRect() self.setCursor(Qt.PointingHandCursor) self.setAcceptsHoverEvents(True) def _iterData(self): raise NotImplementedError() def _dataLen(self): raise NotImplementedError() def font(self): raise NotImplementedError() def setRect(self, fm = None): if fm is None: font = self.font() if font is None: return fm = QFontMetrics(font) lineHeight = fm.height() height = lineHeight * self._dataLen() * 1.1 width = max(fm.width(data) for data in self._iterData()) + 10 if height != self._rect.height() or width != self._rect.width(): self.prepareGeometryChange() self._rect.setBottomRight(QPointF(width, height)) def boundingRect(self): return self._rect def paint(self, painter, dummyOption, dummyWidget = None): painter.save() try: scheme = self._qScore.parent().colourScheme painter.setPen(QPen(scheme.text.borderColour)) font = self.font() if font is None: font = painter.font() else: painter.setFont(font) fm = QFontMetrics(painter.font()) self.setRect(fm) lineHeight = fm.height() for index, data in enumerate(self._iterData()): painter.drawText(QPoint(5, (index + 1) * lineHeight), data) finally: painter.restore() def fontChanged(self): self.update() def update(self): self.setRect() super(QGraphicsListData, self).update() def hoverEnterEvent(self, event): self._qScore.setStatusMessage("Double click to edit %s." % self._editName) event.accept() def hoverLeaveEvent(self, event): self._qScore.setStatusMessage() event.accept()
def layout(self, scene, nodes, center=None, padX=None, padY=None, direction=None, animationGroup=None): """ Lays out the nodes for this scene based on a block layering algorithm. :param scene | <XNodeScene> nodes | [<XNode>, ..] center | <QPointF> || None padX | <int> || None padY | <int> || None direction | <Qt.Direction> animationGroup | <QAnimationGroup> || None :return {<XNode>: <QRectF>, ..} | new rects per affected node """ nodes = filter(lambda x: x is not None and x.isVisible(), nodes) # make sure we have at least 1 node, otherwise, it is already laid out if not nodes or len(nodes) == 1: return {} # calculate the default padding based on the scene if padX == None: if direction == Qt.Vertical: padX = 2 * scene.cellWidth() else: padX = 4 * scene.cellWidth() if padY == None: if direction == Qt.Vertical: padY = 4 * scene.cellHeight() else: padY = 2 * scene.cellWidth() # step 1: create a mapping of the connections connection_map = self.connectionMap(scene, nodes) # step 2: organize the nodes into layers based on their connection chain layers = self.generateLayers(scene, nodes, connection_map) layers = list(reversed(layers)) # step 3: calculate the total dimensions for the layout bounds = QRectF() # step 3.1: compare the nodes together that have common connections layer_widths = [] layer_heights = [] node_heights = {} node_widths = {} for layer_index, layer in enumerate(layers): layer_w = 0 layer_h = 0 layer_node_w = [] layer_node_h = [] self.organizeLayer(layer, connection_map) for node in layer: rect = node.rect() layer_node_w.append(rect.width()) layer_node_h.append(rect.height()) if direction == Qt.Vertical: layer_w += rect.width() layer_h = max(rect.height(), layer_h) else: layer_w = max(rect.width(), layer_w) layer_h += rect.height() # update the bounding area if direction == Qt.Vertical: layer_w += padX * 1 - len(layer) bounds.setWidth(max(layer_w, bounds.width())) bounds.setHeight(bounds.height() + layer_h) else: layer_h += padY * 1 - len(layer) bounds.setWidth(bounds.width() + layer_w) bounds.setHeight(max(layer_h, bounds.height())) node_widths[layer_index] = layer_node_w node_heights[layer_index] = layer_node_h layer_widths.append(layer_w) layer_heights.append(layer_h) if not center: center = scene.sceneRect().center() w = bounds.width() h = bounds.height() bounds.setX(center.x() - bounds.width() / 2.0) bounds.setY(center.y() - bounds.height() / 2.0) bounds.setWidth(w) bounds.setHeight(h) # step 4: assign positions for each node by layer processed_nodes = {} layer_grps = [(i, layer) for i, layer in enumerate(layers)] layer_grps.sort(key=lambda x: len(x[1])) for layer_index, layer in reversed(layer_grps): layer_width = layer_widths[layer_index] layer_height = layer_heights[layer_index] # determine the starting point for this layer if direction == Qt.Vertical: offset = layer_index * padY + sum(layer_heights[:layer_index]) point = QPointF(bounds.x(), offset + bounds.y()) else: offset = layer_index * padX + sum(layer_widths[:layer_index]) point = QPointF(offset + bounds.x(), bounds.y()) # assign node positions based on existing connections for node_index, node in enumerate(layer): max_, min_ = (None, None) inputs, outputs = connection_map[node] for connected_node in inputs + outputs: if not connected_node in processed_nodes: continue npos = processed_nodes[connected_node] nrect = connected_node.rect() rect = QRectF(npos.x(), npos.y(), nrect.width(), nrect.height()) if direction == Qt.Vertical: if min_ is None: min_ = rect.left() min_ = min(rect.left(), min_) max_ = max(rect.right(), max_) else: if min_ is None: min_ = rect.top() min_ = min(rect.top(), min_) max_ = max(rect.bottom(), max_) if direction == Qt.Vertical: off_x = 0 off_y = (layer_height - node.rect().height()) / 2.0 start_x = (bounds.width() - layer_width) start_y = 0 else: off_x = (layer_width - node.rect().width()) / 2.0 off_y = 0 start_x = 0 start_y = (bounds.height() - layer_height) # align against existing nodes if not None in (min_, max): if direction == Qt.Vertical: off_x = (max_ - min_) / 2.0 - node.rect().width() / 2.0 point_x = min_ + off_x point_y = point.y() + off_y else: off_y = (max_ - min_) / 2.0 - node.rect().height() / 2.0 point_x = point.x() + off_x point_y = min_ + off_y # otherwise, align based on its position in the layer else: if direction == Qt.Vertical: off_x = sum(node_widths[layer_index][:node_index]) off_x += node_index * padX off_x += start_x point_x = point.x() + off_x point_y = point.y() + off_y else: off_y = sum(node_heights[layer_index][:node_index]) off_y += node_index * padY off_y += start_y point_x = point.x() + off_x point_y = point.y() + off_y if not animationGroup: node.setPos(point_x, point_y) else: anim = XNodeAnimation(node, 'setPos') anim.setStartValue(node.pos()) anim.setEndValue(QPointF(point_x, point_y)) animationGroup.addAnimation(anim) processed_nodes[node] = QPointF(point_x, point_y) if self._testing: QApplication.processEvents() time.sleep(1) return processed_nodes
def paintBoundaries(tgslicesFile, zSlice, d, boundaryData, mask, filename, swapCoordinates=False, colortable=None, penWidth=4.0): print "* making boundary img '%s'" % filename #b = BoundariesLayerPy(tgslicesFile=tgslicesFile, normalAxis=2, data2scene=QTransform(), swapCoordinates=True) b = BoundariesLayer(None, 2, QTransform(), True) n = b.normalAxis() axis = None if swapCoordinates: if n == 0: axis = "z" elif n == 1: axis = "y" else: axis = "x" else: if n == 0: axis = "x" elif n == 1: axis = "y" else: axis = "z" f = h5py.File(tgslicesFile, 'r') group = "%s/%d" % (axis, zSlice) serializedBoundaries = f[group].value f.close() assert d.ndim == 2 scene = QGraphicsScene() b.setSliceNumber( zSlice ) b.setBoundaries(serializedBoundaries) b.setColormap("tyr") assert boundaryData.dtype == numpy.float32 assert mask.dtype == numpy.float32 b.setBoundaryData(boundaryData, boundaryData.size, boundaryData) b.setBoundaryMask(mask, mask.size) if colortable is not None: b.setColormap(colortable) print "setting pen width to be %f" % penWidth b.setPenWidth(float(penWidth)) print "...done" mag = 4 shape = d.shape dBig = vigra.sampling.resizeImageNoInterpolation(d.astype(numpy.float32), (mag*shape[0], mag*shape[1])) #dBig = dBig.swapaxes(0,1) qimg = qimage2ndarray.gray2qimage(dBig) #qimg = qimg.mirrored(True, False) imgItm = QGraphicsPixmapItem(QPixmap(qimg)) imgItm.setScale(1.0/mag) scene.addItem(imgItm) sourceRect = QRectF(0,0,shape[1], shape[0]) targetRect = QRectF(0,0,mag*shape[1], mag*shape[0]) scene.setSceneRect(sourceRect) scene.addItem(b) img = QImage(targetRect.width(), targetRect.height(), QImage.Format_ARGB32); painter = QPainter(img); painter.setRenderHint(QPainter.Antialiasing); scene.render(painter, targetRect, sourceRect ); img.save(filename) painter.end() #print "img has size ", img.width(), img.height() img = None painter = None scene = None
class ZoomSlider(QFrame): """ Two way slider representing narrowing of a view. The sliders coorespond to factors: a min value and a max value in the range [0, 1] Emits zoomValueChanged(float, float) whenever the markers are adjusted. (float, float) -> (min, max) """ def __init__(self, parent=None, horizontal=True): QFrame.__init__(self, parent) self.horizontal = horizontal if horizontal: self.setFrameShape(QFrame.HLine) self.setMinimumHeight(21) self.tilt = 90 else: self.setFrameShape(QFrame.VLine) self.setMinimumWidth(21) self.tilt = 180 self.setFrameShadow(QFrame.Sunken) self.setMidLineWidth(3) self.setMouseTracking(True) self.size = 12 self.min_value = 0.0 self.max_value = 1.0 self.setDefaultColors() self.button = Qt.NoButton self.selected_marker = 'none' def paintEvent(self, paint_event): QFrame.paintEvent(self, paint_event) painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) w = self.width() h = self.height() if self.horizontal: self.min_marker = QRectF(w * self.min_value, 4, self.size, self.size) self.max_marker = QRectF(w * self.max_value - self.size - 1, 4, self.size, self.size) else: self.min_marker = QRectF(4, h - h * self.min_value - self.size - 1, self.size, self.size) self.max_marker = QRectF(4, h - h * self.max_value, self.size, self.size) pen = painter.pen() pen.setWidth(0) pen.setColor(QApplication.palette().background().color().dark()) painter.setPen(pen) painter.setBrush(self.min_marker_brush) painter.drawPie(self.min_marker, self.tilt * 16, 180 * 16) painter.setBrush(self.max_marker_brush) painter.drawPie(self.max_marker, self.tilt * 16, -180 * 16) def resizeEvent (self, resize_event): QFrame.resizeEvent(self, resize_event) def _getMinTestMarker(self): """Returns the "real" marker bounds. Adjusted for the missing part of an arc.""" if self.horizontal: return QRectF(self.min_marker.left(), self.min_marker.top(), self.min_marker.width() / 2.0, self.min_marker.height()) else: return QRectF(self.min_marker.left(), self.min_marker.top() + self.min_marker.height() / 2.0, self.min_marker.width(), self.min_marker.height() / 2.0) def _getMaxTestMarker(self): """Returns the "real" marker bounds. Adjusted for the missing part of an arc.""" if self.horizontal: return QRectF(self.max_marker.left() + self.max_marker.width() / 2.0, self.max_marker.top(), self.max_marker.width() / 2.0, self.max_marker.height()) else: return QRectF(self.max_marker.left(), self.max_marker.top(), self.max_marker.width(), self.max_marker.height() / 2.0) def mouseMoveEvent (self, mouse_event): """Dragging or highlighting the markers.""" self.setDefaultColors() min_test_marker = self._getMinTestMarker() if min_test_marker.contains(mouse_event.x(), mouse_event.y()) or self.selected_marker == 'min': self.min_marker_brush = self.getDefaultHighlightColor() if self.selected_marker == 'min': if self.horizontal: value = mouse_event.x() / float(self.width()) else: value = (self.height() - mouse_event.y()) / float(self.height()) self.setMinValue(value, False) max_test_marker = self._getMaxTestMarker() if max_test_marker.contains(mouse_event.x(), mouse_event.y()) or self.selected_marker == 'max': self.max_marker_brush = self.getDefaultHighlightColor() if self.selected_marker == 'max': if self.horizontal: value = mouse_event.x() / float(self.width()) else: value = (self.height() - mouse_event.y()) / float(self.height()) self.setMaxValue(value, False) self.update() def mousePressEvent (self, mouse_event): """Selecting a marker.""" if mouse_event.button() == Qt.LeftButton: min_test_marker = self._getMinTestMarker() if min_test_marker.contains(mouse_event.x(), mouse_event.y()): self.selected_marker = 'min' max_test_marker = self._getMaxTestMarker() if max_test_marker.contains(mouse_event.x(), mouse_event.y()): self.selected_marker = 'max' def mouseReleaseEvent (self, mouse_event): self.selected_marker = 'none' def leaveEvent (self, event): self.setDefaultColors() def getDefaultMarkerColor(self): return QApplication.palette().background().color().light(175) def getDefaultHighlightColor(self): return QApplication.palette().highlight().color() def setDefaultColors(self): self.min_marker_brush = self.getDefaultMarkerColor() self.max_marker_brush = self.getDefaultMarkerColor() self.update() def setMaxValue(self, max_value, update=True): """The the position of the max marker.""" if self.horizontal: m = float(self.width()) else: m = float(self.height()) marker_offset = (self.size + 1) / m if not self.max_value == max_value: self.max_value = max_value if self.max_value - marker_offset <= self.min_value: self.max_value = self.min_value + marker_offset if self.max_value > 1.0: self.max_value = 1 self.emit(SIGNAL('zoomValueChanged(float, float)'), self.min_value, self.max_value) if update: self.update() def setMinValue(self, min_value, update=True): """The the position of the min marker.""" if self.horizontal: m = float(self.width()) else: m = float(self.height()) marker_offset = (self.size + 1) / m if not self.min_value == min_value: self.min_value = min_value if self.min_value + marker_offset >= self.max_value: self.min_value = self.max_value - marker_offset if self.min_value < 0.0: self.min_value = 0.0 self.emit(SIGNAL('zoomValueChanged(float, float)'), self.min_value, self.max_value) if update: self.update()
class XYGraphicsScene(QGraphicsScene): def __init__(self, parent): QGraphicsScene.__init__(self, parent) self.cc_x = 1 self.cc_y = 2 self.m_channels = [] self.m_mouseLock = False self.m_smooth = False self.m_smooth_x = 0 self.m_smooth_y = 0 self.setBackgroundBrush(Qt.black) cursorPen = QPen(QColor(255, 255, 255), 2) cursorBrush = QColor(255, 255, 255, 50) self.m_cursor = self.addEllipse(QRectF(-10, -10, 20, 20), cursorPen, cursorBrush) linePen = QPen(QColor(200, 200, 200, 100), 1, Qt.DashLine) self.m_lineH = self.addLine(-9999, 0, 9999, 0, linePen) self.m_lineV = self.addLine(0, -9999, 0, 9999, linePen) self.p_size = QRectF(-100, -100, 100, 100) def setControlX(self, x): self.cc_x = x def setControlY(self, y): self.cc_y = y def setChannels(self, channels): self.m_channels = channels def setPosX(self, x, forward=True): if not self.m_mouseLock: pos_x = x * (self.p_size.x() + self.p_size.width()) self.m_cursor.setPos(pos_x, self.m_cursor.y()) self.m_lineV.setX(pos_x) if forward: self.sendMIDI(pos_x / (self.p_size.x() + self.p_size.width()), None) else: self.m_smooth_x = pos_x def setPosY(self, y, forward=True): if not self.m_mouseLock: pos_y = y * (self.p_size.y() + self.p_size.height()) self.m_cursor.setPos(self.m_cursor.x(), pos_y) self.m_lineH.setY(pos_y) if forward: self.sendMIDI(None, pos_y / (self.p_size.y() + self.p_size.height())) else: self.m_smooth_y = pos_y def setSmooth(self, smooth): self.m_smooth = smooth def setSmoothValues(self, x, y): self.m_smooth_x = x * (self.p_size.x() + self.p_size.width()) self.m_smooth_y = y * (self.p_size.y() + self.p_size.height()) def handleCC(self, param, value): sendUpdate = False xp = yp = 0.0 if param == self.cc_x: sendUpdate = True xp = (float(value) / 63) - 1.0 yp = self.m_cursor.y() / (self.p_size.y() + self.p_size.height()) if xp < -1.0: xp = -1.0 elif xp > 1.0: xp = 1.0 self.setPosX(xp, False) if param == self.cc_y: sendUpdate = True xp = self.m_cursor.x() / (self.p_size.x() + self.p_size.width()) yp = (float(value) / 63) - 1.0 if yp < -1.0: yp = -1.0 elif yp > 1.0: yp = 1.0 self.setPosY(yp, False) if sendUpdate: self.emit(SIGNAL("cursorMoved(double, double)"), xp, yp) def handleMousePos(self, pos): if not self.p_size.contains(pos): if pos.x() < self.p_size.x(): pos.setX(self.p_size.x()) elif pos.x() > self.p_size.x() + self.p_size.width(): pos.setX(self.p_size.x() + self.p_size.width()) if pos.y() < self.p_size.y(): pos.setY(self.p_size.y()) elif pos.y() > self.p_size.y() + self.p_size.height(): pos.setY(self.p_size.y() + self.p_size.height()) self.m_smooth_x = pos.x() self.m_smooth_y = pos.y() if not self.m_smooth: self.m_cursor.setPos(pos) self.m_lineH.setY(pos.y()) self.m_lineV.setX(pos.x()) xp = pos.x() / (self.p_size.x() + self.p_size.width()) yp = pos.y() / (self.p_size.y() + self.p_size.height()) self.sendMIDI(xp, yp) self.emit(SIGNAL("cursorMoved(double, double)"), xp, yp) def sendMIDI(self, xp=None, yp=None): global jack_midi_out_data rate = float(0xff) / 4 if xp != None: value = int((xp * rate) + rate) for channel in self.m_channels: jack_midi_out_data.put_nowait((0xB0 + channel - 1, self.cc_x, value)) if yp != None: value = int((yp * rate) + rate) for channel in self.m_channels: jack_midi_out_data.put_nowait((0xB0 + channel - 1, self.cc_y, value)) def updateSize(self, size): self.p_size.setRect(-(size.width() / 2), -(size.height() / 2), size.width(), size.height()) def updateSmooth(self): if self.m_smooth: if self.m_cursor.x() != self.m_smooth_x or self.m_cursor.y() != self.m_smooth_y: if abs(self.m_cursor.x() - self.m_smooth_x) <= 0.001: self.m_smooth_x = self.m_cursor.x() return elif abs(self.m_cursor.y() - self.m_smooth_y) <= 0.001: self.m_smooth_y = self.m_cursor.y() return new_x = (self.m_smooth_x + self.m_cursor.x() * 3) / 4 new_y = (self.m_smooth_y + self.m_cursor.y() * 3) / 4 pos = QPointF(new_x, new_y) self.m_cursor.setPos(pos) self.m_lineH.setY(pos.y()) self.m_lineV.setX(pos.x()) xp = pos.x() / (self.p_size.x() + self.p_size.width()) yp = pos.y() / (self.p_size.y() + self.p_size.height()) self.sendMIDI(xp, yp) self.emit(SIGNAL("cursorMoved(double, double)"), xp, yp) def keyPressEvent(self, event): event.accept() def wheelEvent(self, event): event.accept() def mousePressEvent(self, event): self.m_mouseLock = True self.handleMousePos(event.scenePos()) QGraphicsScene.mousePressEvent(self, event) def mouseMoveEvent(self, event): self.handleMousePos(event.scenePos()) QGraphicsScene.mouseMoveEvent(self, event) def mouseReleaseEvent(self, event): self.m_mouseLock = False QGraphicsScene.mouseReleaseEvent(self, event)
class EFrameLayout(QGraphicsPolygonItem): def __init__(self, parent=None, scene=None): super(EFrameLayout, self).__init__(parent, scene) self.setFlag(QGraphicsItem.ItemIsMovable, True) self.setAcceptsHoverEvents(True) self.__name = QGraphicsTextItem() self.__name.setPlainText('Frame Layout') self.__handleWidth = 500 self.__handleHeight = 20 self.__separator = 5 self.__boundExtra = 3 + self.pen().width() self.__handleRect = QRectF(0.0, 0.0, self.__handleWidth, self.__handleHeight) self.__controlsBound = 0.0 self.__controls = [] self.__isDefaultPen = False self.__isCollapsed = True self.__pens = { 0: EDraw.EColor.DefaultLeaveHoverPen, 1: EDraw.EColor.DefaultEnterHoverPen } self.setPen(self.__pens[self.__isDefaultPen]) @property def Label(self): return self.__name.toPlainText() @Label.setter def Label(self, label): self.__name.setPlainText(str(label)) @property def Width(self): return self.__handleWidth @Width.setter def Width(self, width): self.__handleWidth = width self.updateGeometry() def toggleContentVisibility(self): if not len(self.__controls): return if self.__controls[0].isVisible(): [control.hide() for control in self.__controls] self.__isCollapsed = True return [control.show() for control in self.__controls] self.__isCollapsed = False def updateGeometry(self): self.__handleRect = QRectF(0.0, 0.0, self.__handleWidth, self.__handleHeight) if not len(self.__controls) or self.__isCollapsed: self.__controlsBound = 0.0 return self.__controlsBound = 0.0 self.__controlsBound = self.__separator self.__controlsBound += sum([ control.boundingRect().height() + self.__separator for control in self.__controls ]) step = self.__handleHeight + self.__separator * 2 for control in self.__controls: control.Name.setTextWidth(self.__controlNameWidth) control.Width = self.__handleRect.normalized().adjusted( 5.0, 0.0, -5.0, 0.0).width() control.setPos(5.0, step) step += control.boundingRect().height() + self.__separator def addControl(self, control): if not isinstance(control, EControlsGroup): raise AttributeError self.__controls.append(control) control.setParentItem(self) control.setFlag(QGraphicsItem.ItemIsMovable, False) self.__controlNameWidth = max([ control.Name.boundingRect().width() for control in self.__controls ]) + 5 self.__isCollapsed = False self.updateGeometry() def clear(self): [control.setParentItem(None) for control in self.__controls] self.__controls = [] self.updateGeometry() def mouseDoubleClickEvent(self, mouseEvent): QGraphicsPolygonItem.mouseDoubleClickEvent(self, mouseEvent) self.toggleContentVisibility() self.updateGeometry() def shape(self): return QGraphicsItem.shape(self) def boundingRect(self): return self.__handleRect.normalized().adjusted(0.0, 0.0, 0.0, self.__controlsBound) def paint(self, painter, option, widget=None): if not self.__isCollapsed: painter.setPen(QPen(QColor(0, 0, 0, 50), 2, Qt.SolidLine)) painter.setBrush(QColor(0, 0, 0, 50)) painter.drawRect(self.boundingRect().adjusted( self.pen().width(), self.__handleHeight, -self.pen().width(), 0.0)) painter.setPen(self.pen()) painter.setBrush( EDraw.EColor.LinearGradient(self.__handleRect, Qt.darkGray)) #painter.drawPolygon( QPolygonF( self.__handleRect.normalized().adjusted(-self.__boundExtra, 0.0, self.__boundExtra, 0.0 ) ) ) painter.drawPolygon(QPolygonF(self.__handleRect)) painter.setPen(Qt.lightGray) r = QRectF(0.0, 0.0, self.__name.boundingRect().width(), self.__handleRect.height()) painter.drawText(r, Qt.AlignCenter, self.__name.toPlainText())
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 ItemMovel(QGraphicsWidget): rectChanged = pyqtSignal() def __init__(self, moveX=True, moveY=True, rect=QRectF(0, 0, 30, 30), parent=None): super().__init__(parent) self._movel = Movel(moveX, moveY, self) self.installEventFilter(self._movel) self._newPos = QPointF() self._oldPos = QPointF() self._rect = QRectF() self._newRect = QRectF() self._oldRect = QRectF() self._timePos = QTimeLine(1000) self._timePos.setCurveShape(QTimeLine.EaseInOutCurve) self._timePos.valueChanged.connect(self._atualizaPos) self._timeRect = QTimeLine(1000) self._timeRect.valueChanged.connect(self._atualizaRect) self.setTamanho(rect) def setMoveXY(self, x, y): self._movel.setMoveXY(x, y) def getRect(self): return self._rect def setRect(self, rect): self._rect = rect self._atualizaGeometria() def boundingRect(self): return self._rect.adjusted(-1, -1, 1, 1) def altura(self): return self._newRect.height() def _atualizaPos(self, t): # Funcao da curva que parametriza um segmento AB # C(t) = A + (B - A)*t pos = self._oldPos + (self._newPos - self._oldPos) * t self.setPos(pos) self._atualizaGeometria() def _atualizaRect(self, t): oldP1 = self._oldRect.topLeft() oldP2 = self._oldRect.bottomRight() newP1 = self._newRect.topLeft() newP2 = self._newRect.bottomRight() p1 = oldP1 + (newP1 - oldP1) * t p2 = oldP2 + (newP2 - oldP2) * t self.setRect(QRectF(p1, p2)) def _atualizaGeometria(self): self.setGeometry(QRectF(self.pos(), self.pos() + self._rect.bottomRight())) def goto(self, pos): if self.pos() == pos: return if self._timePos.state() == QTimeLine.Running: self._timePos.stop() self._oldPos = self.pos() self._newPos = pos self._timePos.start() def setTamanho(self, tam): if self._rect == tam: return if self._timeRect.state() == QTimeLine.Running: self._timeRect.stop() self._oldRect = self._rect self._newRect = tam self._timeRect.start() self.rectChanged.emit() def resize(self, size): if isinstance(size, QRect): size = size.size() self.setTamanho(QRectF(0, 0, size.width() - 3, self._newRect.height())) def paint(self, painter, widget, option): if self._timePos.state() == QTimeLine.Running: currentValue = self._timePos.currentValue() nextValue = self._timePos.valueForTime(self._timePos.currentTime() + 100) painter.setBrush(QColor(255, 0, 0, (nextValue - currentValue) * 150)) painter.drawRoundedRect(self._rect, 7, 5)
def run_loader(self): filename = self.result try: self.retryObject = None # First, prepare the data by getting the images and computing how big they # should be f = open(filename) first_line = f.readline() f.close() if first_line.startswith("TRKR_VERSION"): result = Result(None) result.load(self.result, **self._loading_arguments) result_type = "Growth" else: result = TrackingData() result.load(self.result, **self._loading_arguments) result_type = "Data" self.result = result self.result_type = result_type if result_type == "Data": data = result images = data.images_name if data.cells: self.has_cells = True self.has_walls = True else: self.has_cells = False self.has_walls = False self.has_points = bool(data.cell_points) else: data = result.data images = result.images self.has_cells = False self.has_walls = False self.has_points = False self.images = images cache = image_cache.cache self.update_nb_images(len(result)) bbox = QRectF() ms = data.minScale() for i in range(len(result)): img_name = images[i] img_data = data[img_name] img = cache.image(data.image_path(img_name)) matrix = QTransform() matrix = img_data.matrix() sc = QTransform() sc.scale(1.0 / ms, 1.0 / ms) matrix *= sc r = QRectF(img.rect()) rbox = matrix.map(QPolygonF(r)).boundingRect() bbox |= rbox log_debug( "Image '%s':\n\tSize = %gx%g\n\tTransformed = %gx%g %+g %+g\n\tGlobal bbox = %gx%g %+g %+g\n" % (img_name, r.width(), r.height(), rbox.width(), rbox.height(), rbox.left(), rbox.top(), bbox.width(), bbox.height(), bbox.left(), bbox.top())) log_debug("Matrix:\n%g\t%g\t%g\n%g\t%g\t%g\n" % (matrix.m11(), matrix.m12(), matrix.dx(), matrix.m21(), matrix.m22(), matrix.dy())) if result_type == "Growth": if result.cells[i]: self.has_cells = True if result.walls[i]: self.has_walls = True self.has_points = bool(result.data.cell_points) self.nextImage() translate = bbox.topLeft() translate *= -1 self.translate = translate size = bbox.size().toSize() self.img_size = size self._crop = QRect(QPoint(0, 0), size) self.finished() self._loading_arguments = { } # All done, we don't need that anymore except RetryTrackingDataException as ex: ex.filename = filename self.retryObject = ex self.finished() return except Exception as ex: _, _, exceptionTraceback = sys.exc_info() self.abort(ex, traceback=exceptionTraceback) raise
class ENode(QGraphicsObject): onMove = pyqtSignal() onPress = pyqtSignal() kGuiPropertyId = EObject() kGuiPropertyName = EObject() kGuiAttribute = EObject() kGuiAttributeId = EObject() kGuiAttributeType = EObject() kGuiAttributePlug = EObject() kGuiAttributeParent = EObject() kGuiAttributeParentName = EObject() kGuiAttributeLongName = EObject() kGuiAttributeShortName = EObject() def __init__(self, eNodeHandle): QGraphicsObject.__init__(self) self.setFlag(QGraphicsItem.ItemIsMovable, True) self.setAcceptsHoverEvents(True) self.__isDefaultPen = False self.__pen = None self.__pens = {0: EDraw.EColor.DefaultLeaveHoverPen, 1: EDraw.EColor.DefaultEnterHoverPen} self.setPen(self.__pens[self.__isDefaultPen]) self.__font = EDraw.DefaultNodeFont self.__nodeHandle = eNodeHandle self.__nodeHandle.Message.connect(self.__messageFilter) self.__name = self.__nodeHandle.__class__.__name__ self.__attrRect = QRectF(0, 0, 15, 15) self.__titleRect = QRectF(0, 0, 135, 20) self.__textSpace = QRectF(self.__attrRect.width() + self.pen().width(), 0.0, (self.__titleRect.width() - self.__attrRect.width() * 2 - self.pen().width() * 2) / 2, self.__attrRect.height()) self.buildAttributes() self.__height = max([self.__in_attr_step, self.__out_attr_step]) def __messageFilter(self, message): if message.matches(self.__nodeHandle.kMessageAttributeAdded): self.__buildAttribute(message.getData()) if message.matches(self.__nodeHandle.kMessageAttributeRemoved): print message.getData() self.__attributes = {} self.__properties = {} self.buildAttributes() def __getAttrShortName(self, attributeName): fm = QFontMetrics(self.__font) shortName = '' if fm.width(attributeName) > self.__textSpace.width(): for x in range(len(attributeName) + 1): if fm.width(shortName) > int(self.__textSpace.width()) - 10: return shortName shortName = attributeName[:x] + '...' return attributeName def __getAttributePosition(self, opposite=False): attr_x_pos = 0 if opposite: attr_x_pos = self.__titleRect.width() - self.__attrRect.width() rect = self.__attrRect.translated(QPointF(attr_x_pos, self.__out_attr_step)) point = QPointF((rect.topRight() + rect.bottomRight()) / 2) point.setX(point.x() + self.pen().width() * 2) self.__out_attr_step += self.__attrRect.width() + self.pen().width() return [rect, point] rect = self.__attrRect.translated(QPointF(attr_x_pos, self.__in_attr_step)) point = QPointF((rect.topLeft() + rect.bottomLeft()) / 2) point.setX(point.x() - self.pen().width() * 2) self.__in_attr_step += self.__attrRect.width() + self.pen().width() return [rect, point] def __buildAttribute(self, attribute, opposite=False): """ if not attribute.Type.matches(EAttribute.kTypeGenericInput) and not attribute.Type.matches(EAttribute.kTypeGenericOutput): self.__properties[attribute.Id] = dict({self.kGuiPropertyId: attribute.Id, self.kGuiPropertyName: attribute.Name}) return """ data = self.__getAttributePosition(opposite) self.__attributes[data[0]] = dict({self.kGuiAttributeId: attribute.Id, self.kGuiAttributeType: attribute.Type, self.kGuiAttributeParent: self, self.kGuiAttributePlug: data[1], self.kGuiAttributeLongName: attribute.Name, self.kGuiAttributeShortName: self.__getAttrShortName(attribute.Name)}) self.__height = max([self.__in_attr_step, self.__out_attr_step]) self.update() self.onMove.emit() def buildAttributes(self): self.__attributes = {} self.__properties = {} self.__out_attr_step = self.__titleRect.height() + self.pen().width() self.__in_attr_step = self.__titleRect.height() + self.pen().width() for eddAttr in self.__nodeHandle.lsInputAttributes(): self.__buildAttribute(eddAttr) for eddAttr in self.__nodeHandle.lsOutputAttributes(): self.__buildAttribute(eddAttr, True) self.update() def __toggleHighlight(self): if self.__isDefaultPen: self.__isDefaultPen = False self.setPen(self.__pens[self.__isDefaultPen]) #self.setZValue(0.0) return self.__isDefaultPen = True self.setPen(self.__pens[self.__isDefaultPen]) #self.setZValue(-2.0) def mute(self, uuid): pass @property def Id(self): return self.__nodeHandle.Id @property def Name(self): return self.__name @Name.setter def Name(self, newName): self.__name = newName def pen(self): return self.__pen def setPen(self, pen): if not isinstance(pen, QPen): raise AttributeError self.__pen = pen @property def Font(self): return self.__font @Font.setter def Font(self, QFont): self.__font = QFont @property def Handle(self): return self.__nodeHandle @property def Properties(self): return self.__properties def mapFromPoint(self, QPoint): for attrRect, attrValues in self.__attributes.iteritems(): if attrRect.contains(self.mapFromScene(QPoint)): return attrValues[self.kGuiAttributeId], QPoint return self.__nodeHandle.Id, None def mapFromId(self, attrId): for attrValue in self.__attributes.itervalues(): if attrValue[self.kGuiAttributeId] == attrId: return attrValue return None def hoverEnterEvent(self, mouseEvent): QGraphicsObject.hoverEnterEvent(self, mouseEvent) self.__toggleHighlight() def hoverMoveEvent(self, mouseEvent): QGraphicsObject.hoverMoveEvent(self, mouseEvent) def hoverLeaveEvent(self, mouseEvent): QGraphicsObject.hoverLeaveEvent(self, mouseEvent) self.__toggleHighlight() def mousePressEvent(self, mouseEvent): QGraphicsObject.mousePressEvent(self, mouseEvent) #if mouseEvent.button() == Qt.RightButton: #print self.mapFromPoint(mouseEvent.scenePos()) self.onPress.emit() def mouseDoubleClickEvent(self, mouseEvent): QGraphicsObject.mouseDoubleClickEvent(self, mouseEvent) #self.__nodeHandle.compute() def mouseMoveEvent(self, mouseEvent): QGraphicsObject.mouseMoveEvent(self, mouseEvent) self.onMove.emit() def boundingRect(self): extra = self.pen().width() return self.__titleRect.normalized().adjusted(-extra, -extra, extra, (self.__height - self.__titleRect.height()) + extra) def shape(self): return QGraphicsItem.shape(self) def paint(self, painter, option, widget=None): painter.setBrush(EDraw.EColor.DefaultNodeFillColor) painter.setPen(self.pen()) painter.drawRect(self.boundingRect()) painter.setPen(Qt.NoPen) painter.setBrush(EDraw.EColor.DefaultTitleColor) painter.drawRect(self.__titleRect) painter.setPen(EDraw.EColor.DefaultTitleTextColor) painter.drawText(self.__titleRect, Qt.AlignCenter, self.__name) painter.setPen(Qt.NoPen) painter.setBrush(EDraw.EColor.DefaultAttributeFillColor) for rect in self.__attributes.iterkeys(): painter.drawRect(rect) painter.setBrush(Qt.darkGray) for rect in self.__attributes.iterkeys(): painter.drawPolygon(EDraw.Circle(rect.height() / 3, 3).translated(rect.center())) painter.setPen(QPen(QColor(43, 43, 43), 1.0, Qt.SolidLine)) painter.setBrush(Qt.NoBrush) for attrRect, attrValues in self.__attributes.iteritems(): attrNameRect = self.__textSpace.translated(attrRect.topLeft()) align = Qt.AlignLeft if attrRect.topLeft().x() > 0: attrNameRect = self.__textSpace.translated( QPointF((self.__titleRect.width() / 2) - (attrRect.width() + self.pen().width()), attrRect.topLeft().y())) align = Qt.AlignRight painter.drawText(attrNameRect, align, attrValues[self.kGuiAttributeShortName])
class GradientLegendItem(QGraphicsObject, GraphicsWidgetAnchor): gradient_width = 20 def __init__(self, title, palette, values, parent): QGraphicsObject.__init__(self, parent) GraphicsWidgetAnchor.__init__(self) self.parent = self.legend = parent self.palette = palette self.values = values self.title = QGraphicsTextItem('%s:' % title, self) f = self.title.font() f.setBold(True) self.title.setFont(f) self.title_item = QGraphicsRectItem(self.title.boundingRect(), self) self.title_item.setPen(QPen(Qt.NoPen)) self.title_item.stackBefore(self.title) self.label_items = [QGraphicsTextItem(text, self) for text in values] for i in self.label_items: i.setTextWidth(50) self.rect = QRectF() self.gradient_item = QGraphicsRectItem(self) self.gradient = QLinearGradient() self.gradient.setStops([(v * 0.1, self.palette[v * 0.1]) for v in range(11)]) self.orientation = Qt.Horizontal self.set_orientation(Qt.Vertical) self.setFlag(QGraphicsItem.ItemIgnoresTransformations, True) self.setFlag(QGraphicsItem.ItemIsMovable, True) def set_orientation(self, orientation): return if self.orientation == orientation: return self.orientation = orientation if self.orientation == Qt.Vertical: height = max(item.boundingRect().height() for item in self.label_items) total_height = height * max(5, len(self.label_items)) interval = (total_height - self.label_items[-1].boundingRect().height() ) / (len(self.label_items) - 1) self.gradient_item.setRect(10, 0, self.gradient_width, total_height) self.gradient.setStart(10, 0) self.gradient.setFinalStop(10, total_height) self.gradient_item.setBrush(QBrush(self.gradient)) self.gradient_item.setPen(QPen(Qt.NoPen)) y = -20 # hja, no; dela --> pri boundingRect() zato pristejem +20 x = 0 move_item_xy(self.title, x, y, False) y = 10 x = 30 for item in self.label_items: move_item_xy(item, x, y, False) # self.parent.graph.animate_plot) y += interval self.rect = QRectF(10, 0, self.gradient_width + max(item.boundingRect().width() for item in self.label_items), self.label_items[0].boundingRect().height() * max(5, len(self.label_items))) else: # za horizontalno orientacijo nisem dodajal title-a width = 50 height = max(item.boundingRect().height() for item in self.label_items) total_width = width * max(5, len(self.label_items)) interval = (total_width - self.label_items[-1].boundingRect().width() ) / (len(self.label_items) - 1) self.gradient_item.setRect(0, 0, total_width, self.gradient_width) self.gradient.setStart(0, 0) self.gradient.setFinalStop(total_width, 0) self.gradient_item.setBrush(QBrush(self.gradient)) self.gradient_item.setPen(QPen(Qt.NoPen)) x = 0 y = 30 for item in self.label_items: move_item_xy(item, x, y, False) # self.parent.graph.animate_plot) x += interval self.rect = QRectF(0, 0, total_width, self.gradient_width + height) # noinspection PyPep8Naming def boundingRect(self): width = max(self.rect.width(), self.title_item.boundingRect().width()) height = self.rect.height() + self.title_item.boundingRect().height() return QRectF(self.rect.left(), self.rect.top(), width, height) def paint(self, painter, option, widget): pass
class QGraphicsListData(QGraphicsItem): ''' classdocs ''' _editName = "" def __init__(self, qScore, parent=None): ''' Constructor ''' super(QGraphicsListData, self).__init__(parent=parent, scene=qScore) self._qScore = qScore self._props = qScore.displayProperties self._rect = QRectF(0, 0, 0, 0) self.setRect() self.setCursor(Qt.PointingHandCursor) self.setAcceptsHoverEvents(True) def _iterData(self): raise NotImplementedError() def _dataLen(self): raise NotImplementedError() def font(self): raise NotImplementedError() def setRect(self, fm=None): if fm is None: font = self.font() if font is None: return fm = QFontMetrics(font) lineHeight = fm.height() height = lineHeight * self._dataLen() * 1.1 width = max(fm.width(data) for data in self._iterData()) + 10 if height != self._rect.height() or width != self._rect.width(): self.prepareGeometryChange() self._rect.setBottomRight(QPointF(width, height)) def boundingRect(self): return self._rect def paint(self, painter, dummyOption, dummyWidget=None): painter.save() try: font = self.font() if font is None: font = painter.font() else: painter.setFont(font) fm = QFontMetrics(painter.font()) self.setRect(fm) lineHeight = fm.height() for index, data in enumerate(self._iterData()): painter.drawText(QPoint(5, (index + 1) * lineHeight), data) finally: painter.restore() def fontChanged(self): self.update() def update(self): self.setRect() super(QGraphicsListData, self).update() def hoverEnterEvent(self, *args, **kwargs): self._qScore.setStatusMessage("Double click to edit %s." % self._editName) return super(QGraphicsListData, self).hoverEnterEvent(*args, **kwargs) def hoverLeaveEvent(self, *args, **kwargs): self._qScore.setStatusMessage() return super(QGraphicsListData, self).hoverLeaveEvent(*args, **kwargs)
class DrawManager(QObject): """ DEPRECATED. Will be replaced with BrushingModel, BrushingControler, BrushStroke. """ brushSizeChanged = pyqtSignal(int) brushColorChanged = pyqtSignal(QColor) minBrushSize = 1 maxBrushSize = 61 defaultBrushSize = 3 defaultDrawnNumber = 1 defaultColor = Qt.white erasingColor = Qt.black def __init__(self): QObject.__init__(self) self.shape = None self.bb = QRect() #bounding box enclosing the drawing self.brushSize = self.defaultBrushSize self.drawColor = self.defaultColor self.drawnNumber = self.defaultDrawnNumber self.penVis = QPen(self.drawColor, self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin) self.penDraw = QPen(self.drawColor, self.brushSize, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin) self.pos = None self.erasing = False #on which layer do we want to draw when self.drawingEnabled? self.drawOnto = None #an empty scene, where we add all drawn line segments #a QGraphicsLineItem, and which we can use to then #render to an image self.scene = QGraphicsScene() def growBoundingBox(self): self.bb.setLeft( max(0, self.bb.left()-self.brushSize-1)) self.bb.setTop( max(0, self.bb.top()-self.brushSize-1 )) self.bb.setRight( min(self.shape[0], self.bb.right()+self.brushSize+1)) self.bb.setBottom(min(self.shape[1], self.bb.bottom()+self.brushSize+1)) def toggleErase(self): self.erasing = not(self.erasing) def setErasing(self): self.erasing = True self.brushColorChanged.emit(self.erasingColor) def disableErasing(self): self.erasing = False self.brushColorChanged.emit(self.drawColor) def setBrushSize(self, size): self.brushSize = size self.penVis.setWidth(size) self.penDraw.setWidth(size) self.brushSizeChanged.emit(self.brushSize) def setDrawnNumber(self, num): self.drawnNumber = num self.drawnNumberChanged.emit(num) def getBrushSize(self): return self.brushSize def brushSmaller(self): b = self.brushSize if b > self.minBrushSize: self.setBrushSize(b-1) def brushBigger(self): b = self.brushSize if self.brushSize < self.maxBrushSize: self.setBrushSize(b+1) def setBrushColor(self, color): self.drawColor = color self.penVis.setColor(color) self.emit.brushColorChanged(self.drawColor) def beginDrawing(self, pos, shape): self.shape = shape self.bb = QRectF(0, 0, self.shape[0], self.shape[1]) self.scene.clear() if self.erasing: self.penVis.setColor(self.erasingColor) else: self.penVis.setColor(self.drawColor) self.pos = QPointF(pos.x()+0.0001, pos.y()+0.0001) line = self.moveTo(pos) return line def endDrawing(self, pos): self.moveTo(pos) self.growBoundingBox() tempi = QImage(QSize(self.bb.width(), self.bb.height()), QImage.Format_ARGB32_Premultiplied) #TODO: format tempi.fill(0) painter = QPainter(tempi) self.scene.render(painter, QRectF(QPointF(0,0), self.bb.size()), self.bb) return (self.bb.left(), self.bb.top(), tempi) #TODO: hackish, probably return a class ?? def dumpDraw(self, pos): res = self.endDrawing(pos) self.beginDrawing(pos, self.shape) return res def moveTo(self, pos): lineVis = QGraphicsLineItem(self.pos.x(), self.pos.y(), pos.x(), pos.y()) lineVis.setPen(self.penVis) line = QGraphicsLineItem(self.pos.x(), self.pos.y(), pos.x(), pos.y()) line.setPen(self.penDraw) self.scene.addItem(line) self.pos = pos x = pos.x() y = pos.y() #update bounding Box : if x > self.bb.right(): self.bb.setRight(x) if x < self.bb.left(): self.bb.setLeft(x) if y > self.bb.bottom(): self.bb.setBottom(y) if y < self.bb.top(): self.bb.setTop(y) return lineVis
class DrawableActor(DrawableNode, QGraphicsItem): def __init__(self, uml_object): super(DrawableActor, self).__init__(uml_object) QGraphicsItem.__init__(self) self.__bounding_rect = QRectF(0, 0, 100, 100) self.__font = Drawable.get_font() self.__sectionMargin = 5 self.__text_margin = 3 self.setFlag(QGraphicsItem.ItemIsMovable, 1) self.setFlag(QGraphicsItem.ItemIsSelectable, 1) self.setFlag(QGraphicsItem.ItemSendsGeometryChanges, 1) self.__actor_rectangle = QRectF(0, 0, 40, 80) self.__actor_name_text = DrawableText.create_drawable_text(self) def boundingRect(self): return self.__bounding_rect def paint(self, painter, style, widget): metrics = QFontMetrics(self.__font) painter.setFont(self.__font) painter.setPen(QColor(0, 0, 0)) painter.fillRect(QRectF(self.__bounding_rect), QBrush(QColor(255, 255, 255), Qt.SolidPattern)) painter.setRenderHint(QPainter.Antialiasing, True) head_rad = math.ceil(self.__actor_rectangle.height() / 3) center = self.__actor_rectangle.width() / 2 head_start = center - head_rad / 2 painter.drawEllipse(head_start,0,head_rad,head_rad) painter.drawLine(0, head_rad * 1.3, self.__actor_rectangle.width(), head_rad * 1.3) painter.drawLine(center, head_rad, center, head_rad*2) painter.drawLine(center, head_rad * 2, 0, self.__actor_rectangle.height()) painter.drawLine(center, head_rad * 2, self.__actor_rectangle.width(), self.__actor_rectangle.height()) painter.setRenderHint(QPainter.Antialiasing, False) def update(self): metrics = QFontMetrics(self.__font) self.__bounding_rect = QRectF(self.__actor_rectangle) globalRect = self.globalBoundingRect() # TODO: This again if "name" not in self.uml_object.properties: self.uml_object["name"] = self.uml_object.name self.__actor_name_text.text = self.uml_object["name"] self.__actor_name_text.origin_pos = QPointF(globalRect.x() + globalRect.width() / 2, globalRect.y() + globalRect.height()) self.__actor_name_text.reset_vector = QPointF(- metrics.width(self.uml_object["name"]) / 2, 0) if(not self.__actor_name_text.isVisible()): self.__actor_name_text.reset_pos() self.__actor_name_text.setVisible(True) def crop_line(self, line, line_point): global_rect = self.globalBoundingRect() vertexes = [global_rect.topLeft(), global_rect.topRight(), global_rect.bottomRight(), global_rect.bottomLeft()] intersection_point = QPointF() # Iterate over pairs of vertexes that make rectangle edges for (a, b) in [(0, 1), (1, 2), (2, 3), (3, 0)]: bok = QLineF(vertexes[a], vertexes[b]) itype = line.intersect(bok, intersection_point) if(itype == QLineF.BoundedIntersection): if(line_point == 0): return QLineF(intersection_point, line.p2()) else: return QLineF(line.p1(), intersection_point) return line def find_anchor(self): return self.globalBoundingRect().center() def itemChange(self, change, value): if(change == QGraphicsItem.ItemPositionChange): for anchor in self.anchors: anchor.connector.update() self.resize_scene_rect() return QGraphicsItem.itemChange(self, change, value)
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 ZoomSlider(QFrame): """ Two way slider representing narrowing of a view. The sliders coorespond to factors: a min value and a max value in the range [0, 1] Emits zoomValueChanged(float, float) whenever the markers are adjusted. (float, float) -> (min, max) """ def __init__(self, parent=None, horizontal=True): QFrame.__init__(self, parent) self.horizontal = horizontal if horizontal: self.setFrameShape(QFrame.HLine) self.setMinimumHeight(21) self.tilt = 90 else: self.setFrameShape(QFrame.VLine) self.setMinimumWidth(21) self.tilt = 180 self.setFrameShadow(QFrame.Sunken) self.setMidLineWidth(3) self.setMouseTracking(True) self.size = 12 self.min_value = 0.0 self.max_value = 1.0 self.setDefaultColors() self.button = Qt.NoButton self.selected_marker = 'none' def paintEvent(self, paint_event): QFrame.paintEvent(self, paint_event) painter = QPainter(self) painter.setRenderHint(QPainter.Antialiasing) w = self.width() h = self.height() if self.horizontal: self.min_marker = QRectF(w * self.min_value, 4, self.size, self.size) self.max_marker = QRectF(w * self.max_value - self.size - 1, 4, self.size, self.size) else: self.min_marker = QRectF(4, h - h * self.min_value - self.size - 1, self.size, self.size) self.max_marker = QRectF(4, h - h * self.max_value, self.size, self.size) pen = painter.pen() pen.setWidth(0) pen.setColor(QApplication.palette().background().color().dark()) painter.setPen(pen) painter.setBrush(self.min_marker_brush) painter.drawPie(self.min_marker, self.tilt * 16, 180 * 16) painter.setBrush(self.max_marker_brush) painter.drawPie(self.max_marker, self.tilt * 16, -180 * 16) def resizeEvent(self, resize_event): QFrame.resizeEvent(self, resize_event) def _getMinTestMarker(self): """Returns the "real" marker bounds. Adjusted for the missing part of an arc.""" if self.horizontal: return QRectF(self.min_marker.left(), self.min_marker.top(), self.min_marker.width() / 2.0, self.min_marker.height()) else: return QRectF( self.min_marker.left(), self.min_marker.top() + self.min_marker.height() / 2.0, self.min_marker.width(), self.min_marker.height() / 2.0) def _getMaxTestMarker(self): """Returns the "real" marker bounds. Adjusted for the missing part of an arc.""" if self.horizontal: return QRectF( self.max_marker.left() + self.max_marker.width() / 2.0, self.max_marker.top(), self.max_marker.width() / 2.0, self.max_marker.height()) else: return QRectF(self.max_marker.left(), self.max_marker.top(), self.max_marker.width(), self.max_marker.height() / 2.0) def mouseMoveEvent(self, mouse_event): """Dragging or highlighting the markers.""" self.setDefaultColors() min_test_marker = self._getMinTestMarker() if min_test_marker.contains( mouse_event.x(), mouse_event.y()) or self.selected_marker == 'min': self.min_marker_brush = self.getDefaultHighlightColor() if self.selected_marker == 'min': if self.horizontal: value = mouse_event.x() / float(self.width()) else: value = (self.height() - mouse_event.y()) / float( self.height()) self.setMinValue(value, False) max_test_marker = self._getMaxTestMarker() if max_test_marker.contains( mouse_event.x(), mouse_event.y()) or self.selected_marker == 'max': self.max_marker_brush = self.getDefaultHighlightColor() if self.selected_marker == 'max': if self.horizontal: value = mouse_event.x() / float(self.width()) else: value = (self.height() - mouse_event.y()) / float( self.height()) self.setMaxValue(value, False) self.update() def mousePressEvent(self, mouse_event): """Selecting a marker.""" if mouse_event.button() == Qt.LeftButton: min_test_marker = self._getMinTestMarker() if min_test_marker.contains(mouse_event.x(), mouse_event.y()): self.selected_marker = 'min' max_test_marker = self._getMaxTestMarker() if max_test_marker.contains(mouse_event.x(), mouse_event.y()): self.selected_marker = 'max' def mouseReleaseEvent(self, mouse_event): self.selected_marker = 'none' def leaveEvent(self, event): self.setDefaultColors() def getDefaultMarkerColor(self): return QApplication.palette().background().color().light(175) def getDefaultHighlightColor(self): return QApplication.palette().highlight().color() def setDefaultColors(self): self.min_marker_brush = self.getDefaultMarkerColor() self.max_marker_brush = self.getDefaultMarkerColor() self.update() def setMaxValue(self, max_value, update=True): """The the position of the max marker.""" if self.horizontal: m = float(self.width()) else: m = float(self.height()) marker_offset = (self.size + 1) / m if not self.max_value == max_value: self.max_value = max_value if self.max_value - marker_offset <= self.min_value: self.max_value = self.min_value + marker_offset if self.max_value > 1.0: self.max_value = 1 #print "max:", self.min_value, self.max_value self.emit(SIGNAL('zoomValueChanged(float, float)'), self.min_value, self.max_value) if update: self.update() def setMinValue(self, min_value, update=True): """The the position of the min marker.""" if self.horizontal: m = float(self.width()) else: m = float(self.height()) marker_offset = (self.size + 1) / m if not self.min_value == min_value: self.min_value = min_value if self.min_value + marker_offset >= self.max_value: self.min_value = self.max_value - marker_offset if self.min_value < 0.0: self.min_value = 0.0 #print "min:", self.min_value, self.max_value self.emit(SIGNAL('zoomValueChanged(float, float)'), self.min_value, self.max_value) if update: self.update()
def setAxisIntersect(self, intersect): self._axisIntersect = intersect #print "SkeletonsLayer(axis=%d) is updating intersect=%d" % (self._axis, self._axisIntersect) nodes, eIntersected, ePlane = self._3d._skeletons.intersect( self._axis, self._axisIntersect) #update existing items toRemove = [] for node, item in self._node2view.iteritems(): if node.pos[self._axis] != self._axisIntersect: self._scene.removeItem(item) toRemove.append(node) elif node.pointF(self._axis) != item.pos(): item.setPos(self._scene.data2scene.map(node.pointF( self._axis))) if node.isSelected() != item.isSelected(): item.setSelected(node.isSelected()) assert item.isSelected() == node.isSelected() i = 0 newSize = [0, 0] for j in range(3): if j == self._axis: continue newSize[i] = node.shape[j] i += 1 newRectF = QRectF(0, 0, *newSize) newRectF = self._scene.data2scene.mapRect(newRectF) item.setRect( QRectF(-newRectF.width() / 2.0, -newRectF.height() / 2.0, newRectF.width(), newRectF.height())) for r in toRemove: del self._node2view[r] #add new views for nodes for n in nodes: if n in self._node2view: continue pos2D = list(n.pos) del pos2D[self._axis] shape2D = n.shape2D(self._axis) itm = QGraphicsSkeletonNode(shape2D, skeletons=self._3d._skeletons, node=n) itm.setPos(self._scene.data2scene.map(QPointF(*pos2D))) itm.setSelected(n.isSelected()) self._scene.addItem(itm) self._node2view[n] = itm for itm in self._edge2view.values(): self._scene.removeItem(itm) self._edge2view = dict() for e in ePlane: l = QLineF(e[0].pointF(), e[1].pointF()) c1 = e[0].color() c2 = e[1].color() mixColor = QColor((c1.red() + c2.red()) / 2, (c1.green() + c2.green()) / 2, (c1.blue() + c2.blue()) / 2) line = QGraphicsLineItem(self._scene.data2scene.map(l)) line.setPen(QPen(mixColor)) self._scene.addItem(line) self._edge2view[e] = line for theEdge, e in eIntersected: c1 = theEdge[0].color() c2 = theEdge[1].color() mixColor = QColor((c1.red() + c2.red()) / 2, (c1.green() + c2.green()) / 2, (c1.blue() + c2.blue()) / 2) nodeSize = 6 p = QGraphicsRectItem(-nodeSize / 2, -nodeSize / 2, nodeSize, nodeSize) pos2D = list(e) del pos2D[self._axis] p.setPos(self._scene.data2scene.map(QPointF(*pos2D))) p.setPen(QPen(mixColor)) self._scene.addItem(p) self._edge2view[e] = p