mirror of
https://github.com/rbreu/beeref.git
synced 2026-03-11 08:54:28 +00:00
Arrange horizontal and vertical
This commit is contained in:
parent
60bb35891d
commit
9fa50a323c
5 changed files with 127 additions and 3 deletions
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -77,6 +77,8 @@ menu_structure = [
|
|||
'menu': '&Arrange',
|
||||
'items': [
|
||||
'arrange_optimal',
|
||||
'arrange_horizontal',
|
||||
'arrange_vertical',
|
||||
],
|
||||
},
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
||||
|
|
|
|||
|
|
@ -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())
|
||||
|
|
|
|||
Loading…
Reference in a new issue