Arrange horizontal and vertical

This commit is contained in:
Rebecca Breu 2021-04-23 19:07:32 +02:00
parent 60bb35891d
commit 9fa50a323c
5 changed files with 127 additions and 3 deletions

View file

@ -106,6 +106,20 @@ actions = [
'group': 'active_when_selection',
'enabled': False,
},
{
'id': 'arrange_horizontal',
'text': '&Horizontal',
'callback': 'on_action_arrange_horizontal',
'group': 'active_when_selection',
'enabled': False,
},
{
'id': 'arrange_vertical',
'text': '&Vertical',
'callback': 'on_action_arrange_vertical',
'group': 'active_when_selection',
'enabled': False,
},
{
'id': 'flip_horizontally',
'text': 'Flip &Horizontally',

View file

@ -77,6 +77,8 @@ menu_structure = [
'menu': '&Arrange',
'items': [
'arrange_optimal',
'arrange_horizontal',
'arrange_vertical',
],
},
{

View file

@ -101,16 +101,56 @@ class BeeGraphicsScene(QtWidgets.QGraphicsScene):
commands.NormalizeItems(
self.selectedItems(user_only=True), scale_factors))
def arrange(self, vertical=False):
"""Arrange items in a line (horizontally or vertically)."""
items = self.selectedItems(user_only=True)
if len(items) < 2:
return
center = self.get_selection_center()
positions = []
rects = []
for item in items:
rects.append({
'rect': self.itemsBoundingRect(items=[item]),
'item': item})
if vertical:
rects.sort(key=lambda r: r['rect'].topLeft().y())
sum_height = sum(map(lambda r: r['rect'].height(), rects))
y = round(center.y() - sum_height/2)
for rect in rects:
positions.append(
QtCore.QPointF(
round(center.x() - rect['rect'].width()/2), y))
y += rect['rect'].height()
else:
rects.sort(key=lambda r: r['rect'].topLeft().x())
sum_width = sum(map(lambda r: r['rect'].width(), rects))
x = round(center.x() - sum_width/2)
for rect in rects:
positions.append(
QtCore.QPointF(
x, round(center.y() - rect['rect'].height()/2)))
x += rect['rect'].width()
self.undo_stack.push(
commands.ArrangeItems(self,
[r['item'] for r in rects],
positions))
def arrange_optimal(self):
items = self.selectedItems(user_only=True)
if len(items) < 2:
return
sizes = []
for item in items:
rect = self.itemsBoundingRect(items=[item])
sizes.append((round(rect.width()), round(rect.height())))
if len(sizes) < 2:
return
center = self.get_selection_center()
# The minimal area the items need if they could be packed optimally;

View file

@ -196,6 +196,12 @@ class BeeGraphicsView(QtWidgets.QGraphicsView, ActionsMixin):
def on_action_normalize_size(self):
self.scene.normalize_size()
def on_action_arrange_horizontal(self):
self.scene.arrange()
def on_action_arrange_vertical(self):
self.scene.arrange(vertical=True)
def on_action_arrange_optimal(self):
self.scene.arrange_optimal()

View file

@ -144,6 +144,68 @@ class BeeGraphicsSceneTestCase(BeeTestCase):
def test_normalize_size_when_no_items(self):
self.scene.normalize_size()
def test_arrange_horizontal(self):
item1 = BeePixmapItem(QtGui.QImage())
self.scene.addItem(item1)
item1.setSelected(True)
item1.setPos(10, -100)
item2 = BeePixmapItem(QtGui.QImage())
self.scene.addItem(item2)
item2.setSelected(True)
item2.setPos(-10, 40)
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.arrange()
assert item2.pos() == QtCore.QPointF(-50, -30)
assert item1.pos() == QtCore.QPointF(50, -30)
def test_arrange_vertical(self):
item1 = BeePixmapItem(QtGui.QImage())
self.scene.addItem(item1)
item1.setSelected(True)
item1.setPos(10, -100)
item2 = BeePixmapItem(QtGui.QImage())
self.scene.addItem(item2)
item2.setSelected(True)
item2.setPos(-10, 40)
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.arrange(vertical=True)
assert item1.pos() == QtCore.QPointF(0, -70)
assert item2.pos() == QtCore.QPointF(0, 10)
def test_arrange_when_rotated(self):
item1 = BeePixmapItem(QtGui.QImage())
self.scene.addItem(item1)
item1.setSelected(True)
item1.setPos(10, -100)
item1.setRotation(90)
item2 = BeePixmapItem(QtGui.QImage())
self.scene.addItem(item2)
item2.setSelected(True)
item2.setPos(-10, 40)
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=80):
self.scene.arrange()
assert item2.pos() == QtCore.QPointF(-40, -30)
assert item1.pos() == QtCore.QPointF(40, -30)
def test_arrange_when_no_items(self):
self.scene.arrange()
def test_arrange_optimal(self):
for i in range(4):
item = BeePixmapItem(QtGui.QImage())