qelectrotech-source-mirror/sources/editor/elementprimitivedecorator.cpp

759 lines
22 KiB
C++
Raw Normal View History

/*
Copyright 2006-2019 The QElectroTech Team
This file is part of QElectroTech.
QElectroTech is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 2 of the License, or
(at your option) any later version.
QElectroTech is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
*/
#include "elementprimitivedecorator.h"
#include "elementscene.h"
#include "customelementpart.h"
#include "editorcommands.h"
#include "qet.h"
#include <QPainter>
#include <QGraphicsSceneHoverEvent>
#include <QStyleOptionGraphicsItem>
#include <QGraphicsScene>
#include "QetGraphicsItemModeler/qetgraphicshandleritem.h"
/**
Constructor
@param parent Parent QGraphicsItem
*/
ElementPrimitiveDecorator::ElementPrimitiveDecorator(QGraphicsItem *parent):
QGraphicsObject(parent)
{
init();
}
/**
Destructor
*/
ElementPrimitiveDecorator::~ElementPrimitiveDecorator()
{
removeHandler();
}
/**
@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());
//if @decorated_items_ contain one item and if this item is a vertical or horizontal partline, apply a specific methode
if ((decorated_items_.count() == 1) && (decorated_items_.first() -> xmlName() == "line")) {
QRectF horto = decorated_items_.first() -> sceneGeometricRect();
if (!horto.width() || !horto.height()) {
return (getSceneBoundingRect(decorated_items_.first() -> toItem()));
}
}
QRectF rect = decorated_items_.first() -> sceneGeometricRect();
foreach (CustomElementPart *item, decorated_items_) {
rect = rect.united(item -> sceneGeometricRect());
}
return(rect);
}
/**
@return the outer bounds of the decorator as a rectangle.
*/
QRectF ElementPrimitiveDecorator::boundingRect() const
{
return effective_bounding_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();
Merge Qt5 branch sources folder to trunk -Cette ligne, et les suivantes ci-dessous, seront ignorées-- M sources/aboutqet.cpp M sources/bordertitleblock.cpp M sources/conductorproperties.h M sources/configdialog.cpp M sources/configpages.cpp M sources/configpages.h M sources/createdxf.h M sources/diagram.cpp M sources/diagram.h M sources/diagramcommands.cpp M sources/diagramcommands.h M sources/diagramprintdialog.cpp M sources/diagramprintdialog.h M sources/diagramschooser.cpp M sources/diagramschooser.h M sources/diagramview.cpp M sources/diagramview.h M sources/dvevent/dveventaddimage.cpp M sources/dvevent/dveventaddshape.cpp M sources/editor/arceditor.cpp M sources/editor/arceditor.h M sources/editor/editorcommands.cpp M sources/editor/editorcommands.h M sources/editor/elementitemeditor.h M sources/editor/elementprimitivedecorator.cpp M sources/editor/elementscene.cpp M sources/editor/elementscene.h M sources/editor/elementview.cpp M sources/editor/ellipseeditor.cpp M sources/editor/ellipseeditor.h M sources/editor/esevent/eseventaddtext.cpp M sources/editor/esevent/eseventaddtextfield.cpp M sources/editor/esevent/eseventinterface.cpp M sources/editor/graphicspart/customelementpart.h M sources/editor/graphicspart/parttext.cpp M sources/editor/graphicspart/parttext.h M sources/editor/graphicspart/parttextfield.cpp M sources/editor/graphicspart/parttextfield.h M sources/editor/lineeditor.cpp M sources/editor/lineeditor.h M sources/editor/polygoneditor.cpp M sources/editor/qetelementeditor.cpp M sources/editor/qetelementeditor.h M sources/editor/rectangleeditor.cpp M sources/editor/rectangleeditor.h M sources/editor/styleeditor.cpp M sources/editor/styleeditor.h M sources/editor/terminaleditor.cpp M sources/editor/terminaleditor.h M sources/editor/texteditor.cpp M sources/editor/texteditor.h M sources/editor/textfieldeditor.cpp M sources/editor/textfieldeditor.h M sources/editor/ui/elementpropertieseditorwidget.cpp M sources/elementdefinition.cpp M sources/elementdeleter.cpp M sources/elementdeleter.h M sources/elementdialog.cpp M sources/elementscategorieslist.h M sources/elementscategorieswidget.cpp M sources/elementscategorieswidget.h M sources/elementscategory.cpp M sources/elementscategorydeleter.cpp M sources/elementscategorydeleter.h M sources/elementscategoryeditor.cpp M sources/elementscategoryeditor.h M sources/elementscollection.cpp M sources/elementscollectioncache.cpp M sources/elementspanel.cpp M sources/elementspanel.h M sources/elementspanelwidget.cpp M sources/elementspanelwidget.h M sources/elementtextsmover.h M sources/exportdialog.cpp M sources/exportdialog.h M sources/exportproperties.cpp M sources/exportpropertieswidget.cpp M sources/exportpropertieswidget.h M sources/genericpanel.cpp M sources/integrationmoveelementshandler.cpp M sources/integrationmoveelementshandler.h M sources/interactivemoveelementshandler.cpp M sources/nameslistwidget.cpp M sources/nameslistwidget.h M sources/newelementwizard.cpp M sources/newelementwizard.h M sources/nomenclature.cpp M sources/nomenclature.h M sources/projectconfigpages.cpp M sources/projectview.cpp M sources/projectview.h M sources/qet.cpp M sources/qetapp.cpp M sources/qetapp.h M sources/qetdiagrameditor.cpp M sources/qetdiagrameditor.h M sources/qetgraphicsitem/conductor.cpp M sources/qetgraphicsitem/conductortextitem.cpp M sources/qetgraphicsitem/customelement.cpp M sources/qetgraphicsitem/diagramimageitem.cpp M sources/qetgraphicsitem/diagramtextitem.cpp M sources/qetgraphicsitem/diagramtextitem.h M sources/qetgraphicsitem/element.cpp M sources/qetgraphicsitem/ghostelement.cpp M sources/qetgraphicsitem/qetshapeitem.cpp M sources/qetgraphicsitem/terminal.cpp M sources/qetgraphicsitem/terminal.h M sources/qeticons.cpp M sources/qeticons.h M sources/qetmainwindow.cpp M sources/qetmessagebox.cpp M sources/qetmessagebox.h M sources/qetprintpreviewdialog.cpp M sources/qetprintpreviewdialog.h M sources/qetproject.cpp M sources/qetsingleapplication.cpp M sources/qettabbar.h M sources/qfilenameedit.cpp M sources/qtextorientationspinboxwidget.cpp M sources/qtextorientationspinboxwidget.h M sources/qtextorientationwidget.cpp M sources/qtextorientationwidget.h M sources/richtext/richtexteditor.cpp M sources/richtext/richtexteditor_p.h M sources/richtext/ui_addlinkdialog.h M sources/titleblock/dimensionwidget.h M sources/titleblock/gridlayoutanimation.h M sources/titleblock/helpercell.h M sources/titleblock/integrationmovetemplateshandler.cpp M sources/titleblock/integrationmovetemplateshandler.h M sources/titleblock/qettemplateeditor.cpp M sources/titleblock/qettemplateeditor.h M sources/titleblock/templatecellsset.h M sources/titleblock/templatecellwidget.cpp M sources/titleblock/templatecellwidget.h M sources/titleblock/templatecommands.cpp M sources/titleblock/templatedeleter.cpp M sources/titleblock/templatedeleter.h M sources/titleblock/templatelocationchooser.cpp M sources/titleblock/templatelocationchooser.h M sources/titleblock/templatelocationsaver.cpp M sources/titleblock/templatelocationsaver.h M sources/titleblock/templatelogomanager.cpp M sources/titleblock/templatelogomanager.h M sources/titleblock/templateview.cpp M sources/titleblock/templatevisualcell.h M sources/titleblockcell.cpp M sources/titleblocktemplate.cpp M sources/treecoloranimation.h M sources/ui/conductorpropertieswidget.cpp M sources/ui/diagrampropertiesdialog.cpp M sources/ui/diagramselection.cpp M sources/ui/dialogautonum.cpp M sources/ui/dialogwaiting.cpp M sources/ui/elementpropertieswidget.cpp M sources/ui/elementselectorwidget.cpp M sources/ui/linksingleelementwidget.cpp M sources/ui/masterpropertieswidget.cpp M sources/ui/potentialtextsdialog.cpp M sources/ui/projectpropertiesdialog.cpp M sources/ui/selectautonumw.cpp M sources/ui/titleblockpropertieswidget.cpp M sources/ui/xrefpropertieswidget.cpp M sources/undocommand/changeelementinformationcommand.cpp git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@3783 bfdf4180-ca20-0410-9c96-a3a8aa849046
2015-03-02 20:14:56 +00:00
// paint the original bounding rect
QPen pen(Qt::DashLine);
pen.setCosmetic(true);
painter -> setPen(pen);
painter -> drawRect(modified_bounding_rect_);
// 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)
{
decorated_items_ = items;
adjust();
show();
if (focusItem() != this) {
setFocus();
}
adjusteHandlerPos();
}
/**
@param items the new list of items this decorator is suposed to manipulate.
*/
void ElementPrimitiveDecorator::setItems(const QList<QGraphicsItem *> &items)
{
QList<CustomElementPart *> primitives;
for(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 event generated when mouse buttons are pressed.
@param event Object describing the mouse event
*/
void ElementPrimitiveDecorator::mousePressEvent(QGraphicsSceneMouseEvent *event)
{
if (internalBoundingRect().contains(event->pos()))
{
current_operation_square_ = QET::MoveArea;
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 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)
{
QPointF scene_pos = event -> scenePos();
QPointF movement = scene_pos - latest_pos_;
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();
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();
translateItems(movement);
}
}
/**
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 = nullptr;
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, nullptr, graphicsItems());
command = move_command;
}
if (command) {
emit(actionFinished(command));
}
adjust();
}
current_operation_square_ = QET::NoOperation;
}
/**
@reimp QGraphicsItem::keyPressEvent
*/
void ElementPrimitiveDecorator::keyPressEvent(QKeyEvent *e)
{
const qreal movement_length = 1.0;
QPointF movement;
if (e->modifiers() & Qt::ControlModifier) {
switch(e -> key())
{
case Qt::Key_Left: movement = QPointF(-movement_length / 10, 0.0); break;
case Qt::Key_Right: movement = QPointF(+movement_length / 10, 0.0); break;
case Qt::Key_Up: movement = QPointF(0.0, -movement_length / 10); break;
case Qt::Key_Down: movement = QPointF(0.0, +movement_length / 10); break;
}
}
else {
switch(e -> key())
{
case Qt::Key_Left: movement = QPointF(-movement_length, 0.0); break;
case Qt::Key_Right: movement = QPointF(+movement_length, 0.0); break;
case Qt::Key_Up: movement = QPointF(0.0, -movement_length); break;
case Qt::Key_Down: movement = QPointF(0.0, +movement_length); break;
}
}
if (!movement.isNull() && focusItem() == this)
{
if (!moving_by_keys_)
{
moving_by_keys_ = true;
keys_movement_ = movement;
}
else
{
keys_movement_ += movement;
}
for(QGraphicsItem *qgi : graphicsItems())
{
qgi -> setPos(qgi -> pos() + movement);
adjust();
}
e->accept();
return;
}
QGraphicsObject::keyPressEvent(e);
}
/**
@reimp QGraphicsItem::keyReleaseEvent
*/
void ElementPrimitiveDecorator::keyReleaseEvent(QKeyEvent *e) {
// detecte le relachement d'une touche de direction ( = deplacement de parties)
if(
(e -> key() == Qt::Key_Left || e -> key() == Qt::Key_Right ||\
e -> key() == Qt::Key_Up || e -> key() == Qt::Key_Down) &&\
moving_by_keys_ && !e -> isAutoRepeat()
) {
// cree un objet d'annulation pour le mouvement qui vient de se finir
emit(actionFinished(new MovePartsCommand(keys_movement_, nullptr, graphicsItems())));
keys_movement_ = QPointF();
moving_by_keys_ = false;
e->accept();
return;
}
QGraphicsObject::keyPressEvent(e);
}
/**
Initialize an ElementPrimitiveDecorator
*/
void ElementPrimitiveDecorator::init()
{
setFlag(QGraphicsItem::ItemIsFocusable, true);
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();
adjusteHandlerPos();
}
/**
Start a movement (i.e. either a move or scaling operation)
*/
void ElementPrimitiveDecorator::startMovement() {
adjust();
foreach(CustomElementPart *item, decorated_items_) {
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(nullptr);
}
/**
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();
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()));
}
QVector<QPointF> ElementPrimitiveDecorator::getResizingsPoints() const
{
QRectF primitive_rect = modified_bounding_rect_;
QVector <QPointF> vector;
QPointF half;
vector << primitive_rect.topLeft(); //top left
half = primitive_rect.center();
half.setY(primitive_rect.top());
vector << half; //middle top
vector << primitive_rect.topRight(); //top right
half = primitive_rect.center();
half.setX(primitive_rect.left());
vector << half; //middle left
half = primitive_rect.center();
half.setX(primitive_rect.right());
vector << half; //middle right
vector << primitive_rect.bottomLeft(); //bottom left
half = primitive_rect.center();
half.setY(primitive_rect.bottom());
vector << half; //middle bottom
vector << primitive_rect.bottomRight(); //bottom right
return vector;
}
/**
* @brief ElementPrimitiveDecorator::adjusteHandlerPos
*/
void ElementPrimitiveDecorator::adjusteHandlerPos()
{
QVector <QPointF> points_vector = mapToScene(getResizingsPoints());
for (int i = 0 ; i < points_vector.size() ; ++i)
m_handler_vector.at(i)->setPos(points_vector.at(i));
}
/**
* @brief ElementPrimitiveDecorator::handlerMousePressEvent
* @param qghi
* @param event
*/
void ElementPrimitiveDecorator::handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(event);
QVector <QPointF> points = getResizingsPoints();
current_operation_square_ = m_handler_vector.indexOf(qghi);
first_pos_ = latest_pos_ = mapToScene(points.at(current_operation_square_));
startMovement();
}
/**
* @brief ElementPrimitiveDecorator::handlerMouseMoveEvent
* @param qghi
* @param event
*/
void ElementPrimitiveDecorator::handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(qghi);
QPointF scene_pos = event -> scenePos();
QPointF movement = scene_pos - latest_pos_;
// 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_;
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;
// when scaling the selection, consider the center of the currently dragged resizing rectangle
QPointF current_position = mapToScene(getResizingsPoints().at(current_operation_square_));
// determine the final, effective movement
movement = rounded_scene_pos - current_position;
}
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();
scaleItems(original_bounding_rect_, modified_bounding_rect_);
}
/**
* @brief ElementPrimitiveDecorator::handlerMouseReleaseEvent
* @param qghi
* @param event
*/
void ElementPrimitiveDecorator::handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
{
Q_UNUSED(qghi);
Q_UNUSED(event);
ElementEditionCommand *command = nullptr;
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;
}
if (command) {
emit(actionFinished(command));
}
adjust();
current_operation_square_ = QET::NoOperation;
}
/**
* @brief ElementPrimitiveDecorator::addHandler
* Add handlers for this item
*/
void ElementPrimitiveDecorator::addHandler()
{
if (m_handler_vector.isEmpty() && scene())
{
m_handler_vector = QetGraphicsHandlerItem::handlerForPoint(mapFromScene(getResizingsPoints()));
for(QetGraphicsHandlerItem *handler : m_handler_vector)
{
scene()->addItem(handler);
handler->setColor(Qt::darkGreen);
handler->installSceneEventFilter(this);
handler->setZValue(this->zValue()+1);
}
}
}
/**
* @brief ElementPrimitiveDecorator::removeHandler
* Remove the handlers of this item
*/
void ElementPrimitiveDecorator::removeHandler()
{
if (!m_handler_vector.isEmpty())
{
qDeleteAll(m_handler_vector);
m_handler_vector.clear();
}
}
/**
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 &current, 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.
*/
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));
}
/**
@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;
}
/**
* @brief ElementPrimitiveDecorator::itemChange
* @param change
* @param value
* @return
*/
QVariant ElementPrimitiveDecorator::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
{
if (change == ItemSceneHasChanged)
{
if(scene()) //Item is added to scene, we also add handlers
addHandler();
else //Item is removed from scene, we also remove the handlers
removeHandler();
}
else if (change == ItemVisibleHasChanged)
{
bool visible = value.toBool();
for(QetGraphicsHandlerItem *qghi : m_handler_vector)
qghi->setVisible(visible);
}
else if (change == ItemZValueHasChanged && !m_handler_vector.isEmpty())
{
for (QetGraphicsHandlerItem *qghi : m_handler_vector)
qghi->setZValue(this->zValue()+1);
}
return QGraphicsObject::itemChange(change, value);
}
/**
* @brief ElementPrimitiveDecorator::sceneEventFilter
* @param watched
* @param event
* @return
*/
bool ElementPrimitiveDecorator::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
{
//Watched must be an handler
if(watched->type() == QetGraphicsHandlerItem::Type)
{
QetGraphicsHandlerItem *qghi = qgraphicsitem_cast<QetGraphicsHandlerItem *>(watched);
if(m_handler_vector.contains(qghi)) //Handler must be in m_vector_index, then we can start resize
{
m_vector_index = m_handler_vector.indexOf(qghi);
if (m_vector_index != -1)
{
if(event->type() == QEvent::GraphicsSceneMousePress) //Click
{
handlerMousePressEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
return true;
}
else if(event->type() == QEvent::GraphicsSceneMouseMove) //Move
{
handlerMouseMoveEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
return true;
}
else if (event->type() == QEvent::GraphicsSceneMouseRelease) //Release
{
handlerMouseReleaseEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
return true;
}
}
}
}
return false;
}