diff options
Diffstat (limited to 'silx/gui/plot/PlotInteraction.py')
-rw-r--r-- | silx/gui/plot/PlotInteraction.py | 208 |
1 files changed, 91 insertions, 117 deletions
diff --git a/silx/gui/plot/PlotInteraction.py b/silx/gui/plot/PlotInteraction.py index 27abd10..abfcf79 100644 --- a/silx/gui/plot/PlotInteraction.py +++ b/silx/gui/plot/PlotInteraction.py @@ -1,7 +1,7 @@ # coding: utf-8 # /*########################################################################## # -# Copyright (c) 2014-2018 European Synchrotron Radiation Facility +# Copyright (c) 2014-2019 European Synchrotron Radiation Facility # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal @@ -1079,7 +1079,10 @@ class ItemsInteraction(ClickOrDrag, _PlotInteraction): applyZoomToPlot(self.machine.plot, scaleF, (x, y)) def onMove(self, x, y): - marker = self.machine.plot._pickMarker(x, y) + result = self.machine.plot._pickTopMost( + x, y, lambda item: isinstance(item, items.MarkerBase)) + marker = result.getItem() if result is not None else None + if marker is not None: dataPos = self.machine.plot.pixelToData(x, y) assert dataPos is not None @@ -1151,10 +1154,14 @@ class ItemsInteraction(ClickOrDrag, _PlotInteraction): """ if btn == LEFT_BTN: - marker = self.plot._pickMarker( - x, y, lambda m: m.isSelectable()) - if marker is not None: - xData, yData = marker.getPosition() + result = self.plot._pickTopMost(x, y, lambda i: i.isSelectable()) + if result is None: + return None + + item = result.getItem() + + if isinstance(item, items.MarkerBase): + xData, yData = item.getPosition() if xData is None: xData = [0, 1] if yData is None: @@ -1162,58 +1169,44 @@ class ItemsInteraction(ClickOrDrag, _PlotInteraction): eventDict = prepareMarkerSignal('markerClicked', 'left', - marker.getLegend(), + item.getLegend(), 'marker', - marker.isDraggable(), - marker.isSelectable(), + item.isDraggable(), + item.isSelectable(), (xData, yData), (x, y), None) return eventDict - else: - picked = self.plot._pickImageOrCurve( - x, y, lambda item: item.isSelectable()) - - if picked is None: - pass - - elif picked[0] == 'curve': - curve = picked[1] - indices = picked[2] - - dataPos = self.plot.pixelToData(x, y) - assert dataPos is not None - - xData = curve.getXData(copy=False) - yData = curve.getYData(copy=False) - - eventDict = prepareCurveSignal('left', - curve.getLegend(), - 'curve', - xData[indices], - yData[indices], - dataPos[0], dataPos[1], - x, y) - return eventDict - - elif picked[0] == 'image': - image = picked[1] - - dataPos = self.plot.pixelToData(x, y) - assert dataPos is not None - - # Get corresponding coordinate in image - origin = image.getOrigin() - scale = image.getScale() - column = int((dataPos[0] - origin[0]) / float(scale[0])) - row = int((dataPos[1] - origin[1]) / float(scale[1])) - eventDict = prepareImageSignal('left', - image.getLegend(), - 'image', - column, row, - dataPos[0], dataPos[1], - x, y) - return eventDict + elif isinstance(item, items.Curve): + dataPos = self.plot.pixelToData(x, y) + assert dataPos is not None + + xData = item.getXData(copy=False) + yData = item.getYData(copy=False) + + indices = result.getIndices(copy=False) + eventDict = prepareCurveSignal('left', + item.getLegend(), + 'curve', + xData[indices], + yData[indices], + dataPos[0], dataPos[1], + x, y) + return eventDict + + elif isinstance(item, items.ImageBase): + dataPos = self.plot.pixelToData(x, y) + assert dataPos is not None + + indices = result.getIndices(copy=False) + row, column = indices[0][0], indices[1][0] + eventDict = prepareImageSignal('left', + item.getLegend(), + 'image', + column, row, + dataPos[0], dataPos[1], + x, y) + return eventDict return None @@ -1240,6 +1233,15 @@ class ItemsInteraction(ClickOrDrag, _PlotInteraction): posDataCursor) self.plot.notify(**eventDict) + @staticmethod + def __isDraggableItem(item): + return isinstance(item, items.DraggableMixIn) and item.isDraggable() + + def __terminateDrag(self): + """Finalize a drag operation by reseting to initial state""" + self.plot.setGraphCursorShape() + self.draggedItemRef = None + def beginDrag(self, x, y): """Handle begining of drag interaction @@ -1250,78 +1252,56 @@ class ItemsInteraction(ClickOrDrag, _PlotInteraction): self._lastPos = self.plot.pixelToData(x, y) assert self._lastPos is not None - self.imageLegend = None - self.markerLegend = None - marker = self.plot._pickMarker( - x, y, lambda m: m.isDraggable()) + result = self.plot._pickTopMost(x, y, self.__isDraggableItem) + item = result.getItem() if result is not None else None + + self.draggedItemRef = None if item is None else weakref.ref(item) + + if item is None: + self.__terminateDrag() + return False + + if isinstance(item, items.MarkerBase): + self._signalMarkerMovingEvent('markerMoving', item, x, y) - if marker is not None: - self.markerLegend = marker.getLegend() - self._signalMarkerMovingEvent('markerMoving', marker, x, y) - else: - picked = self.plot._pickImageOrCurve( - x, - y, - lambda item: - hasattr(item, 'isDraggable') and item.isDraggable()) - if picked is None: - self.imageLegend = None - self.plot.setGraphCursorShape() - return False - else: - assert picked[0] == 'image' # For now only drag images - self.imageLegend = picked[1].getLegend() return True def drag(self, x, y): dataPos = self.plot.pixelToData(x, y) assert dataPos is not None - xData, yData = dataPos - if self.markerLegend is not None: - marker = self.plot._getMarker(self.markerLegend) - if marker is not None: - marker.setPosition(xData, yData) + item = None if self.draggedItemRef is None else self.draggedItemRef() + if item is not None: + item.drag(self._lastPos, dataPos) - self._signalMarkerMovingEvent( - 'markerMoving', marker, x, y) + if isinstance(item, items.MarkerBase): + self._signalMarkerMovingEvent('markerMoving', item, x, y) - if self.imageLegend is not None: - image = self.plot.getImage(self.imageLegend) - origin = image.getOrigin() - xImage = origin[0] + xData - self._lastPos[0] - yImage = origin[1] + yData - self._lastPos[1] - image.setOrigin((xImage, yImage)) - - self._lastPos = xData, yData + self._lastPos = dataPos def endDrag(self, startPos, endPos): - if self.markerLegend is not None: - marker = self.plot._getMarker(self.markerLegend) - posData = list(marker.getPosition()) + item = None if self.draggedItemRef is None else self.draggedItemRef() + if item is not None and isinstance(item, items.MarkerBase): + posData = list(item.getPosition()) if posData[0] is None: - posData[0] = [0, 1] + posData[0] = 1. if posData[1] is None: - posData[1] = [0, 1] + posData[1] = 1. eventDict = prepareMarkerSignal( 'markerMoved', 'left', - marker.getLegend(), + item.getLegend(), 'marker', - marker.isDraggable(), - marker.isSelectable(), + item.isDraggable(), + item.isSelectable(), posData) self.plot.notify(**eventDict) - self.plot.setGraphCursorShape() - - del self.markerLegend - del self.imageLegend - del self._lastPos + self.__terminateDrag() def cancel(self): - self.plot.setGraphCursorShape() + self.__terminateDrag() class ItemsInteractionForCombo(ItemsInteraction): @@ -1329,22 +1309,16 @@ class ItemsInteractionForCombo(ItemsInteraction): """ class Idle(ItemsInteraction.Idle): + @staticmethod + def __isItemSelectableOrDraggable(item): + return (item.isSelectable() or ( + isinstance(item, items.DraggableMixIn) and item.isDraggable())) + def onPress(self, x, y, btn): if btn == LEFT_BTN: - def test(item): - return (item.isSelectable() or - (isinstance(item, items.DraggableMixIn) and - item.isDraggable())) - - picked = self.machine.plot._pickMarker(x, y, test) - if picked is not None: - itemInteraction = True - - else: - picked = self.machine.plot._pickImageOrCurve(x, y, test) - itemInteraction = picked is not None - - if itemInteraction: # Request focus and handle interaction + result = self.machine.plot._pickTopMost( + x, y, self.__isItemSelectableOrDraggable) + if result is not None: # Request focus and handle interaction self.goto('clickOrDrag', x, y) return True else: # Do not request focus @@ -1658,7 +1632,7 @@ class PlotInteraction(object): plot = self._plot() assert plot is not None - if color not in (None, 'video inverted'): + if isinstance(color, numpy.ndarray) or color not in (None, 'video inverted'): color = colors.rgba(color) if mode in ('draw', 'select-draw'): |