From eaf3d22d25b96ae20e1948fdc07040bfd528c0a4 Mon Sep 17 00:00:00 2001 From: blacksun Date: Thu, 9 Jul 2015 18:33:14 +0000 Subject: [PATCH] QetShapeItem : add handler for modified the geometry of shapes in the diagram git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@4039 bfdf4180-ca20-0410-9c96-a3a8aa849046 --- .../QetGraphicsItemModeler.pri | 5 + .../qetgraphicshandlerutility.cpp | 108 ++++++++ .../qetgraphicshandlerutility.h | 38 +++ sources/qetgraphicsitem/qetshapeitem.cpp | 236 ++++++++++++++++-- sources/qetgraphicsitem/qetshapeitem.h | 17 +- 5 files changed, 375 insertions(+), 29 deletions(-) create mode 100755 sources/QetGraphicsItemModeler/QetGraphicsItemModeler.pri create mode 100644 sources/QetGraphicsItemModeler/qetgraphicshandlerutility.cpp create mode 100644 sources/QetGraphicsItemModeler/qetgraphicshandlerutility.h diff --git a/sources/QetGraphicsItemModeler/QetGraphicsItemModeler.pri b/sources/QetGraphicsItemModeler/QetGraphicsItemModeler.pri new file mode 100755 index 000000000..ab89d8a6f --- /dev/null +++ b/sources/QetGraphicsItemModeler/QetGraphicsItemModeler.pri @@ -0,0 +1,5 @@ +HEADERS += \ + $$PWD/qetgraphicshandlerutility.h + +SOURCES += \ + $$PWD/qetgraphicshandlerutility.cpp diff --git a/sources/QetGraphicsItemModeler/qetgraphicshandlerutility.cpp b/sources/QetGraphicsItemModeler/qetgraphicshandlerutility.cpp new file mode 100644 index 000000000..91cc47dc2 --- /dev/null +++ b/sources/QetGraphicsItemModeler/qetgraphicshandlerutility.cpp @@ -0,0 +1,108 @@ +/* + Copyright 2006-2015 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 "qetgraphicshandlerutility.h" +#include +#include + +#define QetGraphicsHandlerSquareSize 10 + +/** + * @brief QetGraphicsHandlerUtility::pixmapHandler + * @return The pixmap of an handler + */ +QPixmap QetGraphicsHandlerUtility::pixmapHandler() +{ + QPixmap handler(QetGraphicsHandlerSquareSize, QetGraphicsHandlerSquareSize); + + if (!QPixmapCache::find("QetGraphicsHandler", handler)) + { //Pixmap isn't store in the QPixmapCache, we create it + QColor inner(0xFF, 0xFF, 0xFF); + QColor outer(0x00, 0x61, 0xFF); + + QPainter painter_(&handler); + painter_.setBrush(QBrush(inner)); + QPen square_pen(QBrush(outer), 2.0, Qt::SolidLine, Qt::SquareCap, Qt::MiterJoin); + square_pen.setCosmetic(true); + painter_.setPen(square_pen); + painter_.drawRect(0,0,10,10); + + //Store the pixmap in the QPixmapCache + QPixmapCache::insert("QetGraphicsHandler", handler); + } + return handler; +} + +/** + * @brief QetGraphicsHandlerUtility::posForHandler + * Returns a QPointF at the good coordinates + * for draw the handler pixmap centered on the point to modify + * @param point : the point to modify + * @return : point at the good coordinates to draw handler centered in @point + */ +QPointF QetGraphicsHandlerUtility::posForHandler(const QPointF &point) +{ + QPointF snap_point = point; + snap_point.rx() -= QetGraphicsHandlerSquareSize/2; + snap_point.ry() -= QetGraphicsHandlerSquareSize/2; + return snap_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) +{ + QRectF handler (posForHandler(key_point), QSize(QetGraphicsHandlerSquareSize, QetGraphicsHandlerSquareSize)); + return handler.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) +{ + foreach (QPointF key_point, vector) + if (pointIsInHandler(point, key_point)) + return vector.indexOf(key_point); + + return -1; +} + +/** + * @brief QetGraphicsHandlerUtility::handlerRect + * Return the rect of pixmap 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) +{ + QVector rect_vector; + QSize size(QetGraphicsHandlerSquareSize, QetGraphicsHandlerSquareSize); + + foreach(QPointF point, vector) + rect_vector << QRectF(posForHandler(point), size); + + return rect_vector; +} diff --git a/sources/QetGraphicsItemModeler/qetgraphicshandlerutility.h b/sources/QetGraphicsItemModeler/qetgraphicshandlerutility.h new file mode 100644 index 000000000..defb7b624 --- /dev/null +++ b/sources/QetGraphicsItemModeler/qetgraphicshandlerutility.h @@ -0,0 +1,38 @@ +/* + Copyright 2006-2015 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 QETGRAPHICSHANDLERUTILITY_H +#define QETGRAPHICSHANDLERUTILITY_H + +#include + +/** + * @brief The QetGraphicsHandlerUtility class + * This class provide some static methods to create and use handler for + * modify graphics shape like line rectangle etc... + */ +class QetGraphicsHandlerUtility +{ + public: + static QPixmap pixmapHandler(); + static QPointF posForHandler(const QPointF &point); + static bool pointIsInHandler (const QPointF &point, const QPointF &key_point); + static int pointIsHoverHandler (const QPointF &point, const QVector &vector); + static QVector handlerRect (const QVector &vector); +}; + +#endif // QETGRAPHICSHANDLERUTILITY_H diff --git a/sources/qetgraphicsitem/qetshapeitem.cpp b/sources/qetgraphicsitem/qetshapeitem.cpp index c752af165..ad53d6c94 100644 --- a/sources/qetgraphicsitem/qetshapeitem.cpp +++ b/sources/qetgraphicsitem/qetshapeitem.cpp @@ -21,7 +21,9 @@ #include "qet.h" #include "shapegraphicsitempropertieswidget.h" #include "PropertiesEditor/propertieseditordialog.h" +#include "QetGraphicsItemModeler/qetgraphicshandlerutility.h" +typedef QetGraphicsHandlerUtility QGHU; /** * @brief QetShapeItem::QetShapeItem @@ -37,7 +39,8 @@ QetShapeItem::QetShapeItem(QPointF p1, QPointF p2, ShapeType type, QGraphicsItem m_shapeStyle(Qt::DashLine), m_P1 (Diagram::snapToGrid(p1)), m_P2 (Diagram::snapToGrid(p2)), - m_hovered(false) + m_hovered(false), + m_mouse_grab_handler(false) { if (type == Polyline) m_polygon << m_P1 << m_P2; @@ -95,6 +98,39 @@ void QetShapeItem::setP2(QPointF P2) { setTransformOriginPoint(boundingRect().center()); } +/** + * @brief QetShapeItem::setRect + * Set this item geometry to rect (only available if shape is a rectangle or an ellipse) + * @param rect : new rect + * @return : true when shape is rectangle or ellipse, else false + */ +bool QetShapeItem::setRect(const QRectF &rect) +{ + if (Q_LIKELY(m_shapeType == Rectangle || m_shapeType == Ellipse)) + { + prepareGeometryChange(); + m_P1 = rect.topLeft(); + m_P2 = rect.bottomRight(); + return true; + } + + return false; +} + +/** + * @brief QetShapeItem::setPolygon + * Set this item geometry to polygon (only available if shape is a polyline) + * @param polygon : new polygon + * @return true if item is polygon, else false + */ +bool QetShapeItem::setPolygon(const QPolygon &polygon) +{ + if (Q_UNLIKELY(m_shapeType != Polyline)) return false; + prepareGeometryChange(); + m_polygon = polygon; + return true; +} + /** * @brief QetShapeItem::pointCount * @return the number of point in the polygon @@ -175,8 +211,26 @@ QPainterPath QetShapeItem::shape() const { QPainterPathStroker pps; pps.setWidth(10); pps.setJoinStyle(Qt::RoundJoin); + path = pps.createStroke(path); - return (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, QGHU::handlerRect(vector)) + path.addRect(r); + } + + return (path); } /** @@ -206,8 +260,9 @@ void QetShapeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti painter -> setRenderHint(QPainter::Antialiasing, false); pen.setWidthF(1); - - if (m_hovered) { + //Draw hovered shadow + if (m_hovered) + { painter->save(); QColor color(Qt::darkBlue); color.setAlpha(25); @@ -216,26 +271,54 @@ void QetShapeItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *opti painter -> drawPath (shape()); painter -> restore (); } - else if (isSelected()) { + //Draw red if selected + if (isSelected()) pen.setColor(Qt::red); - } painter -> setPen(pen); - switch (m_shapeType) { + //vector use to draw handler if needed + QVector point_vector; + + //Draw the shape + switch (m_shapeType) + { case Line: painter->drawLine(QLineF(m_P1, m_P2)); + if (isSelected()) + point_vector << m_P1 << m_P2; break; + case Rectangle: painter->drawRect(QRectF(m_P1, m_P2)); + if (isSelected()) + { + QRectF rect (m_P1, m_P2); + point_vector << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft(); + } break; + case Ellipse: painter->drawEllipse(QRectF(m_P1, m_P2)); + if (isSelected()) + { + QRectF rect (m_P1, m_P2); + point_vector << rect.topLeft() << rect.topRight() << rect.bottomRight() << rect.bottomLeft(); + } break; + case Polyline: + { painter->drawPolyline(m_polygon); + point_vector = m_polygon; + } break; } + + //Draw handler if shape is selected + if (isSelected()) + foreach(QPointF point, point_vector) + painter->drawPixmap(QGHU::posForHandler(point), QGHU::pixmapHandler()); } /** @@ -262,6 +345,119 @@ void QetShapeItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { update(); } +/** + * @brief QetShapeItem::mousePressEvent + * Handle mouse press event + * @param event + */ +void QetShapeItem::mousePressEvent(QGraphicsSceneMouseEvent *event) +{ + //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: { + QRectF rect (m_P1, m_P2); + vector << rect.topLeft() << rect.topRight() << rect.bottomLeft() << rect.bottomRight(); + } + break; + + case Ellipse: { + QRectF rect (m_P1, m_P2); + vector << rect.topLeft() << rect.topRight() << rect.bottomLeft() << rect.bottomRight(); + } + break; + + case Polyline: + vector = m_polygon; + break; + } + + m_vector_index = QGHU::pointIsHoverHandler(event->pos(), vector); + if (m_vector_index != -1) + { + //User click on an handler + m_mouse_grab_handler = true; + 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: { + QRectF rect(m_P1, m_P2); + if (m_vector_index == 0) rect.setTopLeft(new_pos); + else if (m_vector_index == 1) rect.setTopRight(new_pos); + else if (m_vector_index == 2) rect.setBottomLeft(new_pos); + else if (m_vector_index == 3) rect.setBottomRight(new_pos); + + setRect(rect); + } + break; + + case Ellipse: { + QRectF rect(m_P1, m_P2); + if (m_vector_index == 0) rect.setTopLeft(new_pos); + else if (m_vector_index == 1) rect.setTopRight(new_pos); + else if (m_vector_index == 2) rect.setBottomLeft(new_pos); + else if (m_vector_index == 3) rect.setBottomRight(new_pos); + + setRect(rect); + } + break; + + case Polyline: { + prepareGeometryChange(); + m_polygon.replace(m_vector_index, new_pos); + } + break; + } //End switch + + return; + } + + QetGraphicsItem::mouseMoveEvent(event); +} + +/** + * @brief QetShapeItem::mouseReleaseEvent + * Handle mouse release event + * @param event + */ +void QetShapeItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) +{ + m_mouse_grab_handler = false; + QetGraphicsItem::mouseReleaseEvent(event); +} + /** * @brief QetShapeItem::fromXml * Build this item from the xml description @@ -368,22 +564,14 @@ void QetShapeItem::editProperty() * @brief QetShapeItem::name * @return the name of the curent shape. */ -QString QetShapeItem::name() const { - switch (m_shapeType) { - case Line: - return tr("une ligne"); - break; - case Rectangle: - return tr("un rectangle"); - break; - case Ellipse: - return tr("une éllipse"); - break; - case Polyline: - return tr("une polyligne"); - break; - default: - return tr("une shape"); - break; +QString QetShapeItem::name() const +{ + switch (m_shapeType) + { + case Line: return tr("une ligne"); break; + case Rectangle: return tr("un rectangle"); break; + case Ellipse: return tr("une éllipse"); break; + case Polyline: return tr("une polyligne"); break; + default: return tr("une shape"); break; } } diff --git a/sources/qetgraphicsitem/qetshapeitem.h b/sources/qetgraphicsitem/qetshapeitem.h index c00224349..7ca2c8d55 100644 --- a/sources/qetgraphicsitem/qetshapeitem.h +++ b/sources/qetgraphicsitem/qetshapeitem.h @@ -61,10 +61,12 @@ class QetShapeItem : public QetGraphicsItem virtual void editProperty(); virtual QString name() const; - void setP2 (QPointF P2); + void setP2 (QPointF P2); + bool setRect (const QRectF &rect); + bool setPolygon (const QPolygon &polygon); //Methods available for polygon shape - int pointsCount () const; + int pointsCount () const; void setNextPoint (QPointF P); void removePoints (int number = 1); @@ -73,8 +75,11 @@ class QetShapeItem : public QetGraphicsItem protected: virtual void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget); - virtual void hoverEnterEvent (QGraphicsSceneHoverEvent *event); - virtual void hoverLeaveEvent (QGraphicsSceneHoverEvent *event); + virtual void hoverEnterEvent (QGraphicsSceneHoverEvent *event); + virtual void hoverLeaveEvent (QGraphicsSceneHoverEvent *event); + virtual void mousePressEvent (QGraphicsSceneMouseEvent *event); + virtual void mouseMoveEvent (QGraphicsSceneMouseEvent *event); + virtual void mouseReleaseEvent (QGraphicsSceneMouseEvent *event); private: void changeGraphicsItem (const ShapeType &newtype); @@ -88,6 +93,8 @@ class QetShapeItem : public QetGraphicsItem Qt::PenStyle m_shapeStyle; QPointF m_P1, m_P2; QPolygonF m_polygon; - bool m_hovered; + bool m_hovered, + m_mouse_grab_handler; + int m_vector_index; }; #endif // QETSHAPEITEM_H