diff --git a/dev_doc/enum_type_of_QGraphicsItem b/dev_doc/enum_type_of_QGraphicsItem index 1dd7d02d7..67853f9e9 100644 --- a/dev_doc/enum_type_of_QGraphicsItem +++ b/dev_doc/enum_type_of_QGraphicsItem @@ -21,6 +21,3 @@ part terminal + 1106 part text + 1107 part text field + 1108 part rectangle + 1109 - -###QetGraphicsHandlerItem### -QetGraphicsHandlerItem = 1200 diff --git a/sources/QetGraphicsItemModeler/QetGraphicsItemModeler.pri b/sources/QetGraphicsItemModeler/QetGraphicsItemModeler.pri index ab89d8a6f..3e783a8be 100755 --- a/sources/QetGraphicsItemModeler/QetGraphicsItemModeler.pri +++ b/sources/QetGraphicsItemModeler/QetGraphicsItemModeler.pri @@ -1,5 +1,7 @@ HEADERS += \ - $$PWD/qetgraphicshandlerutility.h + $$PWD/qetgraphicshandlerutility.h \ + $$PWD/qetgraphicshandleritem.h SOURCES += \ - $$PWD/qetgraphicshandlerutility.cpp + $$PWD/qetgraphicshandlerutility.cpp \ + $$PWD/qetgraphicshandleritem.cpp diff --git a/sources/QetGraphicsItemModeler/qetgraphicshandleritem.cpp b/sources/QetGraphicsItemModeler/qetgraphicshandleritem.cpp new file mode 100644 index 000000000..e2be2e651 --- /dev/null +++ b/sources/QetGraphicsItemModeler/qetgraphicshandleritem.cpp @@ -0,0 +1,99 @@ +/* + Copyright 2006-2017 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 . +*/ +#include "qetgraphicshandleritem.h" +#include +#include + +/** + * @brief QetGraphicsHandlerItem::QetGraphicsHandlerItem + * @param size, the size of the handler + */ +QetGraphicsHandlerItem::QetGraphicsHandlerItem(qreal size) : + m_size(size) +{} + +/** + * @brief QetGraphicsHandlerItem::boundingRect + * @return + */ +QRectF QetGraphicsHandlerItem::boundingRect() const +{ + qreal rect_size = m_size * m_previous_zoom_factor; + QRectF rect(0-rect_size/2, 0-rect_size/2, rect_size, rect_size); + rect.adjust(-2, -2, 2, 2); + return rect; +} + +/** + * @brief QetGraphicsHandlerItem::setColor + * @param color, set the color of the handler + */ +void QetGraphicsHandlerItem::setColor(QColor color) +{ + m_color = color; + update(); +} + +/** + * @brief QetGraphicsHandlerItem::paint + * @param painter + * @param option + * @param widget + */ +void QetGraphicsHandlerItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) +{ + Q_UNUSED(option); + Q_UNUSED(widget); + + qreal zoom_factor = 1.0/painter->transform().m11(); + if(zoom_factor != m_previous_zoom_factor) + { + prepareGeometryChange(); + m_previous_zoom_factor = zoom_factor; + } + + qreal rect_size = m_size * m_previous_zoom_factor; + QRectF rect(0-rect_size/2, 0-rect_size/2, rect_size, rect_size); + + painter->save(); + painter->setBrush(QBrush(m_color)); + QPen pen(QBrush(m_color), 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin); + pen.setCosmetic(true); + painter->setPen(pen); + painter->setRenderHint(QPainter::Antialiasing, true); + painter->drawEllipse(rect); + painter->restore(); +} + +/** + * @brief QetGraphicsHandlerItem::handlerForPoint + * @param points + * @return A list of handler with pos at point + */ +QVector QetGraphicsHandlerItem::handlerForPoint(const QVector &points, int size) +{ + QVector list_; + for (QPointF point : points) + { + QetGraphicsHandlerItem *qghi = new QetGraphicsHandlerItem(size); + qghi->setPos(point); + list_ << qghi; + } + + return list_; +} diff --git a/sources/QetGraphicsItemModeler/qetgraphicshandleritem.h b/sources/QetGraphicsItemModeler/qetgraphicshandleritem.h new file mode 100644 index 000000000..9cf6646ce --- /dev/null +++ b/sources/QetGraphicsItemModeler/qetgraphicshandleritem.h @@ -0,0 +1,53 @@ +/* + Copyright 2006-2017 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 . +*/ +#ifndef QETGRAPHICSHANDLERITEM_H +#define QETGRAPHICSHANDLERITEM_H + +#include + +/** + * @brief The QetGraphicsHandlerItem class + * This graphics item represents a point, destined to be used as an handler, + * for modifie the geometrie of a another graphics item (like shapes). + * The graphics item to be modified, must call "installSceneEventFilter" of this item with itself for argument,. + * The ghraphics item to be modified, need to reimplement "sceneEventFilter" for create the modification behavior. + */ +class QetGraphicsHandlerItem : public QGraphicsItem +{ + public: + QetGraphicsHandlerItem(qreal size = 15); + virtual QRectF boundingRect() const; + + enum { Type = UserType + 1200}; + virtual int type() const {return Type;} + + void setColor(QColor color); + + protected: + virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); + + private: + qreal m_size, + m_previous_zoom_factor = 1; + QColor m_color; + + public: + static QVector handlerForPoint(const QVector &points, int size = 15); +}; + +#endif // QETGRAPHICSHANDLERITEM_H diff --git a/sources/QetGraphicsItemModeler/qetgraphicshandlerutility.cpp b/sources/QetGraphicsItemModeler/qetgraphicshandlerutility.cpp index 656218016..23d8d940c 100644 --- a/sources/QetGraphicsItemModeler/qetgraphicshandlerutility.cpp +++ b/sources/QetGraphicsItemModeler/qetgraphicshandlerutility.cpp @@ -16,111 +16,10 @@ along with QElectroTech. If not, see . */ #include "qetgraphicshandlerutility.h" -#include +//#include +//#include +#include -/** - * @brief QetGraphicsHandlerUtility::QetGraphicsHandlerUtility - * Constructor - * @param size : the size of the handler - */ -QetGraphicsHandlerUtility::QetGraphicsHandlerUtility(qreal size) : - m_size (size) -{} - -/** - * @brief QetGraphicsHandlerUtility::drawHandler - * Draw the handler at pos @point, using the QPainter @painter. - * @param painter : painter to use for drawing the handler - * @param point : point to draw the handler - */ -void QetGraphicsHandlerUtility::drawHandler(QPainter *painter, const QPointF &point) -{ - //Setup the zoom factor to draw the handler in the same size at screen, - //no matter the zoom of the QPainter - m_zoom_factor = 1.0/painter->transform().m11(); - - painter->save(); - painter->setBrush(QBrush(m_inner_color)); - QPen square_pen(QBrush(m_outer_color), 2, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin); - square_pen.setCosmetic(true); - painter->setPen(square_pen); - painter->drawRect(getRect(point)); - painter->restore(); -} - -/** - * @brief QetGraphicsHandlerUtility::drawHandler - * Conveniance method for void QetGraphicsHandlerUtility::drawHandler(QPainter *painter, const QPointF &point) - * @param painter - * @param points - * @param color2 - */ -void QetGraphicsHandlerUtility::drawHandler(QPainter *painter, const QVector &points) { - foreach(QPointF point, points) - drawHandler(painter, point); -} - -/** - * @brief QetGraphicsHandlerUtility::pointIsInHandler - * @param point : point to compare - * @param key_point : point at the center of handler (the point to modify, for exemple the corner of a rectangle) - * @return true if point is in a handler. else false - */ -bool QetGraphicsHandlerUtility::pointIsInHandler(const QPointF &point, const QPointF &key_point) const { - return (getRect(key_point).contains(point)); -} - -/** - * @brief QetGraphicsHandlerUtility::pointIsHoverHandler - * @param point : point to compare - * @param vector : vector of key_point (the point to modify, for exemple the corners of a rectangle) - * @return if point is hover an handler, return the index of the hovered key_point in the vector, else return -1 - */ -int QetGraphicsHandlerUtility::pointIsHoverHandler(const QPointF &point, const QVector &vector) const -{ - foreach (QPointF key_point, vector) - if (pointIsInHandler(point, key_point)) - return vector.indexOf(key_point); - - return -1; -} - -/** - * @brief QetGraphicsHandlerUtility::handlerRect - * Return the rect of the handler for all key_point in vector (the point to modify, for exemple the corners of a rectangle) - * The order of rect in the returned vector is the same as the given vector. - * @param vector - * @return - */ -QVector QetGraphicsHandlerUtility::handlerRect(const QVector &vector) const -{ - QVector rect_vector; - - foreach(QPointF point, vector) - rect_vector << getRect(point); - - return rect_vector; -} - -void QetGraphicsHandlerUtility::setInnerColor(QColor color) { - m_inner_color = color; -} - -void QetGraphicsHandlerUtility::setOuterColor(QColor color) { - m_outer_color = color; -} - -/** - * @brief QetGraphicsHandlerUtility::getRect - * @param point - * @return - */ -QRectF QetGraphicsHandlerUtility::getRect(const QPointF &point) const -{ - qreal rect_size = m_size * m_zoom_factor; - QRectF rect(point.x() - rect_size/2, point.y() - rect_size/2, rect_size, rect_size); - return rect; -} /** * @brief QetGraphicsHandlerUtility::pointsForRect @@ -169,7 +68,6 @@ QVector QetGraphicsHandlerUtility::pointsForLine(const QLineF &line) { return (QVector {line.p1(), line.p2()}); } -#include /** * @brief QetGraphicsHandlerUtility::pointsForArc * Return the points for the given arc. diff --git a/sources/QetGraphicsItemModeler/qetgraphicshandlerutility.h b/sources/QetGraphicsItemModeler/qetgraphicshandlerutility.h index a550b9078..14e8e4b26 100644 --- a/sources/QetGraphicsItemModeler/qetgraphicshandlerutility.h +++ b/sources/QetGraphicsItemModeler/qetgraphicshandlerutility.h @@ -32,25 +32,6 @@ class QPainter; */ class QetGraphicsHandlerUtility { - public: - QetGraphicsHandlerUtility (qreal size = 1); - void setSize(qreal size) {m_size = size;} - void drawHandler (QPainter *painter, const QPointF & point); - void drawHandler(QPainter *painter, const QVector &points); - QPointF posForHandler(const QPointF &point) const; - bool pointIsInHandler (const QPointF &point, const QPointF &key_point) const; - int pointIsHoverHandler (const QPointF &point, const QVector &vector) const; - QVector handlerRect (const QVector &vector) const; - void setInnerColor (QColor color); - void setOuterColor (QColor color); - - private: - QRectF getRect (const QPointF &point) const; - qreal m_size; - qreal m_zoom_factor = 1; - QColor m_inner_color = Qt::white, - m_outer_color = Qt::blue; - public: static QVector pointsForRect (const QRectF &rect); static QVector pointsForLine (const QLineF &line); diff --git a/sources/diagram.cpp b/sources/diagram.cpp index be3995dc6..17a83e934 100644 --- a/sources/diagram.cpp +++ b/sources/diagram.cpp @@ -91,30 +91,31 @@ Diagram::Diagram(QETProject *project) : * @brief Diagram::~Diagram * Destructor */ -Diagram::~Diagram() -{ - //First clear every selection to close an hypothetical editor - clearSelection(); - // clear undo stack to prevent errors, because contains pointers to this diagram and is elements. +Diagram::~Diagram() { + // clear undo stack to prevent errors, because contains pointers to this diagram and is elements. undoStack().clear(); - //delete of QGIManager, every elements he knows are removed + //delete of QGIManager, every elements he knows are removed delete qgi_manager_; - // remove of conductor setter + // remove of conductor setter delete conductor_setter_; - // delete of object for manage movement + // delete of object for manage movement delete elements_mover_; delete element_texts_mover_; - if (m_event_interface) - delete m_event_interface; + if (m_event_interface) delete m_event_interface; - // list removable items + // list removable items QList deletable_items; for(QGraphicsItem *qgi : items()) - { - if (qgi -> parentItem()) continue; - if (qgraphicsitem_cast(qgi)) continue; + { + if (qgi->parentItem()) + continue; + if (qgi->type() == Conductor::Type) + continue; + if (qgi->type() == QetGraphicsHandlerItem::Type) + continue; + deletable_items << qgi; } @@ -377,6 +378,8 @@ void Diagram::keyReleaseEvent(QKeyEvent *e) * Diagram become the ownership of event_interface * If there is a previous interface, they will be delete before * and call init() to the new interface. + * The derivated class of DiagramEventInterface need to emit the signal "finish" when the job is done, + * diagram use this signal to delete the interface. If the signal isn't send, the interface will never be deleted. * @param event_interface */ void Diagram::setEventInterface(DiagramEventInterface *event_interface) diff --git a/sources/editor/elementprimitivedecorator.cpp b/sources/editor/elementprimitivedecorator.cpp index 7c5f3701b..80a2bbace 100644 --- a/sources/editor/elementprimitivedecorator.cpp +++ b/sources/editor/elementprimitivedecorator.cpp @@ -24,23 +24,24 @@ #include #include #include +#include "QetGraphicsItemModeler/qetgraphicshandleritem.h" /** Constructor @param parent Parent QGraphicsItem */ ElementPrimitiveDecorator::ElementPrimitiveDecorator(QGraphicsItem *parent): - QGraphicsObject(parent), - m_handler(10) + QGraphicsObject(parent) { init(); - m_handler.setOuterColor(Qt::darkGreen); } /** Destructor */ -ElementPrimitiveDecorator::~ElementPrimitiveDecorator() { +ElementPrimitiveDecorator::~ElementPrimitiveDecorator() +{ + removeHandler(); } /** @@ -68,12 +69,7 @@ QRectF ElementPrimitiveDecorator::internalBoundingRect() const { */ QRectF ElementPrimitiveDecorator::boundingRect() const { - QVector rect_vector = m_handler.handlerRect(getResizingsPoints()); - - QRectF rect = effective_bounding_rect_; - rect |= rect_vector.first(); - rect |= rect_vector.last(); - return(rect); + return effective_bounding_rect_; } /** @@ -96,9 +92,6 @@ void ElementPrimitiveDecorator::paint(QPainter *painter, const QStyleOptionGraph pen.setCosmetic(true); painter -> setPen(pen); painter -> drawRect(modified_bounding_rect_); - - //Draw the handlers - m_handler.drawHandler(painter, getResizingsPoints()); // uncomment to draw the real bouding rect (=adjusted internal bounding rect) // painter -> setBrush(QBrush(QColor(240, 0, 0, 127))); @@ -118,15 +111,19 @@ void ElementPrimitiveDecorator::setItems(const QList &items if (focusItem() != this) { setFocus(); } + adjusteHandlerPos(); } /** @param items the new list of items this decorator is suposed to manipulate. */ -void ElementPrimitiveDecorator::setItems(const QList &items) { +void ElementPrimitiveDecorator::setItems(const QList &items) +{ QList primitives; - foreach (QGraphicsItem *item, items) { - if (CustomElementPart *part_item = dynamic_cast(item)) { + for(QGraphicsItem *item : items) + { + if (CustomElementPart *part_item = dynamic_cast(item)) + { primitives << part_item; } } @@ -157,72 +154,31 @@ QList ElementPrimitiveDecorator::graphicsItems() const { Adjust the visual decorator according to the currently assigned items. It is notably called by setItems(). */ -void ElementPrimitiveDecorator::adjust() { +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) -{ - int p = m_handler.pointIsHoverHandler(event->pos(), getResizingsPoints()); - - if (p == 0 || p == 7) - setCursor(Qt::SizeFDiagCursor); - else if (p == 2 || p == 5) - setCursor(Qt::SizeBDiagCursor); - else if (p == 1 || p ==6) - setCursor(Qt::SizeVerCursor); - else if (p == 3 || p == 4) - setCursor(Qt::SizeHorCursor); - else if (p == -1 && modified_bounding_rect_.normalized().contains(event->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) -{ - QPointF pos = event -> pos(); - QVector points = getResizingsPoints(); - - current_operation_square_ = m_handler.pointIsHoverHandler(pos, points); - bool accept = false; - - if (current_operation_square_ != QET::NoOperation) - accept = true; - else +{ + if (internalBoundingRect().contains(event->pos())) { - if (internalBoundingRect().contains(pos)) - { - current_operation_square_ = QET::MoveArea; - accept = true; - } - } - - if (accept) - { - if (current_operation_square_ > QET::NoOperation) - first_pos_ = latest_pos_ = mapToScene(points.at(current_operation_square_)); - else - { - first_pos_ = decorated_items_.at(0) -> toItem() -> scenePos(); - latest_pos_ = event -> scenePos(); - mouse_offset_ = event -> scenePos() - first_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(); + event->accept(); } else - event -> ignore(); + event->ignore(); } /** @@ -235,59 +191,25 @@ void ElementPrimitiveDecorator::mouseMoveEvent(QGraphicsSceneMouseEvent *event) QPointF scene_pos = event -> scenePos(); QPointF movement = scene_pos - latest_pos_; - 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_; - - 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; - } - } - else if (current_operation_square_ == QET::MoveArea) { + 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(); - - if (current_operation_square_ == QET::MoveArea) { + + 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); - } else { - scaleItems(original_bounding_rect_, modified_bounding_rect_); } + + + + } /** @@ -296,31 +218,25 @@ void ElementPrimitiveDecorator::mouseMoveEvent(QGraphicsSceneMouseEvent *event) @param event Object describing the mouse event @see QGraphicsScene::mouseGrabberItem() */ -void ElementPrimitiveDecorator::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { +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) { + + if (current_operation_square_ == QET::MoveArea) + { QPointF movement = mapToScene(modified_bounding_rect_.topLeft()) - mapToScene(original_bounding_rect_.topLeft()); - if (!movement.isNull()) { + if (!movement.isNull()) + { MovePartsCommand *move_command = new MovePartsCommand(movement, 0, graphicsItems()); command = move_command; } - } - - if (command) { - emit(actionFinished(command)); - } - - if (current_operation_square_ != QET::NoOperation) { + + if (command) { + emit(actionFinished(command)); + } + adjust(); } @@ -376,7 +292,8 @@ void ElementPrimitiveDecorator::keyReleaseEvent(QKeyEvent *e) { /** Initialize an ElementPrimitiveDecorator */ -void ElementPrimitiveDecorator::init() { +void ElementPrimitiveDecorator::init() +{ setFlag(QGraphicsItem::ItemIsFocusable, true); grid_step_x_ = grid_step_y_ = 1; setAcceptHoverEvents(true); @@ -397,6 +314,7 @@ void ElementPrimitiveDecorator::adjustEffectiveBoundingRect() { prepareGeometryChange(); effective_bounding_rect_ = modified_bounding_rect_ | effective_bounding_rect_; update(); + adjusteHandlerPos(); } /** @@ -528,6 +446,152 @@ QVector ElementPrimitiveDecorator::getResizingsPoints() const return vector; } +/** + * @brief ElementPrimitiveDecorator::adjusteHandlerPos + */ +void ElementPrimitiveDecorator::adjusteHandlerPos() +{ + QVector 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 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 = 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; + } + + 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. @@ -597,3 +661,73 @@ QET::ScalingMethod ElementPrimitiveDecorator::scalingMethod(QGraphicsSceneMouseE } 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(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(event)); + return true; + } + else if(event->type() == QEvent::GraphicsSceneMouseMove) //Move + { + handlerMouseMoveEvent(qghi, static_cast(event)); + return true; + } + else if (event->type() == QEvent::GraphicsSceneMouseRelease) //Release + { + handlerMouseReleaseEvent(qghi, static_cast(event)); + return true; + } + } + } + } + + return false; +} diff --git a/sources/editor/elementprimitivedecorator.h b/sources/editor/elementprimitivedecorator.h index b32e63354..67b5864d7 100644 --- a/sources/editor/elementprimitivedecorator.h +++ b/sources/editor/elementprimitivedecorator.h @@ -20,11 +20,11 @@ #include #include "qet.h" -#include "QetGraphicsItemModeler/qetgraphicshandlerutility.h" class ElementEditionCommand; class ElementScene; class CustomElementPart; +class QetGraphicsHandlerItem; /** This class represents a decorator rendered above selected items so users @@ -42,72 +42,85 @@ class ElementPrimitiveDecorator : public QGraphicsObject Q_OBJECT public: - ElementPrimitiveDecorator(QGraphicsItem * = 0); - virtual ~ElementPrimitiveDecorator(); - - enum { Type = UserType + 2200 }; - - // methods - QRectF internalBoundingRect() const; - virtual QRectF boundingRect () const; - virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0); - virtual int type() const { return Type; } - void setItems(const QList &); - void setItems(const QList &); - QList items() const; - QList graphicsItems() const; + ElementPrimitiveDecorator(QGraphicsItem * = 0); + virtual ~ElementPrimitiveDecorator(); + + enum { Type = UserType + 2200 }; + + // methods + QRectF internalBoundingRect() const; + virtual QRectF boundingRect () const; + virtual void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget * = 0); + virtual int type() const { return Type; } + void setItems(const QList &); + void setItems(const QList &); + QList items() const; + QList graphicsItems() const; public slots: - void adjust(); + void adjust(); signals: - void actionFinished(ElementEditionCommand *); + void actionFinished(ElementEditionCommand *); protected: - void hoverMoveEvent(QGraphicsSceneHoverEvent *); - void mousePressEvent(QGraphicsSceneMouseEvent *); - void mouseMoveEvent(QGraphicsSceneMouseEvent *); - 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 *); + void mousePressEvent(QGraphicsSceneMouseEvent *); + void mouseMoveEvent(QGraphicsSceneMouseEvent *); + 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 *); + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); + virtual bool sceneEventFilter(QGraphicsItem *watched, QEvent *event); private: - void init(); - void saveOriginalBoundingRect(); - void adjustEffectiveBoundingRect(); - void startMovement(); - void applyMovementToRect(int, const QPointF &, QRectF &); - CustomElementPart *singleItem() const; - void translateItems(const QPointF &); - void scaleItems(const QRectF &, const QRectF &); - QRectF getSceneBoundingRect(QGraphicsItem *) const; - QVector getResizingsPoints() const; + void init(); + void saveOriginalBoundingRect(); + void adjustEffectiveBoundingRect(); + void startMovement(); + void applyMovementToRect(int, const QPointF &, QRectF &); + CustomElementPart *singleItem() const; + void translateItems(const QPointF &); + void scaleItems(const QRectF &, const QRectF &); + QRectF getSceneBoundingRect(QGraphicsItem *) const; + QVector getResizingsPoints() const; - // attributes + private: - QList decorated_items_; - QRectF effective_bounding_rect_; ///< actual, effective bounding rect -- never shrinks - QRectF original_bounding_rect_; ///< original bounding rect - QRectF modified_bounding_rect_; ///< new bounding rect, after the user moved or resized items + void adjusteHandlerPos(); + void handlerMousePressEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseMoveEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseReleaseEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + + void addHandler(); + void removeHandler(); + + + + + QList decorated_items_; + QRectF effective_bounding_rect_; ///< actual, effective bounding rect -- never shrinks + QRectF original_bounding_rect_; ///< original bounding rect + QRectF modified_bounding_rect_; ///< new bounding rect, after the user moved or resized items - /** - Index of the square leading the current operation (resizing, etc.) or -1 if no - operation is occurring, -2 for a move operation. - */ - int current_operation_square_; - int grid_step_x_; ///< Grid horizontal step - int grid_step_y_; ///< Grid horizontal step - QPointF first_pos_; ///< First point involved within the current resizing operation - QPointF latest_pos_; ///< Latest point involved within the current resizing operation - QPointF mouse_offset_; ///< Offset between the mouse position and the point to be snapped to grid when moving selection - bool moving_by_keys_; ///< Whether we are currently moving our decorated items using the arrow keys - QPointF keys_movement_; ///< Movement applied to our decorated items using the arrow keys - QetGraphicsHandlerUtility m_handler; + /** + Index of the square leading the current operation (resizing, etc.) or -1 if no + operation is occurring, -2 for a move operation. + */ + int current_operation_square_; + int grid_step_x_; ///< Grid horizontal step + int grid_step_y_; ///< Grid horizontal step + QPointF first_pos_; ///< First point involved within the current resizing operation + QPointF latest_pos_; ///< Latest point involved within the current resizing operation + QPointF mouse_offset_; ///< Offset between the mouse position and the point to be snapped to grid when moving selection + bool moving_by_keys_; ///< Whether we are currently moving our decorated items using the arrow keys + QPointF keys_movement_; ///< Movement applied to our decorated items using the arrow keys + QVector m_handler_vector; + int m_vector_index = -1; }; #endif diff --git a/sources/editor/elementscene.cpp b/sources/editor/elementscene.cpp index 19e95c0ee..b57137142 100644 --- a/sources/editor/elementscene.cpp +++ b/sources/editor/elementscene.cpp @@ -32,8 +32,9 @@ #include "nameslist.h" #include "ui/elementpropertieseditorwidget.h" #include "eseventinterface.h" -#include +#include "QetGraphicsItemModeler/qetgraphicshandleritem.h" +#include #include /** @@ -524,27 +525,45 @@ QETElementEditor* ElementScene::editor() const { } /** - Selectionne une liste de parties - @param content liste des parties a selectionner -*/ -void ElementScene::slot_select(const ElementContent &content) { + * @brief ElementScene::slot_select + * Select the item in content, every others items in the scene are deselected + * @param content + */ +void ElementScene::slot_select(const ElementContent &content) +{ blockSignals(true); + + //Befor clear selection, we must to remove the handlers items in @content, + //because if in @content there are a selected item, but also its handlers items, + //When item is deselected, the item delete its handlers items, + //then handlers in content doesn't exist anymore and cause segfault + QList items_list; + for (QGraphicsItem *qgi : content) + { + if(qgi->type() != QetGraphicsHandlerItem::Type) + items_list << qgi; + } clearSelection(); - foreach(QGraphicsItem *qgi, content) qgi -> setSelected(true); + + foreach(QGraphicsItem *qgi, items_list) + qgi -> setSelected(true); + blockSignals(false); emit(selectionChanged()); } /** - Selectionne tout -*/ + * @brief ElementScene::slot_selectAll + * Select all items + */ void ElementScene::slot_selectAll() { slot_select(items()); } /** - Deselectionne tout -*/ + * @brief ElementScene::slot_deselectAll + * deselect all item + */ void ElementScene::slot_deselectAll() { slot_select(ElementContent()); } @@ -811,7 +830,15 @@ void ElementScene::reset() clearSelection(); undoStack().clear(); - foreach (QGraphicsItem *qgi, items()) + //We don't add handlers, because it's the role of the primitive or decorator to remove it. + QList items_list; + for (QGraphicsItem *qgi : items()) + { + if(qgi->type() != QetGraphicsHandlerItem::Type) + items_list << qgi; + } + + for (QGraphicsItem *qgi : items_list) { removeItem(qgi); qgiManager().release(qgi); @@ -1065,9 +1092,16 @@ void ElementScene::managePrimitivesGroups() // should we hide the decorator? QList selected_items = zItems(ElementScene::Selected | ElementScene::IncludeTerminals); if (selected_items.size() <= 1) + { m_decorator -> hide(); + } else { + for(QGraphicsItem *qgi : selected_items) + { + //We recall set selected, then every primitive will remove there handler because there are several item selected + qgi->setSelected(true); + } m_decorator -> setZValue(1000000); m_decorator -> setPos(0, 0); m_decorator -> setItems(selected_items); diff --git a/sources/editor/elementscene.h b/sources/editor/elementscene.h index d6cbbf11a..39cb19473 100644 --- a/sources/editor/elementscene.h +++ b/sources/editor/elementscene.h @@ -44,13 +44,13 @@ class ElementScene : public QGraphicsScene public: enum Behavior { Normal, PasteArea, AddPart }; enum ItemOption { - SortByZValue = 1, - IncludeTerminals = 2, - IncludeHelperItems = 4, - Selected = 8, - NonSelected = 16, - SelectedOrNot = 24 - }; + SortByZValue = 1, + IncludeTerminals = 2, + IncludeHelperItems = 4, + Selected = 8, + NonSelected = 16, + SelectedOrNot = 24 + }; Q_DECLARE_FLAGS(ItemOptions, ItemOption) // constructors, destructor @@ -82,7 +82,7 @@ class ElementScene : public QGraphicsScene QETElementEditor *m_element_editor = nullptr; /// Variables to manage the paste area on the scene - QGraphicsRectItem *m_paste_area = nullptr; + QGraphicsRectItem *m_paste_area; QRectF m_defined_paste_area; /// Variables to handle copy/paste with offset diff --git a/sources/editor/graphicspart/abstractpartellipse.cpp b/sources/editor/graphicspart/abstractpartellipse.cpp index 392ba0fae..27f171170 100644 --- a/sources/editor/graphicspart/abstractpartellipse.cpp +++ b/sources/editor/graphicspart/abstractpartellipse.cpp @@ -118,6 +118,7 @@ void AbstractPartEllipse::setRect(const QRectF &rect) if (rect == m_rect) return; prepareGeometryChange(); m_rect = rect; + emit rectChanged(); } diff --git a/sources/editor/graphicspart/abstractpartellipse.h b/sources/editor/graphicspart/abstractpartellipse.h index 323c867de..e196da118 100644 --- a/sources/editor/graphicspart/abstractpartellipse.h +++ b/sources/editor/graphicspart/abstractpartellipse.h @@ -20,6 +20,8 @@ #include "customelementgraphicpart.h" +class QetGraphicsHandlerItem; + /** * @brief The AbstractPartEllipse class * This is the base class for all ellipse based item like ellipse, circle, arc. @@ -61,20 +63,21 @@ class AbstractPartEllipse : public CustomElementGraphicPart virtual QPointF sceneTopLeft() const; QRectF rect() const; - void setRect (const QRectF &rect); + virtual void setRect (const QRectF &rect); virtual bool isUseless() const; int startAngle() const {return m_start_angle;} - void setStartAngle (const int &start_angle); + virtual void setStartAngle (const int &start_angle); int spanAngle () const {return m_span_angle;} - void setSpanAngle (const int &span_angle); + virtual void setSpanAngle (const int &span_angle); protected: QList saved_points_; QRectF m_rect; qreal m_start_angle; qreal m_span_angle; + QVector m_handler_vector; }; #endif // ABSTRACTPARTELLIPSE_H diff --git a/sources/editor/graphicspart/partarc.cpp b/sources/editor/graphicspart/partarc.cpp index 09aaaad3f..90df79d43 100644 --- a/sources/editor/graphicspart/partarc.cpp +++ b/sources/editor/graphicspart/partarc.cpp @@ -18,6 +18,8 @@ #include "partarc.h" #include "QPropertyUndoCommand/qpropertyundocommand.h" #include "elementscene.h" +#include "QetGraphicsItemModeler/qetgraphicshandleritem.h" +#include "QetGraphicsItemModeler/qetgraphicshandlerutility.h" /** @@ -37,8 +39,10 @@ PartArc::PartArc(QETElementEditor *editor, QGraphicsItem *parent) : * @brief PartArc::~PartArc * Destructor */ -PartArc::~PartArc() { +PartArc::~PartArc() +{ if(m_undo_command) delete m_undo_command; + removeHandler(); } /** @@ -82,15 +86,7 @@ void PartArc::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, drawShadowShape(painter); if (isSelected()) - { drawCross(m_rect.center(), painter); - if (scene()->selectedItems().size() == 1) { - if (m_resize_mode == 3) - m_handler.drawHandler(painter, m_handler.pointsForArc(m_rect, m_start_angle /16, m_span_angle /16)); - else - m_handler.drawHandler(painter, m_handler.pointsForRect(m_rect)); - } - } } /** @@ -129,16 +125,6 @@ void PartArc::fromXml(const QDomElement &qde) { m_span_angle = qde.attribute("angle", "-1440").toDouble() * 16; } -QRectF PartArc::boundingRect() const -{ - QRectF r = AbstractPartEllipse::boundingRect(); - - foreach(QRectF rect, m_handler.handlerRect(m_handler.pointsForRect(m_rect))) - r |= rect; - - return r; -} - /** * @brief PartArc::shape * @return the shape of this item @@ -153,10 +139,6 @@ QPainterPath PartArc::shape() const pps.setWidth(m_hovered? penWeight()+SHADOWS_HEIGHT : penWeight()); shape = pps.createStroke(shape); - if (isSelected()) - foreach(QRectF rect, m_handler.handlerRect(m_handler.pointsForRect(m_rect))) - shape.addRect(rect); - return shape; } @@ -172,135 +154,6 @@ QPainterPath PartArc::shadowShape() const return (pps.createStroke(shape)); } -void PartArc::hoverMoveEvent(QGraphicsSceneHoverEvent *event) -{ - if (!isSelected()) - { - CustomElementGraphicPart::hoverMoveEvent(event); - return; - } - - if (m_resize_mode == 1 || m_resize_mode == 2) { - int handler = m_handler.pointIsHoverHandler(event->pos(), m_handler.pointsForRect(m_rect)); - - if (handler >= 0) - { - if (handler == 0 || handler == 2 || handler == 5 || handler == 7) - setCursor(Qt::SizeAllCursor); - else if (handler == 1 || handler == 6) - setCursor(Qt::SizeVerCursor); - else if (handler == 3 || handler == 4) - setCursor(Qt::SizeHorCursor); - - return; - } - } - else if (m_resize_mode == 3) { - if (m_handler.pointIsHoverHandler(event->pos(), m_handler.pointsForArc(m_rect, m_start_angle /16, m_span_angle /16)) >= 0) { - setCursor(Qt::SizeAllCursor); - return; - } - } - - CustomElementGraphicPart::hoverMoveEvent(event); -} - -/** - * @brief PartArc::mousePressEvent - * Handle mouse press event - * @param event - */ -void PartArc::mousePressEvent(QGraphicsSceneMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) - { - setCursor(Qt::ClosedHandCursor); - if (isSelected()) - { - //resize rect - if (m_resize_mode == 1 || m_resize_mode == 2) { - m_handler_index = m_handler.pointIsHoverHandler(event->pos(), m_handler.pointsForRect(m_rect)); - - if(m_handler_index >= 0 && m_handler_index <= 7) //User click on an handler - { - m_undo_command = new QPropertyUndoCommand(this, "rect", QVariant(m_rect)); - m_undo_command->setText(tr("Modifier un arc")); - m_undo_command->enableAnimation(); - return; - } - } - //resize angle - if (m_resize_mode == 3) { - m_handler_index = m_handler.pointIsHoverHandler(event->pos(), m_handler.pointsForArc(m_rect, m_start_angle /16, m_span_angle /16)); - if (m_handler_index == 0) { - m_span_point = m_handler.pointsForArc(m_rect, m_start_angle /16, m_span_angle /16).at(1); - - m_undo_command = new QPropertyUndoCommand(this, "startAngle", QVariant(m_start_angle)); - m_undo_command->setText(tr("Modifier un arc")); - m_undo_command->enableAnimation(); - - m_undo_command2 = new QPropertyUndoCommand(this, "spanAngle", QVariant(m_span_angle), m_undo_command); - m_undo_command2->setText(tr("Modifier un arc")); - m_undo_command2->enableAnimation(); - - return; - } - else if (m_handler_index == 1) { - m_undo_command = new QPropertyUndoCommand(this, "spanAngle", QVariant(m_span_angle)); - m_undo_command->setText(tr("Modifier un arc")); - m_undo_command->enableAnimation(); - - return; - } - } - - } - } - - CustomElementGraphicPart::mousePressEvent(event); -} - -/** - * @brief PartArc::mouseMoveEvent - * Handle mouse move event - * @param event - */ -void PartArc::mouseMoveEvent(QGraphicsSceneMouseEvent *event) -{ - if (m_resize_mode == 1 || m_resize_mode == 2) { - if (m_handler_index >= 0 && m_handler_index <= 7) { - QPointF pos_ = event->modifiers() == Qt::ControlModifier ? event->pos() : mapFromScene(elementScene()->snapToGrid(event->scenePos())); - prepareGeometryChange(); - - if (m_resize_mode == 1) - setRect(m_handler.rectForPosAtIndex(m_rect, pos_, m_handler_index)); - else - setRect(m_handler.mirrorRectForPosAtIndex(m_rect, pos_, m_handler_index)); - - return; - } - } - else if (m_resize_mode == 3) { - if (m_handler_index == 0 || m_handler_index == 1) { - QLineF line(m_rect.center(), event->pos()); - prepareGeometryChange(); - - if (m_handler_index == 0) { - setStartAngle(line.angle()*16); - setSpanAngle(line.angleTo(QLineF(m_rect.center(), m_span_point))*16); - } - else if (m_handler_index == 1) { - QLineF line2(m_rect.center(), m_handler.pointsForArc(m_rect, m_start_angle/16, m_span_angle/16).at(0)); - setSpanAngle (line2.angleTo(line)*16); - } - - return; - } - } - - CustomElementGraphicPart::mouseMoveEvent(event); -} - /** * @brief PartArc::mouseReleaseEvent * Handle mouse release event @@ -308,59 +161,317 @@ void PartArc::mouseMoveEvent(QGraphicsSceneMouseEvent *event) */ void PartArc::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { - if (event->button() == Qt::LeftButton) { - setCursor(Qt::OpenHandCursor); - if (event->buttonDownPos(Qt::LeftButton) == event->pos()) - switchResizeMode(); - } + if (event->button() == Qt::LeftButton && event->buttonDownPos(Qt::LeftButton) == event->pos()) + switchResizeMode(); - if (m_resize_mode == 1 || m_resize_mode == 2) { - if (m_handler_index >= 0 && m_handler_index <= 7) { - if (!m_rect.isValid()) - m_rect = m_rect.normalized(); + CustomElementGraphicPart::mouseReleaseEvent(event); +} - m_undo_command->setNewValue(QVariant(m_rect)); - elementScene()->undoStack().push(m_undo_command); - m_undo_command = nullptr; - m_handler_index = -1; - return; +/** + * @brief PartArc::itemChange + * @param change + * @param value + * @return + */ +QVariant PartArc::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) +{ + if (change == ItemSelectedHasChanged && scene()) + { + if (value.toBool() == true) + { + //When item is selected, he must to be up to date whene the selection in the scene change, for display or not the handler, + //according to the number of selected items. + connect(scene(), &QGraphicsScene::selectionChanged, this, &PartArc::sceneSelectionChanged); + + if (scene()->selectedItems().size() == 1) + addHandler(); + } + else + { + disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartArc::sceneSelectionChanged); + removeHandler(); } } - else if (m_resize_mode == 3) { - if (m_handler_index == 0) { + else if (change == ItemPositionHasChanged) + { + adjusteHandlerPos(); + } + else if (change == ItemSceneChange) + { + if(scene()) + disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartArc::sceneSelectionChanged); + + setSelected(false); //This is item removed from scene, then we deselect this, and so, the handlers is also removed. + } + + return QGraphicsItem::itemChange(change, value); +} + +/** + * @brief PartArc::sceneEventFilter + * @param watched + * @param event + * @return + */ +bool PartArc::sceneEventFilter(QGraphicsItem *watched, QEvent *event) +{ + //Watched must be an handler + if(watched->type() == QetGraphicsHandlerItem::Type) + { + QetGraphicsHandlerItem *qghi = qgraphicsitem_cast(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(event)); + return true; + } + else if(event->type() == QEvent::GraphicsSceneMouseMove) //Move + { + handlerMouseMoveEvent(qghi, static_cast(event)); + return true; + } + else if (event->type() == QEvent::GraphicsSceneMouseRelease) //Release + { + handlerMouseReleaseEvent(qghi, static_cast(event)); + return true; + } + } + } + } + + return false; +} + +/** + * @brief PartArc::switchResizeMode + */ +void PartArc::switchResizeMode() +{ + if (m_resize_mode == 1) + { + m_resize_mode = 2; + for (QetGraphicsHandlerItem *qghi : m_handler_vector) + qghi->setColor(Qt::darkGreen); + } + else if (m_resize_mode == 2) + { + m_resize_mode = 3; + + //From rect mode to angle mode, then numbers of handlers change + removeHandler(); + addHandler(); + + for (QetGraphicsHandlerItem *qghi : m_handler_vector) + qghi->setColor(Qt::magenta); + } + else + { + m_resize_mode = 1; + + //From angle mode to rect mode, then numbers of handlers change + removeHandler(); + addHandler(); + + for (QetGraphicsHandlerItem *qghi : m_handler_vector) + qghi->setColor(Qt::blue); + } +} + +/** + * @brief PartArc::adjusteHandlerPos + */ +void PartArc::adjusteHandlerPos() +{ + if (m_handler_vector.isEmpty()) + return; + + QVector points_vector; + + if(m_resize_mode == 3) + points_vector = QetGraphicsHandlerUtility::pointsForArc(m_rect, m_start_angle/16, m_span_angle/16); + else + points_vector = QetGraphicsHandlerUtility::pointsForRect(m_rect); + + + if (m_handler_vector.size() == points_vector.size()) + { + points_vector = mapToScene(points_vector); + for (int i = 0 ; i < points_vector.size() ; ++i) + m_handler_vector.at(i)->setPos(points_vector.at(i)); + } +} + +/** + * @brief PartArc::handlerMousePressEvent + * @param qghi + * @param event + */ +void PartArc::handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + Q_UNUSED(event); + + if (m_resize_mode == 3) //Resize angle + { + if (m_vector_index == 0) + { + m_span_point = QetGraphicsHandlerUtility::pointsForArc(m_rect, m_start_angle /16, m_span_angle /16).at(1); + + m_undo_command = new QPropertyUndoCommand(this, "startAngle", QVariant(m_start_angle)); + m_undo_command->setText(tr("Modifier un arc")); + m_undo_command->enableAnimation(); + + m_undo_command2 = new QPropertyUndoCommand(this, "spanAngle", QVariant(m_span_angle), m_undo_command); + m_undo_command2->setText(tr("Modifier un arc")); + m_undo_command2->enableAnimation(); + } + else if (m_vector_index == 1) + { + m_undo_command = new QPropertyUndoCommand(this, "spanAngle", QVariant(m_span_angle)); + m_undo_command->setText(tr("Modifier un arc")); + m_undo_command->enableAnimation(); + } + } + else //resize rect + { + m_undo_command = new QPropertyUndoCommand(this, "rect", QVariant(m_rect)); + m_undo_command->setText(tr("Modifier un arc")); + m_undo_command->enableAnimation(); + } +} + +/** + * @brief PartArc::handlerMouseMoveEvent + * @param qghi + * @param event + */ +void PartArc::handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + + QPointF new_pos = event->scenePos(); + if (event->modifiers() != Qt::ControlModifier) + new_pos = elementScene()->snapToGrid(event->scenePos()); + new_pos = mapFromScene(new_pos); + + if (m_resize_mode == 1) + setRect(QetGraphicsHandlerUtility::rectForPosAtIndex(m_rect, new_pos, m_vector_index)); + else if (m_resize_mode == 2) + setRect(QetGraphicsHandlerUtility::mirrorRectForPosAtIndex(m_rect, new_pos, m_vector_index)); + else + { + QLineF line(m_rect.center(), mapFromItem(qghi, event->pos())); + prepareGeometryChange(); + + if (m_vector_index == 0) { + setStartAngle(line.angle()*16); + setSpanAngle(line.angleTo(QLineF(m_rect.center(), m_span_point))*16); + } + else if (m_vector_index == 1) { + QLineF line2(m_rect.center(), QetGraphicsHandlerUtility::pointsForArc(m_rect, m_start_angle/16, m_span_angle/16).at(0)); + setSpanAngle (line2.angleTo(line)*16); + } + } +} + +/** + * @brief PartArc::handlerMouseReleaseEvent + * @param qghi + * @param event + */ +void PartArc::handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + Q_UNUSED(event); + + if (m_resize_mode == 3) + { + if (m_vector_index == 0) + { m_undo_command->setNewValue(QVariant(m_start_angle)); m_undo_command2->setNewValue(QVariant(m_span_angle)); elementScene()->undoStack().push(m_undo_command); m_undo_command = nullptr; m_undo_command2 = nullptr; - m_handler_index = -1; - return; + m_vector_index = -1; } - else if (m_handler_index == 1) { + else if (m_vector_index == 1) + { m_undo_command->setNewValue(QVariant(m_span_angle)); elementScene()->undoStack().push(m_undo_command); m_undo_command = nullptr; - m_handler_index = -1; - return; + m_vector_index = -1; } } + else + { + if (!m_rect.isValid()) + m_rect = m_rect.normalized(); - CustomElementGraphicPart::mouseReleaseEvent(event); + m_undo_command->setNewValue(QVariant(m_rect)); + elementScene()->undoStack().push(m_undo_command); + m_undo_command = nullptr; + m_vector_index = -1; + } } -void PartArc::switchResizeMode() +/** + * @brief PartArc::sceneSelectionChanged + * When the scene selection change, if there are several primitive selected, we remove the handler of this item + */ +void PartArc::sceneSelectionChanged() { - if (m_resize_mode == 1) { - m_resize_mode = 2; - m_handler.setOuterColor(Qt::darkGreen); - } - else if (m_resize_mode == 2 ) { - m_resize_mode = 3; - m_handler.setOuterColor(Qt::magenta); - } - else { - m_resize_mode = 1; - m_handler.setOuterColor(Qt::blue); - } - update(); + if (this->isSelected() && scene()->selectedItems().size() == 1) + addHandler(); + else + removeHandler(); +} + +/** + * @brief PartArc::addHandler + * Add handlers for this item + */ +void PartArc::addHandler() +{ + if (m_handler_vector.isEmpty() && scene()) + { + if(m_resize_mode == 3) + { + m_handler_vector = QetGraphicsHandlerItem::handlerForPoint(mapToScene(QetGraphicsHandlerUtility::pointsForArc(m_rect, m_start_angle/16, m_span_angle/16))); + } + else + m_handler_vector = QetGraphicsHandlerItem::handlerForPoint(mapToScene(QetGraphicsHandlerUtility::pointsForRect(m_rect))); + + for(QetGraphicsHandlerItem *handler : m_handler_vector) + { + QColor color = Qt::blue; + if (m_resize_mode == 2) + color = Qt::darkGreen; + else if (m_resize_mode == 3) + color = Qt::magenta; + + handler->setColor(color); + scene()->addItem(handler); + handler->installSceneEventFilter(this); + handler->setZValue(this->zValue()+1); + } + } +} + +/** + * @brief PartArc::removeHandler + * Remove the handlers of this item + */ +void PartArc::removeHandler() +{ + if (!m_handler_vector.isEmpty()) + { + qDeleteAll(m_handler_vector); + m_handler_vector.clear(); + } } diff --git a/sources/editor/graphicspart/partarc.h b/sources/editor/graphicspart/partarc.h index 1bd156b17..348e96506 100644 --- a/sources/editor/graphicspart/partarc.h +++ b/sources/editor/graphicspart/partarc.h @@ -19,9 +19,9 @@ #define PART_ARC_H #include "abstractpartellipse.h" -#include "QetGraphicsItemModeler/qetgraphicshandlerutility.h" class QPropertyUndoCommand; +class QetGraphicsHandlerItem; /** * @brief The PartArc class @@ -54,25 +54,34 @@ class PartArc : public AbstractPartEllipse virtual const QDomElement toXml (QDomDocument &) const; virtual void fromXml (const QDomElement &); - virtual QRectF boundingRect() const; virtual QPainterPath shape() const; virtual QPainterPath shadowShape() const; + virtual void setRect(const QRectF &rect) {AbstractPartEllipse::setRect(rect); adjusteHandlerPos();} + virtual void setStartAngle(const int &start_angle) {AbstractPartEllipse::setStartAngle(start_angle); adjusteHandlerPos();} + virtual void setSpanAngle(const int &span_angle) {AbstractPartEllipse::setSpanAngle(span_angle); adjusteHandlerPos();} protected: - virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); - virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); + virtual bool sceneEventFilter(QGraphicsItem *watched, QEvent *event); private: void switchResizeMode(); + void adjusteHandlerPos(); + void handlerMousePressEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseMoveEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseReleaseEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void sceneSelectionChanged (); + + void addHandler(); + void removeHandler(); private: - QetGraphicsHandlerUtility m_handler = 10; - int m_handler_index = -1; QPropertyUndoCommand *m_undo_command = nullptr; QPropertyUndoCommand *m_undo_command2 = nullptr; - int m_resize_mode = 1; + int m_resize_mode = 1, + m_vector_index = -1; QPointF m_span_point; + QVector m_handler_vector; }; #endif diff --git a/sources/editor/graphicspart/partellipse.cpp b/sources/editor/graphicspart/partellipse.cpp index 93f76486c..97ae2a718 100644 --- a/sources/editor/graphicspart/partellipse.cpp +++ b/sources/editor/graphicspart/partellipse.cpp @@ -18,6 +18,8 @@ #include "partellipse.h" #include "QPropertyUndoCommand/qpropertyundocommand.h" #include "elementscene.h" +#include "QetGraphicsItemModeler/qetgraphicshandleritem.h" +#include "QetGraphicsItemModeler/qetgraphicshandlerutility.h" /** * @brief PartEllipse::PartEllipse @@ -27,8 +29,6 @@ */ PartEllipse::PartEllipse(QETElementEditor *editor, QGraphicsItem *parent) : AbstractPartEllipse(editor, parent), - m_handler(10), - m_handler_index(-1), m_undo_command(nullptr) {} @@ -36,8 +36,10 @@ PartEllipse::PartEllipse(QETElementEditor *editor, QGraphicsItem *parent) : * @brief PartEllipse::~PartEllipse * Destructor */ -PartEllipse::~PartEllipse() { +PartEllipse::~PartEllipse() +{ if(m_undo_command) delete m_undo_command; + removeHandler(); } /** @@ -65,11 +67,7 @@ void PartEllipse::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio drawShadowShape(painter); if (isSelected()) - { drawCross(m_rect.center(), painter); - if (scene()->selectedItems().size() == 1) - m_handler.drawHandler(painter, m_handler.pointsForRect(m_rect)); - } } /** @@ -125,16 +123,6 @@ void PartEllipse::fromXml(const QDomElement &qde) QSizeF(width, height)); } -QRectF PartEllipse::boundingRect() const -{ - QRectF r = AbstractPartEllipse::boundingRect(); - - foreach(QRectF rect, m_handler.handlerRect(m_handler.pointsForRect(m_rect))) - r |= rect; - - return r; -} - /** * @brief PartEllipse::shape * @return the shape of this item @@ -148,10 +136,6 @@ QPainterPath PartEllipse::shape() const pps.setWidth(m_hovered? penWeight()+SHADOWS_HEIGHT : penWeight()); shape = pps.createStroke(shape); - if (isSelected()) - foreach(QRectF rect, m_handler.handlerRect(m_handler.pointsForRect(m_rect))) - shape.addRect(rect); - return shape; } @@ -166,77 +150,6 @@ QPainterPath PartEllipse::shadowShape() const return (pps.createStroke(shape)); } -void PartEllipse::hoverMoveEvent(QGraphicsSceneHoverEvent *event) -{ - if (!isSelected()) - { - CustomElementGraphicPart::hoverMoveEvent(event); - return; - } - - int handler = m_handler.pointIsHoverHandler(event->pos(), m_handler.pointsForRect(m_rect)); - - if (handler >= 0) - { - if (handler == 0 || handler == 2 || handler == 5 || handler == 7) - setCursor(Qt::SizeAllCursor); - else if (handler == 1 || handler == 6) - setCursor(Qt::SizeVerCursor); - else if (handler == 3 || handler == 4) - setCursor(Qt::SizeHorCursor); - } - else - CustomElementGraphicPart::hoverMoveEvent(event); -} - -/** - * @brief PartEllipse::mousePressEvent - * Handle mouse press event - * @param event - */ -void PartEllipse::mousePressEvent(QGraphicsSceneMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) - { - setCursor(Qt::ClosedHandCursor); - if (isSelected()) - { - m_handler_index = m_handler.pointIsHoverHandler(event->pos(), m_handler.pointsForRect(m_rect)); - - if(m_handler_index >= 0 && m_handler_index <= 7) //User click on an handler - { - m_undo_command = new QPropertyUndoCommand(this, "rect", QVariant(m_rect)); - m_undo_command->setText(tr("Modifier une ellipse")); - m_undo_command->enableAnimation(); - return; - } - } - } - - CustomElementGraphicPart::mousePressEvent(event); -} - -/** - * @brief PartEllipse::mouseMoveEvent - * Handle mouse move event - * @param event - */ -void PartEllipse::mouseMoveEvent(QGraphicsSceneMouseEvent *event) -{ - if(m_handler_index >= 0 && m_handler_index <= 7) - { - QPointF pos_ = event->modifiers() == Qt::ControlModifier ? event->pos() : mapFromScene(elementScene()->snapToGrid(event->scenePos())); - prepareGeometryChange(); - - if (m_resize_mode == 1) - setRect(m_handler.rectForPosAtIndex(m_rect, pos_, m_handler_index)); - else - setRect(m_handler.mirrorRectForPosAtIndex(m_rect, pos_, m_handler_index)); - } - else - CustomElementGraphicPart::mouseMoveEvent(event); -} - /** * @brief PartEllipse::mouseReleaseEvent * Handle mouse release event @@ -244,35 +157,225 @@ void PartEllipse::mouseMoveEvent(QGraphicsSceneMouseEvent *event) */ void PartEllipse::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { - if (event->button() == Qt::LeftButton) { - setCursor(Qt::OpenHandCursor); - if (event->buttonDownPos(Qt::LeftButton) == event->pos()) - switchResizeMode(); - } + if (event->button() == Qt::LeftButton && event->buttonDownPos(Qt::LeftButton) == event->pos()) + switchResizeMode(); + + CustomElementGraphicPart::mouseReleaseEvent(event); +} - if (m_handler_index >= 0 && m_handler_index <= 7) +/** + * @brief PartEllipse::itemChange + * @param change + * @param value + * @return + */ +QVariant PartEllipse::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) +{ + if (change == ItemSelectedHasChanged && scene()) { - if (!m_rect.isValid()) - m_rect = m_rect.normalized(); - - m_undo_command->setNewValue(QVariant(m_rect)); - elementScene()->undoStack().push(m_undo_command); - m_undo_command = nullptr; - m_handler_index = -1; + if (value.toBool() == true) + { + //When item is selected, he must to be up to date whene the selection in the scene change, for display or not the handler, + //according to the number of selected items. + connect(scene(), &QGraphicsScene::selectionChanged, this, &PartEllipse::sceneSelectionChanged); + + if (scene()->selectedItems().size() == 1) + addHandler(); + } + else + { + disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartEllipse::sceneSelectionChanged); + removeHandler(); + } } - else - CustomElementGraphicPart::mouseReleaseEvent(event); + else if (change == ItemPositionHasChanged) + { + adjusteHandlerPos(); + } + else if (change == ItemSceneChange) + { + if(scene()) + disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartEllipse::sceneSelectionChanged); + + setSelected(false); //This item is removed from scene, then we deselect this, and so, the handlers is also removed. + } + + return QGraphicsItem::itemChange(change, value); +} + +/** + * @brief PartEllipse::sceneEventFilter + * @param watched + * @param event + * @return + */ +bool PartEllipse::sceneEventFilter(QGraphicsItem *watched, QEvent *event) +{ + //Watched must be an handler + if(watched->type() == QetGraphicsHandlerItem::Type) + { + QetGraphicsHandlerItem *qghi = qgraphicsitem_cast(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(event)); + return true; + } + else if(event->type() == QEvent::GraphicsSceneMouseMove) //Move + { + handlerMouseMoveEvent(qghi, static_cast(event)); + return true; + } + else if (event->type() == QEvent::GraphicsSceneMouseRelease) //Release + { + handlerMouseReleaseEvent(qghi, static_cast(event)); + return true; + } + } + } + } + + return false; } void PartEllipse::switchResizeMode() { - if (m_resize_mode == 1) { + if (m_resize_mode == 1) + { m_resize_mode = 2; - m_handler.setOuterColor(Qt::darkGreen); + for (QetGraphicsHandlerItem *qghi : m_handler_vector) + qghi->setColor(Qt::darkGreen); } - else { + else + { m_resize_mode = 1; - m_handler.setOuterColor(Qt::blue); + for (QetGraphicsHandlerItem *qghi : m_handler_vector) + qghi->setColor(Qt::blue); + } +} + +/** + * @brief PartEllipse::adjusteHandlerPos + */ +void PartEllipse::adjusteHandlerPos() +{ + if (m_handler_vector.isEmpty()) + return; + + QVector points_vector = QetGraphicsHandlerUtility::pointsForRect(m_rect); + + if (m_handler_vector.size() == points_vector.size()) + { + points_vector = mapToScene(points_vector); + for (int i = 0 ; i < points_vector.size() ; ++i) + m_handler_vector.at(i)->setPos(points_vector.at(i)); + } +} + +/** + * @brief PartEllipse::handlerMousePressEvent + * @param qghi + * @param event + */ +void PartEllipse::handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + Q_UNUSED(event); + + m_undo_command = new QPropertyUndoCommand(this, "rect", QVariant(m_rect)); + m_undo_command->setText(tr("Modifier un rectangle")); + m_undo_command->enableAnimation(); + return; +} + +/** + * @brief PartEllipse::handlerMouseMoveEvent + * @param qghi + * @param event + */ +void PartEllipse::handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + + QPointF new_pos = event->scenePos(); + if (event->modifiers() != Qt::ControlModifier) + new_pos = elementScene()->snapToGrid(event->scenePos()); + new_pos = mapFromScene(new_pos); + + if (m_resize_mode == 1) + setRect(QetGraphicsHandlerUtility::rectForPosAtIndex(m_rect, new_pos, m_vector_index)); + else + setRect(QetGraphicsHandlerUtility::mirrorRectForPosAtIndex(m_rect, new_pos, m_vector_index)); + + adjusteHandlerPos(); +} + +/** + * @brief PartEllipse::handlerMouseReleaseEvent + * @param qghi + * @param event + */ +void PartEllipse::handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + Q_UNUSED(event); + + m_undo_command->setNewValue(QVariant(m_rect)); + elementScene()->undoStack().push(m_undo_command); + m_undo_command = nullptr; + m_vector_index = -1; +} + +/** + * @brief PartEllipse::sceneSelectionChanged + * When the scene selection change, if there are several primitive selected, we remove the handler of this item + */ +void PartEllipse::sceneSelectionChanged() +{ + if (this->isSelected() && scene()->selectedItems().size() == 1) + addHandler(); + else + removeHandler(); +} + +/** + * @brief PartEllipse::addHandler + * Add handlers for this item + */ +void PartEllipse::addHandler() +{ + if (m_handler_vector.isEmpty() && scene()) + { + m_handler_vector = QetGraphicsHandlerItem::handlerForPoint(mapToScene(QetGraphicsHandlerUtility::pointsForRect(m_rect))); + + for(QetGraphicsHandlerItem *handler : m_handler_vector) + { + QColor color = Qt::blue; + if (m_resize_mode == 2) + color = Qt::darkGreen; + + handler->setColor(color); + scene()->addItem(handler); + handler->installSceneEventFilter(this); + handler->setZValue(this->zValue()+1); + } + } +} + +/** + * @brief PartEllipse::removeHandler + * Remove the handlers of this item + */ +void PartEllipse::removeHandler() +{ + if (!m_handler_vector.isEmpty()) + { + qDeleteAll(m_handler_vector); + m_handler_vector.clear(); } - update(); } diff --git a/sources/editor/graphicspart/partellipse.h b/sources/editor/graphicspart/partellipse.h index 7fe10594a..8369c8aec 100644 --- a/sources/editor/graphicspart/partellipse.h +++ b/sources/editor/graphicspart/partellipse.h @@ -19,7 +19,6 @@ #define PART_ELLIPSE_H #include "abstractpartellipse.h" -#include "QetGraphicsItemModeler/qetgraphicshandlerutility.h" class QPropertyUndoCommand; @@ -55,24 +54,29 @@ class PartEllipse : public AbstractPartEllipse virtual QString xmlName() const { return(QString("ellipse")); } virtual const QDomElement toXml (QDomDocument &) const; virtual void fromXml (const QDomElement &); - - virtual QRectF boundingRect() const; virtual QPainterPath shape() const; virtual QPainterPath shadowShape() const; + virtual void setRect(const QRectF &rect) {AbstractPartEllipse::setRect(rect); adjusteHandlerPos();} protected: - virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); - virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); + virtual bool sceneEventFilter(QGraphicsItem *watched, QEvent *event); private: void switchResizeMode(); + void adjusteHandlerPos(); + void handlerMousePressEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseMoveEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseReleaseEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void sceneSelectionChanged (); + + void addHandler(); + void removeHandler(); private: - QetGraphicsHandlerUtility m_handler; - int m_handler_index; QPropertyUndoCommand *m_undo_command; - int m_resize_mode = 1; + int m_resize_mode = 1, + m_vector_index = -1; }; #endif diff --git a/sources/editor/graphicspart/partline.cpp b/sources/editor/graphicspart/partline.cpp index 1985aae0f..05ed70612 100644 --- a/sources/editor/graphicspart/partline.cpp +++ b/sources/editor/graphicspart/partline.cpp @@ -19,6 +19,7 @@ #include #include "elementscene.h" #include "QPropertyUndoCommand/qpropertyundocommand.h" +#include "QetGraphicsItemModeler/qetgraphicshandleritem.h" /** @@ -33,14 +34,16 @@ PartLine::PartLine(QETElementEditor *editor, QGraphicsItem *parent) : first_length(1.5), second_end(Qet::None), second_length(1.5), - m_handler(10), - m_handler_index(-1), m_undo_command(nullptr) {} /// Destructeur -PartLine::~PartLine() { - if(m_undo_command) delete m_undo_command; +PartLine::~PartLine() +{ + if(m_undo_command) + delete m_undo_command; + + removeHandler(); } /** @@ -90,9 +93,6 @@ void PartLine::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, if (m_hovered) drawShadowShape(painter); - if (isSelected() && scene()->selectedItems().size() == 1) - m_handler.drawHandler(painter, m_handler.pointsForLine(m_line)); - painter->restore(); } @@ -140,69 +140,206 @@ void PartLine::fromXml(const QDomElement &qde) { } /** - * @brief PartLine::mousePressEvent - * Handle mouse press event - * @param event + * @brief PartLine::itemChange + * @param change + * @param value + * @return */ -void PartLine::mousePressEvent(QGraphicsSceneMouseEvent *event) +QVariant PartLine::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { - if(event->button() == Qt::LeftButton) + if (change == ItemSelectedHasChanged && scene()) { - setCursor(Qt::ClosedHandCursor); - - if (isSelected()) + if (value.toBool() == true) { - m_handler_index = m_handler.pointIsHoverHandler(event->pos(), m_handler.pointsForLine(m_line)); + //When item is selected, he must to be up to date whene the selection in the scene change, for display or not the handler, + //according to the number of selected items. + connect(scene(), &QGraphicsScene::selectionChanged, this, &PartLine::sceneSelectionChanged); + + if (scene()->selectedItems().size() == 1) + addHandler(); + } + else + { + disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartLine::sceneSelectionChanged); + removeHandler(); + } + } + else if (change == ItemPositionHasChanged) + { + adjusteHandlerPos(); + } + else if (change == ItemSceneChange) + { + if(scene()) + disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartLine::sceneSelectionChanged); + + setSelected(false); //This is item removed from scene, then we deselect this, and so, the handlers is also removed. + } + + return QGraphicsItem::itemChange(change, value); +} - if(m_handler_index >= 0 && m_handler_index <= 1) //User click on an handler +/** + * @brief PartLine::sceneEventFilter + * @param watched + * @param event + * @return + */ +bool PartLine::sceneEventFilter(QGraphicsItem *watched, QEvent *event) +{ + //Watched must be an handler + if(watched->type() == QetGraphicsHandlerItem::Type) + { + QetGraphicsHandlerItem *qghi = qgraphicsitem_cast(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) { - m_undo_command = new QPropertyUndoCommand(this, "line", QVariant(m_line)); - m_undo_command->setText(tr("Modifier une ligne")); - m_undo_command->enableAnimation(); - return; + if(event->type() == QEvent::GraphicsSceneMousePress) //Click + { + handlerMousePressEvent(qghi, static_cast(event)); + return true; + } + else if(event->type() == QEvent::GraphicsSceneMouseMove) //Move + { + handlerMouseMoveEvent(qghi, static_cast(event)); + return true; + } + else if (event->type() == QEvent::GraphicsSceneMouseRelease) //Release + { + handlerMouseReleaseEvent(qghi, static_cast(event)); + return true; + } } } } - - CustomElementGraphicPart::mousePressEvent(event); + + return false; } /** - * @brief PartLine::mouseMoveEvent - * Handle pouse move event - * @param event + * @brief PartLine::adjusteHandlerPos + * Adjust the position of the handler item */ -void PartLine::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +void PartLine::adjusteHandlerPos() { - if(m_handler_index >= 0 && m_handler_index <= 1) + if(m_handler_vector.isEmpty()) + return; + + QVector points_vector; + points_vector << m_line.p1() << m_line.p2(); + + if (m_handler_vector.size() == points_vector.size()) { - QPointF pos_ = event->modifiers() == Qt::ControlModifier ? event->pos() : mapFromScene(elementScene()->snapToGrid(event->scenePos())); - prepareGeometryChange(); - setLine(m_handler.lineForPosAtIndex(m_line, pos_, m_handler_index)); + points_vector = mapToScene(points_vector); + for (int i = 0 ; i < points_vector.size() ; ++i) + m_handler_vector.at(i)->setPos(points_vector.at(i)); } - else - CustomElementGraphicPart::mouseMoveEvent(event); } /** - * @brief PartLine::mouseReleaseEvent - * Handle mouse release event + * @brief PartLine::handlerMousePressEvent + * @param qghi * @param event */ -void PartLine::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +void PartLine::handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) { - if (event->button() == Qt::LeftButton) - setCursor(Qt::OpenHandCursor); + Q_UNUSED(qghi); + Q_UNUSED(event); + + m_undo_command = new QPropertyUndoCommand(this, "line", QVariant(m_line)); + m_undo_command->setText(tr("Modifier une ligne")); + m_undo_command->enableAnimation(); + return; +} - if (m_handler_index >= 0 && m_handler_index <= 1) - { - m_undo_command->setNewValue(QVariant(m_line)); - elementScene()->undoStack().push(m_undo_command); - m_undo_command = nullptr; - m_handler_index = -1; - } +/** + * @brief PartLine::handlerMouseMoveEvent + * @param qghi + * @param event + */ +void PartLine::handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + + QPointF new_pos = event->scenePos(); + if (event->modifiers() != Qt::ControlModifier) + new_pos = elementScene()->snapToGrid(event->scenePos()); + new_pos = mapFromScene(new_pos); + + prepareGeometryChange(); + if (m_vector_index == 0) + m_line.setP1(new_pos); else - CustomElementGraphicPart::mouseReleaseEvent(event); + m_line.setP2(new_pos); + + adjusteHandlerPos(); +} + +/** + * @brief PartLine::handlerMouseReleaseEvent + * @param qghi + * @param event + */ +void PartLine::handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + Q_UNUSED(event); + + m_undo_command->setNewValue(QVariant(m_line)); + elementScene()->undoStack().push(m_undo_command); + m_undo_command = nullptr; + m_vector_index = -1; +} + +/** + * @brief PartLine::sceneSelectionChanged + * When the scene selection change, if there are several primitive selected, we remove the handler of this item + */ +void PartLine::sceneSelectionChanged() +{ + if (this->isSelected() && scene()->selectedItems().size() == 1) + addHandler(); + else + removeHandler(); +} + +/** + * @brief PartLine::addHandler + * Add handlers for this item + */ +void PartLine::addHandler() +{ + if (m_handler_vector.isEmpty() && scene()) + { + QVector points_vector; + points_vector << m_line.p1() << m_line.p2(); + + m_handler_vector = QetGraphicsHandlerItem::handlerForPoint(mapToScene(points_vector)); + + for(QetGraphicsHandlerItem *handler : m_handler_vector) + { + handler->setColor(Qt::blue); + scene()->addItem(handler); + handler->installSceneEventFilter(this); + handler->setZValue(this->zValue()+1); + } + } +} + +/** + * @brief PartLine::removeHandler + * Remove the handlers of this item + */ +void PartLine::removeHandler() +{ + if (!m_handler_vector.isEmpty()) + { + qDeleteAll(m_handler_vector); + m_handler_vector.clear(); + } } /** @@ -243,10 +380,6 @@ QPainterPath PartLine::shape() const pps.setWidth(m_hovered? penWeight()+SHADOWS_HEIGHT : penWeight()); shape = pps.createStroke(shape); - if (isSelected()) - foreach(QRectF rect, m_handler.handlerRect(m_handler.pointsForLine(m_line))) - shape.addRect(rect); - return shape; } @@ -402,9 +535,6 @@ QRectF PartLine::boundingRect() const bound = bound.normalized(); bound.adjust(-adjust, -adjust, adjust, adjust); - foreach(QRectF rect, m_handler.handlerRect(m_handler.pointsForLine(m_line))) - bound |= rect; - return bound; } @@ -496,6 +626,7 @@ void PartLine::setLine(const QLineF &line) if (m_line == line) return; prepareGeometryChange(); m_line = line; + adjusteHandlerPos(); emit lineChanged(); } @@ -533,20 +664,6 @@ void PartLine::setSecondEndLength(const qreal &l) emit secondEndLengthChanged(); } -void PartLine::hoverMoveEvent(QGraphicsSceneHoverEvent *event) -{ - if (!isSelected()) - { - CustomElementGraphicPart::hoverMoveEvent(event); - return; - } - - if (m_handler.pointIsHoverHandler(event->pos(), m_handler.pointsForLine(m_line)) >= 0) - setCursor(Qt::SizeAllCursor); - else - CustomElementGraphicPart::hoverMoveEvent(event); -} - /** * @brief PartLine::path * @return this line has a QPainterPath. diff --git a/sources/editor/graphicspart/partline.h b/sources/editor/graphicspart/partline.h index b28582b77..3a0cc1bf7 100644 --- a/sources/editor/graphicspart/partline.h +++ b/sources/editor/graphicspart/partline.h @@ -20,9 +20,9 @@ #include "customelementgraphicpart.h" #include "qet.h" -#include "QetGraphicsItemModeler/qetgraphicshandlerutility.h" class QPropertyUndoCommand; +class QetGraphicsHandlerItem; /** This class represents a line primitive which may be used to compose the @@ -96,19 +96,26 @@ class PartLine : public CustomElementGraphicPart void setSecondEndLength(const qreal &l); protected: - virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); - virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); - + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); + virtual bool sceneEventFilter(QGraphicsItem *watched, QEvent *event); + private: + void adjusteHandlerPos(); + void handlerMousePressEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseMoveEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseReleaseEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void sceneSelectionChanged (); + + void addHandler(); + void removeHandler(); + QPainterPath path() const; - QList fourShapePoints() const; QRectF firstEndCircleRect() const; QRectF secondEndCircleRect() const; void debugPaint(QPainter *); + /*****************/ Qet::EndType first_end; qreal first_length; @@ -116,8 +123,8 @@ class PartLine : public CustomElementGraphicPart qreal second_length; QList saved_points_; QLineF m_line; - QetGraphicsHandlerUtility m_handler; - int m_handler_index; + int m_vector_index = -1; QPropertyUndoCommand *m_undo_command; + QVector m_handler_vector; }; #endif diff --git a/sources/editor/graphicspart/partpolygon.cpp b/sources/editor/graphicspart/partpolygon.cpp index 09ef418eb..8d157325f 100644 --- a/sources/editor/graphicspart/partpolygon.cpp +++ b/sources/editor/graphicspart/partpolygon.cpp @@ -18,6 +18,7 @@ #include "partpolygon.h" #include "QPropertyUndoCommand/qpropertyundocommand.h" #include "elementscene.h" +#include "QetGraphicsItemModeler/qetgraphicshandleritem.h" /** @@ -29,16 +30,16 @@ PartPolygon::PartPolygon(QETElementEditor *editor, QGraphicsItem *parent) : CustomElementGraphicPart(editor, parent), m_closed(false), - m_handler(10), - m_handler_index(-1), m_undo_command(nullptr) {} /** * @brief PartPolygon::~PartPolygon */ -PartPolygon::~PartPolygon() { +PartPolygon::~PartPolygon() +{ if(m_undo_command) delete m_undo_command; + removeHandler(); } /** @@ -64,9 +65,6 @@ void PartPolygon::paint(QPainter *painter, const QStyleOptionGraphicsItem *optio if (m_hovered) drawShadowShape(painter); - - if (isSelected() && scene()->selectedItems().size() == 1) - m_handler.drawHandler(painter, m_polygon); } /** @@ -199,6 +197,7 @@ void PartPolygon::setPolygon(const QPolygonF &polygon) if (m_polygon == polygon) return; prepareGeometryChange(); m_polygon = polygon; + adjusteHandlerPos(); emit polygonChanged(); } @@ -248,83 +247,195 @@ void PartPolygon::setClosed(bool close) emit closedChange(); } -void PartPolygon::hoverMoveEvent(QGraphicsSceneHoverEvent *event) +/** + * @brief PartPolygon::itemChange + * @param change + * @param value + * @return + */ +QVariant PartPolygon::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) { - if (!isSelected()) + if (change == ItemSelectedHasChanged && scene()) { - CustomElementGraphicPart::hoverMoveEvent(event); - return; + if (value.toBool() == true) + { + //When item is selected, he must to be up to date whene the selection in the scene change, for display or not the handler, + //according to the number of selected items. + connect(scene(), &QGraphicsScene::selectionChanged, this, &PartPolygon::sceneSelectionChanged); + + if (scene()->selectedItems().size() == 1) + addHandler(); + } + else + { + disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartPolygon::sceneSelectionChanged); + removeHandler(); + } } - - if (m_handler.pointIsHoverHandler(event->pos(), m_polygon) >= 0) - setCursor(Qt::SizeAllCursor); - else - CustomElementGraphicPart::hoverMoveEvent(event); + else if (change == ItemPositionHasChanged) + { + adjusteHandlerPos(); + } + else if (change == ItemSceneChange) + { + if(scene()) + disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartPolygon::sceneSelectionChanged); + + setSelected(false); //This is item removed from scene, then we deselect this, and so, the handlers is also removed. + } + + return QGraphicsItem::itemChange(change, value); } /** - * @brief PartPolygon::mousePressEvent - * Handle mouse press event + * @brief PartPolygon::sceneEventFilter + * @param watched * @param event + * @return */ -void PartPolygon::mousePressEvent(QGraphicsSceneMouseEvent *event) +bool PartPolygon::sceneEventFilter(QGraphicsItem *watched, QEvent *event) { - if (event->button() == Qt::LeftButton) + //Watched must be an handler + if(watched->type() == QetGraphicsHandlerItem::Type) { - setCursor(Qt::ClosedHandCursor); - if(isSelected()) + QetGraphicsHandlerItem *qghi = qgraphicsitem_cast(watched); + + if(m_handler_vector.contains(qghi)) //Handler must be in m_vector_index, then we can start resize { - m_handler_index = m_handler.pointIsHoverHandler(event->pos(), m_polygon); - - if(m_handler_index >= 0) //User click on an handler + m_vector_index = m_handler_vector.indexOf(qghi); + if (m_vector_index != -1) { - m_undo_command = new QPropertyUndoCommand(this, "polygon", QVariant(m_polygon)); - m_undo_command->setText(tr("Modifier un polygone")); - return; + if(event->type() == QEvent::GraphicsSceneMousePress) //Click + { + handlerMousePressEvent(qghi, static_cast(event)); + return true; + } + else if(event->type() == QEvent::GraphicsSceneMouseMove) //Move + { + handlerMouseMoveEvent(qghi, static_cast(event)); + return true; + } + else if (event->type() == QEvent::GraphicsSceneMouseRelease) //Release + { + handlerMouseReleaseEvent(qghi, static_cast(event)); + return true; + } } } } - - CustomElementGraphicPart::mousePressEvent(event); + + return false; } /** - * @brief PartPolygon::mouseMoveEvent - * Handle mouse move event - * @param event + * @brief PartPolygon::adjusteHandlerPos */ -void PartPolygon::mouseMoveEvent(QGraphicsSceneMouseEvent *event) +void PartPolygon::adjusteHandlerPos() { - if(m_handler_index >= 0) + if(m_handler_vector.isEmpty()) + return; + + if (m_handler_vector.size() == m_polygon.size()) { - QPointF pos_ = event->modifiers() == Qt::ControlModifier ? event->pos() : mapFromScene(elementScene()->snapToGrid(event->scenePos())); - prepareGeometryChange(); - m_polygon.replace(m_handler_index, pos_); - emit polygonChanged(); + QVector points_vector = mapToScene(m_polygon); + for (int i = 0 ; i < points_vector.size() ; ++i) + m_handler_vector.at(i)->setPos(points_vector.at(i)); } - else - CustomElementGraphicPart::mouseMoveEvent(event); } /** - * @brief PartPolygon::mouseReleaseEvent - * Handle mouse release event + * @brief PartPolygon::handlerMousePressEvent + * @param qghi * @param event */ -void PartPolygon::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +void PartPolygon::handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) { - if (event->button() == Qt::LeftButton) - setCursor(Qt::OpenHandCursor); + Q_UNUSED(qghi); + Q_UNUSED(event); + + m_undo_command = new QPropertyUndoCommand(this, "polygon", QVariant(m_polygon)); + m_undo_command->setText(tr("Modifier un polygone")); +} - if (m_handler_index >= 0) - { - m_undo_command->setNewValue(QVariant(m_polygon)); - elementScene()->undoStack().push(m_undo_command); - m_undo_command = nullptr; - m_handler_index = -1; - } +/** + * @brief PartPolygon::handlerMouseMoveEvent + * @param qghi + * @param event + */ +void PartPolygon::handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + + QPointF new_pos = event->scenePos(); + if (event->modifiers() != Qt::ControlModifier) + new_pos = elementScene()->snapToGrid(event->scenePos()); + new_pos = mapFromScene(new_pos); + + prepareGeometryChange(); + m_polygon.replace(m_vector_index, new_pos); + adjusteHandlerPos(); + emit polygonChanged(); +} + +/** + * @brief PartPolygon::handlerMouseReleaseEvent + * @param qghi + * @param event + */ +void PartPolygon::handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + Q_UNUSED(event); + + m_undo_command->setNewValue(QVariant(m_polygon)); + elementScene()->undoStack().push(m_undo_command); + m_undo_command = nullptr; + m_vector_index = -1; +} + +/** + * @brief PartPolygon::sceneSelectionChanged + * When the scene selection change, if there are several primitive selected, we remove the handler of this item + */ +void PartPolygon::sceneSelectionChanged() +{ + if (this->isSelected() && scene()->selectedItems().size() == 1) + addHandler(); else - CustomElementGraphicPart::mouseReleaseEvent(event); + removeHandler(); +} + +/** + * @brief PartPolygon::addHandler + * Add handlers for this item + */ +void PartPolygon::addHandler() +{ + if (m_handler_vector.isEmpty() && scene()) + { + m_handler_vector = QetGraphicsHandlerItem::handlerForPoint(mapToScene(m_polygon)); + + for(QetGraphicsHandlerItem *handler : m_handler_vector) + { + handler->setColor(Qt::blue); + scene()->addItem(handler); + handler->installSceneEventFilter(this); + handler->setZValue(this->zValue()+1); + } + } +} + +/** + * @brief PartPolygon::removeHandler + * Remove the handlers of this item + */ +void PartPolygon::removeHandler() +{ + if (!m_handler_vector.isEmpty()) + { + qDeleteAll(m_handler_vector); + m_handler_vector.clear(); + } } /** @@ -343,10 +454,6 @@ QPainterPath PartPolygon::shape() const pps.setWidth(m_hovered? penWeight()+SHADOWS_HEIGHT : penWeight()); shape = pps.createStroke(shape); - if (isSelected()) - foreach(QRectF rect, m_handler.handlerRect(m_polygon)) - shape.addRect(rect); - return shape; } @@ -379,8 +486,5 @@ QRectF PartPolygon::boundingRect() const r.adjust(-adjust, -adjust, adjust, adjust); - foreach(QRectF rect, m_handler.handlerRect(m_polygon)) - r |=rect; - return(r); } diff --git a/sources/editor/graphicspart/partpolygon.h b/sources/editor/graphicspart/partpolygon.h index ea0e9dbf0..371c46f14 100644 --- a/sources/editor/graphicspart/partpolygon.h +++ b/sources/editor/graphicspart/partpolygon.h @@ -20,10 +20,9 @@ #include #include "customelementgraphicpart.h" -#include "QetGraphicsItemModeler/qetgraphicshandlerutility.h" - class QPropertyUndoCommand; +class QetGraphicsHandlerItem; /** * @brief The PartPolygon class @@ -85,17 +84,25 @@ class PartPolygon : public CustomElementGraphicPart void setClosed (bool close); protected: - virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); - virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); + virtual bool sceneEventFilter(QGraphicsItem *watched, QEvent *event); private: + void adjusteHandlerPos(); + void handlerMousePressEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseMoveEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseReleaseEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void sceneSelectionChanged (); + + void addHandler(); + void removeHandler(); + + bool m_closed; QList saved_points_; QPolygonF m_polygon; - QetGraphicsHandlerUtility m_handler; - int m_handler_index; QPropertyUndoCommand *m_undo_command; + int m_vector_index = -1; + QVector m_handler_vector; }; #endif diff --git a/sources/editor/graphicspart/partrectangle.cpp b/sources/editor/graphicspart/partrectangle.cpp index 9c238df3b..31400b645 100644 --- a/sources/editor/graphicspart/partrectangle.cpp +++ b/sources/editor/graphicspart/partrectangle.cpp @@ -18,6 +18,8 @@ #include "partrectangle.h" #include "elementscene.h" #include "QPropertyUndoCommand/qpropertyundocommand.h" +#include "QetGraphicsItemModeler/qetgraphicshandleritem.h" +#include "QetGraphicsItemModeler/qetgraphicshandlerutility.h" /** * @brief PartRectangle::PartRectangle @@ -27,16 +29,16 @@ */ PartRectangle::PartRectangle(QETElementEditor *editor, QGraphicsItem *parent) : CustomElementGraphicPart(editor, parent), - m_handler(10), - m_handler_index(-1), m_undo_command(nullptr) {} /** * @brief PartRectangle::~PartRectangle */ -PartRectangle::~PartRectangle() { +PartRectangle::~PartRectangle() +{ if(m_undo_command) delete m_undo_command; + removeHandler(); } /** @@ -69,11 +71,7 @@ void PartRectangle::paint(QPainter *painter, const QStyleOptionGraphicsItem *opt drawShadowShape(painter); if (isSelected()) - { drawCross(m_rect.center(), painter); - if (scene()->selectedItems().size() == 1) - m_handler.drawHandler(painter, m_handler.pointsForRect(m_rect)); - } } /** @@ -129,6 +127,7 @@ void PartRectangle::setRect(const QRectF &rect) if (rect == m_rect) return; prepareGeometryChange(); m_rect = rect; + adjusteHandlerPos(); emit rectChanged(); } @@ -164,10 +163,6 @@ QPainterPath PartRectangle::shape() const pps.setWidth(m_hovered? penWeight()+SHADOWS_HEIGHT : penWeight()); shape = pps.createStroke(shape); - if (isSelected()) - foreach(QRectF rect, m_handler.handlerRect(m_handler.pointsForRect(m_rect))) - shape.addRect(rect); - return shape; } @@ -196,9 +191,6 @@ QRectF PartRectangle::boundingRect() const QRectF r = m_rect.normalized(); r.adjust(-adjust, -adjust, adjust, adjust); - foreach(QRectF rect, m_handler.handlerRect(m_handler.pointsForRect(m_rect))) - r |= rect; - return(r); } @@ -237,77 +229,6 @@ void PartRectangle::handleUserTransformation(const QRectF &initial_selection_rec setRect(QRectF(mapFromScene(mapped_points.at(0)), mapFromScene(mapped_points.at(1)))); } -void PartRectangle::hoverMoveEvent(QGraphicsSceneHoverEvent *event) -{ - if (!isSelected()) - { - CustomElementGraphicPart::hoverMoveEvent(event); - return; - } - - int handler = m_handler.pointIsHoverHandler(event->pos(), m_handler.pointsForRect(m_rect)); - - if (handler >= 0) - { - if (handler == 0 || handler == 2 || handler == 5 || handler == 7) - setCursor(Qt::SizeAllCursor); - else if (handler == 1 || handler == 6) - setCursor(Qt::SizeVerCursor); - else if (handler == 3 || handler == 4) - setCursor(Qt::SizeHorCursor); - } - else - CustomElementGraphicPart::hoverMoveEvent(event); -} - -/** - * @brief PartRectangle::mousePressEvent - * Handle mouse press event - * @param event - */ -void PartRectangle::mousePressEvent(QGraphicsSceneMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) - { - setCursor(Qt::ClosedHandCursor); - if(isSelected()) - { - m_handler_index = m_handler.pointIsHoverHandler(event->pos(), m_handler.pointsForRect(m_rect)); - - if(m_handler_index >= 0 && m_handler_index <= 7) //User click on an handler - { - m_undo_command = new QPropertyUndoCommand(this, "rect", QVariant(m_rect)); - m_undo_command->setText(tr("Modifier un rectangle")); - m_undo_command->enableAnimation(); - return; - } - } - } - - CustomElementGraphicPart::mousePressEvent(event); -} - -/** - * @brief PartRectangle::mouseMoveEvent - * Handle mouse press event - * @param event - */ -void PartRectangle::mouseMoveEvent(QGraphicsSceneMouseEvent *event) -{ - if(m_handler_index >= 0 && m_handler_index <= 7) - { - QPointF pos_ = event->modifiers() == Qt::ControlModifier ? event->pos() : mapFromScene(elementScene()->snapToGrid(event->scenePos())); - prepareGeometryChange(); - - if (m_resize_mode == 1) - setRect(m_handler.rectForPosAtIndex(m_rect, pos_, m_handler_index)); - else - setRect(m_handler.mirrorRectForPosAtIndex(m_rect, pos_, m_handler_index)); - } - else - CustomElementGraphicPart::mouseMoveEvent(event); -} - /** * @brief PartRectangle::mouseReleaseEvent * Handle mouse release event @@ -315,35 +236,223 @@ void PartRectangle::mouseMoveEvent(QGraphicsSceneMouseEvent *event) */ void PartRectangle::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { - if (event->button() == Qt::LeftButton) { - setCursor(Qt::OpenHandCursor); - if (event->buttonDownPos(Qt::LeftButton) == event->pos()) - switchResizeMode(); - } - - if (m_handler_index >= 0 && m_handler_index <= 7) - { - if (!m_rect.isValid()) - m_rect = m_rect.normalized(); - - m_undo_command->setNewValue(QVariant(m_rect)); - elementScene()->undoStack().push(m_undo_command); - m_undo_command = nullptr; - m_handler_index = -1; - } - else - CustomElementGraphicPart::mouseReleaseEvent(event); + if (event->button() == Qt::LeftButton && event->buttonDownPos(Qt::LeftButton) == event->pos()) + switchResizeMode(); + + CustomElementGraphicPart::mouseReleaseEvent(event); } +/** + * @brief PartRectangle::itemChange + * @param change + * @param value + * @return + */ +QVariant PartRectangle::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) +{ + if (change == ItemSelectedHasChanged && scene()) + { + if (value.toBool() == true) + { + //When item is selected, he must to be up to date whene the selection in the scene change, for display or not the handler, + //according to the number of selected items. + connect(scene(), &QGraphicsScene::selectionChanged, this, &PartRectangle::sceneSelectionChanged); + + if (scene()->selectedItems().size() == 1) + addHandler(); + } + else + { + disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartRectangle::sceneSelectionChanged); + removeHandler(); + } + } + else if (change == ItemPositionHasChanged) + { + adjusteHandlerPos(); + } + else if (change == ItemSceneChange) + { + if(scene()) + disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartRectangle::sceneSelectionChanged); + + setSelected(false); //This item is removed from scene, then we deselect this, and so, the handlers is also removed. + } + + return QGraphicsItem::itemChange(change, value); +} + +/** + * @brief PartRectangle::sceneEventFilter + * @param watched + * @param event + * @return + */ +bool PartRectangle::sceneEventFilter(QGraphicsItem *watched, QEvent *event) +{ + //Watched must be an handler + if(watched->type() == QetGraphicsHandlerItem::Type) + { + QetGraphicsHandlerItem *qghi = qgraphicsitem_cast(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(event)); + return true; + } + else if(event->type() == QEvent::GraphicsSceneMouseMove) //Move + { + handlerMouseMoveEvent(qghi, static_cast(event)); + return true; + } + else if (event->type() == QEvent::GraphicsSceneMouseRelease) //Release + { + handlerMouseReleaseEvent(qghi, static_cast(event)); + return true; + } + } + } + } + + return false; +} + +/** + * @brief PartRectangle::switchResizeMode + */ void PartRectangle::switchResizeMode() { - if (m_resize_mode == 1) { + if (m_resize_mode == 1) + { m_resize_mode = 2; - m_handler.setOuterColor(Qt::darkGreen); + for (QetGraphicsHandlerItem *qghi : m_handler_vector) + qghi->setColor(Qt::darkGreen); } - else { + else + { m_resize_mode = 1; - m_handler.setOuterColor(Qt::blue); + for (QetGraphicsHandlerItem *qghi : m_handler_vector) + qghi->setColor(Qt::blue); + } +} + +/** + * @brief PartRectangle::adjusteHandlerPos + */ +void PartRectangle::adjusteHandlerPos() +{ + if (m_handler_vector.isEmpty()) + return; + + QVector points_vector = QetGraphicsHandlerUtility::pointsForRect(m_rect); + + if (m_handler_vector.size() == points_vector.size()) + { + points_vector = mapToScene(points_vector); + for (int i = 0 ; i < points_vector.size() ; ++i) + m_handler_vector.at(i)->setPos(points_vector.at(i)); + } +} + +/** + * @brief PartRectangle::handlerMousePressEvent + * @param qghi + * @param event + */ +void PartRectangle::handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + Q_UNUSED(event); + + m_undo_command = new QPropertyUndoCommand(this, "rect", QVariant(m_rect)); + m_undo_command->setText(tr("Modifier un rectangle")); + m_undo_command->enableAnimation(); + return; +} + +/** + * @brief PartRectangle::handlerMouseMoveEvent + * @param qghi + * @param event + */ +void PartRectangle::handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + + QPointF new_pos = event->scenePos(); + if (event->modifiers() != Qt::ControlModifier) + new_pos = elementScene()->snapToGrid(event->scenePos()); + new_pos = mapFromScene(new_pos); + + if (m_resize_mode == 1) + setRect(QetGraphicsHandlerUtility::rectForPosAtIndex(m_rect, new_pos, m_vector_index)); + else + setRect(QetGraphicsHandlerUtility::mirrorRectForPosAtIndex(m_rect, new_pos, m_vector_index)); + + adjusteHandlerPos(); +} + +void PartRectangle::handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + Q_UNUSED(event); + + m_undo_command->setNewValue(QVariant(m_rect)); + elementScene()->undoStack().push(m_undo_command); + m_undo_command = nullptr; + m_vector_index = -1; +} + +/** + * @brief PartRectangle::sceneSelectionChanged + * When the scene selection change, if there are several primitive selected, we remove the handler of this item + */ +void PartRectangle::sceneSelectionChanged() +{ + if (this->isSelected() && scene()->selectedItems().size() == 1) + addHandler(); + else + removeHandler(); +} + +/** + * @brief PartRectangle::addHandler + * Add handlers for this item + */ +void PartRectangle::addHandler() +{ + if (m_handler_vector.isEmpty() && scene()) + { + m_handler_vector = QetGraphicsHandlerItem::handlerForPoint(mapToScene(QetGraphicsHandlerUtility::pointsForRect(m_rect))); + + for(QetGraphicsHandlerItem *handler : m_handler_vector) + { + QColor color = Qt::blue; + if (m_resize_mode == 2) + color = Qt::darkGreen; + + handler->setColor(color); + scene()->addItem(handler); + handler->installSceneEventFilter(this); + handler->setZValue(this->zValue()+1); + } + } +} + +/** + * @brief PartRectangle::removeHandler + * Remove the handlers of this item + */ +void PartRectangle::removeHandler() +{ + if (!m_handler_vector.isEmpty()) + { + qDeleteAll(m_handler_vector); + m_handler_vector.clear(); } - update(); } diff --git a/sources/editor/graphicspart/partrectangle.h b/sources/editor/graphicspart/partrectangle.h index b840920b5..014941b85 100644 --- a/sources/editor/graphicspart/partrectangle.h +++ b/sources/editor/graphicspart/partrectangle.h @@ -19,9 +19,9 @@ #define PART_RECTANGLE_H #include "customelementgraphicpart.h" -#include "QetGraphicsItemModeler/qetgraphicshandlerutility.h" class QPropertyUndoCommand; +class QetGraphicsHandlerItem; /** * This class represents a rectangle primitive which may be used to compose the @@ -75,20 +75,27 @@ class PartRectangle : public CustomElementGraphicPart virtual void handleUserTransformation(const QRectF &, const QRectF &); protected: - virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); - virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); + virtual bool sceneEventFilter(QGraphicsItem *watched, QEvent *event); private: void switchResizeMode(); + void adjusteHandlerPos(); + void handlerMousePressEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseMoveEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseReleaseEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void sceneSelectionChanged (); + + void addHandler(); + void removeHandler(); private: QRectF m_rect; QList saved_points_; - QetGraphicsHandlerUtility m_handler; - int m_handler_index; QPropertyUndoCommand *m_undo_command; - int m_resize_mode = 1; + int m_resize_mode = 1, + m_vector_index = -1; + QVector m_handler_vector; }; #endif diff --git a/sources/qetgraphicsitem/conductor.cpp b/sources/qetgraphicsitem/conductor.cpp index 7f431e725..a094fc974 100644 --- a/sources/qetgraphicsitem/conductor.cpp +++ b/sources/qetgraphicsitem/conductor.cpp @@ -78,17 +78,16 @@ Conductor::Conductor(Terminal *p1, Terminal* p2) : terminal1(p1), terminal2(p2), m_mouse_over(false), - m_handler(10), m_text_item(0), segments(NULL), - moving_segment(false), + m_moving_segment(false), modified_path(false), has_to_save_profile(false), must_highlight_(Conductor::None) { //set Zvalue at 11 to be upper than the DiagramImageItem and element setZValue(11); - previous_z_value = zValue(); + m_previous_z_value = zValue(); //Add this conductor to the list of conductor of each of the two terminal bool ajout_p1 = terminal1 -> addConductor(this); @@ -117,7 +116,7 @@ Conductor::Conductor(Terminal *p1, Terminal* p2) : //Generate the path of this conductor. generateConductorPath(terminal1 -> dockConductor(), terminal1 -> orientation(), terminal2 -> dockConductor(), terminal2 -> orientation()); - setFlags(QGraphicsItem::ItemIsSelectable); + setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsScenePositionChanges); setAcceptHoverEvents(true); // Add the text field @@ -137,6 +136,7 @@ Conductor::Conductor(Terminal *p1, Terminal* p2) : */ Conductor::~Conductor() { + removeHandler(); terminal1->removeConductor(this); terminal2->removeConductor(this); deleteSegments(); @@ -171,30 +171,39 @@ void Conductor::updatePath(const QRectF &rect) { } /** - Genere le QPainterPath a partir de la liste des points -*/ -void Conductor::segmentsToPath() { - // chemin qui sera dessine + * @brief Conductor::segmentsToPath + * Generate the QPainterPath from the list of points + */ +void Conductor::segmentsToPath() +{ QPainterPath path; - // s'il n'y a pa des segments, on arrete la - if (segments == NULL) setPath(path); + if (segments == NULL) + setPath(path); - // demarre le chemin + //Start the path path.moveTo(segments -> firstPoint()); - - // parcourt les segments pour dessiner le chemin + //Each segments ConductorSegment *segment = segments; while(segment -> hasNextSegment()) { path.lineTo(segment -> secondPoint()); segment = segment -> nextSegment(); } - - // termine le chemin + //Finish the path path.lineTo(segment -> secondPoint()); - // affecte le chemin au conducteur setPath(path); + + //If conductor is selected and he's not being modified + //we update the position of the handlers + if (isSelected() && !m_moving_segment) + { + if(handlerPoints().size() == m_handler_vector.size()) + adjusteHandlerPos(); + else + removeHandler(); + addHandler(); + } } /** @@ -456,12 +465,11 @@ QPointF Conductor::extendTerminal(const QPointF &terminal, Qet::Orientation term } /** - * @brief Conductor::paint - * Draw the conductor - * @param qp - * @param options - * @param qw - */ + Dessine le conducteur sans antialiasing. + @param qp Le QPainter a utiliser pour dessiner le conducteur + @param options Les options de style pour le conducteur + @param qw Le QWidget sur lequel on dessine +*/ void Conductor::paint(QPainter *qp, const QStyleOptionGraphicsItem *options, QWidget *qw) { Q_UNUSED(qw); @@ -501,7 +509,7 @@ void Conductor::paint(QPainter *qp, const QStyleOptionGraphicsItem *options, QWi final_conductor_pen.setCosmetic(true); } - qp->setPen(final_conductor_pen); + qp -> setPen(final_conductor_pen); //Draw the conductor qp -> drawPath(path()); @@ -529,22 +537,17 @@ void Conductor::paint(QPainter *qp, const QStyleOptionGraphicsItem *options, QWi if (isSelected()) qp -> setBrush(Qt::NoBrush); } - //Draw the squares used to modify the path of conductor when he is selected - if (isSelected()) - m_handler.drawHandler(qp, handlerPoints()); - //Draw the junctions - const QList junctions_list = junctions(); - if (!junctions_list.isEmpty()) - { + QList junctions_list = junctions(); + if (!junctions_list.isEmpty()) { final_conductor_pen.setStyle(Qt::SolidLine); QBrush junction_brush(final_conductor_color, Qt::SolidPattern); qp -> setPen(final_conductor_pen); qp -> setBrush(junction_brush); qp -> setRenderHint(QPainter::Antialiasing, true); - - for(QPointF point : junctions_list) + foreach(QPointF point, junctions_list) { qp -> drawEllipse(QRectF(point.x() - 1.5, point.y() - 1.5, 3.0, 3.0)); + } } qp -> restore(); @@ -603,70 +606,18 @@ void Conductor::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { */ void Conductor::mousePressEvent(QGraphicsSceneMouseEvent *event) { - //Left clic - if (event->buttons() & Qt::LeftButton) - { - //If user click on a handler (square used to modify the path of conductor), - //we get the segment corresponding to the handler - int index = m_handler.pointIsHoverHandler(event->pos(), handlerPoints()); - if (index > -1) - { - moving_segment = true; - moved_segment = segmentsList().at(index+1); - before_mov_text_pos_ = m_text_item -> pos(); - } - } - QGraphicsPathItem::mousePressEvent(event); - - if (event -> modifiers() & Qt::ControlModifier) + + if (event->modifiers() & Qt::ControlModifier) setSelected(!isSelected()); } -/** - * @brief Conductor::mouseMoveEvent - * Manage the mouse move event - * @param event - */ -void Conductor::mouseMoveEvent(QGraphicsSceneMouseEvent *event) -{ - //Left clic - if ((event->buttons() & Qt::LeftButton) && moving_segment) - { - //Snap the mouse pos to grid - QPointF pos_ = Diagram::snapToGrid(event->pos()); - - //Position of the last point - QPointF p = moved_segment -> middle(); - - //Calcul the movement - moved_segment -> moveX(pos_.x() - p.x()); - moved_segment -> moveY(pos_.y() - p.y()); - - //Apply the movement - modified_path = true; - has_to_save_profile = true; - segmentsToPath(); - calculateTextItemPosition(); - } - - QGraphicsPathItem::mouseMoveEvent(event); -} - /** * @brief Conductor::mouseReleaseEvent - * Manage the mouse release event * @param event */ void Conductor::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { - moving_segment = false; - if (has_to_save_profile) - { - saveProfile(); - has_to_save_profile = false; - } - if (!(event -> modifiers() & Qt::ControlModifier)) QGraphicsPathItem::mouseReleaseEvent(event); } @@ -694,56 +645,209 @@ void Conductor::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { } /** - * @brief Conductor::hoverMoveEvent conductor - * @param e QGraphicsSceneHoverEvent describing the event + * @brief Conductor::itemChange + * @param change + * @param value + * @return */ -void Conductor::hoverMoveEvent(QGraphicsSceneHoverEvent *event) +QVariant Conductor::itemChange(GraphicsItemChange change, const QVariant &value) { - if (isSelected()) + if (change == QGraphicsItem::ItemSelectedChange) { - //If user hover an handler (square used to modify the path of conductor), - //we get the segment corresponding to the handler - int index = m_handler.pointIsHoverHandler(event->pos(), handlerPoints()); - if (index > -1) + if (value.toBool()) { - ConductorSegment *segment_ = segmentsList().at(index+1); - if (m_handler.pointIsInHandler(event->pos(), segment_->secondPoint())) - setCursor(Qt::ForbiddenCursor); - else if (m_handler.pointIsInHandler(event->pos(), segment_->middle())) - setCursor(segmentsList().at(index+1)->isVertical() ? Qt::SplitHCursor : Qt::SplitVCursor); + m_previous_z_value = zValue(); + setZValue(qAbs(m_previous_z_value) + 10000); + addHandler(); } else - setCursor(Qt::ArrowCursor); + { + setZValue(m_previous_z_value); + removeHandler(); + } } - - QGraphicsPathItem::hoverMoveEvent(event); + else if (change == QGraphicsItem::ItemSceneHasChanged) + { + calculateTextItemPosition(); + + if(!scene()) + removeHandler(); + else if (scene() && isSelected()) + addHandler(); + } + else if (change == QGraphicsItem::ItemVisibleHasChanged) { + calculateTextItemPosition(); + } + else if (change == QGraphicsItem::ItemPositionHasChanged && isSelected()) { + adjusteHandlerPos(); + } + + return(QGraphicsPathItem::itemChange(change, value)); } /** - Gere les changements relatifs au conducteur - Reimplemente ici pour : - * positionner le conducteur en avant-plan lorsqu'il est selectionne - @param change Type de changement - @param value Valeur relative au changement -*/ -QVariant Conductor::itemChange(GraphicsItemChange change, const QVariant &value) { - if (change == QGraphicsItem::ItemSelectedChange) { - if (value.toBool()) { - // le conducteur vient de se faire selectionner - previous_z_value = zValue(); - setZValue(qAbs(previous_z_value) + 10000); - } else { - // le conducteur vient de se faire deselectionner - setZValue(previous_z_value); + * @brief Conductor::sceneEventFilter + * @param watched + * @param event + * @return + */ +bool Conductor::sceneEventFilter(QGraphicsItem *watched, QEvent *event) +{ + //Watched must be an handler + if(watched->type() == QetGraphicsHandlerItem::Type) + { + QetGraphicsHandlerItem *qghi = qgraphicsitem_cast(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(event)); + return true; + } + else if(event->type() == QEvent::GraphicsSceneMouseMove) //Move + { + handlerMouseMoveEvent(qghi, static_cast(event)); + return true; + } + else if (event->type() == QEvent::GraphicsSceneMouseRelease) //Release + { + handlerMouseReleaseEvent(qghi, static_cast(event)); + return true; + } + } } - } else if (change == QGraphicsItem::ItemSceneHasChanged) { - // permet de positionner correctement le texte du conducteur lors de son ajout a un schema - calculateTextItemPosition(); - } else if (change == QGraphicsItem::ItemVisibleHasChanged) { - // permet de positionner correctement le texte du conducteur lors de son ajout a un schema - calculateTextItemPosition(); } - return(QGraphicsPathItem::itemChange(change, value)); + + return false; +} + +/** + * @brief Conductor::adjusteHandlerPos + * Adjust the position of the handler item + */ +void Conductor::adjusteHandlerPos() +{ + if (m_handler_vector.isEmpty()) + return; + + if (m_handler_vector.size() == handlerPoints().size()) + { + QVector points_vector = mapToScene(handlerPoints()); + for (int i = 0 ; i < points_vector.size() ; ++i) + m_handler_vector.at(i)->setPos(points_vector.at(i)); + } +} + +/** + * @brief Conductor::handlerMousePressEvent + * @param qghi + * @param event + */ +void Conductor::handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(event); + + //we get the segment corresponding to the handler + if (m_vector_index > -1) + { + qghi->setColor(Qt::cyan); + m_moving_segment = true; + m_moved_segment = segmentsList().at(m_vector_index+1); + before_mov_text_pos_ = m_text_item -> pos(); + + for(QetGraphicsHandlerItem *handler : m_handler_vector) + if(handler != qghi) + handler->hide(); + } +} + +/** + * @brief Conductor::handlerMouseMoveEvent + * @param qghi + * @param event + */ +void Conductor::handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + if (m_moving_segment) + { + //Snap the mouse pos to grid + QPointF pos_ = Diagram::snapToGrid(mapFromItem(qghi, event->pos())); + + //Position of the last point + QPointF p = m_moved_segment -> middle(); + + //Calcul the movement + m_moved_segment -> moveX(pos_.x() - p.x()); + m_moved_segment -> moveY(pos_.y() - p.y()); + + //Apply the movement + modified_path = true; + has_to_save_profile = true; + segmentsToPath(); + calculateTextItemPosition(); + qghi->setPos(mapToScene(m_moved_segment->middle())); + } +} + +/** + * @brief Conductor::handlerMouseReleaseEvent + * @param qghi + * @param event + */ +void Conductor::handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(event); + Q_UNUSED(qghi); + + m_vector_index = -1; + + m_moving_segment = false; + if (has_to_save_profile) + { + saveProfile(); + has_to_save_profile = false; + } + //When handler is released, the conductor can have more segment than befor the handler was moved + //then we remove all handles and new ones are added + removeHandler(); + addHandler(); +} + +/** + * @brief Conductor::addHandler + * Add handlers for this item + */ +void Conductor::addHandler() +{ + if (m_handler_vector.isEmpty() && scene()) + { + m_handler_vector = QetGraphicsHandlerItem::handlerForPoint(mapToScene(handlerPoints())); + + for(QetGraphicsHandlerItem *handler : m_handler_vector) + { + handler->setColor(Qt::blue); + scene()->addItem(handler); + handler->installSceneEventFilter(this); + handler->setZValue(this->zValue()+1); + } + } +} + +/** + * @brief Conductor::removeHandler + * Remove the handlers of this item + */ +void Conductor::removeHandler() +{ + if (!m_handler_vector.isEmpty()) + { + qDeleteAll(m_handler_vector); + m_handler_vector.clear(); + } } /** @@ -768,23 +872,7 @@ QPainterPath Conductor::shape() const pps.setJoinStyle(conductor_pen.joinStyle()); QPainterPath shape_(pps.createStroke(path())); - - /** - Add handle rect to path, occur a weird bug. - when the conductor is removed from the scene he continue to be painted in the scene and make artefact. - If we save (exactly when we clear the undo stack of project when saving), Qet crash, - Don't add the handle rect to the path seem to work well. - More information here : - https://qelectrotech.org/bugtracker/view.php?id=107 - https://qelectrotech.org/forum/viewtopic.php?pid=5619#p5619 - https://qelectrotech.org/forum/viewtopic.php?pid=5067#p5067 - **/ -// if (isSelected()) { -// foreach (QRectF rect, m_handler.handlerRect(handlerPoints())) { -// shape_.addRect(rect); -// } -// } - + return shape_; } diff --git a/sources/qetgraphicsitem/conductor.h b/sources/qetgraphicsitem/conductor.h index dfedb50d4..e8630441d 100644 --- a/sources/qetgraphicsitem/conductor.h +++ b/sources/qetgraphicsitem/conductor.h @@ -20,7 +20,6 @@ #include "conductorproperties.h" #include -#include "QetGraphicsItemModeler/qetgraphicshandlerutility.h" #include "assignvariables.h" class ConductorProfile; @@ -32,6 +31,8 @@ class ConductorTextItem; class Element; class QETDiagramEditor; class NumerotationContext; +class QetGraphicsHandlerItem; + typedef QPair ConductorBend; typedef QHash ConductorProfilesGroup; /** @@ -133,36 +134,45 @@ class Conductor : public QObject, public QGraphicsPathItem protected: virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event); virtual void mousePressEvent(QGraphicsSceneMouseEvent *event); - virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *event); virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *event); virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event); virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *event); - virtual void hoverMoveEvent(QGraphicsSceneHoverEvent *event); virtual QVariant itemChange(GraphicsItemChange, const QVariant &); + virtual bool sceneEventFilter(QGraphicsItem *watched, QEvent *event); private: + void adjusteHandlerPos(); + + void handlerMousePressEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseMoveEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseReleaseEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void addHandler(); + void removeHandler(); + + + QVector m_handler_vector; + int m_vector_index = -1; bool m_mouse_over; - QetGraphicsHandlerUtility m_handler; - /// Functional properties + /// Functional properties ConductorProperties m_properties; - /// Text input for non simple, non-singleline conductors + /// Text input for non simple, non-singleline conductors ConductorTextItem *m_text_item; - /// Segments composing the conductor + /// Segments composing the conductor ConductorSegment *segments; - /// Attributs related to mouse interaction - bool moving_segment; + /// Attributs related to mouse interaction + bool m_moving_segment; int moved_point; - qreal previous_z_value; - ConductorSegment *moved_segment; + qreal m_previous_z_value; + ConductorSegment *m_moved_segment; QPointF before_mov_text_pos_; - /// Whether the conductor was manually modified by users + /// Whether the conductor was manually modified by users bool modified_path; - /// Whether the current profile should be saved as soon as possible + /// Whether the current profile should be saved as soon as possible bool has_to_save_profile; - /// conductor profile: "photography" of what the conductor is supposed to look - /// like - there is one profile per kind of traject + /// conductor profile: "photography" of what the conductor is supposed to look + /// like - there is one profile per kind of traject ConductorProfilesGroup conductor_profiles; - /// Define whether and how the conductor should be highlighted + /// Define whether and how the conductor should be highlighted Highlight must_highlight_; bool m_valid; bool m_freeze_label = false; diff --git a/sources/qetgraphicsitem/qetshapeitem.cpp b/sources/qetgraphicsitem/qetshapeitem.cpp index 2f1d6e4d6..01665c790 100644 --- a/sources/qetgraphicsitem/qetshapeitem.cpp +++ b/sources/qetgraphicsitem/qetshapeitem.cpp @@ -22,6 +22,7 @@ #include "shapegraphicsitempropertieswidget.h" #include "PropertiesEditor/propertieseditordialog.h" #include "QPropertyUndoCommand/qpropertyundocommand.h" +#include "QetGraphicsItemModeler/qetgraphicshandlerutility.h" #include "qetxml.h" /** @@ -37,18 +38,20 @@ QetShapeItem::QetShapeItem(QPointF p1, QPointF p2, ShapeType type, QGraphicsItem m_shapeType(type), m_P1 (p1), m_P2 (p2), - m_hovered(false), - m_mouse_grab_handler(false), - m_handler(10) + m_hovered(false) { if (type == Polygon) m_polygon << m_P1 << m_P2; - setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); + setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges); setAcceptHoverEvents(true); m_pen.setStyle(Qt::DashLine); } -QetShapeItem::~QetShapeItem() {} +QetShapeItem::~QetShapeItem() +{ + if(!m_handler_vector.isEmpty()) + qDeleteAll(m_handler_vector); +} /** * @brief QetShapeItem::setPen @@ -109,6 +112,7 @@ bool QetShapeItem::setLine(const QLineF &line) prepareGeometryChange(); m_P1 = line.p1(); m_P2 = line.p2(); + adjusteHandlerPos(); return true; } @@ -125,6 +129,7 @@ bool QetShapeItem::setRect(const QRectF &rect) prepareGeometryChange(); m_P1 = rect.topLeft(); m_P2 = rect.bottomRight(); + adjusteHandlerPos(); return true; } @@ -142,6 +147,7 @@ bool QetShapeItem::setPolygon(const QPolygonF &polygon) if (Q_UNLIKELY(m_shapeType != Polygon)) return false; prepareGeometryChange(); m_polygon = polygon; + adjusteHandlerPos(); return true; } @@ -246,23 +252,6 @@ QPainterPath QetShapeItem::shape() const pps.setJoinStyle(Qt::RoundJoin); path = pps.createStroke(path); - if (isSelected()) - { - QVector vector; - - if (m_shapeType == Line) - vector << m_P1 << m_P2; - else if (m_shapeType == Rectangle || m_shapeType == Ellipse) { - QRectF rect (m_P1, m_P2); - vector << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft(); - } - else - vector = m_polygon; - - foreach(QRectF r, m_handler.handlerRect(vector)) - path.addRect(r); - } - return (path); } @@ -293,35 +282,16 @@ void QetShapeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti painter -> drawPath (shape()); painter -> restore (); } - - //Draw the shape and handlers if is selected - switch (m_shapeType) - { - case Line: - painter->drawLine(QLineF(m_P1, m_P2)); - if (isSelected()) - m_handler.drawHandler(painter, QVector{m_P1, m_P2}); - break; - - case Rectangle: - painter->drawRect(QRectF(m_P1, m_P2)); - if (isSelected()) - m_handler.drawHandler(painter, m_handler.pointsForRect(QRectF(m_P1, m_P2))); - break; - - case Ellipse: - painter->drawEllipse(QRectF(m_P1, m_P2)); - if (isSelected()) - m_handler.drawHandler(painter, m_handler.pointsForRect(QRectF(m_P1, m_P2))); - break; - - case Polygon: - m_close ? painter->drawPolygon(m_polygon) : painter->drawPolyline(m_polygon); - if (isSelected()) - m_handler.drawHandler(painter, m_polygon); - break; - } - painter->restore(); + + switch (m_shapeType) + { + case Line: painter->drawLine(QLineF(m_P1, m_P2)); break; + case Rectangle: painter->drawRect(QRectF(m_P1, m_P2)); break; + case Ellipse: painter->drawEllipse(QRectF(m_P1, m_P2)); break; + case Polygon: m_close ? painter->drawPolygon(m_polygon) : painter->drawPolyline(m_polygon); break; + } + + painter->restore(); } /** @@ -329,142 +299,23 @@ void QetShapeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti * Handle hover enter event * @param event */ -void QetShapeItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { +void QetShapeItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) +{ m_hovered = true; QetGraphicsItem::hoverEnterEvent(event); } -void QetShapeItem::hoverMoveEvent(QGraphicsSceneHoverEvent *event) -{ - if (!isSelected()) return; - - QVector vector; - switch (m_shapeType) - { - case Line: vector << m_P1 << m_P2; break; - case Rectangle: vector = m_handler.pointsForRect(QRectF(m_P1, m_P2)); break; - case Ellipse: vector = m_handler.pointsForRect(QRectF(m_P1, m_P2)); break; - case Polygon: vector = m_polygon; break; - } - - int handler = m_handler.pointIsHoverHandler(event->pos(), vector); - if (handler >= 0) - { - if (m_shapeType & (Line | Polygon)) { - setCursor(Qt::SizeAllCursor); - return; - } - - if (handler == 0 || handler == 2 || handler == 5 || handler == 7) - setCursor(Qt::SizeAllCursor); - else if (handler == 1 || handler == 6) - setCursor(Qt::SizeVerCursor); - else if (handler == 3 || handler == 4) - setCursor(Qt::SizeHorCursor); - } - else - setCursor(Qt::OpenHandCursor); -} - /** * @brief QetShapeItem::hoverLeaveEvent * Handle hover leave event * @param event */ -void QetShapeItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { +void QetShapeItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) +{ m_hovered = false; - unsetCursor(); QetGraphicsItem::hoverLeaveEvent(event); } -/** - * @brief QetShapeItem::mousePressEvent - * Handle mouse press event - * @param event - */ -void QetShapeItem::mousePressEvent(QGraphicsSceneMouseEvent *event) -{ - if (event->button() == Qt::LeftButton) - { - setCursor(Qt::ClosedHandCursor); - //Shape is selected, we see if user click in a handler - if (isSelected()) - { - QVector vector; - switch (m_shapeType) - { - case Line: vector << m_P1 << m_P2; break; - case Rectangle: vector = m_handler.pointsForRect(QRectF(m_P1, m_P2)); break; - case Ellipse: vector = m_handler.pointsForRect(QRectF(m_P1, m_P2)); break; - case Polygon: vector = m_polygon; break; - } - - m_vector_index = m_handler.pointIsHoverHandler(event->pos(), vector); - if (m_vector_index != -1) - { - //User click on an handler - m_mouse_grab_handler = true; - m_old_P1 = m_P1; - m_old_P2 = m_P2; - m_old_polygon = m_polygon; - return; - } - } - } - - QetGraphicsItem::mousePressEvent(event); -} - -/** - * @brief QetShapeItem::mouseMoveEvent - * Handle move event - * @param event - */ -void QetShapeItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) -{ - if (m_mouse_grab_handler) - { - QPointF new_pos = event->pos(); - if (event->modifiers() != Qt::ControlModifier) - new_pos = mapFromScene(Diagram::snapToGrid(event->scenePos())); - - switch (m_shapeType) - { - case Line: - prepareGeometryChange(); - m_vector_index == 0 ? m_P1 = new_pos : m_P2 = new_pos; - break; - - case Rectangle: - if (m_resize_mode == 1) { - setRect(m_handler.rectForPosAtIndex(QRectF(m_P1, m_P2), new_pos, m_vector_index)); - break; - } - else { - setRect(m_handler.mirrorRectForPosAtIndex(QRectF(m_P1, m_P2), new_pos, m_vector_index)); - break; - } - case Ellipse: - if (m_resize_mode == 1) { - setRect(m_handler.rectForPosAtIndex(QRectF(m_P1, m_P2), new_pos, m_vector_index)); - break; - } - else { - setRect(m_handler.mirrorRectForPosAtIndex(QRectF(m_P1, m_P2), new_pos, m_vector_index)); - break; - } - - case Polygon: - prepareGeometryChange(); - m_polygon.replace(m_vector_index, new_pos); - break; - } //End switch - return; - } - - QetGraphicsItem::mouseMoveEvent(event); -} - /** * @brief QetShapeItem::mouseReleaseEvent * Handle mouse release event @@ -472,52 +323,251 @@ void QetShapeItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) */ void QetShapeItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) { - if ((m_shapeType & (Rectangle | Ellipse)) && event->buttonDownPos(Qt::LeftButton) == event->pos()) + if (event->buttonDownPos(Qt::LeftButton) == event->pos()) switchResizeMode(); - if (m_mouse_grab_handler) - { - m_mouse_grab_handler = false; - if (diagram()) - { - QPropertyUndoCommand *undo = nullptr; - if ((m_shapeType & (Line | Rectangle | Ellipse)) && (m_P1 != m_old_P1 || m_P2 != m_old_P2)) - { - switch(m_shapeType) - { - case Line: undo = new QPropertyUndoCommand(this, "line",QLineF(m_old_P1, m_old_P2), QLineF(m_P1, m_P2)); break; - case Rectangle: undo = new QPropertyUndoCommand(this, "rect",QRectF(m_old_P1, m_old_P2), QRectF(m_P1, m_P2)); break; - case Ellipse: undo = new QPropertyUndoCommand(this, "rect",QRectF(m_old_P1, m_old_P2), QRectF(m_P1, m_P2)); break; - case Polygon: break; - } - if (undo) undo->enableAnimation(); - } - else if (m_shapeType == Polygon && (m_polygon != m_old_polygon)) - undo = new QPropertyUndoCommand(this, "polygon", m_old_polygon, m_polygon); - - if(undo) - { - undo->setText(tr("Modifier %1").arg(name())); - diagram()->undoStack().push(undo); - } - } - setCursor(Qt::OpenHandCursor); - } - - QetGraphicsItem::mouseReleaseEvent(event); + QetGraphicsItem::mouseReleaseEvent(event); } +/** + * @brief QetShapeItem::itemChange + * @param change + * @param value + * @return + */ +QVariant QetShapeItem::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value) +{ + if (change == ItemSelectedHasChanged) + { + if (value.toBool() == true) //If this is selected, wa add handlers. + { + QVector points_vector; + switch (m_shapeType) + { + case Line: points_vector << m_P1 << m_P2; break; + case Rectangle: points_vector = QetGraphicsHandlerUtility::pointsForRect(QRectF(m_P1, m_P2)); break; + case Ellipse: points_vector = QetGraphicsHandlerUtility::pointsForRect(QRectF(m_P1, m_P2)); break; + case Polygon: points_vector = m_polygon; break; + } + + if(!points_vector.isEmpty() && scene()) + { + m_handler_vector = QetGraphicsHandlerItem::handlerForPoint(mapToScene(points_vector)); + + for(QetGraphicsHandlerItem *handler : m_handler_vector) + { + handler->setColor(Qt::blue); + scene()->addItem(handler); + handler->installSceneEventFilter(this); + } + } + } + else //Else this is deselected, we remove handlers + { + if(!m_handler_vector.isEmpty()) + { + qDeleteAll(m_handler_vector); + m_handler_vector.clear(); + } + } + } + else if (change == ItemPositionHasChanged) + { + adjusteHandlerPos(); + } + else if (change == ItemSceneHasChanged) + { + if (!scene()) //This is removed from scene, then we deselect this, and so, the handlers is also removed. + { + setSelected(false); + } + } + + return QGraphicsItem::itemChange(change, value); +} + +/** + * @brief QetShapeItem::sceneEventFilter + * @param watched + * @param event + * @return + */ +bool QetShapeItem::sceneEventFilter(QGraphicsItem *watched, QEvent *event) +{ + //Watched must be an handler + if(watched->type() == QetGraphicsHandlerItem::Type) + { + QetGraphicsHandlerItem *qghi = qgraphicsitem_cast(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(event)); + return true; + } + else if(event->type() == QEvent::GraphicsSceneMouseMove) //Move + { + handlerMouseMoveEvent(qghi, static_cast(event)); + return true; + } + else if (event->type() == QEvent::GraphicsSceneMouseRelease) //Release + { + handlerMouseReleaseEvent(qghi, static_cast(event)); + return true; + } + } + } + } + + return false; +} + +/** + * @brief QetShapeItem::switchResizeMode + */ void QetShapeItem::switchResizeMode() { - if (m_resize_mode == 1) { - m_resize_mode = 2; - m_handler.setOuterColor(Qt::darkGreen); + if (m_shapeType & (Rectangle | Ellipse)) + { + if (m_resize_mode == 1) + { + m_resize_mode = 2; + for (QetGraphicsHandlerItem *qghi : m_handler_vector) + qghi->setColor(Qt::darkGreen); + } + else + { + m_resize_mode = 1; + for (QetGraphicsHandlerItem *qghi : m_handler_vector) + qghi->setColor(Qt::blue); + } } - else { - m_resize_mode = 1; - m_handler.setOuterColor(Qt::blue); +} + +/** + * @brief QetShapeItem::adjusteHandlerPos + * Adjust the position of the handler item + */ +void QetShapeItem::adjusteHandlerPos() +{ + QVector points_vector; + switch (m_shapeType) + { + case Line: points_vector << m_P1 << m_P2; break; + case Rectangle: points_vector = QetGraphicsHandlerUtility::pointsForRect(QRectF(m_P1, m_P2)); break; + case Ellipse: points_vector = QetGraphicsHandlerUtility::pointsForRect(QRectF(m_P1, m_P2)); break; + case Polygon: points_vector = m_polygon; break; + } + + if (m_handler_vector.size() == points_vector.size()) + { + points_vector = mapToScene(points_vector); + for (int i = 0 ; i < points_vector.size() ; ++i) + m_handler_vector.at(i)->setPos(points_vector.at(i)); + } +} + +/** + * @brief QetShapeItem::handlerMousePressEvent + * @param qghi + * @param event + */ +void QetShapeItem::handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + Q_UNUSED(event); + + m_old_P1 = m_P1; + m_old_P2 = m_P2; + m_old_polygon = m_polygon; +} + +/** + * @brief QetShapeItem::handlerMouseMoveEvent + * @param qghi + * @param event + */ +void QetShapeItem::handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + + QPointF new_pos = event->scenePos(); + if (event->modifiers() != Qt::ControlModifier) + new_pos = Diagram::snapToGrid(event->scenePos()); + new_pos = mapFromScene(new_pos); + + switch (m_shapeType) + { + case Line: + prepareGeometryChange(); + m_vector_index == 0 ? m_P1 = new_pos : m_P2 = new_pos; + adjusteHandlerPos(); + break; + + case Rectangle: + if (m_resize_mode == 1) { + setRect(QetGraphicsHandlerUtility::rectForPosAtIndex(QRectF(m_P1, m_P2), new_pos, m_vector_index)); + break; + } + else { + setRect(QetGraphicsHandlerUtility::mirrorRectForPosAtIndex(QRectF(m_P1, m_P2), new_pos, m_vector_index)); + break; + } + case Ellipse: + if (m_resize_mode == 1) { + setRect(QetGraphicsHandlerUtility::rectForPosAtIndex(QRectF(m_P1, m_P2), new_pos, m_vector_index)); + break; + } + else { + setRect(QetGraphicsHandlerUtility::mirrorRectForPosAtIndex(QRectF(m_P1, m_P2), new_pos, m_vector_index)); + break; + } + + case Polygon: + prepareGeometryChange(); + m_polygon.replace(m_vector_index, new_pos); + adjusteHandlerPos(); + break; + } //End switch +} + +/** + * @brief QetShapeItem::handlerMouseReleaseEvent + * @param qghi + * @param event + */ +void QetShapeItem::handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event) +{ + Q_UNUSED(qghi); + Q_UNUSED(event); + + if (diagram()) + { + QPropertyUndoCommand *undo = nullptr; + if ((m_shapeType & (Line | Rectangle | Ellipse)) && (m_P1 != m_old_P1 || m_P2 != m_old_P2)) + { + switch(m_shapeType) + { + case Line: undo = new QPropertyUndoCommand(this, "line",QLineF(m_old_P1, m_old_P2), QLineF(m_P1, m_P2)); break; + case Rectangle: undo = new QPropertyUndoCommand(this, "rect",QRectF(m_old_P1, m_old_P2), QRectF(m_P1, m_P2)); break; + case Ellipse: undo = new QPropertyUndoCommand(this, "rect",QRectF(m_old_P1, m_old_P2), QRectF(m_P1, m_P2)); break; + case Polygon: break; + } + if (undo) undo->enableAnimation(); + } + else if (m_shapeType == Polygon && (m_polygon != m_old_polygon)) + undo = new QPropertyUndoCommand(this, "polygon", m_old_polygon, m_polygon); + + if(undo) + { + undo->setText(tr("Modifier %1").arg(name())); + diagram()->undoStack().push(undo); + } } - update(); } /** diff --git a/sources/qetgraphicsitem/qetshapeitem.h b/sources/qetgraphicsitem/qetshapeitem.h index 01d72115a..fdbf94efd 100644 --- a/sources/qetgraphicsitem/qetshapeitem.h +++ b/sources/qetgraphicsitem/qetshapeitem.h @@ -20,10 +20,11 @@ #include #include "qetgraphicsitem.h" -#include "QetGraphicsItemModeler/qetgraphicshandlerutility.h" +#include "QetGraphicsItemModeler/qetgraphicshandleritem.h" class QDomElement; class QDomDocument; +class QetGraphicsHandlerItem; /** * @brief The QetShapeItem class @@ -96,14 +97,18 @@ class QetShapeItem : public QetGraphicsItem protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); virtual void hoverEnterEvent (QGraphicsSceneHoverEvent *event); - virtual void hoverMoveEvent (QGraphicsSceneHoverEvent *event); virtual void hoverLeaveEvent (QGraphicsSceneHoverEvent *event); - virtual void mousePressEvent (QGraphicsSceneMouseEvent *event); - virtual void mouseMoveEvent (QGraphicsSceneMouseEvent *event); virtual void mouseReleaseEvent (QGraphicsSceneMouseEvent *event); + virtual QVariant itemChange(GraphicsItemChange change, const QVariant &value); + virtual bool sceneEventFilter(QGraphicsItem *watched, QEvent *event); private: void switchResizeMode(); + void adjusteHandlerPos(); + + void handlerMousePressEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseMoveEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); + void handlerMouseReleaseEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); ///ATTRIBUTES private: @@ -112,11 +117,10 @@ class QetShapeItem : public QetGraphicsItem QBrush m_brush; QPointF m_P1, m_P2, m_old_P1, m_old_P2; QPolygonF m_polygon, m_old_polygon; - bool m_hovered, - m_mouse_grab_handler; + bool m_hovered; int m_vector_index; - QetGraphicsHandlerUtility m_handler; bool m_close = false; int m_resize_mode = 1; + QVector m_handler_vector; }; #endif // QETSHAPEITEM_H