QElectroTech  0.70
partarc.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 "partarc.h"
20 #include "elementscene.h"
23 
24 
31 PartArc::PartArc(QETElementEditor *editor, QGraphicsItem *parent) :
32  AbstractPartEllipse(editor, parent)
33 {
34  m_start_angle = 0;
35  m_span_angle = -1440;
36 }
37 
43 {
44  if(m_undo_command) delete m_undo_command;
45  removeHandler();
46 }
47 
55 void PartArc::paint(QPainter *painter, const QStyleOptionGraphicsItem *options, QWidget *widget)
56 {
57  Q_UNUSED(widget);
58 
59  applyStylesToQPainter(*painter);
60 
61  //Always remove the brush
62  painter -> setBrush(Qt::NoBrush);
63  QPen t = painter -> pen();
64  t.setCosmetic(options && options -> levelOfDetail < 1.0);
65  painter -> setPen(t);
66 
67  if (isSelected())
68  {
69  painter->save();
70  QPen pen(Qt::DotLine);
71  pen.setWidth(1);
72  pen.setCosmetic(true);
73  painter->setPen(pen);
74  //Draw the ellipse in black
75  painter -> drawEllipse(rect());
76  painter->restore();
77 
78  //Draw the arc in red
79  t.setColor(Qt::red);
80  painter -> setPen(t);
81  }
82 
83  painter -> drawArc(m_rect, m_start_angle, m_span_angle);
84 
85  if (m_hovered)
86  drawShadowShape(painter);
87 
88  if (isSelected())
89  drawCross(m_rect.center(), painter);
90 }
91 
98 const QDomElement PartArc::toXml(QDomDocument &xml_document) const {
99  QDomElement xml_element = xml_document.createElement("arc");
100  QPointF top_left(sceneTopLeft());
101  xml_element.setAttribute("x", QString("%1").arg(top_left.x()));
102  xml_element.setAttribute("y", QString("%1").arg(top_left.y()));
103  xml_element.setAttribute("width", QString("%1").arg(rect().width()));
104  xml_element.setAttribute("height", QString("%1").arg(rect().height()));
105  //to maintain compatibility with the previous version, we write the angle in degrees.
106  xml_element.setAttribute("start", QString("%1").arg(m_start_angle / 16));
107  xml_element.setAttribute("angle", QString("%1").arg(m_span_angle / 16));
108  stylesToXml(xml_element);
109  return(xml_element);
110 }
111 
117 void PartArc::fromXml(const QDomElement &qde) {
118  stylesFromXml(qde);
119  m_rect = QRectF(mapFromScene(qde.attribute("x", "0").toDouble(),
120  qde.attribute("y", "0").toDouble()),
121  QSizeF(qde.attribute("width", "0").toDouble(),
122  qde.attribute("height", "0").toDouble()) );
123 
124  m_start_angle = qde.attribute("start", "0").toDouble() * 16;
125  m_span_angle = qde.attribute("angle", "-1440").toDouble() * 16;
126 }
127 
132 QPainterPath PartArc::shape() const
133 {
134  QPainterPath shape;
135  shape.arcMoveTo(m_rect, m_start_angle/16);
136  shape.arcTo(m_rect, m_start_angle /16, m_span_angle /16);
137 
138  QPainterPathStroker pps;
139  pps.setWidth(m_hovered? penWeight()+SHADOWS_HEIGHT : penWeight());
140  shape = pps.createStroke(shape);
141 
142  return shape;
143 }
144 
145 QPainterPath PartArc::shadowShape() const
146 {
147  QPainterPath shape;
148  shape.arcMoveTo(m_rect, m_start_angle/16);
149  shape.arcTo(m_rect, m_start_angle /16, m_span_angle /16);
150 
151  QPainterPathStroker pps;
152  pps.setWidth(penWeight());
153 
154  return (pps.createStroke(shape));
155 }
156 
162 void PartArc::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
163 {
164  if (event->button() == Qt::LeftButton && event->buttonDownPos(Qt::LeftButton) == event->pos())
166 
168 }
169 
176 QVariant PartArc::itemChange(QGraphicsItem::GraphicsItemChange change, const QVariant &value)
177 {
178  if (change == ItemSelectedHasChanged && scene())
179  {
180  if (value.toBool() == true)
181  {
182  //When item is selected, he must to be up to date whene the selection in the scene change, for display or not the handler,
183  //according to the number of selected items.
184  connect(scene(), &QGraphicsScene::selectionChanged, this, &PartArc::sceneSelectionChanged);
185 
186  if (scene()->selectedItems().size() == 1)
187  addHandler();
188  }
189  else
190  {
191  disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartArc::sceneSelectionChanged);
192  removeHandler();
193  }
194  }
195  else if (change == ItemPositionHasChanged)
196  {
198  }
199  else if (change == ItemSceneChange)
200  {
201  if(scene())
202  disconnect(scene(), &QGraphicsScene::selectionChanged, this, &PartArc::sceneSelectionChanged);
203 
204  setSelected(false); //This is item removed from scene, then we deselect this, and so, the handlers is also removed.
205  }
206 
207  return QGraphicsItem::itemChange(change, value);
208 }
209 
216 bool PartArc::sceneEventFilter(QGraphicsItem *watched, QEvent *event)
217 {
218  //Watched must be an handler
219  if(watched->type() == QetGraphicsHandlerItem::Type)
220  {
221  QetGraphicsHandlerItem *qghi = qgraphicsitem_cast<QetGraphicsHandlerItem *>(watched);
222 
223  if(m_handler_vector.contains(qghi)) //Handler must be in m_vector_index, then we can start resize
224  {
225  m_vector_index = m_handler_vector.indexOf(qghi);
226  if (m_vector_index != -1)
227  {
228  if(event->type() == QEvent::GraphicsSceneMousePress) //Click
229  {
230  handlerMousePressEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
231  return true;
232  }
233  else if(event->type() == QEvent::GraphicsSceneMouseMove) //Move
234  {
235  handlerMouseMoveEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
236  return true;
237  }
238  else if (event->type() == QEvent::GraphicsSceneMouseRelease) //Release
239  {
240  handlerMouseReleaseEvent(qghi, static_cast<QGraphicsSceneMouseEvent *>(event));
241  return true;
242  }
243  }
244  }
245  }
246 
247  return false;
248 }
249 
254 {
255  if (m_resize_mode == 1)
256  {
257  m_resize_mode = 2;
259  qghi->setColor(Qt::darkGreen);
260  }
261  else if (m_resize_mode == 2)
262  {
263  m_resize_mode = 3;
264 
265  //From rect mode to angle mode, then numbers of handlers change
266  removeHandler();
267  addHandler();
268 
270  qghi->setColor(Qt::magenta);
271  }
272  else
273  {
274  m_resize_mode = 1;
275 
276  //From angle mode to rect mode, then numbers of handlers change
277  removeHandler();
278  addHandler();
279 
281  qghi->setColor(Qt::blue);
282  }
283 }
284 
289 {
290  if (m_handler_vector.isEmpty())
291  return;
292 
293  QVector <QPointF> points_vector;
294 
295  if(m_resize_mode == 3)
297  else
299 
300 
301  if (m_handler_vector.size() == points_vector.size())
302  {
303  points_vector = mapToScene(points_vector);
304  for (int i = 0 ; i < points_vector.size() ; ++i)
305  m_handler_vector.at(i)->setPos(points_vector.at(i));
306  }
307 }
308 
314 void PartArc::handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
315 {
316  Q_UNUSED(qghi);
317  Q_UNUSED(event);
318 
319  if (m_resize_mode == 3) //Resize angle
320  {
321  if (m_vector_index == 0)
322  {
324 
325  m_undo_command = new QPropertyUndoCommand(this, "startAngle", QVariant(m_start_angle));
326  m_undo_command->setText(tr("Modifier un arc"));
328 
329  m_undo_command2 = new QPropertyUndoCommand(this, "spanAngle", QVariant(m_span_angle), m_undo_command);
330  m_undo_command2->setText(tr("Modifier un arc"));
332  }
333  else if (m_vector_index == 1)
334  {
335  m_undo_command = new QPropertyUndoCommand(this, "spanAngle", QVariant(m_span_angle));
336  m_undo_command->setText(tr("Modifier un arc"));
338  }
339  }
340  else //resize rect
341  {
342  m_undo_command = new QPropertyUndoCommand(this, "rect", QVariant(m_rect));
343  m_undo_command->setText(tr("Modifier un arc"));
345  }
346 }
347 
353 void PartArc::handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
354 {
355  Q_UNUSED(qghi);
356 
357  QPointF new_pos = event->scenePos();
358  if (event->modifiers() != Qt::ControlModifier)
359  new_pos = elementScene()->snapToGrid(event->scenePos());
360  new_pos = mapFromScene(new_pos);
361 
362  if (m_resize_mode == 1)
364  else if (m_resize_mode == 2)
366  else
367  {
368  QLineF line(m_rect.center(), mapFromScene(event->scenePos()));
369  prepareGeometryChange();
370 
371  if (m_vector_index == 0) {
372  setStartAngle(line.angle()*16);
373  setSpanAngle(line.angleTo(QLineF(m_rect.center(), m_span_point))*16);
374  }
375  else if (m_vector_index == 1) {
376  QLineF line2(m_rect.center(), QetGraphicsHandlerUtility::pointsForArc(m_rect, m_start_angle/16, m_span_angle/16).at(0));
377  setSpanAngle (line2.angleTo(line)*16);
378  }
379  }
380 }
381 
387 void PartArc::handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
388 {
389  Q_UNUSED(qghi);
390  Q_UNUSED(event);
391 
392  if (m_resize_mode == 3)
393  {
394  if (m_vector_index == 0)
395  {
399  m_undo_command = nullptr;
400  m_undo_command2 = nullptr;
401  m_vector_index = -1;
402  }
403  else if (m_vector_index == 1)
404  {
407  m_undo_command = nullptr;
408  m_vector_index = -1;
409  }
410  }
411  else
412  {
413  if (!m_rect.isValid())
414  m_rect = m_rect.normalized();
415 
416  m_undo_command->setNewValue(QVariant(m_rect));
418  m_undo_command = nullptr;
419  m_vector_index = -1;
420  }
421 }
422 
428 {
429  if (this->isSelected() && scene()->selectedItems().size() == 1)
430  addHandler();
431  else
432  removeHandler();
433 }
434 
440 {
441  if (m_handler_vector.isEmpty() && scene())
442  {
443  if(m_resize_mode == 3)
444  {
446  }
447  else
449 
451  {
452  QColor color = Qt::blue;
453  if (m_resize_mode == 2)
454  color = Qt::darkGreen;
455  else if (m_resize_mode == 3)
456  color = Qt::magenta;
457 
458  handler->setColor(color);
459  scene()->addItem(handler);
460  handler->installSceneEventFilter(this);
461  handler->setZValue(this->zValue()+1);
462  }
463  }
464 }
465 
471 {
472  if (!m_handler_vector.isEmpty())
473  {
474  qDeleteAll(m_handler_vector);
475  m_handler_vector.clear();
476  }
477 }
void fromXml(const QDomElement &) override
PartArc::fromXml Import the properties of this arc from a xml element.
Definition: partarc.cpp:117
The QPropertyUndoCommand class This undo command manage QProperty of a QObject. This undo command can...
void setRect(const QRectF &rect) override
AbstractPartEllipse::setRect Sets the item&#39;s ellipse geometry to rect. The rectangle&#39;s left edge defi...
Definition: partarc.h:59
static QVector< QPointF > pointsForArc(const QRectF &rect, qreal start_angle, qreal span_angle)
QetGraphicsHandlerUtility::pointsForArc Return the points for the given arc. The first value in the v...
The QetGraphicsHandlerItem class This graphics item represents a point, destined to be used as an han...
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override
PartArc::mouseReleaseEvent Handle mouse release event.
Definition: partarc.cpp:162
QRectF rect() const
void setStartAngle(const int &start_angle) override
AbstractPartEllipse::setStartAngle Sets the start angle for an ellipse segment to angle...
Definition: partarc.h:60
QPainterPath shape() const override
PartArc::shape.
Definition: partarc.cpp:132
int m_resize_mode
Definition: partarc.h:82
void enableAnimation(bool animate=true)
QPropertyUndoCommand::enableAnimation True to enable animation.
static void drawCross(const QPointF &center, QPainter *painter)
CustomElementGraphicPart::drawCross Draw a cross at pos center.
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override
PartArc::itemChange.
Definition: partarc.cpp:176
~PartArc() override
PartArc::~PartArc Destructor.
Definition: partarc.cpp:42
QUndoStack & undoStack()
The AbstractPartEllipse class This is the base class for all ellipse based item like ellipse...
void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *=nullptr) override
PartArc::paint Draw this arc.
Definition: partarc.cpp:55
void removeHandler()
PartArc::removeHandler Remove the handlers of this item.
Definition: partarc.cpp:470
static QRectF mirrorRectForPosAtIndex(const QRectF &old_rect, const QPointF &pos, int index)
QetGraphicsHandlerUtility::mirrorRectForPosAtIndex Return a rectangle after modification of the point...
void setSpanAngle(const int &span_angle) override
AbstractPartEllipse::setSpanAngle Returns the span angle of an ellipse segment in 16ths of a degree...
Definition: partarc.h:61
bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) override
PartArc::sceneEventFilter.
Definition: partarc.cpp:216
void stylesToXml(QDomElement &) const
CustomElementGraphicPart::stylesToXml Write the curent style to xml element. The style are stored lik...
QPainterPath shadowShape() const override
Definition: partarc.cpp:145
static QRectF rectForPosAtIndex(const QRectF &old_rect, const QPointF &pos, int index)
QetGraphicsHandlerUtility::rectForPosAtIndex Return a rectangle after modification of the point &#39;&#39; at...
void switchResizeMode()
PartArc::switchResizeMode.
Definition: partarc.cpp:253
void adjusteHandlerPos()
PartArc::adjusteHandlerPos.
Definition: partarc.cpp:288
PartArc(QETElementEditor *editor, QGraphicsItem *parent=nullptr)
PartArc::PartArc Constructor.
Definition: partarc.cpp:31
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override
QIcon tr
Definition: qeticons.cpp:204
const QDomElement toXml(QDomDocument &) const override
PartArc::toXml Export this arc in xml.
Definition: partarc.cpp:98
QPropertyUndoCommand * m_undo_command2
Definition: partarc.h:81
void addHandler()
PartArc::addHandler Add handlers for this item.
Definition: partarc.cpp:439
virtual QPointF sceneTopLeft() const
AbstractPartEllipse::sceneTopLeft.
void stylesFromXml(const QDomElement &)
CustomElementGraphicPart::stylesFromXml Read the style used by this, from a xml element.
void sceneSelectionChanged()
PartArc::sceneSelectionChanged When the scene selection change, if there are several primitive select...
Definition: partarc.cpp:427
static QVector< QPointF > pointsForRect(const QRectF &rect)
QetGraphicsHandlerUtility::pointsForRect Return the keys points of the rectangle, stored in a vector...
QPointF m_span_point
Definition: partarc.h:84
QVector< QetGraphicsHandlerItem * > m_handler_vector
Definition: partarc.h:85
void handlerMouseMoveEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
PartArc::handlerMouseMoveEvent.
Definition: partarc.cpp:353
QPropertyUndoCommand * m_undo_command
Definition: partarc.h:80
void handlerMouseReleaseEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
PartArc::handlerMouseReleaseEvent.
Definition: partarc.cpp:387
virtual ElementScene * elementScene() const
#define SHADOWS_HEIGHT
void handlerMousePressEvent(QetGraphicsHandlerItem *qghi, QGraphicsSceneMouseEvent *event)
PartArc::handlerMousePressEvent.
Definition: partarc.cpp:314
static QVector< QetGraphicsHandlerItem * > handlerForPoint(const QVector< QPointF > &points, int size=10)
QetGraphicsHandlerItem::handlerForPoint.
qreal penWeight() const
CustomElementGraphicPart::penWeight.
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 ...
int m_vector_index
Definition: partarc.h:83
void drawShadowShape(QPainter *painter)
CustomElementGraphicPart::drawShadowShape Draw a transparent blue shadow arround the shape of this it...