Small enhancements around rotating

This commit is contained in:
Rebecca Breu 2021-04-05 19:34:26 +02:00
parent d58b46b08f
commit 2d3e6613bf
5 changed files with 97 additions and 6 deletions

View file

@ -120,16 +120,11 @@ class RotateItemsBy(QtGui.QUndoCommand):
for item in self.items:
item.setRotation(item.rotation() + self.delta,
item.mapFromScene(self.anchor))
item.scene().on_selection_change()
def undo(self):
if self.ignore_first_redo:
self.ignore_first_redo = False
return
for item in self.items:
item.setRotation(item.rotation() - self.delta,
item.mapFromScene(self.anchor))
item.scene().on_selection_change()
class NormalizeItems(QtGui.QUndoCommand):

View file

@ -37,6 +37,7 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
self.multi_select_item = MultiSelectItem()
self.rubberband_item = RubberbandItem()
self.selectionChanged.connect(self.on_selection_change)
self.changed.connect(self.on_change)
def normalize_width_or_height(self, mode):
"""Scale the selected images to have the same width or height, as
@ -186,3 +187,10 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
if not self.has_multi_selection() and self.multi_select_item.scene():
logger.debug('Removing multi select outline')
self.removeItem(self.multi_select_item)
def on_change(self, region):
if (self.multi_select_item.scene()
and not self.multi_select_item.scale_active
and not self.multi_select_item.rotate_active):
self.multi_select_item.fit_selection_area(
self.get_selection_rect())

View file

@ -68,7 +68,7 @@ class SelectableMixin(BaseItemMixin):
SELECT_LINE_WIDTH = 4 # line width for the selection box
SELECT_HANDLE_SIZE = 15 # size of selection handles for scaling
SELECT_RESIZE_SIZE = 20 # size of hover area for scaling
SELECT_ROTATE_SIZE = 20 # size of hover area for rotating
SELECT_ROTATE_SIZE = 15 # size of hover area for rotating
def init_selectable(self):
self.setAcceptHoverEvents(True)
@ -129,6 +129,7 @@ class SelectableMixin(BaseItemMixin):
# If it's a single selection, draw the handles:
if self.has_selection_handles():
pen.setWidth(self.SELECT_HANDLE_SIZE)
pen.setCapStyle(Qt.PenCapStyle.RoundCap)
painter.setPen(pen)
for corner in self.corners:
painter.drawPoint(corner)

View file

@ -150,6 +150,58 @@ class ScaleItemsByTestCase(BeeTestCase):
assert item2.pos().y() == 100
class RotateItemsByTestCase(BeeTestCase):
def test_redo_undo(self):
item1 = BeePixmapItem(QtGui.QImage())
item1.setRotation(0)
item2 = BeePixmapItem(QtGui.QImage())
item2.setRotation(30)
item2.setPos(100, 100)
command = commands.RotateItemsBy([item1, item2], -90,
QtCore.QPointF(100, 100))
command.redo()
assert item1.rotation() == -90
assert item1.pos().x() == 0
assert item1.pos().y() == 200
assert item2.rotation() == -60
assert item2.pos().x() == 100
assert item2.pos().y() == 100
command.undo()
assert item1.rotation() == 0
assert item1.pos().x() == 0
assert item1.pos().y() == 0
assert item2.rotation() == 30
assert item2.pos().x() == 100
assert item2.pos().y() == 100
def test_ignore_first_redo(self):
item1 = BeePixmapItem(QtGui.QImage())
item1.setRotation(0)
item2 = BeePixmapItem(QtGui.QImage())
item2.setRotation(30)
item2.setPos(100, 100)
command = commands.RotateItemsBy([item1, item2], -90,
QtCore.QPointF(100, 100),
ignore_first_redo=True)
command.redo()
assert item1.rotation() == 0
assert item1.pos().x() == 0
assert item1.pos().y() == 0
assert item2.rotation() == 30
assert item2.pos().x() == 100
assert item2.pos().y() == 100
command.redo()
assert item1.rotation() == -90
assert item1.pos().x() == 0
assert item1.pos().y() == 200
assert item2.rotation() == -60
assert item2.pos().x() == 100
assert item2.pos().y() == 100
class NormalizeItemsTestCase(BeeTestCase):
def test_redo_undo(self):

View file

@ -412,3 +412,38 @@ class BeeGraphicsSceneTestCase(BeeTestCase):
m_item = self.scene.multi_select_item
m_item.fit_selection_area.assert_not_called()
self.scene.removeItem.assert_called_once_with(m_item)
def test_on_change_when_multi_select_when_no_scale_no_rotate(self):
self.scene.addItem(self.scene.multi_select_item)
self.scene.multi_select_item.fit_selection_area = MagicMock()
self.scene.get_selection_rect = MagicMock()
self.scene.multi_select_item.scale_active = False
self.scene.multi_select_item.rotate_active = False
self.scene.on_change(None)
self.scene.multi_select_item.fit_selection_area.assert_called_once()
def test_on_change_when_multi_select_when_scale_active(self):
self.scene.addItem(self.scene.multi_select_item)
self.scene.multi_select_item.fit_selection_area = MagicMock()
self.scene.get_selection_rect = MagicMock()
self.scene.multi_select_item.scale_active = True
self.scene.multi_select_item.rotate_active = False
self.scene.on_change(None)
self.scene.multi_select_item.fit_selection_area.assert_not_called()
def test_on_change_when_multi_select_when_rotate_active(self):
self.scene.addItem(self.scene.multi_select_item)
self.scene.multi_select_item.fit_selection_area = MagicMock()
self.scene.get_selection_rect = MagicMock()
self.scene.multi_select_item.scale_active = False
self.scene.multi_select_item.rotate_active = True
self.scene.on_change(None)
self.scene.multi_select_item.fit_selection_area.assert_not_called()
def test_on_change_when_no_multi_select(self):
self.scene.multi_select_item.fit_selection_area = MagicMock()
self.scene.get_selection_rect = MagicMock()
self.scene.multi_select_item.scale_active = True
self.scene.multi_select_item.rotate_active = True
self.scene.on_change(None)
self.scene.multi_select_item.fit_selection_area.assert_not_called()