mirror of
https://github.com/rbreu/beeref.git
synced 2026-03-11 08:54:28 +00:00
Fix normalize for transformed items
This commit is contained in:
parent
94117b82c1
commit
e8e7a0fc1e
4 changed files with 155 additions and 38 deletions
|
|
@ -137,7 +137,7 @@ class NormalizeItems(QtGui.QUndoCommand):
|
|||
self.old_scale_factors = []
|
||||
for item, factor in zip(self.items, self.scale_factors):
|
||||
self.old_scale_factors.append(item.scale())
|
||||
item.setScale(factor,
|
||||
item.setScale(item.scale() * factor,
|
||||
QtCore.QPointF(item.width, item.height) / 2)
|
||||
|
||||
def undo(self):
|
||||
|
|
|
|||
|
|
@ -48,7 +48,10 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
:param mode: "width" or "height".
|
||||
"""
|
||||
|
||||
values = [getattr(i, mode) for i in self.selectedItems(user_only=True)]
|
||||
values = []
|
||||
for item in self.selectedItems(user_only=True):
|
||||
rect = self.itemsBoundingRect(items=[item])
|
||||
values.append(getattr(rect, mode)())
|
||||
if not values:
|
||||
return
|
||||
avg = sum(values) / len(values)
|
||||
|
|
@ -57,7 +60,8 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
|
||||
scale_factors = []
|
||||
for item in self.selectedItems(user_only=True):
|
||||
scale_factors.append(avg / getattr(item, mode))
|
||||
rect = self.itemsBoundingRect(items=[item])
|
||||
scale_factors.append(avg / getattr(rect, mode)())
|
||||
self.undo_stack.push(
|
||||
commands.NormalizeItems(
|
||||
self.selectedItems(user_only=True), scale_factors))
|
||||
|
|
@ -75,8 +79,11 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
|
||||
Size meaning the area = widh * height.
|
||||
"""
|
||||
sizes = [i.width * i.height
|
||||
for i in self.selectedItems(user_only=True)]
|
||||
|
||||
sizes = []
|
||||
for item in self.selectedItems(user_only=True):
|
||||
rect = self.itemsBoundingRect(items=[item])
|
||||
sizes.append(rect.width() * rect.height())
|
||||
|
||||
if not sizes:
|
||||
return
|
||||
|
|
@ -86,7 +93,8 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
|
||||
scale_factors = []
|
||||
for item in self.selectedItems(user_only=True):
|
||||
scale_factors.append(math.sqrt(avg / item.width / item.height))
|
||||
rect = self.itemsBoundingRect(items=[item])
|
||||
scale_factors.append(math.sqrt(avg / rect.width() / rect.height()))
|
||||
self.undo_stack.push(
|
||||
commands.NormalizeItems(
|
||||
self.selectedItems(user_only=True), scale_factors))
|
||||
|
|
@ -140,7 +148,7 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
if not item.isSelected():
|
||||
item.setSelected(True)
|
||||
self.views()[0].fit_rect(
|
||||
self.itemsBoundingRect(selection_only=True),
|
||||
self.itemsBoundingRect(items=[item]),
|
||||
toggle_item=item)
|
||||
return
|
||||
super().mouseDoubleClickEvent(event)
|
||||
|
|
@ -202,23 +210,30 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
|
|||
for item in self.selectedItems():
|
||||
item.on_view_scale_change()
|
||||
|
||||
def itemsBoundingRect(self, selection_only=False):
|
||||
def itemsBoundingRect(self, selection_only=False, items=None):
|
||||
"""Returns the bounding rect of the scene's items; either all of them
|
||||
or only selected ones.
|
||||
or only selected ones, or the items givin in ``items``.
|
||||
|
||||
Re-implemented to not include the items's selection handles.
|
||||
"""
|
||||
|
||||
base = self.selectedItems() if selection_only else self.items()
|
||||
items = list(filter(lambda i: hasattr(i, 'save_id'), base))
|
||||
def filter_user_items(ilist):
|
||||
return list(filter(lambda i: hasattr(i, 'save_id'), ilist))
|
||||
|
||||
if not items:
|
||||
if selection_only:
|
||||
base = filter_user_items(self.selectedItems())
|
||||
elif items:
|
||||
base = items
|
||||
else:
|
||||
base = filter_user_items(self.items())
|
||||
|
||||
if not base:
|
||||
return QtCore.QRectF(0, 0, 0, 0)
|
||||
|
||||
x = []
|
||||
y = []
|
||||
|
||||
for item in items:
|
||||
for item in base:
|
||||
for corner in item.corners_scene_coords:
|
||||
x.append(corner.x())
|
||||
y.append(corner.y())
|
||||
|
|
|
|||
|
|
@ -229,8 +229,8 @@ class NormalizeItemsTestCase(BeeTestCase):
|
|||
command.redo()
|
||||
assert item1.scale() == 2
|
||||
assert item1.pos() == QtCore.QPointF(-50, -40)
|
||||
assert item2.scale() == 0.5
|
||||
assert item2.pos() == QtCore.QPointF(125, 100)
|
||||
assert item2.scale() == 1.5
|
||||
assert item2.pos() == QtCore.QPointF(75, 60)
|
||||
command.undo()
|
||||
assert item1.scale() == 1
|
||||
assert item1.pos() == QtCore.QPointF(0, 0)
|
||||
|
|
|
|||
|
|
@ -24,45 +24,122 @@ class BeeGraphicsSceneTestCase(BeeTestCase):
|
|||
self.addCleanup(views_patcher.stop)
|
||||
|
||||
def test_normalize_height(self):
|
||||
item1 = MagicMock(width=200, height=100, scale_factor=1)
|
||||
item2 = MagicMock(width=300, height=200, scale_factor=3)
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item1)
|
||||
item1.setSelected(True)
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setScale(3)
|
||||
|
||||
with patch.object(self.scene, 'selectedItems',
|
||||
return_value=[item1, item2]):
|
||||
self.scene.normalize_height()
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
self.scene.normalize_height()
|
||||
|
||||
item1.setScale.assert_called_once_with(1.5, QtCore.QPointF(100, 50))
|
||||
item2.setScale.assert_called_once_with(0.75, QtCore.QPointF(150, 100))
|
||||
assert item1.scale() == 2
|
||||
assert item1.pos() == QtCore.QPointF(-50, -40)
|
||||
assert item2.scale() == 2
|
||||
assert item2.pos() == QtCore.QPointF(50, 40)
|
||||
|
||||
def test_normalize_height_with_rotation(self):
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item1)
|
||||
item1.setSelected(True)
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setRotation(90)
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=200):
|
||||
self.scene.normalize_height()
|
||||
|
||||
assert item1.scale() == 0.75
|
||||
assert item2.scale() == 1.5
|
||||
|
||||
def test_normalize_height_when_no_items(self):
|
||||
self.scene.normalize_height()
|
||||
|
||||
def test_normalize_width(self):
|
||||
item1 = MagicMock(width=100, height=200, scale_factor=1)
|
||||
item2 = MagicMock(width=200, height=300, scale_factor=3)
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item1)
|
||||
item1.setSelected(True)
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setScale(3)
|
||||
|
||||
with patch.object(self.scene, 'selectedItems',
|
||||
return_value=[item1, item2]):
|
||||
self.scene.normalize_width()
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=80):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
self.scene.normalize_width()
|
||||
|
||||
item1.setScale.assert_called_once_with(1.5, QtCore.QPointF(50, 100))
|
||||
item2.setScale.assert_called_once_with(0.75, QtCore.QPointF(100, 150))
|
||||
assert item1.scale() == 2
|
||||
assert item1.pos() == QtCore.QPointF(-40, -50)
|
||||
assert item2.scale() == 2
|
||||
assert item2.pos() == QtCore.QPointF(40, 50)
|
||||
|
||||
def test_normalize_width_with_rotation(self):
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item1)
|
||||
item1.setSelected(True)
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setRotation(90)
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=200):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
self.scene.normalize_height()
|
||||
|
||||
assert item1.scale() == 1.5
|
||||
assert item2.scale() == 0.75
|
||||
|
||||
def test_normalize_width_when_no_items(self):
|
||||
self.scene.normalize_width()
|
||||
|
||||
def test_normalize_size(self):
|
||||
item1 = MagicMock(width=100, height=200, scale_factor=1)
|
||||
item2 = MagicMock(width=400, height=100, scale_factor=3)
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item1)
|
||||
item1.setSelected(True)
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setScale(2)
|
||||
|
||||
with patch.object(self.scene, 'selectedItems',
|
||||
return_value=[item1, item2]):
|
||||
self.scene.normalize_size()
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
self.scene.normalize_size()
|
||||
|
||||
item1.setScale.assert_called_once_with(
|
||||
math.sqrt(1.5), QtCore.QPointF(50, 100))
|
||||
item2.setScale.assert_called_once_with(
|
||||
math.sqrt(0.75), QtCore.QPointF(200, 50))
|
||||
assert item1.scale() == approx(math.sqrt(2.5))
|
||||
assert item2.scale() == approx(math.sqrt(2.5))
|
||||
|
||||
def test_normalize_size_with_rotation(self):
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item1)
|
||||
item1.setSelected(True)
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setRotation(90)
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=200):
|
||||
self.scene.normalize_size()
|
||||
|
||||
assert item1.scale() == 1
|
||||
assert item2.scale() == 1
|
||||
|
||||
def test_normalize_size_when_no_items(self):
|
||||
self.scene.normalize_size()
|
||||
|
|
@ -459,6 +536,31 @@ class BeeGraphicsSceneTestCase(BeeTestCase):
|
|||
self.scene.on_view_scale_change()
|
||||
item.on_view_scale_change.assert_called_once()
|
||||
|
||||
def test_items_bounding_rect_given_items(self):
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item1)
|
||||
item1.setSelected(True)
|
||||
item1.setPos(4, -6)
|
||||
item2 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item2)
|
||||
item2.setSelected(True)
|
||||
item2.setPos(-33, 22)
|
||||
item3 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item3)
|
||||
item3.setSelected(True)
|
||||
item3.setPos(1000, 1000)
|
||||
|
||||
with patch('beeref.items.BeePixmapItem.width',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
with patch('beeref.items.BeePixmapItem.height',
|
||||
new_callable=PropertyMock, return_value=100):
|
||||
rect = self.scene.itemsBoundingRect(items=[item1, item2])
|
||||
|
||||
assert rect.topLeft().x() == -33
|
||||
assert rect.topLeft().y() == -6
|
||||
assert rect.bottomRight().x() == 104
|
||||
assert rect.bottomRight().y() == 122
|
||||
|
||||
def test_items_bounding_rect_two_items_selection_only(self):
|
||||
item1 = BeePixmapItem(QtGui.QImage())
|
||||
self.scene.addItem(item1)
|
||||
|
|
|
|||
Loading…
Reference in a new issue