diff --git a/sources/editor/editorcommands.cpp b/sources/editor/editorcommands.cpp
index 7646ab88d..62bc2a013 100644
--- a/sources/editor/editorcommands.cpp
+++ b/sources/editor/editorcommands.cpp
@@ -16,6 +16,7 @@
along with QElectroTech. If not, see .
*/
#include "editorcommands.h"
+#include "../diagram.h"
/**
@brief ElementEditionCommand::ElementEditionCommand
@@ -666,10 +667,32 @@ void RotateFineElementsCommand::redo()
}
+/**
+ @brief selectionCenter
+ @param items
+ @return the center of the united scene bounding rect of items,
+ snapped to the nearest half of the diagram grid. Mirroring across a
+ half-grid line keeps points that were on the grid on the grid.
+*/
+static QPointF selectionCenter(const QList &items)
+{
+ QRectF bounding;
+ for (auto *item : items) {
+ bounding = bounding.united(item->sceneBoundingRect());
+ }
+ QPointF center = bounding.center();
+ const qreal half_x = Diagram::xGrid / 2.0;
+ const qreal half_y = Diagram::yGrid / 2.0;
+ center.setX(qRound(center.x() / half_x) * half_x);
+ center.setY(qRound(center.y() / half_y) * half_y);
+ return center;
+}
+
MirrorElementsCommand::MirrorElementsCommand(ElementScene *scene, QUndoCommand *parent) :
ElementEditionCommand(QObject::tr("Miroir de sélection", "undo caption"), scene, nullptr, parent)
{
m_items = scene->selectedItems();
+ m_axis_x = selectionCenter(m_items).x();
}
/**
@@ -680,28 +703,28 @@ void MirrorElementsCommand::redo()
foreach (auto *item, m_items) {
if (item->type() == PartText::Type) {
PartText* staticText = qgraphicsitem_cast(item);
- staticText->mirror();
+ staticText->mirror(m_axis_x);
} else if (item->type() == PartDynamicTextField::Type) {
PartDynamicTextField* dyntext = qgraphicsitem_cast(item);
- dyntext->mirror();
+ dyntext->mirror(m_axis_x);
} else if (item->type() == PartArc::Type) {
PartArc* arc = qgraphicsitem_cast(item);
- arc->mirror();
+ arc->mirror(m_axis_x);
} else if (item->type() == PartEllipse::Type) {
PartEllipse* ellipse = qgraphicsitem_cast(item);
- ellipse->mirror();
+ ellipse->mirror(m_axis_x);
} else if (item->type() == PartLine::Type) {
PartLine* line = qgraphicsitem_cast(item);
- line->mirror();
+ line->mirror(m_axis_x);
} else if (item->type() == PartPolygon::Type) {
PartPolygon* poly = qgraphicsitem_cast(item);
- poly->mirror();
+ poly->mirror(m_axis_x);
} else if (item->type() == PartRectangle::Type) {
PartRectangle* rect = qgraphicsitem_cast(item);
- rect->mirror();
+ rect->mirror(m_axis_x);
} else if (item->type() == PartTerminal::Type) {
PartTerminal* term = qgraphicsitem_cast(item);
- term->mirror();
+ term->mirror(m_axis_x);
}
}
}
@@ -718,6 +741,7 @@ FlipElementsCommand::FlipElementsCommand(ElementScene *scene, QUndoCommand *pare
ElementEditionCommand(QObject::tr("Retourner la sélection", "undo caption"), scene, nullptr, parent)
{
m_items = scene->selectedItems();
+ m_axis_y = selectionCenter(m_items).y();
}
/**
@@ -728,28 +752,28 @@ void FlipElementsCommand::redo()
foreach (auto *item, m_items) {
if (item->type() == PartText::Type) {
PartText* staticText = qgraphicsitem_cast(item);
- staticText->flip();
+ staticText->flip(m_axis_y);
} else if (item->type() == PartDynamicTextField::Type) {
PartDynamicTextField* dyntext = qgraphicsitem_cast(item);
- dyntext->flip();
+ dyntext->flip(m_axis_y);
} else if (item->type() == PartArc::Type) {
PartArc* arc = qgraphicsitem_cast(item);
- arc->flip();
+ arc->flip(m_axis_y);
} else if (item->type() == PartEllipse::Type) {
PartEllipse* ellipse = qgraphicsitem_cast(item);
- ellipse->flip();
+ ellipse->flip(m_axis_y);
} else if (item->type() == PartLine::Type) {
PartLine* line = qgraphicsitem_cast(item);
- line->flip();
+ line->flip(m_axis_y);
} else if (item->type() == PartPolygon::Type) {
PartPolygon* poly = qgraphicsitem_cast(item);
- poly->flip();
+ poly->flip(m_axis_y);
} else if (item->type() == PartRectangle::Type) {
PartRectangle* rect = qgraphicsitem_cast(item);
- rect->flip();
+ rect->flip(m_axis_y);
} else if (item->type() == PartTerminal::Type) {
PartTerminal* term = qgraphicsitem_cast(item);
- term->flip();
+ term->flip(m_axis_y);
}
}
}
diff --git a/sources/editor/editorcommands.h b/sources/editor/editorcommands.h
index b920b47d9..e5a811a83 100644
--- a/sources/editor/editorcommands.h
+++ b/sources/editor/editorcommands.h
@@ -279,6 +279,12 @@ private:
};
+/**
+ @brief The MirrorElementsCommand class
+ Mirror the selected parts horizontally (left <-> right) across the
+ vertical line through the center of the selection, so the selection
+ keeps its place in the scene.
+*/
class MirrorElementsCommand : public ElementEditionCommand
{
public:
@@ -288,8 +294,15 @@ public:
private:
ElementScene *m_scene =nullptr;
QList m_items;
+ qreal m_axis_x = 0;
};
+/**
+ @brief The FlipElementsCommand class
+ Flip the selected parts vertically (top <-> bottom) across the
+ horizontal line through the center of the selection, so the selection
+ keeps its place in the scene.
+*/
class FlipElementsCommand : public ElementEditionCommand
{
public:
@@ -299,6 +312,7 @@ public:
private:
ElementScene *m_scene =nullptr;
QList m_items;
+ qreal m_axis_y = 0;
};
#endif
diff --git a/sources/editor/graphicspart/partarc.cpp b/sources/editor/graphicspart/partarc.cpp
index 596f19f37..fb06bdb83 100644
--- a/sources/editor/graphicspart/partarc.cpp
+++ b/sources/editor/graphicspart/partarc.cpp
@@ -197,13 +197,13 @@ qreal PartArc::rotation() const {
return qRound(m_rot * 100.0) / 100.0;
}
-void PartArc::flip() {
+void PartArc::flip(qreal axis_y) {
m_start_angle = (-1) * m_start_angle;
m_span_angle = (-1) * m_span_angle;
while (m_start_angle < 0) { m_start_angle += (360*16); }
while (m_start_angle >= (360*16)) { m_start_angle -= (360*16); }
auto p1 = mapToScene(m_rect.x(),m_rect.y());
- p1.setY(((-1.0) * p1.y()) - m_rect.height());
+ p1.setY(2 * axis_y - p1.y() - m_rect.height());
p1 = mapFromScene(p1.x(),p1.y());
m_rect = QRectF(m_rect.x(), p1.y(), m_rect.width(), m_rect.height());
prepareGeometryChange();
@@ -211,13 +211,13 @@ void PartArc::flip() {
emit rectChanged();
}
-void PartArc::mirror() {
+void PartArc::mirror(qreal axis_x) {
m_start_angle = (180.0 * 16) - m_start_angle;
m_span_angle = (-1) * m_span_angle;
while (m_start_angle < 0) { m_start_angle += (360*16); }
while (m_start_angle >= (360*16)) { m_start_angle -= (360*16); }
auto p1 = mapToScene(m_rect.x(),m_rect.y());
- p1.setX(((-1.0) * p1.x()) - m_rect.width());
+ p1.setX(2 * axis_x - p1.x() - m_rect.width());
p1 = mapFromScene(p1.x(), p1.y());
m_rect = QRectF(p1.x(), m_rect.y(), m_rect.width(), m_rect.height());
prepareGeometryChange();
diff --git a/sources/editor/graphicspart/partarc.h b/sources/editor/graphicspart/partarc.h
index bc6f51301..cd0878120 100644
--- a/sources/editor/graphicspart/partarc.h
+++ b/sources/editor/graphicspart/partarc.h
@@ -62,8 +62,8 @@ class PartArc : public AbstractPartEllipse
QRectF sceneGeometricRect() const override;
void setRotation(qreal angle);
qreal rotation() const;
- void flip();
- void mirror();
+ void flip(qreal axis_y = 0);
+ void mirror(qreal axis_x = 0);
void addHandler() override;
void removeHandler() override;
diff --git a/sources/editor/graphicspart/partdynamictextfield.cpp b/sources/editor/graphicspart/partdynamictextfield.cpp
index d04ac6f5b..c65c955df 100644
--- a/sources/editor/graphicspart/partdynamictextfield.cpp
+++ b/sources/editor/graphicspart/partdynamictextfield.cpp
@@ -74,19 +74,19 @@ void PartDynamicTextField::setRotation(qreal angle) {
setPos(QTransform().rotate(diffAngle).map(pos()));
}
-void PartDynamicTextField::mirror() {
+void PartDynamicTextField::mirror(qreal axis_x) {
// at first: rotate the text:
QGraphicsObject::setRotation(QET::correctAngle(360-rotation(), true));
// then see, where we need to re-position depending on the angle!
qreal rot = qRound(QET::correctAngle(rotation(), true));
qreal c = qCos(qDegreesToRadians(rot));
qreal s = qSin(qDegreesToRadians(rot));
- qreal x = (-1) * pos().x() - c * boundingRect().width();
+ qreal x = 2 * axis_x - pos().x() - c * boundingRect().width();
qreal y = pos().y() - s * boundingRect().width();
setPos(x, y);
}
-void PartDynamicTextField::flip() {
+void PartDynamicTextField::flip(qreal axis_y) {
// at first: rotate the text:
QGraphicsObject::setRotation(QET::correctAngle(360-rotation(), true));
// then see, where we need to re-position depending on the angle!
@@ -94,7 +94,7 @@ void PartDynamicTextField::flip() {
qreal c = qCos(qDegreesToRadians(rot));
qreal s = qSin(qDegreesToRadians(rot));
qreal x = pos().x() + s * boundingRect().height();
- qreal y = (-1) * pos().y() - c * boundingRect().height();
+ qreal y = 2 * axis_y - pos().y() - c * boundingRect().height();
setPos(x, y);
}
diff --git a/sources/editor/graphicspart/partdynamictextfield.h b/sources/editor/graphicspart/partdynamictextfield.h
index 4fdf0d700..1b730639b 100644
--- a/sources/editor/graphicspart/partdynamictextfield.h
+++ b/sources/editor/graphicspart/partdynamictextfield.h
@@ -106,8 +106,8 @@ class PartDynamicTextField : public QGraphicsTextItem, public CustomElementPart
bool rotationPointCenter() const;
void setRotation(qreal angle);
- void mirror();
- void flip();
+ void mirror(qreal axis_x = 0);
+ void flip(qreal axis_y = 0);
protected:
diff --git a/sources/editor/graphicspart/partellipse.cpp b/sources/editor/graphicspart/partellipse.cpp
index 4cf3a4f10..dc19d6102 100644
--- a/sources/editor/graphicspart/partellipse.cpp
+++ b/sources/editor/graphicspart/partellipse.cpp
@@ -256,9 +256,9 @@ qreal PartEllipse::rotation() const {
return qRound(m_rot * 100.0) / 100.0;
}
-void PartEllipse::flip() {
+void PartEllipse::flip(qreal axis_y) {
auto p1 = mapToScene(m_rect.x(), m_rect.y());
- p1.setY(((-1.0) * p1.y()) - m_rect.height());
+ p1.setY(2 * axis_y - p1.y() - m_rect.height());
p1 = mapFromScene(p1.x(), p1.y());
m_rect = QRectF(p1.x(), p1.y(), m_rect.width(), m_rect.height());
prepareGeometryChange();
@@ -266,9 +266,9 @@ void PartEllipse::flip() {
emit rectChanged();
}
-void PartEllipse::mirror() {
+void PartEllipse::mirror(qreal axis_x) {
auto p1 = mapToScene(m_rect.x(), m_rect.y());
- p1.setX(((-1.0) * p1.x()) - m_rect.width());
+ p1.setX(2 * axis_x - p1.x() - m_rect.width());
p1 = mapFromScene(p1.x(), p1.y());
m_rect = QRectF(p1.x(), p1.y(), m_rect.width(), m_rect.height());
prepareGeometryChange();
diff --git a/sources/editor/graphicspart/partellipse.h b/sources/editor/graphicspart/partellipse.h
index e566a1f16..477aa3e8c 100644
--- a/sources/editor/graphicspart/partellipse.h
+++ b/sources/editor/graphicspart/partellipse.h
@@ -62,8 +62,8 @@ class PartEllipse : public AbstractPartEllipse
void setRect(const QRectF &rect) override {AbstractPartEllipse::setRect(rect); adjustHandlerPos();}
void setRotation(qreal angle);
qreal rotation() const;
- void flip();
- void mirror();
+ void flip(qreal axis_y = 0);
+ void mirror(qreal axis_x = 0);
void addHandler() override;
void removeHandler() override;
diff --git a/sources/editor/graphicspart/partline.cpp b/sources/editor/graphicspart/partline.cpp
index c0d86bc57..cf71406b1 100644
--- a/sources/editor/graphicspart/partline.cpp
+++ b/sources/editor/graphicspart/partline.cpp
@@ -590,11 +590,11 @@ qreal PartLine::rotation() const {
return qRound(m_rot * 100.0) / 100.0;
}
-void PartLine::flip() {
+void PartLine::flip(qreal axis_y) {
auto p1 = mapToScene(m_line.p1());
auto p2 = mapToScene(m_line.p2());
- p1 = QPointF(p1.x(), (-1) * p1.y());
- p2 = QPointF(p2.x(), (-1) * p2.y());
+ p1 = QPointF(p1.x(), 2 * axis_y - p1.y());
+ p2 = QPointF(p2.x(), 2 * axis_y - p2.y());
m_line.setP1(mapFromScene(p1));
m_line.setP2(mapFromScene(p2));
setLine(m_line);
@@ -603,11 +603,11 @@ void PartLine::flip() {
emit lineChanged();
}
-void PartLine::mirror() {
+void PartLine::mirror(qreal axis_x) {
auto p1 = mapToScene(m_line.p1());
auto p2 = mapToScene(m_line.p2());
- p1 = QPointF((-1) * p1.x(), p1.y());
- p2 = QPointF((-1) * p2.x(), p2.y());
+ p1 = QPointF(2 * axis_x - p1.x(), p1.y());
+ p2 = QPointF(2 * axis_x - p2.x(), p2.y());
m_line.setP1(mapFromScene(p1));
m_line.setP2(mapFromScene(p2));
setLine(m_line);
diff --git a/sources/editor/graphicspart/partline.h b/sources/editor/graphicspart/partline.h
index dfbb361d5..1e3082a53 100644
--- a/sources/editor/graphicspart/partline.h
+++ b/sources/editor/graphicspart/partline.h
@@ -96,8 +96,8 @@ class PartLine : public CustomElementGraphicPart
void setSecondEndLength(const qreal &l);
void setRotation(qreal angle);
qreal rotation() const;
- void flip();
- void mirror();
+ void flip(qreal axis_y = 0);
+ void mirror(qreal axis_x = 0);
void addHandler() override;
void removeHandler() override;
diff --git a/sources/editor/graphicspart/partpolygon.cpp b/sources/editor/graphicspart/partpolygon.cpp
index eceae2bb2..eb96837e4 100644
--- a/sources/editor/graphicspart/partpolygon.cpp
+++ b/sources/editor/graphicspart/partpolygon.cpp
@@ -307,10 +307,10 @@ qreal PartPolygon::rotation() const {
return qRound(m_rot * 100.0) / 100.0;
}
-void PartPolygon::flip() {
+void PartPolygon::flip(qreal axis_y) {
for (auto &pt : m_polygon) {
pt = mapToScene(pt.x(), pt.y());
- pt = QPointF(pt.x(), (-1) * pt.y());
+ pt = QPointF(pt.x(), 2 * axis_y - pt.y());
pt = mapFromScene(pt.x(), pt.y());
}
setPolygon(m_polygon);
@@ -319,10 +319,10 @@ void PartPolygon::flip() {
emit polygonChanged();
}
-void PartPolygon::mirror() {
+void PartPolygon::mirror(qreal axis_x) {
for (auto &pt : m_polygon) {
pt = mapToScene(pt.x(), pt.y());
- pt = QPointF((-1) * pt.x(), pt.y());
+ pt = QPointF(2 * axis_x - pt.x(), pt.y());
pt = mapFromScene(pt.x(), pt.y());
}
setPolygon(m_polygon);
diff --git a/sources/editor/graphicspart/partpolygon.h b/sources/editor/graphicspart/partpolygon.h
index f8a67f18c..bee786be4 100644
--- a/sources/editor/graphicspart/partpolygon.h
+++ b/sources/editor/graphicspart/partpolygon.h
@@ -89,8 +89,8 @@ class PartPolygon : public CustomElementGraphicPart
void setRotation (qreal angle);
qreal rotation () const;
- void flip();
- void mirror();
+ void flip(qreal axis_y = 0);
+ void mirror(qreal axis_x = 0);
void addHandler() override;
void removeHandler() override;
diff --git a/sources/editor/graphicspart/partrectangle.cpp b/sources/editor/graphicspart/partrectangle.cpp
index 78fa726e3..e1955b1b9 100644
--- a/sources/editor/graphicspart/partrectangle.cpp
+++ b/sources/editor/graphicspart/partrectangle.cpp
@@ -187,11 +187,11 @@ qreal PartRectangle::rotation() const {
return qRound(m_rot * 100.0) / 100.0;
}
-void PartRectangle::flip() {
+void PartRectangle::flip(qreal axis_y) {
auto height = m_rect.height();
auto p1 = mapToScene(m_rect.x(),m_rect.y());
qreal x = p1.x();
- qreal y = ((-1.0) * p1.y()) - height;
+ qreal y = 2 * axis_y - p1.y() - height;
p1 = mapFromScene(x, y);
m_rect.setX(p1.x());
m_rect.setY(p1.y());
@@ -201,10 +201,10 @@ void PartRectangle::flip() {
emit rectChanged();
}
-void PartRectangle::mirror() {
+void PartRectangle::mirror(qreal axis_x) {
auto width = m_rect.width();
auto p1 = mapToScene(m_rect.x(),m_rect.y());
- qreal x = ((-1.0) * p1.x()) - width;
+ qreal x = 2 * axis_x - p1.x() - width;
qreal y = p1.y();
p1 = mapFromScene(x, y);
m_rect.setX(p1.x());
diff --git a/sources/editor/graphicspart/partrectangle.h b/sources/editor/graphicspart/partrectangle.h
index 00ed2bc39..c2d259f77 100644
--- a/sources/editor/graphicspart/partrectangle.h
+++ b/sources/editor/graphicspart/partrectangle.h
@@ -73,8 +73,8 @@ class PartRectangle : public CustomElementGraphicPart
void setYRadius(qreal Y);
void setRotation(qreal angle);
qreal rotation() const;
- void flip();
- void mirror();
+ void flip(qreal axis_y = 0);
+ void mirror(qreal axis_x = 0);
QRectF sceneGeometricRect() const override;
virtual QPointF sceneTopLeft() const;
diff --git a/sources/editor/graphicspart/partterminal.cpp b/sources/editor/graphicspart/partterminal.cpp
index 194ae0aec..0b85ba026 100644
--- a/sources/editor/graphicspart/partterminal.cpp
+++ b/sources/editor/graphicspart/partterminal.cpp
@@ -293,9 +293,9 @@ qreal PartTerminal::rotation() const {
@brief PartTerminal::flip
turn part upside down
*/
-void PartTerminal::flip() {
+void PartTerminal::flip(qreal axis_y) {
d->m_pos.setX( pos().x());
- d->m_pos.setY((-1.0) * pos().y());
+ d->m_pos.setY(2 * axis_y - pos().y());
switch (d->m_orientation) {
case Qet::North : setOrientation(Qet::South);
break;
@@ -314,8 +314,8 @@ void PartTerminal::flip() {
@brief PartTerminal::mirror
turn part from left to right
*/
-void PartTerminal::mirror() {
- d->m_pos.setX((-1.0) * pos().x());
+void PartTerminal::mirror(qreal axis_x) {
+ d->m_pos.setX(2 * axis_x - pos().x());
d->m_pos.setY( pos().y());
switch (d->m_orientation) {
case Qet::North : break;
diff --git a/sources/editor/graphicspart/partterminal.h b/sources/editor/graphicspart/partterminal.h
index d0ba05da9..1ef413cd6 100644
--- a/sources/editor/graphicspart/partterminal.h
+++ b/sources/editor/graphicspart/partterminal.h
@@ -96,8 +96,8 @@ class PartTerminal : public CustomElementGraphicPart
void setRotation(qreal angle);
qreal rotation() const;
- void flip();
- void mirror();
+ void flip(qreal axis_y = 0);
+ void mirror(qreal axis_x = 0);
void nextOrientation();
void previousOrientation();
diff --git a/sources/editor/graphicspart/parttext.cpp b/sources/editor/graphicspart/parttext.cpp
index ae6d97277..47d3007af 100644
--- a/sources/editor/graphicspart/parttext.cpp
+++ b/sources/editor/graphicspart/parttext.cpp
@@ -75,7 +75,7 @@ void PartText::setRotation(qreal angle) {
setPos(QTransform().rotate(diffAngle).map(pos()));
}
-void PartText::mirror() {
+void PartText::mirror(qreal axis_x) {
// at first: rotate the text:
QGraphicsObject::setRotation(QET::correctAngle((360-rotation()), true));
// then see, where we need to re-position depending on text, font ...
@@ -86,12 +86,12 @@ void PartText::mirror() {
qreal c = qCos(qDegreesToRadians(rot));
qreal s = qSin(qDegreesToRadians(rot));
// Now: Move!
- qreal x = (-1) * pos().x() - c * (textwidth);
+ qreal x = 2 * axis_x - pos().x() - c * (textwidth);
qreal y = pos().y() - s * (textwidth);
setPos(x, y);
}
-void PartText::flip() {
+void PartText::flip(qreal axis_y) {
// at first: rotate the text:
QGraphicsObject::setRotation(QET::correctAngle((360-rotation()), true));
// then see, where we need to re-position depending on text, font ...
@@ -103,7 +103,7 @@ void PartText::flip() {
qreal s = qSin(qDegreesToRadians(rot));
// Now: Move!
qreal x = pos().x() - s * (textheight);
- qreal y = (-1) * pos().y() + c * (textheight);
+ qreal y = 2 * axis_y - pos().y() + c * (textheight);
setPos(x, y);
}
diff --git a/sources/editor/graphicspart/parttext.h b/sources/editor/graphicspart/parttext.h
index 4ba66f7c8..29609440e 100644
--- a/sources/editor/graphicspart/parttext.h
+++ b/sources/editor/graphicspart/parttext.h
@@ -64,8 +64,8 @@ class PartText : public QGraphicsTextItem, public CustomElementPart {
void fromXml(const QDomElement &) override;
const QDomElement toXml(QDomDocument &) const override;
void setRotation(qreal angle);
- void mirror();
- void flip();
+ void mirror(qreal axis_x = 0);
+ void flip(qreal axis_y = 0);
bool isUseless() const override;
QRectF sceneGeometricRect() const override;
void startUserTransformation(const QRectF &) override;