diff --git a/sources/diagram.cpp b/sources/diagram.cpp index 9acc55294..25e8091bf 100644 --- a/sources/diagram.cpp +++ b/sources/diagram.cpp @@ -38,6 +38,7 @@ #include "dynamicelementtextitem.h" #include "elementtextitemgroup.h" #include "undocommand/addelementtextcommand.h" +#include "QPropertyUndoCommand/qpropertyundocommand.h" const int Diagram::xGrid = 10; const int Diagram::yGrid = 10; @@ -1268,6 +1269,62 @@ void Diagram::loadFolioSeqHash(QHash *hash, QString title, } } +/** + * @brief Diagram::changeZValue + * Change the Z value of the current selected item, according to @option + */ +void Diagram::changeZValue(QET::DepthOption option) +{ + DiagramContent dc(this); + QUndoCommand *undo = new QUndoCommand(tr("Modifier la profondeur")); + QList l = dc.items(DiagramContent::SelectedOnly | \ + DiagramContent::Elements | \ + DiagramContent::Shapes | \ + DiagramContent::Images); + QList list; + for(QGraphicsItem *item : l) + list << item->toGraphicsObject(); + + qreal maxz=0, + minz=0; + for(QGraphicsItem *item : this->items()) + { + qreal z = item->zValue(); + if(z >= Terminal::Z-2) + continue; + maxz = std::max(maxz,z); + minz = std::min(minz,z); + } + + if(option == QET::Raise) + { + for(QGraphicsObject *qgo : list) + if(qgo->zValue() < (Terminal::Z-2)) //Ensure item is always below terminal + new QPropertyUndoCommand(qgo, "z", qgo->zValue(), qgo->zValue()+1, undo); + } + else if(option == QET::Lower) + { + for(QGraphicsObject *qgo : list) + if(qgo->zValue() < (Terminal::Z-2)) //Ensure item is always below terminal + new QPropertyUndoCommand(qgo, "z", qgo->zValue(), qgo->zValue()-1, undo); + } + else if (option == QET::BringForward) + { + for(QGraphicsObject *qgo : list) + new QPropertyUndoCommand(qgo, "z", qgo->zValue(), maxz+1, undo); + } + else if(option == QET::SendBackward) + { + for(QGraphicsObject *qgo : list) + new QPropertyUndoCommand(qgo, "z", qgo->zValue(), minz-1, undo); + } + + if(undo->childCount()) + this->undoStack().push(undo); + else + delete undo; +} + /** * @brief Diagram::loadElmtFolioSeq * This class loads all folio sequential variables related diff --git a/sources/diagram.h b/sources/diagram.h index f25d4688f..5ffc4ed63 100644 --- a/sources/diagram.h +++ b/sources/diagram.h @@ -212,7 +212,7 @@ class Diagram : public QGraphicsScene //methods related to insertion and loading of folio sequential void insertFolioSeqHash (QHash *hash, QString title, QString seq, NumerotationContext *nc); void loadFolioSeqHash (QHash *hash, QString title, QString seq, NumerotationContext *nc); - + void changeZValue(QET::DepthOption option); public slots: void adjustSceneRect (); diff --git a/sources/qet.h b/sources/qet.h index 86bf0e26f..c645e7f6c 100644 --- a/sources/qet.h +++ b/sources/qet.h @@ -30,6 +30,14 @@ namespace QET { const QString displayedVersion = "0.70-dev"; QString license(); + /// List the various kind of changes for the zValue + enum DepthOption { + BringForward, ///< Bring item to the foreground so they have the highest zValue + Raise, ///< Raise item one layer above their current one; zValues are incremented + Lower, ///< Send item one layer below their current one; zValues are decremented + SendBackward ///< Send item to the background so they have the lowest zValue + }; + /// Oriented movements enum OrientedMovement { ToNorth, @@ -165,6 +173,8 @@ namespace QET { bool eachStrIsEqual (const QStringList &qsl); } +Q_DECLARE_METATYPE(QET::DepthOption) + class Qet : public QObject { Q_OBJECT public: diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index 8f5eaa8c8..ac6f1d3c1 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -513,56 +513,84 @@ void QETDiagramEditor::setUpActions() connect(prev_window, SIGNAL(triggered()), &workspace, SLOT(activatePreviousSubWindow()) ); connect(m_conductor_reset, SIGNAL(triggered()), this, SLOT(slot_resetConductors()) ); connect(infos_diagram, SIGNAL(triggered()), this, SLOT(editCurrentDiagramProperties())); + + //Depth action + m_depth_action_group = new QActionGroup(this); + + QAction *edit_forward = new QAction(QET::Icons::BringForward, tr("Amener au premier plan"), m_depth_action_group); + QAction *edit_raise = new QAction(QET::Icons::Raise, tr("Rapprocher"), m_depth_action_group); + QAction *edit_lower = new QAction(QET::Icons::Lower, tr("Éloigner"), m_depth_action_group); + QAction *edit_backward = new QAction(QET::Icons::SendBackward, tr("Envoyer au fond"), m_depth_action_group); + + edit_raise ->setShortcut(QKeySequence(tr("Ctrl+Shift+Up"))); + edit_lower ->setShortcut(QKeySequence(tr("Ctrl+Shift+Down"))); + edit_backward->setShortcut(QKeySequence(tr("Ctrl+Shift+End"))); + edit_forward ->setShortcut(QKeySequence(tr("Ctrl+Shift+Home"))); + + edit_forward ->setData(QET::BringForward); + edit_raise ->setData(QET::Raise); + edit_lower ->setData(QET::Lower); + edit_backward->setData(QET::SendBackward); + m_depth_action_group->setDisabled(true); + + connect(m_depth_action_group, &QActionGroup::triggered, [this](QAction *action) { + this->currentDiagramView()->diagram()->changeZValue(action->data().value()); + }); } /** * @brief QETDiagramEditor::setUpToolBar */ -void QETDiagramEditor::setUpToolBar() { - main_bar = new QToolBar(tr("Outils"), this); - main_bar -> setObjectName("toolbar"); +void QETDiagramEditor::setUpToolBar() +{ + main_tool_bar = new QToolBar(tr("Outils"), this); + main_tool_bar -> setObjectName("toolbar"); - view_bar = new QToolBar(tr("Affichage"), this); - view_bar -> setObjectName("display"); + view_tool_bar = new QToolBar(tr("Affichage"), this); + view_tool_bar -> setObjectName("display"); - diagram_bar = new QToolBar(tr("Schéma"), this); - diagram_bar -> setObjectName("diagram"); + diagram_tool_bar = new QToolBar(tr("Schéma"), this); + diagram_tool_bar -> setObjectName("diagram"); - main_bar -> addActions(m_file_actions_group.actions()); - main_bar -> addAction(print); - main_bar -> addSeparator(); - main_bar -> addAction(undo); - main_bar -> addAction(redo); - main_bar -> addSeparator(); - main_bar -> addAction(m_cut); - main_bar -> addAction(m_copy); - main_bar -> addAction(paste); - main_bar -> addSeparator(); - main_bar -> addAction(m_delete_selection); - main_bar -> addAction(m_rotate_selection); + main_tool_bar -> addActions(m_file_actions_group.actions()); + main_tool_bar -> addAction(print); + main_tool_bar -> addSeparator(); + main_tool_bar -> addAction(undo); + main_tool_bar -> addAction(redo); + main_tool_bar -> addSeparator(); + main_tool_bar -> addAction(m_cut); + main_tool_bar -> addAction(m_copy); + main_tool_bar -> addAction(paste); + main_tool_bar -> addSeparator(); + main_tool_bar -> addAction(m_delete_selection); + main_tool_bar -> addAction(m_rotate_selection); // Modes selection / visualisation et zoom - view_bar -> addAction(mode_selection); - view_bar -> addAction(mode_visualise); - view_bar -> addSeparator(); - view_bar -> addAction(m_draw_grid); - view_bar -> addAction (m_grey_background); - view_bar -> addSeparator(); - view_bar -> addActions(m_zoom_action_toolBar); + view_tool_bar -> addAction(mode_selection); + view_tool_bar -> addAction(mode_visualise); + view_tool_bar -> addSeparator(); + view_tool_bar -> addAction(m_draw_grid); + view_tool_bar -> addAction (m_grey_background); + view_tool_bar -> addSeparator(); + view_tool_bar -> addActions(m_zoom_action_toolBar); - diagram_bar -> addAction (infos_diagram); - diagram_bar -> addAction (m_conductor_reset); - diagram_bar -> addAction (m_auto_conductor); + diagram_tool_bar -> addAction (infos_diagram); + diagram_tool_bar -> addAction (m_conductor_reset); + diagram_tool_bar -> addAction (m_auto_conductor); - m_add_item_toolBar = new QToolBar(tr("Ajouter"), this); - m_add_item_toolBar->setObjectName("adding"); - m_add_item_toolBar->addActions(m_add_item_actions_group.actions()); + m_add_item_tool_bar = new QToolBar(tr("Ajouter"), this); + m_add_item_tool_bar->setObjectName("adding"); + m_add_item_tool_bar->addActions(m_add_item_actions_group.actions()); + + m_depth_tool_bar = new QToolBar(tr("Profondeur", "toolbar title")); + m_depth_tool_bar->setObjectName("diagram_depth_toolbar"); + m_depth_tool_bar->addActions(m_depth_action_group->actions()); - // ajout de la barre d'outils a la fenetre principale - addToolBar(Qt::TopToolBarArea, main_bar); - addToolBar(Qt::TopToolBarArea, view_bar); - addToolBar(Qt::TopToolBarArea, diagram_bar); - addToolBar(Qt::TopToolBarArea, m_add_item_toolBar); + addToolBar(Qt::TopToolBarArea, main_tool_bar); + addToolBar(Qt::TopToolBarArea, view_tool_bar); + addToolBar(Qt::TopToolBarArea, diagram_tool_bar); + addToolBar(Qt::TopToolBarArea, m_add_item_tool_bar); + addToolBar(Qt::TopToolBarArea, m_depth_tool_bar); } /** @@ -612,6 +640,8 @@ void QETDiagramEditor::setUpMenu() { menu_edition -> addSeparator(); menu_edition -> addAction(infos_diagram); menu_edition -> addActions(m_row_column_actions_group.actions()); + menu_edition -> addSeparator(); + menu_edition -> addActions(m_depth_action_group->actions()); // menu Projet menu_project -> addAction(prj_edit_prop); @@ -623,9 +653,9 @@ void QETDiagramEditor::setUpMenu() { menu_project -> addAction(prj_nomenclature); menu_project -> addAction(prj_terminalBloc); - main_bar -> toggleViewAction() -> setStatusTip(tr("Affiche ou non la barre d'outils principale")); - view_bar -> toggleViewAction() -> setStatusTip(tr("Affiche ou non la barre d'outils Affichage")); - diagram_bar -> toggleViewAction() -> setStatusTip(tr("Affiche ou non la barre d'outils Schéma")); + main_tool_bar -> toggleViewAction() -> setStatusTip(tr("Affiche ou non la barre d'outils principale")); + view_tool_bar -> toggleViewAction() -> setStatusTip(tr("Affiche ou non la barre d'outils Affichage")); + diagram_tool_bar -> toggleViewAction() -> setStatusTip(tr("Affiche ou non la barre d'outils Schéma")); qdw_pa -> toggleViewAction() -> setStatusTip(tr("Affiche ou non le panel d'appareils")); qdw_undo -> toggleViewAction() -> setStatusTip(tr("Affiche ou non la liste des modifications")); @@ -1513,6 +1543,13 @@ void QETDiagramEditor::slot_updateComplexActions() m_edit_selection -> setIcon(QET::Icons::ElementEdit); m_edit_selection -> setEnabled(false); } + + //Actions for edit Z value + QList list = dc.items(DiagramContent::SelectedOnly | \ + DiagramContent::Elements | \ + DiagramContent::Shapes | \ + DiagramContent::Images); + m_depth_action_group->setEnabled(list.isEmpty()? false : true); } /** diff --git a/sources/qetdiagrameditor.h b/sources/qetdiagrameditor.h index 57710fd14..83d9fc03c 100644 --- a/sources/qetdiagrameditor.h +++ b/sources/qetdiagrameditor.h @@ -205,6 +205,7 @@ class QETDiagramEditor : public QETMainWindow { public: QActionGroup m_row_column_actions_group; /// Action related to add/remove rows/column in diagram QActionGroup m_selection_actions_group; ///Action related to edit a selected item + QActionGroup *m_depth_action_group = nullptr; private: QAction *m_delete_selection; ///< Delete selection QAction *m_rotate_selection; ///< Rotate selected elements and text items by 90 degrees @@ -219,22 +220,25 @@ class QETDiagramEditor : public QETMainWindow { QMdiArea workspace; QSignalMapper windowMapper; - /// Directory to use for file dialogs such as File > save + /// Directory to use for file dialogs such as File > save QDir open_dialog_dir; - /// Dock for the elements panel + /// Dock for the elements panel QDockWidget *qdw_pa; QDockWidget *m_qdw_elmt_collection; ElementsCollectionWidget *m_element_collection_widget; - /// Dock for the undo list + /// Dock for the undo list QDockWidget *qdw_undo; DiagramPropertiesEditorDockWidget *m_selection_properties_editor; - /// Elements panel + /// Elements panel ElementsPanelWidget *pa; QMenu *windows_menu; - QToolBar *main_bar; - QToolBar *view_bar; - QToolBar *diagram_bar; - QToolBar *m_add_item_toolBar; + + QToolBar *main_tool_bar = nullptr, + *view_tool_bar = nullptr, + *diagram_tool_bar = nullptr, + *m_add_item_tool_bar = nullptr, + *m_depth_tool_bar = nullptr; + QUndoGroup undo_group; // AutoNumbering Selection Dock AutoNumberingDockWidget *m_autonumbering_dock; diff --git a/sources/qetgraphicsitem/customelement.cpp b/sources/qetgraphicsitem/customelement.cpp index 3376cd240..6c9755be7 100644 --- a/sources/qetgraphicsitem/customelement.cpp +++ b/sources/qetgraphicsitem/customelement.cpp @@ -810,7 +810,6 @@ Terminal *CustomElement::parseTerminal(QDomElement &e) { else if (e.attribute("orientation") == "w") terminalo = Qet::West; else return(nullptr); Terminal *new_terminal = new Terminal(terminalx, terminaly, terminalo, this); - new_terminal -> setZValue(420); // valeur arbitraire pour maintenir les bornes au-dessus des champs de texte m_terminals << new_terminal; //Sort from top to bottom and left to rigth diff --git a/sources/qetgraphicsitem/diagramimageitem.cpp b/sources/qetgraphicsitem/diagramimageitem.cpp index c05b87e96..1b8980a4f 100644 --- a/sources/qetgraphicsitem/diagramimageitem.cpp +++ b/sources/qetgraphicsitem/diagramimageitem.cpp @@ -124,19 +124,27 @@ QString DiagramImageItem::name() const { } /** - Load the image from this xml element - @param e xml element that define an image -*/ -bool DiagramImageItem::fromXml(const QDomElement &e) { - if (e.tagName() != "image") return (false); + * @brief DiagramImageItem::fromXml + * Load this image fro xml elemebt @e + * @param e + * @return true if succesfully load. + */ +bool DiagramImageItem::fromXml(const QDomElement &e) +{ + if (e.tagName() != "image") { + return (false); + } + QDomNode image_node = e.firstChild(); - if (!image_node.isText()) return (false); + if (!image_node.isText()) { + return (false); + } - //load xml image to QByteArray + //load xml image to QByteArray QByteArray array; array = QByteArray::fromBase64(e.text().toLatin1()); - //Set QPixmap from the @array + //Set QPixmap from the @array QPixmap pixmap; pixmap.loadFromData(array); setPixmap(pixmap); @@ -145,6 +153,7 @@ bool DiagramImageItem::fromXml(const QDomElement &e) { setRotation(e.attribute("rotation").toDouble()); //We directly call setPos from QGraphicsObject, because QetGraphicsItem will snap to grid QGraphicsObject::setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble()); + setZValue(e.attribute("z", QString::number(this->zValue())).toDouble()); is_movable_ = (e.attribute("is_movable").toInt()); return (true); @@ -157,10 +166,11 @@ bool DiagramImageItem::fromXml(const QDomElement &e) { QDomElement DiagramImageItem::toXml(QDomDocument &document) const { QDomElement result = document.createElement("image"); //write some attribute - result.setAttribute("x", QString("%1").arg(pos().x())); - result.setAttribute("y", QString("%1").arg(pos().y())); - result.setAttribute("rotation", QString("%1").arg(QET::correctAngle(rotation()))); - result.setAttribute("size", QString("%1").arg(scale())); + result.setAttribute("x", QString::number(pos().x())); + result.setAttribute("y", QString::number(pos().y())); + result.setAttribute("z", QString::number(this->zValue())); + result.setAttribute("rotation", QString::number(QET::correctAngle(rotation()))); + result.setAttribute("size", QString::number(scale())); result.setAttribute("is_movable", bool(is_movable_)); //write the pixmap in the xml element after he was been transformed to base64 diff --git a/sources/qetgraphicsitem/element.cpp b/sources/qetgraphicsitem/element.cpp index 3c06a3eb9..e83f87274 100644 --- a/sources/qetgraphicsitem/element.cpp +++ b/sources/qetgraphicsitem/element.cpp @@ -421,6 +421,7 @@ bool Element::fromXml(QDomElement &e, QHash &table_id_adr, bool //Position and selection. //We directly call setPos from QGraphicsObject, because QetGraphicsItem will snap to grid QGraphicsObject::setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble()); + setZValue(e.attribute("z", QString::number(this->zValue())).toDouble()); setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); // orientation @@ -724,9 +725,10 @@ QDomElement Element::toXml(QDomDocument &document, QHash &table element.appendChild(seq); // position, selection et orientation - element.setAttribute("x", QString("%1").arg(pos().x())); - element.setAttribute("y", QString("%1").arg(pos().y())); - element.setAttribute("orientation", QString("%1").arg(orientation())); + element.setAttribute("x", QString::number(pos().x())); + element.setAttribute("y", QString::number(pos().y())); + element.setAttribute("z", QString::number(this->zValue())); + element.setAttribute("orientation", QString::number(orientation())); /* recupere le premier id a utiliser pour les bornes de cet element */ int id_terminal = 0; diff --git a/sources/qetgraphicsitem/qetshapeitem.cpp b/sources/qetgraphicsitem/qetshapeitem.cpp index 353f4ddf8..cac86f400 100644 --- a/sources/qetgraphicsitem/qetshapeitem.cpp +++ b/sources/qetgraphicsitem/qetshapeitem.cpp @@ -44,6 +44,12 @@ QetShapeItem::QetShapeItem(QPointF p1, QPointF p2, ShapeType type, QGraphicsItem setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemSendsGeometryChanges); setAcceptHoverEvents(true); m_pen.setStyle(Qt::DashLine); + //ensure handlers are always above this item + connect(this, &QetShapeItem::zChanged, [this]() + { + for(QetGraphicsHandlerItem *qghi : m_handler_vector) + qghi->setZValue(this->zValue()+1); + }); } @@ -356,6 +362,7 @@ QVariant QetShapeItem::itemChange(QGraphicsItem::GraphicsItemChange change, cons for(QetGraphicsHandlerItem *handler : m_handler_vector) { + handler->setZValue(this->zValue()+1); handler->setColor(Qt::blue); scene()->addItem(handler); handler->installSceneEventFilter(this); @@ -614,6 +621,7 @@ bool QetShapeItem::fromXml(const QDomElement &e) else foreach(QDomElement de, QET::findInDomElement(e, "points", "point")) m_polygon << QPointF(de.attribute("x", nullptr).toDouble(), de.attribute("y", nullptr).toDouble()); + setZValue(e.attribute("z", QString::number(this->zValue())).toDouble()); return (true); } @@ -656,6 +664,7 @@ QDomElement QetShapeItem::toXml(QDomDocument &document) const } result.appendChild(points); } + result.setAttribute("z", QString::number(this->zValue())); return(result); } diff --git a/sources/qetgraphicsitem/terminal.cpp b/sources/qetgraphicsitem/terminal.cpp index e53d55b8e..4e8a31c92 100644 --- a/sources/qetgraphicsitem/terminal.cpp +++ b/sources/qetgraphicsitem/terminal.cpp @@ -28,6 +28,7 @@ QColor Terminal::allowedColor = QColor(Qt::darkGreen); QColor Terminal::warningColor = QColor("#ff8000"); QColor Terminal::forbiddenColor = QColor(Qt::red); const qreal Terminal::terminalSize = 4.0; +const qreal Terminal::Z = 1000; /** Methode privee pour initialiser la borne. @@ -68,6 +69,7 @@ void Terminal::init(QPointF pf, Qet::Orientation o, QString number, QString name setAcceptedMouseButtons(Qt::LeftButton); hovered_ = false; setToolTip(QObject::tr("Borne", "tooltip")); + setZValue(Z); } /** diff --git a/sources/qetgraphicsitem/terminal.h b/sources/qetgraphicsitem/terminal.h index a19816e11..b616a8022 100644 --- a/sources/qetgraphicsitem/terminal.h +++ b/sources/qetgraphicsitem/terminal.h @@ -89,21 +89,21 @@ class Terminal : public QGraphicsObject void mouseMoveEvent (QGraphicsSceneMouseEvent *) override; void mouseReleaseEvent(QGraphicsSceneMouseEvent *) override; - // attributes + // attributes public: - enum { Type = UserType + 1002 }; - /// terminal length - static const qreal terminalSize; - - // Various static colors used for hover effects - /// default color - static QColor neutralColor; - /// color for legal actions - static QColor allowedColor; - /// color for allowed but fuzzy or not recommended actions - static QColor warningColor; - /// color for forbidden actions - static QColor forbiddenColor; + enum { Type = UserType + 1002 }; + + static const qreal terminalSize; + static const qreal Z; + // Various static colors used for hover effects + /// default color + static QColor neutralColor; + /// color for legal actions + static QColor allowedColor; + /// color for allowed but fuzzy or not recommended actions + static QColor warningColor; + /// color for forbidden actions + static QColor forbiddenColor; private: bool m_draw_help_line;