class InteractiveGRWidget(GRWidget): logXinDomain = QtCore.Signal(bool) logYinDomain = QtCore.Signal(bool) modePick = QtCore.Signal(bool) GESTURE_RECOGNIZERS = [PanGestureRecognizer, SelectGestureRecognizer] def __init__(self, *args, **kwargs): super(InteractiveGRWidget, self).__init__(*args, **kwargs) self._recognizers = [] # register gesture recognizers for recognizer in self.GESTURE_RECOGNIZERS: instance = recognizer() self.grabGesture(recognizer.registerRecognizer(instance)) # keep a reference on existing QGestureRecognizers in order # to circumvent that they will be accidentially freed when # using PyQt4 versions which will not handle the membership # correctly, e.g. PyQt4 4.9.1 shipped with Ubuntu 12.04. self._recognizers.append(instance) self._eventFilter = installEventFilter(self) self._eventFilterEnabled = True self.cbm.addHandler(MouseEvent.MOUSE_MOVE, self.mouseMove) self.cbm.addHandler(MouseEvent.MOUSE_PRESS, self.mousePress) self.cbm.addHandler(MouseEvent.MOUSE_RELEASE, self.mouseRelease) self.cbm.addHandler(WheelEvent.WHEEL_MOVE, self.wheelMove) self.cbm.addHandler(PickEvent.PICK_MOVE, self.pickMove) self.cbm.addHandler(MouseGestureEvent.MOUSE_PAN, self._mousePan) self.cbm.addHandler(MouseGestureEvent.MOUSE_SELECT, self._mouseSelect) self.setMouseTracking(True) self._tselect = None # select point tuple self._logXinDomain = None self._logYinDomain = None self._pickMode = False self._pickEvent = None self._selectEnabled, self._panEnabled = True, True self._roiEnabled = True self._zoomEnabled = True self._lstPlot = [] def draw(self, clear=None, update=None): # obsolete kwargs clear, update (unused) just kept for compatibility GRWidget.draw(self, clear, update) gr.setwsviewport(0, self.mwidth, 0, self.mheight) gr.setwswindow(0, self.sizex, 0, self.sizey) for plot in self._lstPlot: plot.sizex, plot.sizey = self.sizex, self.sizey plot.drawGR() # logDomainCheck logXinDomain = plot.logXinDomain() logYinDomain = plot.logYinDomain() if logXinDomain != self._logXinDomain: self._logXinDomain = logXinDomain self.logXinDomain.emit(self._logXinDomain) if logYinDomain != self._logYinDomain: self._logYinDomain = logYinDomain self.logYinDomain.emit(self._logYinDomain) if self._pickEvent: event = self._pickEvent gr.setviewport(*event.viewportscaled) wcPoint = event.getWC(event.viewport) window = gr.inqwindow() gr.setwindow(*event.getWindow()) gr.setmarkertype(gr.MARKERTYPE_PLUS) gr.polymarker([wcPoint.x], [wcPoint.y]) gr.setwindow(*window) def addPlot(self, *args, **kwargs): for plot in args: if plot and plot not in self._lstPlot: self._lstPlot.append(plot) self.update() return self._lstPlot @property def cbm(self): """Get CallbackManager used by EventFilter""" return self._eventFilter.manager def setEventFilterEnabled(self, flag): """Dis-/Enable QtGR events""" if self._eventFilterEnabled: if not flag: self.removeEventFilter(self._eventFilter) elif flag: self.installEventFilter(self._eventFilter) self._eventFilterEnabled = flag def plot(self, *args, **kwargs): plot = Plot() axes = PlotAxes(plot.viewport) axes.plot(*args, **kwargs) plot.addAxes(axes) return self.addPlot(plot) def adjustSelectRect(self, p0, p1): # can be used to restrict select rectangle, e.g. to given aspect ratio return p0, p1 def paintEvent(self, event): super(InteractiveGRWidget, self).paintEvent(event) self._painter.begin(self) if self.getMouseSelectionEnabled() and self._tselect: p0, p1 = self._tselect coords = DeviceCoordConverter(self.dwidth, self.dheight) coords.setNDC(p0.x, p0.y) p0dc = coords.getDC() coords.setNDC(p1.x, p1.y) p1dc = coords.getDC() if self._getPlotsForPoint(p0): rect = QtCore.QRect(QtCore.QPoint(p0dc.x, p0dc.y), QtCore.QPoint(p1dc.x, p1dc.y)).normalized() self._painter.setOpacity(.75) self._painter.drawRect(rect) self._painter.setOpacity(1.) self._painter.end() def setAutoScale(self, mask): for plot in self._lstPlot: plot.autoscale = mask def getPickMode(self): return self._pickMode def setPickMode(self, bool): self._pickMode = bool self.modePick.emit(self._pickMode) def getMouseSelectionEnabled(self): return self._selectEnabled def setMouseSelectionEnabled(self, flag): self._selectEnabled = flag def getMousePanEnabled(self): return self._panEnabled def setMousePanEnabled(self, flag): self._panEnabled = flag def getMouseZoomEnabled(self): return self._zoomEnabled def setMouseZoomEnabled(self, flag): self._zoomEnabled = flag def _getPlotsForPoint(self, p0): res = [] for plot in self._lstPlot: xmin, xmax, ymin, ymax = plot.viewportscaled if p0.x >= xmin and p0.x <= xmax and p0.y >= ymin and p0.y <= ymax: res.append(plot) return res def _pick(self, p0, type): for plot in self._getPlotsForPoint(p0): (coord, axes, _curve) = plot.pick(p0, self.dwidth, self.dheight) if coord: dcPoint = coord.getDC() QApplication.sendEvent(self, PickEvent(type, self.dwidth, self.dheight, dcPoint.x, dcPoint.y, plot.viewport, coord.getWindow(), sizex=axes.sizex, sizey=axes.sizey)) def _select(self, p0, p1): self._pickEvent = None change = False for plot in self._getPlotsForPoint(p0): plot.select(p0, p1, self.dwidth, self.dheight) change = True if change: self.update() def mouseSelect(self, event): p0 = event.getNDC() p0, p1 = self.adjustSelectRect(p0, p0 + event.getOffset()) self._tselect = (p0, p1) if event.isFinished(): self._tselect = None self._select(p0, p1) self.update() def _mouseSelect(self, event): if self.getMouseSelectionEnabled(): self.mouseSelect(event) def _pan(self, p0, dp): self._pickEvent = None change = False for plot in self._getPlotsForPoint(p0): plot.pan(dp, self.dwidth, self.dheight) change = True if change: self.update() def mousePan(self, event): self._pan(event.getNDC(), event.getOffset()) def _mousePan(self, event): if self.getMousePanEnabled(): self.mousePan(event) # disable roi recognition during pannning self._roiEnabled = event.isFinished() def _zoom(self, dpercent, p0): self._pickEvent = None change = False for plot in self._getPlotsForPoint(p0): plot.zoom(dpercent, p0, self.dwidth, self.dheight) change = True if change: self.update() def _roi(self, p0, type, buttons, modifiers): if self._roiEnabled: for plot in self._lstPlot: roi = plot.getROI(p0) if roi: if roi.regionType == RegionOfInterest.LEGEND: eventObj = LegendEvent else: eventObj = ROIEvent coords = DeviceCoordConverter(self.dwidth, self.dheight) coords.setNDC(p0.x, p0.y) p0dc = coords.getDC() QApplication.sendEvent(self, eventObj(type, self.dwidth, self.dheight, p0dc.x, p0dc.y, buttons, modifiers, roi)) def mousePress(self, event): if event.getButtons() & MouseEvent.LEFT_BUTTON: if self.getPickMode(): self.setPickMode(False) self._pick(event.getNDC(), PickEvent.PICK_PRESS) else: if event.getModifiers() & MouseEvent.CONTROL_MODIFIER: self.setPickMode(True) def mouseRelease(self, event): self._roi(event.getNDC(), ROIEvent.ROI_CLICKED, event.getButtons(), event.getModifiers()) def mouseMove(self, event): if self.getPickMode(): self._pick(event.getNDC(), PickEvent.PICK_MOVE) self._roi(event.getNDC(), ROIEvent.ROI_OVER, event.getButtons(), event.getModifiers()) def wheelMove(self, event): if self.getMouseZoomEnabled(): # delta percent dpercent = event.getSteps() * .1 self._zoom(dpercent, event.getNDC()) def pickMove(self, event): self._pickEvent = event self.update()
class InteractiveGRWidget(GRWidget): logXinDomain = QtCore.Signal(bool) logYinDomain = QtCore.Signal(bool) modePick = QtCore.Signal(bool) def __init__(self, *args, **kwargs): super(InteractiveGRWidget, self).__init__(*args, **kwargs) guiConn = GUIConnector(self) guiConn.connect(qtgr.events.MouseEvent.MOUSE_MOVE, self.mouseMove) guiConn.connect(qtgr.events.MouseEvent.MOUSE_PRESS, self.mousePress) guiConn.connect(qtgr.events.MouseEvent.MOUSE_RELEASE, self.mouseRelease) guiConn.connect(qtgr.events.WheelEvent.WHEEL_MOVE, self.wheelMove) guiConn.connect(qtgr.events.PickEvent.PICK_MOVE, self.pickMove) self.setMouseTracking(True) self._mouseLeft = False self._mouseRight = False self._startPoint = None self._curPoint = None self._logXinDomain = None self._logYinDomain = None self._pickMode = False self._pickEvent = None self._selectEnabled, self._panEnabled = True, True self._zoomEnabled = True self._lstPlot = [] def draw(self, clear=False, update=True): if clear: gr.clearws() gr.setwsviewport(0, self.mwidth, 0, self.mheight) gr.setwswindow(0, self.sizex, 0, self.sizey) for plot in self._lstPlot: plot.sizex, plot.sizey = self.sizex, self.sizey plot.drawGR() # logDomainCheck logXinDomain = plot.logXinDomain() logYinDomain = plot.logYinDomain() if logXinDomain != self._logXinDomain: self._logXinDomain = logXinDomain self.logXinDomain.emit(self._logXinDomain) if logYinDomain != self._logYinDomain: self._logYinDomain = logYinDomain self.logYinDomain.emit(self._logYinDomain) if self._pickEvent: event = self._pickEvent gr.setviewport(*event.viewport) wcPoint = event.getWC(event.viewport) window = gr.inqwindow() gr.setwindow(*event.getWindow()) gr.setmarkertype(gr.MARKERTYPE_PLUS) gr.polymarker([wcPoint.x], [wcPoint.y]) gr.setwindow(*window) def addPlot(self, *args, **kwargs): for plot in args: if plot and plot not in self._lstPlot: self._lstPlot.append(plot) self._draw(clear=True, update=True) return self._lstPlot def plot(self, *args, **kwargs): plot = Plot() axes = PlotAxes(plot.viewport) axes.plot(*args, **kwargs) plot.addAxes(axes) return self.addPlot(plot) def adjustSelectRect(self, p0, p1): # can be used to restrict select rectangle, e.g. to given aspect ratio return p0, p1 def paintEvent(self, event): super(InteractiveGRWidget, self).paintEvent(event) self._painter.begin(self) if self._mouseLeft and self.getMouseSelectionEnabled(): p0 = self._startPoint.getNDC() p1 = self._curPoint.getNDC() p0, p1 = self.adjustSelectRect(p0, p1) coords = DeviceCoordConverter(self.dwidth, self.dheight) coords.setNDC(p0.x, p0.y) p0dc = coords.getDC() coords.setNDC(p1.x, p1.y) p1dc = coords.getDC() if self._getPlotsForPoint(p0): rect = QtCore.QRect(QtCore.QPoint(p0dc.x, p0dc.y), QtCore.QPoint(p1dc.x, p1dc.y)).normalized() self._painter.setOpacity(.75) self._painter.drawRect(rect) self._painter.setOpacity(1.) self._painter.end() def setAutoScale(self, mask): for plot in self._lstPlot: plot.autoscale = mask def getPickMode(self): return self._pickMode def setPickMode(self, bool): self._pickMode = bool self.modePick.emit(self._pickMode) def getMouseSelectionEnabled(self): return self._selectEnabled def setMouseSelectionEnabled(self, flag): self._selectEnabled = flag def getMousePanEnabled(self): return self._panEnabled def setMousePanEnabled(self, flag): self._panEnabled = flag def getMouseZoomEnabled(self): return self._zoomEnabled def setMouseZoomEnabled(self, flag): self._zoomEnabled = flag def _getPlotsForPoint(self, p0): res = [] for plot in self._lstPlot: xmin, xmax, ymin, ymax = plot.viewportscaled if p0.x >= xmin and p0.x <= xmax and p0.y >= ymin and p0.y <= ymax: res.append(plot) return res def _pick(self, p0, type): for plot in self._getPlotsForPoint(p0): (coord, _axes, _curve) = plot.pick(p0, self.dwidth, self.dheight) if coord: dcPoint = coord.getDC() QtGui.QApplication.sendEvent( self, PickEvent(type, self.dwidth, self.dheight, dcPoint.x, dcPoint.y, plot.viewport, coord.getWindow())) def _select(self, p0, p1): self._pickEvent = None change = False for plot in self._getPlotsForPoint(p0): plot.select(p0, p1, self.dwidth, self.dheight) change = True if change: self._draw(True) self.update() def _pan(self, p0, dp): self._pickEvent = None change = False for plot in self._getPlotsForPoint(p0): plot.pan(dp, self.dwidth, self.dheight) change = True if change: self._draw(True) self.update() def _zoom(self, dpercent, p0): self._pickEvent = None change = False for plot in self._getPlotsForPoint(p0): plot.zoom(dpercent, p0, self.dwidth, self.dheight) change = True if change: self._draw(True) self.update() def _roi(self, p0, type, buttons, modifiers): for plot in self._lstPlot: roi = plot.getROI(p0) if roi: if roi.regionType == RegionOfInterest.LEGEND: eventObj = LegendEvent else: eventObj = ROIEvent coords = DeviceCoordConverter(self.dwidth, self.dheight) coords.setNDC(p0.x, p0.y) p0dc = coords.getDC() QtGui.QApplication.sendEvent( self, eventObj(type, self.dwidth, self.dheight, p0dc.x, p0dc.y, buttons, modifiers, roi)) def mousePress(self, event): if event.getButtons() & MouseEvent.LEFT_BUTTON: if self.getPickMode(): self.setPickMode(False) self._pick(event.getNDC(), PickEvent.PICK_PRESS) else: if event.getModifiers() & MouseEvent.CONTROL_MODIFIER: self.setPickMode(True) else: self._mouseLeft = True elif event.getButtons() & MouseEvent.RIGHT_BUTTON: self._mouseRight = True self._curPoint = event self._startPoint = event def mouseRelease(self, event): if event.getButtons() & MouseEvent.LEFT_BUTTON and self._mouseLeft: self._mouseLeft = False self._curPoint = event p0 = self._startPoint.getNDC() p1 = self._curPoint.getNDC() if p0 != p1: if (self.getMouseSelectionEnabled() and self._getPlotsForPoint(p0)): p0, p1 = self.adjustSelectRect(p0, p1) self._select(p0, p1) else: self._roi(p0, ROIEvent.ROI_CLICKED, event.getButtons(), event.getModifiers()) elif event.getButtons() & MouseEvent.RIGHT_BUTTON and self._mouseRight: self._mouseRight = False self._roi(event.getNDC(), ROIEvent.ROI_CLICKED, event.getButtons(), event.getModifiers()) self._curPoint = event def mouseMove(self, event): if self.getPickMode(): self._pick(event.getNDC(), PickEvent.PICK_MOVE) if event.getButtons() & MouseEvent.LEFT_BUTTON: self._curPoint = event super(InteractiveGRWidget, self).update() elif event.getButtons() & MouseEvent.RIGHT_BUTTON: p0 = self._curPoint.getNDC() # point before now p1 = event.getNDC() dp = p1 - p0 self._curPoint = event if self.getMousePanEnabled(): self._pan(self._startPoint.getNDC(), dp) self._mouseRight = False self._roi(event.getNDC(), ROIEvent.ROI_OVER, event.getButtons(), event.getModifiers()) def wheelMove(self, event): if self.getMouseZoomEnabled(): # delta percent dpercent = event.getSteps() * .1 self._zoom(dpercent, event.getNDC()) def pickMove(self, event): self._pickEvent = event self.update()