diff --git a/sources/qetgraphicsitem/qetshapeitem.cpp b/sources/qetgraphicsitem/qetshapeitem.cpp index 4bd850794..38d523d16 100644 --- a/sources/qetgraphicsitem/qetshapeitem.cpp +++ b/sources/qetgraphicsitem/qetshapeitem.cpp @@ -63,6 +63,19 @@ void QetShapeItem::setPen(const QPen &pen) emit penChanged(); } +/** + * @brief QetShapeItem::setBrush + * Set the brush to use for the fill the shape + * @param brush + */ +void QetShapeItem::setBrush(const QBrush &brush) +{ + if (m_brush == brush) return; + m_brush = brush; + update(); + emit brushChanged(); +} + /** * @brief QetShapeItem::setP2 * Set the second point of this item. @@ -132,6 +145,21 @@ bool QetShapeItem::setPolygon(const QPolygonF &polygon) return true; } +/** + * @brief QetShapeItem::setClosed + * Close this item, have effect only if this item is a polygon. + * @param close + */ +void QetShapeItem::setClosed(bool close) +{ + if (m_shapeType == Polygon && close != m_close) + { + prepareGeometryChange(); + m_close = close; + emit closeChanged(); + } +} + /** * @brief QetShapeItem::pointCount * @return the number of point in the polygon @@ -196,7 +224,8 @@ QPainterPath QetShapeItem::shape() const path.lineTo(m_P2); break; case Rectangle: path.addRect(QRectF(m_P1, m_P2)); break; case Ellipse: path.addEllipse(QRectF(m_P1, m_P2)); break; - case Polygon: path.addPolygon(m_polygon); break; + case Polygon: path.addPolygon(m_polygon); + if (m_close) path.closeSubpath(); break; default: Q_ASSERT(false); break; } @@ -239,6 +268,7 @@ void QetShapeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti painter->save(); painter->setRenderHint(QPainter::Antialiasing, true); painter->setPen(m_pen); + painter->setBrush(m_brush); //Draw hovered shadow if (m_hovered) @@ -274,7 +304,7 @@ void QetShapeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti break; case Polygon: - painter->drawPolyline(m_polygon); + m_close ? painter->drawPolygon(m_polygon) : painter->drawPolyline(m_polygon); if (isSelected()) m_handler.drawHandler(painter, m_polygon); break; @@ -457,7 +487,9 @@ 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_pen = QETXML::penFromXml(e.firstChildElement("pen")); + m_brush = QETXML::brushFromXml(e.firstChildElement("brush")); QString type = e.attribute("type"); //@TODO Compatibility for version older than N°4075, shape type was stored with an int @@ -506,7 +538,10 @@ QDomElement QetShapeItem::toXml(QDomDocument &document) const QMetaEnum me = metaObject()->enumerator(metaObject()->indexOfEnumerator("ShapeType")); result.setAttribute("type", me.valueToKey(m_shapeType)); 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)); + if (m_shapeType != Polygon) { result.setAttribute("x1", QString::number(mapToScene(m_P1).x())); diff --git a/sources/qetgraphicsitem/qetshapeitem.h b/sources/qetgraphicsitem/qetshapeitem.h index b3192748e..8eb7a640e 100644 --- a/sources/qetgraphicsitem/qetshapeitem.h +++ b/sources/qetgraphicsitem/qetshapeitem.h @@ -35,12 +35,16 @@ class QetShapeItem : public QetGraphicsItem Q_OBJECT Q_PROPERTY(QPen pen READ pen WRITE setPen NOTIFY penChanged) + Q_PROPERTY(QBrush brush READ brush WRITE setBrush NOTIFY brushChanged) Q_PROPERTY(QRectF rect READ rect WRITE setRect) Q_PROPERTY(QLineF line READ line WRITE setLine) Q_PROPERTY(QPolygonF polygon READ polygon WRITE setPolygon) + Q_PROPERTY(bool close READ isClosed WRITE setClosed NOTIFY closeChanged) signals: void penChanged(); + void brushChanged(); + void closeChanged(); public: Q_ENUMS(ShapeType) @@ -60,6 +64,8 @@ class QetShapeItem : public QetGraphicsItem ///METHODS QPen pen() const {return m_pen;} void setPen(const QPen &pen); + QBrush brush() const {return m_brush;} + void setBrush(const QBrush &brush); ShapeType shapeType() const {return m_shapeType;} virtual bool fromXml (const QDomElement &); @@ -76,6 +82,8 @@ 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;} + void setClosed (bool close); //Methods available for polygon shape int pointsCount () const; @@ -98,11 +106,13 @@ class QetShapeItem : public QetGraphicsItem private: ShapeType m_shapeType; QPen m_pen; + 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; int m_vector_index; QetGraphicsHandlerUtility m_handler; + bool m_close = false; }; #endif // QETSHAPEITEM_H diff --git a/sources/qetxml.cpp b/sources/qetxml.cpp index d3de552fd..246c223e7 100644 --- a/sources/qetxml.cpp +++ b/sources/qetxml.cpp @@ -78,6 +78,78 @@ QPen QETXML::penFromXml(const QDomElement &element) return pen; } +/** + * @brief QETXML::brushToXml + * Write attribute of a QBrush in xml element + * @param parent_document : parent document for create the QDomElement + * @param brush : the brush to store + * @return A QDomElement with the attribute stored. The tagName of QDomeElement is "brush". + */ +QDomElement QETXML::brushToXml(QDomDocument &parent_document, QBrush brush) +{ + QDomElement element = parent_document.createElement("brush"); + + QString style; + switch (brush.style()) + { + case Qt::NoBrush : style = "NoBrush"; break; + case Qt::SolidPattern : style = "SolidPattern"; break; + case Qt::Dense1Pattern : style = "Dense1Pattern"; break; + case Qt::Dense2Pattern : style = "Dense2Pattern"; break; + case Qt::Dense3Pattern : style = "Dense3Pattern"; break; + case Qt::Dense4Pattern : style = "Dense4Pattern"; break; + case Qt::Dense5Pattern : style = "Dense5Pattern"; break; + case Qt::Dense6Pattern : style = "Dense6Pattern"; break; + case Qt::Dense7Pattern : style = "Dense7Pattern"; break; + case Qt::HorPattern : style = "HorPattern"; break; + case Qt::VerPattern : style = "VerPattern"; break; + case Qt::CrossPattern : style = "CrossPattern"; break; + case Qt::BDiagPattern : style = "BDiagPattern"; break; + case Qt::FDiagPattern : style = "FDiagPattern"; break; + case Qt::DiagCrossPattern : style = "DiagCrossPattern"; break; + default : style = "Unknow"; break; + } + + element.setAttribute("style", style); + element.setAttribute("color", brush.color().name()); + return element; +} + +/** + * @brief QETXML::brushFromXml + * Build a QBrush from a xml description + * @param element, the QDomElement that describe the pen + * @return the created brush. If @element is null or tagName isn't "brush" + * return a default constructed QBrush + */ +QBrush QETXML::brushFromXml(const QDomElement &element) +{ + QBrush brush; + + if (!(!element.isNull() && element.tagName() == "brush")) return brush; + + QString style = element.attribute("style", "NoBrush"); + if (style == "NoBrush") brush.setStyle(Qt::NoBrush); + else if (style == "SolidPattern") brush.setStyle(Qt::SolidPattern); + else if (style == "Dense1Pattern") brush.setStyle(Qt::Dense1Pattern); + else if (style == "Dense2Pattern") brush.setStyle(Qt::Dense2Pattern); + else if (style == "Dense3Pattern") brush.setStyle(Qt::Dense3Pattern); + else if (style == "Dense4Pattern") brush.setStyle(Qt::Dense4Pattern); + else if (style == "Dense5Pattern") brush.setStyle(Qt::Dense5Pattern); + else if (style == "Dense6Pattern") brush.setStyle(Qt::Dense6Pattern); + else if (style == "Dense7Pattern") brush.setStyle(Qt::Dense7Pattern); + else if (style == "HorPattern") brush.setStyle(Qt::HorPattern); + else if (style == "VerPattern") brush.setStyle(Qt::VerPattern); + else if (style == "CrossPattern") brush.setStyle(Qt::CrossPattern); + else if (style == "BDiagPattern") brush.setStyle(Qt::BDiagPattern); + else if (style == "FDiagPattern") brush.setStyle(Qt::FDiagPattern); + else if (style == "DiagCrossPattern") brush.setStyle(Qt::DiagCrossPattern); + else if (style == "Unknow") brush.setStyle(Qt::NoBrush); + + brush.setColor(QColor(element.attribute("color", "#000000"))); + return brush; +} + /** * @brief QETXML::fileSystemDirToXmlCollectionDir * @param document : owner document of returned QDomElement, use to create the QDomElement. diff --git a/sources/qetxml.h b/sources/qetxml.h index ee075b416..c609ac442 100644 --- a/sources/qetxml.h +++ b/sources/qetxml.h @@ -33,6 +33,9 @@ namespace QETXML QDomElement penToXml(QDomDocument &parent_document, QPen pen); QPen penFromXml (const QDomElement &element); + QDomElement brushToXml (QDomDocument &parent_document, QBrush brush); + QBrush brushFromXml (const QDomElement &element); + QDomElement fileSystemDirToXmlCollectionDir (QDomDocument &document, const QDir &dir); QDomElement fileSystemElementToXmlCollectionElement (QDomDocument &document, QFile &file); diff --git a/sources/ui/shapegraphicsitempropertieswidget.cpp b/sources/ui/shapegraphicsitempropertieswidget.cpp index 07f93bbaf..28ba135cf 100644 --- a/sources/ui/shapegraphicsitempropertieswidget.cpp +++ b/sources/ui/shapegraphicsitempropertieswidget.cpp @@ -52,16 +52,24 @@ ShapeGraphicsItemPropertiesWidget::~ShapeGraphicsItemPropertiesWidget() */ void ShapeGraphicsItemPropertiesWidget::setItem(QetShapeItem *shape) { - if (!shape) return; - if (shape == m_shape) return; + if (!shape || shape == m_shape) return; if (m_shape && m_live_edit) + { disconnect(m_shape, &QetShapeItem::penChanged, this, &ShapeGraphicsItemPropertiesWidget::updateUi); + disconnect(m_shape, &QetShapeItem::brushChanged, this, &ShapeGraphicsItemPropertiesWidget::updateUi); + disconnect(m_shape, &QetShapeItem::closeChanged, this, &ShapeGraphicsItemPropertiesWidget::updateUi); + } m_shape = shape; + ui->m_close_polygon->setVisible(m_shape->shapeType() == QetShapeItem::Polygon); if (m_live_edit) + { connect(m_shape, &QetShapeItem::penChanged, this, &ShapeGraphicsItemPropertiesWidget::updateUi); + connect(m_shape, &QetShapeItem::brushChanged, this, &ShapeGraphicsItemPropertiesWidget::updateUi); + connect(m_shape, &QetShapeItem::closeChanged, this, &ShapeGraphicsItemPropertiesWidget::updateUi); + } updateUi(); } @@ -94,6 +102,7 @@ void ShapeGraphicsItemPropertiesWidget::reset() { */ QUndoCommand* ShapeGraphicsItemPropertiesWidget::associatedUndo() const { + QPropertyUndoCommand *undo = nullptr; QPen old_pen = m_shape->pen(); QPen new_pen = old_pen; @@ -101,10 +110,39 @@ QUndoCommand* ShapeGraphicsItemPropertiesWidget::associatedUndo() const new_pen.setWidthF(ui->m_size_dsb->value()); new_pen.setColor(ui->m_color_pb->palette().color(QPalette::Button)); - if (new_pen == old_pen) return nullptr; + if (new_pen != old_pen) + { + undo = new QPropertyUndoCommand(m_shape, "pen", old_pen, new_pen); + undo->setText(tr("Modifier le trait d'une forme")); + } + + QBrush old_brush = m_shape->brush(); + QBrush new_brush = old_brush; + new_brush.setStyle(Qt::BrushStyle(ui->m_brush_style_cb->currentIndex())); + new_brush.setColor(ui->m_brush_color_pb->palette().color(QPalette::Button)); + + if (new_brush != old_brush) + { + if (undo) + new QPropertyUndoCommand(m_shape, "brush", old_brush, new_brush, undo); + else + { + undo = new QPropertyUndoCommand(m_shape, "brush", old_brush, new_brush); + undo->setText(tr("Modifier le remplissage d'une forme")); + } + } + + if (ui->m_close_polygon->isChecked() != m_shape->isClosed()) + { + if (undo) + new QPropertyUndoCommand(m_shape, "close", m_shape->isClosed(), ui->m_close_polygon->isChecked(), undo); + else + { + undo = new QPropertyUndoCommand(m_shape, "close", m_shape->isClosed(), ui->m_close_polygon->isChecked(), undo); + undo->setText(tr("Fermer le polygone")); + } + } - QPropertyUndoCommand *undo = new QPropertyUndoCommand(m_shape, "pen", old_pen, new_pen); - undo->setText(tr("Modifier le type de trait d'une forme")); return undo; } @@ -115,10 +153,16 @@ void ShapeGraphicsItemPropertiesWidget::updateUi() { bool le = m_live_edit; setLiveEdit(false); //Disable temporally live edit mode to avoid weird behavior + //Pen ui->m_style_cb->setCurrentIndex(static_cast(m_shape->pen().style()) - 1); ui->m_size_dsb ->setValue(m_shape->pen().widthF()); - setColorButton(m_shape->pen().color()); + setPenColorButton(m_shape->pen().color()); + //Brush + ui->m_brush_style_cb->setCurrentIndex(static_cast(m_shape->brush().style())); + setBrushColorButton(m_shape->brush().color()); + ui->m_lock_pos_cb->setChecked(!m_shape->isMovable()); + ui->m_close_polygon->setChecked(m_shape->isClosed()); setLiveEdit(le); } @@ -136,42 +180,73 @@ bool ShapeGraphicsItemPropertiesWidget::setLiveEdit(bool live_edit) { connect (ui->m_style_cb, SIGNAL(activated(int)), this, SLOT(apply())); connect (ui->m_size_dsb, SIGNAL(valueChanged(double)), this, SLOT(apply())); + connect (ui->m_brush_style_cb, SIGNAL(activated(int)), this, SLOT(apply())); + connect (ui->m_close_polygon, &QCheckBox::clicked, this, &ShapeGraphicsItemPropertiesWidget::apply); connect (m_shape, &QetShapeItem::penChanged, this, &ShapeGraphicsItemPropertiesWidget::updateUi); + connect (m_shape, &QetShapeItem::closeChanged, this, &ShapeGraphicsItemPropertiesWidget::updateUi); } else { disconnect (ui->m_style_cb, SIGNAL(activated(int)), this, SLOT(apply())); disconnect (ui->m_size_dsb, SIGNAL(valueChanged(double)), this, SLOT(apply())); + disconnect (ui->m_brush_style_cb, SIGNAL(activated(int)), this, SLOT(apply())); + disconnect (ui->m_close_polygon, &QCheckBox::clicked, this, &ShapeGraphicsItemPropertiesWidget::apply); disconnect (m_shape, &QetShapeItem::penChanged, this, &ShapeGraphicsItemPropertiesWidget::updateUi); + disconnect (m_shape, &QetShapeItem::closeChanged, this, &ShapeGraphicsItemPropertiesWidget::updateUi); } return true; } /** - * @brief ShapeGraphicsItemPropertiesWidget::setColorButton - * Set the color of the push button to the current color of the shape + * @brief ShapeGraphicsItemPropertiesWidget::setPenColorButton + * Set the color of pen push button to the current color of the shape pen * @param color */ -void ShapeGraphicsItemPropertiesWidget::setColorButton(const QColor &color) +void ShapeGraphicsItemPropertiesWidget::setPenColorButton(const QColor &color) { QPalette palette; palette.setColor(QPalette::Button, color); ui -> m_color_pb -> setStyleSheet(QString("background-color: %1; min-height: 1.5em; border-style: outset; border-width: 2px; border-color: gray; border-radius: 4px;").arg(color.name())); } +/** + * @brief ShapeGraphicsItemPropertiesWidget::setBrushColorButton + * Set the color of brush push button to the current color of shape brush + * @param color + */ +void ShapeGraphicsItemPropertiesWidget::setBrushColorButton(const QColor &color) +{ + QPalette palette; + palette.setColor(QPalette::Button, color); + ui->m_brush_color_pb->setStyleSheet(QString("background-color: %1; min-height: 1.5em; border-style: outset; border-width: 2px; border-color: gray; border-radius: 4px;").arg(color.name())); +} + void ShapeGraphicsItemPropertiesWidget::on_m_lock_pos_cb_clicked() { m_shape->setMovable(!ui->m_lock_pos_cb->isChecked()); } /** * @brief ShapeGraphicsItemPropertiesWidget::on_m_color_pb_clicked - * Color button was clicked, we open a QColorDialog for select the color to apply to the shape. + * Pen color button was clicked, we open a QColorDialog for select the color to apply to the shape pen. */ void ShapeGraphicsItemPropertiesWidget::on_m_color_pb_clicked() { QColor color = QColorDialog::getColor(m_shape->pen().color(), this); if (color.isValid()) - setColorButton(color); - if(m_live_edit) + setPenColorButton(color); + if (m_live_edit) + apply(); +} + +/** + * @brief ShapeGraphicsItemPropertiesWidget::on_m_brush_color_pb_clicked + * Brush color button was clicked, we open a QColorDialog for select the color to apply to the shape brush. + */ +void ShapeGraphicsItemPropertiesWidget::on_m_brush_color_pb_clicked() +{ + QColor color = QColorDialog::getColor(m_shape->brush().color(), this); + if (color.isValid()) + setBrushColorButton(color); + if (m_live_edit) apply(); } diff --git a/sources/ui/shapegraphicsitempropertieswidget.h b/sources/ui/shapegraphicsitempropertieswidget.h index b92daadda..a749a051f 100644 --- a/sources/ui/shapegraphicsitempropertieswidget.h +++ b/sources/ui/shapegraphicsitempropertieswidget.h @@ -50,11 +50,13 @@ class ShapeGraphicsItemPropertiesWidget : public PropertiesEditorWidget virtual bool setLiveEdit(bool live_edit); private: - void setColorButton(const QColor &color); + void setPenColorButton(const QColor &color); + void setBrushColorButton(const QColor &color); private slots: void on_m_lock_pos_cb_clicked(); void on_m_color_pb_clicked(); + void on_m_brush_color_pb_clicked(); private: Ui::ShapeGraphicsItemPropertiesWidget *ui; diff --git a/sources/ui/shapegraphicsitempropertieswidget.ui b/sources/ui/shapegraphicsitempropertieswidget.ui index 84d545909..4170af26a 100644 --- a/sources/ui/shapegraphicsitempropertieswidget.ui +++ b/sources/ui/shapegraphicsitempropertieswidget.ui @@ -7,7 +7,7 @@ 0 0 261 - 185 + 293 @@ -114,6 +114,115 @@ + + + + Remplissage + + + + + + Style + + + + + + + + Aucun + + + + + Plein + + + + + Densité 1 + + + + + Densité 2 + + + + + Densité 3 + + + + + Densité 4 + + + + + Densité 5 + + + + + Densité 6 + + + + + Densité 7 + + + + + Horizontal + + + + + Vertical + + + + + Croix + + + + + Diagonal arrière + + + + + Diagonal avant + + + + + Diagonal en croix + + + + + + + + Couleur + + + + + + + + + + + + + @@ -121,6 +230,13 @@ + + + + Polygone fermé + + +