mirror of
https://github.com/rbreu/beeref.git
synced 2026-03-11 08:54:28 +00:00
Fix scale handle cursor shapes for rotated items
This commit is contained in:
parent
a34231cd7d
commit
829d0d19fc
3 changed files with 59 additions and 39 deletions
|
|
@ -229,15 +229,20 @@ class SelectableMixin(BaseItemMixin):
|
|||
return
|
||||
|
||||
for corner in self.corners:
|
||||
# See if we need to change the cursor for scale areas
|
||||
# See if we need to change the cursor for interactable areas
|
||||
if self.get_scale_bounds(corner).contains(event.pos()):
|
||||
direction = self.get_corner_direction(corner)
|
||||
if direction.x() == direction.y():
|
||||
self.event_anchor = self.center_scene_coords
|
||||
angle = self.get_rotate_angle(self.mapToScene(corner))
|
||||
if abs(angle) >= 157.5 or abs(angle) <= 22.5:
|
||||
self.setCursor(Qt.CursorShape.SizeVerCursor)
|
||||
elif 112.5 <= angle <= 157.5 or -67.5 <= angle <= -22.5:
|
||||
self.setCursor(Qt.CursorShape.SizeFDiagCursor)
|
||||
elif 67.5 <= abs(angle) <= 112.5:
|
||||
self.setCursor(Qt.CursorShape.SizeHorCursor)
|
||||
else:
|
||||
self.setCursor(Qt.CursorShape.SizeBDiagCursor)
|
||||
return
|
||||
if self.get_rotate_bounds(corner).contains(event.pos()):
|
||||
elif self.get_rotate_bounds(corner).contains(event.pos()):
|
||||
self.setCursor(BeeAssets().cursor_rotate)
|
||||
return
|
||||
|
||||
|
|
@ -257,11 +262,10 @@ class SelectableMixin(BaseItemMixin):
|
|||
# Start scale action for this corner
|
||||
self.scale_active = True
|
||||
self.event_start = event.scenePos()
|
||||
self.event_direction = self.get_mouse_event_direction(
|
||||
event)
|
||||
self.event_direction = self.get_direction_from_center(
|
||||
event.scenePos())
|
||||
self.event_anchor = self.mapToScene(
|
||||
self.get_scale_anchor(corner))
|
||||
self.scale_direction = self.get_corner_direction(corner)
|
||||
for item in self.selection_action_items():
|
||||
item.scale_orig_factor = item.scale()
|
||||
event.accept()
|
||||
|
|
@ -271,7 +275,8 @@ class SelectableMixin(BaseItemMixin):
|
|||
# Start rotate action
|
||||
self.rotate_active = True
|
||||
self.event_anchor = self.center_scene_coords
|
||||
self.rotate_start_angle = self.get_rotate_angle(event)
|
||||
self.rotate_start_angle = self.get_rotate_angle(
|
||||
event.scenePos())
|
||||
for item in self.selection_action_items():
|
||||
item.rotate_orig_degrees = item.rotation()
|
||||
event.accept()
|
||||
|
|
@ -298,23 +303,21 @@ class SelectableMixin(BaseItemMixin):
|
|||
return QtCore.QPointF(1 if corner.x() > 0 else -1,
|
||||
1 if corner.y() > 0 else -1)
|
||||
|
||||
def get_mouse_event_direction(self, event):
|
||||
"""The direction of a mouse event in relation to the item's center.
|
||||
"""
|
||||
diff = event.scenePos() - self.center_scene_coords
|
||||
def get_direction_from_center(self, pos):
|
||||
"""The direction of a point in relation to the item's center."""
|
||||
diff = pos - self.center_scene_coords
|
||||
length = math.sqrt(QtCore.QPointF.dotProduct(diff, diff))
|
||||
return diff / length
|
||||
|
||||
def get_rotate_angle(self, event):
|
||||
"""Get the angle of the current mouse position towards the
|
||||
scale center."""
|
||||
def get_rotate_angle(self, pos):
|
||||
"""Get the angle of the given position towards the event anchor."""
|
||||
|
||||
diff = event.scenePos() - self.event_anchor
|
||||
diff = pos - self.event_anchor
|
||||
return -math.degrees(math.atan2(diff.x(), diff.y()))
|
||||
|
||||
def get_rotate_delta(self, event):
|
||||
def get_rotate_delta(self, pos):
|
||||
"""Get the rotate delta for the current mouse movement"""
|
||||
return self.get_rotate_angle(event) - self.rotate_start_angle
|
||||
return self.get_rotate_angle(pos) - self.rotate_start_angle
|
||||
|
||||
def mouseMoveEvent(self, event):
|
||||
if self.scale_active:
|
||||
|
|
@ -324,7 +327,7 @@ class SelectableMixin(BaseItemMixin):
|
|||
item.mapFromScene(self.event_anchor))
|
||||
event.accept()
|
||||
elif self.rotate_active:
|
||||
delta = self.get_rotate_delta(event)
|
||||
delta = self.get_rotate_delta(event.scenePos())
|
||||
for item in self.selection_action_items():
|
||||
item.setRotation(item.rotate_orig_degrees + delta,
|
||||
item.mapFromScene(self.event_anchor))
|
||||
|
|
@ -346,7 +349,7 @@ class SelectableMixin(BaseItemMixin):
|
|||
self.scene().undo_stack.push(
|
||||
commands.RotateItemsBy(
|
||||
self.selection_action_items(),
|
||||
self.get_rotate_delta(event),
|
||||
self.get_rotate_delta(event.scenePos()),
|
||||
self.event_anchor,
|
||||
ignore_first_redo=True))
|
||||
self.rotate_active = False
|
||||
|
|
|
|||
|
|
@ -352,7 +352,7 @@ class BeeGraphicsView(QtWidgets.QGraphicsView):
|
|||
self.scene.clearSelection()
|
||||
item = BeePixmapItem(img)
|
||||
pos = self.mapToScene(self.mapFromGlobal(self.cursor().pos()))
|
||||
item.set_pos_center(pos.x(), pos.y())
|
||||
item.set_pos_center(pos)
|
||||
self.undo_stack.push(commands.InsertItems(self.scene, [item]))
|
||||
|
||||
def on_selection_changed(self):
|
||||
|
|
|
|||
|
|
@ -398,37 +398,30 @@ class SelectableMixinScalingTestCase(SelectableMixinBaseTestCase):
|
|||
assert self.item.get_corner_direction(
|
||||
QtCore.QPointF(0, 80)) == QtCore.QPointF(-1, 1)
|
||||
|
||||
def test_get_mouse_event_direction_bottomright(self):
|
||||
event = MagicMock()
|
||||
event.scenePos = MagicMock(return_value=QtCore.QPointF(100, 90))
|
||||
direction = self.item.get_mouse_event_direction(event)
|
||||
def test_get_direction_from_center_bottomright(self):
|
||||
direction = self.item.get_direction_from_center(
|
||||
QtCore.QPointF(100, 90))
|
||||
assert direction == approx(QtCore.QPointF(1, 1) / math.sqrt(2))
|
||||
|
||||
def test_get_mouse_event_direction_topleft(self):
|
||||
event = MagicMock()
|
||||
event.scenePos = MagicMock(return_value=QtCore.QPointF(0, -10))
|
||||
direction = self.item.get_mouse_event_direction(event)
|
||||
def test_get_direction_from_center_topleft(self):
|
||||
direction = self.item.get_direction_from_center(
|
||||
QtCore.QPointF(0, -10))
|
||||
assert direction == approx(QtCore.QPointF(-1, -1) / math.sqrt(2))
|
||||
|
||||
def test_get_mouse_event_direction_bottomright_when_rotated_180(self):
|
||||
def test_get_direction_from_center_bottomright_when_rotated_180(self):
|
||||
self.item.setRotation(180, QtCore.QPointF(50, 40))
|
||||
event = MagicMock()
|
||||
event.scenePos = MagicMock(return_value=QtCore.QPointF(100, 90))
|
||||
direction = self.item.get_mouse_event_direction(event)
|
||||
direction = self.item.get_direction_from_center(
|
||||
QtCore.QPointF(100, 90))
|
||||
assert direction == approx(QtCore.QPointF(1, 1) / math.sqrt(2))
|
||||
|
||||
def test_get_rotate_angle(self):
|
||||
self.item.event_anchor = QtCore.QPointF(10, 20)
|
||||
event = MagicMock()
|
||||
event.scenePos = MagicMock(return_value=QtCore.QPointF(15, 25))
|
||||
assert self.item.get_rotate_angle(event) == -45
|
||||
assert self.item.get_rotate_angle(QtCore.QPointF(15, 25)) == -45
|
||||
|
||||
def test_get_rotate_delta(self):
|
||||
self.item.event_anchor = QtCore.QPointF(10, 20)
|
||||
self.item.rotate_start_angle = -3
|
||||
event = MagicMock()
|
||||
event.scenePos = MagicMock(return_value=QtCore.QPointF(15, 25))
|
||||
assert self.item.get_rotate_delta(event) == -42
|
||||
assert self.item.get_rotate_delta(QtCore.QPointF(15, 25)) == -42
|
||||
|
||||
|
||||
class SelectableMixinMouseEventsTestCase(SelectableMixinBaseTestCase):
|
||||
|
|
@ -466,6 +459,30 @@ class SelectableMixinMouseEventsTestCase(SelectableMixinBaseTestCase):
|
|||
self.item.setCursor.assert_called_once_with(
|
||||
Qt.CursorShape.SizeBDiagCursor)
|
||||
|
||||
def test_hover_move_event_topright_scale_rotated_90(self):
|
||||
self.item.setRotation(90)
|
||||
self.item.setSelected(True)
|
||||
self.event.pos = MagicMock(return_value=QtCore.QPointF(0, 0))
|
||||
self.item.hoverMoveEvent(self.event)
|
||||
self.item.setCursor.assert_called_once_with(
|
||||
Qt.CursorShape.SizeBDiagCursor)
|
||||
|
||||
def test_hover_move_event_top_scale_rotated_45(self):
|
||||
self.item.setRotation(45)
|
||||
self.item.setSelected(True)
|
||||
self.event.pos = MagicMock(return_value=QtCore.QPointF(0, 0))
|
||||
self.item.hoverMoveEvent(self.event)
|
||||
self.item.setCursor.assert_called_once_with(
|
||||
Qt.CursorShape.SizeVerCursor)
|
||||
|
||||
def test_hover_move_event_left_scale_rotated_45(self):
|
||||
self.item.setRotation(45)
|
||||
self.item.setSelected(True)
|
||||
self.event.pos = MagicMock(return_value=QtCore.QPointF(0, 80))
|
||||
self.item.hoverMoveEvent(self.event)
|
||||
self.item.setCursor.assert_called_once_with(
|
||||
Qt.CursorShape.SizeHorCursor)
|
||||
|
||||
def test_hover_move_event_rotate(self):
|
||||
self.item.setSelected(True)
|
||||
self.event.pos = MagicMock(return_value=QtCore.QPointF(110, 90))
|
||||
|
|
|
|||
Loading…
Reference in a new issue