mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2025-12-21 00:30:53 +01:00
Element editor: changed the way scaling operations get rounded.
git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@2058 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
@@ -59,6 +59,17 @@ void CustomElementPart::setDecorator(ElementPrimitiveDecorator *decorator) {
|
|||||||
Q_UNUSED(decorator)
|
Q_UNUSED(decorator)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
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
|
This method is called by the decorator when it manages only a single
|
||||||
primitive and it received a mouse press event.
|
primitive and it received a mouse press event.
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <QtGui>
|
#include <QtGui>
|
||||||
#include <QtXml>
|
#include <QtXml>
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
|
#include "qet.h"
|
||||||
class CustomElement;
|
class CustomElement;
|
||||||
class ElementPrimitiveDecorator;
|
class ElementPrimitiveDecorator;
|
||||||
class ElementScene;
|
class ElementScene;
|
||||||
@@ -101,6 +102,7 @@ class CustomElementPart {
|
|||||||
virtual QGraphicsItem *toItem();
|
virtual QGraphicsItem *toItem();
|
||||||
|
|
||||||
virtual void setDecorator(ElementPrimitiveDecorator *);
|
virtual void setDecorator(ElementPrimitiveDecorator *);
|
||||||
|
virtual QET::ScalingMethod preferredScalingMethod() const;
|
||||||
virtual bool singleItemPressEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
virtual bool singleItemPressEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||||
virtual bool singleItemMoveEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
virtual bool singleItemMoveEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||||
virtual bool singleItemReleaseEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
virtual bool singleItemReleaseEvent(ElementPrimitiveDecorator *, QGraphicsSceneMouseEvent *);
|
||||||
|
|||||||
@@ -245,15 +245,30 @@ void ElementPrimitiveDecorator::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
|||||||
QPointF scene_pos = event -> scenePos();
|
QPointF scene_pos = event -> scenePos();
|
||||||
QPointF movement = scene_pos - latest_pos_;
|
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
|
// real, non-rounded movement from the mouse press event
|
||||||
QPointF global_movement = scene_pos - first_pos_;
|
QPointF global_movement = scene_pos - first_pos_;
|
||||||
|
|
||||||
|
QPointF rounded_global_movement;
|
||||||
|
if (scaling_method == QET::SnapScalingPointToGrid) {
|
||||||
// real, rounded movement from the mouse press event
|
// real, rounded movement from the mouse press event
|
||||||
QPointF rounded_global_movement = snapConstPointToGrid(global_movement);
|
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
|
// rounded position of the current mouse move event
|
||||||
QPointF rounded_scene_pos = first_pos_ + rounded_global_movement;
|
QPointF rounded_scene_pos = first_pos_ + rounded_global_movement;
|
||||||
@@ -262,12 +277,17 @@ void ElementPrimitiveDecorator::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
|||||||
QPointF current_position = mapToScene(rects.at(current_operation_square_).center());
|
QPointF current_position = mapToScene(rects.at(current_operation_square_).center());
|
||||||
// determine the final, effective movement
|
// determine the final, effective movement
|
||||||
movement = rounded_scene_pos - current_position;
|
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
|
}
|
||||||
|
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 current_position = scene_pos - mouse_offset_;
|
||||||
QPointF rounded_current_position = snapConstPointToGrid(current_position);
|
QPointF rounded_current_position = snapConstPointToGrid(current_position);
|
||||||
movement = rounded_current_position - decorated_items_.at(0) -> toItem() -> scenePos();
|
movement = rounded_current_position - decorated_items_.at(0) -> toItem() -> scenePos();
|
||||||
} else {
|
}
|
||||||
|
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()) {
|
if (CustomElementPart *single_item = singleItem()) {
|
||||||
bool event_accepted = single_item -> singleItemMoveEvent(this, event);
|
bool event_accepted = single_item -> singleItemMoveEvent(this, event);
|
||||||
if (event_accepted) {
|
if (event_accepted) {
|
||||||
@@ -276,7 +296,6 @@ void ElementPrimitiveDecorator::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
QRectF bounding_rect = modified_bounding_rect_;
|
QRectF bounding_rect = modified_bounding_rect_;
|
||||||
applyMovementToRect(current_operation_square_, movement, modified_bounding_rect_);
|
applyMovementToRect(current_operation_square_, movement, modified_bounding_rect_);
|
||||||
@@ -627,6 +646,30 @@ int ElementPrimitiveDecorator::resizingSquareAtPos(const QPointF &position) {
|
|||||||
return(current_square);
|
return(current_square);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
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
|
Round the coordinates of \a point so it is snapped to the grid defined by the
|
||||||
grid_step_x_ and grid_step_y_ attributes.
|
grid_step_x_ and grid_step_y_ attributes.
|
||||||
@@ -656,3 +699,19 @@ void ElementPrimitiveDecorator::snapPointToGrid(QPointF &point) const {
|
|||||||
bool ElementPrimitiveDecorator::mustSnapToGrid(QGraphicsSceneMouseEvent *event) {
|
bool ElementPrimitiveDecorator::mustSnapToGrid(QGraphicsSceneMouseEvent *event) {
|
||||||
return(!(event -> modifiers() & Qt::ControlModifier));
|
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;
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#ifndef ELEMENTPRIMITIVEDECORATOR_H
|
#ifndef ELEMENTPRIMITIVEDECORATOR_H
|
||||||
#define ELEMENTPRIMITIVEDECORATOR_H
|
#define ELEMENTPRIMITIVEDECORATOR_H
|
||||||
#include <QGraphicsObject>
|
#include <QGraphicsObject>
|
||||||
|
#include "qet.h"
|
||||||
class ElementEditionCommand;
|
class ElementEditionCommand;
|
||||||
class ElementScene;
|
class ElementScene;
|
||||||
class CustomElementPart;
|
class CustomElementPart;
|
||||||
@@ -49,9 +50,11 @@ class ElementPrimitiveDecorator : public QGraphicsObject {
|
|||||||
void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
|
void mouseReleaseEvent(QGraphicsSceneMouseEvent *);
|
||||||
void keyPressEvent(QKeyEvent *);
|
void keyPressEvent(QKeyEvent *);
|
||||||
void keyReleaseEvent(QKeyEvent *);
|
void keyReleaseEvent(QKeyEvent *);
|
||||||
|
QPointF deltaForRoundScaling(const QRectF &, const QRectF &, qreal);
|
||||||
QPointF snapConstPointToGrid(const QPointF &) const;
|
QPointF snapConstPointToGrid(const QPointF &) const;
|
||||||
void snapPointToGrid(QPointF &) const;
|
void snapPointToGrid(QPointF &) const;
|
||||||
bool mustSnapToGrid(QGraphicsSceneMouseEvent *);
|
bool mustSnapToGrid(QGraphicsSceneMouseEvent *);
|
||||||
|
QET::ScalingMethod scalingMethod(QGraphicsSceneMouseEvent *);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void init();
|
void init();
|
||||||
|
|||||||
@@ -190,6 +190,17 @@ void PartPolygon::handleUserTransformation(const QRectF &initial_selection_rect,
|
|||||||
setPolygon(mapFromScene(QPolygonF(mapped_points.toVector())));
|
setPolygon(mapFromScene(QPolygonF(mapped_points.toVector())));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
@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.
|
@return le rectangle delimitant cette partie.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -59,6 +59,7 @@ class PartPolygon : public QGraphicsPolygonItem, public CustomElementGraphicPart
|
|||||||
virtual QRectF sceneGeometricRect() const;
|
virtual QRectF sceneGeometricRect() const;
|
||||||
virtual void startUserTransformation(const QRectF &);
|
virtual void startUserTransformation(const QRectF &);
|
||||||
virtual void handleUserTransformation(const QRectF &, const QRectF &);
|
virtual void handleUserTransformation(const QRectF &, const QRectF &);
|
||||||
|
virtual QET::ScalingMethod preferredScalingMethod() const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
QVariant itemChange(GraphicsItemChange, const QVariant &);
|
QVariant itemChange(GraphicsItemChange, const QVariant &);
|
||||||
|
|||||||
@@ -59,6 +59,13 @@ namespace QET {
|
|||||||
ResizeFromBottomRightCorner = 7
|
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
|
/// Known kinds of conductor segments
|
||||||
enum ConductorSegmentType {
|
enum ConductorSegmentType {
|
||||||
Horizontal = 1, ///< Horizontal segment
|
Horizontal = 1, ///< Horizontal segment
|
||||||
|
|||||||
Reference in New Issue
Block a user