diff --git a/beeref/items.py b/beeref/items.py index 31a67cc..207184b 100644 --- a/beeref/items.py +++ b/beeref/items.py @@ -435,13 +435,13 @@ class BeePixmapItem(BeeItemMixin, QtWidgets.QGraphicsPixmapItem): for handle in self.crop_handles(): if handle().contains(event.pos()): - self.setCursor(self.get_crop_handle_cursor(handle)) + self.set_cursor(self.get_crop_handle_cursor(handle)) return for edge in self.crop_edges(): if edge().contains(event.pos()): - self.setCursor(self.get_crop_edge_cursor(edge)) + self.set_cursor(self.get_crop_edge_cursor(edge)) return - self.setCursor(Qt.CursorShape.ArrowCursor) + self.unset_cursor() def mousePressEvent(self, event): if not self.crop_mode: diff --git a/beeref/main_controls.py b/beeref/main_controls.py index fbaccc6..4ab1ef5 100644 --- a/beeref/main_controls.py +++ b/beeref/main_controls.py @@ -49,10 +49,17 @@ class MainControlsMixin: else: self.enter_movewin_mode() + @property + def viewport_or_self(self): + if hasattr(self, 'viewport'): + return self.viewport() + return self + def enter_movewin_mode(self): logger.debug('Entering movewin mode') self.setMouseTracking(True) self.movewin_active = True + self.viewport_or_self.setCursor(Qt.CursorShape.SizeAllCursor) self.event_start = QtCore.QPointF(self.cursor().pos()) if hasattr(self, 'disable_mouse_events'): self.disable_mouse_events() @@ -61,6 +68,7 @@ class MainControlsMixin: logger.debug('Exiting movewin mode') self.setMouseTracking(False) self.movewin_active = False + self.viewport_or_self.unsetCursor() if hasattr(self, 'enable_mouse_events'): self.enable_mouse_events() diff --git a/beeref/scene.py b/beeref/scene.py index 167b9fd..3fde06b 100644 --- a/beeref/scene.py +++ b/beeref/scene.py @@ -32,6 +32,8 @@ logger = logging.getLogger(__name__) class BeeGraphicsScene(QtWidgets.QGraphicsScene): + cursor_changed = QtCore.pyqtSignal(QtGui.QCursor) + cursor_cleared = QtCore.pyqtSignal() def __init__(self, undo_stack): super().__init__() diff --git a/beeref/selection.py b/beeref/selection.py index fc39875..b39417e 100644 --- a/beeref/selection.py +++ b/beeref/selection.py @@ -118,6 +118,15 @@ class BaseItemMixin: """The item's center in scene coordinates.""" return self.mapToScene(self.center) + def set_cursor(self, cursor): + self.scene().cursor_changed.emit(cursor) + + def unset_cursor(self): + self.scene().cursor_cleared.emit() + + def hoverLeaveEvent(self, event): + self.unset_cursor() + class SelectableMixin(BaseItemMixin): """Common code for selectable items: Selection outline, handles etc.""" @@ -363,31 +372,32 @@ class SelectableMixin(BaseItemMixin): # This area should always trigger regular move operations, # even if it is covered by selection scale/flip/... handles. # This ensures that small items can always still be moved/edited. - self.setCursor(Qt.CursorShape.ArrowCursor) + self.unset_cursor() return for corner in self.corners: # See if we need to change the cursor for interactable areas if self.get_scale_bounds(corner).contains(event.pos()): - self.setCursor(self.get_corner_scale_cursor(corner)) + self.scene().cursor_changed.emit(self.get_corner_scale_cursor(corner)) + self.set_cursor(self.get_corner_scale_cursor(corner)) return elif self.get_rotate_bounds(corner).contains(event.pos()): - self.setCursor(BeeAssets().cursor_rotate) + self.set_cursor(BeeAssets().cursor_rotate) return for edge in self.get_flip_bounds(): if edge['rect'].contains(event.pos()): if self.get_edge_flips_v(edge): - self.setCursor(BeeAssets().cursor_flip_v) + self.set_cursor(BeeAssets().cursor_flip_v) else: - self.setCursor(BeeAssets().cursor_flip_h) + self.set_cursor(BeeAssets().cursor_flip_h) return - self.setCursor(Qt.CursorShape.ArrowCursor) + self.unset_cursor() def hoverEnterEvent(self, event): - # Always return regular cursor when there aren't any selection handles + # Always set regular cursor when there aren't any selection handles if not self.has_selection_handles(): - self.setCursor(Qt.CursorShape.ArrowCursor) + self.unset_cursor() def mousePressEvent(self, event): self.event_start = event.scenePos() diff --git a/beeref/view.py b/beeref/view.py index 9b05072..b4697e8 100644 --- a/beeref/view.py +++ b/beeref/view.py @@ -68,6 +68,8 @@ class BeeGraphicsView(MainControlsMixin, self.scene = BeeGraphicsScene(self.undo_stack) self.scene.changed.connect(self.on_scene_changed) self.scene.selectionChanged.connect(self.on_selection_changed) + self.scene.cursor_changed.connect(self.on_cursor_changed) + self.scene.cursor_cleared.connect(self.on_cursor_cleared) self.setScene(self.scene) # Context menu and actions @@ -603,6 +605,16 @@ class BeeGraphicsView(MainControlsMixin, self.scene.has_single_image_selection()) self.viewport().repaint() + def on_cursor_changed(self, cursor): + print('set', cursor.shape()) + if not self.pan_active: + self.viewport().setCursor(cursor) + + def on_cursor_cleared(self): + print('unset') + if not self.pan_active: + self.viewport().unsetCursor() + def recalc_scene_rect(self): """Resize the scene rectangle so that it is always one view width wider than all items' bounding box at each side and one view @@ -716,8 +728,10 @@ class BeeGraphicsView(MainControlsMixin, if (event.button() == Qt.MouseButton.MiddleButton or (event.button() == Qt.MouseButton.LeftButton and event.modifiers() == Qt.KeyboardModifier.AltModifier)): + logger.debug('Begin pan') self.pan_active = True self.event_start = event.position() + self.viewport().setCursor(Qt.CursorShape.ClosedHandCursor) self.setCursor(Qt.CursorShape.ClosedHandCursor) event.accept() return @@ -748,7 +762,8 @@ class BeeGraphicsView(MainControlsMixin, def mouseReleaseEvent(self, event): if self.pan_active: - self.setCursor(Qt.CursorShape.ArrowCursor) + logger.debug('End pan') + self.viewport().unsetCursor() self.pan_active = False event.accept() return