Merge pull request #358 from plc-user/master

some more rotation, mirror and flip
This commit is contained in:
Laurent Trinques
2025-02-16 17:24:33 +01:00
committed by GitHub
13 changed files with 211 additions and 65 deletions

View File

@@ -541,11 +541,19 @@ void RotateElementsCommand::undo()
}
else if (item->type() == PartLine::Type) {
PartLine* line = qgraphicsitem_cast<PartLine*>(item);
line->setRotation(line->rotation()-90);
line->setRotation(-90);
}
else if (item->type() == PartPolygon::Type) {
PartPolygon* poly = qgraphicsitem_cast<PartPolygon*>(item);
poly->setRotation(poly->rotation()-90);
poly->setRotation(-90);
}
else if (item->type() == PartText::Type) {
PartText* text = qgraphicsitem_cast<PartText*>(item);
text->setRotation(-90);
}
else if (item->type() == PartDynamicTextField::Type) {
PartDynamicTextField* dyntext = qgraphicsitem_cast<PartDynamicTextField*>(item);
dyntext->setRotation(-90);
}
else {
item->setRotation(item->rotation()-90);
@@ -578,11 +586,19 @@ void RotateElementsCommand::redo()
}
else if (item->type() == PartLine::Type) {
PartLine* line = qgraphicsitem_cast<PartLine*>(item);
line->setRotation(line->rotation()+90);
line->setRotation(+90);
}
else if (item->type() == PartPolygon::Type) {
PartPolygon* poly = qgraphicsitem_cast<PartPolygon*>(item);
poly->setRotation(poly->rotation()+90);
poly->setRotation(+90);
}
else if (item->type() == PartText::Type) {
PartText* text = qgraphicsitem_cast<PartText*>(item);
text->setRotation(+90);
}
else if (item->type() == PartDynamicTextField::Type) {
PartDynamicTextField* dyntext = qgraphicsitem_cast<PartDynamicTextField*>(item);
dyntext->setRotation(+90);
}
else {
item->setRotation(item->rotation()+90);
@@ -591,6 +607,71 @@ void RotateElementsCommand::redo()
}
RotateFineElementsCommand::RotateFineElementsCommand(ElementScene *scene, QUndoCommand *parent) :
ElementEditionCommand(QObject::tr("Pivoter la selection", "undo caption"), scene, nullptr, parent)
{
m_items = scene->selectedItems();
}
/**
@brief RotateFineElementsCommand::undo
*/
void RotateFineElementsCommand::undo()
{
for (QGraphicsItem *item : m_items)
{
if (item->type() == PartLine::Type) {
PartLine* line = qgraphicsitem_cast<PartLine*>(item);
line->setRotation(-5);
}
else if (item->type() == PartPolygon::Type) {
PartPolygon* poly = qgraphicsitem_cast<PartPolygon*>(item);
poly->setRotation(-5);
}
else if (item->type() == PartText::Type) {
PartText* text = qgraphicsitem_cast<PartText*>(item);
text->setRotation(-5);
}
else if (item->type() == PartDynamicTextField::Type) {
PartDynamicTextField* dyntext = qgraphicsitem_cast<PartDynamicTextField*>(item);
dyntext->setRotation(-5);
}
else {
//item->setRotation(-5);
}
}
}
/**
@brief RotateFineElementsCommand::redo
*/
void RotateFineElementsCommand::redo()
{
for (QGraphicsItem *item : m_items)
{
if (item->type() == PartLine::Type) {
PartLine* line = qgraphicsitem_cast<PartLine*>(item);
line->setRotation(+5);
}
else if (item->type() == PartPolygon::Type) {
PartPolygon* poly = qgraphicsitem_cast<PartPolygon*>(item);
poly->setRotation(+5);
}
else if (item->type() == PartText::Type) {
PartText* text = qgraphicsitem_cast<PartText*>(item);
text->setRotation(+5);
}
else if (item->type() == PartDynamicTextField::Type) {
PartDynamicTextField* dyntext = qgraphicsitem_cast<PartDynamicTextField*>(item);
dyntext->setRotation(+5);
}
else {
//item->setRotation(+5);
}
}
}
MirrorElementsCommand::MirrorElementsCommand(ElementScene *scene, QUndoCommand *parent) :
ElementEditionCommand(QObject::tr("Miroir de sélection", "undo caption"), scene, nullptr, parent)
{
@@ -603,9 +684,12 @@ ElementEditionCommand(QObject::tr("Miroir de sélection", "undo caption"), scene
void MirrorElementsCommand::redo()
{
foreach (auto *item, m_items) {
if ((item->type() == PartText::Type) ||
(item->type() == PartDynamicTextField::Type)) {
continue;
if (item->type() == PartText::Type) {
PartText* staticText = qgraphicsitem_cast<PartText*>(item);
//staticText->mirror();
} else if (item->type() == PartDynamicTextField::Type) {
PartDynamicTextField* dyntext = qgraphicsitem_cast<PartDynamicTextField*>(item);
dyntext->mirror();
} else if (item->type() == PartArc::Type) {
PartArc* arc = qgraphicsitem_cast<PartArc*>(item);
arc->mirror();
@@ -648,9 +732,12 @@ ElementEditionCommand(QObject::tr("Retourner la sélection", "undo caption"), sc
void FlipElementsCommand::redo()
{
foreach (auto *item, m_items) {
if ((item->type() == PartText::Type) ||
(item->type() == PartDynamicTextField::Type)) {
continue;
if (item->type() == PartText::Type) {
PartText* staticText = qgraphicsitem_cast<PartText*>(item);
//staticText->flip();
} else if (item->type() == PartDynamicTextField::Type) {
PartDynamicTextField* dyntext = qgraphicsitem_cast<PartDynamicTextField*>(item);
dyntext->flip();
} else if (item->type() == PartArc::Type) {
PartArc* arc = qgraphicsitem_cast<PartArc*>(item);
arc->flip();

View File

@@ -265,6 +265,20 @@ private:
};
class RotateFineElementsCommand : public ElementEditionCommand
{
public:
RotateFineElementsCommand(ElementScene *scene, QUndoCommand *parent=nullptr);
void undo() override;
void redo() override;
private:
ElementScene *m_scene =nullptr;
QList<QGraphicsItem*> m_items;
};
class MirrorElementsCommand : public ElementEditionCommand
{
public:

View File

@@ -33,7 +33,7 @@ PartDynamicTextField::PartDynamicTextField(QETElementEditor *editor, QGraphicsIt
setDefaultTextColor(Qt::black);
setFont(QETApp::dynamicTextsItemFont());
QSettings settings;
setRotation(settings.value("diagrameditor/dynamic_text_rotation", 0).toInt());
QGraphicsObject::setRotation(QET::correctAngle(settings.value("diagrameditor/dynamic_text_rotation", 0).toInt()));
setTextWidth(settings.value("diagrameditor/dynamic_text_width", -1).toInt());
setText("_");
setTextFrom(DynamicElementTextItem::UserText);
@@ -60,6 +60,41 @@ QString PartDynamicTextField::xmlName() const
return QString("dynamic_text");
}
/**
Redefines setRotation
@param angle
*/
void PartDynamicTextField::setRotation(qreal angle) {
QGraphicsObject::setRotation(QET::correctAngle(rotation()+angle, true));
setPos(QTransform().rotate(angle).map(pos()));
}
void PartDynamicTextField::mirror() {
// 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 y = pos().y() - s * boundingRect().width();
setPos(x, y);
}
void PartDynamicTextField::flip() {
// 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 = pos().x() + s * boundingRect().height();
qreal y = (-1) * pos().y() - c * boundingRect().height();
setPos(x, y);
}
/**
@brief PartDynamicTextField::startUserTransformation
@param initial_selection_rect
@@ -172,7 +207,7 @@ void PartDynamicTextField::fromXml(const QDomElement &dom_elmt) {
dom_elmt.attribute("y", QString::number(0)).toDouble()
);
setZValue(dom_elmt.attribute("z", QString::number(zValue())).toDouble());
QGraphicsTextItem::setRotation(dom_elmt.attribute("rotation", QString::number(0)).toDouble());
QGraphicsObject::setRotation(QET::correctAngle(dom_elmt.attribute("rotation", QString::number(0)).toDouble()));
setKeepVisualRotation(dom_elmt.attribute("keep_visual_rotation", "true") == "true"? true : false);
if (dom_elmt.hasAttribute("font")) {
@@ -255,7 +290,7 @@ void PartDynamicTextField::fromTextFieldXml(const QDomElement &dom_element)
setInfoName(dom_element.attribute("tagg", "label"));
}
QGraphicsTextItem::setRotation(dom_element.attribute("rotation", "0").toDouble());
QGraphicsObject::setRotation(QET::correctAngle(dom_element.attribute("rotation", "0").toDouble()));
//the origin transformation point of PartDynamicTextField is the top left corner, no matter the font size
//The origin transformation point of PartTextField is the middle of left edge, and so by definition, change with the size of the font
@@ -460,7 +495,7 @@ bool PartDynamicTextField::keepVisualRotation() const {
*/
void PartDynamicTextField::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
if((event -> buttons() & Qt::LeftButton) && (flags() & QGraphicsItem::ItemIsMovable)) {
QPointF pos = event -> scenePos() + (m_origine_pos - event -> buttonDownScenePos(Qt::LeftButton));
QPointF pos = event -> scenePos() + (m_origin_pos - event -> buttonDownScenePos(Qt::LeftButton));
event -> modifiers() == Qt::ControlModifier ? setPos(pos) : setPos(elementScene() -> snapToGrid(pos));
}
else
@@ -473,7 +508,7 @@ void PartDynamicTextField::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
*/
void PartDynamicTextField::mousePressEvent(QGraphicsSceneMouseEvent *event) {
if(event -> button() == Qt::LeftButton)
m_origine_pos = this -> pos();
m_origin_pos = this -> pos();
QGraphicsObject::mousePressEvent(event);
}
@@ -485,9 +520,9 @@ void PartDynamicTextField::mousePressEvent(QGraphicsSceneMouseEvent *event) {
void PartDynamicTextField::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
if((event -> button() & Qt::LeftButton) &&
(flags() & QGraphicsItem::ItemIsMovable) &&
m_origine_pos != pos()) {
m_origin_pos != pos()) {
QPropertyUndoCommand *undo =\
new QPropertyUndoCommand(this, "pos", QVariant(m_origine_pos), QVariant(pos()));
new QPropertyUndoCommand(this, "pos", QVariant(m_origin_pos), QVariant(pos()));
undo -> setText(tr("Déplacer un champ texte"));
undo -> enableAnimation();
elementScene() -> undoStack().push(undo);

View File

@@ -101,6 +101,11 @@ class PartDynamicTextField : public QGraphicsTextItem, public CustomElementPart
void setKeepVisualRotation(const bool &keep);
bool keepVisualRotation() const;
void setRotation(qreal angle);
void mirror();
void flip();
protected:
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
@@ -114,7 +119,7 @@ class PartDynamicTextField : public QGraphicsTextItem, public CustomElementPart
void finishAlignment();
private:
QPointF m_origine_pos,
QPointF m_origin_pos,
m_saved_point;
QString m_text,
m_info_name,

View File

@@ -251,10 +251,10 @@ void PartEllipse::setRotation(qreal angle) {
qreal x = m_rect.y();
qreal y = (m_rect.x() + m_rect.width()) * (-1);
m_rect = QRectF(x, y, width, height);
}
prepareGeometryChange();
adjustHandlerPos();
emit rectChanged();
}
prepareGeometryChange();
adjustHandlerPos();
emit rectChanged();
}
qreal PartEllipse::rotation() const {

View File

@@ -579,26 +579,9 @@ void PartLine::setSecondEndLength(const qreal &l)
}
void PartLine::setRotation(qreal angle) {
double tmp, x, y;
if (angle > 0) {
tmp = m_line.p1().y();
y = m_line.p1().x();
x = (-1) * tmp;
m_line.setP1(QPointF(x, y));
tmp = m_line.p2().y();
y = m_line.p2().x();
x = (-1) * tmp;
m_line.setP2(QPointF(x, y));
} else {
tmp = m_line.p1().x();
x = m_line.p1().y();
y = (-1) * tmp;
m_line.setP1(QPointF(x, y));
tmp = m_line.p2().x();
x = m_line.p2().y();
y = (-1) * tmp;
m_line.setP2(QPointF(x, y));
}
m_rot += angle;
m_line.setP1(QTransform().rotate(angle).map(m_line.p1()));
m_line.setP2(QTransform().rotate(angle).map(m_line.p2()));
prepareGeometryChange();
setLine(m_line);
adjustHandlerPos();

View File

@@ -297,21 +297,9 @@ void PartPolygon::resetAllHandlerColor()
void PartPolygon::setRotation(qreal angle) {
for (auto &punkt : m_polygon) {
double tmp, x, y;
if (angle > 0) {
tmp = punkt.y();
y = punkt.x();
x = (-1) * tmp;
} else {
tmp = punkt.x();
x = punkt.y();
y = (-1) * tmp;
}
punkt = QPointF(x, y);
}
setPolygon(m_polygon);
QTransform rotation = QTransform().rotate(angle);
m_rot += angle;
setPolygon(rotation.map(m_polygon));
prepareGeometryChange();
adjustHandlerPos();
emit polygonChanged();

View File

@@ -63,6 +63,15 @@ PartText::~PartText()
{
}
/**
Redefines setRotation
@param angle
*/
void PartText::setRotation(qreal angle) {
QGraphicsObject::setRotation(QET::correctAngle(rotation()+angle, true));
setPos(QTransform().rotate(angle).map(pos()));
}
/**
Importe les proprietes d'un texte statique depuis un element XML
@param xml_element Element XML a lire
@@ -89,7 +98,7 @@ void PartText::fromXml(const QDomElement &xml_element) {
setPlainText(xml_element.attribute("text"));
setPos(xml_element.attribute("x").toDouble(),
xml_element.attribute("y").toDouble());
setRotation(xml_element.attribute("rotation", QString::number(0)).toDouble());
QGraphicsObject::setRotation(QET::correctAngle(xml_element.attribute("rotation", QString::number(0)).toDouble()));
}
/**
@@ -116,6 +125,7 @@ const QDomElement PartText::toXml(QDomDocument &xml_document) const
/**
@return Les coordonnees du point situe en bas a gauche du texte.
The coordinates of the point at the bottom left of the text.
*/
QPointF PartText::margin() const
{
@@ -124,8 +134,10 @@ QPointF PartText::margin() const
qreal document_margin = document() -> documentMargin();
QPointF margin(
// margin around the text
// marge autour du texte
document_margin,
// margin above the text + distance between the top of the text and the baseline
// marge au-dessus du texte + distance entre le plafond du texte et la baseline
document_margin + qfm.ascent()
);
@@ -273,7 +285,7 @@ void PartText::setFont(const QFont &font) {
void PartText::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
if((event -> buttons() & Qt::LeftButton) && (flags() & QGraphicsItem::ItemIsMovable)) {
QPointF pos = event -> scenePos() + (m_origine_pos - event -> buttonDownScenePos(Qt::LeftButton));
QPointF pos = event -> scenePos() + (m_origin_pos - event -> buttonDownScenePos(Qt::LeftButton));
event -> modifiers() == Qt::ControlModifier ? setPos(pos) : setPos(elementScene() -> snapToGrid(pos));
}
else {
@@ -283,7 +295,7 @@ void PartText::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
void PartText::mousePressEvent(QGraphicsSceneMouseEvent *event) {
if(event -> button() == Qt::LeftButton)
m_origine_pos = this -> pos();
m_origin_pos = this -> pos();
QGraphicsObject::mousePressEvent(event);
}
@@ -291,9 +303,9 @@ void PartText::mousePressEvent(QGraphicsSceneMouseEvent *event) {
void PartText::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
if((event -> button() & Qt::LeftButton) &&
(flags() & QGraphicsItem::ItemIsMovable) &&
m_origine_pos != pos())
m_origin_pos != pos())
{
QPropertyUndoCommand *undo = new QPropertyUndoCommand(this, "pos", QVariant(m_origine_pos), QVariant(pos()));
QPropertyUndoCommand *undo = new QPropertyUndoCommand(this, "pos", QVariant(m_origin_pos), QVariant(pos()));
undo -> setText(tr("Déplacer un texte"));
undo -> enableAnimation();
elementScene() -> undoStack().push(undo);

View File

@@ -61,7 +61,7 @@ class PartText : public QGraphicsTextItem, public CustomElementPart {
QString xmlName() const override { return(QString("text")); }
void fromXml(const QDomElement &) override;
const QDomElement toXml(QDomDocument &) const override;
void setRotation(qreal angle) {(QGraphicsObject::setRotation(QET::correctAngle(angle)));}
void setRotation(qreal angle);
bool isUseless() const override;
QRectF sceneGeometricRect() const override;
void startUserTransformation(const QRectF &) override;
@@ -100,6 +100,6 @@ class PartText : public QGraphicsTextItem, public CustomElementPart {
QPointF saved_point_;
qreal saved_font_size_;
QGraphicsItem *decorator_;
QPointF m_origine_pos;
QPointF m_origin_pos;
};
#endif

View File

@@ -1002,6 +1002,10 @@ void QETElementEditor::setupActions()
ui->m_rotate_action -> setShortcut(Qt::Key_Space);
connect(ui->m_rotate_action, &QAction::triggered, [this]() {this -> elementScene() -> undoStack().push(new RotateElementsCommand(this->elementScene()));});
//Rotate Fine action = rotate with smaller inkrement
ui->m_rotateFine_action -> setShortcut(Qt::CTRL | Qt::Key_Space);
connect(ui->m_rotateFine_action, &QAction::triggered, [this]() {this -> elementScene() -> undoStack().push(new RotateFineElementsCommand(this->elementScene()));});
//Flip action
ui->m_flip_action -> setShortcut(Qt::Key_F);
connect(ui->m_flip_action, &QAction::triggered, [this]() {this -> elementScene() -> undoStack().push(new FlipElementsCommand(this->elementScene()));});
@@ -1076,6 +1080,7 @@ void QETElementEditor::updateAction()
<< ui->m_copy_action
<< ui->m_delete_action
<< ui->m_rotate_action
<< ui->m_rotateFine_action
<< ui->m_flip_action
<< ui->m_mirror_action;
auto items_selected = !m_read_only && m_elmt_scene->selectedItems().count();

View File

@@ -77,6 +77,7 @@
<addaction name="m_edit_author_action"/>
<addaction name="m_edit_element_properties_action"/>
<addaction name="m_rotate_action"/>
<addaction name="m_rotateFine_action"/>
<addaction name="m_mirror_action"/>
<addaction name="m_flip_action"/>
</widget>
@@ -495,6 +496,15 @@
<string>Rotation</string>
</property>
</action>
<action name="m_rotateFine_action">
<property name="icon">
<iconset resource="../../../qelectrotech.qrc">
<normaloff>:/ico/16x16/orientations.png</normaloff>:/ico/16x16/orientations.png</iconset>
</property>
<property name="text">
<string>Fine-Rotation</string>
</property>
</action>
<action name="m_mirror_action">
<property name="icon">
<iconset resource="../../../qelectrotech.qrc">

View File

@@ -519,6 +519,10 @@ void ElementPictureFactory::parseText(const QDomElement &dom, QPainter &painter,
painter.rotate(dom.attribute("rotation", "0").toDouble());
/*
Moves the QPainter's coordinate system to render in the right place;
note: the font's ascent() is subtracted to determine the top left
corner of the text, whereas the position indicated corresponds
to the baseline.
Deplace le systeme de coordonnees du QPainter pour effectuer le rendu au
bon endroit ; note : on soustrait l'ascent() de la police pour
determiner le coin superieur gauche du texte alors que la position

View File

@@ -576,8 +576,11 @@ qreal QET::round(qreal x, qreal epsilon) {
}
/**
@param angle Un angle quelconque
@param angle Un angle quelconque / any angle in degrees
@param positive (bool)
@return l'angle passe en parametre, mais ramene entre -360.0 + 360.0 degres
the angle passed as a parameter, but reduced to between -360.0 +360.0 degrees
reduced to 0.0 .. 360.0, when bool-parameter is true
*/
qreal QET::correctAngle(const qreal &angle, const bool &positive) {
// ramene l'angle demande entre -360.0 et +360.0 degres