mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2025-09-13 20:23:04 +02:00
git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@2027 bfdf4180-ca20-0410-9c96-a3a8aa849046
615 lines
20 KiB
C++
615 lines
20 KiB
C++
#include "elementprimitivedecorator.h"
|
|
#include "elementscene.h"
|
|
#include "customelementpart.h"
|
|
#include "editorcommands.h"
|
|
#include "qet.h"
|
|
#include <QPainter>
|
|
#include <QDebug>
|
|
#include <QGraphicsSceneHoverEvent>
|
|
#include <QStyleOptionGraphicsItem>
|
|
#include <QGraphicsScene>
|
|
#include <QTransform>
|
|
|
|
/**
|
|
Constructor
|
|
@param parent Parent QGraphicsItem
|
|
*/
|
|
ElementPrimitiveDecorator::ElementPrimitiveDecorator(QGraphicsItem *parent):
|
|
QGraphicsObject(parent)
|
|
{
|
|
init();
|
|
}
|
|
|
|
/**
|
|
Destructor
|
|
*/
|
|
ElementPrimitiveDecorator::~ElementPrimitiveDecorator() {
|
|
}
|
|
|
|
/**
|
|
@return the internal bouding rect, i.e. the smallest rectangle containing
|
|
the bounding rectangle of every selected item.
|
|
*/
|
|
QRectF ElementPrimitiveDecorator::internalBoundingRect() const {
|
|
if (!decorated_items_.count() || !scene()) return(QRectF());
|
|
|
|
QRectF rect = getSceneBoundingRect(decorated_items_.first() -> toItem());
|
|
foreach (CustomElementPart *item, decorated_items_) {
|
|
rect = rect.united(getSceneBoundingRect(item -> toItem()));
|
|
}
|
|
return(rect);
|
|
}
|
|
|
|
/**
|
|
@return the outer bounds of the decorator as a rectangle.
|
|
*/
|
|
QRectF ElementPrimitiveDecorator::boundingRect() const {
|
|
const qreal additional_margin = 2.5;
|
|
|
|
QRectF rect = effective_bounding_rect_;
|
|
rect.adjust(-additional_margin, -additional_margin, additional_margin, additional_margin);
|
|
return(rect);
|
|
}
|
|
|
|
/**
|
|
Paint the contents of an item in local coordinates, using \a painter, with
|
|
respect to \a option and
|
|
@param option The option parameter provides style options for the item, such
|
|
as its state, exposed area and its level-of-detail hints.
|
|
@param The widget argument is optional. If provided, it points to the
|
|
widget that is being painted on; otherwise, it is 0. For cached painting,
|
|
widget is always 0.
|
|
*/
|
|
void ElementPrimitiveDecorator::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
|
|
Q_UNUSED(option)
|
|
Q_UNUSED(widget)
|
|
painter -> save();
|
|
|
|
// paint the original bounding rect
|
|
painter -> setPen(Qt::DashLine);
|
|
//QGraphicsItemGroup::paint(painter, option, widget);
|
|
painter -> drawRect(modified_bounding_rect_);
|
|
drawSquares(painter, option, widget);
|
|
|
|
// uncomment to draw the real bouding rect (=adjusted internal bounding rect)
|
|
// painter -> setBrush(QBrush(QColor(240, 0, 0, 127)));
|
|
// painter -> drawRect(boundingRect());
|
|
painter -> restore();
|
|
}
|
|
|
|
/**
|
|
@param items the new list of items this decorator is suposed to manipulate.
|
|
*/
|
|
void ElementPrimitiveDecorator::setItems(const QList<CustomElementPart *> &items) {
|
|
if (CustomElementPart *single_item = singleItem()) {
|
|
if (items.count() == 1 && items.first() == single_item) {
|
|
// no actual change
|
|
goto end_setItems;
|
|
}
|
|
|
|
// break any connection between the former single selected item (if any) and
|
|
// the decorator
|
|
single_item -> setDecorator(0);
|
|
if (QGraphicsObject *single_object = dynamic_cast<QGraphicsObject *>(single_item)) {
|
|
disconnect(single_object, 0, this, 0);
|
|
}
|
|
}
|
|
|
|
decorated_items_ = items;
|
|
|
|
// when only a single primitive is selected, the decorator behaves specially
|
|
// to enable extra features, such as text edition, internal points movements,
|
|
// etc.
|
|
if (CustomElementPart *single_item = singleItem()) {
|
|
single_item -> setDecorator(this);
|
|
}
|
|
|
|
end_setItems:
|
|
adjust();
|
|
show();
|
|
grabKeyboard();
|
|
}
|
|
|
|
/**
|
|
@param items the new list of items this decorator is suposed to manipulate.
|
|
*/
|
|
void ElementPrimitiveDecorator::setItems(const QList<QGraphicsItem *> &items) {
|
|
QList<CustomElementPart *> primitives;
|
|
foreach (QGraphicsItem *item, items) {
|
|
if (CustomElementPart *part_item = dynamic_cast<CustomElementPart *>(item)) {
|
|
primitives << part_item;
|
|
}
|
|
}
|
|
setItems(primitives);
|
|
}
|
|
|
|
/**
|
|
@return the list of items this decorator is supposed to manipulate
|
|
*/
|
|
QList<CustomElementPart *> ElementPrimitiveDecorator::items() const {
|
|
return(decorated_items_);
|
|
}
|
|
|
|
/**
|
|
@return the list of items this decorator is supposed to manipulate
|
|
*/
|
|
QList<QGraphicsItem *> ElementPrimitiveDecorator::graphicsItems() const {
|
|
QList<QGraphicsItem *> list;
|
|
foreach (CustomElementPart *part_item, decorated_items_) {
|
|
if (QGraphicsItem *item = dynamic_cast<QGraphicsItem *>(part_item)) {
|
|
list << item;
|
|
}
|
|
}
|
|
return(list);
|
|
}
|
|
|
|
/**
|
|
Adjust the visual decorator according to the currently assigned items.
|
|
It is notably called by setItems().
|
|
*/
|
|
void ElementPrimitiveDecorator::adjust() {
|
|
saveOriginalBoundingRect();
|
|
modified_bounding_rect_ = original_bounding_rect_;
|
|
adjustEffectiveBoundingRect();
|
|
}
|
|
|
|
/**
|
|
Handle events generated when the mouse hovers over the decorator.
|
|
@param event Object describing the hover event.
|
|
*/
|
|
void ElementPrimitiveDecorator::hoverMoveEvent(QGraphicsSceneHoverEvent *event) {
|
|
QList<QRectF> rects = getResizingSquares();
|
|
QPointF pos = event -> pos();
|
|
|
|
if (rects.at(QET::ResizeFromTopLeftCorner).contains(pos) || rects.at(QET::ResizeFromBottomRightCorner).contains(pos)) {
|
|
setCursor(Qt::SizeFDiagCursor);
|
|
} else if (rects.at(QET::ResizeFromTopRightCorner).contains(pos) || rects.at(QET::ResizeFromBottomLeftCorner).contains(pos)) {
|
|
setCursor(Qt::SizeBDiagCursor);
|
|
} else if (rects.at(QET::ResizeFromTopCenterCorner).contains(pos) || rects.at(QET::ResizeFromBottomCenterCorner).contains(pos)) {
|
|
setCursor(Qt::SizeVerCursor);
|
|
} else if (rects.at(QET::ResizeFromMiddleLeftCorner).contains(pos) || rects.at(QET::ResizeFromMiddleRightCorner).contains(pos)) {
|
|
setCursor(Qt::SizeHorCursor);
|
|
} else if (internalBoundingRect().contains(pos)) {
|
|
setCursor(Qt::SizeAllCursor);
|
|
} else {
|
|
setCursor(Qt::ArrowCursor);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Handle event generated when mouse buttons are pressed.
|
|
@param event Object describing the mouse event
|
|
*/
|
|
void ElementPrimitiveDecorator::mousePressEvent(QGraphicsSceneMouseEvent *event) {
|
|
qDebug() << Q_FUNC_INFO << event << zValue();
|
|
QList<QRectF> rects = getResizingSquares();
|
|
QPointF pos = event -> pos();
|
|
|
|
current_operation_square_ = resizingSquareAtPos(pos);
|
|
bool accept = false;
|
|
if (current_operation_square_ != QET::NoOperation) {
|
|
accept = true;
|
|
} else {
|
|
if (internalBoundingRect().contains(pos)) {
|
|
if (CustomElementPart *single_item = singleItem()) {
|
|
bool event_accepted = single_item -> singleItemPressEvent(this, event);
|
|
if (event_accepted) {
|
|
event -> ignore();
|
|
return;
|
|
}
|
|
}
|
|
current_operation_square_ = QET::MoveArea;
|
|
accept = true;
|
|
}
|
|
}
|
|
|
|
if (accept) {
|
|
if (current_operation_square_ > QET::NoOperation) {
|
|
first_pos_ = latest_pos_ = mapToScene(rects.at(current_operation_square_).center());
|
|
} else {
|
|
first_pos_ = decorated_items_.at(0) -> toItem() -> scenePos();
|
|
latest_pos_ = event -> scenePos();
|
|
mouse_offset_ = event -> scenePos() - first_pos_;
|
|
}
|
|
startMovement();
|
|
event -> accept();
|
|
} else {
|
|
event -> ignore();
|
|
}
|
|
}
|
|
|
|
/**
|
|
Handle events generated when mouse buttons are double clicked.
|
|
@param event Object describing the mouse event
|
|
*/
|
|
void ElementPrimitiveDecorator::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) {
|
|
//QGraphicsObject::mouseDoubleClickEvent(event);
|
|
if (CustomElementPart *single_item = singleItem()) {
|
|
bool event_accepted = single_item -> singleItemDoubleClickEvent(this, event);
|
|
if (event_accepted) {
|
|
event -> ignore();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
Handle event generated when the mouse is moved and the decorator is the mouse grabber item.
|
|
@param event Object describing the mouse event
|
|
@see QGraphicsScene::mouseGrabberItem()
|
|
*/
|
|
void ElementPrimitiveDecorator::mouseMoveEvent(QGraphicsSceneMouseEvent *event) {
|
|
QList<QRectF> rects = getResizingSquares();
|
|
|
|
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) {
|
|
// 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);
|
|
|
|
// rounded position of the current mouse move event
|
|
QPointF rounded_scene_pos = first_pos_ + rounded_global_movement;
|
|
|
|
// when scaling the selection, consider the center of the currently dragged resizing rectangle
|
|
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;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
QRectF bounding_rect = modified_bounding_rect_;
|
|
applyMovementToRect(current_operation_square_, movement, modified_bounding_rect_);
|
|
if (modified_bounding_rect_ != bounding_rect) {
|
|
adjustEffectiveBoundingRect();
|
|
}
|
|
latest_pos_ = event -> scenePos();
|
|
|
|
if (current_operation_square_ == QET::MoveArea) {
|
|
translateItems(movement);
|
|
} else {
|
|
scaleItems(original_bounding_rect_, modified_bounding_rect_);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Handle event generated when a mouse buttons are releaseis moved and the
|
|
decorator is the mouse grabber item.
|
|
@param event Object describing the mouse event
|
|
@see QGraphicsScene::mouseGrabberItem()
|
|
*/
|
|
void ElementPrimitiveDecorator::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) {
|
|
Q_UNUSED(event)
|
|
|
|
ElementEditionCommand *command = 0;
|
|
if (current_operation_square_ > QET::NoOperation) {
|
|
ScalePartsCommand *scale_command = new ScalePartsCommand();
|
|
scale_command -> setScaledPrimitives(items());
|
|
scale_command -> setTransformation(
|
|
mapToScene(original_bounding_rect_).boundingRect(),
|
|
mapToScene(modified_bounding_rect_).boundingRect()
|
|
);
|
|
command = scale_command;
|
|
} else if (current_operation_square_ == QET::MoveArea) {
|
|
QPointF movement = mapToScene(modified_bounding_rect_.topLeft()) - mapToScene(original_bounding_rect_.topLeft());
|
|
if (!movement.isNull()) {
|
|
MovePartsCommand *move_command = new MovePartsCommand(movement, 0, graphicsItems());
|
|
command = move_command;
|
|
}
|
|
} else {
|
|
if (CustomElementPart *single_item = singleItem()) {
|
|
bool event_accepted = single_item -> singleItemReleaseEvent(this, event);
|
|
if (event_accepted) {
|
|
event -> ignore();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (command) {
|
|
emit(actionFinished(command));
|
|
}
|
|
|
|
if (current_operation_square_ != QET::NoOperation) {
|
|
adjust();
|
|
}
|
|
|
|
current_operation_square_ = QET::NoOperation;
|
|
}
|
|
|
|
/**
|
|
Initialize an ElementPrimitiveDecorator
|
|
*/
|
|
void ElementPrimitiveDecorator::init() {
|
|
//setAcceptedMouseButtons(Qt::LeftButton);
|
|
grid_step_x_ = grid_step_y_ = 1;
|
|
setAcceptHoverEvents(true);
|
|
}
|
|
|
|
/**
|
|
Save the original bounding rectangle.
|
|
*/
|
|
void ElementPrimitiveDecorator::saveOriginalBoundingRect() {
|
|
original_bounding_rect_ = internalBoundingRect();
|
|
}
|
|
|
|
/**
|
|
Adjust the effective bounding rect. This method should be called after the
|
|
modified_bouding_rect_ attribute was modified.
|
|
*/
|
|
void ElementPrimitiveDecorator::adjustEffectiveBoundingRect() {
|
|
prepareGeometryChange();
|
|
effective_bounding_rect_ = modified_bounding_rect_ | effective_bounding_rect_;
|
|
update();
|
|
}
|
|
|
|
/**
|
|
Start a movement (i.e. either a move or scaling operation)
|
|
*/
|
|
void ElementPrimitiveDecorator::startMovement() {
|
|
adjust();
|
|
|
|
foreach(CustomElementPart *item, decorated_items_) {
|
|
qDebug() << Q_FUNC_INFO << "starting movement with rect" << original_bounding_rect_ << "i.e. in scene coordinates " << mapToScene(original_bounding_rect_).boundingRect();
|
|
item -> startUserTransformation(mapToScene(original_bounding_rect_).boundingRect());
|
|
}
|
|
}
|
|
|
|
/**
|
|
Apply the movement described by \a movement_type and \a movement to \a rect.
|
|
*/
|
|
void ElementPrimitiveDecorator::applyMovementToRect(int movement_type, const QPointF &movement, QRectF &rect) {
|
|
qreal new_value;
|
|
QPointF new_point;
|
|
|
|
switch (movement_type) {
|
|
case QET::MoveArea:
|
|
rect.translate(movement.x(), movement.y());
|
|
break;
|
|
case QET::ResizeFromTopLeftCorner:
|
|
new_point = rect.topLeft() + movement;
|
|
rect.setTopLeft(new_point);
|
|
break;
|
|
case QET::ResizeFromTopCenterCorner:
|
|
new_value = rect.top() + movement.y();
|
|
rect.setTop(new_value);
|
|
break;
|
|
case QET::ResizeFromTopRightCorner:
|
|
new_point = rect.topRight() + movement;
|
|
rect.setTopRight(new_point);
|
|
break;
|
|
case QET::ResizeFromMiddleLeftCorner:
|
|
new_value = rect.left() + movement.x();
|
|
rect.setLeft(new_value);
|
|
break;
|
|
case QET::ResizeFromMiddleRightCorner:
|
|
new_value = rect.right() + movement.x();
|
|
rect.setRight(new_value);
|
|
break;
|
|
case QET::ResizeFromBottomLeftCorner:
|
|
new_point = rect.bottomLeft() + movement;
|
|
rect.setBottomLeft(new_point);
|
|
break;
|
|
case QET::ResizeFromBottomCenterCorner:
|
|
new_value = rect.bottom() + movement.y();
|
|
rect.setBottom(new_value);
|
|
break;
|
|
case QET::ResizeFromBottomRightCorner:
|
|
new_point = rect.bottomRight() + movement;
|
|
rect.setBottomRight(new_point);
|
|
break;
|
|
}
|
|
}
|
|
|
|
CustomElementPart *ElementPrimitiveDecorator::singleItem() const {
|
|
if (decorated_items_.count() == 1) {
|
|
return(decorated_items_.first());
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
Translated the managed items by the \a movement
|
|
*/
|
|
void ElementPrimitiveDecorator::translateItems(const QPointF &movement) {
|
|
if (!decorated_items_.count()) return;
|
|
|
|
foreach(QGraphicsItem *qgi, graphicsItems()) {
|
|
// this is a naive, proof-of-concept implementation; we actually need to take
|
|
// the grid into account and create a command object in mouseReleaseEvent()
|
|
qgi -> moveBy(movement.x(), movement.y());
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
Scale the managed items, provided they originally fit within \a
|
|
original_rect and they should now fit \a new_rect
|
|
*/
|
|
void ElementPrimitiveDecorator::scaleItems(const QRectF &original_rect, const QRectF &new_rect) {
|
|
if (!decorated_items_.count()) return;
|
|
if (original_rect == new_rect) return;
|
|
if (!original_rect.width() || !original_rect.height()) return; // cowardly flee division by zero FIXME?
|
|
|
|
QRectF scene_original_rect = mapToScene(original_rect).boundingRect();
|
|
QRectF scene_new_rect = mapToScene(new_rect).boundingRect();
|
|
qDebug() << Q_FUNC_INFO << "from " << original_rect << " to " << new_rect;
|
|
qDebug() << Q_FUNC_INFO << "from " << scene_original_rect << " to " << scene_new_rect << "(scene coordinates)";
|
|
|
|
foreach(CustomElementPart *item, decorated_items_) {
|
|
item -> handleUserTransformation(scene_original_rect, scene_new_rect);
|
|
}
|
|
}
|
|
|
|
/**
|
|
@return the bounding rectangle of \a item, in scene coordinates
|
|
*/
|
|
QRectF ElementPrimitiveDecorator::getSceneBoundingRect(QGraphicsItem *item) const {
|
|
if (!item) return(QRectF());
|
|
return(item -> mapRectToScene(item -> boundingRect()));
|
|
}
|
|
|
|
/**
|
|
Draw all known resizing squares using \a painter.
|
|
@param option The option parameter provides style options for the item, such
|
|
as its state, exposed area and its level-of-detail hints.
|
|
@param The widget argument is optional. If provided, it points to the
|
|
widget that is being painted on; otherwise, it is 0. For cached painting,
|
|
widget is always 0.
|
|
*/
|
|
void ElementPrimitiveDecorator::drawSquares(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) {
|
|
foreach (QRectF rect, getResizingSquares()) {
|
|
drawResizeSquare(painter, option, widget, rect);
|
|
}
|
|
}
|
|
|
|
/**
|
|
Draw the provided resizing square \a rect using \a painter.
|
|
@param option The option parameter provides style options for the item, such
|
|
as its state, exposed area and its level-of-detail hints.
|
|
@param The widget argument is optional. If provided, it points to the
|
|
widget that is being painted on; otherwise, it is 0. For cached painting,
|
|
widget is always 0.
|
|
*/
|
|
void ElementPrimitiveDecorator::drawResizeSquare(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget, const QRectF &rect) {
|
|
QColor inner(0xFF, 0xFF, 0xFF);
|
|
QColor outer(0x00, 0x61, 0xFF);
|
|
if (decorated_items_.count() > 1) {
|
|
outer = QColor(0x1A, 0x5C, 0x14);
|
|
}
|
|
drawGenericSquare(painter, option, widget, rect, inner, outer);
|
|
}
|
|
|
|
/**
|
|
Draw a generic square \a rect using \a painter.
|
|
@param inner Color used to fill the square
|
|
@param outer Color usd to draw the outline
|
|
@param option The option parameter provides style options for the item, such
|
|
as its state, exposed area and its level-of-detail hints.
|
|
@param The widget argument is optional. If provided, it points to the
|
|
widget that is being painted on; otherwise, it is 0. For cached painting,
|
|
widget is always 0.
|
|
*/
|
|
void ElementPrimitiveDecorator::drawGenericSquare(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget, const QRectF &rect, const QColor &inner, const QColor &outer) {
|
|
Q_UNUSED(option)
|
|
Q_UNUSED(widget)
|
|
// 1.0px will end up to level_of_details px once rendered
|
|
// qreal level_of_details = option->levelOfDetailFromTransform(painter -> transform());
|
|
|
|
painter -> save();
|
|
painter -> setBrush(QBrush(inner));
|
|
QPen square_pen(QBrush(outer), 2.0, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin);
|
|
square_pen.setCosmetic(true);
|
|
painter -> setPen(square_pen);
|
|
painter -> drawRect(rect);
|
|
painter -> restore();
|
|
}
|
|
|
|
/**
|
|
@return A list containing all known resizing squares, based on the
|
|
modified_bounding_rect_ attribute. They are ordered following
|
|
QET::OperationAreas, so it is possible to use positive values from this enum
|
|
to fetch the corresponding square in the list.
|
|
@see QET::OperationAreas
|
|
*/
|
|
QList<QRectF> ElementPrimitiveDecorator::getResizingSquares() {
|
|
QRectF primitive_rect = modified_bounding_rect_;
|
|
QRectF half_primitive_rect1 = primitive_rect;
|
|
half_primitive_rect1.setHeight(half_primitive_rect1.height() / 2.0);
|
|
QRectF half_primitive_rect2 = primitive_rect;
|
|
half_primitive_rect2.setWidth(half_primitive_rect2.width() / 2.0);
|
|
|
|
QList<QRectF> rects;
|
|
|
|
rects << getGenericSquare(primitive_rect.topLeft());
|
|
rects << getGenericSquare(half_primitive_rect2.topRight());
|
|
rects << getGenericSquare(primitive_rect.topRight());
|
|
rects << getGenericSquare(half_primitive_rect1.bottomLeft());
|
|
rects << getGenericSquare(half_primitive_rect1.bottomRight());
|
|
rects << getGenericSquare(primitive_rect.bottomLeft());
|
|
rects << getGenericSquare(half_primitive_rect2.bottomRight());
|
|
rects << getGenericSquare(primitive_rect.bottomRight());
|
|
|
|
/// TODO cache the rects instead of calculating them again and again?
|
|
return(rects);
|
|
}
|
|
|
|
/**
|
|
@return the square to be drawn to represent \a position
|
|
*/
|
|
QRectF ElementPrimitiveDecorator::getGenericSquare(const QPointF &position) {
|
|
const qreal square_half_size = 0.5;
|
|
return(
|
|
QRectF(
|
|
position.x() - square_half_size,
|
|
position.y() - square_half_size,
|
|
square_half_size * 2.0,
|
|
square_half_size * 2.0
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
@return the index of the square containing the \a position point or -1 if
|
|
none matches.
|
|
*/
|
|
int ElementPrimitiveDecorator::resizingSquareAtPos(const QPointF &position) {
|
|
QList<QRectF> rects = getResizingSquares();
|
|
int current_square = QET::NoOperation;
|
|
for (int i = 0 ; i < rects.count() ; ++ i) {
|
|
if (rects.at(i).contains(position)) {
|
|
current_square = i;
|
|
}
|
|
}
|
|
return(current_square);
|
|
}
|
|
|
|
/**
|
|
Round the coordinates of \a point so it is snapped to the grid defined by the
|
|
grid_step_x_ and grid_step_y_ attributes.
|
|
*/
|
|
QPointF ElementPrimitiveDecorator::snapConstPointToGrid(const QPointF &point) const {
|
|
return(
|
|
QPointF(
|
|
qRound(point.x() / grid_step_x_) * grid_step_x_,
|
|
qRound(point.y() / grid_step_y_) * grid_step_y_
|
|
)
|
|
);
|
|
}
|
|
|
|
/**
|
|
Round the coordinates of \a point so it is snapped to the grid defined by the
|
|
grid_step_x_ and grid_step_y_ attributes.
|
|
*/
|
|
void ElementPrimitiveDecorator::snapPointToGrid(QPointF &point) const {
|
|
point.rx() = qRound(point.x() / grid_step_x_) * grid_step_x_;
|
|
point.ry() = qRound(point.y() / grid_step_y_) * grid_step_y_;
|
|
}
|
|
|
|
/**
|
|
@return whether the current operation should take the grid into account
|
|
according to the state of the provided \a event
|
|
*/
|
|
bool ElementPrimitiveDecorator::mustSnapToGrid(QGraphicsSceneMouseEvent *event) {
|
|
return(!(event -> modifiers() & Qt::ControlModifier));
|
|
}
|