mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2025-12-20 16:20:52 +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)
|
||||
}
|
||||
|
||||
/**
|
||||
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.
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include <QtGui>
|
||||
#include <QtXml>
|
||||
#include <QImage>
|
||||
#include "qet.h"
|
||||
class CustomElement;
|
||||
class ElementPrimitiveDecorator;
|
||||
class ElementScene;
|
||||
@@ -101,6 +102,7 @@ class CustomElementPart {
|
||||
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 *);
|
||||
|
||||
@@ -245,15 +245,30 @@ void ElementPrimitiveDecorator::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
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 @@ void ElementPrimitiveDecorator::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -627,6 +646,30 @@ int ElementPrimitiveDecorator::resizingSquareAtPos(const QPointF &position) {
|
||||
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
|
||||
grid_step_x_ and grid_step_y_ attributes.
|
||||
@@ -656,3 +699,19 @@ void ElementPrimitiveDecorator::snapPointToGrid(QPointF &point) const {
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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 @@ class ElementPrimitiveDecorator : public QGraphicsObject {
|
||||
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();
|
||||
|
||||
@@ -190,6 +190,17 @@ void PartPolygon::handleUserTransformation(const QRectF &initial_selection_rect,
|
||||
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.
|
||||
*/
|
||||
|
||||
@@ -59,6 +59,7 @@ class PartPolygon : public QGraphicsPolygonItem, public CustomElementGraphicPart
|
||||
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 &);
|
||||
|
||||
@@ -59,6 +59,13 @@ namespace QET {
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user