Re-implemend itemsBoundingRect to not include selection handles

This commit is contained in:
Rebecca Breu 2021-04-15 18:21:21 +02:00
parent ea833d830a
commit 4d64a7422f
3 changed files with 47 additions and 24 deletions

View file

@ -129,8 +129,9 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
item = self.itemAt(event.scenePos(), self.views()[0].transform())
if item:
self.move_active = False
self.views()[0].fit_rect(self.get_selection_rect(),
toggle_item=item)
self.views()[0].fit_rect(
self.itemsBoundingRect(selection_only=True),
toggle_item=item)
return
super().mouseDoubleClickEvent(event)
@ -178,11 +179,19 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
for item in self.selectedItems():
item.on_view_scale_change()
def get_selection_rect(self):
"""Returns the bounding rect of the currently selected items."""
def itemsBoundingRect(self, selection_only=False):
"""Returns the bounding rect of the scene's items; either all of them
or only selected ones.
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))
if not items:
return QtCore.QRectF(0, 0, 0, 0)
items = list(filter(lambda i: hasattr(i, 'save_id'),
self.selectedItems()))
x = []
y = []
@ -196,13 +205,13 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
QtCore.QPointF(max(x), max(y)))
def get_selection_center(self):
rect = self.get_selection_rect()
rect = self.itemsBoundingRect(selection_only=True)
return (rect.topLeft() + rect.bottomRight()) / 2
def on_selection_change(self):
if self.has_multi_selection():
self.multi_select_item.fit_selection_area(
self.get_selection_rect())
self.itemsBoundingRect(selection_only=True))
if self.has_multi_selection() and not self.multi_select_item.scene():
logger.debug('Adding multi select outline')
self.addItem(self.multi_select_item)
@ -216,7 +225,7 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
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())
self.itemsBoundingRect(selection_only=True))
def add_item_later(self, item, selected=False):
"""Keep an item for adding later via ``add_delayed_items``"""

View file

@ -141,7 +141,7 @@ class BeeGraphicsView(QtWidgets.QGraphicsView, ActionsMixin):
self.fit_rect(self.scene.itemsBoundingRect())
def on_action_fit_selection(self):
self.fit_rect(self.scene.get_selection_rect())
self.fit_rect(self.scene.itemsBoundingRect(selection_only=True))
def on_action_undo(self):
logger.debug('Undo: %s' % self.undo_stack.undoText())

View file

@ -72,7 +72,7 @@ class BeeGraphicsSceneTestCase(BeeTestCase):
self.scene.addItem(item)
item.setSelected(True)
self.scene.undo_stack = MagicMock(push=MagicMock())
with patch('beeref.scene.BeeGraphicsScene.get_selection_rect',
with patch('beeref.scene.BeeGraphicsScene.itemsBoundingRect',
return_value=QtCore.QRectF(10, 20, 100, 60)):
self.scene.flip_items(vertical=True)
args = self.scene.undo_stack.push.call_args_list[0][0]
@ -372,7 +372,7 @@ class BeeGraphicsSceneTestCase(BeeTestCase):
self.scene.on_view_scale_change()
item.on_view_scale_change.assert_called_once()
def test_get_selection_rect_two_items(self):
def test_items_bounding_rect_two_items_selection_only(self):
item1 = BeePixmapItem(QtGui.QImage())
self.scene.addItem(item1)
item1.setSelected(True)
@ -390,32 +390,50 @@ class BeeGraphicsSceneTestCase(BeeTestCase):
new_callable=PropertyMock, return_value=100):
with patch('beeref.items.BeePixmapItem.height',
new_callable=PropertyMock, return_value=100):
rect = self.scene.get_selection_rect()
rect = self.scene.itemsBoundingRect(selection_only=True)
assert rect.topLeft().x() == -33
assert rect.topLeft().y() == -6
assert rect.bottomRight().x() == 104
assert rect.bottomRight().y() == 122
def test_get_selection_rect_rotated_item(self):
def test_items_bounding_rect_rotated_item(self):
item = BeePixmapItem(QtGui.QImage())
self.scene.addItem(item)
item.setSelected(True)
item.setRotation(-45)
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.get_selection_rect()
rect = self.scene.itemsBoundingRect()
assert rect.topLeft().x() == 0
assert rect.topLeft().y() == approx(-math.sqrt(2) * 50)
assert rect.bottomRight().x() == approx(math.sqrt(2) * 100)
assert rect.bottomRight().y() == approx(math.sqrt(2) * 50)
def test_items_bounding_rect_flipped_item(self):
item = BeePixmapItem(QtGui.QImage())
self.scene.addItem(item)
item.do_flip()
with patch('beeref.items.BeePixmapItem.width',
new_callable=PropertyMock, return_value=50):
with patch('beeref.items.BeePixmapItem.height',
new_callable=PropertyMock, return_value=100):
rect = self.scene.itemsBoundingRect()
assert rect.topLeft().x() == -50
assert rect.topLeft().y() == 0
assert rect.bottomRight().x() == 0
assert rect.bottomRight().y() == 100
def test_items_bounding_rect_when_no_items(self):
rect = self.scene.itemsBoundingRect()
assert rect == QtCore.QRectF(0, 0, 0, 0)
def test_get_selection_center(self):
with patch('beeref.scene.BeeGraphicsScene.get_selection_rect',
with patch('beeref.scene.BeeGraphicsScene.itemsBoundingRect',
return_value=QtCore.QRectF(10, 20, 100, 60)):
center = self.scene.get_selection_center()
assert center == QtCore.QPointF(60, 50)
@ -424,7 +442,7 @@ class BeeGraphicsSceneTestCase(BeeTestCase):
self.scene.has_multi_selection = MagicMock(return_value=True)
self.scene.multi_select_item.fit_selection_area = MagicMock()
self.scene.multi_select_item.bring_to_front = MagicMock()
self.scene.get_selection_rect = MagicMock(
self.scene.itemsBoundingRect = MagicMock(
return_value=QtCore.QRectF(0, 0, 100, 80))
self.scene.addItem = MagicMock()
@ -441,7 +459,7 @@ class BeeGraphicsSceneTestCase(BeeTestCase):
self.scene.has_multi_selection = MagicMock(return_value=True)
self.scene.multi_select_item.fit_selection_area = MagicMock()
self.scene.multi_select_item.bring_to_front = MagicMock()
self.scene.get_selection_rect = MagicMock(
self.scene.itemsBoundingRect = MagicMock(
return_value=QtCore.QRectF(0, 0, 100, 80))
self.scene.addItem = MagicMock()
@ -458,7 +476,7 @@ class BeeGraphicsSceneTestCase(BeeTestCase):
self.scene.has_multi_selection = MagicMock(return_value=False)
self.scene.multi_select_item.fit_selection_area = MagicMock()
self.scene.multi_select_item.bring_to_front = MagicMock()
self.scene.get_selection_rect = MagicMock(
self.scene.itemsBoundingRect = MagicMock(
return_value=QtCore.QRectF(0, 0, 100, 80))
self.scene.removeItem = MagicMock()
@ -471,7 +489,6 @@ class BeeGraphicsSceneTestCase(BeeTestCase):
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)
@ -480,7 +497,6 @@ class BeeGraphicsSceneTestCase(BeeTestCase):
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)
@ -489,7 +505,6 @@ class BeeGraphicsSceneTestCase(BeeTestCase):
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)
@ -497,7 +512,6 @@ class BeeGraphicsSceneTestCase(BeeTestCase):
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)