mouseEvents.py 13.9 KB
Newer Older
1 2
from ..Point import Point
from ..Qt import QtCore, QtGui
3
import weakref
4
from .. import ptime as ptime
5

6
class MouseDragEvent(object):
Luke Campagnola's avatar
Luke Campagnola committed
7 8 9 10 11 12 13
    """
    Instances of this class are delivered to items in a :class:`GraphicsScene <pyqtgraph.GraphicsScene>` via their mouseDragEvent() method when the item is being mouse-dragged. 
    
    """
    
    
    
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
    def __init__(self, moveEvent, pressEvent, lastEvent, start=False, finish=False):
        self.start = start
        self.finish = finish
        self.accepted = False
        self.currentItem = None
        self._buttonDownScenePos = {}
        self._buttonDownScreenPos = {}
        for btn in [QtCore.Qt.LeftButton, QtCore.Qt.MidButton, QtCore.Qt.RightButton]:
            self._buttonDownScenePos[int(btn)] = moveEvent.buttonDownScenePos(btn)
            self._buttonDownScreenPos[int(btn)] = moveEvent.buttonDownScreenPos(btn)
        self._scenePos = moveEvent.scenePos()
        self._screenPos = moveEvent.screenPos()
        if lastEvent is None:
            self._lastScenePos = pressEvent.scenePos()
            self._lastScreenPos = pressEvent.screenPos()
        else:
            self._lastScenePos = lastEvent.scenePos()
            self._lastScreenPos = lastEvent.screenPos()
        self._buttons = moveEvent.buttons()
        self._button = pressEvent.button()
        self._modifiers = moveEvent.modifiers()
Luke Campagnola's avatar
Luke Campagnola committed
35
        self.acceptedItem = None
36 37
        
    def accept(self):
Luke Campagnola's avatar
Luke Campagnola committed
38
        """An item should call this method if it can handle the event. This will prevent the event being delivered to any other items."""
39 40 41 42
        self.accepted = True
        self.acceptedItem = self.currentItem
        
    def ignore(self):
Luke Campagnola's avatar
Luke Campagnola committed
43
        """An item should call this method if it cannot handle the event. This will allow the event to be delivered to other items."""
44 45 46 47 48 49
        self.accepted = False
    
    def isAccepted(self):
        return self.accepted
    
    def scenePos(self):
Luke Campagnola's avatar
Luke Campagnola committed
50
        """Return the current scene position of the mouse."""
51 52 53
        return Point(self._scenePos)
    
    def screenPos(self):
Luke Campagnola's avatar
Luke Campagnola committed
54
        """Return the current screen position (pixels relative to widget) of the mouse."""
55 56 57
        return Point(self._screenPos)
    
    def buttonDownScenePos(self, btn=None):
Luke Campagnola's avatar
Luke Campagnola committed
58 59 60 61
        """
        Return the scene position of the mouse at the time *btn* was pressed.
        If *btn* is omitted, then the button that initiated the drag is assumed.
        """
62 63 64 65 66
        if btn is None:
            btn = self.button()
        return Point(self._buttonDownScenePos[int(btn)])
    
    def buttonDownScreenPos(self, btn=None):
Luke Campagnola's avatar
Luke Campagnola committed
67 68 69 70
        """
        Return the screen position (pixels relative to widget) of the mouse at the time *btn* was pressed.
        If *btn* is omitted, then the button that initiated the drag is assumed.
        """
71 72 73 74 75
        if btn is None:
            btn = self.button()
        return Point(self._buttonDownScreenPos[int(btn)])
    
    def lastScenePos(self):
Luke Campagnola's avatar
Luke Campagnola committed
76 77 78
        """
        Return the scene position of the mouse immediately prior to this event.
        """
79 80 81
        return Point(self._lastScenePos)
    
    def lastScreenPos(self):
Luke Campagnola's avatar
Luke Campagnola committed
82 83 84
        """
        Return the screen position of the mouse immediately prior to this event.
        """
85 86 87
        return Point(self._lastScreenPos)
    
    def buttons(self):
Luke Campagnola's avatar
Luke Campagnola committed
88 89 90 91
        """
        Return the buttons currently pressed on the mouse.
        (see QGraphicsSceneMouseEvent::buttons in the Qt documentation)
        """
92 93 94
        return self._buttons
        
    def button(self):
Luke Campagnola's avatar
Luke Campagnola committed
95 96 97 98
        """Return the button that initiated the drag (may be different from the buttons currently pressed)
        (see QGraphicsSceneMouseEvent::button in the Qt documentation)
        
        """
99 100 101
        return self._button
        
    def pos(self):
Luke Campagnola's avatar
Luke Campagnola committed
102 103 104 105
        """
        Return the current position of the mouse in the coordinate system of the item
        that the event was delivered to.
        """
106 107 108
        return Point(self.currentItem.mapFromScene(self._scenePos))
    
    def lastPos(self):
Luke Campagnola's avatar
Luke Campagnola committed
109 110 111 112
        """
        Return the previous position of the mouse in the coordinate system of the item
        that the event was delivered to.
        """
113 114 115
        return Point(self.currentItem.mapFromScene(self._lastScenePos))
        
    def buttonDownPos(self, btn=None):
Luke Campagnola's avatar
Luke Campagnola committed
116 117 118 119
        """
        Return the position of the mouse at the time the drag was initiated
        in the coordinate system of the item that the event was delivered to.
        """
120 121 122 123 124
        if btn is None:
            btn = self.button()
        return Point(self.currentItem.mapFromScene(self._buttonDownScenePos[int(btn)]))
    
    def isStart(self):
Luke Campagnola's avatar
Luke Campagnola committed
125
        """Returns True if this event is the first since a drag was initiated."""
126 127 128
        return self.start
        
    def isFinish(self):
Luke Campagnola's avatar
Luke Campagnola committed
129 130
        """Returns False if this is the last event in a drag. Note that this
        event will have the same position as the previous one."""
131 132 133
        return self.finish

    def __repr__(self):
Luke Campagnola's avatar
Luke Campagnola committed
134 135 136 137 138 139
        if self.currentItem is None:
            lp = self._lastScenePos
            p = self._scenePos
        else:
            lp = self.lastPos()
            p = self.pos()
140 141 142
        return "<MouseDragEvent (%g,%g)->(%g,%g) buttons=%d start=%s finish=%s>" % (lp.x(), lp.y(), p.x(), p.y(), int(self.buttons()), str(self.isStart()), str(self.isFinish()))
        
    def modifiers(self):
Luke Campagnola's avatar
Luke Campagnola committed
143 144 145 146
        """Return any keyboard modifiers currently pressed.
        (see QGraphicsSceneMouseEvent::modifiers in the Qt documentation)
        
        """
147 148 149 150
        return self._modifiers



151
class MouseClickEvent(object):
Luke Campagnola's avatar
Luke Campagnola committed
152 153 154 155 156 157
    """
    Instances of this class are delivered to items in a :class:`GraphicsScene <pyqtgraph.GraphicsScene>` via their mouseClickEvent() method when the item is clicked. 
    
    
    """
    
158 159 160 161 162 163 164 165 166 167
    def __init__(self, pressEvent, double=False):
        self.accepted = False
        self.currentItem = None
        self._double = double
        self._scenePos = pressEvent.scenePos()
        self._screenPos = pressEvent.screenPos()
        self._button = pressEvent.button()
        self._buttons = pressEvent.buttons()
        self._modifiers = pressEvent.modifiers()
        self._time = ptime.time()
Luke Campagnola's avatar
Luke Campagnola committed
168
        self.acceptedItem = None
169 170
        
    def accept(self):
Luke Campagnola's avatar
Luke Campagnola committed
171
        """An item should call this method if it can handle the event. This will prevent the event being delivered to any other items."""
172 173 174 175
        self.accepted = True
        self.acceptedItem = self.currentItem
        
    def ignore(self):
Luke Campagnola's avatar
Luke Campagnola committed
176
        """An item should call this method if it cannot handle the event. This will allow the event to be delivered to other items."""
177 178 179 180 181 182
        self.accepted = False
    
    def isAccepted(self):
        return self.accepted
    
    def scenePos(self):
Luke Campagnola's avatar
Luke Campagnola committed
183
        """Return the current scene position of the mouse."""
184 185 186
        return Point(self._scenePos)
    
    def screenPos(self):
Luke Campagnola's avatar
Luke Campagnola committed
187
        """Return the current screen position (pixels relative to widget) of the mouse."""
188 189 190
        return Point(self._screenPos)
    
    def buttons(self):
Luke Campagnola's avatar
Luke Campagnola committed
191 192 193 194
        """
        Return the buttons currently pressed on the mouse.
        (see QGraphicsSceneMouseEvent::buttons in the Qt documentation)
        """
195 196 197
        return self._buttons
    
    def button(self):
Luke Campagnola's avatar
Luke Campagnola committed
198 199 200
        """Return the mouse button that generated the click event.
        (see QGraphicsSceneMouseEvent::button in the Qt documentation)
        """
201 202 203
        return self._button
    
    def double(self):
Luke Campagnola's avatar
Luke Campagnola committed
204
        """Return True if this is a double-click."""
205 206 207
        return self._double

    def pos(self):
Luke Campagnola's avatar
Luke Campagnola committed
208 209 210 211
        """
        Return the current position of the mouse in the coordinate system of the item
        that the event was delivered to.
        """
212 213 214
        return Point(self.currentItem.mapFromScene(self._scenePos))
    
    def lastPos(self):
Luke Campagnola's avatar
Luke Campagnola committed
215 216 217 218
        """
        Return the previous position of the mouse in the coordinate system of the item
        that the event was delivered to.
        """
219 220 221
        return Point(self.currentItem.mapFromScene(self._lastScenePos))
        
    def modifiers(self):
Luke Campagnola's avatar
Luke Campagnola committed
222 223 224
        """Return any keyboard modifiers currently pressed.
        (see QGraphicsSceneMouseEvent::modifiers in the Qt documentation)        
        """
225 226 227
        return self._modifiers

    def __repr__(self):
228
        try:
Luke Campagnola's avatar
Luke Campagnola committed
229 230 231 232
            if self.currentItem is None:
                p = self._scenePos
            else:
                p = self.pos()
233 234 235 236
            return "<MouseClickEvent (%g,%g) button=%d>" % (p.x(), p.y(), int(self.button()))
        except:
            return "<MouseClickEvent button=%d>" % (int(self.button()))

237 238 239 240 241
    def time(self):
        return self._time



242
class HoverEvent(object):
243
    """
Luke Campagnola's avatar
Luke Campagnola committed
244
    Instances of this class are delivered to items in a :class:`GraphicsScene <pyqtgraph.GraphicsScene>` via their hoverEvent() method when the mouse is hovering over the item.
245
    This event class both informs items that the mouse cursor is nearby and allows items to 
Luke Campagnola's avatar
Luke Campagnola committed
246
    communicate with one another about whether each item will accept *potential* mouse events. 
247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282
    
    It is common for multiple overlapping items to receive hover events and respond by changing 
    their appearance. This can be misleading to the user since, in general, only one item will
    respond to mouse events. To avoid this, items make calls to event.acceptClicks(button) 
    and/or acceptDrags(button).
    
    Each item may make multiple calls to acceptClicks/Drags, each time for a different button. 
    If the method returns True, then the item is guaranteed to be
    the recipient of the claimed event IF the user presses the specified mouse button before
    moving. If claimEvent returns False, then this item is guaranteed NOT to get the specified
    event (because another has already claimed it) and the item should change its appearance 
    accordingly.
    
    event.isEnter() returns True if the mouse has just entered the item's shape;
    event.isExit() returns True if the mouse has just left.
    """
    def __init__(self, moveEvent, acceptable):
        self.enter = False
        self.acceptable = acceptable
        self.exit = False
        self.__clickItems = weakref.WeakValueDictionary()
        self.__dragItems = weakref.WeakValueDictionary()
        self.currentItem = None
        if moveEvent is not None:
            self._scenePos = moveEvent.scenePos()
            self._screenPos = moveEvent.screenPos()
            self._lastScenePos = moveEvent.lastScenePos()
            self._lastScreenPos = moveEvent.lastScreenPos()
            self._buttons = moveEvent.buttons()
            self._modifiers = moveEvent.modifiers()
        else:
            self.exit = True
            
        
        
    def isEnter(self):
Luke Campagnola's avatar
Luke Campagnola committed
283
        """Returns True if the mouse has just entered the item's shape"""
284 285 286
        return self.enter
        
    def isExit(self):
Luke Campagnola's avatar
Luke Campagnola committed
287
        """Returns True if the mouse has just exited the item's shape"""
288 289 290
        return self.exit
        
    def acceptClicks(self, button):
Luke Campagnola's avatar
Luke Campagnola committed
291 292 293 294 295 296 297
        """Inform the scene that the item (that the event was delivered to)
        would accept a mouse click event if the user were to click before
        moving the mouse again.
        
        Returns True if the request is successful, otherwise returns False (indicating
        that some other item would receive an incoming click).
        """
298 299 300 301 302 303 304 305
        if not self.acceptable:
            return False
        if button not in self.__clickItems:
            self.__clickItems[button] = self.currentItem
            return True
        return False
        
    def acceptDrags(self, button):
Luke Campagnola's avatar
Luke Campagnola committed
306 307 308 309 310 311 312
        """Inform the scene that the item (that the event was delivered to)
        would accept a mouse drag event if the user were to drag before
        the next hover event.
        
        Returns True if the request is successful, otherwise returns False (indicating
        that some other item would receive an incoming drag event).
        """
313 314 315 316 317 318 319 320
        if not self.acceptable:
            return False
        if button not in self.__dragItems:
            self.__dragItems[button] = self.currentItem
            return True
        return False
        
    def scenePos(self):
Luke Campagnola's avatar
Luke Campagnola committed
321
        """Return the current scene position of the mouse."""
322 323 324
        return Point(self._scenePos)
    
    def screenPos(self):
Luke Campagnola's avatar
Luke Campagnola committed
325
        """Return the current screen position of the mouse."""
326 327 328
        return Point(self._screenPos)
    
    def lastScenePos(self):
Luke Campagnola's avatar
Luke Campagnola committed
329
        """Return the previous scene position of the mouse."""
330 331 332
        return Point(self._lastScenePos)
    
    def lastScreenPos(self):
Luke Campagnola's avatar
Luke Campagnola committed
333
        """Return the previous screen position of the mouse."""
334 335 336
        return Point(self._lastScreenPos)
    
    def buttons(self):
Luke Campagnola's avatar
Luke Campagnola committed
337 338 339 340
        """
        Return the buttons currently pressed on the mouse.
        (see QGraphicsSceneMouseEvent::buttons in the Qt documentation)
        """
341 342 343
        return self._buttons
        
    def pos(self):
Luke Campagnola's avatar
Luke Campagnola committed
344 345 346 347
        """
        Return the current position of the mouse in the coordinate system of the item
        that the event was delivered to.
        """
348 349 350
        return Point(self.currentItem.mapFromScene(self._scenePos))
    
    def lastPos(self):
Luke Campagnola's avatar
Luke Campagnola committed
351 352 353 354
        """
        Return the previous position of the mouse in the coordinate system of the item
        that the event was delivered to.
        """
355 356 357
        return Point(self.currentItem.mapFromScene(self._lastScenePos))

    def __repr__(self):
358 359 360
        if self.exit:
            return "<HoverEvent exit=True>"
        
Luke Campagnola's avatar
Luke Campagnola committed
361 362 363 364 365 366
        if self.currentItem is None:
            lp = self._lastScenePos
            p = self._scenePos
        else:
            lp = self.lastPos()
            p = self.pos()
367 368 369
        return "<HoverEvent (%g,%g)->(%g,%g) buttons=%d enter=%s exit=%s>" % (lp.x(), lp.y(), p.x(), p.y(), int(self.buttons()), str(self.isEnter()), str(self.isExit()))
        
    def modifiers(self):
Luke Campagnola's avatar
Luke Campagnola committed
370 371 372
        """Return any keyboard modifiers currently pressed.
        (see QGraphicsSceneMouseEvent::modifiers in the Qt documentation)        
        """
373 374 375 376 377 378 379 380 381 382
        return self._modifiers
    
    def clickItems(self):
        return self.__clickItems
        
    def dragItems(self):
        return self.__dragItems