diff --git a/sources/diagramview.cpp b/sources/diagramview.cpp index 285db573a..2e61c6d29 100644 --- a/sources/diagramview.cpp +++ b/sources/diagramview.cpp @@ -83,8 +83,7 @@ DiagramView::DiagramView(Diagram *diagram, QWidget *parent) : updateWindowTitle(); m_diagram->loadElmtFolioSeq(); m_diagram->loadCndFolioSeq(); - - m_context_menu = new QMenu(this); + m_paste_here = new QAction(QET::Icons::EditPaste, tr("Coller ici", "context menu action"), this); connect(m_paste_here, SIGNAL(triggered()), this, SLOT(pasteHere())); @@ -1008,47 +1007,85 @@ void DiagramView::setEventInterface(DVEventInterface *event_interface) } /** - Gere le menu contextuel - @param e Evenement decrivant la demande de menu contextuel -*/ -void DiagramView::contextMenuEvent(QContextMenuEvent *e) { - if (QGraphicsItem *qgi = m_diagram -> itemAt(mapToScene(e -> pos()), transform())) { - if (!qgi -> isSelected()) m_diagram -> clearSelection(); - qgi -> setSelected(true); - } - - if (QETDiagramEditor *qde = diagramEditor()) { - m_context_menu -> clear(); - if (m_diagram -> selectedItems().isEmpty()) { - m_paste_here_pos = e -> pos(); - m_paste_here -> setEnabled(Diagram::clipboardMayContainDiagram()); - m_context_menu -> addAction(m_paste_here); - m_context_menu -> addSeparator(); - m_context_menu -> addAction(qde -> m_edit_diagram_properties); - m_context_menu -> addActions(qde -> m_row_column_actions_group.actions()); - } else { - m_context_menu -> addAction(qde -> m_cut); - m_context_menu -> addAction(qde -> m_copy); - m_context_menu -> addAction(m_multi_paste); - m_context_menu -> addSeparator(); - m_context_menu -> addAction(qde -> m_conductor_reset); - m_context_menu -> addSeparator(); - m_context_menu -> addActions(qde -> m_selection_actions_group.actions()); - m_context_menu -> addSeparator(); - m_context_menu -> addActions(qde->m_depth_action_group->actions()); + * @brief DiagramView::contextMenuActions + * @return a list of actions currently available for a context menu. + * + */ +QList DiagramView::contextMenuActions() const +{ + QList list; + if (QETDiagramEditor *qde = diagramEditor()) + { + if (m_diagram->selectedItems().isEmpty()) + { + list << m_paste_here; + list << new QAction; + list.last()->setSeparator(true); + list << qde->m_edit_diagram_properties; + list << qde->m_row_column_actions_group.actions(); + } + else + { + list << qde->m_cut; + list << qde->m_copy; + list << m_multi_paste; + list << new QAction(); + list.last()->setSeparator(true); + list << qde->m_conductor_reset; + list << new QAction(); + list.last()->setSeparator(true); + list << qde->m_selection_actions_group.actions(); + list << new QAction(); + list.last()->setSeparator(true); + list << qde->m_depth_action_group->actions(); } //Remove from the context menu the actions which are disabled. - const QList actions = m_context_menu->actions(); + const QList actions = list; for(QAction *action : actions) { - if(!action->isEnabled()) - m_context_menu->removeAction(action); + if (!action->isEnabled()) { + list.removeAll(action); + } + } + } + + return list; +} + +/** + * @brief DiagramView::contextMenuEvent + * @param e + */ +void DiagramView::contextMenuEvent(QContextMenuEvent *e) +{ + QGraphicsView::contextMenuEvent(e); + if(e->isAccepted()) + return; + + if (QGraphicsItem *qgi = m_diagram->itemAt(mapToScene(e->pos()), transform())) + { + if (!qgi -> isSelected()) { + m_diagram->clearSelection(); } - m_context_menu -> popup(e -> globalPos()); + qgi->setSelected(true); + } + + if (m_diagram->selectedItems().isEmpty()) + { + m_paste_here_pos = e->pos(); + m_paste_here->setEnabled(Diagram::clipboardMayContainDiagram()); + } + + QList list = contextMenuActions(); + if(!list.isEmpty()) + { + QMenu *context_menu = new QMenu(this); + context_menu->addActions(list); + context_menu->popup(e->globalPos()); + e->accept(); } - e -> accept(); } /** diff --git a/sources/diagramview.h b/sources/diagramview.h index 4a63064ad..b72348d86 100644 --- a/sources/diagramview.h +++ b/sources/diagramview.h @@ -27,7 +27,6 @@ class Conductor; class Diagram; class QETDiagramEditor; class DVEventInterface; -class QMenu; class QInputEvent; class QGestureEvent; @@ -51,7 +50,6 @@ class DiagramView : public QGraphicsView Diagram *m_diagram = nullptr; DVEventInterface *m_event_interface = nullptr; - QMenu *m_context_menu = nullptr; QAction *m_paste_here = nullptr; QAction *m_multi_paste = nullptr; QPoint m_paste_here_pos; @@ -65,6 +63,7 @@ class DiagramView : public QGraphicsView QETDiagramEditor *diagramEditor() const; void editSelection(); void setEventInterface (DVEventInterface *event_interface); + QList contextMenuActions() const; protected: void mouseDoubleClickEvent(QMouseEvent *) override; diff --git a/sources/qetgraphicsitem/qetshapeitem.cpp b/sources/qetgraphicsitem/qetshapeitem.cpp index cac86f400..08ac21ea0 100644 --- a/sources/qetgraphicsitem/qetshapeitem.cpp +++ b/sources/qetgraphicsitem/qetshapeitem.cpp @@ -24,6 +24,8 @@ #include "QPropertyUndoCommand/qpropertyundocommand.h" #include "QetGraphicsItemModeler/qetgraphicshandlerutility.h" #include "qetxml.h" +#include "diagramview.h" +#include "qeticons.h" /** * @brief QetShapeItem::QetShapeItem @@ -50,6 +52,13 @@ QetShapeItem::QetShapeItem(QPointF p1, QPointF p2, ShapeType type, QGraphicsItem for(QetGraphicsHandlerItem *qghi : m_handler_vector) qghi->setZValue(this->zValue()+1); }); + + m_insert_point = new QAction(tr("Ajouter un point"), this); + m_insert_point->setIcon(QET::Icons::Add); + connect(m_insert_point, &QAction::triggered, this, &QetShapeItem::insertPoint); + m_remove_point = new QAction(tr("Supprimer ce point"), this); + m_remove_point->setIcon(QET::Icons::Remove); + connect(m_remove_point, &QAction::triggered, this, &QetShapeItem::removePoint); } @@ -164,10 +173,10 @@ bool QetShapeItem::setPolygon(const QPolygonF &polygon) */ void QetShapeItem::setClosed(bool close) { - if (m_shapeType == Polygon && close != m_close) + if (m_shapeType == Polygon && close != m_closed) { prepareGeometryChange(); - m_close = close; + m_closed = close; emit closeChanged(); } } @@ -244,7 +253,7 @@ QPainterPath QetShapeItem::shape() const break; case Polygon: path.addPolygon(m_polygon); - if (m_close) { + if (m_closed) { path.closeSubpath(); } break; @@ -294,7 +303,7 @@ void QetShapeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti 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; + case Polygon: m_closed ? painter->drawPolygon(m_polygon) : painter->drawPolyline(m_polygon); break; } painter->restore(); @@ -345,29 +354,8 @@ QVariant QetShapeItem::itemChange(QGraphicsItem::GraphicsItemChange change, cons { 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->setZValue(this->zValue()+1); - handler->setColor(Qt::blue); - scene()->addItem(handler); - handler->installSceneEventFilter(this); - } - } + if (value.toBool() == true) { //If this is selected, wa add handlers. + addHandler(); } else //Else this is deselected, we remove handlers { @@ -433,6 +421,65 @@ bool QetShapeItem::sceneEventFilter(QGraphicsItem *watched, QEvent *event) return false; } +/** + * @brief QetShapeItem::contextMenuEvent + * @param event + */ +void QetShapeItem::contextMenuEvent(QGraphicsSceneContextMenuEvent *event) +{ + m_context_menu_pos = event->pos(); + + if (m_shapeType == QetShapeItem::Polygon) + { + if (diagram()->selectedItems().isEmpty()) { + this->setSelected(true); + } + + if (isSelected() && scene()->selectedItems().size() == 1) + { + if (diagram()) + { + DiagramView *d_view = nullptr; + for (QGraphicsView *view : diagram()->views()) + { + if (view->isActiveWindow()) + { + d_view = dynamic_cast(view); + if (d_view) + continue; + } + } + + if (d_view) + { + QScopedPointer menu(new QMenu()); + menu.data()->addAction(m_insert_point); + + if (m_handler_vector.count() > 2) + { + for (QetGraphicsHandlerItem *qghi : m_handler_vector) + { + if (qghi->contains(qghi->mapFromScene(event->scenePos()))) + { + menu.data()->addAction(m_remove_point); + break; + } + } + } + + menu.data()->addSeparator(); + menu.data()->addActions(d_view->contextMenuActions()); + menu.data()->exec(event->screenPos()); + event->accept(); + return; + } + } + } + } + + QetGraphicsItem::contextMenuEvent(event); +} + /** * @brief QetShapeItem::switchResizeMode */ @@ -455,6 +502,34 @@ void QetShapeItem::switchResizeMode() } } +void QetShapeItem::addHandler() +{ + if (m_handler_vector.isEmpty()) + { + 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->setZValue(this->zValue()+1); + handler->setColor(Qt::blue); + scene()->addItem(handler); + handler->installSceneEventFilter(this); + } + } + } +} + /** * @brief QetShapeItem::adjusteHandlerPos * Adjust the position of the handler item @@ -476,6 +551,101 @@ void QetShapeItem::adjusteHandlerPos() for (int i = 0 ; i < points_vector.size() ; ++i) m_handler_vector.at(i)->setPos(points_vector.at(i)); } + else + { + qDeleteAll(m_handler_vector); + m_handler_vector.clear(); + addHandler(); + } +} + +void QetShapeItem::insertPoint() +{ + if (m_shapeType != QetShapeItem::Polygon) { + return; + } + + qreal max_angle = 0; + int index = 0; + + for (int i=1 ; i max_angle) + { + max_angle = angle; + index=i; + } + } + //Special case when polygon is close + if (m_closed) + { + QLineF line_a(m_polygon.last(), m_context_menu_pos); + QLineF line_b(m_context_menu_pos, m_polygon.first()); + + qreal angle = line_a.angleTo(line_b); + if (angle<180) + angle = 360-angle; + + if (angle > max_angle) + { + max_angle = angle; + index=m_polygon.size(); + } + } + + QPolygonF polygon = this->polygon(); + polygon.insert(index, Diagram::snapToGrid(m_context_menu_pos)); + + //Wrap the undo for avoid to merge the undo commands when user add several points. + QUndoCommand *undo = new QUndoCommand(tr("Ajouter un point à un polygone")); + new QPropertyUndoCommand(this, "polygon", this->polygon(), polygon, undo); + diagram()->undoStack().push(undo); +} + +void QetShapeItem::removePoint() +{ + if (m_shapeType != QetShapeItem::Polygon) { + return; + } + + if (m_handler_vector.size() == 2) { + return; + } + + QPointF point = mapToScene(m_context_menu_pos); + int index = -1; + for (int i=0 ; icontains(qghi->mapFromScene(point))) + { + index = i; + break; + } + } + if (index > -1 && indexpolygon(); + polygon.removeAt(index); + + //Wrap the undo for avoid to merge the undo commands when user add several points. + QUndoCommand *undo = new QUndoCommand(tr("Supprimer un point d'un polygone")); + new QPropertyUndoCommand(this, "polygon", this->polygon(), polygon, undo); + diagram()->undoStack().push(undo); + } } /** @@ -588,7 +758,7 @@ bool QetShapeItem::fromXml(const QDomElement &e) if (e.tagName() != "shape") return (false); is_movable_ = (e.attribute("is_movable").toInt()); - m_close = e.attribute("closed", "0").toInt(); + m_closed = e.attribute("closed", "0").toInt(); m_pen = QETXML::penFromXml(e.firstChildElement("pen")); m_brush = QETXML::brushFromXml(e.firstChildElement("brush")); @@ -642,7 +812,7 @@ QDomElement QetShapeItem::toXml(QDomDocument &document) const result.appendChild(QETXML::penToXml(document, m_pen)); result.appendChild(QETXML::brushToXml(document, m_brush)); result.setAttribute("is_movable", bool(is_movable_)); - result.setAttribute("closed", bool(m_close)); + result.setAttribute("closed", bool(m_closed)); if (m_shapeType != Polygon) { diff --git a/sources/qetgraphicsitem/qetshapeitem.h b/sources/qetgraphicsitem/qetshapeitem.h index 205b15b77..aa5a155cc 100644 --- a/sources/qetgraphicsitem/qetshapeitem.h +++ b/sources/qetgraphicsitem/qetshapeitem.h @@ -25,6 +25,7 @@ class QDomElement; class QDomDocument; class QetGraphicsHandlerItem; +class QAction; /** * @brief The QetShapeItem class @@ -83,7 +84,7 @@ class QetShapeItem : public QetGraphicsItem bool setRect (const QRectF &rect); QPolygonF polygon() const {return m_polygon;} bool setPolygon (const QPolygonF &polygon); - bool isClosed() const {return m_close;} + bool isClosed() const {return m_closed;} void setClosed (bool close); //Methods available for polygon shape @@ -101,10 +102,14 @@ class QetShapeItem : public QetGraphicsItem void mouseReleaseEvent (QGraphicsSceneMouseEvent *event) override; QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) override; + void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override; private: void switchResizeMode(); + void addHandler(); void adjusteHandlerPos(); + void insertPoint(); + void removePoint(); void handlerMousePressEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); void handlerMouseMoveEvent (QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event); @@ -115,12 +120,18 @@ class QetShapeItem : public QetGraphicsItem ShapeType m_shapeType; QPen m_pen; QBrush m_brush; - QPointF m_P1, m_P2, m_old_P1, m_old_P2; + QPointF m_P1, + m_P2, + m_old_P1, + m_old_P2, + m_context_menu_pos; QPolygonF m_polygon, m_old_polygon; bool m_hovered; int m_vector_index; - bool m_close = false; + bool m_closed = false; int m_resize_mode = 1; QVector m_handler_vector; + QAction *m_insert_point, + *m_remove_point; }; #endif // QETSHAPEITEM_H