diff options
author | Jochen Becher <jochen_becher@gmx.de> | 2018-08-09 09:11:25 +0200 |
---|---|---|
committer | Jochen Becher <jochen_becher@gmx.de> | 2018-09-03 17:51:03 +0000 |
commit | 741885a52b29259c2798491cf7b1acf7ab728d08 (patch) | |
tree | 1dcacddf0fb150b94b9b3da83fc14fc610fd66e4 /src/libs/modelinglib | |
parent | 39d7aa7f70a30a53c55393298a16b61c6f5b1667 (diff) |
ModelEditor: Layout elements on diagram
Change-Id: I7f02375a4c4626ba4719bb965eb949c07f628a01
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/libs/modelinglib')
5 files changed, 174 insertions, 4 deletions
diff --git a/src/libs/modelinglib/qmt/diagram_scene/capabilities/alignable.h b/src/libs/modelinglib/qmt/diagram_scene/capabilities/alignable.h index 2b569ecce8d..34664957b6f 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/capabilities/alignable.h +++ b/src/libs/modelinglib/qmt/diagram_scene/capabilities/alignable.h @@ -41,7 +41,11 @@ public: AlignVcenter, AlignWidth, AlignHeight, - AlignSize + AlignSize, + AlignHCenterDistance, + AlignVCenterDistance, + AlignHBorderDistance, + AlignVBorderDistance }; virtual ~IAlignable() {} diff --git a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp index d6cf0848be1..8bd92463364 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/items/objectitem.cpp @@ -447,6 +447,26 @@ void ObjectItem::align(IAlignable::AlignType alignType, const QString &identifie minimumSize(m_diagramSceneModel->selectedItems()), m_diagramSceneModel->diagram()); break; + case IAlignable::AlignHCenterDistance: + QMT_CHECK(identifier == "sameHCenterDistance"); + m_diagramSceneModel->diagramSceneController()->alignHCenterDistance(m_diagramSceneModel->selectedElements(), + m_diagramSceneModel->diagram()); + break; + case IAlignable::AlignVCenterDistance: + QMT_CHECK(identifier == "sameVCenterDistance"); + m_diagramSceneModel->diagramSceneController()->alignVCenterDistance(m_diagramSceneModel->selectedElements(), + m_diagramSceneModel->diagram()); + break; + case IAlignable::AlignHBorderDistance: + QMT_CHECK(identifier == "sameHBorderDistance"); + m_diagramSceneModel->diagramSceneController()->alignHBorderDistance(m_diagramSceneModel->selectedElements(), + m_diagramSceneModel->diagram()); + break; + case IAlignable::AlignVBorderDistance: + QMT_CHECK(identifier == "sameVBorderDistance"); + m_diagramSceneModel->diagramSceneController()->alignVBorderDistance(m_diagramSceneModel->selectedElements(), + m_diagramSceneModel->diagram()); + break; } } @@ -1008,6 +1028,14 @@ void ObjectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) alignMenu.addAction(new ContextMenuAction(tr("Same Size"), "sameSize", &alignMenu)); alignMenu.setEnabled(m_diagramSceneModel->hasMultiObjectsSelection()); menu.addMenu(&alignMenu); + QMenu layoutMenu; + layoutMenu.setTitle(tr("Layout Objects")); + layoutMenu.addAction(new ContextMenuAction(tr("Equal Horizontal Distance"), "sameHCenterDistance", &alignMenu)); + layoutMenu.addAction(new ContextMenuAction(tr("Equal Vertical Distance"), "sameVCenterDistance", &alignMenu)); + layoutMenu.addAction(new ContextMenuAction(tr("Equal Horizontal Space"), "sameHBorderDistance", &alignMenu)); + layoutMenu.addAction(new ContextMenuAction(tr("Equal Vertical Space"), "sameVBorderDistance", &alignMenu)); + layoutMenu.setEnabled(m_diagramSceneModel->hasMultiObjectsSelection()); + menu.addMenu(&layoutMenu); menu.addAction(new ContextMenuAction(tr("Add Related Elements"), "addRelatedElements", &menu)); QAction *selectedAction = menu.exec(event->screenPos()); @@ -1045,6 +1073,14 @@ void ObjectItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) align(IAlignable::AlignHcenter, "center"); } else if (action->id() == "alignBottom") { align(IAlignable::AlignBottom, "bottom"); + } else if (action->id() == "sameHCenterDistance") { + align(IAlignable::AlignHCenterDistance, "sameHCenterDistance"); + } else if (action->id() == "sameVCenterDistance") { + align(IAlignable::AlignVCenterDistance, "sameVCenterDistance"); + } else if (action->id() == "sameHBorderDistance") { + align(IAlignable::AlignHBorderDistance, "sameHBorderDistance"); + } else if (action->id() == "sameVBorderDistance") { + align(IAlignable::AlignVBorderDistance, "sameVBorderDistance"); } else if (action->id() == "sameWidth") { align(IAlignable::AlignWidth, "width"); } else if (action->id() == "sameHeight") { diff --git a/src/libs/modelinglib/qmt/diagram_scene/parts/alignbuttonsitem.cpp b/src/libs/modelinglib/qmt/diagram_scene/parts/alignbuttonsitem.cpp index 4848d91c75b..6a68f5fdc70 100644 --- a/src/libs/modelinglib/qmt/diagram_scene/parts/alignbuttonsitem.cpp +++ b/src/libs/modelinglib/qmt/diagram_scene/parts/alignbuttonsitem.cpp @@ -167,6 +167,10 @@ void AlignButtonsItem::addButton(IAlignable::AlignType alignType, const QString case IAlignable::AlignWidth: case IAlignable::AlignHeight: case IAlignable::AlignSize: + case IAlignable::AlignHCenterDistance: + case IAlignable::AlignVCenterDistance: + case IAlignable::AlignHBorderDistance: + case IAlignable::AlignVBorderDistance: QMT_CHECK(false); break; } diff --git a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp index ef36d78b8eb..8147303adea 100644 --- a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp +++ b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.cpp @@ -654,6 +654,118 @@ void DiagramSceneController::alignSize(DObject *object, const DSelection &select alignSize(object, selection, minimumSize, alignObjectSize, diagram); } +void DiagramSceneController::alignHCenterDistance(const DSelection &selection, MDiagram *diagram) +{ + QList<DObject *> sortedObjects = collectObjects(selection, diagram); + if (sortedObjects.length() > 2) { + std::sort(sortedObjects.begin(), sortedObjects.end(), [](const DObject *lhs, const DObject *rhs) { + return lhs->pos().x() < rhs->pos().x(); + }); + int n = sortedObjects.length() - 1; + DObject *leftObject = sortedObjects.at(0); + DObject *rightObject = sortedObjects.at(n); + double distance = rightObject->pos().x() - leftObject->pos().x(); + double step = distance / n; + double startX = leftObject->pos().x(); + for (int i = 1; i < n; ++i) { + DObject *selectedObject = sortedObjects.at(i); + QPointF newPos = selectedObject->pos(); + newPos.setX(startX + i * step); + if (newPos != selectedObject->pos()) { + m_diagramController->startUpdateElement(selectedObject, diagram, DiagramController::UpdateGeometry); + selectedObject->setPos(newPos); + m_diagramController->finishUpdateElement(selectedObject, diagram, false); + } + } + } +} + +void DiagramSceneController::alignVCenterDistance(const DSelection &selection, MDiagram *diagram) +{ + QList<DObject *> sortedObjects = collectObjects(selection, diagram); + if (sortedObjects.length() > 2) { + std::sort(sortedObjects.begin(), sortedObjects.end(), [](const DObject *lhs, const DObject *rhs) { + return lhs->pos().y() < rhs->pos().y(); + }); + int n = sortedObjects.length() - 1; + DObject *topObject = sortedObjects.at(0); + DObject *bottomObject = sortedObjects.at(n); + double distance = bottomObject->pos().y() - topObject->pos().y(); + double step = distance / n; + double startY = topObject->pos().y(); + for (int i = 1; i < n; ++i) { + DObject *selectedObject = sortedObjects.at(i); + QPointF newPos = selectedObject->pos(); + newPos.setY(startY + i * step); + if (newPos != selectedObject->pos()) { + m_diagramController->startUpdateElement(selectedObject, diagram, DiagramController::UpdateGeometry); + selectedObject->setPos(newPos); + m_diagramController->finishUpdateElement(selectedObject, diagram, false); + } + } + } +} + +void DiagramSceneController::alignHBorderDistance(const DSelection &selection, MDiagram *diagram) +{ + QList<DObject *> sortedObjects = collectObjects(selection, diagram); + if (sortedObjects.length() > 2) { + std::sort(sortedObjects.begin(), sortedObjects.end(), [](const DObject *lhs, const DObject *rhs) { + return lhs->pos().x() < rhs->pos().x(); + }); + int n = sortedObjects.length() - 1; + DObject *leftObject = sortedObjects.at(0); + DObject *rightObject = sortedObjects.at(n); + double space = rightObject->pos().x() + rightObject->rect().left() - (leftObject->pos().x() + leftObject->rect().right()); + for (int i = 1; i < n; ++i) + space -= sortedObjects.at(i)->rect().width(); + double step = space / n; + double x = leftObject->pos().x() + leftObject->rect().right(); + for (int i = 1 ; i < n; ++i) { + DObject *selectedObject = sortedObjects.at(i); + QPointF newPos = selectedObject->pos(); + x += step; + newPos.setX(x - selectedObject->rect().left()); + x += selectedObject->rect().width(); + if (newPos != selectedObject->pos()) { + m_diagramController->startUpdateElement(selectedObject, diagram, DiagramController::UpdateGeometry); + selectedObject->setPos(newPos); + m_diagramController->finishUpdateElement(selectedObject, diagram, false); + } + } + } +} + +void DiagramSceneController::alignVBorderDistance(const DSelection &selection, MDiagram *diagram) +{ + QList<DObject *> sortedObjects = collectObjects(selection, diagram); + if (sortedObjects.length() > 2) { + std::sort(sortedObjects.begin(), sortedObjects.end(), [](const DObject *lhs, const DObject *rhs) { + return lhs->pos().y() < rhs->pos().y(); + }); + int n = sortedObjects.length() - 1; + DObject *topObject = sortedObjects.at(0); + DObject *bottomObject = sortedObjects.at(n); + double space = bottomObject->pos().y() + bottomObject->rect().top() - (topObject->pos().y() + topObject->rect().bottom()); + for (int i = 1; i < n; ++i) + space -= sortedObjects.at(i)->rect().height(); + double step = space / n; + double y = topObject->pos().y() + topObject->rect().bottom(); + for (int i = 1 ; i < n; ++i) { + DObject *selectedObject = sortedObjects.at(i); + QPointF newPos = selectedObject->pos(); + y += step; + newPos.setY(y - selectedObject->rect().top()); + y += selectedObject->rect().height(); + if (newPos != selectedObject->pos()) { + m_diagramController->startUpdateElement(selectedObject, diagram, DiagramController::UpdateGeometry); + selectedObject->setPos(newPos); + m_diagramController->finishUpdateElement(selectedObject, diagram, false); + } + } + } +} + void DiagramSceneController::alignPosition(DObject *object, const DSelection &selection, QPointF (*aligner)(DObject *, DObject *), MDiagram *diagram) { @@ -707,6 +819,17 @@ void DiagramSceneController::alignOnRaster(DElement *element, MDiagram *diagram) element->accept(&visitor); } +QList<DObject *> DiagramSceneController::collectObjects(const DSelection &selection, MDiagram *diagram) +{ + QList<DObject *> list; + foreach (const DSelection::Index &index, selection.indices()) { + DObject *object = m_diagramController->findElement<DObject>(index.elementKey(), diagram); + if (object) + list.append(object); + } + return list; +} + DElement *DiagramSceneController::addModelElement(const Uid &modelElementKey, const QPointF &pos, MDiagram *diagram) { DElement *element = nullptr; diff --git a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h index 97717cbc21d..5f925df48b5 100644 --- a/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h +++ b/src/libs/modelinglib/qmt/tasks/diagramscenecontroller.h @@ -125,9 +125,10 @@ public: MDiagram *diagram); void alignSize(DObject *object, const DSelection &selection, const QSizeF &minimumSize, MDiagram *diagram); - void distributeHorizontal(DObject *object, const DSelection &selection, MDiagram *diagram); - void distributeVertical(DObject *object, const DSelection &selection, MDiagram *diagram); - void distributeField(DObject *object, const DSelection &selection, MDiagram *diagram); + void alignHCenterDistance(const DSelection &selection, MDiagram *diagram); + void alignVCenterDistance(const DSelection &selection, MDiagram *diagram); + void alignHBorderDistance(const DSelection &selection, MDiagram *diagram); + void alignVBorderDistance(const DSelection &selection, MDiagram *diagram); private: void alignPosition(DObject *object, const DSelection &selection, @@ -137,6 +138,8 @@ private: QRectF (*aligner)(DObject *, const QSizeF &), MDiagram *diagram); void alignOnRaster(DElement *element, MDiagram *diagram); + QList<DObject *> collectObjects(const DSelection &selection, MDiagram *diagram); + DElement *addModelElement(const Uid &modelElementKey, const QPointF &pos, MDiagram *diagram); DObject *addObject(MObject *modelObject, const QPointF &pos, MDiagram *diagram); DRelation *addRelation(MRelation *modelRelation, const QList<QPointF> &intermediatePoints, |