Prevent flipping of crop area

This commit is contained in:
Rebecca Breu 2021-10-17 21:56:01 +02:00
parent cf55d1a5e3
commit 6b162f3ffb
2 changed files with 99 additions and 27 deletions

View file

@ -369,46 +369,80 @@ class BeePixmapItem(BeeItemMixin, QtWidgets.QGraphicsPixmapItem):
self.exit_crop_mode(
confirm=self.crop_temp.contains(event.pos()))
def ensure_point_within_pixmap_bounds(self, point):
def ensure_point_within_crop_bounds(self, point, handle):
"""Returns the point, or the nearest point within the pixmap."""
point.setX(min(self.pixmap().size().width(), max(0, point.x())))
point.setY(min(self.pixmap().size().height(), max(0, point.y())))
if handle == self.crop_handle_topleft:
topleft = QtCore.QPointF(0, 0)
bottomright = self.crop_temp.bottomRight()
if handle == self.crop_handle_bottomleft:
topleft = QtCore.QPointF(0, self.crop_temp.top())
bottomright = QtCore.QPointF(
self.crop_temp.right(), self.pixmap().size().height())
if handle == self.crop_handle_bottomright:
topleft = self.crop_temp.topLeft()
bottomright = QtCore.QPointF(
self.pixmap().size().width(), self.pixmap().size().height())
if handle == self.crop_handle_topright:
topleft = QtCore.QPointF(self.crop_temp.left(), 0)
bottomright = QtCore.QPointF(
self.pixmap().size().width(), self.crop_temp.bottom())
if handle == self.crop_edge_top:
topleft = QtCore.QPointF(0, 0)
bottomright = QtCore.QPointF(
self.pixmap().size().width(), self.crop_temp.bottom())
if handle == self.crop_edge_bottom:
topleft = QtCore.QPointF(0, self.crop_temp.top())
bottomright = QtCore.QPointF(
self.pixmap().size().width(), self.pixmap().size().height())
if handle == self.crop_edge_left:
topleft = QtCore.QPointF(0, 0)
bottomright = QtCore.QPointF(
self.crop_temp.right(), self.pixmap().size().height())
if handle == self.crop_edge_right:
topleft = QtCore.QPointF(self.crop_temp.left(), 0)
bottomright = QtCore.QPointF(
self.pixmap().size().width(), self.pixmap().size().height())
point.setX(min(bottomright.x(), max(topleft.x(), point.x())))
point.setY(min(bottomright.y(), max(topleft.y(), point.y())))
return point
def mouseMoveEvent(self, event):
if self.crop_mode:
diff = event.pos() - self.crop_mode_event_start
if self.crop_mode_move == self.crop_handle_topleft:
new = self.ensure_point_within_pixmap_bounds(
self.crop_temp.topLeft() + diff)
new = self.ensure_point_within_crop_bounds(
self.crop_temp.topLeft() + diff, self.crop_mode_move)
self.crop_temp.setTopLeft(new)
if self.crop_mode_move == self.crop_handle_bottomleft:
new = self.ensure_point_within_pixmap_bounds(
self.crop_temp.bottomLeft() + diff)
new = self.ensure_point_within_crop_bounds(
self.crop_temp.bottomLeft() + diff, self.crop_mode_move)
self.crop_temp.setBottomLeft(new)
if self.crop_mode_move == self.crop_handle_bottomright:
new = self.ensure_point_within_pixmap_bounds(
self.crop_temp.bottomRight() + diff)
new = self.ensure_point_within_crop_bounds(
self.crop_temp.bottomRight() + diff, self.crop_mode_move)
self.crop_temp.setBottomRight(new)
if self.crop_mode_move == self.crop_handle_topright:
new = self.ensure_point_within_pixmap_bounds(
self.crop_temp.topRight() + diff)
new = self.ensure_point_within_crop_bounds(
self.crop_temp.topRight() + diff, self.crop_mode_move)
self.crop_temp.setTopRight(new)
if self.crop_mode_move == self.crop_edge_top:
new = self.ensure_point_within_pixmap_bounds(
self.crop_temp.topLeft() + diff)
new = self.ensure_point_within_crop_bounds(
self.crop_temp.topLeft() + diff, self.crop_mode_move)
self.crop_temp.setTop(new.y())
if self.crop_mode_move == self.crop_edge_left:
new = self.ensure_point_within_pixmap_bounds(
self.crop_temp.topLeft() + diff)
new = self.ensure_point_within_crop_bounds(
self.crop_temp.topLeft() + diff, self.crop_mode_move)
self.crop_temp.setLeft(new.x())
if self.crop_mode_move == self.crop_edge_bottom:
new = self.ensure_point_within_pixmap_bounds(
self.crop_temp.bottomLeft() + diff)
new = self.ensure_point_within_crop_bounds(
self.crop_temp.bottomLeft() + diff, self.crop_mode_move)
self.crop_temp.setBottom(new.y())
if self.crop_mode_move == self.crop_edge_right:
new = self.ensure_point_within_pixmap_bounds(
self.crop_temp.topRight() + diff)
new = self.ensure_point_within_crop_bounds(
self.crop_temp.topRight() + diff, self.crop_mode_move)
self.crop_temp.setRight(new.x())
self.update()
self.crop_mode_event_start = event.pos()

View file

@ -520,17 +520,55 @@ def test_mouse_press_event_crop_mode_outside_handle_outside_crop(
event.accept.assert_called_once_with()
@pytest.mark.parametrize('point,expected',
[((45, 56), (45, 56)),
((0, 0), (0, 0)),
((-5, -5), (0, 0)),
((100, 80), (100, 80)),
((105, 85), (100, 80))])
def test_ensure_point_within_pixmap_bounds_inside(point, expected, qapp, item):
@pytest.mark.parametrize('point,handle,expected',
[((25, 40), 'crop_handle_topleft', (25, 40)),
((0, 0), 'crop_handle_topleft', (0, 0)),
((-5, -5), 'crop_handle_topleft', (0, 0)),
((40, 60), 'crop_handle_topleft', (40, 60)),
((100, 80), 'crop_handle_topleft', (40, 60)),
((25, 40), 'crop_handle_bottomleft', (25, 40)),
((0, 80), 'crop_handle_bottomleft', (0, 80)),
((-5, 85), 'crop_handle_bottomleft', (0, 80)),
((40, 20), 'crop_handle_bottomleft', (40, 20)),
((45, 15), 'crop_handle_bottomleft', (40, 20)),
((25, 40), 'crop_handle_bottomright', (25, 40)),
((10, 20), 'crop_handle_bottomright', (10, 20)),
((5, 15), 'crop_handle_bottomright', (10, 20)),
((100, 80), 'crop_handle_bottomright', (100, 80)),
((105, 85), 'crop_handle_bottomright', (100, 80)),
((25, 40), 'crop_handle_topright', (25, 40)),
((10, 0), 'crop_handle_topright', (10, 0)),
((5, -5), 'crop_handle_topright', (10, 0)),
((100, 60), 'crop_handle_topright', (100, 60)),
((105, 65), 'crop_handle_topright', (100, 60)),
((25, 40), 'crop_edge_top', (25, 40)),
((0, 0), 'crop_edge_top', (0, 0)),
((-5, -5), 'crop_edge_top', (0, 0)),
((100, 60), 'crop_edge_top', (100, 60)),
((105, 65), 'crop_edge_top', (100, 60)),
((25, 40), 'crop_edge_bottom', (25, 40)),
((0, 20), 'crop_edge_bottom', (0, 20)),
((-5, 15), 'crop_edge_bottom', (0, 20)),
((100, 80), 'crop_edge_bottom', (100, 80)),
((105, 85), 'crop_edge_bottom', (100, 80)),
((25, 40), 'crop_edge_left', (25, 40)),
((0, 0), 'crop_edge_left', (0, 0)),
((-5, -5), 'crop_edge_left', (0, 0)),
((40, 80), 'crop_edge_left', (40, 80)),
((45, 85), 'crop_edge_left', (40, 80)),
((25, 40), 'crop_edge_right', (25, 40)),
((10, 0), 'crop_edge_right', (10, 0)),
((5, -5), 'crop_edge_right', (10, 0)),
((100, 80), 'crop_edge_right', (100, 80)),
((105, 85), 'crop_edge_right', (100, 80))])
def test_ensure_point_within_crop_bounds(
point, handle, expected, qapp, item):
pixmap = MagicMock()
pixmap.size.return_value = QtCore.QRectF(0, 0, 100, 80)
item.pixmap = MagicMock(return_value=pixmap)
result = item.ensure_point_within_pixmap_bounds(QtCore.QPointF(*point))
item.crop_temp = QtCore.QRectF(10, 20, 30, 40)
result = item.ensure_point_within_crop_bounds(
QtCore.QPointF(*point), getattr(item, handle))
assert result == QtCore.QPointF(*expected)