diff --git a/sources/editor/customelementpart.cpp b/sources/editor/customelementpart.cpp index eeee1a4b8..4a9722884 100644 --- a/sources/editor/customelementpart.cpp +++ b/sources/editor/customelementpart.cpp @@ -43,3 +43,33 @@ ElementScene *CustomElementPart::elementScene() const { QUndoStack &CustomElementPart::undoStack() const { return(elementScene() -> undoStack()); } + +/** + Helper method to map points in CustomElementPart::handleUserTransformation() + @param initial_selection_rect Selection rectangle when the movement started, in scene coordinates + @param new_selection_rect New selection rectangle, in scene coordinates + @param points List of points when the movement started, in scene coordinates. + @return The list of points mapped from initial_selection_rect to new_selection_rect +*/ +QList CustomElementPart::mapPoints(const QRectF &initial_selection_rect, const QRectF &new_selection_rect, const QList &points) { + QList new_points; + if (!points.count()) return(new_points); + + // compare the new selection rectangle with the stored one to get the scaling ratio + qreal sx = new_selection_rect.width() / initial_selection_rect.width(); + qreal sy = new_selection_rect.height() / initial_selection_rect.height(); + + QPointF initial_top_left = initial_selection_rect.topLeft(); + qreal new_top_left_x = new_selection_rect.x(); + qreal new_top_left_y = new_selection_rect.y(); + + foreach (QPointF point, points) { + QPointF point_offset = point - initial_top_left; + new_points << QPointF( + new_top_left_x + (point_offset.rx() * sx), + new_top_left_y + (point_offset.y() * sy) + ); + } + + return(new_points); +} diff --git a/sources/editor/customelementpart.h b/sources/editor/customelementpart.h index 29af22510..b2f1c85ad 100644 --- a/sources/editor/customelementpart.h +++ b/sources/editor/customelementpart.h @@ -71,6 +71,14 @@ class CustomElementPart { Typically, useless primitives are discarded when saving the element. */ virtual bool isUseless() const = 0; + /** + Inform this part a user-induced transformation is about to begin. This method can be used to save data required by handleUserTransformation(). + */ + virtual void startUserTransformation(const QRectF &) = 0; + /** + Make this part fit into the provided rectangle. + */ + virtual void handleUserTransformation(const QRectF &, const QRectF &) = 0; /// @return a pointer to the parent element editor virtual QETElementEditor *elementEditor() const; /** @@ -86,5 +94,8 @@ class CustomElementPart { virtual QString name() const = 0; /// @return the name that will be used as XML tag when exporting the primitive virtual QString xmlName() const = 0; + + protected: + QList mapPoints(const QRectF &, const QRectF &, const QList &); }; #endif diff --git a/sources/editor/partarc.cpp b/sources/editor/partarc.cpp index fc0ff4d55..35a92aabf 100644 --- a/sources/editor/partarc.cpp +++ b/sources/editor/partarc.cpp @@ -256,6 +256,24 @@ bool PartArc::isUseless() const { return(rect().isNull() || !angle()); } +/** + Start the user-induced transformation, provided this primitive is contained + within the \a initial_selection_rect bounding rectangle. +*/ +void PartArc::startUserTransformation(const QRectF &initial_selection_rect) { + Q_UNUSED(initial_selection_rect) + saved_points_.clear(); + saved_points_ << mapToScene(rect().topLeft()) << mapToScene(rect().bottomRight()); +} + +/** + Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect +*/ +void PartArc::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) { + QList mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_); + setRect(QRectF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1)))); +} + /** @return le rectangle delimitant cette partie. */ diff --git a/sources/editor/partarc.h b/sources/editor/partarc.h index f61d66736..a3ade5eef 100644 --- a/sources/editor/partarc.h +++ b/sources/editor/partarc.h @@ -60,8 +60,13 @@ class PartArc : public QGraphicsEllipseItem, public CustomElementGraphicPart { virtual void setProperty(const QString &, const QVariant &); virtual QVariant property(const QString &); virtual bool isUseless() const; + virtual void startUserTransformation(const QRectF &); + virtual void handleUserTransformation(const QRectF &, const QRectF &); protected: QVariant itemChange(GraphicsItemChange, const QVariant &); + + private: + QList saved_points_; }; #endif diff --git a/sources/editor/partcircle.cpp b/sources/editor/partcircle.cpp index e7c417ca8..2fa93f107 100644 --- a/sources/editor/partcircle.cpp +++ b/sources/editor/partcircle.cpp @@ -198,3 +198,30 @@ QRectF PartCircle::boundingRect() const { bool PartCircle::isUseless() const { return(rect().isNull()); } + +/** + Start the user-induced transformation, provided this primitive is contained + within the \a initial_selection_rect bounding rectangle. +*/ +void PartCircle::startUserTransformation(const QRectF &initial_selection_rect) { + Q_UNUSED(initial_selection_rect) + saved_center_ = mapToScene(rect().center()); + saved_diameter_ = rect().width(); +} + +/** + Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect +*/ +void PartCircle::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) { + QPointF new_center = mapPoints(initial_selection_rect, new_selection_rect, QList() << saved_center_).first(); + + qreal sx = new_selection_rect.width() / initial_selection_rect.width(); + qreal sy = new_selection_rect.height() / initial_selection_rect.height(); + qreal smallest_scale_factor = sx > sy ? sy : sx; + qreal new_diameter = saved_diameter_ * smallest_scale_factor; + + QRectF new_rect(QPointF(), QSizeF(new_diameter, new_diameter)); + new_rect.moveCenter(mapFromScene(new_center)); + + setRect(new_rect); +} diff --git a/sources/editor/partcircle.h b/sources/editor/partcircle.h index 21015215f..62b9e1e77 100644 --- a/sources/editor/partcircle.h +++ b/sources/editor/partcircle.h @@ -52,8 +52,14 @@ class PartCircle : public QGraphicsEllipseItem, public CustomElementGraphicPart virtual void setProperty(const QString &, const QVariant &); virtual QVariant property(const QString &); virtual bool isUseless() const; + virtual void startUserTransformation(const QRectF &); + virtual void handleUserTransformation(const QRectF &, const QRectF &); protected: QVariant itemChange(GraphicsItemChange, const QVariant &); + + private: + QPointF saved_center_; + qreal saved_diameter_; }; #endif diff --git a/sources/editor/partellipse.cpp b/sources/editor/partellipse.cpp index 2d677b1ca..fd7fda21b 100644 --- a/sources/editor/partellipse.cpp +++ b/sources/editor/partellipse.cpp @@ -189,6 +189,25 @@ bool PartEllipse::isUseless() const { return(rect().isNull()); } +/** + Start the user-induced transformation, provided this primitive is contained + within the \a initial_selection_rect bounding rectangle. +*/ +void PartEllipse::startUserTransformation(const QRectF &initial_selection_rect) { + Q_UNUSED(initial_selection_rect) + // we keep track of our own rectangle at the moment in scene coordinates too + saved_points_.clear(); + saved_points_ << mapToScene(rect().topLeft()) << mapToScene(rect().bottomRight()); +} + +/** + Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect +*/ +void PartEllipse::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) { + QList mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_); + setRect(QRectF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1)))); +} + /** @return le rectangle delimitant cette partie. */ diff --git a/sources/editor/partellipse.h b/sources/editor/partellipse.h index dfaa35c67..c9673759c 100644 --- a/sources/editor/partellipse.h +++ b/sources/editor/partellipse.h @@ -51,8 +51,13 @@ class PartEllipse : public QGraphicsEllipseItem, public CustomElementGraphicPart virtual void setProperty(const QString &, const QVariant &); virtual QVariant property(const QString &); virtual bool isUseless() const; + virtual void startUserTransformation(const QRectF &); + virtual void handleUserTransformation(const QRectF &, const QRectF &); protected: QVariant itemChange(GraphicsItemChange, const QVariant &); + + private: + QList saved_points_; }; #endif diff --git a/sources/editor/partline.cpp b/sources/editor/partline.cpp index 897b52d5b..9c471876a 100644 --- a/sources/editor/partline.cpp +++ b/sources/editor/partline.cpp @@ -476,6 +476,24 @@ bool PartLine::isUseless() const { return(sceneP1() == sceneP2()); } +/** + Start the user-induced transformation, provided this primitive is contained + within the \a initial_selection_rect bounding rectangle. +*/ +void PartLine::startUserTransformation(const QRectF &initial_selection_rect) { + Q_UNUSED(initial_selection_rect) + saved_points_.clear(); + saved_points_ << sceneP1() << sceneP2(); +} + +/** + Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect +*/ +void PartLine::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) { + QList mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_); + setLine(QLineF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1)))); +} + /** @param end_type nouveau type d'embout pour l'extremite 1 */ diff --git a/sources/editor/partline.h b/sources/editor/partline.h index c294f208f..0f5292648 100644 --- a/sources/editor/partline.h +++ b/sources/editor/partline.h @@ -44,6 +44,7 @@ class PartLine : public QGraphicsLineItem, public CustomElementGraphicPart { qreal first_length; QET::EndType second_end; qreal second_length; + QList saved_points_; // methods public: @@ -67,6 +68,8 @@ class PartLine : public QGraphicsLineItem, public CustomElementGraphicPart { virtual void setProperty(const QString &, const QVariant &); virtual QVariant property(const QString &); virtual bool isUseless() const; + virtual void startUserTransformation(const QRectF &); + virtual void handleUserTransformation(const QRectF &, const QRectF &); virtual void setFirstEndType(const QET::EndType &); virtual QET::EndType firstEndType() const; virtual void setSecondEndType(const QET::EndType &); diff --git a/sources/editor/partpolygon.cpp b/sources/editor/partpolygon.cpp index afcb5c650..2c2d4817a 100644 --- a/sources/editor/partpolygon.cpp +++ b/sources/editor/partpolygon.cpp @@ -163,6 +163,23 @@ bool PartPolygon::isUseless() const { return(true); } +/** + Start the user-induced transformation, provided this primitive is contained + within the \a initial_selection_rect bounding rectangle. +*/ +void PartPolygon::startUserTransformation(const QRectF &initial_selection_rect) { + Q_UNUSED(initial_selection_rect) + saved_points_ = mapToScene(polygon()).toList(); +} + +/** + Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect +*/ +void PartPolygon::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) { + QList mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_); + setPolygon(mapFromScene(QPolygonF(mapped_points.toVector()))); +} + /** @return le rectangle delimitant cette partie. */ diff --git a/sources/editor/partpolygon.h b/sources/editor/partpolygon.h index 11d57c72c..62025dca8 100644 --- a/sources/editor/partpolygon.h +++ b/sources/editor/partpolygon.h @@ -56,9 +56,14 @@ class PartPolygon : public QGraphicsPolygonItem, public CustomElementGraphicPart void setProperty(const QString &, const QVariant &); virtual QVariant property(const QString &); virtual bool isUseless() const; + virtual void startUserTransformation(const QRectF &); + virtual void handleUserTransformation(const QRectF &, const QRectF &); protected: QVariant itemChange(GraphicsItemChange, const QVariant &); + + private: + QList saved_points_; }; /** diff --git a/sources/editor/partrectangle.cpp b/sources/editor/partrectangle.cpp index d849b4135..25ebf7955 100644 --- a/sources/editor/partrectangle.cpp +++ b/sources/editor/partrectangle.cpp @@ -196,6 +196,25 @@ bool PartRectangle::isUseless() const { return(rect().isNull()); } +/** + Start the user-induced transformation, provided this primitive is contained + within the \a initial_selection_rect bounding rectangle. +*/ +void PartRectangle::startUserTransformation(const QRectF &initial_selection_rect) { + Q_UNUSED(initial_selection_rect) + // we keep track of our own rectangle at the moment in scene coordinates too + saved_points_.clear(); + saved_points_ << mapToScene(rect().topLeft()) << mapToScene(rect().bottomRight()); +} + +/** + Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect +*/ +void PartRectangle::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) { + QList mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_); + setRect(QRectF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1)))); +} + /** @return le rectangle delimitant cette partie. */ diff --git a/sources/editor/partrectangle.h b/sources/editor/partrectangle.h index c255d29cf..818702e64 100644 --- a/sources/editor/partrectangle.h +++ b/sources/editor/partrectangle.h @@ -51,8 +51,13 @@ class PartRectangle : public QGraphicsRectItem, public CustomElementGraphicPart virtual void setProperty(const QString &, const QVariant &); virtual QVariant property(const QString &); virtual bool isUseless() const; + virtual void startUserTransformation(const QRectF &); + virtual void handleUserTransformation(const QRectF &, const QRectF &); protected: QVariant itemChange(GraphicsItemChange, const QVariant &); + + private: + QList saved_points_; }; #endif diff --git a/sources/editor/partterminal.cpp b/sources/editor/partterminal.cpp index 1b15fed05..3ffdca7a6 100644 --- a/sources/editor/partterminal.cpp +++ b/sources/editor/partterminal.cpp @@ -219,3 +219,20 @@ void PartTerminal::updateSecondPoint() { bool PartTerminal::isUseless() const { return(false); } + +/** + Start the user-induced transformation, provided this primitive is contained + within the \a initial_selection_rect bounding rectangle. +*/ +void PartTerminal::startUserTransformation(const QRectF &initial_selection_rect) { + Q_UNUSED(initial_selection_rect) + saved_position_ = scenePos(); +} + +/** + Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect +*/ +void PartTerminal::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) { + QPointF mapped_point = mapPoints(initial_selection_rect, new_selection_rect, QList() << saved_position_).first(); + setPos(mapped_point); +} diff --git a/sources/editor/partterminal.h b/sources/editor/partterminal.h index 35c8bb376..b655a105b 100644 --- a/sources/editor/partterminal.h +++ b/sources/editor/partterminal.h @@ -57,11 +57,16 @@ class PartTerminal : public CustomElementPart, public QGraphicsItem { virtual void setProperty(const QString &, const QVariant &); virtual QVariant property(const QString &); virtual bool isUseless() const; + virtual void startUserTransformation(const QRectF &); + virtual void handleUserTransformation(const QRectF &, const QRectF &); protected: QVariant itemChange(GraphicsItemChange, const QVariant &); private: void updateSecondPoint(); + + private: + QPointF saved_position_; }; #endif diff --git a/sources/editor/parttext.cpp b/sources/editor/parttext.cpp index 1789f601e..b17951ac7 100644 --- a/sources/editor/parttext.cpp +++ b/sources/editor/parttext.cpp @@ -285,6 +285,32 @@ bool PartText::isUseless() const { return(toPlainText().isEmpty()); } +/** + Start the user-induced transformation, provided this primitive is contained + within the \a rect bounding rectangle. +*/ +void PartText::startUserTransformation(const QRectF &rect) { + Q_UNUSED(rect) + saved_point_ = pos(); // scene coordinates, no need to mapFromScene() + saved_font_size_ = font().pointSize(); +} + +/** + Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect +*/ +void PartText::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) { + // let's try the naive approach + QPointF new_pos = mapPoints(initial_selection_rect, new_selection_rect, QList() << saved_point_).first(); + setPos(new_pos); + + // adjust the font size following the smallest scale factor + qreal sx = new_selection_rect.width() / initial_selection_rect.width(); + qreal sy = new_selection_rect.height() / initial_selection_rect.height(); + qreal smallest_scale_factor = sx > sy ? sy : sx; + qreal new_font_size = saved_font_size_ * smallest_scale_factor; + setProperty("size", qMax(1, qRound(new_font_size))); +} + /** Dessine le texte statique. @param painter QPainter a utiliser pour effectuer le rendu diff --git a/sources/editor/parttext.h b/sources/editor/parttext.h index d5fdf4df0..801c49c60 100644 --- a/sources/editor/parttext.h +++ b/sources/editor/parttext.h @@ -55,6 +55,8 @@ class PartText : public QGraphicsTextItem, public CustomElementPart { virtual void setProperty(const QString &, const QVariant &); virtual QVariant property(const QString &); virtual bool isUseless() const; + virtual void startUserTransformation(const QRectF &); + virtual void handleUserTransformation(const QRectF &, const QRectF &); virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0 ); public slots: @@ -72,5 +74,7 @@ class PartText : public QGraphicsTextItem, public CustomElementPart { void drawPoint(QPainter *, const QPointF &); #endif QString previous_text; + QPointF saved_point_; + int saved_font_size_; }; #endif diff --git a/sources/editor/parttextfield.cpp b/sources/editor/parttextfield.cpp index 093c9bfc1..208a8de80 100644 --- a/sources/editor/parttextfield.cpp +++ b/sources/editor/parttextfield.cpp @@ -268,6 +268,31 @@ bool PartTextField::isUseless() const { return(false); } +/** + Start the user-induced transformation, provided this primitive is contained + within the \a initial_selection_rect bounding rectangle. +*/ +void PartTextField::startUserTransformation(const QRectF &initial_selection_rect) { + Q_UNUSED(initial_selection_rect) + saved_point_ = pos(); // scene coordinates, no need to mapFromScene() + saved_font_size_ = font().pointSize(); +} + +/** + Handle the user-induced transformation from \a initial_selection_rect to \a new_selection_rect +*/ +void PartTextField::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect) { + // let's try the naive approach + QPointF new_pos = mapPoints(initial_selection_rect, new_selection_rect, QList() << saved_point_).first(); + setPos(new_pos); + + // adjust the font size following the smallest scale factor + qreal sx = new_selection_rect.width() / initial_selection_rect.width(); + qreal sy = new_selection_rect.height() / initial_selection_rect.height(); + qreal smallest_scale_factor = sx > sy ? sy : sx; + qreal new_font_size = saved_font_size_ * smallest_scale_factor; + setProperty("size", qMax(1, qRound(new_font_size))); +} /** Dessine le texte statique. @param painter QPainter a utiliser pour effectuer le rendu diff --git a/sources/editor/parttextfield.h b/sources/editor/parttextfield.h index 74e3df95d..110f6a0bf 100644 --- a/sources/editor/parttextfield.h +++ b/sources/editor/parttextfield.h @@ -61,6 +61,8 @@ class PartTextField : public QGraphicsTextItem, public CustomElementPart { virtual void setProperty(const QString &, const QVariant &); virtual QVariant property(const QString &); virtual bool isUseless() const; + virtual void startUserTransformation(const QRectF &); + virtual void handleUserTransformation(const QRectF &, const QRectF &); virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0 ); public slots: @@ -78,5 +80,7 @@ class PartTextField : public QGraphicsTextItem, public CustomElementPart { void drawPoint(QPainter *, const QPointF &); #endif QString previous_text; + QPointF saved_point_; + int saved_font_size_; }; #endif