diff --git a/sources/editor/editorcommands.cpp b/sources/editor/editorcommands.cpp index b452c9df2..87d7cc706 100644 --- a/sources/editor/editorcommands.cpp +++ b/sources/editor/editorcommands.cpp @@ -541,11 +541,19 @@ void RotateElementsCommand::undo() } else if (item->type() == PartLine::Type) { PartLine* line = qgraphicsitem_cast(item); - line->setRotation(line->rotation()-90); + line->setRotation(-90); } else if (item->type() == PartPolygon::Type) { PartPolygon* poly = qgraphicsitem_cast(item); - poly->setRotation(poly->rotation()-90); + poly->setRotation(-90); + } + else if (item->type() == PartText::Type) { + PartText* text = qgraphicsitem_cast(item); + text->setRotation(-90); + } + else if (item->type() == PartDynamicTextField::Type) { + PartDynamicTextField* dyntext = qgraphicsitem_cast(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(item); - line->setRotation(line->rotation()+90); + line->setRotation(+90); } else if (item->type() == PartPolygon::Type) { PartPolygon* poly = qgraphicsitem_cast(item); - poly->setRotation(poly->rotation()+90); + poly->setRotation(+90); + } + else if (item->type() == PartText::Type) { + PartText* text = qgraphicsitem_cast(item); + text->setRotation(+90); + } + else if (item->type() == PartDynamicTextField::Type) { + PartDynamicTextField* dyntext = qgraphicsitem_cast(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(item); + line->setRotation(-5); + } + else if (item->type() == PartPolygon::Type) { + PartPolygon* poly = qgraphicsitem_cast(item); + poly->setRotation(-5); + } + else if (item->type() == PartText::Type) { + PartText* text = qgraphicsitem_cast(item); + text->setRotation(-5); + } + else if (item->type() == PartDynamicTextField::Type) { + PartDynamicTextField* dyntext = qgraphicsitem_cast(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(item); + line->setRotation(+5); + } + else if (item->type() == PartPolygon::Type) { + PartPolygon* poly = qgraphicsitem_cast(item); + poly->setRotation(+5); + } + else if (item->type() == PartText::Type) { + PartText* text = qgraphicsitem_cast(item); + text->setRotation(+5); + } + else if (item->type() == PartDynamicTextField::Type) { + PartDynamicTextField* dyntext = qgraphicsitem_cast(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(item); + //staticText->mirror(); + } else if (item->type() == PartDynamicTextField::Type) { + PartDynamicTextField* dyntext = qgraphicsitem_cast(item); + dyntext->mirror(); } else if (item->type() == PartArc::Type) { PartArc* arc = qgraphicsitem_cast(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(item); + //staticText->flip(); + } else if (item->type() == PartDynamicTextField::Type) { + PartDynamicTextField* dyntext = qgraphicsitem_cast(item); + dyntext->flip(); } else if (item->type() == PartArc::Type) { PartArc* arc = qgraphicsitem_cast(item); arc->flip(); diff --git a/sources/editor/editorcommands.h b/sources/editor/editorcommands.h index 23c6de8d0..7cb387804 100644 --- a/sources/editor/editorcommands.h +++ b/sources/editor/editorcommands.h @@ -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 m_items; + +}; + class MirrorElementsCommand : public ElementEditionCommand { public: diff --git a/sources/editor/graphicspart/partdynamictextfield.cpp b/sources/editor/graphicspart/partdynamictextfield.cpp index ed426cc2e..bcc25435b 100644 --- a/sources/editor/graphicspart/partdynamictextfield.cpp +++ b/sources/editor/graphicspart/partdynamictextfield.cpp @@ -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); diff --git a/sources/editor/graphicspart/partdynamictextfield.h b/sources/editor/graphicspart/partdynamictextfield.h index 3aa7c519c..07a1996e9 100644 --- a/sources/editor/graphicspart/partdynamictextfield.h +++ b/sources/editor/graphicspart/partdynamictextfield.h @@ -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, diff --git a/sources/editor/graphicspart/partellipse.cpp b/sources/editor/graphicspart/partellipse.cpp index 308e8eebd..ae05841f3 100644 --- a/sources/editor/graphicspart/partellipse.cpp +++ b/sources/editor/graphicspart/partellipse.cpp @@ -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 { diff --git a/sources/editor/graphicspart/partline.cpp b/sources/editor/graphicspart/partline.cpp index 01d9e76af..94c7f8437 100644 --- a/sources/editor/graphicspart/partline.cpp +++ b/sources/editor/graphicspart/partline.cpp @@ -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(); diff --git a/sources/editor/graphicspart/partpolygon.cpp b/sources/editor/graphicspart/partpolygon.cpp index 06061914b..9a3e019f9 100644 --- a/sources/editor/graphicspart/partpolygon.cpp +++ b/sources/editor/graphicspart/partpolygon.cpp @@ -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(); diff --git a/sources/editor/graphicspart/parttext.cpp b/sources/editor/graphicspart/parttext.cpp index d8469f7b2..caad2fa18 100644 --- a/sources/editor/graphicspart/parttext.cpp +++ b/sources/editor/graphicspart/parttext.cpp @@ -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); diff --git a/sources/editor/graphicspart/parttext.h b/sources/editor/graphicspart/parttext.h index fac3be654..d5650c406 100644 --- a/sources/editor/graphicspart/parttext.h +++ b/sources/editor/graphicspart/parttext.h @@ -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 diff --git a/sources/editor/ui/qetelementeditor.cpp b/sources/editor/ui/qetelementeditor.cpp index fc8a226d4..4b510af21 100644 --- a/sources/editor/ui/qetelementeditor.cpp +++ b/sources/editor/ui/qetelementeditor.cpp @@ -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(); diff --git a/sources/editor/ui/qetelementeditor.ui b/sources/editor/ui/qetelementeditor.ui index 9e9d761e7..90cf36118 100644 --- a/sources/editor/ui/qetelementeditor.ui +++ b/sources/editor/ui/qetelementeditor.ui @@ -77,6 +77,7 @@ + @@ -495,6 +496,15 @@ Rotation + + + + :/ico/16x16/orientations.png:/ico/16x16/orientations.png + + + Fine-Rotation + + diff --git a/sources/factory/elementpicturefactory.cpp b/sources/factory/elementpicturefactory.cpp index 522c1a721..5868da77c 100644 --- a/sources/factory/elementpicturefactory.cpp +++ b/sources/factory/elementpicturefactory.cpp @@ -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 diff --git a/sources/qet.cpp b/sources/qet.cpp index b73074f57..3537e24ba 100644 --- a/sources/qet.cpp +++ b/sources/qet.cpp @@ -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