QElectroTech  0.70
partpolygon.cpp
Go to the documentation of this file.
1 /*
2  Copyright 2006-2019 The QElectroTech Team
3  This file is part of QElectroTech.
4 
5  QElectroTech is free software: you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation, either version 2 of the License, or
8  (at your option) any later version.
9 
10  QElectroTech is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "partpolygon.h"
20 #include "elementscene.h"
22 #include "qetelementeditor.h"
23 #include "qeticons.h"
25 
26 
33 PartPolygon::PartPolygon(QETElementEditor *editor, QGraphicsItem *parent) :
34  CustomElementGraphicPart(editor, parent),
35  m_closed(false),
36  m_undo_command(nullptr)
37 {
38  m_insert_point = new QAction(tr("Ajouter un point"), this);
40  connect(m_insert_point, &QAction::triggered, this, &PartPolygon::insertPoint);
41  m_remove_point = new QAction(tr("Supprimer ce point"), this);
43  connect(m_remove_point, &QAction::triggered, this, &PartPolygon::removePoint);
44 }
45 
50 {
51  if(m_undo_command) delete m_undo_command;
52  removeHandler();
53 }
54 
62 void PartPolygon::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget)
63 {
64  Q_UNUSED(widget);
65 
66  applyStylesToQPainter(*painter);
67 
68  QPen t = painter -> pen();
69  t.setCosmetic(options && options -> levelOfDetail < 1.0);
70  if (isSelected()) t.setColor(Qt::red);
71  painter -> setPen(t);
72 
73  m_closed ? painter -> drawPolygon (m_polygon) :
74  painter -> drawPolyline(m_polygon);
75 
76  if (m_hovered)
77  drawShadowShape(painter);
78 }
79 
85 void PartPolygon::fromXml(const QDomElement &qde)
86 {
87  stylesFromXml(qde);
88 
89  int i = 1;
90  while(true)
91  {
92  if (QET::attributeIsAReal(qde, QString("x%1").arg(i)) &&\
93  QET::attributeIsAReal(qde, QString("y%1").arg(i)))
94  ++ i;
95 
96  else break;
97  }
98 
99  QPolygonF temp_polygon;
100  for (int j = 1 ; j < i ; ++ j)
101  {
102  temp_polygon << QPointF(qde.attribute(QString("x%1").arg(j)).toDouble(),
103  qde.attribute(QString("y%1").arg(j)).toDouble());
104  }
105  m_polygon = temp_polygon;
106 
107  m_closed = qde.attribute("closed") != "false";
108 }
109 
116 const QDomElement PartPolygon::toXml(QDomDocument &xml_document) const
117 {
118  QDomElement xml_element = xml_document.createElement("polygon");
119  int i = 1;
120  foreach(QPointF point, m_polygon) {
121  point = mapToScene(point);
122  xml_element.setAttribute(QString("x%1").arg(i), QString("%1").arg(point.x()));
123  xml_element.setAttribute(QString("y%1").arg(i), QString("%1").arg(point.y()));
124  ++ i;
125  }
126  if (!m_closed) xml_element.setAttribute("closed", "false");
127  stylesToXml(xml_element);
128  return(xml_element);
129 }
130 
137 {
138  if (m_polygon.count() < 2) return(true);
139 
140  for (int i = 1 ; i < m_polygon.count() ; ++ i)
141  if (m_polygon[i] != m_polygon[i-1]) return(false);
142 
143  return(true);
144 }
145 
154  return(mapToScene(m_polygon.boundingRect()).boundingRect());
155 }
156 
163 void PartPolygon::startUserTransformation(const QRectF &initial_selection_rect)
164 {
165  Q_UNUSED(initial_selection_rect)
166  saved_points_ = mapToScene(m_polygon).toList();
167 }
168 
175 void PartPolygon::handleUserTransformation(const QRectF &initial_selection_rect, const QRectF &new_selection_rect)
176 {
177  QList<QPointF> mapped_points = mapPoints(initial_selection_rect, new_selection_rect, saved_points_);
178  m_polygon = (mapFromScene(QPolygonF(mapped_points.toVector())));
179 }
180 
189  return(QET::RoundScaleRatios);
190 }
191 
196 QPolygonF PartPolygon::polygon() const {
197  return m_polygon;
198 }
199 
205 void PartPolygon::setPolygon(const QPolygonF &polygon)
206 {
207  if (m_polygon == polygon) return;
208  prepareGeometryChange();
209  m_polygon = polygon;
211  emit polygonChanged();
212 }
213 
219 void PartPolygon::addPoint(const QPointF &point)
220 {
221  prepareGeometryChange();
222  m_polygon << point;
223 }
224 
230 void PartPolygon::setLastPoint(const QPointF &point)
231 {
232  if (m_polygon.size())
233  m_polygon.pop_back();
234 
235  prepareGeometryChange();
236  m_polygon << point;
237 }
238 
244 {
245  if (m_polygon.size())
246  {
247  prepareGeometryChange();
248  m_polygon.pop_back();
249  }
250 }
251 
252 void PartPolygon::setClosed(bool close)
253 {
254  if (m_closed == close) return;
255  prepareGeometryChange();
256  m_closed = close;
257  emit closedChange();
258 }
259 
266 QVariant PartPolygon::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
267 {
268  if (change == ItemSelectedHasChanged && scene())
269  {
270  if (value.toBool() == true)
271  {
272  //When item is selected, he must to be up to date whene the selection in the scene change, for display or not the handler,
273  //according to the number of selected items.
274  connect(scene(), &QGraphicsScene::selectionChanged, this, &PartPolygon::sceneSelectionChanged);
275 
276  if (scene()->selectedItems().size() == 1)
277  addHandler();
278  }
279  else
280  {
281  disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartPolygon::sceneSelectionChanged);
282  removeHandler();
283  }
284  }
285  else if (change == ItemPositionHasChanged)
286  {
288  }
289  else if (change == ItemSceneChange)
290  {
291  if(scene())
292  disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartPolygon::sceneSelectionChanged);
293 
294  setSelected(false); //This is item removed from scene, then we deselect this, and so, the handlers is also removed.
295  }
296 
297  return QGraphicsItem::itemChange(change, value);
298 }
299 
306 bool PartPolygon::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
307 {
308  //Watched must be an handler
309  if(watched->type() == QetGraphicsHandlerItem::Type)
310  {
311  QetGraphicsHandlerItem *qghi = qgraphicsitem_cast<QetGraphicsHandlerItem *>(watched);
312 
313  if(m_handler_vector.contains(qghi)) //Handler must be in m_vector_index, then we can start resize
314  {
315  m_vector_index = m_handler_vector.indexOf(qghi);
316  if (m_vector_index != -1)
317  {
318  if(event->type() == QEvent::GraphicsSceneMousePress) //Click
319  {
320  handlerMousePressEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
321  return true;
322  }
323  else if(event->type() == QEvent::GraphicsSceneMouseMove) //Move
324  {
325  handlerMouseMoveEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
326  return true;
327  }
328  else if (event->type() == QEvent::GraphicsSceneMouseRelease) //Release
329  {
330  handlerMouseReleaseEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
331  return true;
332  }
333  }
334  }
335  }
336 
337  return false;
338 }
339 
340 void PartPolygon::contextMenuEvent(QGraphicsSceneContextMenuEvent *event)
341 {
342  m_context_menu_pos = event->pos();
343  event->ignore();
344  if (isSelected() && elementScene() && (elementScene()->behavior() == ElementScene::Normal))
345  {
346  QList<QAction *> list;
347  list << m_insert_point;
348  if (m_handler_vector.count() > 2)
349  {
351  {
352  if (qghi->contains(qghi->mapFromScene(event->scenePos())))
353  {
354  list << m_remove_point;
355  break;
356  }
357  }
358  }
359  elementScene()->editor()->contextMenu(event->screenPos(), list);
360  event->accept();
361  }
362 }
363 
368 {
369  if(m_handler_vector.isEmpty())
370  return;
371 
372  if (m_handler_vector.size() == m_polygon.size())
373  {
374  QVector <QPointF> points_vector = mapToScene(m_polygon);
375  for (int i = 0 ; i < points_vector.size() ; ++i)
376  m_handler_vector.at(i)->setPos(points_vector.at(i));
377  }
378  else
379  {
380  qDeleteAll(m_handler_vector);
381  m_handler_vector.clear();
382  addHandler();
383  }
384 }
385 
391 void PartPolygon::handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
392 {
393  Q_UNUSED(qghi);
394  Q_UNUSED(event);
395 
396  m_undo_command = new QPropertyUndoCommand(this, "polygon", QVariant(m_polygon));
397  m_undo_command->setText(tr("Modifier un polygone"));
398 }
399 
405 void PartPolygon::handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
406 {
407  Q_UNUSED(qghi);
408 
409  QPointF new_pos = event->scenePos();
410  if (event->modifiers() != Qt::ControlModifier)
411  new_pos = elementScene()->snapToGrid(event->scenePos());
412  new_pos = mapFromScene(new_pos);
413 
414  prepareGeometryChange();
415  m_polygon.replace(m_vector_index, new_pos);
417  emit polygonChanged();
418 }
419 
425 void PartPolygon::handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
426 {
427  Q_UNUSED(qghi);
428  Q_UNUSED(event);
429 
432  m_undo_command = nullptr;
433  m_vector_index = -1;
434 }
435 
441 {
442  if (this->isSelected() && scene()->selectedItems().size() == 1)
443  addHandler();
444  else
445  removeHandler();
446 }
447 
453 {
454  if (m_handler_vector.isEmpty() && scene())
455  {
457 
459  {
460  handler->setColor(Qt::blue);
461  scene()->addItem(handler);
462  handler->installSceneEventFilter(this);
463  handler->setZValue(this->zValue()+1);
464  }
465  }
466 }
467 
473 {
474  if (!m_handler_vector.isEmpty())
475  {
476  qDeleteAll(m_handler_vector);
477  m_handler_vector.clear();
478  }
479 }
480 
486 {
488 
489  if(new_polygon != m_polygon)
490  {
491  //Wrap the undo for avoid to merge the undo commands when user add several points.
492  QUndoCommand *undo = new QUndoCommand(tr("Ajouter un point à un polygone"));
493  new QPropertyUndoCommand(this, "polygon", m_polygon, new_polygon, undo);
494  elementScene()->undoStack().push(undo);
495  }
496 }
497 
503 {
504  if (m_handler_vector.size() == 2)
505  return;
506 
507  QPointF point = mapToScene(m_context_menu_pos);
508  int index = -1;
509  for (int i=0 ; i<m_handler_vector.size() ; i++)
510  {
512  if (qghi->contains(qghi->mapFromScene(point)))
513  {
514  index = i;
515  break;
516  }
517  }
518  if (index > -1 && index<m_handler_vector.count())
519  {
520  QPolygonF polygon = this->polygon();
521  polygon.removeAt(index);
522 
523  //Wrap the undo for avoid to merge the undo commands when user add several points.
524  QUndoCommand *undo = new QUndoCommand(tr("Supprimer un point d'un polygone"));
525  new QPropertyUndoCommand(this, "polygon", this->polygon(), polygon, undo);
526  elementScene()->undoStack().push(undo);
527  }
528 
529 }
530 
535 QPainterPath PartPolygon::shape() const
536 {
537  QPainterPath shape;
538  shape.addPolygon(m_polygon);
539 
540  if (m_closed)
541  shape.lineTo(m_polygon.first());
542 
543  QPainterPathStroker pps;
544  pps.setWidth(m_hovered? penWeight()+SHADOWS_HEIGHT : penWeight());
545  shape = pps.createStroke(shape);
546 
547  return shape;
548 }
549 
550 QPainterPath PartPolygon::shadowShape() const
551 {
552  QPainterPath shape;
553  shape.addPolygon(m_polygon);
554 
555  if (m_closed)
556  shape.lineTo(m_polygon.first());
557 
558  QPainterPathStroker pps;
559  pps.setWidth(penWeight());
560 
561  return (pps.createStroke(shape));
562 }
563 
569 {
570  QRectF r = m_polygon.boundingRect();
571 
572  qreal adjust = (SHADOWS_HEIGHT + penWeight()) / 2;
573  //We add 0.5 because CustomElementGraphicPart::drawShadowShape
574  //draw a shape bigger of 0.5 when pen weight is to 0.
575  if (penWeight() == 0) adjust += 0.5;
576 
577  r.adjust(-adjust, -adjust, adjust, adjust);
578 
579  return(r);
580 }
void fromXml(const QDomElement &) override
PartPolygon::fromXml Import the properties of this polygon from a xml element.
Definition: partpolygon.cpp:85
The QPropertyUndoCommand class This undo command manage QProperty of a QObject. This undo command can...
QPolygonF polygon() const
void addPoint(const QPointF &point)
PartPolygon::addPoint Add new point to polygon.
void adjusteHandlerPos()
PartPolygon::adjusteHandlerPos.
void removeHandler()
PartPolygon::removeHandler Remove the handlers of this item.
void removePoint()
PartPolygon::removePoint remove a point on this polygon.
QVector< QetGraphicsHandlerItem * > m_handler_vector
Definition: partpolygon.h:110
void sceneSelectionChanged()
PartPolygon::sceneSelectionChanged When the scene selection change, if there are several primitive se...
The QetGraphicsHandlerItem class This graphics item represents a point, destined to be used as an han...
void handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
PartPolygon::handlerMouseReleaseEvent.
int m_vector_index
Definition: partpolygon.h:109
QPainterPath shape() const override
PartPolygon::shape.
~PartPolygon() override
PartPolygon::~PartPolygon.
Definition: partpolygon.cpp:49
void setLastPoint(const QPointF &point)
PartPolygon::setLastPoint Set the last point of polygon to .
void setClosed(bool close)
void addHandler()
PartPolygon::addHandler Add handlers for this item.
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override
PartPolygon::paint Draw this polygon.
Definition: partpolygon.cpp:62
void polygonChanged()
QList< QPointF > mapPoints(const QRectF &, const QRectF &, const QList< QPointF > &)
QETElementEditor * editor() const
The CustomElementGraphicPart class This class is the base for all home-made primitive like line...
QAction * m_insert_point
Definition: partpolygon.h:111
QUndoStack & undoStack()
void insertPoint()
PartPolygon::insertPoint Insert a point in this polygone.
void handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
PartPolygon::handlerMousePressEvent.
QET::ScalingMethod preferredScalingMethod() const override
PartPolygon::preferredScalingMethod This method is called by the decorator when it needs to determine...
static QPolygonF polygonForInsertPoint(const QPolygonF &old_polygon, bool closed, const QPointF &pos)
QetGraphicsHandlerUtility::polygonForInsertPoint.
void contextMenuEvent(QGraphicsSceneContextMenuEvent *event) override
void startUserTransformation(const QRectF &) override
PartPolygon::startUserTransformation Start the user-induced transformation, provided this primitive i...
void stylesToXml(QDomElement &) const
CustomElementGraphicPart::stylesToXml Write the curent style to xml element. The style are stored lik...
void removeLastPoint()
PartPolygon::removeLastPoint Remove the last point of polygon.
adjust the scaling movement so that the induced scaling ratios are rounded
Definition: qet.h:82
PartPolygon(QETElementEditor *editor, QGraphicsItem *parent=nullptr)
PartPolygon::PartPolygon Constructor.
Definition: partpolygon.cpp:33
QPointF m_context_menu_pos
Definition: partpolygon.h:113
QRectF boundingRect() const override
PartPolygon::boundingRect.
QIcon tr
Definition: qeticons.cpp:204
void handleUserTransformation(const QRectF &, const QRectF &) override
PartPolygon::handleUserTransformation Handle the user-induced transformation from initial_selection_r...
bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) override
PartPolygon::sceneEventFilter.
void closedChange()
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override
PartPolygon::itemChange.
QPainterPath shadowShape() const override
ScalingMethod
Supported types of interactive scaling, typically for a single element primitive. ...
Definition: qet.h:79
bool isUseless() const override
PartPolygon::isUseless.
QIcon Remove
Definition: qeticons.cpp:155
bool attributeIsAReal(const QDomElement &, const QString &, qreal *=nullptr)
Definition: qet.cpp:219
QRectF sceneGeometricRect() const override
PartPolygon::sceneGeometricRect.
void handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
PartPolygon::handlerMouseMoveEvent.
QIcon Add
Definition: qeticons.cpp:24
void setPolygon(const QPolygonF &polygon)
PartPolygon::setPolygon Sets the item&#39;s polygon to be the given polygon.
void stylesFromXml(const QDomElement &)
CustomElementGraphicPart::stylesFromXml Read the style used by this, from a xml element.
void contextMenu(QPoint p, QList< QAction *> actions=QList< QAction *>())
QETElementEditor::contextMenu Display a context menu, with all available action.
const QDomElement toXml(QDomDocument &) const override
PartPolygon::toXml Export this polygin in xml.
virtual ElementScene * elementScene() const
#define SHADOWS_HEIGHT
QPropertyUndoCommand * m_undo_command
Definition: partpolygon.h:108
static QVector< QetGraphicsHandlerItem * > handlerForPoint(const QVector< QPointF > &points, int size=10)
QetGraphicsHandlerItem::handlerForPoint.
qreal penWeight() const
CustomElementGraphicPart::penWeight.
QList< QPointF > saved_points_
Definition: partpolygon.h:106
void applyStylesToQPainter(QPainter &) const
CustomElementGraphicPart::applyStylesToQPainter Apply the current style to the QPainter.
QPointF snapToGrid(QPointF point)
void setNewValue(const QVariant &new_value)
QPropertyUndoCommand::setNewValue Set the new value of the property (set with redo) to ...
QAction * m_remove_point
Definition: partpolygon.h:111
void drawShadowShape(QPainter *painter)
CustomElementGraphicPart::drawShadowShape Draw a transparent blue shadow arround the shape of this it...
QPolygonF m_polygon
Definition: partpolygon.h:107