Example #1
0
    def __init__(self, *args, **kwargs):
        QtGui.QWidget.__init__(self)
        # variable that handles the manipulation of the spectrogram
        # create, recompute etc
        self.specgramHandler = Spectrogram()

        # create the histogram widget
        self.imageItem = ImageItem()
        self.__histogram = HorizontalHistogramWidget()
        self.__histogram.item.setImageItem(self.imageItem)

        # internal vieBox for image graph
        self.viewBox = ViewBox()
        self.viewBox.addItem(self.imageItem)
        self.viewBox.setMouseEnabled(x=False, y=False)
        self.viewBox.setMenuEnabled(False)
        self.viewBox.setAspectLocked(False)

        # set the X and Y axis for the graph
        self.xAxis = OscXAxis(self, orientation='bottom')
        self.yAxis = SpecYAxis(self, orientation='left')

        self.xAxis.linkToView(self.viewBox)
        self.yAxis.linkToView(self.viewBox)

        self.xAxis.setGrid(self.AXIS_LINES_OPACITY)
        self.yAxis.setGrid(self.AXIS_LINES_OPACITY)

        # adjust the graph zone in the control
        horizontal_histogram = kwargs[
            "horizontal_histogram"] if "horizontal_histogram" in kwargs else True
        visible_histogram = kwargs[
            "visible_histogram"] if "visible_histogram" in kwargs else False
        self.__updateLayout(histogramHorizontal=(
            horizontal_histogram if visible_histogram else None))
Example #2
0
 def __init__(self, graph):
     ViewBox.__init__(self, enableMenu=False)
     self.graph = graph
     self.setMouseMode(self.PanMode)
     self.zoomstartpoint = None
     self.selection_start = None
     self.action = PANNING
Example #3
0
    def __init__(self, graph):
        ViewBox.__init__(self, enableMenu=False)
        self.graph = graph
        self.setMouseMode(self.PanMode)
        self.zoomstartpoint = None
        self.current_selection = None
        self.action = PANNING
        self.y_padding = 0.02
        self.x_padding = 0

        # line for marking selection
        self.selection_line = pg.PlotCurveItem()
        self.selection_line.setPen(
            pg.mkPen(color=QColor(Qt.black), width=2, style=Qt.DotLine))
        self.selection_line.setZValue(1e9)
        self.selection_line.hide()
        self.addItem(self.selection_line, ignoreBounds=True)

        # yellow marker for ending the polygon
        self.selection_poly_marker = pg.ScatterPlotItem()
        self.selection_poly_marker.setPen(
            pg.mkPen(color=QColor(Qt.yellow), width=2))
        self.selection_poly_marker.setSize(SELECT_POLYGON_TOLERANCE * 2)
        self.selection_poly_marker.setBrush(None)
        self.selection_poly_marker.setZValue(1e9 + 1)
        self.selection_poly_marker.hide()
        self.selection_poly_marker.mouseClickEvent = lambda x: x  # ignore mouse clicks
        self.addItem(self.selection_poly_marker, ignoreBounds=True)
Example #4
0
 def __init__(self, parent=None, allowTransforms=True, hideCtrl=False, name=None):
     QtGui.QWidget.__init__(self, parent)
     self.ui = Ui_Form()
     self.ui.setupUi(self)
     #self.view = self.ui.view
     self.view = ViewBox()
     self.ui.view.setCentralItem(self.view)
     self.itemList = self.ui.itemList
     self.itemList.setSelectionMode(self.itemList.ExtendedSelection)
     self.allowTransforms = allowTransforms
     self.multiSelectBox = SelectBox()
     self.view.addItem(self.multiSelectBox)
     self.multiSelectBox.hide()
     self.multiSelectBox.setZValue(1e6)
     self.ui.mirrorSelectionBtn.hide()
     self.ui.reflectSelectionBtn.hide()
     self.ui.resetTransformsBtn.hide()
     
     self.redirect = None  ## which canvas to redirect items to
     self.items = []
     
     #self.view.enableMouse()
     self.view.setAspectLocked(True)
     self.view.invertY()
     
     grid = GridItem()
     self.grid = CanvasItem(grid, name='Grid', movable=False)
     self.addItem(self.grid)
     
     self.hideBtn = QtGui.QPushButton('>', self)
     self.hideBtn.setFixedWidth(20)
     self.hideBtn.setFixedHeight(20)
     self.ctrlSize = 200
     self.sizeApplied = False
     self.hideBtn.clicked.connect(self.hideBtnClicked)
     self.ui.splitter.splitterMoved.connect(self.splitterMoved)
     
     self.ui.itemList.itemChanged.connect(self.treeItemChanged)
     self.ui.itemList.sigItemMoved.connect(self.treeItemMoved)
     self.ui.itemList.itemSelectionChanged.connect(self.treeItemSelected)
     self.ui.autoRangeBtn.clicked.connect(self.autoRange)
     self.ui.storeSvgBtn.clicked.connect(self.storeSvg)
     self.ui.storePngBtn.clicked.connect(self.storePng)
     self.ui.redirectCheck.toggled.connect(self.updateRedirect)
     self.ui.redirectCombo.currentIndexChanged.connect(self.updateRedirect)
     self.multiSelectBox.sigRegionChanged.connect(self.multiSelectBoxChanged)
     self.multiSelectBox.sigRegionChangeFinished.connect(self.multiSelectBoxChangeFinished)
     self.ui.mirrorSelectionBtn.clicked.connect(self.mirrorSelectionClicked)
     self.ui.reflectSelectionBtn.clicked.connect(self.reflectSelectionClicked)
     self.ui.resetTransformsBtn.clicked.connect(self.resetTransformsClicked)
     
     self.resizeEvent()
     if hideCtrl:
         self.hideBtnClicked()
         
     if name is not None:
         self.registeredName = CanvasManager.instance().registerCanvas(self, name)
         self.ui.redirectCombo.setHostName(self.registeredName)
    def __init__(self, graph, enable_menu=False):
        ViewBox.__init__(self, enableMenu=enable_menu)
        self.graph = graph
        self.setMouseMode(self.PanMode)

        pen = mkPen(LinePlotColors.SELECTION_LINE, width=2)
        self.selection_line = QGraphicsLineItem()
        self.selection_line.setPen(pen)
        self.selection_line.setZValue(1e9)
        self.addItem(self.selection_line, ignoreBounds=True)
Example #6
0
 def getContextMenus(self, ev):
     # called by scene to add menus on to someone else's context menu
     sourceMenu = self.widget.buildSourceMenu(ev.scenePos())
     sourceMenu.setTitle("Add Source")
     operationMenu = self.widget.buildOperationMenu(ev.scenePos())
     operationMenu.setTitle("Add Operation")
     return [sourceMenu, operationMenu, ViewBox.getMenu(self, ev)]
Example #7
0
 def __init__(self, parent=None, allowTransforms=True, hideCtrl=False, name=None):
     QtGui.QWidget.__init__(self, parent)
     self.ui = Ui_Form()
     self.ui.setupUi(self)
     #self.view = self.ui.view
     self.view = ViewBox()
     self.ui.view.setCentralItem(self.view)
     self.itemList = self.ui.itemList
     self.itemList.setSelectionMode(self.itemList.ExtendedSelection)
     self.allowTransforms = allowTransforms
     self.multiSelectBox = SelectBox()
     self.view.addItem(self.multiSelectBox)
     self.multiSelectBox.hide()
     self.multiSelectBox.setZValue(1e6)
     self.ui.mirrorSelectionBtn.hide()
     self.ui.reflectSelectionBtn.hide()
     self.ui.resetTransformsBtn.hide()
     
     self.redirect = None  ## which canvas to redirect items to
     self.items = []
     
     #self.view.enableMouse()
     self.view.setAspectLocked(True)
     self.view.invertY()
     
     grid = GridItem()
     self.grid = CanvasItem(grid, name='Grid', movable=False)
     self.addItem(self.grid)
     
     self.hideBtn = QtGui.QPushButton('>', self)
     self.hideBtn.setFixedWidth(20)
     self.hideBtn.setFixedHeight(20)
     self.ctrlSize = 200
     self.sizeApplied = False
     self.hideBtn.clicked.connect(self.hideBtnClicked)
     self.ui.splitter.splitterMoved.connect(self.splitterMoved)
     
     self.ui.itemList.itemChanged.connect(self.treeItemChanged)
     self.ui.itemList.sigItemMoved.connect(self.treeItemMoved)
     self.ui.itemList.itemSelectionChanged.connect(self.treeItemSelected)
     self.ui.autoRangeBtn.clicked.connect(self.autoRange)
     self.ui.storeSvgBtn.clicked.connect(self.storeSvg)
     self.ui.storePngBtn.clicked.connect(self.storePng)
     self.ui.redirectCheck.toggled.connect(self.updateRedirect)
     self.ui.redirectCombo.currentIndexChanged.connect(self.updateRedirect)
     self.multiSelectBox.sigRegionChanged.connect(self.multiSelectBoxChanged)
     self.multiSelectBox.sigRegionChangeFinished.connect(self.multiSelectBoxChangeFinished)
     self.ui.mirrorSelectionBtn.clicked.connect(self.mirrorSelectionClicked)
     self.ui.reflectSelectionBtn.clicked.connect(self.reflectSelectionClicked)
     self.ui.resetTransformsBtn.clicked.connect(self.resetTransformsClicked)
     
     self.resizeEvent()
     if hideCtrl:
         self.hideBtnClicked()
         
     if name is not None:
         self.registeredName = CanvasManager.instance().registerCanvas(self, name)
         self.ui.redirectCombo.setHostName(self.registeredName)
Example #8
0
    def __init__(self, graph):
        ViewBox.__init__(self, enableMenu=False)
        self.graph = graph
        self.setMouseMode(self.PanMode)
        self.zoomstartpoint = None
        self.selection_start = None
        self.action = PANNING
        self.y_padding = 0.02
        self.x_padding = 0

        # line for line selection
        self.selection_line = pg.PlotCurveItem()
        self.selection_line.setPen(pg.mkPen(color=QColor(Qt.black), width=2, style=Qt.DotLine))
        self.selection_line.setZValue(1e9)
        self.selection_line.hide()
        self.addItem(self.selection_line, ignoreBounds=True)

        # square for square selection
        self.selection_square = pg.PlotCurveItem()
        self.selection_square.setPen(pg.mkPen(color=QColor(Qt.black), width=2, style=Qt.DotLine))
        self.selection_square.setZValue(1e9)
        self.selection_square.hide()
        self.addItem(self.selection_square, ignoreBounds=True)
Example #9
0
    def getContextMenus(self, ev):
        ## called by scene to add menus on to someone else's context menu
        menu = self.widget.buildMenu(ev.scenePos())
        menu.setTitle("Add node")
        return [menu, ViewBox.getMenu(self, ev)]


##class FlowchartGraphicsScene(QtGui.QGraphicsScene):
#class FlowchartGraphicsScene(GraphicsScene):

#sigContextMenuEvent = QtCore.Signal(object)

#def __init__(self, *args):
##QtGui.QGraphicsScene.__init__(self, *args)
#GraphicsScene.__init__(self, *args)

#def mouseClickEvent(self, ev):
##QtGui.QGraphicsScene.contextMenuEvent(self, ev)
#if not ev.button() in [QtCore.Qt.RightButton]:
#self.sigContextMenuEvent.emit(ev)
Example #10
0
 def __init__(self, graph, enable_menu=False):
     self.init_history()
     ViewBox.__init__(self, enableMenu=enable_menu)
     self.graph = graph
     self.setMouseMode(self.PanMode)
     self.grabGesture(Qt.PinchGesture)
Example #11
0
class Canvas(QtGui.QWidget):
    
    sigSelectionChanged = QtCore.Signal(object, object)
    sigItemTransformChanged = QtCore.Signal(object, object)
    sigItemTransformChangeFinished = QtCore.Signal(object, object)
    
    def __init__(self, parent=None, allowTransforms=True, hideCtrl=False, name=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_Form()
        self.ui.setupUi(self)
        #self.view = self.ui.view
        self.view = ViewBox()
        self.ui.view.setCentralItem(self.view)
        self.itemList = self.ui.itemList
        self.itemList.setSelectionMode(self.itemList.ExtendedSelection)
        self.allowTransforms = allowTransforms
        self.multiSelectBox = SelectBox()
        self.view.addItem(self.multiSelectBox)
        self.multiSelectBox.hide()
        self.multiSelectBox.setZValue(1e6)
        self.ui.mirrorSelectionBtn.hide()
        self.ui.reflectSelectionBtn.hide()
        self.ui.resetTransformsBtn.hide()
        
        self.redirect = None  ## which canvas to redirect items to
        self.items = []
        
        #self.view.enableMouse()
        self.view.setAspectLocked(True)
        self.view.invertY()
        
        grid = GridItem()
        self.grid = CanvasItem(grid, name='Grid', movable=False)
        self.addItem(self.grid)
        
        self.hideBtn = QtGui.QPushButton('>', self)
        self.hideBtn.setFixedWidth(20)
        self.hideBtn.setFixedHeight(20)
        self.ctrlSize = 200
        self.sizeApplied = False
        self.hideBtn.clicked.connect(self.hideBtnClicked)
        self.ui.splitter.splitterMoved.connect(self.splitterMoved)
        
        self.ui.itemList.itemChanged.connect(self.treeItemChanged)
        self.ui.itemList.sigItemMoved.connect(self.treeItemMoved)
        self.ui.itemList.itemSelectionChanged.connect(self.treeItemSelected)
        self.ui.autoRangeBtn.clicked.connect(self.autoRange)
        self.ui.storeSvgBtn.clicked.connect(self.storeSvg)
        self.ui.storePngBtn.clicked.connect(self.storePng)
        self.ui.redirectCheck.toggled.connect(self.updateRedirect)
        self.ui.redirectCombo.currentIndexChanged.connect(self.updateRedirect)
        self.multiSelectBox.sigRegionChanged.connect(self.multiSelectBoxChanged)
        self.multiSelectBox.sigRegionChangeFinished.connect(self.multiSelectBoxChangeFinished)
        self.ui.mirrorSelectionBtn.clicked.connect(self.mirrorSelectionClicked)
        self.ui.reflectSelectionBtn.clicked.connect(self.reflectSelectionClicked)
        self.ui.resetTransformsBtn.clicked.connect(self.resetTransformsClicked)
        
        self.resizeEvent()
        if hideCtrl:
            self.hideBtnClicked()
            
        if name is not None:
            self.registeredName = CanvasManager.instance().registerCanvas(self, name)
            self.ui.redirectCombo.setHostName(self.registeredName)

    def storeSvg(self):
        self.ui.view.writeSvg()

    def storePng(self):
        self.ui.view.writeImage()

    def splitterMoved(self):
        self.resizeEvent()

    def hideBtnClicked(self):
        ctrlSize = self.ui.splitter.sizes()[1]
        if ctrlSize == 0:
            cs = self.ctrlSize
            w = self.ui.splitter.size().width()
            if cs > w:
                cs = w - 20
            self.ui.splitter.setSizes([w-cs, cs])
            self.hideBtn.setText('>')
        else:
            self.ctrlSize = ctrlSize
            self.ui.splitter.setSizes([100, 0])
            self.hideBtn.setText('<')
        self.resizeEvent()

    def autoRange(self):
        self.view.autoRange()

    def resizeEvent(self, ev=None):
        if ev is not None:
            QtGui.QWidget.resizeEvent(self, ev)
        self.hideBtn.move(self.ui.view.size().width() - self.hideBtn.width(), 0)
        
        if not self.sizeApplied:
            self.sizeApplied = True
            s = min(self.width(), max(100, min(200, self.width()*0.25)))
            s2 = self.width()-s
            self.ui.splitter.setSizes([s2, s])

    
    def updateRedirect(self, *args):
        ### Decide whether/where to redirect items and make it so
        cname = str(self.ui.redirectCombo.currentText())
        man = CanvasManager.instance()
        if self.ui.redirectCheck.isChecked() and cname != '':
            redirect = man.getCanvas(cname)
        else:
            redirect = None
            
        if self.redirect is redirect:
            return
            
        self.redirect = redirect
        if redirect is None:
            self.reclaimItems()
        else:
            self.redirectItems(redirect)

    
    def redirectItems(self, canvas):
        for i in self.items:
            if i is self.grid:
                continue
            li = i.listItem
            parent = li.parent()
            if parent is None:
                tree = li.treeWidget()
                if tree is None:
                    print "Skipping item", i, i.name
                    continue
                tree.removeTopLevelItem(li)
            else:
                parent.removeChild(li)
            canvas.addItem(i)
            

    def reclaimItems(self):
        items = self.items
        #self.items = {'Grid': items['Grid']}
        #del items['Grid']
        self.items = [self.grid]
        items.remove(self.grid)
        
        for i in items:
            i.canvas.removeItem(i)
            self.addItem(i)

    def treeItemChanged(self, item, col):
        #gi = self.items.get(item.name, None)
        #if gi is None:
            #return
        try:
            citem = item.canvasItem
        except AttributeError:
            return
        if item.checkState(0) == QtCore.Qt.Checked:
            for i in range(item.childCount()):
                item.child(i).setCheckState(0, QtCore.Qt.Checked)
            citem.show()
        else:
            for i in range(item.childCount()):
                item.child(i).setCheckState(0, QtCore.Qt.Unchecked)
            citem.hide()

    def treeItemSelected(self):
        sel = self.selectedItems()
        #sel = []
        #for listItem in self.itemList.selectedItems():
            #if hasattr(listItem, 'canvasItem') and listItem.canvasItem is not None:
                #sel.append(listItem.canvasItem)
        #sel = [self.items[item.name] for item in sel]
        
        if len(sel) == 0:
            #self.selectWidget.hide()
            return
            
        multi = len(sel) > 1
        for i in self.items:
            #i.ctrlWidget().hide()
            ## updated the selected state of every item
            i.selectionChanged(i in sel, multi)
            
        if len(sel)==1:
            #item = sel[0]
            #item.ctrlWidget().show()
            self.multiSelectBox.hide()
            self.ui.mirrorSelectionBtn.hide()
            self.ui.reflectSelectionBtn.hide()
            self.ui.resetTransformsBtn.hide()
        elif len(sel) > 1:
            self.showMultiSelectBox()
        
        #if item.isMovable():
            #self.selectBox.setPos(item.item.pos())
            #self.selectBox.setSize(item.item.sceneBoundingRect().size())
            #self.selectBox.show()
        #else:
            #self.selectBox.hide()
        
        #self.emit(QtCore.SIGNAL('itemSelected'), self, item)
        self.sigSelectionChanged.emit(self, sel)
        
    def selectedItems(self):
        """
        Return list of all selected canvasItems
        """
        return [item.canvasItem for item in self.itemList.selectedItems() if item.canvasItem is not None]
        
    #def selectedItem(self):
        #sel = self.itemList.selectedItems()
        #if sel is None or len(sel) < 1:
            #return
        #return self.items.get(sel[0].name, None)

    def selectItem(self, item):
        li = item.listItem
        #li = self.getListItem(item.name())
        #print "select", li
        self.itemList.setCurrentItem(li)

        
        
    def showMultiSelectBox(self):
        ## Get list of selected canvas items
        items = self.selectedItems()
        
        rect = self.view.itemBoundingRect(items[0].graphicsItem())
        for i in items:
            if not i.isMovable():  ## all items in selection must be movable
                return
            br = self.view.itemBoundingRect(i.graphicsItem())
            rect = rect|br
            
        self.multiSelectBox.blockSignals(True)
        self.multiSelectBox.setPos([rect.x(), rect.y()])
        self.multiSelectBox.setSize(rect.size())
        self.multiSelectBox.setAngle(0)
        self.multiSelectBox.blockSignals(False)
        
        self.multiSelectBox.show()
        
        self.ui.mirrorSelectionBtn.show()
        self.ui.reflectSelectionBtn.show()
        self.ui.resetTransformsBtn.show()
        #self.multiSelectBoxBase = self.multiSelectBox.getState().copy()

    def mirrorSelectionClicked(self):
        for ci in self.selectedItems():
            ci.mirrorY()
        self.showMultiSelectBox()

    def reflectSelectionClicked(self):
        for ci in self.selectedItems():
            ci.mirrorXY()
        self.showMultiSelectBox()
            
    def resetTransformsClicked(self):
        for i in self.selectedItems():
            i.resetTransformClicked()
        self.showMultiSelectBox()

    def multiSelectBoxChanged(self):
        self.multiSelectBoxMoved()
        
    def multiSelectBoxChangeFinished(self):
        for ci in self.selectedItems():
            ci.applyTemporaryTransform()
            ci.sigTransformChangeFinished.emit(ci)
        
    def multiSelectBoxMoved(self):
        transform = self.multiSelectBox.getGlobalTransform()
        for ci in self.selectedItems():
            ci.setTemporaryTransform(transform)
            ci.sigTransformChanged.emit(ci)
        

    def addGraphicsItem(self, item, **opts):
        """Add a new GraphicsItem to the scene at pos.
        Common options are name, pos, scale, and z
        """
        citem = CanvasItem(item, **opts)
        item._canvasItem = citem
        self.addItem(citem)
        return citem
            

    def addGroup(self, name, **kargs):
        group = GroupCanvasItem(name=name)
        self.addItem(group, **kargs)
        return group
        

    def addItem(self, citem):
        """
        Add an item to the canvas. 
        """
        
        ## Check for redirections
        if self.redirect is not None:
            name = self.redirect.addItem(citem)
            self.items.append(citem)
            return name

        if not self.allowTransforms:
            citem.setMovable(False)

        citem.sigTransformChanged.connect(self.itemTransformChanged)
        citem.sigTransformChangeFinished.connect(self.itemTransformChangeFinished)
        citem.sigVisibilityChanged.connect(self.itemVisibilityChanged)

        
        ## Determine name to use in the item list
        name = citem.opts['name']
        if name is None:
            name = 'item'
        newname = name

        ## If name already exists, append a number to the end
        ## NAH. Let items have the same name if they really want.
        #c=0
        #while newname in self.items:
            #c += 1
            #newname = name + '_%03d' %c
        #name = newname
            
        ## find parent and add item to tree
        #currentNode = self.itemList.invisibleRootItem()
        insertLocation = 0
        #print "Inserting node:", name
        
            
        ## determine parent list item where this item should be inserted
        parent = citem.parentItem()
        if parent in (None, self.view.childGroup):
            parent = self.itemList.invisibleRootItem()
        else:
            parent = parent.listItem
        
        ## set Z value above all other siblings if none was specified
        siblings = [parent.child(i).canvasItem for i in xrange(parent.childCount())]
        z = citem.zValue()
        if z is None:
            zvals = [i.zValue() for i in siblings]
            if len(zvals) == 0:
                z = 0
            else:
                z = max(zvals)+10
            citem.setZValue(z)
            
        ## determine location to insert item relative to its siblings
        for i in range(parent.childCount()):
            ch = parent.child(i)
            zval = ch.canvasItem.graphicsItem().zValue()  ## should we use CanvasItem.zValue here?
            if zval < z:
                insertLocation = i
                break
            else:
                insertLocation = i+1
                
        node = QtGui.QTreeWidgetItem([name])
        flags = node.flags() | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsDragEnabled
        if not isinstance(citem, GroupCanvasItem):
            flags = flags & ~QtCore.Qt.ItemIsDropEnabled
        node.setFlags(flags)
        if citem.opts['visible']:
            node.setCheckState(0, QtCore.Qt.Checked)
        else:
            node.setCheckState(0, QtCore.Qt.Unchecked)
        
        node.name = name
        #if citem.opts['parent'] != None:
            ## insertLocation is incorrect in this case
        parent.insertChild(insertLocation, node)
        #else:    
            #root.insertChild(insertLocation, node)
        
        citem.name = name
        citem.listItem = node
        node.canvasItem = citem
        self.items.append(citem)

        ctrl = citem.ctrlWidget()
        ctrl.hide()
        self.ui.ctrlLayout.addWidget(ctrl)
        
        ## inform the canvasItem that its parent canvas has changed
        citem.setCanvas(self)

        ## Autoscale to fit the first item added (not including the grid).
        if len(self.items) == 2:
            self.autoRange()
            
        
        #for n in name:
            #nextnode = None
            #for x in range(currentNode.childCount()):
                #ch = currentNode.child(x)
                #if hasattr(ch, 'name'):    ## check Z-value of current item to determine insert location
                    #zval = ch.canvasItem.zValue()
                    #if zval > z:
                        ###print "  ->", x
                        #insertLocation = x+1
                #if n == ch.text(0):
                    #nextnode = ch
                    #break
            #if nextnode is None:  ## If name doesn't exist, create it
                #nextnode = QtGui.QTreeWidgetItem([n])
                #nextnode.setFlags((nextnode.flags() | QtCore.Qt.ItemIsUserCheckable) & ~QtCore.Qt.ItemIsDropEnabled)
                #nextnode.setCheckState(0, QtCore.Qt.Checked)
                ### Add node to correct position in list by Z-value
                ###print "  ==>", insertLocation
                #currentNode.insertChild(insertLocation, nextnode)
                
                #if n == name[-1]:   ## This is the leaf; add some extra properties.
                    #nextnode.name = name
                
                #if n == name[0]:   ## This is the root; make the item movable
                    #nextnode.setFlags(nextnode.flags() | QtCore.Qt.ItemIsDragEnabled)
                #else:
                    #nextnode.setFlags(nextnode.flags() & ~QtCore.Qt.ItemIsDragEnabled)
                    
            #currentNode = nextnode
        return citem

    def treeItemMoved(self, item, parent, index):
        ##Item moved in tree; update Z values
        if parent is self.itemList.invisibleRootItem():
            item.canvasItem.setParentItem(self.view.childGroup)
        else:
            item.canvasItem.setParentItem(parent.canvasItem)
        siblings = [parent.child(i).canvasItem for i in xrange(parent.childCount())]
        
        zvals = [i.zValue() for i in siblings]
        zvals.sort(reverse=True)
        
        for i in range(len(siblings)):
            item = siblings[i]
            item.setZValue(zvals[i])
            #item = self.itemList.topLevelItem(i)
            
            ##ci = self.items[item.name]
            #ci = item.canvasItem
            #if ci is None:
                #continue
            #if ci.zValue() != zvals[i]:
                #ci.setZValue(zvals[i])
        
        #if self.itemList.topLevelItemCount() < 2:
            #return
        #name = item.name
        #gi = self.items[name]
        #if index == 0:   
            #next = self.itemList.topLevelItem(1)
            #z = self.items[next.name].zValue()+1
        #else:
            #prev = self.itemList.topLevelItem(index-1)
            #z = self.items[prev.name].zValue()-1
        #gi.setZValue(z)





        
    def itemVisibilityChanged(self, item):
        listItem = item.listItem
        checked = listItem.checkState(0) == QtCore.Qt.Checked
        vis = item.isVisible()
        if vis != checked:
            if vis:
                listItem.setCheckState(0, QtCore.Qt.Checked)
            else:
                listItem.setCheckState(0, QtCore.Qt.Unchecked)

    def removeItem(self, item):
        if isinstance(item, CanvasItem):
            item.setCanvas(None)
            self.itemList.removeTopLevelItem(item.listItem)
            self.items.remove(item)
        else:
            if hasattr(item, '_canvasItem'):
                self.removeItem(item._canvasItem)
            else:
                self.view.removeItem(item)
        
        ## disconnect signals, remove from list, etc..
        

    def addToScene(self, item):
        self.view.addItem(item)
        
    def removeFromScene(self, item):
        self.view.removeItem(item)

    
    def listItems(self):
        """Return a dictionary of name:item pairs"""
        return self.items
        
    def getListItem(self, name):
        return self.items[name]
        
    #def scene(self):
        #return self.view.scene()
        
    def itemTransformChanged(self, item):
        #self.emit(QtCore.SIGNAL('itemTransformChanged'), self, item)
        self.sigItemTransformChanged.emit(self, item)
    
    def itemTransformChangeFinished(self, item):
        #self.emit(QtCore.SIGNAL('itemTransformChangeFinished'), self, item)
        self.sigItemTransformChangeFinished.emit(self, item)
Example #12
0
    def __init__(self, image=None, fillHistogram=True):
        """
        If *image* (ImageItem) is provided, then the control will be automatically linked
        to the image and changes to the control will be immediately reflected in the image's appearance.
        By default, the histogram is rendered with a fill. For performance, set *fillHistogram* = False.
        """
        HistogramLUTItem.__init__(self, image, fillHistogram)

        self.layout = QtGui.QGraphicsGridLayout()
        self.layout.setContentsMargins(1, 1, 1, 1)
        self.layout.setSpacing(0)

        # the viewbox in which would be displayed the histogram
        # get a new and descriptive name for the view box
        self.view_boxHistogram = self.vb
        self.view_boxHistogram = ViewBox()
        self.view_boxHistogram.setMaximumHeight(self.HISTOGRAM_MAX_HEIGHT)
        self.view_boxHistogram.setMinimumHeight(self.HISTOGRAM_MIN_HEIGHT)
        self.view_boxHistogram.setMouseEnabled(x=False, y=False)

        # set defaults gradient position and color bar
        self.gradient.setOrientation('bottom')
        self.gradient.loadPreset('thermal')

        # todo remove this parche the region of threshold selection
        self.region.setVisible(False)
        self._region = LinearRegionItem(values=[-40, 0], orientation=LinearRegionItem.Vertical)

        self.view_boxHistogram.addItem(self._region)
        self.axis = AxisItem('top', linkView=self.view_boxHistogram, maxTickLength=-10, showValues=False)

        self.layout.addItem(self.axis, 0, 0)
        self.layout.addItem(self.view_boxHistogram, 1, 0)
        self.layout.addItem(self.gradient, 2, 0)

        self.gradient.setFlag(self.gradient.ItemStacksBehindParent)
        self.view_boxHistogram.setFlag(self.gradient.ItemStacksBehindParent)

        self.plot = PlotDataItem()
        self.fillHistogram(fillHistogram)

        self.view_boxHistogram.addItem(self.plot)
        self.autoHistogramRange()

        # set the fixed range of visualization
        self.view_boxHistogram.setXRange(-120, 5)
        self._region.setBounds((-120, 5))

        y_range = self.view_boxHistogram.viewRange()[1]

        # the minThresholdLabel and maxThresholdLabel labels
        self.minThresholdLabel = pg.TextItem(self.tr(u'Min'), color=(255, 255, 255), anchor=(1, 0.5))
        self.view_boxHistogram.addItem(self.minThresholdLabel)

        self.maxThresholdLabel = pg.TextItem(self.tr(u'Max'), color=(255, 255, 255), anchor=(0, 0.5))
        self.view_boxHistogram.addItem(self.maxThresholdLabel)

        self.gradient.sigGradientChanged.connect(self.gradientChanged)
        self._region.sigRegionChanged.connect(self.regionChanging)
        self._region.sigRegionChangeFinished.connect(self.regionChanged)

        labels_ypos = self.view_boxHistogram.viewRange()[1][1] * 0.7
        self.maxThresholdLabel.setPos(self._region.getRegion()[1], labels_ypos)
        self.minThresholdLabel.setPos(self._region.getRegion()[0], labels_ypos)

        # update the tooltips and position of the limit labels
        self._region.sigRegionChangeFinished.connect(
            lambda: self.maxThresholdLabel.setToolTip(self.tr(u'Max Threshold') + u": " +
                                                      unicode(round(self._region.getRegion()[1],
                                                                    self.DECIMAL_PLACES))))

        self._region.sigRegionChangeFinished.connect(
            lambda: self.minThresholdLabel.setToolTip(self.tr(u'Min Threshold') + u": " +
                                                      unicode(round(self._region.getRegion()[0],
                                                                    self.DECIMAL_PLACES))))

        # set the y position of the labels to the 70% of the visible y range of the viewbox
        self._region.sigRegionChanged.connect(
            lambda: self.maxThresholdLabel.setPos(self._region.getRegion()[1],
                                                  self.view_boxHistogram.viewRange()[1][1] * 0.7))

        self._region.sigRegionChanged.connect(
            lambda: self.minThresholdLabel.setPos(self._region.getRegion()[0],
                                                  self.view_boxHistogram.viewRange()[1][1] * 0.7))

        if image is not None:
            self.setImageItem(image)

        self.setLayout(self.layout)
Example #13
0
class Canvas(QtGui.QWidget):

    sigSelectionChanged = QtCore.Signal(object, object)
    sigItemTransformChanged = QtCore.Signal(object, object)
    sigItemTransformChangeFinished = QtCore.Signal(object, object)

    def __init__(self,
                 parent=None,
                 allowTransforms=True,
                 hideCtrl=False,
                 name=None):
        QtGui.QWidget.__init__(self, parent)
        self.ui = Ui_Form()
        self.ui.setupUi(self)
        #self.view = self.ui.view
        self.view = ViewBox()
        self.ui.view.setCentralItem(self.view)
        self.itemList = self.ui.itemList
        self.itemList.setSelectionMode(self.itemList.ExtendedSelection)
        self.allowTransforms = allowTransforms
        self.multiSelectBox = SelectBox()
        self.view.addItem(self.multiSelectBox)
        self.multiSelectBox.hide()
        self.multiSelectBox.setZValue(1e6)
        self.ui.mirrorSelectionBtn.hide()
        self.ui.reflectSelectionBtn.hide()
        self.ui.resetTransformsBtn.hide()

        self.redirect = None  ## which canvas to redirect items to
        self.items = []

        #self.view.enableMouse()
        self.view.setAspectLocked(True)
        #self.view.invertY()

        grid = GridItem()
        self.grid = CanvasItem(grid, name='Grid', movable=False)
        self.addItem(self.grid)

        self.hideBtn = QtGui.QPushButton('>', self)
        self.hideBtn.setFixedWidth(20)
        self.hideBtn.setFixedHeight(20)
        self.ctrlSize = 200
        self.sizeApplied = False
        self.hideBtn.clicked.connect(self.hideBtnClicked)
        self.ui.splitter.splitterMoved.connect(self.splitterMoved)

        self.ui.itemList.itemChanged.connect(self.treeItemChanged)
        self.ui.itemList.sigItemMoved.connect(self.treeItemMoved)
        self.ui.itemList.itemSelectionChanged.connect(self.treeItemSelected)
        self.ui.autoRangeBtn.clicked.connect(self.autoRange)
        self.ui.storeSvgBtn.clicked.connect(self.storeSvg)
        self.ui.storePngBtn.clicked.connect(self.storePng)
        self.ui.redirectCheck.toggled.connect(self.updateRedirect)
        self.ui.redirectCombo.currentIndexChanged.connect(self.updateRedirect)
        self.multiSelectBox.sigRegionChanged.connect(
            self.multiSelectBoxChanged)
        self.multiSelectBox.sigRegionChangeFinished.connect(
            self.multiSelectBoxChangeFinished)
        self.ui.mirrorSelectionBtn.clicked.connect(self.mirrorSelectionClicked)
        self.ui.reflectSelectionBtn.clicked.connect(
            self.reflectSelectionClicked)
        self.ui.resetTransformsBtn.clicked.connect(self.resetTransformsClicked)

        self.resizeEvent()
        if hideCtrl:
            self.hideBtnClicked()

        if name is not None:
            self.registeredName = CanvasManager.instance().registerCanvas(
                self, name)
            self.ui.redirectCombo.setHostName(self.registeredName)

        self.menu = QtGui.QMenu()
        #self.menu.setTitle("Image")
        remAct = QtGui.QAction("Remove item", self.menu)
        remAct.triggered.connect(self.removeClicked)
        self.menu.addAction(remAct)
        self.menu.remAct = remAct
        self.ui.itemList.contextMenuEvent = self.itemListContextMenuEvent

    def storeSvg(self):
        self.ui.view.writeSvg()

    def storePng(self):
        self.ui.view.writeImage()

    def splitterMoved(self):
        self.resizeEvent()

    def hideBtnClicked(self):
        ctrlSize = self.ui.splitter.sizes()[1]
        if ctrlSize == 0:
            cs = self.ctrlSize
            w = self.ui.splitter.size().width()
            if cs > w:
                cs = w - 20
            self.ui.splitter.setSizes([w - cs, cs])
            self.hideBtn.setText('>')
        else:
            self.ctrlSize = ctrlSize
            self.ui.splitter.setSizes([100, 0])
            self.hideBtn.setText('<')
        self.resizeEvent()

    def autoRange(self):
        self.view.autoRange()

    def resizeEvent(self, ev=None):
        if ev is not None:
            QtGui.QWidget.resizeEvent(self, ev)
        self.hideBtn.move(self.ui.view.size().width() - self.hideBtn.width(),
                          0)

        if not self.sizeApplied:
            self.sizeApplied = True
            s = min(self.width(), max(100, min(200, self.width() * 0.25)))
            s2 = self.width() - s
            self.ui.splitter.setSizes([s2, s])

    def updateRedirect(self, *args):
        ### Decide whether/where to redirect items and make it so
        cname = str(self.ui.redirectCombo.currentText())
        man = CanvasManager.instance()
        if self.ui.redirectCheck.isChecked() and cname != '':
            redirect = man.getCanvas(cname)
        else:
            redirect = None

        if self.redirect is redirect:
            return

        self.redirect = redirect
        if redirect is None:
            self.reclaimItems()
        else:
            self.redirectItems(redirect)

    def redirectItems(self, canvas):
        for i in self.items:
            if i is self.grid:
                continue
            li = i.listItem
            parent = li.parent()
            if parent is None:
                tree = li.treeWidget()
                if tree is None:
                    print("Skipping item", i, i.name)
                    continue
                tree.removeTopLevelItem(li)
            else:
                parent.removeChild(li)
            canvas.addItem(i)

    def reclaimItems(self):
        items = self.items
        #self.items = {'Grid': items['Grid']}
        #del items['Grid']
        self.items = [self.grid]
        items.remove(self.grid)

        for i in items:
            i.canvas.removeItem(i)
            self.addItem(i)

    def treeItemChanged(self, item, col):
        #gi = self.items.get(item.name, None)
        #if gi is None:
        #return
        try:
            citem = item.canvasItem()
        except AttributeError:
            return
        if item.checkState(0) == QtCore.Qt.Checked:
            for i in range(item.childCount()):
                item.child(i).setCheckState(0, QtCore.Qt.Checked)
            citem.show()
        else:
            for i in range(item.childCount()):
                item.child(i).setCheckState(0, QtCore.Qt.Unchecked)
            citem.hide()

    def treeItemSelected(self):
        sel = self.selectedItems()
        #sel = []
        #for listItem in self.itemList.selectedItems():
        #if hasattr(listItem, 'canvasItem') and listItem.canvasItem is not None:
        #sel.append(listItem.canvasItem)
        #sel = [self.items[item.name] for item in sel]

        if len(sel) == 0:
            #self.selectWidget.hide()
            return

        multi = len(sel) > 1
        for i in self.items:
            #i.ctrlWidget().hide()
            ## updated the selected state of every item
            i.selectionChanged(i in sel, multi)

        if len(sel) == 1:
            #item = sel[0]
            #item.ctrlWidget().show()
            self.multiSelectBox.hide()
            self.ui.mirrorSelectionBtn.hide()
            self.ui.reflectSelectionBtn.hide()
            self.ui.resetTransformsBtn.hide()
        elif len(sel) > 1:
            self.showMultiSelectBox()

        #if item.isMovable():
        #self.selectBox.setPos(item.item.pos())
        #self.selectBox.setSize(item.item.sceneBoundingRect().size())
        #self.selectBox.show()
        #else:
        #self.selectBox.hide()

        #self.emit(QtCore.SIGNAL('itemSelected'), self, item)
        self.sigSelectionChanged.emit(self, sel)

    def selectedItems(self):
        """
        Return list of all selected canvasItems
        """
        return [
            item.canvasItem() for item in self.itemList.selectedItems()
            if item.canvasItem() is not None
        ]

    #def selectedItem(self):
    #sel = self.itemList.selectedItems()
    #if sel is None or len(sel) < 1:
    #return
    #return self.items.get(sel[0].name, None)

    def selectItem(self, item):
        li = item.listItem
        #li = self.getListItem(item.name())
        #print "select", li
        self.itemList.setCurrentItem(li)

    def showMultiSelectBox(self):
        ## Get list of selected canvas items
        items = self.selectedItems()

        rect = self.view.itemBoundingRect(items[0].graphicsItem())
        for i in items:
            if not i.isMovable():  ## all items in selection must be movable
                return
            br = self.view.itemBoundingRect(i.graphicsItem())
            rect = rect | br

        self.multiSelectBox.blockSignals(True)
        self.multiSelectBox.setPos([rect.x(), rect.y()])
        self.multiSelectBox.setSize(rect.size())
        self.multiSelectBox.setAngle(0)
        self.multiSelectBox.blockSignals(False)

        self.multiSelectBox.show()

        self.ui.mirrorSelectionBtn.show()
        self.ui.reflectSelectionBtn.show()
        self.ui.resetTransformsBtn.show()
        #self.multiSelectBoxBase = self.multiSelectBox.getState().copy()

    def mirrorSelectionClicked(self):
        for ci in self.selectedItems():
            ci.mirrorY()
        self.showMultiSelectBox()

    def reflectSelectionClicked(self):
        for ci in self.selectedItems():
            ci.mirrorXY()
        self.showMultiSelectBox()

    def resetTransformsClicked(self):
        for i in self.selectedItems():
            i.resetTransformClicked()
        self.showMultiSelectBox()

    def multiSelectBoxChanged(self):
        self.multiSelectBoxMoved()

    def multiSelectBoxChangeFinished(self):
        for ci in self.selectedItems():
            ci.applyTemporaryTransform()
            ci.sigTransformChangeFinished.emit(ci)

    def multiSelectBoxMoved(self):
        transform = self.multiSelectBox.getGlobalTransform()
        for ci in self.selectedItems():
            ci.setTemporaryTransform(transform)
            ci.sigTransformChanged.emit(ci)

    def addGraphicsItem(self, item, **opts):
        """Add a new GraphicsItem to the scene at pos.
        Common options are name, pos, scale, and z
        """
        citem = CanvasItem(item, **opts)
        item._canvasItem = citem
        self.addItem(citem)
        return citem

    def addGroup(self, name, **kargs):
        group = GroupCanvasItem(name=name)
        self.addItem(group, **kargs)
        return group

    def addItem(self, citem):
        """
        Add an item to the canvas. 
        """

        ## Check for redirections
        if self.redirect is not None:
            name = self.redirect.addItem(citem)
            self.items.append(citem)
            return name

        if not self.allowTransforms:
            citem.setMovable(False)

        citem.sigTransformChanged.connect(self.itemTransformChanged)
        citem.sigTransformChangeFinished.connect(
            self.itemTransformChangeFinished)
        citem.sigVisibilityChanged.connect(self.itemVisibilityChanged)

        ## Determine name to use in the item list
        name = citem.opts['name']
        if name is None:
            name = 'item'
        newname = name

        ## If name already exists, append a number to the end
        ## NAH. Let items have the same name if they really want.
        #c=0
        #while newname in self.items:
        #c += 1
        #newname = name + '_%03d' %c
        #name = newname

        ## find parent and add item to tree
        #currentNode = self.itemList.invisibleRootItem()
        insertLocation = 0
        #print "Inserting node:", name

        ## determine parent list item where this item should be inserted
        parent = citem.parentItem()
        if parent in (None, self.view.childGroup):
            parent = self.itemList.invisibleRootItem()
        else:
            parent = parent.listItem

        ## set Z value above all other siblings if none was specified
        siblings = [
            parent.child(i).canvasItem() for i in range(parent.childCount())
        ]
        z = citem.zValue()
        if z is None:
            zvals = [i.zValue() for i in siblings]
            if parent == self.itemList.invisibleRootItem():
                if len(zvals) == 0:
                    z = 0
                else:
                    z = max(zvals) + 10
            else:
                if len(zvals) == 0:
                    z = parent.canvasItem().zValue()
                else:
                    z = max(zvals) + 1
            citem.setZValue(z)

        ## determine location to insert item relative to its siblings
        for i in range(parent.childCount()):
            ch = parent.child(i)
            zval = ch.canvasItem().graphicsItem().zValue(
            )  ## should we use CanvasItem.zValue here?
            if zval < z:
                insertLocation = i
                break
            else:
                insertLocation = i + 1

        node = QtGui.QTreeWidgetItem([name])
        flags = node.flags(
        ) | QtCore.Qt.ItemIsUserCheckable | QtCore.Qt.ItemIsDragEnabled
        if not isinstance(citem, GroupCanvasItem):
            flags = flags & ~QtCore.Qt.ItemIsDropEnabled
        node.setFlags(flags)
        if citem.opts['visible']:
            node.setCheckState(0, QtCore.Qt.Checked)
        else:
            node.setCheckState(0, QtCore.Qt.Unchecked)

        node.name = name
        #if citem.opts['parent'] != None:
        ## insertLocation is incorrect in this case
        parent.insertChild(insertLocation, node)
        #else:
        #root.insertChild(insertLocation, node)

        citem.name = name
        citem.listItem = node
        node.canvasItem = weakref.ref(citem)
        self.items.append(citem)

        ctrl = citem.ctrlWidget()
        ctrl.hide()
        self.ui.ctrlLayout.addWidget(ctrl)

        ## inform the canvasItem that its parent canvas has changed
        citem.setCanvas(self)

        ## Autoscale to fit the first item added (not including the grid).
        if len(self.items) == 2:
            self.autoRange()

        #for n in name:
        #nextnode = None
        #for x in range(currentNode.childCount()):
        #ch = currentNode.child(x)
        #if hasattr(ch, 'name'):    ## check Z-value of current item to determine insert location
        #zval = ch.canvasItem.zValue()
        #if zval > z:
        ###print "  ->", x
        #insertLocation = x+1
        #if n == ch.text(0):
        #nextnode = ch
        #break
        #if nextnode is None:  ## If name doesn't exist, create it
        #nextnode = QtGui.QTreeWidgetItem([n])
        #nextnode.setFlags((nextnode.flags() | QtCore.Qt.ItemIsUserCheckable) & ~QtCore.Qt.ItemIsDropEnabled)
        #nextnode.setCheckState(0, QtCore.Qt.Checked)
        ### Add node to correct position in list by Z-value
        ###print "  ==>", insertLocation
        #currentNode.insertChild(insertLocation, nextnode)

        #if n == name[-1]:   ## This is the leaf; add some extra properties.
        #nextnode.name = name

        #if n == name[0]:   ## This is the root; make the item movable
        #nextnode.setFlags(nextnode.flags() | QtCore.Qt.ItemIsDragEnabled)
        #else:
        #nextnode.setFlags(nextnode.flags() & ~QtCore.Qt.ItemIsDragEnabled)

        #currentNode = nextnode
        return citem

    def treeItemMoved(self, item, parent, index):
        ##Item moved in tree; update Z values
        if parent is self.itemList.invisibleRootItem():
            item.canvasItem().setParentItem(self.view.childGroup)
        else:
            item.canvasItem().setParentItem(parent.canvasItem())
        siblings = [
            parent.child(i).canvasItem() for i in range(parent.childCount())
        ]

        zvals = [i.zValue() for i in siblings]
        zvals.sort(reverse=True)

        for i in range(len(siblings)):
            item = siblings[i]
            item.setZValue(zvals[i])
            #item = self.itemList.topLevelItem(i)

            ##ci = self.items[item.name]
            #ci = item.canvasItem
            #if ci is None:
            #continue
            #if ci.zValue() != zvals[i]:
            #ci.setZValue(zvals[i])

        #if self.itemList.topLevelItemCount() < 2:
        #return
        #name = item.name
        #gi = self.items[name]
        #if index == 0:
        #next = self.itemList.topLevelItem(1)
        #z = self.items[next.name].zValue()+1
        #else:
        #prev = self.itemList.topLevelItem(index-1)
        #z = self.items[prev.name].zValue()-1
        #gi.setZValue(z)

    def itemVisibilityChanged(self, item):
        listItem = item.listItem
        checked = listItem.checkState(0) == QtCore.Qt.Checked
        vis = item.isVisible()
        if vis != checked:
            if vis:
                listItem.setCheckState(0, QtCore.Qt.Checked)
            else:
                listItem.setCheckState(0, QtCore.Qt.Unchecked)

    def removeItem(self, item):
        if isinstance(item, QtGui.QTreeWidgetItem):
            item = item.canvasItem()

        if isinstance(item, CanvasItem):
            item.setCanvas(None)
            listItem = item.listItem
            listItem.canvasItem = None
            item.listItem = None
            self.itemList.removeTopLevelItem(listItem)
            self.items.remove(item)
            ctrl = item.ctrlWidget()
            ctrl.hide()
            self.ui.ctrlLayout.removeWidget(ctrl)
        else:
            if hasattr(item, '_canvasItem'):
                self.removeItem(item._canvasItem)
            else:
                self.view.removeItem(item)

        ## disconnect signals, remove from list, etc..

    def clear(self):
        while len(self.items) > 0:
            self.removeItem(self.items[0])

    def addToScene(self, item):
        self.view.addItem(item)

    def removeFromScene(self, item):
        self.view.removeItem(item)

    def listItems(self):
        """Return a dictionary of name:item pairs"""
        return self.items

    def getListItem(self, name):
        return self.items[name]

    #def scene(self):
    #return self.view.scene()

    def itemTransformChanged(self, item):
        #self.emit(QtCore.SIGNAL('itemTransformChanged'), self, item)
        self.sigItemTransformChanged.emit(self, item)

    def itemTransformChangeFinished(self, item):
        #self.emit(QtCore.SIGNAL('itemTransformChangeFinished'), self, item)
        self.sigItemTransformChangeFinished.emit(self, item)

    def itemListContextMenuEvent(self, ev):
        self.menuItem = self.itemList.itemAt(ev.pos())
        self.menu.popup(ev.globalPos())

    def removeClicked(self):
        self.removeItem(self.menuItem)
        self.menuItem = None
        import gc
        gc.collect()
Example #14
0
 def __init__(self, graph, enable_menu=False):
     ViewBox.__init__(self, enableMenu=enable_menu)
     self.graph = graph
     self.setMouseMode(self.PanMode)
Example #15
0
 def __init__(self, graph, enable_menu=False):
     ViewBox.__init__(self, enableMenu=enable_menu)
     self.graph = graph
     self.setMouseMode(self.PanMode)
Example #16
0
class SpectrogramWidget(QtGui.QWidget):
    """
    Widget that visualize and interacts with a spectrogram graph
    of an audio signal.
    """
    # SIGNALS

    # CONSTANTS
    # Value of the axis lines opacity
    AXIS_LINES_OPACITY = 255

    # Max amount of columns to show on the visual widget.
    MAX_SPECGRAM_COLUMNS = 800

    def __init__(self, *args, **kwargs):
        QtGui.QWidget.__init__(self)
        # variable that handles the manipulation of the spectrogram
        # create, recompute etc
        self.specgramHandler = Spectrogram()

        # create the histogram widget
        self.imageItem = ImageItem()
        self.__histogram = HorizontalHistogramWidget()
        self.__histogram.item.setImageItem(self.imageItem)

        # internal vieBox for image graph
        self.viewBox = ViewBox()
        self.viewBox.addItem(self.imageItem)
        self.viewBox.setMouseEnabled(x=False, y=False)
        self.viewBox.setMenuEnabled(False)
        self.viewBox.setAspectLocked(False)

        # set the X and Y axis for the graph
        self.xAxis = OscXAxis(self, orientation='bottom')
        self.yAxis = SpecYAxis(self, orientation='left')

        self.xAxis.linkToView(self.viewBox)
        self.yAxis.linkToView(self.viewBox)

        self.xAxis.setGrid(self.AXIS_LINES_OPACITY)
        self.yAxis.setGrid(self.AXIS_LINES_OPACITY)

        # adjust the graph zone in the control
        horizontal_histogram = kwargs[
            "horizontal_histogram"] if "horizontal_histogram" in kwargs else True
        visible_histogram = kwargs[
            "visible_histogram"] if "visible_histogram" in kwargs else False
        self.__updateLayout(histogramHorizontal=(
            horizontal_histogram if visible_histogram else None))

    def __updateLayout(self, histogramHorizontal=None):
        """
        Updates the layout of the widget to change the histogram
        position (horizontal-vertical) and visibility
        :param histogramHorizontal: None if invisible, true if horizontal
        false if vertical
        :return:
        """
        # graph_control_layout

        self.graphics_view = pg.GraphicsView()

        # set the layout of the graphics view internal
        # that contains the axis and the view box to graph the spectrogram
        graphics_view_grid_layout = QtGui.QGraphicsGridLayout()
        graphics_view_grid_layout.setContentsMargins(0, 0, 0, 0)
        graphics_view_grid_layout.setHorizontalSpacing(0)
        graphics_view_grid_layout.setVerticalSpacing(0)

        graphics_view_grid_layout.addItem(self.xAxis, 1, 1)
        graphics_view_grid_layout.addItem(self.yAxis, 0, 0)
        graphics_view_grid_layout.addItem(self.viewBox, 0, 1)

        self.graphics_view.centralWidget.setLayout(graphics_view_grid_layout)
        layout = QtGui.QGridLayout()
        layout.setContentsMargins(0, 0, 0, 0)
        layout.addWidget(self.graphics_view, 0, 0)
        # add the elements in row,col

        if histogramHorizontal is not None:
            row = 1 if histogramHorizontal else 0
            col = 1 - row
            self.__histogram = HorizontalHistogramWidget() if histogramHorizontal else\
                               HistogramLUTWidget()
            self.__histogram.item.gradient.loadPreset('thermal')
            self.__histogram.item.setImageItem(self.imageItem)
            layout.addWidget(self.histogram, row, col)

        self.setLayout(layout)

    # region Signal Property
    @property
    def signal(self):
        return self.specgramHandler.signal

    @signal.setter
    def signal(self, signal):
        if signal is None or not isinstance(signal, AudioSignal):
            raise ValueError(
                "Invalid assignation. Must be of type AudioSignal")

        self.specgramHandler.signal = signal

        max_columns = max(self.viewBox.width(), self.MAX_SPECGRAM_COLUMNS)

        self.specgramHandler.recomputeSpectrogram(maxCol=max_columns)
        # updating the axis scales
        self.xAxis.scale = self.specgramHandler.signal.samplingRate

        # updating the frequencies present in the signal
        # samplingRate/2 by Nyquist theorem. After update the spectrogram handler
        # there is an array in the specgramHandler with the freqs returned by the specgram
        # freqs is an array with the values of the frequency of each row of the specgram matriz
        self.yAxis.frequencies = self.specgramHandler.freqs

    # endregion

    # region Histogram Prop
    @property
    def histogram(self):
        """
        Histogram widget with the values of the image.
        interacts with the image graph to change its color,
        threshold etc. Allow to visualize it outside the spectrogram widget
        :return:
        """
        return self.__histogram

    # endregion

    def getInfo(self, x, y):
        """
        Gets the values at x, y in the spectrogram
        :param x: the time position in rows of the spectrogram matriz
        :param y: the freq position in columns of the spectrogram matriz
        :return: a tuple with (time, freq, intensity)
        """
        return self.specgramHandler.getInfo(x, y)

    def graph(self, indexFrom=0, indexTo=-1, padding=0):

        indexTo = indexTo if (indexTo >= 0
                              and indexTo > indexFrom) else self.signal.length

        # avoid to set the max columns too high that the spectrogram cant be computed
        # and do not consume more resources that necessary
        # show at most as many columns as pixels in the widget's width
        max_columns = max(self.viewBox.width(), self.MAX_SPECGRAM_COLUMNS)

        self.specgramHandler.recomputeSpectrogram(indexFrom, indexTo,
                                                  max_columns)
        self.yAxis.frequencies = self.specgramHandler.freqs

        # set the new spectrogram image computed
        self.imageItem.setImage(self.specgramHandler.matriz)
        self.viewBox.setRange(
            xRange=(self.specgramHandler.from_osc_to_spec(indexFrom),
                    self.specgramHandler.from_osc_to_spec(indexTo - 1)),
            padding=padding)

        # update the histogram colors of the spectrogram
        self.histogram.item.region.lineMoved()
        self.histogram.item.region.lineMoveFinished()
        self.xAxis.setRange(indexFrom, indexTo)

        self.update()
Example #17
0
    def __init__(self,
                 image=None,
                 fillHistogram=True,
                 orientation='right',
                 gradients=None):
        """
        If *image* (ImageItem) is provided, then the control will be automatically linked to the image and changes to the control will be immediately reflected in the image's appearance.
        By default, the histogram is rendered with a fill. For performance, set *fillHistogram* = False.
        """
        GraphicsWidget.__init__(self)
        self.lut = None
        self.imageItem = lambda: None  # fake a dead weakref

        self.layout = QtGui.QGraphicsGridLayout()
        self.setLayout(self.layout)
        self.layout.setContentsMargins(1, 1, 1, 1)
        self.layout.setSpacing(0)
        self.vb = ViewBox(parent=self)

        if orientation in ['right', 'left']:
            self.vb.setMaximumWidth(150)
            self.vb.setMinimumWidth(15)
            self.vb.setMouseEnabled(x=False, y=True)
        elif orientation in ['bottom', 'top']:
            self.vb.setMaximumHeight(150)
            self.vb.setMinimumHeight(15)
            self.vb.setMouseEnabled(x=True, y=False)

        self.orientation = orientation
        orientationGEI = orientation
        if orientation == 'right':
            orientationLRI = 'horizontal'
            orientationAI = 'left'
        elif orientation == 'left':
            orientationLRI = 'horizontal'
            orientationAI = 'right'
        elif orientation == 'bottom':
            orientationLRI = 'vertical'
            orientationAI = 'top'
        elif orientation == 'top':
            orientationLRI = 'vertical'
            orientationAI = 'bottom'

        self.gradient = GradientEditorItem(gradients=gradients)
        self.gradient.setOrientation(orientationGEI)
        self.gradient.loadPreset('grey')
        self.region = LinearRegionItem([0, 1], orientation=orientationLRI)
        self.region.setZValue(1000)
        self.vb.addItem(self.region)
        self.axis = AxisItem(orientationAI,
                             linkView=self.vb,
                             maxTickLength=-10,
                             parent=self)

        if orientation == 'right':
            self.layout.addItem(self.axis, 0, 0)
            self.layout.addItem(self.vb, 0, 1)
            self.layout.addItem(self.gradient, 0, 2)
        elif orientation == 'left':
            self.layout.addItem(self.gradient, 0, 0)
            self.layout.addItem(self.vb, 0, 1)
            self.layout.addItem(self.axis, 0, 2)
        elif orientation == 'bottom':
            self.layout.addItem(self.axis, 0, 0)
            self.layout.addItem(self.vb, 1, 0)
            self.layout.addItem(self.gradient, 2, 0)
        elif orientation == 'top':
            self.layout.addItem(self.gradient, 0, 0)
            self.layout.addItem(self.vb, 1, 0)
            self.layout.addItem(self.axis, 2, 0)

        self.range = None
        self.gradient.setFlag(self.gradient.ItemStacksBehindParent)
        self.vb.setFlag(self.gradient.ItemStacksBehindParent)

        #self.grid = GridItem()
        #self.vb.addItem(self.grid)

        self.gradient.sigGradientChanged.connect(self.gradientChanged)
        self.region.sigRegionChanged.connect(self.regionChanging)
        self.region.sigRegionChangeFinished.connect(self.regionChanged)
        self.vb.sigRangeChanged.connect(self.viewRangeChanged)
        self.plot = PlotDataItem()
        self.plot.rotate(90)
        self.fillHistogram(fillHistogram)

        self.vb.addItem(self.plot)
        self.autoHistogramRange()

        if image is not None:
            self.setImageItem(image)
Example #18
0
 def __init__(self, graph, enable_menu=False):
     self.init_history()
     ViewBox.__init__(self, enableMenu=enable_menu)
     self.graph = graph
     self.setMouseMode(self.PanMode)
     self.grabGesture(Qt.PinchGesture)
Example #19
0
 def __init__(self, widget, *args, **kwargs):
     ViewBox.__init__(self, *args, **kwargs)
     self.widget = widget
 def getContextMenus(self, ev):
     ## called by scene to add menus on to someone else's context menu
     menu = self.widget.buildMenu(ev.scenePos())
     menu.setTitle("Add node")
     return [menu, ViewBox.getMenu(self, ev)]
 def __init__(self, widget, *args, **kwargs):
     ViewBox.__init__(self, *args, **kwargs)
     self.widget = widget
Example #22
0
 def clear(self):
   ViewBox.clear(self)
   self.image_item = ImageItem()
   self.addItem(self.image_item)
Example #23
0
class HistogramLUTItem(GraphicsWidget):
    """
    This is a graphicsWidget which provides controls for adjusting the display of an image.
    Includes:

    - Image histogram 
    - Movable region over histogram to select black/white levels
    - Gradient editor to define color lookup table for single-channel images
    """

    sigLookupTableChanged = QtCore.Signal(object)
    sigLevelsChanged = QtCore.Signal(object)
    sigLevelChangeFinished = QtCore.Signal(object)

    def __init__(self,
                 image=None,
                 fillHistogram=True,
                 orientation='right',
                 gradients=None):
        """
        If *image* (ImageItem) is provided, then the control will be automatically linked to the image and changes to the control will be immediately reflected in the image's appearance.
        By default, the histogram is rendered with a fill. For performance, set *fillHistogram* = False.
        """
        GraphicsWidget.__init__(self)
        self.lut = None
        self.imageItem = lambda: None  # fake a dead weakref

        self.layout = QtGui.QGraphicsGridLayout()
        self.setLayout(self.layout)
        self.layout.setContentsMargins(1, 1, 1, 1)
        self.layout.setSpacing(0)
        self.vb = ViewBox(parent=self)

        if orientation in ['right', 'left']:
            self.vb.setMaximumWidth(150)
            self.vb.setMinimumWidth(15)
            self.vb.setMouseEnabled(x=False, y=True)
        elif orientation in ['bottom', 'top']:
            self.vb.setMaximumHeight(150)
            self.vb.setMinimumHeight(15)
            self.vb.setMouseEnabled(x=True, y=False)

        self.orientation = orientation
        orientationGEI = orientation
        if orientation == 'right':
            orientationLRI = 'horizontal'
            orientationAI = 'left'
        elif orientation == 'left':
            orientationLRI = 'horizontal'
            orientationAI = 'right'
        elif orientation == 'bottom':
            orientationLRI = 'vertical'
            orientationAI = 'top'
        elif orientation == 'top':
            orientationLRI = 'vertical'
            orientationAI = 'bottom'

        self.gradient = GradientEditorItem(gradients=gradients)
        self.gradient.setOrientation(orientationGEI)
        self.gradient.loadPreset('grey')
        self.region = LinearRegionItem([0, 1], orientation=orientationLRI)
        self.region.setZValue(1000)
        self.vb.addItem(self.region)
        self.axis = AxisItem(orientationAI,
                             linkView=self.vb,
                             maxTickLength=-10,
                             parent=self)

        if orientation == 'right':
            self.layout.addItem(self.axis, 0, 0)
            self.layout.addItem(self.vb, 0, 1)
            self.layout.addItem(self.gradient, 0, 2)
        elif orientation == 'left':
            self.layout.addItem(self.gradient, 0, 0)
            self.layout.addItem(self.vb, 0, 1)
            self.layout.addItem(self.axis, 0, 2)
        elif orientation == 'bottom':
            self.layout.addItem(self.axis, 0, 0)
            self.layout.addItem(self.vb, 1, 0)
            self.layout.addItem(self.gradient, 2, 0)
        elif orientation == 'top':
            self.layout.addItem(self.gradient, 0, 0)
            self.layout.addItem(self.vb, 1, 0)
            self.layout.addItem(self.axis, 2, 0)

        self.range = None
        self.gradient.setFlag(self.gradient.ItemStacksBehindParent)
        self.vb.setFlag(self.gradient.ItemStacksBehindParent)

        #self.grid = GridItem()
        #self.vb.addItem(self.grid)

        self.gradient.sigGradientChanged.connect(self.gradientChanged)
        self.region.sigRegionChanged.connect(self.regionChanging)
        self.region.sigRegionChangeFinished.connect(self.regionChanged)
        self.vb.sigRangeChanged.connect(self.viewRangeChanged)
        self.plot = PlotDataItem()
        self.plot.rotate(90)
        self.fillHistogram(fillHistogram)

        self.vb.addItem(self.plot)
        self.autoHistogramRange()

        if image is not None:
            self.setImageItem(image)
        #self.setSizePolicy(QtGui.QSizePolicy.Preferred, QtGui.QSizePolicy.Expanding)

    def fillHistogram(self, fill=True, level=0.0, color=(100, 100, 200)):
        if fill:
            self.plot.setFillLevel(level)
            self.plot.setFillBrush(color)
        else:
            self.plot.setFillLevel(None)

    #def sizeHint(self, *args):
    #return QtCore.QSizeF(115, 200)

    def paint(self, p, *args):
        pen = self.region.lines[0].pen
        rgn = self.getLevels()
        if self.orientation == 'right':
            p1 = self.vb.mapFromViewToItem(
                self, Point(self.vb.viewRect().center().x(), rgn[0]))
            p2 = self.vb.mapFromViewToItem(
                self, Point(self.vb.viewRect().center().x(), rgn[1]))
            gradRect = self.gradient.mapRectToParent(
                self.gradient.gradRect.rect())
            for pen in [fn.mkPen('k', width=3), pen]:
                p.setPen(pen)
                p.drawLine(p1, gradRect.bottomLeft())
                p.drawLine(p2, gradRect.topLeft())
                p.drawLine(gradRect.topLeft(), gradRect.topRight())
                p.drawLine(gradRect.bottomLeft(), gradRect.bottomRight())
        elif self.orientation == 'left':
            p1 = self.vb.mapFromViewToItem(
                self, Point(self.vb.viewRect().center().x(), rgn[0]))
            p2 = self.vb.mapFromViewToItem(
                self, Point(self.vb.viewRect().center().x(), rgn[1]))
            gradRect = self.gradient.mapRectToParent(
                self.gradient.gradRect.rect())
            for pen in [fn.mkPen('k', width=3), pen]:
                p.setPen(pen)
                p.drawLine(p1, gradRect.bottomRight())
                p.drawLine(p2, gradRect.topRight())
                p.drawLine(gradRect.topLeft(), gradRect.topRight())
                p.drawLine(gradRect.bottomLeft(), gradRect.bottomRight())
        elif self.orientation == 'bottom':
            p1 = self.vb.mapFromViewToItem(
                self, Point(rgn[0],
                            self.vb.viewRect().center().y()))
            p2 = self.vb.mapFromViewToItem(
                self, Point(rgn[1],
                            self.vb.viewRect().center().y()))
            gradRect = self.gradient.mapRectToParent(
                self.gradient.gradRect.rect())
            for pen in [fn.mkPen('k', width=3), pen]:
                p.setPen(pen)
                p.drawLine(p1, gradRect.topLeft())
                p.drawLine(p2, gradRect.topRight())
                p.drawLine(gradRect.topLeft(), gradRect.bottomLeft())
                p.drawLine(gradRect.topRight(), gradRect.bottomRight())
        elif self.orientation == 'top':
            p1 = self.vb.mapFromViewToItem(
                self, Point(rgn[0],
                            self.vb.viewRect().center().y()))
            p2 = self.vb.mapFromViewToItem(
                self, Point(rgn[1],
                            self.vb.viewRect().center().y()))
            gradRect = self.gradient.mapRectToParent(
                self.gradient.gradRect.rect())
            for pen in [fn.mkPen('k', width=3), pen]:
                p.setPen(pen)
                p.drawLine(p1, gradRect.bottomLeft())
                p.drawLine(p2, gradRect.bottomRight())
                p.drawLine(gradRect.topLeft(), gradRect.bottomLeft())
                p.drawLine(gradRect.topRight(), gradRect.bottomRight())
        #p.drawRect(self.boundingRect())

    def setHistogramRange(self, mn, mx, padding=0.1):
        """Set the Y range on the histogram plot. This disables auto-scaling."""
        self.vb.enableAutoRange(self.vb.YAxis, False)
        self.vb.setYRange(mn, mx, padding)

        #d = mx-mn
        #mn -= d*padding
        #mx += d*padding
        #self.range = [mn,mx]
        #self.updateRange()
        #self.vb.setMouseEnabled(False, True)
        #self.region.setBounds([mn,mx])

    def autoHistogramRange(self):
        """Enable auto-scaling on the histogram plot."""
        self.vb.enableAutoRange(self.vb.XYAxes)
        #self.range = None
        #self.updateRange()
        #self.vb.setMouseEnabled(False, False)

    #def updateRange(self):
    #self.vb.autoRange()
    #if self.range is not None:
    #self.vb.setYRange(*self.range)
    #vr = self.vb.viewRect()

    #self.region.setBounds([vr.top(), vr.bottom()])

    def setImageItem(self, img):
        """Set an ImageItem to have its levels and LUT automatically controlled
        by this HistogramLUTItem.
        """
        self.imageItem = weakref.ref(img)
        img.sigImageChanged.connect(self.imageChanged)
        img.setLookupTable(
            self.getLookupTable)  ## send function pointer, not the result
        #self.gradientChanged()
        self.regionChanged()
        self.imageChanged(autoLevel=True)
        #self.vb.autoRange()

    def viewRangeChanged(self):
        self.update()

    def gradientChanged(self):
        if self.imageItem() is not None:
            if self.gradient.isLookupTrivial():
                self.imageItem().setLookupTable(
                    None)  #lambda x: x.astype(np.uint8))
            else:
                self.imageItem().setLookupTable(
                    self.getLookupTable
                )  ## send function pointer, not the result

        self.lut = None
        #if self.imageItem is not None:
        #self.imageItem.setLookupTable(self.gradient.getLookupTable(512))
        self.sigLookupTableChanged.emit(self)

    def getLookupTable(self, img=None, n=None, alpha=None):
        """Return a lookup table from the color gradient defined by this 
        HistogramLUTItem.
        """
        if n is None:
            if img.dtype == np.uint8:
                n = 256
            else:
                n = 512
        if self.lut is None:
            self.lut = self.gradient.getLookupTable(n, alpha=alpha)
        return self.lut

    def regionChanged(self):
        if self.imageItem() is not None:
            self.imageItem().setLevels(self.region.getRegion())
        self.sigLevelChangeFinished.emit(self)
        #self.update()

    def regionChanging(self):
        if self.imageItem() is not None:
            self.imageItem().setLevels(self.region.getRegion())
        self.sigLevelsChanged.emit(self)
        self.update()

    def imageChanged(self, autoLevel=False, autoRange=False):
        profiler = debug.Profiler()
        h = self.imageItem().getHistogram()
        profiler('get histogram')
        if h[0] is None:
            return
        self.plot.setData(*h)
        profiler('set plot')
        if autoLevel:
            mn = h[0][0]
            mx = h[0][-1]
            self.region.setRegion([mn, mx])
            profiler('set region')

    def getLevels(self):
        """Return the min and max levels.
        """
        return self.region.getRegion()

    def setLevels(self, mn, mx):
        """Set the min and max levels.
        """
        self.region.setRegion([mn, mx])
        self.update()