butterfly_viewer.aux_trackers
Trackers and signalers for SplitView.
Not intended as a script. Used in Butterfly Viewer and Registrator.
Creates widgets to track and signal events in SplitView, primarily for mouse movement.
1#!/usr/bin/env python3 2 3"""Trackers and signalers for SplitView. 4 5Not intended as a script. Used in Butterfly Viewer and Registrator. 6 7Creates widgets to track and signal events in SplitView, primarily for mouse movement. 8""" 9# SPDX-License-Identifier: GPL-3.0-or-later 10 11 12 13from PyQt5 import QtCore, QtGui 14 15 16 17class EventTracker(QtCore.QObject): 18 """Track and signal mouse movement and clicks. 19 20 Args: 21 widget (QWidget or child class thereof): Widget of which to track and signal mouse events. 22 """ 23 24 mouse_position_changed = QtCore.pyqtSignal(QtCore.QPoint) 25 mouse_leaved = QtCore.pyqtSignal() 26 mouse_entered = QtCore.pyqtSignal() 27 28 def __init__(self, widget): 29 super().__init__(widget) 30 self._widget = widget 31 self.widget.setMouseTracking(True) 32 self.widget.installEventFilter(self) 33 34 @property 35 def widget(self): 36 return self._widget 37 38 def eventFilter(self, source, event): 39 if source is self.widget and event.type() == QtCore.QEvent.MouseMove: 40 self.mouse_position_changed.emit(event.pos()) 41 if source is self.widget and event.type() == QtCore.QEvent.Leave: 42 self.mouse_leaved.emit() 43 if source is self.widget and event.type() == QtCore.QEvent.Enter: 44 self.mouse_entered.emit() 45 return super().eventFilter(source, event) 46 47 48 49class EventTrackerSplitBypassDeadzone(QtCore.QObject): 50 """Limit the reported global position of the mouse to within a widget's bounds. 51 52 This class is intended to help track mouse movement in the deadzones along the SplitView's borders. 53 These deadzones fix the issue of resize handles appearing in QMdiArea; however, 54 these deadzones hide the mouse from the view, so the mouse must be separately tracked 55 to ensure the split is updated. 56 The mouse position is bounded to include only positions within the widget to fix issues with positions 57 reported as outside the bounds. 58 59 Args: 60 widget (QWidget or child class thereof): Widget of which to track and signal mouse events (intended to be the resize_deadzone in SplitView). 61 """ 62 63 def __init__(self, widget): 64 super().__init__(widget) 65 self._widget = widget 66 self.widget.setMouseTracking(True) 67 self.widget.installEventFilter(self) 68 69 mouse_position_changed_global = QtCore.pyqtSignal(QtCore.QPoint) 70 71 @property 72 def widget(self): 73 return self._widget 74 75 def width(self): 76 return self.widget.width() 77 78 def height(self): 79 return self.widget.height() 80 81 def eventFilter(self, source, event): 82 """Override eventFilter to limit the reported position of mouse movement. 83 84 Args: 85 source (PyQt source) 86 event (PyQt event) 87 88 Returns: 89 The base eventFilter using source and event (passes it along to PyQt). 90 """ 91 pos = QtGui.QCursor.pos() 92 if event.type() == QtCore.QEvent.MouseMove: 93 pos = self.limit_mouse_position_to_within_widget_bounds(pos) # Prevent erroneous mouse tracking outside the widget 94 self.mouse_position_changed_global.emit(pos) 95 96 return super().eventFilter(source, event) 97 98 99 def limit_mouse_position_to_within_widget_bounds(self, pos): 100 """Return a given global mouse position which is limited to within the widget's borders. 101 102 Args: 103 pos (QPoint): The position of the mouse in global coordinates. 104 105 Returns: 106 pos_global_bounded (QPoint): The position of the mouse in global coordinates limited ("floored") to within the widget borders. 107 """ 108 pos_global = pos 109 pos_widget = self.widget.mapFromGlobal(pos_global) 110 x_bounded = max(min(pos_widget.x(), self.width()), 0) 111 y_bounded = max(min(pos_widget.y(), self.height()), 0) 112 pos_widget.setX(x_bounded) 113 pos_widget.setY(y_bounded) 114 pos_global_bounded = self.widget.mapToGlobal(pos_widget) 115 return pos_global_bounded 116 117 118 119class EventTrackerSplitBypassInterface(QtCore.QObject): 120 """Track mouse events while over widgets (for example, interface elements). 121 122 Needed to track the split of the sliding overlay while mouse is hovering over interface widgets. 123 Prevents the split from skipping and stopping when entering and exiting interface elements. 124 125 Args: 126 widget (QWidget or child class thereof): The widget over which to track mouse movement. 127 """ 128 129 mouse_position_changed = QtCore.pyqtSignal() 130 propagate_mouse_press_event = QtCore.pyqtSignal(QtCore.QEvent) 131 132 def __init__(self, widget): 133 super().__init__(widget) 134 self._widget = widget 135 self.widget.setMouseTracking(True) 136 self.widget.installEventFilter(self) 137 138 @property 139 def widget(self): 140 return self._widget 141 142 def eventFilter(self, source, event): 143 """"Override event filter to emit mouse movement and button press events. 144 145 See parent method for full documentation. 146 147 Args: 148 source (PyQt source) 149 event (PyQt event) 150 151 Returns: 152 The base eventFilter using source and event (passes it along to PyQt). 153 """ 154 if event.type() == QtCore.QEvent.MouseMove: 155 self.mouse_position_changed.emit() # Emits position when mouse moves 156 if event.type() == QtCore.QEvent.MouseButtonPress: 157 self.propagate_mouse_press_event.emit(event) 158 return super().eventFilter(source, event)
18class EventTracker(QtCore.QObject): 19 """Track and signal mouse movement and clicks. 20 21 Args: 22 widget (QWidget or child class thereof): Widget of which to track and signal mouse events. 23 """ 24 25 mouse_position_changed = QtCore.pyqtSignal(QtCore.QPoint) 26 mouse_leaved = QtCore.pyqtSignal() 27 mouse_entered = QtCore.pyqtSignal() 28 29 def __init__(self, widget): 30 super().__init__(widget) 31 self._widget = widget 32 self.widget.setMouseTracking(True) 33 self.widget.installEventFilter(self) 34 35 @property 36 def widget(self): 37 return self._widget 38 39 def eventFilter(self, source, event): 40 if source is self.widget and event.type() == QtCore.QEvent.MouseMove: 41 self.mouse_position_changed.emit(event.pos()) 42 if source is self.widget and event.type() == QtCore.QEvent.Leave: 43 self.mouse_leaved.emit() 44 if source is self.widget and event.type() == QtCore.QEvent.Enter: 45 self.mouse_entered.emit() 46 return super().eventFilter(source, event)
Track and signal mouse movement and clicks.
Arguments:
- widget (QWidget or child class thereof): Widget of which to track and signal mouse events.
39 def eventFilter(self, source, event): 40 if source is self.widget and event.type() == QtCore.QEvent.MouseMove: 41 self.mouse_position_changed.emit(event.pos()) 42 if source is self.widget and event.type() == QtCore.QEvent.Leave: 43 self.mouse_leaved.emit() 44 if source is self.widget and event.type() == QtCore.QEvent.Enter: 45 self.mouse_entered.emit() 46 return super().eventFilter(source, event)
eventFilter(self, QObject, QEvent) -> bool
50class EventTrackerSplitBypassDeadzone(QtCore.QObject): 51 """Limit the reported global position of the mouse to within a widget's bounds. 52 53 This class is intended to help track mouse movement in the deadzones along the SplitView's borders. 54 These deadzones fix the issue of resize handles appearing in QMdiArea; however, 55 these deadzones hide the mouse from the view, so the mouse must be separately tracked 56 to ensure the split is updated. 57 The mouse position is bounded to include only positions within the widget to fix issues with positions 58 reported as outside the bounds. 59 60 Args: 61 widget (QWidget or child class thereof): Widget of which to track and signal mouse events (intended to be the resize_deadzone in SplitView). 62 """ 63 64 def __init__(self, widget): 65 super().__init__(widget) 66 self._widget = widget 67 self.widget.setMouseTracking(True) 68 self.widget.installEventFilter(self) 69 70 mouse_position_changed_global = QtCore.pyqtSignal(QtCore.QPoint) 71 72 @property 73 def widget(self): 74 return self._widget 75 76 def width(self): 77 return self.widget.width() 78 79 def height(self): 80 return self.widget.height() 81 82 def eventFilter(self, source, event): 83 """Override eventFilter to limit the reported position of mouse movement. 84 85 Args: 86 source (PyQt source) 87 event (PyQt event) 88 89 Returns: 90 The base eventFilter using source and event (passes it along to PyQt). 91 """ 92 pos = QtGui.QCursor.pos() 93 if event.type() == QtCore.QEvent.MouseMove: 94 pos = self.limit_mouse_position_to_within_widget_bounds(pos) # Prevent erroneous mouse tracking outside the widget 95 self.mouse_position_changed_global.emit(pos) 96 97 return super().eventFilter(source, event) 98 99 100 def limit_mouse_position_to_within_widget_bounds(self, pos): 101 """Return a given global mouse position which is limited to within the widget's borders. 102 103 Args: 104 pos (QPoint): The position of the mouse in global coordinates. 105 106 Returns: 107 pos_global_bounded (QPoint): The position of the mouse in global coordinates limited ("floored") to within the widget borders. 108 """ 109 pos_global = pos 110 pos_widget = self.widget.mapFromGlobal(pos_global) 111 x_bounded = max(min(pos_widget.x(), self.width()), 0) 112 y_bounded = max(min(pos_widget.y(), self.height()), 0) 113 pos_widget.setX(x_bounded) 114 pos_widget.setY(y_bounded) 115 pos_global_bounded = self.widget.mapToGlobal(pos_widget) 116 return pos_global_bounded
Limit the reported global position of the mouse to within a widget's bounds.
This class is intended to help track mouse movement in the deadzones along the SplitView's borders. These deadzones fix the issue of resize handles appearing in QMdiArea; however, these deadzones hide the mouse from the view, so the mouse must be separately tracked to ensure the split is updated. The mouse position is bounded to include only positions within the widget to fix issues with positions reported as outside the bounds.
Arguments:
- widget (QWidget or child class thereof): Widget of which to track and signal mouse events (intended to be the resize_deadzone in SplitView).
82 def eventFilter(self, source, event): 83 """Override eventFilter to limit the reported position of mouse movement. 84 85 Args: 86 source (PyQt source) 87 event (PyQt event) 88 89 Returns: 90 The base eventFilter using source and event (passes it along to PyQt). 91 """ 92 pos = QtGui.QCursor.pos() 93 if event.type() == QtCore.QEvent.MouseMove: 94 pos = self.limit_mouse_position_to_within_widget_bounds(pos) # Prevent erroneous mouse tracking outside the widget 95 self.mouse_position_changed_global.emit(pos) 96 97 return super().eventFilter(source, event)
Override eventFilter to limit the reported position of mouse movement.
Arguments:
- source (PyQt source)
- event (PyQt event)
Returns:
- The base eventFilter using source and event (passes it along to PyQt).
100 def limit_mouse_position_to_within_widget_bounds(self, pos): 101 """Return a given global mouse position which is limited to within the widget's borders. 102 103 Args: 104 pos (QPoint): The position of the mouse in global coordinates. 105 106 Returns: 107 pos_global_bounded (QPoint): The position of the mouse in global coordinates limited ("floored") to within the widget borders. 108 """ 109 pos_global = pos 110 pos_widget = self.widget.mapFromGlobal(pos_global) 111 x_bounded = max(min(pos_widget.x(), self.width()), 0) 112 y_bounded = max(min(pos_widget.y(), self.height()), 0) 113 pos_widget.setX(x_bounded) 114 pos_widget.setY(y_bounded) 115 pos_global_bounded = self.widget.mapToGlobal(pos_widget) 116 return pos_global_bounded
Return a given global mouse position which is limited to within the widget's borders.
Arguments:
- pos (QPoint): The position of the mouse in global coordinates.
Returns:
- pos_global_bounded (QPoint): The position of the mouse in global coordinates limited ("floored") to within the widget borders.
120class EventTrackerSplitBypassInterface(QtCore.QObject): 121 """Track mouse events while over widgets (for example, interface elements). 122 123 Needed to track the split of the sliding overlay while mouse is hovering over interface widgets. 124 Prevents the split from skipping and stopping when entering and exiting interface elements. 125 126 Args: 127 widget (QWidget or child class thereof): The widget over which to track mouse movement. 128 """ 129 130 mouse_position_changed = QtCore.pyqtSignal() 131 propagate_mouse_press_event = QtCore.pyqtSignal(QtCore.QEvent) 132 133 def __init__(self, widget): 134 super().__init__(widget) 135 self._widget = widget 136 self.widget.setMouseTracking(True) 137 self.widget.installEventFilter(self) 138 139 @property 140 def widget(self): 141 return self._widget 142 143 def eventFilter(self, source, event): 144 """"Override event filter to emit mouse movement and button press events. 145 146 See parent method for full documentation. 147 148 Args: 149 source (PyQt source) 150 event (PyQt event) 151 152 Returns: 153 The base eventFilter using source and event (passes it along to PyQt). 154 """ 155 if event.type() == QtCore.QEvent.MouseMove: 156 self.mouse_position_changed.emit() # Emits position when mouse moves 157 if event.type() == QtCore.QEvent.MouseButtonPress: 158 self.propagate_mouse_press_event.emit(event) 159 return super().eventFilter(source, event)
Track mouse events while over widgets (for example, interface elements).
Needed to track the split of the sliding overlay while mouse is hovering over interface widgets. Prevents the split from skipping and stopping when entering and exiting interface elements.
Arguments:
- widget (QWidget or child class thereof): The widget over which to track mouse movement.
143 def eventFilter(self, source, event): 144 """"Override event filter to emit mouse movement and button press events. 145 146 See parent method for full documentation. 147 148 Args: 149 source (PyQt source) 150 event (PyQt event) 151 152 Returns: 153 The base eventFilter using source and event (passes it along to PyQt). 154 """ 155 if event.type() == QtCore.QEvent.MouseMove: 156 self.mouse_position_changed.emit() # Emits position when mouse moves 157 if event.type() == QtCore.QEvent.MouseButtonPress: 158 self.propagate_mouse_press_event.emit(event) 159 return super().eventFilter(source, event)
"Override event filter to emit mouse movement and button press events.
See parent method for full documentation.
Arguments:
- source (PyQt source)
- event (PyQt event)
Returns:
- The base eventFilter using source and event (passes it along to PyQt).