[qet] [2058] Element editor: changed the way scaling operations get rounded. |
[ Thread Index |
Date Index
| More lists.tuxfamily.org/qet Archives
]
Revision: 2058
Author: xavier
Date: 2013-03-06 19:51:29 +0100 (Wed, 06 Mar 2013)
Log Message:
-----------
Element editor: changed the way scaling operations get rounded.
Modified Paths:
--------------
trunk/sources/editor/customelementpart.cpp
trunk/sources/editor/customelementpart.h
trunk/sources/editor/elementprimitivedecorator.cpp
trunk/sources/editor/elementprimitivedecorator.h
trunk/sources/editor/partpolygon.cpp
trunk/sources/editor/partpolygon.h
trunk/sources/qet.h
Modified: trunk/sources/editor/customelementpart.cpp
===================================================================
--- trunk/sources/editor/customelementpart.cpp 2013-03-06 18:50:46 UTC (rev 2057)
+++ trunk/sources/editor/customelementpart.cpp 2013-03-06 18:51:29 UTC (rev 2058)
@@ -60,6 +60,17 @@
}
/**
+ This method is called by the decorator when it needs to determine the best
+ way to interactively scale a primitive. It is typically called when only a
+ single primitive is being scaled.
+ The default implementation systematically returns
+ QET::SnapScalingPointToGrid
+*/
+QET::ScalingMethod CustomElementPart::preferredScalingMethod() const {
+ return(QET::SnapScalingPointToGrid);
+}
+
+/**
This method is called by the decorator when it manages only a single
primitive and it received a mouse press event.
The implementation should return true if the primitive accepts the event, false otherwise.
Modified: trunk/sources/editor/customelementpart.h
===================================================================
--- trunk/sources/editor/customelementpart.h 2013-03-06 18:50:46 UTC (rev 2057)
+++ trunk/sources/editor/customelementpart.h 2013-03-06 18:51:29 UTC (rev 2058)
@@ -20,6 +20,7 @@
#include <QtGui>
#include <QtXml>
#include <QImage>
+#include "qet.h"
class CustomElement;
class ElementPrimitiveDecorator;
class ElementScene;
@@ -101,6 +102,7 @@
virtual QGraphicsItem *toItem();
virtual void setDecorator(ElementPrimitiveDecorator *);
+ virtual QET::ScalingMethod preferredScalingMethod() const;
virtual bool singleItemPressEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
virtual bool singleItemMoveEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
virtual bool singleItemReleaseEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
Modified: trunk/sources/editor/elementprimitivedecorator.cpp
===================================================================
--- trunk/sources/editor/elementprimitivedecorator.cpp 2013-03-06 18:50:46 UTC (rev 2057)
+++ trunk/sources/editor/elementprimitivedecorator.cpp 2013-03-06 18:51:29 UTC (rev 2058)
@@ -245,15 +245,30 @@
QPointF scene_pos = event -> scenePos();
QPointF movement = scene_pos - latest_pos_;
- // snap the movement to a non-visible grid when scaling selection
- if (mustSnapToGrid(event)) {
- // We now want some point belonging to the selection to be snapped to this rounded position
- if (current_operation_square_ > QET::NoOperation) {
+ if (current_operation_square_ > QET::NoOperation) {
+ // This is a scaling operation.
+
+ // For convenience purposes, we may need to adjust mouse movements.
+ QET::ScalingMethod scaling_method = scalingMethod(event);
+ if (scaling_method > QET::FreeScaling) {
// real, non-rounded movement from the mouse press event
QPointF global_movement = scene_pos - first_pos_;
- // real, rounded movement from the mouse press event
- QPointF rounded_global_movement = snapConstPointToGrid(global_movement);
+ QPointF rounded_global_movement;
+ if (scaling_method == QET::SnapScalingPointToGrid) {
+ // real, rounded movement from the mouse press event
+ rounded_global_movement = snapConstPointToGrid(global_movement);
+ }
+ else {
+ QRectF new_bounding_rect = original_bounding_rect_;
+ applyMovementToRect(current_operation_square_, global_movement, new_bounding_rect);
+
+ const qreal scale_epsilon = 20.0; // rounds to 0.05
+ QPointF delta = deltaForRoundScaling(original_bounding_rect_, new_bounding_rect, scale_epsilon);
+
+ // real, rounded movement from the mouse press event
+ rounded_global_movement = global_movement + delta;
+ }
// rounded position of the current mouse move event
QPointF rounded_scene_pos = first_pos_ + rounded_global_movement;
@@ -262,18 +277,22 @@
QPointF current_position = mapToScene(rects.at(current_operation_square_).center());
// determine the final, effective movement
movement = rounded_scene_pos - current_position;
- } else if (current_operation_square_ == QET::MoveArea) {
- // when moving the selection, consider the position of the first selected item
- QPointF current_position = scene_pos - mouse_offset_;
- QPointF rounded_current_position = snapConstPointToGrid(current_position);
- movement = rounded_current_position - decorated_items_.at(0) -> toItem() -> scenePos();
- } else {
- if (CustomElementPart *single_item = singleItem()) {
- bool event_accepted = single_item -> singleItemMoveEvent(this, event);
- if (event_accepted) {
- event -> ignore();
- return;
- }
+ }
+ }
+ else if (current_operation_square_ == QET::MoveArea) {
+ // When moving the selection, consider the position of the first selected item
+ QPointF current_position = scene_pos - mouse_offset_;
+ QPointF rounded_current_position = snapConstPointToGrid(current_position);
+ movement = rounded_current_position - decorated_items_.at(0) -> toItem() -> scenePos();
+ }
+ else {
+ // Neither a movement nor a scaling operation -- perhaps the underlying item
+ // is interested in the mouse event for custom operations?
+ if (CustomElementPart *single_item = singleItem()) {
+ bool event_accepted = single_item -> singleItemMoveEvent(this, event);
+ if (event_accepted) {
+ event -> ignore();
+ return;
}
}
}
@@ -628,6 +647,30 @@
}
/**
+ Receive two rects, assuming they share a common corner and current is a \a
+ scaled version of \a original.
+ Calculate the scale ratios implied by this assumption, round them to the
+ nearest multiple of \a epsilon, then return the horizontal and vertical
+ offsets to be applied in order to pass from \a current to \a original scaled
+ by the rounded factors.
+ This method can be used to adjust a mouse movement so that it inputs a
+ round scaling operation.
+*/
+QPointF ElementPrimitiveDecorator::deltaForRoundScaling(const QRectF &original, const QRectF ¤t, qreal epsilon) {
+ qreal sx = current.width() / original.width();
+ qreal sy = current.height() / original.height();
+
+ qreal sx_rounded = QET::round(sx, epsilon);
+ qreal sy_rounded = QET::round(sy, epsilon);
+
+ QPointF delta(
+ original.width() * (sx_rounded - sx),
+ original.height() * (sy_rounded - sy)
+ );
+ return(delta);
+}
+
+/**
Round the coordinates of \a point so it is snapped to the grid defined by the
grid_step_x_ and grid_step_y_ attributes.
*/
@@ -656,3 +699,19 @@
bool ElementPrimitiveDecorator::mustSnapToGrid(QGraphicsSceneMouseEvent *event) {
return(!(event -> modifiers() & Qt::ControlModifier));
}
+
+/**
+ @param event Mouse event during the scale operations -- simply passed to mustSnapToGrid()
+ @return the scaling method to be used for the currently decorated items.
+ @see QET::ScalingMethod
+ @see mustSnapToGrid()
+*/
+QET::ScalingMethod ElementPrimitiveDecorator::scalingMethod(QGraphicsSceneMouseEvent *event) {
+ if (event && !mustSnapToGrid(event)) {
+ return(QET::FreeScaling);
+ }
+ if (CustomElementPart *single_item = singleItem()) {
+ return single_item -> preferredScalingMethod();
+ }
+ return QET::RoundScaleRatios;
+}
Modified: trunk/sources/editor/elementprimitivedecorator.h
===================================================================
--- trunk/sources/editor/elementprimitivedecorator.h 2013-03-06 18:50:46 UTC (rev 2057)
+++ trunk/sources/editor/elementprimitivedecorator.h 2013-03-06 18:51:29 UTC (rev 2058)
@@ -1,6 +1,7 @@
#ifndef ELEMENTPRIMITIVEDECORATOR_H
#define ELEMENTPRIMITIVEDECORATOR_H
#include <QGraphicsObject>
+#include "qet.h"
class ElementEditionCommand;
class ElementScene;
class CustomElementPart;
@@ -49,9 +50,11 @@
void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
void keyPressEvent(QKeyEvent *);
void keyReleaseEvent(QKeyEvent *);
+ QPointF deltaForRoundScaling(const QRectF &, const QRectF &, qreal);
QPointF snapConstPointToGrid(const QPointF &) const;
void snapPointToGrid(QPointF &) const;
bool mustSnapToGrid(QGraphicsSceneMouseEvent *);
+ QET::ScalingMethod scalingMethod(QGraphicsSceneMouseEvent *);
private:
void init();
Modified: trunk/sources/editor/partpolygon.cpp
===================================================================
--- trunk/sources/editor/partpolygon.cpp 2013-03-06 18:50:46 UTC (rev 2057)
+++ trunk/sources/editor/partpolygon.cpp 2013-03-06 18:51:29 UTC (rev 2058)
@@ -191,6 +191,17 @@
}
/**
+ @reimp CustomElementPart::preferredScalingMethod
+ This method is called by the decorator when it needs to determine the best
+ way to interactively scale a primitive. It is typically called when only a
+ single primitive is being scaled.
+ This reimplementation systematically returns QET::RoundScaleRatios.
+*/
+QET::ScalingMethod PartPolygon::preferredScalingMethod() const {
+ return(QET::RoundScaleRatios);
+}
+
+/**
@return le rectangle delimitant cette partie.
*/
QRectF PartPolygon::boundingRect() const {
Modified: trunk/sources/editor/partpolygon.h
===================================================================
--- trunk/sources/editor/partpolygon.h 2013-03-06 18:50:46 UTC (rev 2057)
+++ trunk/sources/editor/partpolygon.h 2013-03-06 18:51:29 UTC (rev 2058)
@@ -59,6 +59,7 @@
virtual QRectF sceneGeometricRect() const;
virtual void startUserTransformation(const QRectF &);
virtual void handleUserTransformation(const QRectF &, const QRectF &);
+ virtual QET::ScalingMethod preferredScalingMethod() const;
protected:
QVariant itemChange(GraphicsItemChange, const QVariant &);
Modified: trunk/sources/qet.h
===================================================================
--- trunk/sources/qet.h 2013-03-06 18:50:46 UTC (rev 2057)
+++ trunk/sources/qet.h 2013-03-06 18:51:29 UTC (rev 2058)
@@ -59,6 +59,13 @@
ResizeFromBottomRightCorner = 7
};
+ /// Supported types of interactive scaling, typically for a single element primitive
+ enum ScalingMethod {
+ FreeScaling, ///< do not interfer with the default scaling process
+ SnapScalingPointToGrid, ///< snap the point used to define the new bounding rectangle to the grid
+ RoundScaleRatios ///< adjust the scaling movement so that the induced scaling ratios are rounded
+ };
+
/// Known kinds of conductor segments
enum ConductorSegmentType {
Horizontal = 1, ///< Horizontal segment